magic

package module
v0.1.0 Latest Latest
Warning

This package is not in the latest version of its module.

Go to latest
Published: Jul 31, 2026 License: MIT Imports: 2 Imported by: 0

README

magic

Pure Go content detection for files and bounded file prefixes. The package reports a physical format, MIME type, text encoding, and whether a prefix needs more bytes. It has no CGO, native runtime, filesystem, or third-party module dependency.

Install

go get github.com/git-pkgs/magic

Use

Detect treats its byte slice as the complete file:

result := magic.Detect(data)

switch result.Kind {
case magic.KindText:
	fmt.Println(result.Format, result.MIME, result.Encoding)
case magic.KindBinary:
	fmt.Println(result.Format, result.MIME)
case magic.KindUnknown:
	fmt.Println(result.Reason)
}

Call DetectPrefix when the bytes came from a bounded read:

result := magic.DetectPrefix(prefix)
if result.Reason == magic.ReasonNeedMore {
	// More bytes could change the result.
}

A complete binary signature can finish detection from a prefix. Text remains provisional because later bytes can contain a NUL, an invalid encoding, or a binary signature. NeedBytes is reserved for a known minimum total length and is zero in the first release.

Both functions are safe for concurrent use. They retain no input and use no mutable package state.

Results

Kind is text, binary, or unknown. Format and MIME describe the physical content. Encoding is set for accepted UTF-8, UTF-16LE, or UTF-16BE text and never appears as a MIME charset parameter.

The first format registry contains:

  • ZIP, TAR, gzip, bzip2, xz, PDF, CFBF, PNG, JPEG, and GIF
  • plain text, HTML, XML, and SVG

Detection uses bytes only. ZIP-based package types such as JAR, wheel, and NuGet remain zip, and compressed payloads are not opened. A caller can combine the result with filename or domain rules when it needs a semantic type.

Text accepts valid UTF-8 and BOM-marked UTF-16. Tab, line feed, form feed, carriage return, and escape are the permitted C0 controls. Other C0 controls classify the input as binary. Invalid UTF-8 without a NUL is unknown with ReasonInvalidText; callers that need Latin-1 can apply their own fallback.

HTML, XML, and SVG signatures supply format metadata before the shared text rules run. The metadata remains present if malformed or control-bearing input is classified as unknown or binary.

Performance

The detector performs no allocations for the supplied fixtures. On an Apple M1 Pro with Go 1.26.5, a 4 KiB text input takes about 1.5 microseconds, the mixed 4 KiB fixture corpus averages about 0.77 microseconds per call, and a 1 MiB text input takes about 0.35 milliseconds. Importing and calling the package adds 16,640 bytes to a stripped minimal binary.

Run the package benchmarks on the target machine:

go test -run '^$' -bench . -benchmem

The implementation scans at most 512 bytes for registered signatures. Text validation is linear in the supplied byte count and uses fixed auxiliary memory.

Provenance

The signature matcher is adapted from Go 1.26.5's net/http.DetectContentType and the WHATWG MIME Sniffing Standard. The registry is intentionally limited to the formats listed above. NOTICE contains the source and license details.

License

MIT

Documentation

Overview

Package magic identifies the physical format and text encoding of file content.

Index

Examples

Constants

This section is empty.

Variables

This section is empty.

Functions

This section is empty.

Types

type Kind

type Kind string

Kind is the broad content class.

const (
	// KindUnknown means the bytes could not be classified as text or binary.
	KindUnknown Kind = "unknown"
	// KindText means the bytes satisfy the package's text rules.
	KindText Kind = "text"
	// KindBinary means the bytes have a binary signature or binary content.
	KindBinary Kind = "binary"
)

type Reason

type Reason string

Reason explains why a classification is provisional or unknown.

const (
	// ReasonNone means the classification is final for the supplied input.
	ReasonNone Reason = ""
	// ReasonNeedMore means more bytes could change a prefix classification.
	ReasonNeedMore Reason = "need-more"
	// ReasonInvalidText means the bytes are neither accepted text nor
	// recognised binary content.
	ReasonInvalidText Reason = "invalid-text"
)

type Result

type Result struct {
	Kind      Kind
	MIME      string
	Format    string
	Encoding  string
	Reason    Reason
	NeedBytes int
}

Result describes the physical format and text properties of content.

MIME never includes a charset parameter. Encoding uses lowercase registered names. Empty fields mean that the corresponding property was not identified.

func Detect

func Detect(data []byte) Result

Detect classifies data as the complete content of a file.

Example
package main

import (
	"fmt"

	"github.com/git-pkgs/magic"
)

func main() {
	result := magic.Detect([]byte("package main\n"))
	fmt.Println(result.Kind, result.Format, result.MIME, result.Encoding)

}
Output:
text text text/plain utf-8

func DetectPrefix

func DetectPrefix(prefix []byte) Result

DetectPrefix classifies an intentionally bounded file prefix.

ReasonNeedMore reports that later bytes could change the answer. NeedBytes is reserved for a known minimum total length and is zero in this release.

Example
package main

import (
	"fmt"

	"github.com/git-pkgs/magic"
)

func main() {
	result := magic.DetectPrefix([]byte("hello"))
	fmt.Println(result.Kind, result.Reason)

}
Output:
text need-more

Jump to

Keyboard shortcuts

? : This menu
/ : Search site
f or F : Jump to
y or Y : Canonical URL