8 * file - determine type of file
10 #define LENDIAN(p) ((p)[0] | ((p)[1]<<8) | ((p)[2]<<16) | ((p)[3]<<24))
84 /* codes for 'mode' field in language structure */
87 First, /* first entry for language spanning several ranges */
88 Multi, /* later entries " " " ... */
89 Shared, /* codes used in several languages */
94 int mode; /* see enum above */
102 Normal, 0, 0x0100, 0x01FF, "Extended Latin",
103 Normal, 0, 0x0370, 0x03FF, "Greek",
104 Normal, 0, 0x0400, 0x04FF, "Cyrillic",
105 Normal, 0, 0x0530, 0x058F, "Armenian",
106 Normal, 0, 0x0590, 0x05FF, "Hebrew",
107 Normal, 0, 0x0600, 0x06FF, "Arabic",
108 Normal, 0, 0x0900, 0x097F, "Devanagari",
109 Normal, 0, 0x0980, 0x09FF, "Bengali",
110 Normal, 0, 0x0A00, 0x0A7F, "Gurmukhi",
111 Normal, 0, 0x0A80, 0x0AFF, "Gujarati",
112 Normal, 0, 0x0B00, 0x0B7F, "Oriya",
113 Normal, 0, 0x0B80, 0x0BFF, "Tamil",
114 Normal, 0, 0x0C00, 0x0C7F, "Telugu",
115 Normal, 0, 0x0C80, 0x0CFF, "Kannada",
116 Normal, 0, 0x0D00, 0x0D7F, "Malayalam",
117 Normal, 0, 0x0E00, 0x0E7F, "Thai",
118 Normal, 0, 0x0E80, 0x0EFF, "Lao",
119 Normal, 0, 0x1000, 0x105F, "Tibetan",
120 Normal, 0, 0x10A0, 0x10FF, "Georgian",
121 Normal, 0, 0x3040, 0x30FF, "Japanese",
122 Normal, 0, 0x3100, 0x312F, "Chinese",
123 First, 0, 0x3130, 0x318F, "Korean",
124 Multi, 0, 0x3400, 0x3D2F, "Korean",
125 Shared, 0, 0x4e00, 0x9fff, "CJK",
126 Normal, 0, 0, 0, 0, /* terminal entry */
132 Fascii, /* printable ascii */
134 Futf, /* UTF character set */
135 Fbinary, /* binary */
136 Feascii, /* ASCII with control chars */
137 Fnull, /* NULL in file */
140 void bump_utf_count(Rune);
141 int cistrncmp(char*, char*, int);
143 int getfontnum(uchar*, uchar**);
168 int p9bitnum(uchar*);
169 int p9subfont(uchar*);
170 void print_utf(void);
171 void type(char*, int);
175 int (*call[])(void) =
177 long0, /* recognizable by first 4 bytes */
178 istring, /* recognizable by first string */
179 iself, /* ELF (foreign) executable */
180 isexec, /* native executables */
181 iff, /* interchange file format (strings) */
182 longoff, /* recognizable by 4 bytes at some offset */
183 isoffstr, /* recognizable by string at some offset */
184 isrfc822, /* email file */
185 ismbox, /* mail box */
186 istar, /* recognizable by tar checksum */
187 ishtml, /* html keywords */
188 iscint, /* compiler/assembler intermediate */
189 islimbo, /* limbo source */
190 isc, /* c & alef compiler key words */
191 isas, /* assembler key words */
192 isp9font, /* plan 9 font */
193 isp9bit, /* plan 9 image (as from /dev/window) */
194 isrtf, /* rich text format */
195 ismsdos, /* msdos exe (virus file attachement) */
196 isicocur, /* windows icon or cursor file */
197 isface, /* ascii face file */
200 ismung, /* entropy compressed/encrypted */
201 isenglish, /* char frequency English */
207 char OCTET[] = "application/octet-stream\n";
208 char PLAIN[] = "text/plain\n";
211 main(int argc, char *argv[])
222 fprint(2, "usage: file [-m] [file...]\n");
227 if(mime == 0 || argc > 1){
228 for(i = 0; i < argc; i++) {
229 for (j = 0, cp = argv[i]; *cp; j++, cp += chartorune(&r, cp))
241 for(i = 0; i < argc; i++)
242 type(argv[i], maxlen);
248 type(char *file, int nlen)
256 for (i = 0, p = file; *p; i++) {
257 if (*p == '/') /* find rightmost slash */
259 p += chartorune(&r, p); /* count runes */
261 print("%s:%*s",file, nlen-i+1, "");
264 if ((fd = open(file, OREAD)) < 0) {
265 print("cannot open: %r\n");
273 * Unicode 4.0 4-byte runes.
282 fullrune1(char *p, int n)
290 if(n >= 2 && c < 0xE0)
292 if(n >= 3 && c < 0xF0)
301 chartorune1(Rune1 *rune, char *str)
303 int c, c1, c2, c3, n;
309 n = chartorune(&r, str);
314 c1 = *(uchar*)(str+1) & ~0x80;
315 c2 = *(uchar*)(str+2) & ~0x80;
316 c3 = *(uchar*)(str+3) & ~0x80;
317 n = (c<<18) | (c1<<12) | (c2<<6) | c3;
318 if(n < 0x10000 || n > 0x10FFFF){
336 print("cannot stat: %r\n");
339 if(mbuf->mode & DMDIR) {
340 print(mime ? OCTET : "directory\n");
343 if(mbuf->type != 'M' && mbuf->type != '|') {
344 print(mime ? OCTET : "special file #%C/%s\n",
345 mbuf->type, mbuf->name);
348 /* may be reading a pipe on standard input */
349 nbuf = readn(fd, buf, sizeof(buf)-1);
351 print("cannot read: %r\n");
355 print(mime ? PLAIN : "empty file\n");
361 * build histogram table
363 memset(cfreq, 0, sizeof(cfreq));
364 for (i = 0; language[i].name; i++)
365 language[i].count = 0;
366 eob = (char *)buf+nbuf;
367 for(n = 0, p = (char *)buf; p < eob; n++) {
368 if (!fullrune1(p, eob-p) && eob-p < UTFmax1)
370 p += chartorune1(&r, p);
373 else if (r <= 0x7f) {
374 if (!isprint(r) && !isspace(r))
375 f = Ceascii; /* ASCII control char */
377 } else if (r == 0x80) {
381 f = Cbinary; /* Invalid Runes */
383 f = Clatin; /* Latin 1 */
386 f = Cutf; /* UTF extension */
388 cfreq[f]++; /* ASCII chars peg directly */
395 else if (cfreq[Cutf])
397 else if (cfreq[Clatin])
399 else if (cfreq[Ceascii])
401 else if (cfreq[Cnull])
406 * lookup dictionary words
408 memset(wfreq, 0, sizeof(wfreq));
409 if(guess == Fascii || guess == Flatin || guess == Futf)
412 * call individual classify routines
414 for(i=0; call[i]; i++)
420 * print out gross classification
422 if (nbuf < 100 && !mime)
423 print(mime ? PLAIN : "short ");
425 print(mime ? PLAIN : "Ascii\n");
426 else if (guess == Feascii)
427 print(mime ? PLAIN : "extended ascii\n");
428 else if (guess == Flatin)
429 print(mime ? PLAIN : "latin ascii\n");
430 else if (guess == Futf && utf_count() < 4)
432 else print(mime ? OCTET : "binary\n");
436 bump_utf_count(Rune r)
440 high = sizeof(language)/sizeof(language[0])-1;
441 for (low = 0; low < high;) {
443 if (r >= language[mid].low) {
444 if (r <= language[mid].high) {
445 language[mid].count++;
458 for (i = 0; language[i].name; i++)
459 if (language[i].count > 0)
460 switch (language[i].mode) {
476 for (i = 'a'; i < 'z'; i++)
479 for (i = 'A'; i < 'Z'; i++)
486 find_first(char *name)
490 for (i = 0; language[i].name != 0; i++)
491 if (language[i].mode == First
492 && strcmp(language[i].name, name) == 0)
511 for (i = 0; language[i].name; i++)
512 if (language[i].count) {
513 switch(language[i].mode) {
515 j = find_first(language[i].name);
518 if (language[j].count > 0)
526 print("%s", language[i].name);
541 int low, high, mid, r;
546 while (p < buf+nbuf && !isalpha(*p))
551 while(p < buf+nbuf && isalpha(*p))
555 high = sizeof(dict)/sizeof(dict[0]);
556 for(low = 0;low < high;) {
558 r = strcmp(dict[mid].word, (char*)p2);
560 wfreq[dict[mid].class]++;
572 typedef struct Filemagic Filemagic;
581 * integers in this table must be as seen on a little-endian machine
582 * when read from a file.
584 Filemagic long0tab[] = {
585 0xF16DF16D, 0xFFFFFFFF, "pac1 audio file\n", OCTET,
587 0x31636170, 0xFFFFFFFF, "pac3 audio file\n", OCTET,
589 0x32630070, 0xFFFF00FF, "pac4 audio file\n", OCTET,
590 0xBA010000, 0xFFFFFFFF, "mpeg system stream\n", OCTET,
591 0x43614c66, 0xFFFFFFFF, "FLAC audio file\n", OCTET,
592 0x30800CC0, 0xFFFFFFFF, "inferno .dis executable\n", OCTET,
593 0x04034B50, 0xFFFFFFFF, "zip archive\n", "application/zip",
594 070707, 0xFFFF, "cpio archive\n", "application/x-cpio",
595 0x2F7, 0xFFFF, "tex dvi\n", "application/dvi",
596 0xfaff, 0xfeff, "mp3 audio\n", "audio/mpeg",
597 0xfeff0000, 0xffffffff, "utf-32be\n", "text/plain charset=utf-32be",
598 0xfffe, 0xffffffff, "utf-32le\n", "text/plain charset=utf-32le",
599 0xfeff, 0xffff, "utf-16be\n", "text/plain charset=utf-16be",
600 0xfffe, 0xffff, "utf-16le\n", "text/plain charset=utf-16le",
601 /* 0xfeedface: this could alternately be a Next Plan 9 boot image */
602 0xcefaedfe, 0xFFFFFFFF, "32-bit power Mach-O executable\n", OCTET,
604 0xcffaedfe, 0xFFFFFFFF, "64-bit power Mach-O executable\n", OCTET,
606 0xfeedface, 0xFFFFFFFF, "386 Mach-O executable\n", OCTET,
608 0xfeedfacf, 0xFFFFFFFF, "amd64 Mach-O executable\n", OCTET,
610 0xbebafeca, 0xFFFFFFFF, "Mach-O universal executable\n", OCTET,
612 * venti & fossil magic numbers are stored big-endian on disk,
613 * thus the numbers appear reversed in this table.
615 0xad4e5cd1, 0xFFFFFFFF, "venti arena\n", OCTET,
619 filemagic(Filemagic *tab, int ntab, ulong x)
623 for(i=0; i<ntab; i++)
624 if((x&tab[i].mask) == tab[i].x){
625 print(mime ? tab[i].mime : tab[i].desc);
634 return filemagic(long0tab, nelem(long0tab), LENDIAN(buf));
637 typedef struct Fileoffmag Fileoffmag;
644 * integers in this table must be as seen on a little-endian machine
645 * when read from a file.
647 Fileoffmag longofftab[] = {
649 * venti & fossil magic numbers are stored big-endian on disk,
650 * thus the numbers appear reversed in this table.
652 256*1024, 0xe7a5e4a9, 0xFFFFFFFF, "venti arenas partition\n", OCTET,
653 256*1024, 0xc75e5cd1, 0xFFFFFFFF, "venti index section\n", OCTET,
654 128*1024, 0x89ae7637, 0xFFFFFFFF, "fossil write buffer\n", OCTET,
655 4, 0x31647542, 0xFFFFFFFF, "OS X finder properties\n", OCTET,
659 fileoffmagic(Fileoffmag *tab, int ntab)
664 uchar buf[sizeof(long)];
666 for(i=0; i<ntab; i++) {
668 seek(fd, tp->off, 0);
669 if (readn(fd, buf, sizeof buf) != sizeof buf)
672 if((x&tp->mask) == tp->x){
673 print(mime? tp->mime: tp->desc);
683 return fileoffmagic(longofftab, nelem(longofftab));
691 seek(fd, 0, 0); /* reposition to start of file */
692 if(crackhdr(fd, &f)) {
693 print(mime ? OCTET : "%s\n", f.name);
701 enum { NAMSIZ = 100, TBLOCK = 512 };
716 char linkname[NAMSIZ];
717 /* rest are defined by POSIX's ustar format; see p1003.2b */
718 char magic[6]; /* "ustar" */
724 char prefix[155]; /* if non-null, path = prefix "/" name */
729 checksum(union hblock *hp)
733 struct header *hdr = &hp->dbuf;
735 for (cp = hdr->chksum; cp < &hdr->chksum[sizeof hdr->chksum]; cp++)
738 for (cp = hp->dummy; cp < &hp->dummy[TBLOCK]; cp++)
748 union hblock *hp = (union hblock *)tblock;
749 struct header *hdr = &hp->dbuf;
751 seek(fd, 0, 0); /* reposition to start of file */
752 if (readn(fd, tblock, sizeof tblock) != sizeof tblock)
754 chksum = strtol(hdr->chksum, 0, 8);
755 if (hdr->name[0] != '\0' && checksum(hp) == chksum) {
756 if (strcmp(hdr->magic, "ustar") == 0)
757 print(mime? "application/x-ustar\n": "posix tar archive\n");
759 print(mime? "application/x-tar\n": "tar archive\n");
766 * initial words to classify file
776 "\x1f\x9d", "compressed", 2, "application/x-compress",
777 "\x1f\x8b", "gzip compressed", 2, "application/x-gzip",
778 "BZh", "bzip2 compressed", 3, "application/x-bzip2",
779 "!<arch>\n__.SYMDEF", "archive random library", 16, "application/octet-stream",
780 "!<arch>\n", "archive", 8, "application/octet-stream",
781 "070707", "cpio archive - ascii header", 6, "application/octet-stream",
782 "#!/bin/rc", "rc executable file", 9, "text/plain",
783 "#!/bin/sh", "sh executable file", 9, "text/plain",
784 "%!", "postscript", 2, "application/postscript",
785 "\004%!", "postscript", 3, "application/postscript",
786 "x T post", "troff output for post", 8, "application/troff",
787 "x T Latin1", "troff output for Latin1", 10, "application/troff",
788 "x T utf", "troff output for UTF", 7, "application/troff",
789 "x T 202", "troff output for 202", 7, "application/troff",
790 "x T aps", "troff output for aps", 7, "application/troff",
791 "GIF", "GIF image", 3, "image/gif",
792 "\0PC Research, Inc\0", "ghostscript fax file", 18, "application/ghostscript",
793 "%PDF", "PDF", 4, "application/pdf",
794 "<!DOCTYPE", "HTML file", 9, "text/html",
795 "<!doctype", "HTML file", 9, "text/html",
796 "<!--", "HTML file", 4, "text/html",
797 "<html>", "HTML file", 6, "text/html",
798 "<HTML>", "HTML file", 6, "text/html",
799 "<?xml", "HTML file", 5, "text/html",
800 "\111\111\052\000", "tiff", 4, "image/tiff",
801 "\115\115\000\052", "tiff", 4, "image/tiff",
802 "\377\330\377\340", "jpeg", 4, "image/jpeg",
803 "\377\330\377\341", "jpeg", 4, "image/jpeg",
804 "\377\330\377\333", "jpeg", 4, "image/jpeg",
805 "BM", "bmp", 2, "image/bmp",
806 "\xD0\xCF\x11\xE0\xA1\xB1\x1A\xE1", "microsoft office document", 8, "application/doc",
807 "<MakerFile ", "FrameMaker file", 11, "application/framemaker",
808 "\033E\033", "HP PCL printer data", 3, OCTET,
809 "\033%-12345X", "HPJCL file", 9, "application/hpjcl",
810 "ID3", "mp3 audio with id3", 3, "audio/mpeg",
811 "\211PNG", "PNG image", 4, "image/png",
812 "P3\n", "ppm", 3, "image/ppm",
813 "P6\n", "ppm", 3, "image/ppm",
814 "/* XPM */\n", "xbm", 10, "image/xbm",
815 ".HTML ", "troff -ms input", 6, "text/troff",
816 ".LP", "troff -ms input", 3, "text/troff",
817 ".ND", "troff -ms input", 3, "text/troff",
818 ".PP", "troff -ms input", 3, "text/troff",
819 ".TL", "troff -ms input", 3, "text/troff",
820 ".TR", "troff -ms input", 3, "text/troff",
821 ".TH", "manual page", 3, "text/troff",
822 ".\\\"", "troff input", 3, "text/troff",
823 ".de", "troff input", 3, "text/troff",
824 ".if", "troff input", 3, "text/troff",
825 ".nr", "troff input", 3, "text/troff",
826 ".tr", "troff input", 3, "text/troff",
827 "vac:", "venti score", 4, "text/plain",
828 "-----BEGIN CERTIFICATE-----\n",
829 "pem certificate", -1, "text/plain",
830 "-----BEGIN TRUSTED CERTIFICATE-----\n",
831 "pem trusted certificate", -1, "text/plain",
832 "-----BEGIN X509 CERTIFICATE-----\n",
833 "pem x.509 certificate", -1, "text/plain",
834 "subject=/C=", "pem certificate with header", -1, "text/plain",
835 "process snapshot ", "process snapshot", -1, "application/snapfs",
836 "d8:announce", "torrent file", 11, "application/x-bittorrent",
837 "[playlist]", "playlist", 10, "application/x-scpls",
838 "#EXTM3U", "playlist", 7, "audio/x-mpegurl",
846 struct FILE_STRING *p;
848 for(p = file_string; p->key; p++) {
852 if(nbuf >= l && memcmp(buf, p->key, l) == 0) {
854 print("%s\n", p->mime);
856 print("%s\n", p->filetype);
860 if(strncmp((char*)buf, "TYPE=", 5) == 0) { /* td */
861 for(i = 5; i < nbuf; i++)
867 print("%.*s picture\n", utfnlen((char*)buf+5, i-5), (char*)buf+5);
878 32*1024, "\001CD001\001", "ISO9660 CD image", 7, "application/x-iso9660-image",
889 for(p = offstrs; p->key; p++) {
894 if (readn(fd, buf, n) != n)
896 if(memcmp(buf, p->key, n) == 0) {
898 print("%s\n", p->mime);
900 print("%s\n", p->filetype);
910 if (strncmp((char*)buf, "FORM", 4) == 0 &&
911 strncmp((char*)buf+8, "AIFF", 4) == 0) {
912 print("%s\n", mime? "audio/x-aiff": "aiff audio");
915 if (strncmp((char*)buf, "RIFF", 4) == 0) {
916 if (strncmp((char*)buf+8, "WAVE", 4) == 0)
917 print("%s\n", mime? "audio/wave": "wave audio");
918 else if (strncmp((char*)buf+8, "AVI ", 4) == 0)
919 print("%s\n", mime? "video/avi": "avi video");
921 print("%s\n", mime? "application/octet-stream":
928 char* html_string[] = {
930 "!DOCTYPE", "![CDATA[", "basefont", "frameset", "noframes", "textarea",
932 "button", "center", "iframe", "object", "option", "script",
934 "blink", "embed", "frame", "input", "label", "param", "small",
935 "style", "table", "tbody", "tfoot", "thead", "title",
936 "?xml", "body", "code", "font", "form", "head", "html",
937 "link", "menu", "meta", "span",
938 "!--", "big", "dir", "div", "img", "pre", "sub", "sup",
939 "br", "dd", "dl", "dt", "em", "h1", "h2", "h3", "h4", "h5",
940 "h6", "hr", "li", "ol", "td", "th", "tr", "tt", "ul",
941 "a", "b", "i", "p", "q", "u",
954 while(p < buf+nbuf && *p != '<')
963 for(i = 0; html_string[i]; i++){
964 n = strlen(html_string[i]);
967 if(cistrncmp(html_string[i], (char*)p, n) == 0) {
969 if(p < buf+nbuf && strchr("\t\r\n />", *p)){
971 print(mime ? "text/html\n" : "HTML file\n");
982 char* rfc822_string[] =
1004 q = strchr(p, '\n');
1008 if(p == (char*)buf && strncmp(p, "From ", 5) == 0 && strstr(p, " remote from ")){
1015 if(*p != '\t' && *p != ' '){
1019 for(i = 0; rfc822_string[i]; i++) {
1020 if(cistrncmp(p, rfc822_string[i], strlen(rfc822_string[i])) == 0){
1029 print(mime ? "message/rfc822\n" : "email file\n");
1041 q = strchr(p, '\n');
1045 if(strncmp(p, "From ", 5) == 0 && strstr(p, " remote from ") == nil){
1046 print(mime ? "text/plain\n" : "mail box\n");
1060 if(Binit(&b, fd, OREAD) == Beof)
1063 type = objtype(&b, &name);
1069 print("%s intermediate\n", name);
1082 if(n >= 2 && wfreq[I2] >= n && wfreq[I3] >= n && cfreq['.'] >= n)
1084 if(n >= 1 && wfreq[Alword] >= n && wfreq[I3] >= n && cfreq['.'] >= n)
1089 if(wfreq[Cword] >= 5 && cfreq[';'] >= 5)
1094 if(cfreq[';'] >= 10 && cfreq['='] >= 10 && wfreq[Cword] >= 1)
1103 if(wfreq[Alword] > 0)
1104 print("alef program\n");
1106 print("c program\n");
1117 if(wfreq[Lword] < 4)
1119 print(mime ? PLAIN : "limbo program\n");
1130 if(wfreq[Aword] < 2)
1132 print(mime ? PLAIN : "as program\n");
1137 * low entropy means encrypted
1147 memset(bucket, 0, sizeof(bucket));
1148 for(i=nbuf-64; i<nbuf; i++)
1149 bucket[(buf[i]>>5)&07] += 1;
1153 cs += (bucket[i]-8)*(bucket[i]-8);
1156 if(buf[0]==0x1f && buf[1]==0x9d)
1157 print(mime ? "application/x-compress" : "compressed\n");
1159 if(buf[0]==0x1f && buf[1]==0x8b)
1160 print(mime ? "application/x-gzip" : "gzip compressed\n");
1162 if(buf[0]=='B' && buf[1]=='Z' && buf[2]=='h')
1163 print(mime ? "application/x-bzip2" : "bzip2 compressed\n");
1165 if(buf[0]==0x78 && buf[1]==0x9c)
1166 print(mime ? "application/x-deflate" : "zlib compressed\n");
1168 print(mime ? OCTET : "encrypted\n");
1175 * english by punctuation and frequencies
1180 int vow, comm, rare, badpun, punct;
1183 if(guess != Fascii && guess != Feascii)
1187 for(p = (char *)buf; p < (char *)buf+nbuf-1; p++)
1197 if(p[1] != ' ' && p[1] != '\n')
1200 if(badpun*5 > punct)
1202 if(cfreq['>']+cfreq['<']+cfreq['/'] > cfreq['e']) /* shell file test */
1204 if(2*cfreq[';'] > cfreq['e'])
1208 for(p="AEIOU"; *p; p++) {
1210 vow += cfreq[tolower(*p)];
1213 for(p="ETAION"; *p; p++) {
1215 comm += cfreq[tolower(*p)];
1218 for(p="VJKQXZ"; *p; p++) {
1220 rare += cfreq[tolower(*p)];
1222 if(vow*5 >= nbuf-cfreq[' '] && comm >= 10*rare) {
1223 print(mime ? PLAIN : "English text\n");
1230 * pick up a number with
1260 depthof(char *s, int *newp)
1267 while(s<es && *s==' ')
1271 if('0'<=*s && *s<='9')
1272 return 1<<strtol(s, 0, 0);
1276 while(s<es && *s!=' '){
1277 s++; /* skip letter */
1278 d += strtoul(s, &s, 10);
1281 if(d % 8 == 0 || 8 % d == 0)
1290 int dep, lox, loy, hix, hiy, px, new, cmpr;
1300 if(memcmp(cp, "compressed\n", 11) == 0) {
1305 dep = depthof((char*)cp + 0*P9BITLEN, &new);
1308 lox = p9bitnum(cp + 1*P9BITLEN);
1309 loy = p9bitnum(cp + 2*P9BITLEN);
1310 hix = p9bitnum(cp + 3*P9BITLEN);
1311 hiy = p9bitnum(cp + 4*P9BITLEN);
1312 if(dep < 0 || lox < 0 || loy < 0 || hix < 0 || hiy < 0)
1316 px = 8/dep; /* pixels per byte */
1317 /* set l to number of bytes of data per scan line */
1319 len = (hix+px-1)/px - lox/px;
1320 else{ /* make positive before divide */
1323 len = (t+hix+px-1)/px;
1326 len = (hix-lox)*dep/8;
1327 len *= hiy - loy; /* col length */
1328 len += 5 * P9BITLEN; /* size of initial ascii */
1331 * for compressed images, don't look any further. otherwise:
1332 * for image file, length is non-zero and must match calculation above.
1333 * for /dev/window and /dev/screen the length is always zero.
1334 * for subfont, the subfont header should follow immediately.
1337 print(mime ? "image/p9bit\n" : "Compressed %splan 9 image or subfont, depth %d\n",
1342 * mbuf->length == 0 probably indicates reading a pipe.
1343 * Ghostscript sometimes produces a little extra on the end.
1345 if (len != 0 && (mbuf->length == 0 || mbuf->length == len ||
1346 mbuf->length > len && mbuf->length < len+P9BITLEN)) {
1347 print(mime ? "image/p9bit\n" : "%splan 9 image, depth %d\n", newlabel, dep);
1350 if (p9subfont(buf+len)) {
1351 print(mime ? "image/p9bit\n" : "%ssubfont file, depth %d\n", newlabel, dep);
1362 /* if image too big, assume it's a subfont */
1363 if (p+3*P9BITLEN > buf+sizeof(buf))
1366 n = p9bitnum(p + 0*P9BITLEN); /* char count */
1369 h = p9bitnum(p + 1*P9BITLEN); /* height */
1372 a = p9bitnum(p + 2*P9BITLEN); /* ascent */
1378 #define WHITESPACE(c) ((c) == ' ' || (c) == '\t' || (c) == '\n')
1385 char pathname[1024];
1388 if (!getfontnum(cp, &cp)) /* height */
1390 if (!getfontnum(cp, &cp)) /* ascent */
1392 for (i = 0; cp=(uchar*)strchr((char*)cp, '\n'); i++) {
1393 if (!getfontnum(cp, &cp)) /* min */
1395 if (!getfontnum(cp, &cp)) /* max */
1397 getfontnum(cp, &cp); /* optional offset */
1398 while (WHITESPACE(*cp))
1400 for (p = cp; *cp && !WHITESPACE(*cp); cp++)
1402 /* construct a path name, if needed */
1404 if (*p != '/' && slash) {
1406 if (n < sizeof(pathname))
1407 memcpy(pathname, fname, n);
1410 if (n+cp-p+4 < sizeof(pathname)) {
1411 memcpy(pathname+n, p, cp-p);
1414 if (access(pathname, AEXIST) < 0) {
1415 strcpy(pathname+n, ".0");
1416 if (access(pathname, AEXIST) < 0)
1422 print(mime ? "text/plain\n" : "font file\n");
1429 getfontnum(uchar *cp, uchar **rp)
1431 while (WHITESPACE(*cp)) /* extract ulong delimited by whitespace */
1433 if (*cp < '0' || *cp > '9')
1435 strtoul((char *)cp, (char **)rp, 0);
1436 if (!WHITESPACE(**rp)) {
1446 if(strstr((char *)buf, "\\rtf1")){
1447 print(mime ? "application/rtf\n" : "rich text format\n");
1456 if (buf[0] == 0x4d && buf[1] == 0x5a){
1457 print(mime ? "application/x-msdownload\n" : "MSDOS executable\n");
1466 if(buf[0] || buf[1] || buf[3] || buf[9])
1468 if(buf[4] == 0x00 && buf[5] == 0x00)
1472 print(mime ? "image/x-icon\n" : "Microsoft icon file\n");
1475 print(mime ? "image/x-icon\n" : "Microsoft cursor file\n");
1484 static char *cpu[] = { /* NB: incomplete and arbitary list */
1507 static char *type[] = {
1508 [1] "relocatable object",
1510 [3] "shared library",
1514 if (memcmp(buf, "\x7fELF", 4) == 0){
1517 int n = (buf[19] << 8) | buf[18];
1518 char *p = "unknown";
1519 char *t = "unknown";
1521 if (n > 0 && n < nelem(cpu) && cpu[n])
1524 /* try the other byte order */
1526 n = (buf[18] << 8) | buf[19];
1527 if (n > 0 && n < nelem(cpu) && cpu[n])
1531 n = (buf[16]<< 8) | buf[17];
1533 n = (buf[17]<< 8) | buf[16];
1535 if(n>0 && n < nelem(type) && type[n])
1537 print("%s ELF %s\n", p, t);
1540 print("application/x-elf-executable");
1550 int i, j, ldepth, l;
1554 for(j = 0; j < 3; j++){
1555 for(p = (char*)buf, i=0; i<3; i++){
1556 if(p[0] != '0' || p[1] != 'x')
1560 else if(buf[2+4] == ',')
1571 while(*p == ' ' || *p == '\t')
1579 print("application/x-face\n");
1581 print("face image depth %d\n", ldepth);