root/ext/fileinfo/libmagic/softmagic.c

/* [<][>][^][v][top][bottom][index][help] */

DEFINITIONS

This source file includes following definitions.
  1. file_softmagic
  2. file_fmtcheck
  3. match
  4. check_fmt
  5. mprint
  6. moffset
  7. cvt_flip
  8. cvt_8
  9. cvt_16
  10. cvt_32
  11. cvt_64
  12. cvt_float
  13. cvt_double
  14. mconvert
  15. mdebug
  16. mcopy
  17. mget
  18. file_strncmp
  19. file_strncmp16
  20. convert_libmagic_pattern
  21. magiccheck
  22. handle_annotation
  23. print_sep

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

/* [<][>][^][v][top][bottom][index][help] */