Annotation of embedaddon/php/ext/fileinfo/libmagic/softmagic.c, revision 1.1.1.1
1.1 misho 1: /*
2: * Copyright (c) Ian F. Darwin 1986-1995.
3: * Software written by Ian F. Darwin and others;
4: * maintained 1995-present by Christos Zoulas and others.
5: *
6: * Redistribution and use in source and binary forms, with or without
7: * modification, are permitted provided that the following conditions
8: * are met:
9: * 1. Redistributions of source code must retain the above copyright
10: * notice immediately at the beginning of the file, without modification,
11: * this list of conditions, and the following disclaimer.
12: * 2. Redistributions in binary form must reproduce the above copyright
13: * notice, this list of conditions and the following disclaimer in the
14: * documentation and/or other materials provided with the distribution.
15: *
16: * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
17: * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
18: * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
19: * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE FOR
20: * ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
21: * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
22: * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
23: * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
24: * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
25: * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
26: * SUCH DAMAGE.
27: */
28: /*
29: * softmagic - interpret variable magic from MAGIC
30: */
31:
32: #include "file.h"
33:
34: #ifndef lint
35: FILE_RCSID("@(#)$File: softmagic.c,v 1.135 2009/03/27 22:42:49 christos Exp $")
36: #endif /* lint */
37:
38: #include "magic.h"
39: #include <string.h>
40: #include <ctype.h>
41: #include <stdlib.h>
42: #include <time.h>
43:
44: #ifndef PREG_OFFSET_CAPTURE
45: # define PREG_OFFSET_CAPTURE (1<<8)
46: #endif
47:
48:
49:
50: private int match(struct magic_set *, struct magic *, uint32_t,
51: const unsigned char *, size_t, int);
52: private int mget(struct magic_set *, const unsigned char *,
53: struct magic *, size_t, unsigned int);
54: private int magiccheck(struct magic_set *, struct magic *);
55: private int32_t mprint(struct magic_set *, struct magic *);
56: private int32_t moffset(struct magic_set *, struct magic *);
57: private void mdebug(uint32_t, const char *, size_t);
58: private int mcopy(struct magic_set *, union VALUETYPE *, int, int,
59: const unsigned char *, uint32_t, size_t, size_t);
60: private int mconvert(struct magic_set *, struct magic *);
61: private int print_sep(struct magic_set *, int);
62: private int handle_annotation(struct magic_set *, struct magic *);
63: private void cvt_8(union VALUETYPE *, const struct magic *);
64: private void cvt_16(union VALUETYPE *, const struct magic *);
65: private void cvt_32(union VALUETYPE *, const struct magic *);
66: private void cvt_64(union VALUETYPE *, const struct magic *);
67:
68: /*
69: * softmagic - lookup one file in parsed, in-memory copy of database
70: * Passed the name and FILE * of one file to be typed.
71: */
72: /*ARGSUSED1*/ /* nbytes passed for regularity, maybe need later */
73: protected int
74: file_softmagic(struct magic_set *ms, const unsigned char *buf, size_t nbytes, int mode)
75: {
76: struct mlist *ml;
77: int rv;
78: for (ml = ms->mlist->next; ml != ms->mlist; ml = ml->next)
79: if ((rv = match(ms, ml->magic, ml->nmagic, buf, nbytes, mode)) != 0)
80: return rv;
81:
82: return 0;
83: }
84:
85: /*
86: * Go through the whole list, stopping if you find a match. Process all
87: * the continuations of that match before returning.
88: *
89: * We support multi-level continuations:
90: *
91: * At any time when processing a successful top-level match, there is a
92: * current continuation level; it represents the level of the last
93: * successfully matched continuation.
94: *
95: * Continuations above that level are skipped as, if we see one, it
96: * means that the continuation that controls them - i.e, the
97: * lower-level continuation preceding them - failed to match.
98: *
99: * Continuations below that level are processed as, if we see one,
100: * it means we've finished processing or skipping higher-level
101: * continuations under the control of a successful or unsuccessful
102: * lower-level continuation, and are now seeing the next lower-level
103: * continuation and should process it. The current continuation
104: * level reverts to the level of the one we're seeing.
105: *
106: * Continuations at the current level are processed as, if we see
107: * one, there's no lower-level continuation that may have failed.
108: *
109: * If a continuation matches, we bump the current continuation level
110: * so that higher-level continuations are processed.
111: */
112: private int
113: match(struct magic_set *ms, struct magic *magic, uint32_t nmagic,
114: const unsigned char *s, size_t nbytes, int mode)
115: {
116: uint32_t magindex = 0;
117: unsigned int cont_level = 0;
118: int need_separator = 0;
119: int returnval = 0, e; /* if a match is found it is set to 1*/
120: int firstline = 1; /* a flag to print X\n X\n- X */
121: int printed_something = 0;
122: int print = (ms->flags & (MAGIC_MIME|MAGIC_APPLE)) == 0;
123:
124: if (file_check_mem(ms, cont_level) == -1)
125: return -1;
126:
127: for (magindex = 0; magindex < nmagic; magindex++) {
128: int flush = 0;
129: struct magic *m = &magic[magindex];
130:
131: if ((m->flag & BINTEST) != mode) {
132: /* Skip sub-tests */
133: while (magindex < nmagic - 1 && magic[magindex + 1].cont_level != 0) {
134: magindex++;
135: }
136: continue; /* Skip to next top-level test*/
137: }
138:
139: ms->offset = m->offset;
140: ms->line = m->lineno;
141:
142: /* if main entry matches, print it... */
143: switch (mget(ms, s, m, nbytes, cont_level)) {
144: case -1:
145: return -1;
146: case 0:
147: flush = m->reln != '!';
148: break;
149: default:
150: if (m->type == FILE_INDIRECT)
151: returnval = 1;
152:
153: switch (magiccheck(ms, m)) {
154: case -1:
155: return -1;
156: case 0:
157: flush++;
158: break;
159: default:
160: flush = 0;
161: break;
162: }
163: break;
164: }
165: if (flush) {
166: /*
167: * main entry didn't match,
168: * flush its continuations
169: */
170: while (magindex < nmagic - 1 && magic[magindex + 1].cont_level != 0) {
171: magindex++;
172: }
173: continue;
174: }
175:
176: /*
177: * If we are going to print something, we'll need to print
178: * a blank before we print something else.
179: */
180: if (*m->desc) {
181: need_separator = 1;
182: printed_something = 1;
183: if ((e = handle_annotation(ms, m)) != 0)
184: return e;
185: if (print_sep(ms, firstline) == -1)
186: return -1;
187: }
188:
189:
190: if (print && mprint(ms, m) == -1)
191: return -1;
192:
193: ms->c.li[cont_level].off = moffset(ms, m);
194:
195: /* and any continuations that match */
196: if (file_check_mem(ms, ++cont_level) == -1)
197: return -1;
198:
199: while (magindex < nmagic - 1 && magic[magindex + 1].cont_level != 0) {
200: magindex++;
201: m = &magic[magindex];
202: ms->line = m->lineno; /* for messages */
203:
204: if (cont_level < m->cont_level)
205: continue;
206: if (cont_level > m->cont_level) {
207: /*
208: * We're at the end of the level
209: * "cont_level" continuations.
210: */
211: cont_level = m->cont_level;
212: }
213: ms->offset = m->offset;
214: if (m->flag & OFFADD) {
215: ms->offset += ms->c.li[cont_level - 1].off;
216: }
217:
218: #ifdef ENABLE_CONDITIONALS
219: if (m->cond == COND_ELSE ||
220: m->cond == COND_ELIF) {
221: if (ms->c.li[cont_level].last_match == 1)
222: continue;
223: }
224: #endif
225: switch (mget(ms, s, m, nbytes, cont_level)) {
226: case -1:
227: return -1;
228: case 0:
229: if (m->reln != '!')
230: continue;
231: flush = 1;
232: break;
233: default:
234: if (m->type == FILE_INDIRECT)
235: returnval = 1;
236: flush = 0;
237: break;
238: }
239:
240: switch (flush ? 1 : magiccheck(ms, m)) {
241: case -1:
242: return -1;
243: case 0:
244: #ifdef ENABLE_CONDITIONALS
245: ms->c.li[cont_level].last_match = 0;
246: #endif
247: break;
248: default:
249: #ifdef ENABLE_CONDITIONALS
250: ms->c.li[cont_level].last_match = 1;
251: #endif
252: if (m->type != FILE_DEFAULT)
253: ms->c.li[cont_level].got_match = 1;
254: else if (ms->c.li[cont_level].got_match) {
255: ms->c.li[cont_level].got_match = 0;
256: break;
257: }
258: /*
259: * If we are going to print something,
260: * make sure that we have a separator first.
261: */
262: if (*m->desc) {
263: if ((e = handle_annotation(ms, m)) != 0)
264: return e;
265: if (!printed_something) {
266: printed_something = 1;
267: if (print_sep(ms, firstline)
268: == -1)
269: return -1;
270: }
271: }
272: /*
273: * This continuation matched. Print
274: * its message, with a blank before it
275: * if the previous item printed and
276: * this item isn't empty.
277: */
278: /* space if previous printed */
279: if (need_separator
280: && ((m->flag & NOSPACE) == 0)
281: && *m->desc) {
282: if (print &&
283: file_printf(ms, " ") == -1)
284: return -1;
285: need_separator = 0;
286: }
287: if (print && mprint(ms, m) == -1)
288: return -1;
289:
290: ms->c.li[cont_level].off = moffset(ms, m);
291:
292: if (*m->desc)
293: need_separator = 1;
294:
295: /*
296: * If we see any continuations
297: * at a higher level,
298: * process them.
299: */
300: if (file_check_mem(ms, ++cont_level) == -1)
301: return -1;
302: break;
303: }
304: }
305: if (printed_something) {
306: firstline = 0;
307: if (print)
308: returnval = 1;
309: }
310: if ((ms->flags & MAGIC_CONTINUE) == 0 && printed_something) {
311: return returnval; /* don't keep searching */
312: }
313: }
314: return returnval; /* This is hit if -k is set or there is no match */
315: }
316:
317: private int
318: check_fmt(struct magic_set *ms, struct magic *m)
319: {
320: pcre *pce;
321: int re_options;
322: pcre_extra *re_extra;
323: TSRMLS_FETCH();
324:
325: if (strchr(m->desc, '%') == NULL) {
326: return 0;
327: }
328:
329: if ((pce = pcre_get_compiled_regex("~%[-0-9.]*s~", &re_extra, &re_options TSRMLS_CC)) == NULL) {
330: return -1;
331: } else {
332: return !pcre_exec(pce, re_extra, m->desc, strlen(m->desc), 0, re_options, NULL, 0);
333: }
334: }
335:
336: private int32_t
337: mprint(struct magic_set *ms, struct magic *m)
338: {
339: uint64_t v;
340: float vf;
341: double vd;
342: int64_t t = 0;
343: char buf[128];
344: union VALUETYPE *p = &ms->ms_value;
345:
346: switch (m->type) {
347: case FILE_BYTE:
348: v = file_signextend(ms, m, (uint64_t)p->b);
349: switch (check_fmt(ms, m)) {
350: case -1:
351: return -1;
352: case 1:
353: (void)snprintf(buf, sizeof(buf), "%c",
354: (unsigned char)v);
355: if (file_printf(ms, m->desc, buf) == -1)
356: return -1;
357: break;
358: default:
359: if (file_printf(ms, m->desc, (unsigned char) v) == -1)
360: return -1;
361: break;
362: }
363: t = ms->offset + sizeof(char);
364: break;
365:
366: case FILE_SHORT:
367: case FILE_BESHORT:
368: case FILE_LESHORT:
369: v = file_signextend(ms, m, (uint64_t)p->h);
370: switch (check_fmt(ms, m)) {
371: case -1:
372: return -1;
373: case 1:
374: (void)snprintf(buf, sizeof(buf), "%hu",
375: (unsigned short)v);
376: if (file_printf(ms, m->desc, buf) == -1)
377: return -1;
378: break;
379: default:
380: if (
381: file_printf(ms, m->desc, (unsigned short) v) == -1)
382: return -1;
383: break;
384: }
385: t = ms->offset + sizeof(short);
386: break;
387:
388: case FILE_LONG:
389: case FILE_BELONG:
390: case FILE_LELONG:
391: case FILE_MELONG:
392: v = file_signextend(ms, m, (uint64_t)p->l);
393: switch (check_fmt(ms, m)) {
394: case -1:
395: return -1;
396: case 1:
397: (void)snprintf(buf, sizeof(buf), "%u", (uint32_t)v);
398: if (file_printf(ms, m->desc, buf) == -1)
399: return -1;
400: break;
401: default:
402: if (file_printf(ms, m->desc, (uint32_t) v) == -1)
403: return -1;
404: break;
405: }
406: t = ms->offset + sizeof(int32_t);
407: break;
408:
409: case FILE_QUAD:
410: case FILE_BEQUAD:
411: case FILE_LEQUAD:
412: v = file_signextend(ms, m, p->q);
413: if (file_printf(ms, m->desc, (uint64_t) v) == -1)
414: return -1;
415: t = ms->offset + sizeof(int64_t);
416: break;
417:
418: case FILE_STRING:
419: case FILE_PSTRING:
420: case FILE_BESTRING16:
421: case FILE_LESTRING16:
422: if (m->reln == '=' || m->reln == '!') {
423: if (file_printf(ms, m->desc, m->value.s) == -1)
424: return -1;
425: t = ms->offset + m->vallen;
426: }
427: else {
428: if (*m->value.s == '\0')
429: p->s[strcspn(p->s, "\n")] = '\0';
430: if (file_printf(ms, m->desc, p->s) == -1)
431: return -1;
432: t = ms->offset + strlen(p->s);
433: if (m->type == FILE_PSTRING)
434: t++;
435: }
436: break;
437:
438: case FILE_DATE:
439: case FILE_BEDATE:
440: case FILE_LEDATE:
441: case FILE_MEDATE:
442: if (file_printf(ms, m->desc, file_fmttime(p->l, 1)) == -1)
443: return -1;
444: t = ms->offset + sizeof(time_t);
445: break;
446:
447: case FILE_LDATE:
448: case FILE_BELDATE:
449: case FILE_LELDATE:
450: case FILE_MELDATE:
451: if (file_printf(ms, m->desc, file_fmttime(p->l, 0)) == -1)
452: return -1;
453: t = ms->offset + sizeof(time_t);
454: break;
455:
456: case FILE_QDATE:
457: case FILE_BEQDATE:
458: case FILE_LEQDATE:
459: if (file_printf(ms, m->desc, file_fmttime((uint32_t)p->q,
460: 1)) == -1)
461: return -1;
462: t = ms->offset + sizeof(uint64_t);
463: break;
464:
465: case FILE_QLDATE:
466: case FILE_BEQLDATE:
467: case FILE_LEQLDATE:
468: if (file_printf(ms, m->desc, file_fmttime((uint32_t)p->q,
469: 0)) == -1)
470: return -1;
471: t = ms->offset + sizeof(uint64_t);
472: break;
473:
474: case FILE_FLOAT:
475: case FILE_BEFLOAT:
476: case FILE_LEFLOAT:
477: vf = p->f;
478: switch (check_fmt(ms, m)) {
479: case -1:
480: return -1;
481: case 1:
482: (void)snprintf(buf, sizeof(buf), "%g", vf);
483: if (file_printf(ms, m->desc, buf) == -1)
484: return -1;
485: break;
486: default:
487: if (file_printf(ms, m->desc, vf) == -1)
488: return -1;
489: break;
490: }
491: t = ms->offset + sizeof(float);
492: break;
493:
494: case FILE_DOUBLE:
495: case FILE_BEDOUBLE:
496: case FILE_LEDOUBLE:
497: vd = p->d;
498: switch (check_fmt(ms, m)) {
499: case -1:
500: return -1;
501: case 1:
502: (void)snprintf(buf, sizeof(buf), "%g", vd);
503: if (file_printf(ms, m->desc, buf) == -1)
504: return -1;
505: break;
506: default:
507: if (file_printf(ms, m->desc, vd) == -1)
508: return -1;
509: break;
510: }
511: t = ms->offset + sizeof(double);
512: break;
513:
514: case FILE_REGEX: {
515: char *cp;
516: int rval;
517:
518: cp = estrndup((const char *)ms->search.s, ms->search.rm_len);
519:
520: rval = file_printf(ms, m->desc, cp);
521: efree(cp);
522:
523: if (rval == -1)
524: return -1;
525:
526: if ((m->str_flags & REGEX_OFFSET_START))
527: t = ms->search.offset;
528: else
529: t = ms->search.offset + ms->search.rm_len;
530: break;
531: }
532:
533: case FILE_SEARCH:
534: if (file_printf(ms, m->desc, m->value.s) == -1)
535: return -1;
536: if ((m->str_flags & REGEX_OFFSET_START))
537: t = ms->search.offset;
538: else
539: t = ms->search.offset + m->vallen;
540: break;
541:
542: case FILE_DEFAULT:
543: if (file_printf(ms, m->desc, m->value.s) == -1)
544: return -1;
545: t = ms->offset;
546: break;
547:
548: case FILE_INDIRECT:
549: t = ms->offset;
550: break;
551:
552: default:
553: file_magerror(ms, "invalid m->type (%d) in mprint()", m->type);
554: return -1;
555: }
556: return (int32_t)t;
557: }
558:
559: private int32_t
560: moffset(struct magic_set *ms, struct magic *m)
561: {
562: switch (m->type) {
563: case FILE_BYTE:
564: return ms->offset + sizeof(char);
565:
566: case FILE_SHORT:
567: case FILE_BESHORT:
568: case FILE_LESHORT:
569: return ms->offset + sizeof(short);
570:
571: case FILE_LONG:
572: case FILE_BELONG:
573: case FILE_LELONG:
574: case FILE_MELONG:
575: return ms->offset + sizeof(int32_t);
576:
577: case FILE_QUAD:
578: case FILE_BEQUAD:
579: case FILE_LEQUAD:
580: return ms->offset + sizeof(int64_t);
581:
582: case FILE_STRING:
583: case FILE_PSTRING:
584: case FILE_BESTRING16:
585: case FILE_LESTRING16:
586: if (m->reln == '=' || m->reln == '!')
587: return ms->offset + m->vallen;
588: else {
589: union VALUETYPE *p = &ms->ms_value;
590: uint32_t t;
591:
592: if (*m->value.s == '\0')
593: p->s[strcspn(p->s, "\n")] = '\0';
594: t = ms->offset + strlen(p->s);
595: if (m->type == FILE_PSTRING)
596: t++;
597: return t;
598: }
599:
600: case FILE_DATE:
601: case FILE_BEDATE:
602: case FILE_LEDATE:
603: case FILE_MEDATE:
604: return ms->offset + sizeof(time_t);
605:
606: case FILE_LDATE:
607: case FILE_BELDATE:
608: case FILE_LELDATE:
609: case FILE_MELDATE:
610: return ms->offset + sizeof(time_t);
611:
612: case FILE_QDATE:
613: case FILE_BEQDATE:
614: case FILE_LEQDATE:
615: return ms->offset + sizeof(uint64_t);
616:
617: case FILE_QLDATE:
618: case FILE_BEQLDATE:
619: case FILE_LEQLDATE:
620: return ms->offset + sizeof(uint64_t);
621:
622: case FILE_FLOAT:
623: case FILE_BEFLOAT:
624: case FILE_LEFLOAT:
625: return ms->offset + sizeof(float);
626:
627: case FILE_DOUBLE:
628: case FILE_BEDOUBLE:
629: case FILE_LEDOUBLE:
630: return ms->offset + sizeof(double);
631: break;
632:
633: case FILE_REGEX:
634: if ((m->str_flags & REGEX_OFFSET_START) != 0)
635: return ms->search.offset;
636: else
637: return ms->search.offset + ms->search.rm_len;
638:
639: case FILE_SEARCH:
640: if ((m->str_flags & REGEX_OFFSET_START) != 0)
641: return ms->search.offset;
642: else
643: return ms->search.offset + m->vallen;
644:
645: case FILE_DEFAULT:
646: return ms->offset;
647:
648: case FILE_INDIRECT:
649: return ms->offset;
650:
651: default:
652: return 0;
653: }
654: }
655:
656: #define DO_CVT(fld, cast) \
657: if (m->num_mask) \
658: switch (m->mask_op & FILE_OPS_MASK) { \
659: case FILE_OPAND: \
660: p->fld &= cast m->num_mask; \
661: break; \
662: case FILE_OPOR: \
663: p->fld |= cast m->num_mask; \
664: break; \
665: case FILE_OPXOR: \
666: p->fld ^= cast m->num_mask; \
667: break; \
668: case FILE_OPADD: \
669: p->fld += cast m->num_mask; \
670: break; \
671: case FILE_OPMINUS: \
672: p->fld -= cast m->num_mask; \
673: break; \
674: case FILE_OPMULTIPLY: \
675: p->fld *= cast m->num_mask; \
676: break; \
677: case FILE_OPDIVIDE: \
678: p->fld /= cast m->num_mask; \
679: break; \
680: case FILE_OPMODULO: \
681: p->fld %= cast m->num_mask; \
682: break; \
683: } \
684: if (m->mask_op & FILE_OPINVERSE) \
685: p->fld = ~p->fld \
686:
687: private void
688: cvt_8(union VALUETYPE *p, const struct magic *m)
689: {
690: DO_CVT(b, (uint8_t));
691: }
692:
693: private void
694: cvt_16(union VALUETYPE *p, const struct magic *m)
695: {
696: DO_CVT(h, (uint16_t));
697: }
698:
699: private void
700: cvt_32(union VALUETYPE *p, const struct magic *m)
701: {
702: DO_CVT(l, (uint32_t));
703: }
704:
705: private void
706: cvt_64(union VALUETYPE *p, const struct magic *m)
707: {
708: DO_CVT(q, (uint64_t));
709: }
710:
711: #define DO_CVT2(fld, cast) \
712: if (m->num_mask) \
713: switch (m->mask_op & FILE_OPS_MASK) { \
714: case FILE_OPADD: \
715: p->fld += cast (int64_t)m->num_mask; \
716: break; \
717: case FILE_OPMINUS: \
718: p->fld -= cast (int64_t)m->num_mask; \
719: break; \
720: case FILE_OPMULTIPLY: \
721: p->fld *= cast (int64_t)m->num_mask; \
722: break; \
723: case FILE_OPDIVIDE: \
724: p->fld /= cast (int64_t)m->num_mask; \
725: break; \
726: } \
727:
728: private void
729: cvt_float(union VALUETYPE *p, const struct magic *m)
730: {
731: DO_CVT2(f, (float));
732: }
733:
734: private void
735: cvt_double(union VALUETYPE *p, const struct magic *m)
736: {
737: DO_CVT2(d, (double));
738: }
739:
740: /*
741: * Convert the byte order of the data we are looking at
742: * While we're here, let's apply the mask operation
743: * (unless you have a better idea)
744: */
745: private int
746: mconvert(struct magic_set *ms, struct magic *m)
747: {
748: union VALUETYPE *p = &ms->ms_value;
749:
750: switch (m->type) {
751: case FILE_BYTE:
752: cvt_8(p, m);
753: return 1;
754: case FILE_SHORT:
755: cvt_16(p, m);
756: return 1;
757: case FILE_LONG:
758: case FILE_DATE:
759: case FILE_LDATE:
760: cvt_32(p, m);
761: return 1;
762: case FILE_QUAD:
763: case FILE_QDATE:
764: case FILE_QLDATE:
765: cvt_64(p, m);
766: return 1;
767: case FILE_STRING:
768: case FILE_BESTRING16:
769: case FILE_LESTRING16: {
770: /* Null terminate and eat *trailing* return */
771: p->s[sizeof(p->s) - 1] = '\0';
772: #if 0
773: /* Why? breaks magic numbers that end with \xa */
774: len = strlen(p->s);
775: if (len-- && p->s[len] == '\n')
776: p->s[len] = '\0';
777: #endif
778: return 1;
779: }
780: case FILE_PSTRING: {
781: char *ptr1 = p->s, *ptr2 = ptr1 + 1;
782: size_t len = *p->s;
783: if (len >= sizeof(p->s))
784: len = sizeof(p->s) - 1;
785: while (len--)
786: *ptr1++ = *ptr2++;
787: *ptr1 = '\0';
788: #if 0
789: /* Why? breaks magic numbers that end with \xa */
790: len = strlen(p->s);
791: if (len-- && p->s[len] == '\n')
792: p->s[len] = '\0';
793: #endif
794: return 1;
795: }
796: case FILE_BESHORT:
797: p->h = (short)((p->hs[0]<<8)|(p->hs[1]));
798: cvt_16(p, m);
799: return 1;
800: case FILE_BELONG:
801: case FILE_BEDATE:
802: case FILE_BELDATE:
803: p->l = (int32_t)
804: ((p->hl[0]<<24)|(p->hl[1]<<16)|(p->hl[2]<<8)|(p->hl[3]));
805: cvt_32(p, m);
806: return 1;
807: case FILE_BEQUAD:
808: case FILE_BEQDATE:
809: case FILE_BEQLDATE:
810: p->q = (uint64_t)
811: (((uint64_t)p->hq[0]<<56)|((uint64_t)p->hq[1]<<48)|
812: ((uint64_t)p->hq[2]<<40)|((uint64_t)p->hq[3]<<32)|
813: ((uint64_t)p->hq[4]<<24)|((uint64_t)p->hq[5]<<16)|
814: ((uint64_t)p->hq[6]<<8)|((uint64_t)p->hq[7]));
815: cvt_64(p, m);
816: return 1;
817: case FILE_LESHORT:
818: p->h = (short)((p->hs[1]<<8)|(p->hs[0]));
819: cvt_16(p, m);
820: return 1;
821: case FILE_LELONG:
822: case FILE_LEDATE:
823: case FILE_LELDATE:
824: p->l = (int32_t)
825: ((p->hl[3]<<24)|(p->hl[2]<<16)|(p->hl[1]<<8)|(p->hl[0]));
826: cvt_32(p, m);
827: return 1;
828: case FILE_LEQUAD:
829: case FILE_LEQDATE:
830: case FILE_LEQLDATE:
831: p->q = (uint64_t)
832: (((uint64_t)p->hq[7]<<56)|((uint64_t)p->hq[6]<<48)|
833: ((uint64_t)p->hq[5]<<40)|((uint64_t)p->hq[4]<<32)|
834: ((uint64_t)p->hq[3]<<24)|((uint64_t)p->hq[2]<<16)|
835: ((uint64_t)p->hq[1]<<8)|((uint64_t)p->hq[0]));
836: cvt_64(p, m);
837: return 1;
838: case FILE_MELONG:
839: case FILE_MEDATE:
840: case FILE_MELDATE:
841: p->l = (int32_t)
842: ((p->hl[1]<<24)|(p->hl[0]<<16)|(p->hl[3]<<8)|(p->hl[2]));
843: cvt_32(p, m);
844: return 1;
845: case FILE_FLOAT:
846: cvt_float(p, m);
847: return 1;
848: case FILE_BEFLOAT:
849: p->l = ((uint32_t)p->hl[0]<<24)|((uint32_t)p->hl[1]<<16)|
850: ((uint32_t)p->hl[2]<<8) |((uint32_t)p->hl[3]);
851: cvt_float(p, m);
852: return 1;
853: case FILE_LEFLOAT:
854: p->l = ((uint32_t)p->hl[3]<<24)|((uint32_t)p->hl[2]<<16)|
855: ((uint32_t)p->hl[1]<<8) |((uint32_t)p->hl[0]);
856: cvt_float(p, m);
857: return 1;
858: case FILE_DOUBLE:
859: cvt_double(p, m);
860: return 1;
861: case FILE_BEDOUBLE:
862: p->q = ((uint64_t)p->hq[0]<<56)|((uint64_t)p->hq[1]<<48)|
863: ((uint64_t)p->hq[2]<<40)|((uint64_t)p->hq[3]<<32)|
864: ((uint64_t)p->hq[4]<<24)|((uint64_t)p->hq[5]<<16)|
865: ((uint64_t)p->hq[6]<<8) |((uint64_t)p->hq[7]);
866: cvt_double(p, m);
867: return 1;
868: case FILE_LEDOUBLE:
869: p->q = ((uint64_t)p->hq[7]<<56)|((uint64_t)p->hq[6]<<48)|
870: ((uint64_t)p->hq[5]<<40)|((uint64_t)p->hq[4]<<32)|
871: ((uint64_t)p->hq[3]<<24)|((uint64_t)p->hq[2]<<16)|
872: ((uint64_t)p->hq[1]<<8) |((uint64_t)p->hq[0]);
873: cvt_double(p, m);
874: return 1;
875: case FILE_REGEX:
876: case FILE_SEARCH:
877: case FILE_DEFAULT:
878: return 1;
879: default:
880: file_magerror(ms, "invalid type %d in mconvert()", m->type);
881: return 0;
882: }
883: }
884:
885:
886: private void
887: mdebug(uint32_t offset, const char *str, size_t len)
888: {
889: (void) fprintf(stderr, "mget @%d: ", offset);
890: file_showstr(stderr, str, len);
891: (void) fputc('\n', stderr);
892: (void) fputc('\n', stderr);
893: }
894:
895: private int
896: mcopy(struct magic_set *ms, union VALUETYPE *p, int type, int indir,
897: const unsigned char *s, uint32_t offset, size_t nbytes, size_t linecnt)
898: {
899: /*
900: * Note: FILE_SEARCH and FILE_REGEX do not actually copy
901: * anything, but setup pointers into the source
902: */
903: if (indir == 0) {
904: switch (type) {
905: case FILE_SEARCH:
906: ms->search.s = (const char *)s + offset;
907: ms->search.s_len = nbytes - offset;
908: ms->search.offset = offset;
909: return 0;
910:
911: case FILE_REGEX: {
912: const char *b;
913: const char *c;
914: const char *last; /* end of search region */
915: const char *buf; /* start of search region */
916: const char *end;
917: size_t lines;
918:
919: if (s == NULL) {
920: ms->search.s_len = 0;
921: ms->search.s = NULL;
922: return 0;
923: }
924: buf = (const char *)s + offset;
925: end = last = (const char *)s + nbytes;
926: /* mget() guarantees buf <= last */
927: for (lines = linecnt, b = buf;
928: lines && ((b = memchr(c = b, '\n', end - b)) || (b = memchr(c, '\r', end - c)));
929: lines--, b++) {
930: last = b;
931: if (b[0] == '\r' && b[1] == '\n')
932: b++;
933: }
934: if (lines)
935: last = (const char *)s + nbytes;
936:
937: ms->search.s = buf;
938: ms->search.s_len = last - buf;
939: ms->search.offset = offset;
940: ms->search.rm_len = 0;
941: return 0;
942: }
943: case FILE_BESTRING16:
944: case FILE_LESTRING16: {
945: const unsigned char *src = s + offset;
946: const unsigned char *esrc = s + nbytes;
947: char *dst = p->s;
948: char *edst = &p->s[sizeof(p->s) - 1];
949:
950: if (type == FILE_BESTRING16)
951: src++;
952:
953: /* check for pointer overflow */
954: if (src < s) {
955: file_magerror(ms, "invalid offset %u in mcopy()",
956: offset);
957: return -1;
958: }
959: for (/*EMPTY*/; src < esrc; src += 2, dst++) {
960: if (dst < edst)
961: *dst = *src;
962: else
963: break;
964: if (*dst == '\0') {
965: if (type == FILE_BESTRING16 ?
966: *(src - 1) != '\0' :
967: *(src + 1) != '\0')
968: *dst = ' ';
969: }
970: }
971: *edst = '\0';
972: return 0;
973: }
974: case FILE_STRING: /* XXX - these two should not need */
975: case FILE_PSTRING: /* to copy anything, but do anyway. */
976: default:
977: break;
978: }
979: }
980:
981: if (offset >= nbytes) {
982: (void)memset(p, '\0', sizeof(*p));
983: return 0;
984: }
985: if (nbytes - offset < sizeof(*p))
986: nbytes = nbytes - offset;
987: else
988: nbytes = sizeof(*p);
989:
990: (void)memcpy(p, s + offset, nbytes);
991:
992: /*
993: * the usefulness of padding with zeroes eludes me, it
994: * might even cause problems
995: */
996: if (nbytes < sizeof(*p))
997: (void)memset(((char *)(void *)p) + nbytes, '\0',
998: sizeof(*p) - nbytes);
999: return 0;
1000: }
1001:
1002: private int
1003: mget(struct magic_set *ms, const unsigned char *s,
1004: struct magic *m, size_t nbytes, unsigned int cont_level)
1005: {
1006: uint32_t offset = ms->offset;
1007: uint32_t count = m->str_range;
1008: union VALUETYPE *p = &ms->ms_value;
1009:
1010: if (mcopy(ms, p, m->type, m->flag & INDIR, s, offset, nbytes, count) == -1)
1011: return -1;
1012:
1013: if ((ms->flags & MAGIC_DEBUG) != 0) {
1014: mdebug(offset, (char *)(void *)p, sizeof(union VALUETYPE));
1015: }
1016:
1017: if (m->flag & INDIR) {
1018: int off = m->in_offset;
1019: if (m->in_op & FILE_OPINDIRECT) {
1020: const union VALUETYPE *q =
1021: ((const void *)(s + offset + off));
1022: switch (m->in_type) {
1023: case FILE_BYTE:
1024: off = q->b;
1025: break;
1026: case FILE_SHORT:
1027: off = q->h;
1028: break;
1029: case FILE_BESHORT:
1030: off = (short)((q->hs[0]<<8)|(q->hs[1]));
1031: break;
1032: case FILE_LESHORT:
1033: off = (short)((q->hs[1]<<8)|(q->hs[0]));
1034: break;
1035: case FILE_LONG:
1036: off = q->l;
1037: break;
1038: case FILE_BELONG:
1039: case FILE_BEID3:
1040: off = (int32_t)((q->hl[0]<<24)|(q->hl[1]<<16)|
1041: (q->hl[2]<<8)|(q->hl[3]));
1042: break;
1043: case FILE_LEID3:
1044: case FILE_LELONG:
1045: off = (int32_t)((q->hl[3]<<24)|(q->hl[2]<<16)|
1046: (q->hl[1]<<8)|(q->hl[0]));
1047: break;
1048: case FILE_MELONG:
1049: off = (int32_t)((q->hl[1]<<24)|(q->hl[0]<<16)|
1050: (q->hl[3]<<8)|(q->hl[2]));
1051: break;
1052: }
1053: }
1054: switch (m->in_type) {
1055: case FILE_BYTE:
1056: if (nbytes < (offset + 1))
1057: return 0;
1058: if (off) {
1059: switch (m->in_op & FILE_OPS_MASK) {
1060: case FILE_OPAND:
1061: offset = p->b & off;
1062: break;
1063: case FILE_OPOR:
1064: offset = p->b | off;
1065: break;
1066: case FILE_OPXOR:
1067: offset = p->b ^ off;
1068: break;
1069: case FILE_OPADD:
1070: offset = p->b + off;
1071: break;
1072: case FILE_OPMINUS:
1073: offset = p->b - off;
1074: break;
1075: case FILE_OPMULTIPLY:
1076: offset = p->b * off;
1077: break;
1078: case FILE_OPDIVIDE:
1079: offset = p->b / off;
1080: break;
1081: case FILE_OPMODULO:
1082: offset = p->b % off;
1083: break;
1084: }
1085: } else
1086: offset = p->b;
1087: if (m->in_op & FILE_OPINVERSE)
1088: offset = ~offset;
1089: break;
1090: case FILE_BESHORT:
1091: if (nbytes < (offset + 2))
1092: return 0;
1093: if (off) {
1094: switch (m->in_op & FILE_OPS_MASK) {
1095: case FILE_OPAND:
1096: offset = (short)((p->hs[0]<<8)|
1097: (p->hs[1])) &
1098: off;
1099: break;
1100: case FILE_OPOR:
1101: offset = (short)((p->hs[0]<<8)|
1102: (p->hs[1])) |
1103: off;
1104: break;
1105: case FILE_OPXOR:
1106: offset = (short)((p->hs[0]<<8)|
1107: (p->hs[1])) ^
1108: off;
1109: break;
1110: case FILE_OPADD:
1111: offset = (short)((p->hs[0]<<8)|
1112: (p->hs[1])) +
1113: off;
1114: break;
1115: case FILE_OPMINUS:
1116: offset = (short)((p->hs[0]<<8)|
1117: (p->hs[1])) -
1118: off;
1119: break;
1120: case FILE_OPMULTIPLY:
1121: offset = (short)((p->hs[0]<<8)|
1122: (p->hs[1])) *
1123: off;
1124: break;
1125: case FILE_OPDIVIDE:
1126: offset = (short)((p->hs[0]<<8)|
1127: (p->hs[1])) /
1128: off;
1129: break;
1130: case FILE_OPMODULO:
1131: offset = (short)((p->hs[0]<<8)|
1132: (p->hs[1])) %
1133: off;
1134: break;
1135: }
1136: } else
1137: offset = (short)((p->hs[0]<<8)|
1138: (p->hs[1]));
1139: if (m->in_op & FILE_OPINVERSE)
1140: offset = ~offset;
1141: break;
1142: case FILE_LESHORT:
1143: if (nbytes < (offset + 2))
1144: return 0;
1145: if (off) {
1146: switch (m->in_op & FILE_OPS_MASK) {
1147: case FILE_OPAND:
1148: offset = (short)((p->hs[1]<<8)|
1149: (p->hs[0])) &
1150: off;
1151: break;
1152: case FILE_OPOR:
1153: offset = (short)((p->hs[1]<<8)|
1154: (p->hs[0])) |
1155: off;
1156: break;
1157: case FILE_OPXOR:
1158: offset = (short)((p->hs[1]<<8)|
1159: (p->hs[0])) ^
1160: off;
1161: break;
1162: case FILE_OPADD:
1163: offset = (short)((p->hs[1]<<8)|
1164: (p->hs[0])) +
1165: off;
1166: break;
1167: case FILE_OPMINUS:
1168: offset = (short)((p->hs[1]<<8)|
1169: (p->hs[0])) -
1170: off;
1171: break;
1172: case FILE_OPMULTIPLY:
1173: offset = (short)((p->hs[1]<<8)|
1174: (p->hs[0])) *
1175: off;
1176: break;
1177: case FILE_OPDIVIDE:
1178: offset = (short)((p->hs[1]<<8)|
1179: (p->hs[0])) /
1180: off;
1181: break;
1182: case FILE_OPMODULO:
1183: offset = (short)((p->hs[1]<<8)|
1184: (p->hs[0])) %
1185: off;
1186: break;
1187: }
1188: } else
1189: offset = (short)((p->hs[1]<<8)|
1190: (p->hs[0]));
1191: if (m->in_op & FILE_OPINVERSE)
1192: offset = ~offset;
1193: break;
1194: case FILE_SHORT:
1195: if (nbytes < (offset + 2))
1196: return 0;
1197: if (off) {
1198: switch (m->in_op & FILE_OPS_MASK) {
1199: case FILE_OPAND:
1200: offset = p->h & off;
1201: break;
1202: case FILE_OPOR:
1203: offset = p->h | off;
1204: break;
1205: case FILE_OPXOR:
1206: offset = p->h ^ off;
1207: break;
1208: case FILE_OPADD:
1209: offset = p->h + off;
1210: break;
1211: case FILE_OPMINUS:
1212: offset = p->h - off;
1213: break;
1214: case FILE_OPMULTIPLY:
1215: offset = p->h * off;
1216: break;
1217: case FILE_OPDIVIDE:
1218: offset = p->h / off;
1219: break;
1220: case FILE_OPMODULO:
1221: offset = p->h % off;
1222: break;
1223: }
1224: }
1225: else
1226: offset = p->h;
1227: if (m->in_op & FILE_OPINVERSE)
1228: offset = ~offset;
1229: break;
1230: case FILE_BELONG:
1231: case FILE_BEID3:
1232: if (nbytes < (offset + 4))
1233: return 0;
1234: if (off) {
1235: switch (m->in_op & FILE_OPS_MASK) {
1236: case FILE_OPAND:
1237: offset = (int32_t)((p->hl[0]<<24)|
1238: (p->hl[1]<<16)|
1239: (p->hl[2]<<8)|
1240: (p->hl[3])) &
1241: off;
1242: break;
1243: case FILE_OPOR:
1244: offset = (int32_t)((p->hl[0]<<24)|
1245: (p->hl[1]<<16)|
1246: (p->hl[2]<<8)|
1247: (p->hl[3])) |
1248: off;
1249: break;
1250: case FILE_OPXOR:
1251: offset = (int32_t)((p->hl[0]<<24)|
1252: (p->hl[1]<<16)|
1253: (p->hl[2]<<8)|
1254: (p->hl[3])) ^
1255: off;
1256: break;
1257: case FILE_OPADD:
1258: offset = (int32_t)((p->hl[0]<<24)|
1259: (p->hl[1]<<16)|
1260: (p->hl[2]<<8)|
1261: (p->hl[3])) +
1262: off;
1263: break;
1264: case FILE_OPMINUS:
1265: offset = (int32_t)((p->hl[0]<<24)|
1266: (p->hl[1]<<16)|
1267: (p->hl[2]<<8)|
1268: (p->hl[3])) -
1269: off;
1270: break;
1271: case FILE_OPMULTIPLY:
1272: offset = (int32_t)((p->hl[0]<<24)|
1273: (p->hl[1]<<16)|
1274: (p->hl[2]<<8)|
1275: (p->hl[3])) *
1276: off;
1277: break;
1278: case FILE_OPDIVIDE:
1279: offset = (int32_t)((p->hl[0]<<24)|
1280: (p->hl[1]<<16)|
1281: (p->hl[2]<<8)|
1282: (p->hl[3])) /
1283: off;
1284: break;
1285: case FILE_OPMODULO:
1286: offset = (int32_t)((p->hl[0]<<24)|
1287: (p->hl[1]<<16)|
1288: (p->hl[2]<<8)|
1289: (p->hl[3])) %
1290: off;
1291: break;
1292: }
1293: } else
1294: offset = (int32_t)((p->hl[0]<<24)|
1295: (p->hl[1]<<16)|
1296: (p->hl[2]<<8)|
1297: (p->hl[3]));
1298: if (m->in_op & FILE_OPINVERSE)
1299: offset = ~offset;
1300: break;
1301: case FILE_LELONG:
1302: case FILE_LEID3:
1303: if (nbytes < (offset + 4))
1304: return 0;
1305: if (off) {
1306: switch (m->in_op & FILE_OPS_MASK) {
1307: case FILE_OPAND:
1308: offset = (int32_t)((p->hl[3]<<24)|
1309: (p->hl[2]<<16)|
1310: (p->hl[1]<<8)|
1311: (p->hl[0])) &
1312: off;
1313: break;
1314: case FILE_OPOR:
1315: offset = (int32_t)((p->hl[3]<<24)|
1316: (p->hl[2]<<16)|
1317: (p->hl[1]<<8)|
1318: (p->hl[0])) |
1319: off;
1320: break;
1321: case FILE_OPXOR:
1322: offset = (int32_t)((p->hl[3]<<24)|
1323: (p->hl[2]<<16)|
1324: (p->hl[1]<<8)|
1325: (p->hl[0])) ^
1326: off;
1327: break;
1328: case FILE_OPADD:
1329: offset = (int32_t)((p->hl[3]<<24)|
1330: (p->hl[2]<<16)|
1331: (p->hl[1]<<8)|
1332: (p->hl[0])) +
1333: off;
1334: break;
1335: case FILE_OPMINUS:
1336: offset = (int32_t)((p->hl[3]<<24)|
1337: (p->hl[2]<<16)|
1338: (p->hl[1]<<8)|
1339: (p->hl[0])) -
1340: off;
1341: break;
1342: case FILE_OPMULTIPLY:
1343: offset = (int32_t)((p->hl[3]<<24)|
1344: (p->hl[2]<<16)|
1345: (p->hl[1]<<8)|
1346: (p->hl[0])) *
1347: off;
1348: break;
1349: case FILE_OPDIVIDE:
1350: offset = (int32_t)((p->hl[3]<<24)|
1351: (p->hl[2]<<16)|
1352: (p->hl[1]<<8)|
1353: (p->hl[0])) /
1354: off;
1355: break;
1356: case FILE_OPMODULO:
1357: offset = (int32_t)((p->hl[3]<<24)|
1358: (p->hl[2]<<16)|
1359: (p->hl[1]<<8)|
1360: (p->hl[0])) %
1361: off;
1362: break;
1363: }
1364: } else
1365: offset = (int32_t)((p->hl[3]<<24)|
1366: (p->hl[2]<<16)|
1367: (p->hl[1]<<8)|
1368: (p->hl[0]));
1369: if (m->in_op & FILE_OPINVERSE)
1370: offset = ~offset;
1371: break;
1372: case FILE_MELONG:
1373: if (nbytes < (offset + 4))
1374: return 0;
1375: if (off) {
1376: switch (m->in_op & FILE_OPS_MASK) {
1377: case FILE_OPAND:
1378: offset = (int32_t)((p->hl[1]<<24)|
1379: (p->hl[0]<<16)|
1380: (p->hl[3]<<8)|
1381: (p->hl[2])) &
1382: off;
1383: break;
1384: case FILE_OPOR:
1385: offset = (int32_t)((p->hl[1]<<24)|
1386: (p->hl[0]<<16)|
1387: (p->hl[3]<<8)|
1388: (p->hl[2])) |
1389: off;
1390: break;
1391: case FILE_OPXOR:
1392: offset = (int32_t)((p->hl[1]<<24)|
1393: (p->hl[0]<<16)|
1394: (p->hl[3]<<8)|
1395: (p->hl[2])) ^
1396: off;
1397: break;
1398: case FILE_OPADD:
1399: offset = (int32_t)((p->hl[1]<<24)|
1400: (p->hl[0]<<16)|
1401: (p->hl[3]<<8)|
1402: (p->hl[2])) +
1403: off;
1404: break;
1405: case FILE_OPMINUS:
1406: offset = (int32_t)((p->hl[1]<<24)|
1407: (p->hl[0]<<16)|
1408: (p->hl[3]<<8)|
1409: (p->hl[2])) -
1410: off;
1411: break;
1412: case FILE_OPMULTIPLY:
1413: offset = (int32_t)((p->hl[1]<<24)|
1414: (p->hl[0]<<16)|
1415: (p->hl[3]<<8)|
1416: (p->hl[2])) *
1417: off;
1418: break;
1419: case FILE_OPDIVIDE:
1420: offset = (int32_t)((p->hl[1]<<24)|
1421: (p->hl[0]<<16)|
1422: (p->hl[3]<<8)|
1423: (p->hl[2])) /
1424: off;
1425: break;
1426: case FILE_OPMODULO:
1427: offset = (int32_t)((p->hl[1]<<24)|
1428: (p->hl[0]<<16)|
1429: (p->hl[3]<<8)|
1430: (p->hl[2])) %
1431: off;
1432: break;
1433: }
1434: } else
1435: offset = (int32_t)((p->hl[1]<<24)|
1436: (p->hl[0]<<16)|
1437: (p->hl[3]<<8)|
1438: (p->hl[2]));
1439: if (m->in_op & FILE_OPINVERSE)
1440: offset = ~offset;
1441: break;
1442: case FILE_LONG:
1443: if (nbytes < (offset + 4))
1444: return 0;
1445: if (off) {
1446: switch (m->in_op & FILE_OPS_MASK) {
1447: case FILE_OPAND:
1448: offset = p->l & off;
1449: break;
1450: case FILE_OPOR:
1451: offset = p->l | off;
1452: break;
1453: case FILE_OPXOR:
1454: offset = p->l ^ off;
1455: break;
1456: case FILE_OPADD:
1457: offset = p->l + off;
1458: break;
1459: case FILE_OPMINUS:
1460: offset = p->l - off;
1461: break;
1462: case FILE_OPMULTIPLY:
1463: offset = p->l * off;
1464: break;
1465: case FILE_OPDIVIDE:
1466: offset = p->l / off;
1467: break;
1468: case FILE_OPMODULO:
1469: offset = p->l % off;
1470: break;
1471: }
1472: } else
1473: offset = p->l;
1474: if (m->in_op & FILE_OPINVERSE)
1475: offset = ~offset;
1476: break;
1477: }
1478:
1479: switch (m->in_type) {
1480: case FILE_LEID3:
1481: case FILE_BEID3:
1482: offset = ((((offset >> 0) & 0x7f) << 0) |
1483: (((offset >> 8) & 0x7f) << 7) |
1484: (((offset >> 16) & 0x7f) << 14) |
1485: (((offset >> 24) & 0x7f) << 21)) + 10;
1486: break;
1487: default:
1488: break;
1489: }
1490:
1491: if (m->flag & INDIROFFADD) {
1492: offset += ms->c.li[cont_level-1].off;
1493: }
1494: if (mcopy(ms, p, m->type, 0, s, offset, nbytes, count) == -1)
1495: return -1;
1496: ms->offset = offset;
1497:
1498: if ((ms->flags & MAGIC_DEBUG) != 0) {
1499: mdebug(offset, (char *)(void *)p,
1500: sizeof(union VALUETYPE));
1501: }
1502: }
1503:
1504: /* Verify we have enough data to match magic type */
1505: switch (m->type) {
1506: case FILE_BYTE:
1507: if (nbytes < (offset + 1)) /* should alway be true */
1508: return 0;
1509: break;
1510:
1511: case FILE_SHORT:
1512: case FILE_BESHORT:
1513: case FILE_LESHORT:
1514: if (nbytes < (offset + 2))
1515: return 0;
1516: break;
1517:
1518: case FILE_LONG:
1519: case FILE_BELONG:
1520: case FILE_LELONG:
1521: case FILE_MELONG:
1522: case FILE_DATE:
1523: case FILE_BEDATE:
1524: case FILE_LEDATE:
1525: case FILE_MEDATE:
1526: case FILE_LDATE:
1527: case FILE_BELDATE:
1528: case FILE_LELDATE:
1529: case FILE_MELDATE:
1530: case FILE_FLOAT:
1531: case FILE_BEFLOAT:
1532: case FILE_LEFLOAT:
1533: if (nbytes < (offset + 4))
1534: return 0;
1535: break;
1536:
1537: case FILE_DOUBLE:
1538: case FILE_BEDOUBLE:
1539: case FILE_LEDOUBLE:
1540: if (nbytes < (offset + 8))
1541: return 0;
1542: break;
1543:
1544: case FILE_STRING:
1545: case FILE_PSTRING:
1546: case FILE_SEARCH:
1547: if (nbytes < (offset + m->vallen))
1548: return 0;
1549: break;
1550:
1551: case FILE_REGEX:
1552: if (nbytes < offset)
1553: return 0;
1554: break;
1555:
1556: case FILE_INDIRECT:
1557: if ((ms->flags & (MAGIC_MIME|MAGIC_APPLE)) == 0 &&
1558: file_printf(ms, m->desc) == -1)
1559: return -1;
1560: if (nbytes < offset)
1561: return 0;
1562: return file_softmagic(ms, s + offset, nbytes - offset,
1563: BINTEST);
1564:
1565: case FILE_DEFAULT: /* nothing to check */
1566: default:
1567: break;
1568: }
1569: if (!mconvert(ms, m))
1570: return 0;
1571: return 1;
1572: }
1573:
1574: private uint64_t
1575: file_strncmp(const char *s1, const char *s2, size_t len, uint32_t flags)
1576: {
1577: /*
1578: * Convert the source args to unsigned here so that (1) the
1579: * compare will be unsigned as it is in strncmp() and (2) so
1580: * the ctype functions will work correctly without extra
1581: * casting.
1582: */
1583: const unsigned char *a = (const unsigned char *)s1;
1584: const unsigned char *b = (const unsigned char *)s2;
1585: uint64_t v;
1586:
1587: /*
1588: * What we want here is v = strncmp(s1, s2, len),
1589: * but ignoring any nulls.
1590: */
1591: v = 0;
1592: if (0L == flags) { /* normal string: do it fast */
1593: while (len-- > 0)
1594: if ((v = *b++ - *a++) != '\0')
1595: break;
1596: }
1597: else { /* combine the others */
1598: while (len-- > 0) {
1599: if ((flags & STRING_IGNORE_LOWERCASE) &&
1600: islower(*a)) {
1601: if ((v = tolower(*b++) - *a++) != '\0')
1602: break;
1603: }
1604: else if ((flags & STRING_IGNORE_UPPERCASE) &&
1605: isupper(*a)) {
1606: if ((v = toupper(*b++) - *a++) != '\0')
1607: break;
1608: }
1609: else if ((flags & STRING_COMPACT_BLANK) &&
1610: isspace(*a)) {
1611: a++;
1612: if (isspace(*b++)) {
1613: while (isspace(*b))
1614: b++;
1615: }
1616: else {
1617: v = 1;
1618: break;
1619: }
1620: }
1621: else if ((flags & STRING_COMPACT_OPTIONAL_BLANK) &&
1622: isspace(*a)) {
1623: a++;
1624: while (isspace(*b))
1625: b++;
1626: }
1627: else {
1628: if ((v = *b++ - *a++) != '\0')
1629: break;
1630: }
1631: }
1632: }
1633: return v;
1634: }
1635:
1636: private uint64_t
1637: file_strncmp16(const char *a, const char *b, size_t len, uint32_t flags)
1638: {
1639: /*
1640: * XXX - The 16-bit string compare probably needs to be done
1641: * differently, especially if the flags are to be supported.
1642: * At the moment, I am unsure.
1643: */
1644: flags = 0;
1645: return file_strncmp(a, b, len, flags);
1646: }
1647:
1648: private void
1649: convert_libmagic_pattern(zval *pattern, int options)
1650: {
1651: int i, j=0;
1652: char *t;
1653:
1654: t = (char *) safe_emalloc(Z_STRLEN_P(pattern), 2, 5);
1655:
1656: t[j++] = '~';
1657:
1658: for (i=0; i<Z_STRLEN_P(pattern); i++, j++) {
1659: switch (Z_STRVAL_P(pattern)[i]) {
1660: case '?':
1661: t[j] = '.';
1662: break;
1663: case '*':
1664: t[j++] = '.';
1665: t[j] = '*';
1666: break;
1667: case '.':
1668: t[j++] = '\\';
1669: t[j] = '.';
1670: break;
1671: case '\\':
1672: t[j++] = '\\';
1673: t[j] = '\\';
1674: break;
1675: case '(':
1676: t[j++] = '\\';
1677: t[j] = '(';
1678: break;
1679: case ')':
1680: t[j++] = '\\';
1681: t[j] = ')';
1682: break;
1683: case '~':
1684: t[j++] = '\\';
1685: t[j] = '~';
1686: break;
1687: default:
1688: t[j] = Z_STRVAL_P(pattern)[i];
1689: break;
1690: }
1691: }
1692: t[j++] = '~';
1693:
1694: if (options & PCRE_CASELESS)
1695: t[j++] = 'm';
1696:
1697: if (options & PCRE_MULTILINE)
1698: t[j++] = 'i';
1699:
1700: t[j]=0;
1701:
1702: Z_STRVAL_P(pattern) = t;
1703: Z_STRLEN_P(pattern) = j;
1704:
1705: }
1706:
1707: private int
1708: magiccheck(struct magic_set *ms, struct magic *m)
1709: {
1710: uint64_t l = m->value.q;
1711: uint64_t v;
1712: float fl, fv;
1713: double dl, dv;
1714: int matched;
1715: union VALUETYPE *p = &ms->ms_value;
1716:
1717: switch (m->type) {
1718: case FILE_BYTE:
1719: v = p->b;
1720: break;
1721:
1722: case FILE_SHORT:
1723: case FILE_BESHORT:
1724: case FILE_LESHORT:
1725: v = p->h;
1726: break;
1727:
1728: case FILE_LONG:
1729: case FILE_BELONG:
1730: case FILE_LELONG:
1731: case FILE_MELONG:
1732: case FILE_DATE:
1733: case FILE_BEDATE:
1734: case FILE_LEDATE:
1735: case FILE_MEDATE:
1736: case FILE_LDATE:
1737: case FILE_BELDATE:
1738: case FILE_LELDATE:
1739: case FILE_MELDATE:
1740: v = p->l;
1741: break;
1742:
1743: case FILE_QUAD:
1744: case FILE_LEQUAD:
1745: case FILE_BEQUAD:
1746: case FILE_QDATE:
1747: case FILE_BEQDATE:
1748: case FILE_LEQDATE:
1749: case FILE_QLDATE:
1750: case FILE_BEQLDATE:
1751: case FILE_LEQLDATE:
1752: v = p->q;
1753: break;
1754:
1755: case FILE_FLOAT:
1756: case FILE_BEFLOAT:
1757: case FILE_LEFLOAT:
1758: fl = m->value.f;
1759: fv = p->f;
1760: switch (m->reln) {
1761: case 'x':
1762: matched = 1;
1763: break;
1764:
1765: case '!':
1766: matched = fv != fl;
1767: break;
1768:
1769: case '=':
1770: matched = fv == fl;
1771: break;
1772:
1773: case '>':
1774: matched = fv > fl;
1775: break;
1776:
1777: case '<':
1778: matched = fv < fl;
1779: break;
1780:
1781: default:
1782: matched = 0;
1783: file_magerror(ms, "cannot happen with float: invalid relation `%c'",
1784: m->reln);
1785: return -1;
1786: }
1787: return matched;
1788:
1789: case FILE_DOUBLE:
1790: case FILE_BEDOUBLE:
1791: case FILE_LEDOUBLE:
1792: dl = m->value.d;
1793: dv = p->d;
1794: switch (m->reln) {
1795: case 'x':
1796: matched = 1;
1797: break;
1798:
1799: case '!':
1800: matched = dv != dl;
1801: break;
1802:
1803: case '=':
1804: matched = dv == dl;
1805: break;
1806:
1807: case '>':
1808: matched = dv > dl;
1809: break;
1810:
1811: case '<':
1812: matched = dv < dl;
1813: break;
1814:
1815: default:
1816: matched = 0;
1817: file_magerror(ms, "cannot happen with double: invalid relation `%c'", m->reln);
1818: return -1;
1819: }
1820: return matched;
1821:
1822: case FILE_DEFAULT:
1823: l = 0;
1824: v = 0;
1825: break;
1826:
1827: case FILE_STRING:
1828: case FILE_PSTRING:
1829: l = 0;
1830: v = file_strncmp(m->value.s, p->s, (size_t)m->vallen, m->str_flags);
1831: break;
1832:
1833: case FILE_BESTRING16:
1834: case FILE_LESTRING16:
1835: l = 0;
1836: v = file_strncmp16(m->value.s, p->s, (size_t)m->vallen, m->str_flags);
1837: break;
1838:
1839: case FILE_SEARCH: { /* search ms->search.s for the string m->value.s */
1840: size_t slen;
1841: size_t idx;
1842:
1843: if (ms->search.s == NULL)
1844: return 0;
1845:
1846: slen = MIN(m->vallen, sizeof(m->value.s));
1847: l = 0;
1848: v = 0;
1849:
1850: for (idx = 0; m->str_range == 0 || idx < m->str_range; idx++) {
1851: if (slen + idx > ms->search.s_len)
1852: break;
1853:
1854: v = file_strncmp(m->value.s, ms->search.s + idx, slen, m->str_flags);
1855: if (v == 0) { /* found match */
1856: ms->search.offset += idx;
1857: break;
1858: }
1859: }
1860: break;
1861: }
1862: case FILE_REGEX: {
1863: zval *pattern;
1864: int options = 0;
1865: pcre_cache_entry *pce;
1866: TSRMLS_FETCH();
1867:
1868: MAKE_STD_ZVAL(pattern);
1869: ZVAL_STRINGL(pattern, (char *)m->value.s, m->vallen, 0);
1870:
1871: options |= PCRE_MULTILINE;
1872:
1873: if (m->str_flags & STRING_IGNORE_CASE) {
1874: options |= PCRE_CASELESS;
1875: }
1876:
1877: convert_libmagic_pattern(pattern, options);
1878:
1879: #if (PHP_MAJOR_VERSION < 6)
1880: if ((pce = pcre_get_compiled_regex_cache(Z_STRVAL_P(pattern), Z_STRLEN_P(pattern) TSRMLS_CC)) == NULL) {
1881: #else
1882: if ((pce = pcre_get_compiled_regex_cache(IS_STRING, Z_STRVAL_P(pattern), Z_STRLEN_P(pattern) TSRMLS_CC)) == NULL) {
1883: #endif
1884: zval_dtor(pattern);
1885: FREE_ZVAL(pattern);
1886: return -1;
1887: } else {
1888: /* pce now contains the compiled regex */
1889: zval *retval;
1890: zval *subpats;
1891: char *haystack;
1892:
1893: MAKE_STD_ZVAL(retval);
1894: ALLOC_INIT_ZVAL(subpats);
1895:
1896: /* Cut the search len from haystack, equals to REG_STARTEND */
1897: haystack = estrndup(ms->search.s, ms->search.s_len);
1898:
1899: /* match v = 0, no match v = 1 */
1900: #if (PHP_MAJOR_VERSION < 6)
1901: php_pcre_match_impl(pce, haystack, ms->search.s_len, retval, subpats, 1, 1, PREG_OFFSET_CAPTURE, 0 TSRMLS_CC);
1902: #else
1903: php_pcre_match_impl(pce, IS_STRING, haystack, ms->search.s_len, retval, subpats, 1, 1, PREG_OFFSET_CAPTURE, 0 TSRMLS_CC);
1904: #endif
1905: /* Free haystack */
1906: efree(haystack);
1907:
1908: if (Z_LVAL_P(retval) < 0) {
1909: zval_ptr_dtor(&subpats);
1910: FREE_ZVAL(retval);
1911: zval_dtor(pattern);
1912: FREE_ZVAL(pattern);
1913: return -1;
1914: } else if ((Z_LVAL_P(retval) > 0) && (Z_TYPE_P(subpats) == IS_ARRAY)) {
1915:
1916: /* Need to fetch global match which equals pmatch[0] */
1917: HashTable *ht = Z_ARRVAL_P(subpats);
1918: HashPosition outer_pos;
1919: zval *pattern_match = NULL, *pattern_offset = NULL;
1920:
1921: zend_hash_internal_pointer_reset_ex(ht, &outer_pos);
1922:
1923: if (zend_hash_has_more_elements_ex(ht, &outer_pos) == SUCCESS &&
1924: zend_hash_move_forward_ex(ht, &outer_pos)) {
1925:
1926: zval **ppzval;
1927:
1928: /* The first element (should be) is the global match
1929: Need to move to the inner array to get the global match */
1930:
1931: if (zend_hash_get_current_data_ex(ht, (void**)&ppzval, &outer_pos) != FAILURE) {
1932:
1933: HashTable *inner_ht;
1934: HashPosition inner_pos;
1935: zval **match, **offset;
1936: zval tmpcopy = **ppzval, matchcopy, offsetcopy;
1937:
1938: zval_copy_ctor(&tmpcopy);
1939: INIT_PZVAL(&tmpcopy);
1940:
1941: inner_ht = Z_ARRVAL(tmpcopy);
1942:
1943: /* If everything goes according to the master plan
1944: tmpcopy now contains two elements:
1945: 0 = the match
1946: 1 = starting position of the match */
1947: zend_hash_internal_pointer_reset_ex(inner_ht, &inner_pos);
1948:
1949: if (zend_hash_has_more_elements_ex(inner_ht, &inner_pos) == SUCCESS &&
1950: zend_hash_move_forward_ex(inner_ht, &inner_pos)) {
1951:
1952: if (zend_hash_get_current_data_ex(inner_ht, (void**)&match, &inner_pos) != FAILURE) {
1953:
1954: matchcopy = **match;
1955: zval_copy_ctor(&matchcopy);
1956: INIT_PZVAL(&matchcopy);
1957: convert_to_string(&matchcopy);
1958:
1959: MAKE_STD_ZVAL(pattern_match);
1960: Z_STRVAL_P(pattern_match) = (char *)Z_STRVAL(matchcopy);
1961: Z_STRLEN_P(pattern_match) = Z_STRLEN(matchcopy);
1962: Z_TYPE_P(pattern_match) = IS_STRING;
1963:
1964: zval_dtor(&matchcopy);
1965: }
1966: }
1967:
1968: if (zend_hash_has_more_elements_ex(inner_ht, &inner_pos) == SUCCESS &&
1969: zend_hash_move_forward_ex(inner_ht, &inner_pos)) {
1970:
1971: if (zend_hash_get_current_data_ex(inner_ht, (void**)&offset, &inner_pos) != FAILURE) {
1972:
1973: offsetcopy = **offset;
1974: zval_copy_ctor(&offsetcopy);
1975: INIT_PZVAL(&offsetcopy);
1976: convert_to_long(&offsetcopy);
1977:
1978: MAKE_STD_ZVAL(pattern_offset);
1979: Z_LVAL_P(pattern_offset) = Z_LVAL(offsetcopy);
1980: Z_TYPE_P(pattern_offset) = IS_LONG;
1981:
1982: zval_dtor(&offsetcopy);
1983: }
1984: }
1985: zval_dtor(&tmpcopy);
1986: }
1987:
1988: if ((pattern_match != NULL) && (pattern_offset != NULL)) {
1989: ms->search.s += (int)Z_LVAL_P(pattern_offset); /* this is where the match starts */
1990: ms->search.offset += (size_t)Z_LVAL_P(pattern_offset); /* this is where the match starts as size_t */
1991: ms->search.rm_len = Z_STRLEN_P(pattern_match) /* This is the length of the matched pattern */;
1992: v = 0;
1993:
1994: efree(pattern_match);
1995: efree(pattern_offset);
1996:
1997: } else {
1998: zval_ptr_dtor(&subpats);
1999: FREE_ZVAL(retval);
2000: zval_dtor(pattern);
2001: FREE_ZVAL(pattern);
2002: return -1;
2003: }
2004: }
2005:
2006:
2007: } else {
2008: v = 1;
2009: }
2010: zval_ptr_dtor(&subpats);
2011: FREE_ZVAL(retval);
2012: }
2013: zval_dtor(pattern);
2014: FREE_ZVAL(pattern);
2015: break;
2016: }
2017: case FILE_INDIRECT:
2018: return 1;
2019: default:
2020: file_magerror(ms, "invalid type %d in magiccheck()", m->type);
2021: return -1;
2022: }
2023:
2024: v = file_signextend(ms, m, v);
2025:
2026: switch (m->reln) {
2027: case 'x':
2028: if ((ms->flags & MAGIC_DEBUG) != 0)
2029: (void) fprintf(stderr, "%llu == *any* = 1\n",
2030: (uint64_t)v);
2031: matched = 1;
2032: break;
2033:
2034: case '!':
2035: matched = v != l;
2036: if ((ms->flags & MAGIC_DEBUG) != 0)
2037: (void) fprintf(stderr, "%llu != %llu = %d\n",
2038: (uint64_t)v, (uint64_t)l,
2039: matched);
2040: break;
2041:
2042: case '=':
2043: matched = v == l;
2044: if ((ms->flags & MAGIC_DEBUG) != 0)
2045: (void) fprintf(stderr, "%llu == %llu = %d\n",
2046: (uint64_t)v, (uint64_t)l,
2047: matched);
2048: break;
2049:
2050: case '>':
2051: if (m->flag & UNSIGNED) {
2052: matched = v > l;
2053: if ((ms->flags & MAGIC_DEBUG) != 0)
2054: (void) fprintf(stderr, "%llu > %llu = %d\n",
2055: (uint64_t)v,
2056: (uint64_t)l, matched);
2057: }
2058: else {
2059: matched = (int64_t) v > (int64_t) l;
2060: if ((ms->flags & MAGIC_DEBUG) != 0)
2061: (void) fprintf(stderr, "%lld > %lld = %d\n",
2062: (uint64_t)v, (uint64_t)l, matched);
2063: }
2064: break;
2065:
2066: case '<':
2067: if (m->flag & UNSIGNED) {
2068: matched = v < l;
2069: if ((ms->flags & MAGIC_DEBUG) != 0)
2070: (void) fprintf(stderr, "%llu < %llu = %d\n",
2071: (uint64_t)v,
2072: (uint64_t)l, matched);
2073: }
2074: else {
2075: matched = (int64_t) v < (int64_t) l;
2076: if ((ms->flags & MAGIC_DEBUG) != 0)
2077: (void) fprintf(stderr, "%lld < %lld = %d\n",
2078: (int64_t)v, (int64_t)l, matched);
2079: }
2080: break;
2081:
2082: case '&':
2083: matched = (v & l) == l;
2084: if ((ms->flags & MAGIC_DEBUG) != 0)
2085: (void) fprintf(stderr, "((%llx & %llx) == %llx) = %d\n",
2086: (uint64_t)v, (uint64_t)l,
2087: (uint64_t)l, matched);
2088: break;
2089:
2090: case '^':
2091: matched = (v & l) != l;
2092: if ((ms->flags & MAGIC_DEBUG) != 0)
2093: (void) fprintf(stderr, "((%llx & %llx) != %llx) = %d\n",
2094: (uint64_t)v, (uint64_t)l,
2095: (uint64_t)l, matched);
2096: break;
2097:
2098: default:
2099: matched = 0;
2100: file_magerror(ms, "cannot happen: invalid relation `%c'",
2101: m->reln);
2102: return -1;
2103: }
2104:
2105: return matched;
2106: }
2107:
2108: private int
2109: handle_annotation(struct magic_set *ms, struct magic *m)
2110: {
2111: if (ms->flags & MAGIC_APPLE) {
2112: if (file_printf(ms, "%.8s", m->apple) == -1)
2113: return -1;
2114: return 1;
2115: }
2116: if ((ms->flags & MAGIC_MIME_TYPE) && m->mimetype[0]) {
2117: if (file_printf(ms, "%s", m->mimetype) == -1)
2118: return -1;
2119: return 1;
2120: }
2121: return 0;
2122: }
2123:
2124: private int
2125: print_sep(struct magic_set *ms, int firstline)
2126: {
2127: if (ms->flags & MAGIC_MIME)
2128: return 0;
2129: if (firstline)
2130: return 0;
2131: /*
2132: * we found another match
2133: * put a newline and '-' to do some simple formatting
2134: */
2135: return file_printf(ms, "\n- ");
2136: }
FreeBSD-CVSweb <freebsd-cvsweb@FreeBSD.org>