@@ -8,11 +8,26 @@ export function detect(bytes: Uint8Array) {
88 if ( startsWith ( bytes , [ 0x25 , 0x50 , 0x44 , 0x46 , 0x2d ] ) ) return "application/pdf"
99 if ( startsWith ( bytes , [ 0x52 , 0x49 , 0x46 , 0x46 ] ) && startsWith ( bytes . subarray ( 8 ) , [ 0x57 , 0x45 , 0x42 , 0x50 ] ) )
1010 return "image/webp"
11- if (
12- startsWith ( bytes . subarray ( 4 ) , [ 0x66 , 0x74 , 0x79 , 0x70 ] ) &&
13- ( startsWith ( bytes . subarray ( 8 ) , [ 0x61 , 0x76 , 0x69 , 0x66 ] ) || startsWith ( bytes . subarray ( 8 ) , [ 0x61 , 0x76 , 0x69 , 0x73 ] ) )
14- )
15- return "image/avif"
11+ if ( bytes . length >= 12 && ascii ( bytes , 4 , 8 ) === "ftyp" ) {
12+ // AVIF, HEIC, QuickTime and M4A share MP4's container; the major brand tells them apart, and generic HEIF brands
13+ // list `avif`/`avis` among the compatible brands that follow the minor version.
14+ const brand = ascii ( bytes , 8 , 12 )
15+ const boxEnd = Math . min ( new DataView ( bytes . buffer , bytes . byteOffset ) . getUint32 ( 0 ) , bytes . length )
16+ const compatible = Array . from ( { length : Math . floor ( ( boxEnd - 16 ) / 4 ) } , ( _ , index ) =>
17+ ascii ( bytes , 16 + index * 4 , 20 + index * 4 ) ,
18+ )
19+ const generic = brand === "mif1" || brand === "msf1"
20+ if (
21+ brand === "avif" ||
22+ brand === "avis" ||
23+ ( generic && ( compatible . includes ( "avif" ) || compatible . includes ( "avis" ) ) )
24+ )
25+ return "image/avif"
26+ if ( generic || [ "heic" , "heix" , "hevc" , "hevx" ] . includes ( brand ) ) return "image/heic"
27+ if ( brand === "qt " ) return "video/quicktime"
28+ if ( brand === "M4A " ) return "audio/mp4"
29+ return "video/mp4"
30+ }
1631 return isText ( bytes ) ? "text/plain" : "application/octet-stream"
1732}
1833
@@ -26,6 +41,10 @@ export const isTextual = (mime: string) =>
2641 mime === "application/javascript" ||
2742 mime === "application/x-javascript"
2843
44+ function ascii ( bytes : Uint8Array , start : number , end : number ) {
45+ return String . fromCharCode ( ...bytes . subarray ( start , end ) )
46+ }
47+
2948function startsWith ( bytes : Uint8Array , prefix : number [ ] ) {
3049 return prefix . every ( ( value , index ) => bytes [ index ] === value )
3150}
0 commit comments