root/ext/fileinfo/libmagic/softmagic.c

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

DEFINITIONS

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

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