|
| 1 | +# magic |
| 2 | + |
| 3 | +Pure Go content detection for files and bounded file prefixes. The package |
| 4 | +reports a physical format, MIME type, text encoding, and whether a prefix needs |
| 5 | +more bytes. It has no CGO, native runtime, filesystem, or third-party module |
| 6 | +dependency. |
| 7 | + |
| 8 | +## Install |
| 9 | + |
| 10 | +```bash |
| 11 | +go get github.com/git-pkgs/magic |
| 12 | +``` |
| 13 | + |
| 14 | +## Use |
| 15 | + |
| 16 | +`Detect` treats its byte slice as the complete file: |
| 17 | + |
| 18 | +```go |
| 19 | +result := magic.Detect(data) |
| 20 | + |
| 21 | +switch result.Kind { |
| 22 | +case magic.KindText: |
| 23 | + fmt.Println(result.Format, result.MIME, result.Encoding) |
| 24 | +case magic.KindBinary: |
| 25 | + fmt.Println(result.Format, result.MIME) |
| 26 | +case magic.KindUnknown: |
| 27 | + fmt.Println(result.Reason) |
| 28 | +} |
| 29 | +``` |
| 30 | + |
| 31 | +Call `DetectPrefix` when the bytes came from a bounded read: |
| 32 | + |
| 33 | +```go |
| 34 | +result := magic.DetectPrefix(prefix) |
| 35 | +if result.Reason == magic.ReasonNeedMore { |
| 36 | + // More bytes could change the result. |
| 37 | +} |
| 38 | +``` |
| 39 | + |
| 40 | +A complete binary signature can finish detection from a prefix. Text remains |
| 41 | +provisional because later bytes can contain a NUL, an invalid encoding, or a |
| 42 | +binary signature. `NeedBytes` is reserved for a known minimum total length and |
| 43 | +is zero in the first release. |
| 44 | + |
| 45 | +Both functions are safe for concurrent use. They retain no input and use no |
| 46 | +mutable package state. |
| 47 | + |
| 48 | +## Results |
| 49 | + |
| 50 | +`Kind` is `text`, `binary`, or `unknown`. `Format` and `MIME` describe the |
| 51 | +physical content. `Encoding` is set for accepted UTF-8, UTF-16LE, or UTF-16BE |
| 52 | +text and never appears as a MIME charset parameter. |
| 53 | + |
| 54 | +The first format registry contains: |
| 55 | + |
| 56 | +- ZIP, TAR, gzip, bzip2, xz, PDF, CFBF, PNG, JPEG, and GIF |
| 57 | +- plain text, HTML, XML, and SVG |
| 58 | + |
| 59 | +Detection uses bytes only. ZIP-based package types such as JAR, wheel, and |
| 60 | +NuGet remain `zip`, and compressed payloads are not opened. A caller can |
| 61 | +combine the result with filename or domain rules when it needs a semantic |
| 62 | +type. |
| 63 | + |
| 64 | +Text accepts valid UTF-8 and BOM-marked UTF-16. Tab, line feed, form feed, |
| 65 | +carriage return, and escape are the permitted C0 controls. Other C0 controls |
| 66 | +classify the input as binary. Invalid UTF-8 without a NUL is unknown with |
| 67 | +`ReasonInvalidText`; callers that need Latin-1 can apply their own fallback. |
| 68 | + |
| 69 | +HTML, XML, and SVG signatures supply format metadata before the shared text |
| 70 | +rules run. The metadata remains present if malformed or control-bearing input |
| 71 | +is classified as unknown or binary. |
| 72 | + |
| 73 | +## Performance |
| 74 | + |
| 75 | +The detector performs no allocations for the supplied fixtures. On an Apple |
| 76 | +M1 Pro with Go 1.26.5, a 4 KiB text input takes about 1.5 microseconds, the |
| 77 | +mixed 4 KiB fixture corpus averages about 0.77 microseconds per call, and a |
| 78 | +1 MiB text input takes about 0.35 milliseconds. Importing and calling the |
| 79 | +package adds 16,640 bytes to a stripped minimal binary. |
| 80 | + |
| 81 | +Run the package benchmarks on the target machine: |
| 82 | + |
| 83 | +```bash |
| 84 | +go test -run '^$' -bench . -benchmem |
| 85 | +``` |
| 86 | + |
| 87 | +The implementation scans at most 512 bytes for registered signatures. Text |
| 88 | +validation is linear in the supplied byte count and uses fixed auxiliary |
| 89 | +memory. |
| 90 | + |
| 91 | +## Provenance |
| 92 | + |
| 93 | +The signature matcher is adapted from Go 1.26.5's |
| 94 | +`net/http.DetectContentType` and the WHATWG MIME Sniffing Standard. The |
| 95 | +registry is intentionally limited to the formats listed above. [NOTICE](NOTICE) |
| 96 | +contains the source and license details. |
| 97 | + |
| 98 | +## License |
| 99 | + |
| 100 | +MIT |
0 commit comments