19 #include "kmimemagic.h"
21 #include <kapplication.h>
23 #include <ksimpleconfig.h>
24 #include <kstandarddirs.h>
25 #include <kstaticdeleter.h>
26 #include <klargefile.h>
29 static int fsmagic(
struct config_rec* conf,
const char *fn, KDE_struct_stat *sb);
30 static void process(
struct config_rec* conf,
const TQString &);
31 static int ascmagic(
struct config_rec* conf,
unsigned char *buf,
int nbytes);
32 static int tagmagic(
unsigned char *buf,
int nbytes);
33 static int textmagic(
struct config_rec* conf,
unsigned char *,
int);
35 static void tryit(
struct config_rec* conf,
unsigned char *buf,
int nb);
36 static int match(
struct config_rec* conf,
unsigned char *,
int);
39 static KStaticDeleter<KMimeMagic> kmimemagicsd;
48 void KMimeMagic::initStatic()
50 s_pSelf = kmimemagicsd.setObject( s_pSelf,
new KMimeMagic() );
58 #include <sys/types.h>
76 #if (defined DEBUG_MIMEMAGIC || defined DEBUG_APPRENTICE)
77 #define DEBUG_LINENUMBERS
83 #define MIME_BINARY_UNKNOWN "application/octet-stream"
84 #define MIME_BINARY_UNREADABLE "application/x-unreadable"
85 #define MIME_BINARY_ZEROSIZE "application/x-zerosize"
86 #define MIME_TEXT_UNKNOWN "text/plain"
87 #define MIME_TEXT_PLAIN "text/plain"
88 #define MIME_INODE_DIR "inode/directory"
89 #define MIME_INODE_CDEV "inode/chardevice"
90 #define MIME_INODE_BDEV "inode/blockdevice"
91 #define MIME_INODE_FIFO "inode/fifo"
92 #define MIME_INODE_LINK "inode/link"
93 #define MIME_INODE_SOCK "inode/socket"
95 #define MIME_APPL_TROFF "application/x-troff"
96 #define MIME_APPL_TAR "application/x-tar"
97 #define MIME_TEXT_FORTRAN "text/x-fortran"
99 #define MAXMIMESTRING 256
105 typedef union VALUETYPE {
116 #ifdef DEBUG_LINENUMBERS
165 #define RECORDSIZE 512
171 char charptr[RECORDSIZE];
181 char linkname[NAMSIZ];
191 #define TMAGIC "ustar "
196 static int is_tar(
unsigned char *,
int);
197 static unsigned long signextend(
struct magic *,
unsigned long);
198 static int getvalue(
struct magic *,
char **);
199 static int hextoint(
int);
200 static char *getstr(
char *,
char *,
int,
int *);
201 static int mget(
union VALUETYPE *,
unsigned char *,
struct magic *,
int);
202 static int mcheck(
union VALUETYPE *,
struct magic *);
203 static int mconvert(
union VALUETYPE *,
struct magic *);
204 static long from_oct(
int,
char *);
234 #define FLAG_STRONG 0x1000
249 typedef struct asc_type {
255 static const asc_type types[] = {
256 {
"text/html", 19, 2 },
257 {
"text/x-c", 13, 1 },
258 {
"text/x-makefile", 4, 1.9 },
259 {
"text/x-pli", 1, 3 },
260 {
"text/x-assembler", 6, 2.1 },
261 {
"text/x-pascal", 1, 1 },
262 {
"text/x-java", 12, 1 },
263 {
"text/x-c++", 19, 1 },
264 {
"message/rfc822", 4, 1.9 },
265 {
"message/news", 3, 2 },
266 {
"text/x-diff", 4, 2 },
267 {
"text/x-objc", 10, 1 }
270 #define NTYPES (sizeof(types)/sizeof(asc_type))
272 static struct names {
277 "<html", L_HTML | FLAG_STRONG
280 "<HTML", L_HTML | FLAG_STRONG
346 "<script", L_HTML | FLAG_STRONG
349 "<SCRIPT", L_HTML | FLAG_STRONG
352 "/*", L_C|L_CPP|L_JAVA|L_OBJC
355 "//", L_C|L_CPP|L_JAVA|L_OBJC
358 "#include", L_C|L_CPP
370 "char", L_C|L_CPP|L_JAVA|L_OBJC
373 "int", L_C|L_CPP|L_JAVA|L_OBJC
376 "float", L_C|L_CPP|L_JAVA|L_OBJC
379 "void", L_C|L_CPP|L_JAVA|L_OBJC
400 "class", L_CPP|L_JAVA
403 "public", L_CPP|L_JAVA
406 "private", L_CPP|L_JAVA
424 "@implementation", L_OBJC
445 "exec_prefix", L_MAKE
482 "Return-Path:", L_MAIL
488 "Newsgroups:", L_NEWS
494 "Organization:", L_NEWS
523 class KMimeMagicUtimeConf
526 KMimeMagicUtimeConf()
528 tmpDirs << TQString::fromLatin1(
"/tmp");
532 TQStringList confDirs = KGlobal::dirs()->resourceDirs(
"config" );
533 if ( !confDirs.isEmpty() )
535 TQString globalConf = confDirs.last() +
"kmimemagicrc";
536 if ( TQFile::exists( globalConf ) )
538 KSimpleConfig cfg( globalConf );
539 cfg.setGroup(
"Settings" );
540 tmpDirs = cfg.readListEntry(
"atimeDirs" );
542 if ( confDirs.count() > 1 )
544 TQString localConf = confDirs.first() +
"kmimemagicrc";
545 if ( TQFile::exists( localConf ) )
547 KSimpleConfig cfg( localConf );
548 cfg.setGroup(
"Settings" );
549 tmpDirs += cfg.readListEntry(
"atimeDirs" );
552 for ( TQStringList::Iterator it = tmpDirs.begin() ; it != tmpDirs.end() ; ++it )
555 if ( !dir.isEmpty() && dir[ dir.length()-1 ] !=
'/' )
561 for ( TQStringList::Iterator it = tmpDirs.begin() ; it != tmpDirs.end() ; ++it )
562 kdDebug(7018) <<
" atimeDir: " << *it << endl;
566 bool restoreAccessTime(
const TQString & file )
const
568 TQString dir = file.left( file.findRev(
'/' ) );
569 bool res = tmpDirs.contains( dir );
573 TQStringList tmpDirs;
584 KMimeMagicUtimeConf * utimeConf;
587 #ifdef MIME_MAGIC_DEBUG_TABLE
592 struct magic *prevm = NULL;
594 kdDebug(7018) <<
"test_table : started" << endl;
595 for (m = conf->magic; m; m = m->next) {
596 if (isprint((((
unsigned long) m) >> 24) & 255) &&
597 isprint((((
unsigned long) m) >> 16) & 255) &&
598 isprint((((
unsigned long) m) >> 8) & 255) &&
599 isprint(((
unsigned long) m) & 255)) {
602 (((
unsigned long) m) >> 24) & 255,
603 (((
unsigned long) m) >> 16) & 255,
604 (((
unsigned long) m) >> 8) & 255,
605 ((
unsigned long) m) & 255,
606 prevm ? prevm->lineno : -1);
614 #define EATAB {while (isascii((unsigned char) *l) && \
615 isspace((unsigned char) *l)) ++l;}
617 int KMimeMagic::parse_line(
char *line,
int *rule,
int lineno)
623 line[strlen(line) - 1] =
'\0';
627 while (line[ws_offset] && isspace(line[ws_offset])) {
632 if (line[ws_offset] == 0) {
636 if (line[ws_offset] ==
'#')
643 return (parse(line + ws_offset, lineno) != 0);
649 int KMimeMagic::apprentice(
const TQString& magicfile )
652 char line[BUFSIZ + 1];
658 if (magicfile.isEmpty())
660 fname = TQFile::encodeName(magicfile);
661 f = fopen(fname,
"r");
663 kdError(7018) <<
"can't read magic file " << fname.data() <<
": " << strerror(errno) << endl;
668 for (lineno = 1; fgets(line, BUFSIZ, f) != NULL; lineno++)
669 if (parse_line(line, &rule, lineno))
674 #ifdef DEBUG_APPRENTICE
675 kdDebug(7018) <<
"apprentice: conf=" << conf <<
" file=" << magicfile <<
" m=" << (conf->magic ?
"set" :
"NULL") <<
" m->next=" << ((conf->magic && conf->magic->next) ?
"set" :
"NULL") <<
" last=" << (conf->last ?
"set" :
"NULL") << endl;
676 kdDebug(7018) <<
"apprentice: read " << lineno <<
" lines, " << rule <<
" rules, " << errs <<
" errors" << endl;
679 #ifdef MIME_MAGIC_DEBUG_TABLE
683 return (errs ? -1 : 0);
686 int KMimeMagic::buff_apprentice(
char *buff)
688 char line[BUFSIZ + 2];
695 int len = strlen(buff) + 1;
699 count = (len > BUFSIZ-1)?BUFSIZ-1:len;
700 strncpy(line, start, count);
702 if ((end = strchr(line,
'\n'))) {
704 count = strlen(line);
709 if (parse_line(line, &rule, lineno))
714 #ifdef DEBUG_APPRENTICE
715 kdDebug(7018) <<
"buff_apprentice: conf=" << conf <<
" m=" << (conf->magic ?
"set" :
"NULL") <<
" m->next=" << ((conf->magic && conf->magic->next) ?
"set" :
"NULL") <<
" last=" << (conf->last ?
"set" :
"NULL") << endl;
716 kdDebug(7018) <<
"buff_apprentice: read " << lineno <<
" lines, " << rule <<
" rules, " << errs <<
" errors" << endl;
719 #ifdef MIME_MAGIC_DEBUG_TABLE
723 return (errs ? -1 : 0);
730 signextend(
struct magic *m,
unsigned long v)
732 if (!(m->flag & UNSIGNED))
758 kdError(7018) <<
"" <<
"signextend" <<
": can't happen: m->type=" << m->type << endl;
767 int KMimeMagic::parse(
char *l,
int
768 #ifdef DEBUG_LINENUMBERS
778 if ((m = (
struct magic *) calloc(1,
sizeof(
struct magic))) == NULL) {
779 kdError(7018) <<
"parse: Out of memory." << endl;
784 if (!conf->magic || !conf->last) {
785 conf->magic = conf->last = m;
787 conf->last->next = m;
794 #ifdef DEBUG_LINENUMBERS
803 if (m->cont_level != 0 && *l ==
'(') {
808 m->offset = (int) strtol(l, &t, 0);
810 kdError(7018) <<
"parse: offset " << l <<
" invalid" << endl;
814 if (m->flag & INDIR) {
832 kdError(7018) <<
"parse: indirect offset type " << *l <<
" invalid" << endl;
838 if (*l ==
'+' || *l ==
'-')
840 if (isdigit((
unsigned char) *l)) {
841 m->in.offset = strtol(l, &t, 0);
843 m->in.offset = -m->in.offset;
847 kdError(7018) <<
"parse: missing ')' in indirect offset" << endl;
851 while (isascii((
unsigned char) *l) && isdigit((
unsigned char) *l))
872 if (strncmp(l,
"byte", NBYTE) == 0) {
875 }
else if (strncmp(l,
"short", NSHORT) == 0) {
878 }
else if (strncmp(l,
"long", NLONG) == 0) {
881 }
else if (strncmp(l,
"string", NSTRING) == 0) {
884 }
else if (strncmp(l,
"date", NDATE) == 0) {
887 }
else if (strncmp(l,
"beshort", NBESHORT) == 0) {
890 }
else if (strncmp(l,
"belong", NBELONG) == 0) {
893 }
else if (strncmp(l,
"bedate", NBEDATE) == 0) {
896 }
else if (strncmp(l,
"leshort", NLESHORT) == 0) {
899 }
else if (strncmp(l,
"lelong", NLELONG) == 0) {
902 }
else if (strncmp(l,
"ledate", NLEDATE) == 0) {
906 kdError(7018) <<
"parse: type " << l <<
" invalid" << endl;
912 m->mask = signextend(m, strtol(l, &l, 0));
914 m->mask = (
unsigned long) ~0L;
928 if (m->type != STRING) {
935 if (*l ==
'x' && isascii((
unsigned char) l[1]) &&
936 isspace((
unsigned char) l[1])) {
956 }
else if ((l[0] ==
'\\') && (l[1] ==
'b')) {
963 while (*l !=
'\0' && *l !=
'#' && i < MAXDESC-1)
967 while (--i>0 && isspace( m->desc[i] ))
973 #ifdef DEBUG_APPRENTICE
974 kdDebug(7018) <<
"parse: line=" << lineno <<
" m=" << m <<
" next=" << m->next <<
" cont=" << m->cont_level <<
" desc=" << (m->desc ? m->desc :
"NULL") << endl;
985 getvalue(
struct magic *m,
char **p)
989 if (m->type == STRING) {
990 *p = getstr(*p, m->value.s,
sizeof(m->value.s), &slen);
992 }
else if (m->reln !=
'x')
993 m->value.l = signextend(m, strtol(*p, p, 0));
1003 getstr(
register char *s,
register char *p,
int plen,
int *slen)
1007 char *pmax = p + plen - 1;
1011 while ((c = *s++) !=
'\0') {
1012 if (isspace((
unsigned char) c))
1015 kdError(7018) <<
"String too long: " << origs << endl;
1063 if (c >=
'0' && c <=
'7') {
1064 val = (val << 3) | (c -
'0');
1066 if (c >=
'0' && c <=
'7')
1067 val = (val << 3) | (c -
'0');
1083 val = (val << 4) + c;
1086 val = (val << 4) + c;
1112 if (!isascii((
unsigned char) c))
1114 if (isdigit((
unsigned char) c))
1116 if ((c >=
'a') && (c <=
'f'))
1117 return c + 10 -
'a';
1118 if ((c >=
'A') && (c <=
'F'))
1119 return c + 10 -
'A';
1127 mconvert(
union VALUETYPE *p,
struct magic *m)
1134 p->s[
sizeof(p->s) - 1] =
'\0';
1136 #ifndef WORDS_BIGENDIAN
1140 p->h = (short) ((p->hs[0] << 8) | (p->hs[1]));
1142 #ifndef WORDS_BIGENDIAN
1149 ((p->hl[0] << 24) | (p->hl[1] << 16) | (p->hl[2] << 8) | (p->hl[3]));
1151 #ifdef WORDS_BIGENDIAN
1155 p->h = (short) ((p->hs[1] << 8) | (p->hs[0]));
1157 #ifdef WORDS_BIGENDIAN
1164 ((p->hl[3] << 24) | (p->hl[2] << 16) | (p->hl[1] << 8) | (p->hl[0]));
1167 kdError(7018) <<
"mconvert: invalid type " << m->type << endl;
1174 mget(
union VALUETYPE *p,
unsigned char *s,
struct magic *m,
1177 long offset = m->offset;
1181 if ( offset + 1 > nbytes-1 )
1187 if ( offset + 2 > nbytes-1 )
1196 if ( offset + 4 > nbytes-1 )
1206 if (offset + (
int)
sizeof(
union VALUETYPE) > nbytes)
1208 int have = nbytes - offset;
1209 memset(p, 0,
sizeof(
union VALUETYPE));
1211 memcpy(p, s + offset, have);
1213 memcpy(p, s + offset,
sizeof(
union VALUETYPE));
1215 if (!mconvert(p, m))
1218 if (m->flag & INDIR) {
1220 switch (m->in.type) {
1222 offset = p->b + m->in.offset;
1225 offset = p->h + m->in.offset;
1228 offset = p->l + m->in.offset;
1232 if (offset + (
int)
sizeof(
union VALUETYPE) > nbytes)
1235 memcpy(p, s + offset,
sizeof(
union VALUETYPE));
1237 if (!mconvert(p, m))
1244 mcheck(
union VALUETYPE *p,
struct magic *m)
1246 register unsigned long l = m->value.l;
1247 register unsigned long v;
1250 if ((m->value.s[0] ==
'x') && (m->value.s[1] ==
'\0')) {
1251 kdError(7018) <<
"BOINK" << endl;
1283 register unsigned char *a = (
unsigned char *) m->value.s;
1284 register unsigned char *b = (
unsigned char *) p->s;
1285 register int len = m->vallen;
1289 if ((v = *b++ - *a++) != 0)
1294 kdError(7018) <<
"mcheck: invalid type " << m->type << endl;
1298 qDebug(
"Before signextend %08x", v);
1300 v = signextend(m, v) & m->mask;
1302 qDebug(
"After signextend %08x", v);
1319 if (m->flag & UNSIGNED)
1322 matched = (long) v > (
long) l;
1326 if (m->flag & UNSIGNED)
1329 matched = (long) v < (
long) l;
1333 matched = (v & l) == l;
1337 matched = (v & l) != l;
1342 kdError(7018) <<
"mcheck: can't happen: invalid relation " << m->reln <<
"." << endl;
1354 void process(
struct config_rec* conf,
const TQString & fn)
1357 unsigned char buf[HOWMANY + 1];
1361 TQCString fileName = TQFile::encodeName( fn );
1366 if (fsmagic(conf, fileName, &sb) != 0) {
1370 if ((fd = KDE_open(fileName, O_RDONLY)) < 0) {
1377 conf->resultBuf = MIME_BINARY_UNREADABLE;
1383 if ((nbytes = read(fd, (
char *) buf, HOWMANY)) == -1) {
1384 kdError(7018) <<
"" << fn <<
" read failed (" << strerror(errno) <<
")." << endl;
1385 conf->resultBuf = MIME_BINARY_UNREADABLE;
1389 if ((tagbytes = tagmagic(buf, nbytes))) {
1391 lseek(fd, tagbytes, SEEK_SET);
1392 nbytes = read(fd, (
char*)buf, HOWMANY);
1394 conf->resultBuf = MIME_BINARY_UNREADABLE;
1400 conf->resultBuf = MIME_BINARY_ZEROSIZE;
1402 buf[nbytes++] =
'\0';
1403 tryit(conf, buf, nbytes);
1406 if ( conf->utimeConf && conf->utimeConf->restoreAccessTime( fn ) )
1413 struct utimbuf utbuf;
1414 utbuf.actime = sb.st_atime;
1415 utbuf.modtime = sb.st_mtime;
1416 (void) utime(fileName, &utbuf);
1422 static void tryit(
struct config_rec* conf,
unsigned char *buf,
int nb)
1425 if (match(conf, buf, nb))
1429 if (ascmagic(conf, buf, nb) == 1)
1433 if (textmagic(conf, buf, nb))
1437 conf->resultBuf = MIME_BINARY_UNKNOWN;
1442 fsmagic(
struct config_rec* conf,
const char *fn, KDE_struct_stat *sb)
1450 ret = KDE_lstat(fn, sb);
1462 switch (sb->st_mode & S_IFMT) {
1464 conf->resultBuf = MIME_INODE_DIR;
1467 conf->resultBuf = MIME_INODE_CDEV;
1470 conf->resultBuf = MIME_INODE_BDEV;
1475 conf->resultBuf = MIME_INODE_FIFO;
1481 char buf[BUFSIZ + BUFSIZ + 4];
1483 KDE_struct_stat tstatbuf;
1485 if ((nch = readlink(fn, buf, BUFSIZ - 1)) <= 0) {
1486 conf->resultBuf = MIME_INODE_LINK;
1493 if (KDE_stat(buf, &tstatbuf) < 0) {
1494 conf->resultBuf = MIME_INODE_LINK;
1500 char buf2[BUFSIZ + BUFSIZ + 4];
1502 strncpy(buf2, fn, BUFSIZ);
1505 if ((tmp = strrchr(buf2,
'/')) == NULL) {
1513 if (KDE_stat(tmp, &tstatbuf) < 0) {
1514 conf->resultBuf = MIME_INODE_LINK;
1520 if (conf->followLinks)
1521 process( conf, TQFile::decodeName( buf ) );
1523 conf->resultBuf = MIME_INODE_LINK;
1529 #ifndef __COHERENT__
1531 conf->resultBuf = MIME_INODE_SOCK;
1538 kdError(7018) <<
"KMimeMagic::fsmagic: invalid mode 0" << sb->st_mode <<
"." << endl;
1545 if (sb->st_size == 0) {
1546 conf->resultBuf = MIME_BINARY_ZEROSIZE;
1579 match(
struct config_rec* conf,
unsigned char *s,
int nbytes)
1585 #ifdef DEBUG_MIMEMAGIC
1586 kdDebug(7018) <<
"match: conf=" << conf <<
" m=" << (conf->magic ?
"set" :
"NULL") <<
" m->next=" << ((conf->magic && conf->magic->next) ?
"set" :
"NULL") <<
" last=" << (conf->last ?
"set" :
"NULL") << endl;
1587 for (m = conf->magic; m; m = m->next) {
1588 if (isprint((((
unsigned long) m) >> 24) & 255) &&
1589 isprint((((
unsigned long) m) >> 16) & 255) &&
1590 isprint((((
unsigned long) m) >> 8) & 255) &&
1591 isprint(((
unsigned long) m) & 255)) {
1592 kdDebug(7018) <<
"match: POINTER CLOBBERED! " << endl;
1598 for (m = conf->magic; m; m = m->next) {
1599 #ifdef DEBUG_MIMEMAGIC
1600 kdDebug(7018) <<
"match: line=" << m->lineno <<
" desc=" << m->desc << endl;
1602 memset(&p, 0,
sizeof(
union VALUETYPE));
1605 if (!mget(&p, s, m, nbytes) ||
1607 struct magic *m_cont;
1612 if (!m->next || (m->next->cont_level == 0)) {
1616 while (m_cont && (m_cont->cont_level != 0)) {
1617 #ifdef DEBUG_MIMEMAGIC
1618 kdDebug(7018) <<
"match: line=" << m->lineno <<
" cont=" << m_cont->cont_level <<
" mc=" << m_cont->lineno <<
" mc->next=" << m_cont <<
" " << endl;
1625 m_cont = m_cont->next;
1631 #ifdef DEBUG_MIMEMAGIC
1632 kdDebug(7018) <<
"match: rule matched, line=" << m->lineno <<
" type=" << m->type <<
" " << ((m->type == STRING) ? m->value.s :
"") << endl;
1636 conf->resultBuf = m->desc;
1644 while (m && (m->cont_level != 0)) {
1645 #ifdef DEBUG_MIMEMAGIC
1646 kdDebug(7018) <<
"match: line=" << m->lineno <<
" cont=" << m->cont_level <<
" type=" << m->type <<
" " << ((m->type == STRING) ? m->value.s :
"") << endl;
1648 if (cont_level >= m->cont_level) {
1649 if (cont_level > m->cont_level) {
1654 cont_level = m->cont_level;
1656 if (mget(&p, s, m, nbytes) &&
1664 #ifdef DEBUG_MIMEMAGIC
1665 kdDebug(7018) <<
"continuation matched" << endl;
1667 conf->resultBuf = m->desc;
1676 if ( !conf->resultBuf.isEmpty() )
1678 #ifdef DEBUG_MIMEMAGIC
1679 kdDebug(7018) <<
"match: matched" << endl;
1684 #ifdef DEBUG_MIMEMAGIC
1685 kdDebug(7018) <<
"match: failed" << endl;
1692 static int tagmagic(
unsigned char *buf,
int nbytes)
1694 if(nbytes<40)
return 0;
1695 if(buf[0] ==
'I' && buf[1] ==
'D' && buf[2] ==
'3') {
1698 if(buf[3] > 4)
return 0;
1699 if(buf[5] & 0x0F)
return 0;
1701 if(buf[5] & 0x10) size += 10;
1704 size += buf[8] << 7;
1705 size += buf[7] << 14;
1706 size += buf[6] << 21;
1719 Tokenizer(
char* buf,
int nbytes) {
1727 Token* nextToken() {
1732 token.data = data+pos;
1735 switch (data[pos]) {
1746 if (token.length == 0) token.data++;
1769 static inline bool STREQ(
const Token *token,
const char *b) {
1770 const char *a = token->data;
1771 int len = token->length;
1772 if (a == b)
return true;
1773 while(*a && *b && len > 0) {
1774 if (*a != *b)
return false;
1777 return (len == 0 && *b == 0);
1780 static int ascmagic(
struct config_rec* conf,
unsigned char *buf,
int nbytes)
1783 double pct, maxpct, pctsum;
1784 double pcts[NTYPES];
1785 int mostaccurate, tokencount;
1786 int typeset, jonly, conly, jconly, objconly, cpponly;
1787 int has_escapes = 0;
1792 conf->accuracy = 70;
1800 unsigned char *tp = buf + 1;
1802 while (isascii(*tp) && isspace(*tp))
1804 if ((isascii(*tp) && (isalnum(*tp) || *tp ==
'\\') &&
1805 isascii(*(tp + 1)) && (isalnum(*(tp + 1)) || *tp ==
'"'))) {
1806 conf->resultBuf = MIME_APPL_TROFF;
1810 if ((*buf ==
'c' || *buf ==
'C') &&
1811 isascii(*(buf + 1)) && isspace(*(buf + 1))) {
1813 conf->resultBuf = MIME_TEXT_FORTRAN;
1816 assert(nbytes-1 < HOWMANY + 1);
1818 has_escapes = (memchr(buf,
'\033', nbytes) != NULL);
1819 Tokenizer tokenizer((
char*)buf, nbytes);
1821 bool linecomment =
false, blockcomment =
false;
1822 const struct names *p;
1823 int typecount[NTYPES];
1828 memset(&typecount, 0,
sizeof(typecount));
1836 bool foundClass =
false;
1839 while ((token = tokenizer.nextToken())->length > 0) {
1840 #ifdef DEBUG_MIMEMAGIC
1841 kdDebug(7018) <<
"KMimeMagic::ascmagic token=" << token << endl;
1843 if (linecomment && tokenizer.isNewLine())
1844 linecomment =
false;
1845 if (blockcomment && STREQ(token,
"*/")) {
1846 blockcomment =
false;
1849 for (p = names; p->name ; p++) {
1850 if (STREQ(token, p->name)) {
1851 #ifdef DEBUG_MIMEMAGIC
1852 kdDebug(7018) <<
"KMimeMagic::ascmagic token matches ! name=" << p->name <<
" type=" << p->type << endl;
1856 if(p->type & (L_C|L_CPP|L_JAVA|L_OBJC)) {
1857 if (linecomment || blockcomment) {
1861 switch(p->type & (L_C|L_CPP|L_JAVA|L_OBJC))
1872 case (L_CPP|L_JAVA):
1874 if ( !foundClass && STREQ(token,
"class") )
1881 if (STREQ(token,
"//")) linecomment =
true;
1882 if (STREQ(token,
"/*")) blockcomment =
true;
1886 for (i = 0; i < (int)NTYPES; i++) {
1887 if ((1 << i) & p->type) typecount[i]+= p->type & FLAG_STRONG ? 2 : 1;
1893 if (typeset & (L_C|L_CPP|L_JAVA|L_OBJC)) {
1894 conf->accuracy = 60;
1895 if (!(typeset & ~(L_C|L_CPP|L_JAVA|L_OBJC))) {
1896 #ifdef DEBUG_MIMEMAGIC
1897 kdDebug(7018) <<
"C/C++/Java/ObjC: jonly=" << jonly <<
" conly=" << conly <<
" jconly=" << jconly <<
" objconly=" << objconly << endl;
1899 if (jonly > 1 && foundClass) {
1901 conf->resultBuf = TQString(types[P_JAVA].type);
1906 if (typecount[P_JAVA] < typecount[P_CPP])
1907 conf->resultBuf = TQString(types[P_CPP].type);
1909 conf->resultBuf = TQString(types[P_JAVA].type);
1912 if (conly + cpponly > 1) {
1915 conf->resultBuf = TQString(types[P_CPP].type);
1917 conf->resultBuf = TQString(types[P_C].type);
1921 conf->resultBuf = TQString(types[P_OBJC].type);
1932 maxpct = pctsum = 0.0;
1933 for (i = 0; i < (int)NTYPES; i++) {
1934 if (typecount[i] > 1) {
1935 pct = (double)typecount[i] / (
double)types[i].kwords *
1936 (double)types[i].weight;
1943 #ifdef DEBUG_MIMEMAGIC
1944 kdDebug(7018) <<
"" << types[i].type <<
" has " << typecount[i] <<
" hits, " << types[i].kwords <<
" kw, weight " << types[i].weight <<
", " << pct <<
" -> max = " << maxpct <<
"\n" << endl;
1948 if (mostaccurate >= 0) {
1949 if ( mostaccurate != P_JAVA || foundClass )
1951 conf->accuracy = (int)(pcts[mostaccurate] / pctsum * 60);
1952 #ifdef DEBUG_MIMEMAGIC
1953 kdDebug(7018) <<
"mostaccurate=" << mostaccurate <<
" pcts=" << pcts[mostaccurate] <<
" pctsum=" << pctsum <<
" accuracy=" << conf->accuracy << endl;
1955 conf->resultBuf = TQString(types[mostaccurate].type);
1960 switch (is_tar(buf, nbytes)) {
1963 conf->resultBuf = MIME_APPL_TAR;
1964 conf->accuracy = 90;
1968 conf->resultBuf = MIME_APPL_TAR;
1969 conf->accuracy = 90;
1973 for (i = 0; i < nbytes; i++) {
1974 if (!isascii(*(buf + i)))
1979 conf->accuracy = 90;
1983 conf->resultBuf = MIME_TEXT_UNKNOWN;
1986 conf->resultBuf = MIME_TEXT_PLAIN;
2000 static int textmagic(
struct config_rec* conf,
unsigned char * buf,
int nbytes)
2008 for (i = 0, cp = buf; i < nbytes; i++, cp++)
2009 if ((*cp < 8) || (*cp>13 && *cp<32 && *cp!=27 ) || (*cp==0x7F))
2012 conf->resultBuf = MIME_TEXT_PLAIN;
2030 #define isodigit(c) ( ((c) >= '0') && ((c) <= '7') )
2038 is_tar(
unsigned char *buf,
int nbytes)
2040 register union record *header = (
union record *) buf;
2046 if (nbytes < (
int)
sizeof(
union record))
2049 recsum = from_oct(8, header->header.chksum);
2052 p = header->charptr;
2053 for (i =
sizeof(
union record); --i >= 0;) {
2062 for (i =
sizeof(header->header.chksum); --i >= 0;)
2063 sum -= 0xFF & header->header.chksum[i];
2064 sum +=
' ' *
sizeof header->header.chksum;
2069 if (0 == strcmp(header->header.magic, TMAGIC))
2082 from_oct(
int digs,
char *where)
2084 register long value;
2086 while (isspace(*where)) {
2092 while (digs > 0 && isodigit(*where)) {
2093 value = (value << 3) | (*where++ -
'0');
2097 if (digs > 0 && *where && !isspace(*where))
2106 TQString mimefile = locate(
"mime",
"magic" );
2109 TQStringList snippets = KGlobal::dirs()->findAllResources(
"config",
"magic/*.magic",
true );
2110 for ( TQStringList::Iterator it = snippets.begin() ; it != snippets.end() ; ++it )
2112 kdWarning() << k_funcinfo <<
"Failed to parse " << *it << endl;
2117 init( _configfile );
2120 void KMimeMagic::init(
const TQString& _configfile )
2123 conf =
new config_rec;
2126 conf->magic = conf->last = NULL;
2128 conf->followLinks =
false;
2130 conf->utimeConf = 0L;
2132 result = apprentice(_configfile);
2135 #ifdef MIME_MAGIC_DEBUG_TABLE
2147 struct magic *p = conf->magic;
2154 delete conf->utimeConf;
2163 kdDebug(7018) << k_funcinfo << _configfile << endl;
2166 if (_configfile.isEmpty())
2168 result = apprentice(_configfile);
2172 #ifdef MIME_MAGIC_DEBUG_TABLE
2184 result = buff_apprentice(_configbuf);
2187 #ifdef MIME_MAGIC_DEBUG_TABLE
2198 conf->followLinks = _enable;
2204 unsigned char buf[HOWMANY + 1];
2206 conf->resultBuf = TQString::null;
2210 conf->accuracy = 100;
2212 int nbytes = array.size();
2214 if (nbytes > HOWMANY)
2216 memcpy(buf, array.data(), nbytes);
2218 conf->resultBuf = MIME_BINARY_ZEROSIZE;
2220 buf[nbytes++] =
'\0';
2221 tryit(conf, buf, nbytes);
2224 magicResult->setMimeType(conf->resultBuf.stripWhiteSpace());
2235 if ( tmp ==
"text/x-c" || tmp ==
"text/x-objc" )
2237 if ( _filename.right(2) ==
".h" )
2241 r->setMimeType(tmp);
2244 if ( tmp ==
"text/x-c++" )
2246 if ( _filename.endsWith(
".h")
2247 || _filename.endsWith(
".hh")
2248 || _filename.endsWith(
".H")
2249 || !_filename.right(4).contains(
'.'))
2253 r->setMimeType(tmp);
2256 if ( tmp ==
"application/x-sharedlib" )
2258 if ( _filename.find(
".so" ) == -1 )
2260 tmp =
"application/x-executable";
2261 r->setMimeType( tmp );
2271 refineResult(r, fn);
2280 #ifdef DEBUG_MIMEMAGIC
2281 kdDebug(7018) <<
"KMimeMagic::findFileType " << fn << endl;
2283 conf->resultBuf = TQString::null;
2288 conf->accuracy = 100;
2290 if ( !conf->utimeConf )
2291 conf->utimeConf =
new KMimeMagicUtimeConf();
2298 magicResult->setMimeType(conf->resultBuf.stripWhiteSpace());