Back to index

php5  5.3.10
softmagic.c
Go to the documentation of this file.
00001 /*
00002  * Copyright (c) Ian F. Darwin 1986-1995.
00003  * Software written by Ian F. Darwin and others;
00004  * maintained 1995-present by Christos Zoulas and others.
00005  *
00006  * Redistribution and use in source and binary forms, with or without
00007  * modification, are permitted provided that the following conditions
00008  * are met:
00009  * 1. Redistributions of source code must retain the above copyright
00010  *    notice immediately at the beginning of the file, without modification,
00011  *    this list of conditions, and the following disclaimer.
00012  * 2. Redistributions in binary form must reproduce the above copyright
00013  *    notice, this list of conditions and the following disclaimer in the
00014  *    documentation and/or other materials provided with the distribution.
00015  *
00016  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
00017  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
00018  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
00019  * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE FOR
00020  * ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
00021  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
00022  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
00023  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
00024  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
00025  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
00026  * SUCH DAMAGE.
00027  */
00028 /*
00029  * softmagic - interpret variable magic from MAGIC
00030  */
00031 
00032 #include "file.h"
00033 
00034 #ifndef       lint
00035 FILE_RCSID("@(#)$File: softmagic.c,v 1.135 2009/03/27 22:42:49 christos Exp $")
00036 #endif /* lint */
00037 
00038 #include "magic.h"
00039 #include <string.h>
00040 #include <ctype.h>
00041 #include <stdlib.h>
00042 #include <time.h>
00043 
00044 #ifndef PREG_OFFSET_CAPTURE
00045 # define PREG_OFFSET_CAPTURE                 (1<<8)
00046 #endif
00047 
00048 
00049 
00050 private int match(struct magic_set *, struct magic *, uint32_t,
00051     const unsigned char *, size_t, int);
00052 private int mget(struct magic_set *, const unsigned char *,
00053     struct magic *, size_t, unsigned int);
00054 private int magiccheck(struct magic_set *, struct magic *);
00055 private int32_t mprint(struct magic_set *, struct magic *);
00056 private int32_t moffset(struct magic_set *, struct magic *);
00057 private void mdebug(uint32_t, const char *, size_t);
00058 private int mcopy(struct magic_set *, union VALUETYPE *, int, int,
00059     const unsigned char *, uint32_t, size_t, size_t);
00060 private int mconvert(struct magic_set *, struct magic *);
00061 private int print_sep(struct magic_set *, int);
00062 private int handle_annotation(struct magic_set *, struct magic *);
00063 private void cvt_8(union VALUETYPE *, const struct magic *);
00064 private void cvt_16(union VALUETYPE *, const struct magic *);
00065 private void cvt_32(union VALUETYPE *, const struct magic *);
00066 private void cvt_64(union VALUETYPE *, const struct magic *);
00067 
00068 /*
00069  * softmagic - lookup one file in parsed, in-memory copy of database
00070  * Passed the name and FILE * of one file to be typed.
00071  */
00072 /*ARGSUSED1*/        /* nbytes passed for regularity, maybe need later */
00073 protected int
00074 file_softmagic(struct magic_set *ms, const unsigned char *buf, size_t nbytes, int mode)
00075 {
00076        struct mlist *ml;
00077        int rv;
00078        for (ml = ms->mlist->next; ml != ms->mlist; ml = ml->next)
00079               if ((rv = match(ms, ml->magic, ml->nmagic, buf, nbytes, mode)) != 0)
00080                      return rv;
00081 
00082        return 0;
00083 }
00084 
00085 /*
00086  * Go through the whole list, stopping if you find a match.  Process all
00087  * the continuations of that match before returning.
00088  *
00089  * We support multi-level continuations:
00090  *
00091  *     At any time when processing a successful top-level match, there is a
00092  *     current continuation level; it represents the level of the last
00093  *     successfully matched continuation.
00094  *
00095  *     Continuations above that level are skipped as, if we see one, it
00096  *     means that the continuation that controls them - i.e, the
00097  *     lower-level continuation preceding them - failed to match.
00098  *
00099  *     Continuations below that level are processed as, if we see one,
00100  *     it means we've finished processing or skipping higher-level
00101  *     continuations under the control of a successful or unsuccessful
00102  *     lower-level continuation, and are now seeing the next lower-level
00103  *     continuation and should process it.  The current continuation
00104  *     level reverts to the level of the one we're seeing.
00105  *
00106  *     Continuations at the current level are processed as, if we see
00107  *     one, there's no lower-level continuation that may have failed.
00108  *
00109  *     If a continuation matches, we bump the current continuation level
00110  *     so that higher-level continuations are processed.
00111  */
00112 private int
00113 match(struct magic_set *ms, struct magic *magic, uint32_t nmagic,
00114     const unsigned char *s, size_t nbytes, int mode)
00115 {
00116        uint32_t magindex = 0;
00117        unsigned int cont_level = 0;
00118        int need_separator = 0;
00119        int returnval = 0, e; /* if a match is found it is set to 1*/
00120        int firstline = 1; /* a flag to print X\n  X\n- X */
00121        int printed_something = 0;
00122        int print = (ms->flags & (MAGIC_MIME|MAGIC_APPLE)) == 0;
00123 
00124        if (file_check_mem(ms, cont_level) == -1)
00125               return -1;
00126 
00127        for (magindex = 0; magindex < nmagic; magindex++) {
00128               int flush = 0;
00129               struct magic *m = &magic[magindex];
00130 
00131               if ((m->flag & BINTEST) != mode) {
00132                      /* Skip sub-tests */
00133                      while (magindex < nmagic - 1 && magic[magindex + 1].cont_level != 0) {
00134                             magindex++;
00135                      }
00136                      continue; /* Skip to next top-level test*/
00137               }
00138 
00139               ms->offset = m->offset;
00140               ms->line = m->lineno;
00141 
00142               /* if main entry matches, print it... */
00143               switch (mget(ms, s, m, nbytes, cont_level)) {
00144               case -1:
00145                      return -1;
00146               case 0:
00147                      flush = m->reln != '!';
00148                      break;
00149               default:
00150                      if (m->type == FILE_INDIRECT)
00151                             returnval = 1;
00152                             
00153                      switch (magiccheck(ms, m)) {
00154                      case -1:
00155                             return -1;
00156                      case 0:
00157                             flush++;
00158                             break;
00159                      default:
00160                             flush = 0;
00161                             break;
00162                      }
00163                      break;
00164               }
00165               if (flush) {
00166                      /*
00167                       * main entry didn't match,
00168                       * flush its continuations
00169                       */
00170                      while (magindex < nmagic - 1 && magic[magindex + 1].cont_level != 0) {
00171                             magindex++;
00172                      }
00173                      continue;
00174               }
00175 
00176               /*
00177                * If we are going to print something, we'll need to print
00178                * a blank before we print something else.
00179                */
00180               if (*m->desc) {
00181                      need_separator = 1;
00182                      printed_something = 1;
00183                      if ((e = handle_annotation(ms, m)) != 0)
00184                             return e;
00185                      if (print_sep(ms, firstline) == -1)
00186                             return -1;
00187               }
00188 
00189 
00190               if (print && mprint(ms, m) == -1)
00191                      return -1;
00192 
00193               ms->c.li[cont_level].off = moffset(ms, m);
00194 
00195               /* and any continuations that match */
00196               if (file_check_mem(ms, ++cont_level) == -1)
00197                      return -1;
00198 
00199               while (magindex < nmagic - 1 && magic[magindex + 1].cont_level != 0) {
00200                      magindex++;
00201                      m = &magic[magindex];
00202                      ms->line = m->lineno; /* for messages */
00203 
00204                      if (cont_level < m->cont_level)
00205                             continue;
00206                      if (cont_level > m->cont_level) {
00207                             /*
00208                              * We're at the end of the level
00209                              * "cont_level" continuations.
00210                              */
00211                             cont_level = m->cont_level;
00212                      }
00213                      ms->offset = m->offset;
00214                      if (m->flag & OFFADD) {
00215                             ms->offset += ms->c.li[cont_level - 1].off;
00216                      }
00217 
00218 #ifdef ENABLE_CONDITIONALS
00219                      if (m->cond == COND_ELSE ||
00220                          m->cond == COND_ELIF) {
00221                             if (ms->c.li[cont_level].last_match == 1)
00222                                    continue;
00223                      }
00224 #endif
00225                      switch (mget(ms, s, m, nbytes, cont_level)) {
00226                      case -1:
00227                             return -1;
00228                      case 0:
00229                             if (m->reln != '!')
00230                                    continue;
00231                             flush = 1;
00232                             break;
00233                      default:
00234                             if (m->type == FILE_INDIRECT)
00235                                    returnval = 1;
00236                             flush = 0;
00237                             break;
00238                      }
00239 
00240                      switch (flush ? 1 : magiccheck(ms, m)) {
00241                      case -1:
00242                             return -1;
00243                      case 0:
00244 #ifdef ENABLE_CONDITIONALS
00245                             ms->c.li[cont_level].last_match = 0;
00246 #endif
00247                             break;
00248                      default:
00249 #ifdef ENABLE_CONDITIONALS
00250                             ms->c.li[cont_level].last_match = 1;
00251 #endif
00252                             if (m->type != FILE_DEFAULT)
00253                                    ms->c.li[cont_level].got_match = 1;
00254                             else if (ms->c.li[cont_level].got_match) {
00255                                    ms->c.li[cont_level].got_match = 0;
00256                                    break;
00257                             }
00258                             /*
00259                              * If we are going to print something,
00260                              * make sure that we have a separator first.
00261                              */
00262                             if (*m->desc) {
00263                                    if ((e = handle_annotation(ms, m)) != 0)
00264                                           return e;
00265                                    if (!printed_something) {
00266                                           printed_something = 1;
00267                                           if (print_sep(ms, firstline)
00268                                               == -1)
00269                                                  return -1;
00270                                    }
00271                             }
00272                             /*
00273                              * This continuation matched.  Print
00274                              * its message, with a blank before it
00275                              * if the previous item printed and
00276                              * this item isn't empty.
00277                              */
00278                             /* space if previous printed */
00279                             if (need_separator
00280                                 && ((m->flag & NOSPACE) == 0)
00281                                 && *m->desc) {
00282                                    if (print &&
00283                                        file_printf(ms, " ") == -1)
00284                                           return -1;
00285                                    need_separator = 0;
00286                             }
00287                             if (print && mprint(ms, m) == -1)
00288                                    return -1;
00289 
00290                             ms->c.li[cont_level].off = moffset(ms, m);
00291 
00292                             if (*m->desc)
00293                                    need_separator = 1;
00294 
00295                             /*
00296                              * If we see any continuations
00297                              * at a higher level,
00298                              * process them.
00299                              */
00300                             if (file_check_mem(ms, ++cont_level) == -1)
00301                                    return -1;
00302                             break;
00303                      }
00304               }
00305               if (printed_something) {
00306                      firstline = 0;
00307                      if (print)
00308                             returnval = 1;
00309               }
00310               if ((ms->flags & MAGIC_CONTINUE) == 0 && printed_something) {
00311                      return returnval; /* don't keep searching */
00312               }
00313        }
00314        return returnval;  /* This is hit if -k is set or there is no match */
00315 }
00316 
00317 private int
00318 check_fmt(struct magic_set *ms, struct magic *m)
00319 {
00320        pcre *pce;
00321        int re_options;
00322        pcre_extra *re_extra;
00323        TSRMLS_FETCH();
00324        
00325        if (strchr(m->desc, '%') == NULL) {
00326               return 0;
00327        }
00328        
00329        if ((pce = pcre_get_compiled_regex("~%[-0-9.]*s~", &re_extra, &re_options TSRMLS_CC)) == NULL) {
00330               return -1;
00331        } else {
00332               return !pcre_exec(pce, re_extra, m->desc, strlen(m->desc), 0, re_options, NULL, 0);
00333        }
00334 }
00335 
00336 private int32_t
00337 mprint(struct magic_set *ms, struct magic *m)
00338 {
00339        uint64_t v;
00340        float vf;
00341        double vd;
00342        int64_t t = 0;
00343        char buf[128];
00344        union VALUETYPE *p = &ms->ms_value;
00345 
00346        switch (m->type) {
00347        case FILE_BYTE:
00348               v = file_signextend(ms, m, (uint64_t)p->b);
00349               switch (check_fmt(ms, m)) {
00350               case -1:
00351                      return -1;
00352               case 1:
00353                      (void)snprintf(buf, sizeof(buf), "%c",
00354                          (unsigned char)v);
00355                      if (file_printf(ms, m->desc, buf) == -1)
00356                             return -1;
00357                      break;
00358               default:
00359                      if (file_printf(ms, m->desc, (unsigned char) v) == -1)
00360                             return -1;
00361                      break;
00362               }
00363               t = ms->offset + sizeof(char);
00364               break;
00365 
00366        case FILE_SHORT:
00367        case FILE_BESHORT:
00368        case FILE_LESHORT:
00369               v = file_signextend(ms, m, (uint64_t)p->h);
00370               switch (check_fmt(ms, m)) {
00371               case -1:
00372                      return -1;
00373               case 1:
00374                      (void)snprintf(buf, sizeof(buf), "%hu",
00375                          (unsigned short)v);
00376                      if (file_printf(ms, m->desc, buf) == -1)
00377                             return -1;
00378                      break;
00379               default:
00380                      if (
00381                          file_printf(ms, m->desc, (unsigned short) v) == -1)
00382                             return -1;
00383                      break;
00384               }
00385               t = ms->offset + sizeof(short);
00386               break;
00387 
00388        case FILE_LONG:
00389        case FILE_BELONG:
00390        case FILE_LELONG:
00391        case FILE_MELONG:
00392               v = file_signextend(ms, m, (uint64_t)p->l);
00393               switch (check_fmt(ms, m)) {
00394               case -1:
00395                      return -1;
00396               case 1:
00397                      (void)snprintf(buf, sizeof(buf), "%u", (uint32_t)v);
00398                      if (file_printf(ms, m->desc, buf) == -1)
00399                             return -1;
00400                      break;
00401               default:
00402                      if (file_printf(ms, m->desc, (uint32_t) v) == -1)
00403                             return -1;
00404                      break;
00405               }
00406               t = ms->offset + sizeof(int32_t);
00407               break;
00408 
00409        case FILE_QUAD:
00410        case FILE_BEQUAD:
00411        case FILE_LEQUAD:
00412               v = file_signextend(ms, m, p->q);
00413               if (file_printf(ms, m->desc, (uint64_t) v) == -1)
00414                      return -1;
00415               t = ms->offset + sizeof(int64_t);
00416               break;
00417 
00418        case FILE_STRING:
00419        case FILE_PSTRING:
00420        case FILE_BESTRING16:
00421        case FILE_LESTRING16:
00422               if (m->reln == '=' || m->reln == '!') {
00423                      if (file_printf(ms, m->desc, m->value.s) == -1)
00424                             return -1;
00425                      t = ms->offset + m->vallen;
00426               }
00427               else {
00428                      if (*m->value.s == '\0')
00429                             p->s[strcspn(p->s, "\n")] = '\0';
00430                      if (file_printf(ms, m->desc, p->s) == -1)
00431                             return -1;
00432                      t = ms->offset + strlen(p->s);
00433                      if (m->type == FILE_PSTRING)
00434                             t++;
00435               }
00436               break;
00437 
00438        case FILE_DATE:
00439        case FILE_BEDATE:
00440        case FILE_LEDATE:
00441        case FILE_MEDATE:
00442               if (file_printf(ms, m->desc, file_fmttime(p->l, 1)) == -1)
00443                      return -1;
00444               t = ms->offset + sizeof(time_t);
00445               break;
00446 
00447        case FILE_LDATE:
00448        case FILE_BELDATE:
00449        case FILE_LELDATE:
00450        case FILE_MELDATE:
00451               if (file_printf(ms, m->desc, file_fmttime(p->l, 0)) == -1)
00452                      return -1;
00453               t = ms->offset + sizeof(time_t);
00454               break;
00455 
00456        case FILE_QDATE:
00457        case FILE_BEQDATE:
00458        case FILE_LEQDATE:
00459               if (file_printf(ms, m->desc, file_fmttime((uint32_t)p->q,
00460                   1)) == -1)
00461                      return -1;
00462               t = ms->offset + sizeof(uint64_t);
00463               break;
00464 
00465        case FILE_QLDATE:
00466        case FILE_BEQLDATE:
00467        case FILE_LEQLDATE:
00468               if (file_printf(ms, m->desc, file_fmttime((uint32_t)p->q,
00469                   0)) == -1)
00470                      return -1;
00471               t = ms->offset + sizeof(uint64_t);
00472               break;
00473 
00474        case FILE_FLOAT:
00475        case FILE_BEFLOAT:
00476        case FILE_LEFLOAT:
00477               vf = p->f;
00478               switch (check_fmt(ms, m)) {
00479               case -1:
00480                      return -1;
00481               case 1:
00482                      (void)snprintf(buf, sizeof(buf), "%g", vf);
00483                      if (file_printf(ms, m->desc, buf) == -1)
00484                             return -1;
00485                      break;
00486               default:
00487                      if (file_printf(ms, m->desc, vf) == -1)
00488                             return -1;
00489                      break;
00490               }
00491               t = ms->offset + sizeof(float);
00492               break;
00493 
00494        case FILE_DOUBLE:
00495        case FILE_BEDOUBLE:
00496        case FILE_LEDOUBLE:
00497               vd = p->d;
00498               switch (check_fmt(ms, m)) {
00499               case -1:
00500                      return -1;
00501               case 1:
00502                      (void)snprintf(buf, sizeof(buf), "%g", vd);
00503                      if (file_printf(ms, m->desc, buf) == -1)
00504                             return -1;
00505                      break;
00506               default:
00507                      if (file_printf(ms, m->desc, vd) == -1)
00508                             return -1;
00509                      break;
00510               }
00511               t = ms->offset + sizeof(double);
00512               break;
00513 
00514        case FILE_REGEX: {
00515               char *cp;
00516               int rval;
00517 
00518               cp = estrndup((const char *)ms->search.s, ms->search.rm_len);
00519 
00520               rval = file_printf(ms, m->desc, cp);
00521               efree(cp);
00522 
00523               if (rval == -1)
00524                      return -1;
00525 
00526               if ((m->str_flags & REGEX_OFFSET_START))
00527                      t = ms->search.offset;
00528               else
00529                      t = ms->search.offset + ms->search.rm_len;
00530               break;
00531        }
00532 
00533        case FILE_SEARCH:
00534               if (file_printf(ms, m->desc, m->value.s) == -1)
00535                      return -1;
00536               if ((m->str_flags & REGEX_OFFSET_START))
00537                      t = ms->search.offset;
00538               else
00539                      t = ms->search.offset + m->vallen;
00540               break;
00541 
00542        case FILE_DEFAULT:
00543               if (file_printf(ms, m->desc, m->value.s) == -1)
00544                      return -1;
00545               t = ms->offset;
00546               break;
00547 
00548        case FILE_INDIRECT:
00549               t = ms->offset;
00550               break;
00551 
00552        default:
00553               file_magerror(ms, "invalid m->type (%d) in mprint()", m->type);
00554               return -1;
00555        }
00556        return (int32_t)t;
00557 }
00558 
00559 private int32_t
00560 moffset(struct magic_set *ms, struct magic *m)
00561 {
00562        switch (m->type) {
00563        case FILE_BYTE:
00564               return ms->offset + sizeof(char);
00565 
00566        case FILE_SHORT:
00567        case FILE_BESHORT:
00568        case FILE_LESHORT:
00569               return ms->offset + sizeof(short);
00570 
00571        case FILE_LONG:
00572        case FILE_BELONG:
00573        case FILE_LELONG:
00574        case FILE_MELONG:
00575               return ms->offset + sizeof(int32_t);
00576 
00577        case FILE_QUAD:
00578        case FILE_BEQUAD:
00579        case FILE_LEQUAD:
00580               return ms->offset + sizeof(int64_t);
00581 
00582        case FILE_STRING:
00583        case FILE_PSTRING:
00584        case FILE_BESTRING16:
00585        case FILE_LESTRING16:
00586               if (m->reln == '=' || m->reln == '!')
00587                      return ms->offset + m->vallen;
00588               else {
00589                      union VALUETYPE *p = &ms->ms_value;
00590                      uint32_t t;
00591 
00592                      if (*m->value.s == '\0')
00593                             p->s[strcspn(p->s, "\n")] = '\0';
00594                      t = ms->offset + strlen(p->s);
00595                      if (m->type == FILE_PSTRING)
00596                             t++;
00597                      return t;
00598               }
00599 
00600        case FILE_DATE:
00601        case FILE_BEDATE:
00602        case FILE_LEDATE:
00603        case FILE_MEDATE:
00604               return ms->offset + sizeof(time_t);
00605 
00606        case FILE_LDATE:
00607        case FILE_BELDATE:
00608        case FILE_LELDATE:
00609        case FILE_MELDATE:
00610               return ms->offset + sizeof(time_t);
00611 
00612        case FILE_QDATE:
00613        case FILE_BEQDATE:
00614        case FILE_LEQDATE:
00615               return ms->offset + sizeof(uint64_t);
00616 
00617        case FILE_QLDATE:
00618        case FILE_BEQLDATE:
00619        case FILE_LEQLDATE:
00620               return ms->offset + sizeof(uint64_t);
00621 
00622        case FILE_FLOAT:
00623        case FILE_BEFLOAT:
00624        case FILE_LEFLOAT:
00625               return ms->offset + sizeof(float);
00626 
00627        case FILE_DOUBLE:
00628        case FILE_BEDOUBLE:
00629        case FILE_LEDOUBLE:
00630               return ms->offset + sizeof(double);
00631               break;
00632 
00633        case FILE_REGEX:
00634               if ((m->str_flags & REGEX_OFFSET_START) != 0)
00635                      return ms->search.offset;
00636               else
00637                      return ms->search.offset + ms->search.rm_len;
00638 
00639        case FILE_SEARCH:
00640               if ((m->str_flags & REGEX_OFFSET_START) != 0)
00641                      return ms->search.offset;
00642               else
00643                      return ms->search.offset + m->vallen;
00644 
00645        case FILE_DEFAULT:
00646               return ms->offset;
00647 
00648        case FILE_INDIRECT:
00649               return ms->offset;
00650 
00651        default:
00652               return 0;
00653        }
00654 }
00655 
00656 #define DO_CVT(fld, cast) \
00657        if (m->num_mask) \
00658               switch (m->mask_op & FILE_OPS_MASK) { \
00659               case FILE_OPAND: \
00660                      p->fld &= cast m->num_mask; \
00661                      break; \
00662               case FILE_OPOR: \
00663                      p->fld |= cast m->num_mask; \
00664                      break; \
00665               case FILE_OPXOR: \
00666                      p->fld ^= cast m->num_mask; \
00667                      break; \
00668               case FILE_OPADD: \
00669                      p->fld += cast m->num_mask; \
00670                      break; \
00671               case FILE_OPMINUS: \
00672                      p->fld -= cast m->num_mask; \
00673                      break; \
00674               case FILE_OPMULTIPLY: \
00675                      p->fld *= cast m->num_mask; \
00676                      break; \
00677               case FILE_OPDIVIDE: \
00678                      p->fld /= cast m->num_mask; \
00679                      break; \
00680               case FILE_OPMODULO: \
00681                      p->fld %= cast m->num_mask; \
00682                      break; \
00683               } \
00684        if (m->mask_op & FILE_OPINVERSE) \
00685               p->fld = ~p->fld \
00686 
00687 private void
00688 cvt_8(union VALUETYPE *p, const struct magic *m)
00689 {
00690        DO_CVT(b, (uint8_t));
00691 }
00692 
00693 private void
00694 cvt_16(union VALUETYPE *p, const struct magic *m)
00695 {
00696        DO_CVT(h, (uint16_t));
00697 }
00698 
00699 private void
00700 cvt_32(union VALUETYPE *p, const struct magic *m)
00701 {
00702        DO_CVT(l, (uint32_t));
00703 }
00704 
00705 private void
00706 cvt_64(union VALUETYPE *p, const struct magic *m)
00707 {
00708        DO_CVT(q, (uint64_t));
00709 }
00710 
00711 #define DO_CVT2(fld, cast) \
00712        if (m->num_mask) \
00713               switch (m->mask_op & FILE_OPS_MASK) { \
00714               case FILE_OPADD: \
00715                      p->fld += cast (int64_t)m->num_mask; \
00716                      break; \
00717               case FILE_OPMINUS: \
00718                      p->fld -= cast (int64_t)m->num_mask; \
00719                      break; \
00720               case FILE_OPMULTIPLY: \
00721                      p->fld *= cast (int64_t)m->num_mask; \
00722                      break; \
00723               case FILE_OPDIVIDE: \
00724                      p->fld /= cast (int64_t)m->num_mask; \
00725                      break; \
00726               } \
00727 
00728 private void
00729 cvt_float(union VALUETYPE *p, const struct magic *m)
00730 {
00731        DO_CVT2(f, (float));
00732 }
00733 
00734 private void
00735 cvt_double(union VALUETYPE *p, const struct magic *m)
00736 {
00737        DO_CVT2(d, (double));
00738 }
00739 
00740 /*
00741  * Convert the byte order of the data we are looking at
00742  * While we're here, let's apply the mask operation
00743  * (unless you have a better idea)
00744  */
00745 private int
00746 mconvert(struct magic_set *ms, struct magic *m)
00747 {
00748        union VALUETYPE *p = &ms->ms_value;
00749 
00750        switch (m->type) {
00751        case FILE_BYTE:
00752               cvt_8(p, m);
00753               return 1;
00754        case FILE_SHORT:
00755               cvt_16(p, m);
00756               return 1;
00757        case FILE_LONG:
00758        case FILE_DATE:
00759        case FILE_LDATE:
00760               cvt_32(p, m);
00761               return 1;
00762        case FILE_QUAD:
00763        case FILE_QDATE:
00764        case FILE_QLDATE:
00765               cvt_64(p, m);
00766               return 1;
00767        case FILE_STRING:
00768        case FILE_BESTRING16:
00769        case FILE_LESTRING16: {
00770               /* Null terminate and eat *trailing* return */
00771               p->s[sizeof(p->s) - 1] = '\0';
00772 #if 0
00773               /* Why? breaks magic numbers that end with \xa */
00774               len = strlen(p->s);
00775               if (len-- && p->s[len] == '\n')
00776                      p->s[len] = '\0';
00777 #endif
00778               return 1;
00779        }
00780        case FILE_PSTRING: {
00781               char *ptr1 = p->s, *ptr2 = ptr1 + 1;
00782               size_t len = *p->s;
00783               if (len >= sizeof(p->s))
00784                      len = sizeof(p->s) - 1;
00785               while (len--)
00786                      *ptr1++ = *ptr2++;
00787               *ptr1 = '\0';
00788 #if 0
00789               /* Why? breaks magic numbers that end with \xa */
00790               len = strlen(p->s);
00791               if (len-- && p->s[len] == '\n')
00792                      p->s[len] = '\0';
00793 #endif
00794               return 1;
00795        }
00796        case FILE_BESHORT:
00797               p->h = (short)((p->hs[0]<<8)|(p->hs[1]));
00798               cvt_16(p, m);
00799               return 1;
00800        case FILE_BELONG:
00801        case FILE_BEDATE:
00802        case FILE_BELDATE:
00803               p->l = (int32_t)
00804                   ((p->hl[0]<<24)|(p->hl[1]<<16)|(p->hl[2]<<8)|(p->hl[3]));
00805               cvt_32(p, m);
00806               return 1;
00807        case FILE_BEQUAD:
00808        case FILE_BEQDATE:
00809        case FILE_BEQLDATE:
00810               p->q = (uint64_t)
00811                   (((uint64_t)p->hq[0]<<56)|((uint64_t)p->hq[1]<<48)|
00812                    ((uint64_t)p->hq[2]<<40)|((uint64_t)p->hq[3]<<32)|
00813                    ((uint64_t)p->hq[4]<<24)|((uint64_t)p->hq[5]<<16)|
00814                    ((uint64_t)p->hq[6]<<8)|((uint64_t)p->hq[7]));
00815               cvt_64(p, m);
00816               return 1;
00817        case FILE_LESHORT:
00818               p->h = (short)((p->hs[1]<<8)|(p->hs[0]));
00819               cvt_16(p, m);
00820               return 1;
00821        case FILE_LELONG:
00822        case FILE_LEDATE:
00823        case FILE_LELDATE:
00824               p->l = (int32_t)
00825                   ((p->hl[3]<<24)|(p->hl[2]<<16)|(p->hl[1]<<8)|(p->hl[0]));
00826               cvt_32(p, m);
00827               return 1;
00828        case FILE_LEQUAD:
00829        case FILE_LEQDATE:
00830        case FILE_LEQLDATE:
00831               p->q = (uint64_t)
00832                   (((uint64_t)p->hq[7]<<56)|((uint64_t)p->hq[6]<<48)|
00833                    ((uint64_t)p->hq[5]<<40)|((uint64_t)p->hq[4]<<32)|
00834                    ((uint64_t)p->hq[3]<<24)|((uint64_t)p->hq[2]<<16)|
00835                    ((uint64_t)p->hq[1]<<8)|((uint64_t)p->hq[0]));
00836               cvt_64(p, m);
00837               return 1;
00838        case FILE_MELONG:
00839        case FILE_MEDATE:
00840        case FILE_MELDATE:
00841               p->l = (int32_t)
00842                   ((p->hl[1]<<24)|(p->hl[0]<<16)|(p->hl[3]<<8)|(p->hl[2]));
00843               cvt_32(p, m);
00844               return 1;
00845        case FILE_FLOAT:
00846               cvt_float(p, m);
00847               return 1;
00848        case FILE_BEFLOAT:
00849               p->l =  ((uint32_t)p->hl[0]<<24)|((uint32_t)p->hl[1]<<16)|
00850                      ((uint32_t)p->hl[2]<<8) |((uint32_t)p->hl[3]);
00851               cvt_float(p, m);
00852               return 1;
00853        case FILE_LEFLOAT:
00854               p->l =  ((uint32_t)p->hl[3]<<24)|((uint32_t)p->hl[2]<<16)|
00855                      ((uint32_t)p->hl[1]<<8) |((uint32_t)p->hl[0]);
00856               cvt_float(p, m);
00857               return 1;
00858        case FILE_DOUBLE:
00859               cvt_double(p, m);
00860               return 1;
00861        case FILE_BEDOUBLE:
00862               p->q =  ((uint64_t)p->hq[0]<<56)|((uint64_t)p->hq[1]<<48)|
00863                      ((uint64_t)p->hq[2]<<40)|((uint64_t)p->hq[3]<<32)|
00864                      ((uint64_t)p->hq[4]<<24)|((uint64_t)p->hq[5]<<16)|
00865                      ((uint64_t)p->hq[6]<<8) |((uint64_t)p->hq[7]);
00866               cvt_double(p, m);
00867               return 1;
00868        case FILE_LEDOUBLE:
00869               p->q =  ((uint64_t)p->hq[7]<<56)|((uint64_t)p->hq[6]<<48)|
00870                      ((uint64_t)p->hq[5]<<40)|((uint64_t)p->hq[4]<<32)|
00871                      ((uint64_t)p->hq[3]<<24)|((uint64_t)p->hq[2]<<16)|
00872                      ((uint64_t)p->hq[1]<<8) |((uint64_t)p->hq[0]);
00873               cvt_double(p, m);
00874               return 1;
00875        case FILE_REGEX:
00876        case FILE_SEARCH:
00877        case FILE_DEFAULT:
00878               return 1;
00879        default:
00880               file_magerror(ms, "invalid type %d in mconvert()", m->type);
00881               return 0;
00882        }
00883 }
00884 
00885 
00886 private void
00887 mdebug(uint32_t offset, const char *str, size_t len)
00888 {
00889        (void) fprintf(stderr, "mget @%d: ", offset);
00890        file_showstr(stderr, str, len);
00891        (void) fputc('\n', stderr);
00892        (void) fputc('\n', stderr);
00893 }
00894 
00895 private int
00896 mcopy(struct magic_set *ms, union VALUETYPE *p, int type, int indir,
00897     const unsigned char *s, uint32_t offset, size_t nbytes, size_t linecnt)
00898 {
00899        /*
00900         * Note: FILE_SEARCH and FILE_REGEX do not actually copy
00901         * anything, but setup pointers into the source
00902         */
00903        if (indir == 0) {
00904               switch (type) {
00905               case FILE_SEARCH:
00906                      ms->search.s = (const char *)s + offset;
00907                      ms->search.s_len = nbytes - offset;
00908                      ms->search.offset = offset;
00909                      return 0;
00910 
00911               case FILE_REGEX: {
00912                      const char *b;
00913                      const char *c;
00914                      const char *last;    /* end of search region */
00915                      const char *buf;     /* start of search region */
00916                      const char *end;
00917                      size_t lines;
00918 
00919                      if (s == NULL) {
00920                             ms->search.s_len = 0;
00921                             ms->search.s = NULL;
00922                             return 0;
00923                      }
00924                      buf = (const char *)s + offset;
00925                      end = last = (const char *)s + nbytes;
00926                      /* mget() guarantees buf <= last */
00927                      for (lines = linecnt, b = buf;
00928                           lines && ((b = memchr(c = b, '\n', end - b)) || (b = memchr(c, '\r', end - c)));
00929                           lines--, b++) {
00930                             last = b;
00931                             if (b[0] == '\r' && b[1] == '\n')
00932                                    b++;
00933                      }
00934                      if (lines)
00935                             last = (const char *)s + nbytes;
00936 
00937                      ms->search.s = buf;
00938                      ms->search.s_len = last - buf;
00939                      ms->search.offset = offset;
00940                      ms->search.rm_len = 0;
00941                      return 0;
00942               }
00943               case FILE_BESTRING16:
00944               case FILE_LESTRING16: {
00945                      const unsigned char *src = s + offset;
00946                      const unsigned char *esrc = s + nbytes;
00947                      char *dst = p->s;
00948                      char *edst = &p->s[sizeof(p->s) - 1];
00949 
00950                      if (type == FILE_BESTRING16)
00951                             src++;
00952 
00953                      /* check for pointer overflow */
00954                      if (src < s) {
00955                             file_magerror(ms, "invalid offset %u in mcopy()",
00956                                 offset);
00957                             return -1;
00958                      }
00959                      for (/*EMPTY*/; src < esrc; src += 2, dst++) {
00960                             if (dst < edst)
00961                                    *dst = *src;
00962                             else
00963                                    break;
00964                             if (*dst == '\0') {
00965                                    if (type == FILE_BESTRING16 ?
00966                                        *(src - 1) != '\0' :
00967                                        *(src + 1) != '\0')
00968                                           *dst = ' ';
00969                             }
00970                      }
00971                      *edst = '\0';
00972                      return 0;
00973               }
00974               case FILE_STRING:    /* XXX - these two should not need */
00975               case FILE_PSTRING:   /* to copy anything, but do anyway. */
00976               default:
00977                      break;
00978               }
00979        }
00980 
00981        if (offset >= nbytes) {
00982               (void)memset(p, '\0', sizeof(*p));
00983               return 0;
00984        }
00985        if (nbytes - offset < sizeof(*p))
00986               nbytes = nbytes - offset;
00987        else
00988               nbytes = sizeof(*p);
00989 
00990        (void)memcpy(p, s + offset, nbytes);
00991 
00992        /*
00993         * the usefulness of padding with zeroes eludes me, it
00994         * might even cause problems
00995         */
00996        if (nbytes < sizeof(*p))
00997               (void)memset(((char *)(void *)p) + nbytes, '\0',
00998                   sizeof(*p) - nbytes);
00999        return 0;
01000 }
01001 
01002 private int
01003 mget(struct magic_set *ms, const unsigned char *s,
01004     struct magic *m, size_t nbytes, unsigned int cont_level)
01005 {
01006        uint32_t offset = ms->offset;
01007        uint32_t count = m->str_range;
01008        union VALUETYPE *p = &ms->ms_value;
01009 
01010        if (mcopy(ms, p, m->type, m->flag & INDIR, s, offset, nbytes, count) == -1)
01011               return -1;
01012 
01013        if ((ms->flags & MAGIC_DEBUG) != 0) {
01014               mdebug(offset, (char *)(void *)p, sizeof(union VALUETYPE));
01015        }
01016 
01017        if (m->flag & INDIR) {
01018               int off = m->in_offset;
01019               if (m->in_op & FILE_OPINDIRECT) {
01020                      const union VALUETYPE *q =
01021                          ((const void *)(s + offset + off));
01022                      switch (m->in_type) {
01023                      case FILE_BYTE:
01024                             off = q->b;
01025                             break;
01026                      case FILE_SHORT:
01027                             off = q->h;
01028                             break;
01029                      case FILE_BESHORT:
01030                             off = (short)((q->hs[0]<<8)|(q->hs[1]));
01031                             break;
01032                      case FILE_LESHORT:
01033                             off = (short)((q->hs[1]<<8)|(q->hs[0]));
01034                             break;
01035                      case FILE_LONG:
01036                             off = q->l;
01037                             break;
01038                      case FILE_BELONG:
01039                      case FILE_BEID3:
01040                             off = (int32_t)((q->hl[0]<<24)|(q->hl[1]<<16)|
01041                                            (q->hl[2]<<8)|(q->hl[3]));
01042                             break;
01043                      case FILE_LEID3:
01044                      case FILE_LELONG:
01045                             off = (int32_t)((q->hl[3]<<24)|(q->hl[2]<<16)|
01046                                            (q->hl[1]<<8)|(q->hl[0]));
01047                             break;
01048                      case FILE_MELONG:
01049                             off = (int32_t)((q->hl[1]<<24)|(q->hl[0]<<16)|
01050                                            (q->hl[3]<<8)|(q->hl[2]));
01051                             break;
01052                      }
01053               }
01054               switch (m->in_type) {
01055               case FILE_BYTE:
01056                      if (nbytes < (offset + 1))
01057                             return 0;
01058                      if (off) {
01059                             switch (m->in_op & FILE_OPS_MASK) {
01060                             case FILE_OPAND:
01061                                    offset = p->b & off;
01062                                    break;
01063                             case FILE_OPOR:
01064                                    offset = p->b | off;
01065                                    break;
01066                             case FILE_OPXOR:
01067                                    offset = p->b ^ off;
01068                                    break;
01069                             case FILE_OPADD:
01070                                    offset = p->b + off;
01071                                    break;
01072                             case FILE_OPMINUS:
01073                                    offset = p->b - off;
01074                                    break;
01075                             case FILE_OPMULTIPLY:
01076                                    offset = p->b * off;
01077                                    break;
01078                             case FILE_OPDIVIDE:
01079                                    offset = p->b / off;
01080                                    break;
01081                             case FILE_OPMODULO:
01082                                    offset = p->b % off;
01083                                    break;
01084                             }
01085                      } else
01086                             offset = p->b;
01087                      if (m->in_op & FILE_OPINVERSE)
01088                             offset = ~offset;
01089                      break;
01090               case FILE_BESHORT:
01091                      if (nbytes < (offset + 2))
01092                             return 0;
01093                      if (off) {
01094                             switch (m->in_op & FILE_OPS_MASK) {
01095                             case FILE_OPAND:
01096                                    offset = (short)((p->hs[0]<<8)|
01097                                                   (p->hs[1])) &
01098                                            off;
01099                                    break;
01100                             case FILE_OPOR:
01101                                    offset = (short)((p->hs[0]<<8)|
01102                                                   (p->hs[1])) |
01103                                            off;
01104                                    break;
01105                             case FILE_OPXOR:
01106                                    offset = (short)((p->hs[0]<<8)|
01107                                                   (p->hs[1])) ^
01108                                            off;
01109                                    break;
01110                             case FILE_OPADD:
01111                                    offset = (short)((p->hs[0]<<8)|
01112                                                   (p->hs[1])) +
01113                                            off;
01114                                    break;
01115                             case FILE_OPMINUS:
01116                                    offset = (short)((p->hs[0]<<8)|
01117                                                   (p->hs[1])) -
01118                                            off;
01119                                    break;
01120                             case FILE_OPMULTIPLY:
01121                                    offset = (short)((p->hs[0]<<8)|
01122                                                   (p->hs[1])) *
01123                                            off;
01124                                    break;
01125                             case FILE_OPDIVIDE:
01126                                    offset = (short)((p->hs[0]<<8)|
01127                                                   (p->hs[1])) /
01128                                            off;
01129                                    break;
01130                             case FILE_OPMODULO:
01131                                    offset = (short)((p->hs[0]<<8)|
01132                                                   (p->hs[1])) %
01133                                            off;
01134                                    break;
01135                             }
01136                      } else
01137                             offset = (short)((p->hs[0]<<8)|
01138                                            (p->hs[1]));
01139                      if (m->in_op & FILE_OPINVERSE)
01140                             offset = ~offset;
01141                      break;
01142               case FILE_LESHORT:
01143                      if (nbytes < (offset + 2))
01144                             return 0;
01145                      if (off) {
01146                             switch (m->in_op & FILE_OPS_MASK) {
01147                             case FILE_OPAND:
01148                                    offset = (short)((p->hs[1]<<8)|
01149                                                   (p->hs[0])) &
01150                                            off;
01151                                    break;
01152                             case FILE_OPOR:
01153                                    offset = (short)((p->hs[1]<<8)|
01154                                                   (p->hs[0])) |
01155                                            off;
01156                                    break;
01157                             case FILE_OPXOR:
01158                                    offset = (short)((p->hs[1]<<8)|
01159                                                   (p->hs[0])) ^
01160                                            off;
01161                                    break;
01162                             case FILE_OPADD:
01163                                    offset = (short)((p->hs[1]<<8)|
01164                                                   (p->hs[0])) +
01165                                            off;
01166                                    break;
01167                             case FILE_OPMINUS:
01168                                    offset = (short)((p->hs[1]<<8)|
01169                                                   (p->hs[0])) -
01170                                            off;
01171                                    break;
01172                             case FILE_OPMULTIPLY:
01173                                    offset = (short)((p->hs[1]<<8)|
01174                                                   (p->hs[0])) *
01175                                            off;
01176                                    break;
01177                             case FILE_OPDIVIDE:
01178                                    offset = (short)((p->hs[1]<<8)|
01179                                                   (p->hs[0])) /
01180                                            off;
01181                                    break;
01182                             case FILE_OPMODULO:
01183                                    offset = (short)((p->hs[1]<<8)|
01184                                                   (p->hs[0])) %
01185                                            off;
01186                                    break;
01187                             }
01188                      } else
01189                             offset = (short)((p->hs[1]<<8)|
01190                                            (p->hs[0]));
01191                      if (m->in_op & FILE_OPINVERSE)
01192                             offset = ~offset;
01193                      break;
01194               case FILE_SHORT:
01195                      if (nbytes < (offset + 2))
01196                             return 0;
01197                      if (off) {
01198                             switch (m->in_op & FILE_OPS_MASK) {
01199                             case FILE_OPAND:
01200                                    offset = p->h & off;
01201                                    break;
01202                             case FILE_OPOR:
01203                                    offset = p->h | off;
01204                                    break;
01205                             case FILE_OPXOR:
01206                                    offset = p->h ^ off;
01207                                    break;
01208                             case FILE_OPADD:
01209                                    offset = p->h + off;
01210                                    break;
01211                             case FILE_OPMINUS:
01212                                    offset = p->h - off;
01213                                    break;
01214                             case FILE_OPMULTIPLY:
01215                                    offset = p->h * off;
01216                                    break;
01217                             case FILE_OPDIVIDE:
01218                                    offset = p->h / off;
01219                                    break;
01220                             case FILE_OPMODULO:
01221                                    offset = p->h % off;
01222                                    break;
01223                             }
01224                      }
01225                      else
01226                             offset = p->h;
01227                      if (m->in_op & FILE_OPINVERSE)
01228                             offset = ~offset;
01229                      break;
01230               case FILE_BELONG:
01231               case FILE_BEID3:
01232                      if (nbytes < (offset + 4))
01233                             return 0;
01234                      if (off) {
01235                             switch (m->in_op & FILE_OPS_MASK) {
01236                             case FILE_OPAND:
01237                                    offset = (int32_t)((p->hl[0]<<24)|
01238                                                   (p->hl[1]<<16)|
01239                                                   (p->hl[2]<<8)|
01240                                                   (p->hl[3])) &
01241                                            off;
01242                                    break;
01243                             case FILE_OPOR:
01244                                    offset = (int32_t)((p->hl[0]<<24)|
01245                                                   (p->hl[1]<<16)|
01246                                                   (p->hl[2]<<8)|
01247                                                   (p->hl[3])) |
01248                                            off;
01249                                    break;
01250                             case FILE_OPXOR:
01251                                    offset = (int32_t)((p->hl[0]<<24)|
01252                                                   (p->hl[1]<<16)|
01253                                                   (p->hl[2]<<8)|
01254                                                   (p->hl[3])) ^
01255                                            off;
01256                                    break;
01257                             case FILE_OPADD:
01258                                    offset = (int32_t)((p->hl[0]<<24)|
01259                                                   (p->hl[1]<<16)|
01260                                                   (p->hl[2]<<8)|
01261                                                   (p->hl[3])) +
01262                                            off;
01263                                    break;
01264                             case FILE_OPMINUS:
01265                                    offset = (int32_t)((p->hl[0]<<24)|
01266                                                   (p->hl[1]<<16)|
01267                                                   (p->hl[2]<<8)|
01268                                                   (p->hl[3])) -
01269                                            off;
01270                                    break;
01271                             case FILE_OPMULTIPLY:
01272                                    offset = (int32_t)((p->hl[0]<<24)|
01273                                                   (p->hl[1]<<16)|
01274                                                   (p->hl[2]<<8)|
01275                                                   (p->hl[3])) *
01276                                            off;
01277                                    break;
01278                             case FILE_OPDIVIDE:
01279                                    offset = (int32_t)((p->hl[0]<<24)|
01280                                                   (p->hl[1]<<16)|
01281                                                   (p->hl[2]<<8)|
01282                                                   (p->hl[3])) /
01283                                            off;
01284                                    break;
01285                             case FILE_OPMODULO:
01286                                    offset = (int32_t)((p->hl[0]<<24)|
01287                                                   (p->hl[1]<<16)|
01288                                                   (p->hl[2]<<8)|
01289                                                   (p->hl[3])) %
01290                                            off;
01291                                    break;
01292                             }
01293                      } else
01294                             offset = (int32_t)((p->hl[0]<<24)|
01295                                            (p->hl[1]<<16)|
01296                                            (p->hl[2]<<8)|
01297                                            (p->hl[3]));
01298                      if (m->in_op & FILE_OPINVERSE)
01299                             offset = ~offset;
01300                      break;
01301               case FILE_LELONG:
01302               case FILE_LEID3:
01303                      if (nbytes < (offset + 4))
01304                             return 0;
01305                      if (off) {
01306                             switch (m->in_op & FILE_OPS_MASK) {
01307                             case FILE_OPAND:
01308                                    offset = (int32_t)((p->hl[3]<<24)|
01309                                                   (p->hl[2]<<16)|
01310                                                   (p->hl[1]<<8)|
01311                                                   (p->hl[0])) &
01312                                            off;
01313                                    break;
01314                             case FILE_OPOR:
01315                                    offset = (int32_t)((p->hl[3]<<24)|
01316                                                   (p->hl[2]<<16)|
01317                                                   (p->hl[1]<<8)|
01318                                                   (p->hl[0])) |
01319                                            off;
01320                                    break;
01321                             case FILE_OPXOR:
01322                                    offset = (int32_t)((p->hl[3]<<24)|
01323                                                   (p->hl[2]<<16)|
01324                                                   (p->hl[1]<<8)|
01325                                                   (p->hl[0])) ^
01326                                            off;
01327                                    break;
01328                             case FILE_OPADD:
01329                                    offset = (int32_t)((p->hl[3]<<24)|
01330                                                   (p->hl[2]<<16)|
01331                                                   (p->hl[1]<<8)|
01332                                                   (p->hl[0])) +
01333                                            off;
01334                                    break;
01335                             case FILE_OPMINUS:
01336                                    offset = (int32_t)((p->hl[3]<<24)|
01337                                                   (p->hl[2]<<16)|
01338                                                   (p->hl[1]<<8)|
01339                                                   (p->hl[0])) -
01340                                            off;
01341                                    break;
01342                             case FILE_OPMULTIPLY:
01343                                    offset = (int32_t)((p->hl[3]<<24)|
01344                                                   (p->hl[2]<<16)|
01345                                                   (p->hl[1]<<8)|
01346                                                   (p->hl[0])) *
01347                                            off;
01348                                    break;
01349                             case FILE_OPDIVIDE:
01350                                    offset = (int32_t)((p->hl[3]<<24)|
01351                                                   (p->hl[2]<<16)|
01352                                                   (p->hl[1]<<8)|
01353                                                   (p->hl[0])) /
01354                                            off;
01355                                    break;
01356                             case FILE_OPMODULO:
01357                                    offset = (int32_t)((p->hl[3]<<24)|
01358                                                   (p->hl[2]<<16)|
01359                                                   (p->hl[1]<<8)|
01360                                                   (p->hl[0])) %
01361                                            off;
01362                                    break;
01363                             }
01364                      } else
01365                             offset = (int32_t)((p->hl[3]<<24)|
01366                                            (p->hl[2]<<16)|
01367                                            (p->hl[1]<<8)|
01368                                            (p->hl[0]));
01369                      if (m->in_op & FILE_OPINVERSE)
01370                             offset = ~offset;
01371                      break;
01372               case FILE_MELONG:
01373                      if (nbytes < (offset + 4))
01374                             return 0;
01375                      if (off) {
01376                             switch (m->in_op & FILE_OPS_MASK) {
01377                             case FILE_OPAND:
01378                                    offset = (int32_t)((p->hl[1]<<24)|
01379                                                   (p->hl[0]<<16)|
01380                                                   (p->hl[3]<<8)|
01381                                                   (p->hl[2])) &
01382                                            off;
01383                                    break;
01384                             case FILE_OPOR:
01385                                    offset = (int32_t)((p->hl[1]<<24)|
01386                                                   (p->hl[0]<<16)|
01387                                                   (p->hl[3]<<8)|
01388                                                   (p->hl[2])) |
01389                                            off;
01390                                    break;
01391                             case FILE_OPXOR:
01392                                    offset = (int32_t)((p->hl[1]<<24)|
01393                                                   (p->hl[0]<<16)|
01394                                                   (p->hl[3]<<8)|
01395                                                   (p->hl[2])) ^
01396                                            off;
01397                                    break;
01398                             case FILE_OPADD:
01399                                    offset = (int32_t)((p->hl[1]<<24)|
01400                                                   (p->hl[0]<<16)|
01401                                                   (p->hl[3]<<8)|
01402                                                   (p->hl[2])) +
01403                                            off;
01404                                    break;
01405                             case FILE_OPMINUS:
01406                                    offset = (int32_t)((p->hl[1]<<24)|
01407                                                   (p->hl[0]<<16)|
01408                                                   (p->hl[3]<<8)|
01409                                                   (p->hl[2])) -
01410                                            off;
01411                                    break;
01412                             case FILE_OPMULTIPLY:
01413                                    offset = (int32_t)((p->hl[1]<<24)|
01414                                                   (p->hl[0]<<16)|
01415                                                   (p->hl[3]<<8)|
01416                                                   (p->hl[2])) *
01417                                            off;
01418                                    break;
01419                             case FILE_OPDIVIDE:
01420                                    offset = (int32_t)((p->hl[1]<<24)|
01421                                                   (p->hl[0]<<16)|
01422                                                   (p->hl[3]<<8)|
01423                                                   (p->hl[2])) /
01424                                            off;
01425                                    break;
01426                             case FILE_OPMODULO:
01427                                    offset = (int32_t)((p->hl[1]<<24)|
01428                                                   (p->hl[0]<<16)|
01429                                                   (p->hl[3]<<8)|
01430                                                   (p->hl[2])) %
01431                                            off;
01432                                    break;
01433                             }
01434                      } else
01435                             offset = (int32_t)((p->hl[1]<<24)|
01436                                            (p->hl[0]<<16)|
01437                                            (p->hl[3]<<8)|
01438                                            (p->hl[2]));
01439                      if (m->in_op & FILE_OPINVERSE)
01440                             offset = ~offset;
01441                      break;
01442               case FILE_LONG:
01443                      if (nbytes < (offset + 4))
01444                             return 0;
01445                      if (off) {
01446                             switch (m->in_op & FILE_OPS_MASK) {
01447                             case FILE_OPAND:
01448                                    offset = p->l & off;
01449                                    break;
01450                             case FILE_OPOR:
01451                                    offset = p->l | off;
01452                                    break;
01453                             case FILE_OPXOR:
01454                                    offset = p->l ^ off;
01455                                    break;
01456                             case FILE_OPADD:
01457                                    offset = p->l + off;
01458                                    break;
01459                             case FILE_OPMINUS:
01460                                    offset = p->l - off;
01461                                    break;
01462                             case FILE_OPMULTIPLY:
01463                                    offset = p->l * off;
01464                                    break;
01465                             case FILE_OPDIVIDE:
01466                                    offset = p->l / off;
01467                                    break;
01468                             case FILE_OPMODULO:
01469                                    offset = p->l % off;
01470                                    break;
01471                             }
01472                      } else
01473                             offset = p->l;
01474                      if (m->in_op & FILE_OPINVERSE)
01475                             offset = ~offset;
01476                      break;
01477               }
01478 
01479               switch (m->in_type) {
01480               case FILE_LEID3:
01481               case FILE_BEID3:
01482                      offset = ((((offset >>  0) & 0x7f) <<  0) |
01483                              (((offset >>  8) & 0x7f) <<  7) |
01484                              (((offset >> 16) & 0x7f) << 14) |
01485                              (((offset >> 24) & 0x7f) << 21)) + 10;
01486                      break;
01487               default:
01488                      break;
01489               }
01490 
01491               if (m->flag & INDIROFFADD) {
01492                      offset += ms->c.li[cont_level-1].off;
01493               }
01494               if (mcopy(ms, p, m->type, 0, s, offset, nbytes, count) == -1)
01495                      return -1;
01496               ms->offset = offset;
01497 
01498               if ((ms->flags & MAGIC_DEBUG) != 0) {
01499                      mdebug(offset, (char *)(void *)p,
01500                          sizeof(union VALUETYPE));
01501               }
01502        }
01503 
01504        /* Verify we have enough data to match magic type */
01505        switch (m->type) {
01506        case FILE_BYTE:
01507               if (nbytes < (offset + 1)) /* should alway be true */
01508                      return 0;
01509               break;
01510 
01511        case FILE_SHORT:
01512        case FILE_BESHORT:
01513        case FILE_LESHORT:
01514               if (nbytes < (offset + 2))
01515                      return 0;
01516               break;
01517 
01518        case FILE_LONG:
01519        case FILE_BELONG:
01520        case FILE_LELONG:
01521        case FILE_MELONG:
01522        case FILE_DATE:
01523        case FILE_BEDATE:
01524        case FILE_LEDATE:
01525        case FILE_MEDATE:
01526        case FILE_LDATE:
01527        case FILE_BELDATE:
01528        case FILE_LELDATE:
01529        case FILE_MELDATE:
01530        case FILE_FLOAT:
01531        case FILE_BEFLOAT:
01532        case FILE_LEFLOAT:
01533               if (nbytes < (offset + 4))
01534                      return 0;
01535               break;
01536 
01537        case FILE_DOUBLE:
01538        case FILE_BEDOUBLE:
01539        case FILE_LEDOUBLE:
01540               if (nbytes < (offset + 8))
01541                      return 0;
01542               break;
01543 
01544        case FILE_STRING:
01545        case FILE_PSTRING:
01546        case FILE_SEARCH:
01547               if (nbytes < (offset + m->vallen))
01548                      return 0;
01549               break;
01550 
01551        case FILE_REGEX:
01552               if (nbytes < offset)
01553                      return 0;
01554               break;
01555 
01556        case FILE_INDIRECT:
01557               if ((ms->flags & (MAGIC_MIME|MAGIC_APPLE)) == 0 &&
01558                   file_printf(ms, m->desc) == -1)
01559                      return -1;
01560               if (nbytes < offset)
01561                      return 0;
01562               return file_softmagic(ms, s + offset, nbytes - offset,
01563                   BINTEST);
01564 
01565        case FILE_DEFAULT:   /* nothing to check */
01566        default:
01567               break;
01568        }
01569        if (!mconvert(ms, m))
01570               return 0;
01571        return 1;
01572 }
01573 
01574 private uint64_t
01575 file_strncmp(const char *s1, const char *s2, size_t len, uint32_t flags)
01576 {
01577        /*
01578         * Convert the source args to unsigned here so that (1) the
01579         * compare will be unsigned as it is in strncmp() and (2) so
01580         * the ctype functions will work correctly without extra
01581         * casting.
01582         */
01583        const unsigned char *a = (const unsigned char *)s1;
01584        const unsigned char *b = (const unsigned char *)s2;
01585        uint64_t v;
01586 
01587        /*
01588         * What we want here is v = strncmp(s1, s2, len),
01589         * but ignoring any nulls.
01590         */
01591        v = 0;
01592        if (0L == flags) { /* normal string: do it fast */
01593               while (len-- > 0)
01594                      if ((v = *b++ - *a++) != '\0')
01595                             break;
01596        }
01597        else { /* combine the others */
01598               while (len-- > 0) {
01599                      if ((flags & STRING_IGNORE_LOWERCASE) &&
01600                          islower(*a)) {
01601                             if ((v = tolower(*b++) - *a++) != '\0')
01602                                    break;
01603                      }
01604                      else if ((flags & STRING_IGNORE_UPPERCASE) &&
01605                          isupper(*a)) {
01606                             if ((v = toupper(*b++) - *a++) != '\0')
01607                                    break;
01608                      }
01609                      else if ((flags & STRING_COMPACT_BLANK) &&
01610                          isspace(*a)) {
01611                             a++;
01612                             if (isspace(*b++)) {
01613                                    while (isspace(*b))
01614                                           b++;
01615                             }
01616                             else {
01617                                    v = 1;
01618                                    break;
01619                             }
01620                      }
01621                      else if ((flags & STRING_COMPACT_OPTIONAL_BLANK) &&
01622                          isspace(*a)) {
01623                             a++;
01624                             while (isspace(*b))
01625                                    b++;
01626                      }
01627                      else {
01628                             if ((v = *b++ - *a++) != '\0')
01629                                    break;
01630                      }
01631               }
01632        }
01633        return v;
01634 }
01635 
01636 private uint64_t
01637 file_strncmp16(const char *a, const char *b, size_t len, uint32_t flags)
01638 {
01639        /*
01640         * XXX - The 16-bit string compare probably needs to be done
01641         * differently, especially if the flags are to be supported.
01642         * At the moment, I am unsure.
01643         */
01644        flags = 0;
01645        return file_strncmp(a, b, len, flags);
01646 }
01647 
01648 private void
01649 convert_libmagic_pattern(zval *pattern, int options)
01650 {
01651               int i, j=0;
01652               char *t;
01653 
01654               t = (char *) safe_emalloc(Z_STRLEN_P(pattern), 2, 5);
01655               
01656               t[j++] = '~';
01657               
01658               for (i=0; i<Z_STRLEN_P(pattern); i++, j++) {
01659                      switch (Z_STRVAL_P(pattern)[i]) {
01660                             case '?':
01661                                    t[j] = '.';
01662                                    break;
01663                             case '*':
01664                                    t[j++] = '.';
01665                                    t[j] = '*';
01666                                    break;
01667                             case '.':
01668                                    t[j++] = '\\';
01669                                    t[j] = '.';
01670                                    break;
01671                             case '\\':
01672                                    t[j++] = '\\';
01673                                    t[j] = '\\';
01674                                    break;
01675                             case '(':
01676                                    t[j++] = '\\';
01677                                    t[j] = '(';
01678                                    break;
01679                             case ')':
01680                                    t[j++] = '\\';
01681                                    t[j] = ')';
01682                                    break;
01683                             case '~':
01684                                    t[j++] = '\\';
01685                                    t[j] = '~';
01686                                    break;
01687                             default:
01688                                    t[j] = Z_STRVAL_P(pattern)[i];
01689                                    break;
01690                      }
01691               }
01692               t[j++] = '~';
01693        
01694               if (options & PCRE_CASELESS) 
01695                      t[j++] = 'm';
01696        
01697               if (options & PCRE_MULTILINE)
01698                      t[j++] = 'i';
01699 
01700               t[j]=0;
01701        
01702               Z_STRVAL_P(pattern) = t;
01703               Z_STRLEN_P(pattern) = j;
01704 
01705 }
01706 
01707 private int
01708 magiccheck(struct magic_set *ms, struct magic *m)
01709 {
01710        uint64_t l = m->value.q;
01711        uint64_t v;
01712        float fl, fv;
01713        double dl, dv;
01714        int matched;
01715        union VALUETYPE *p = &ms->ms_value;
01716 
01717        switch (m->type) {
01718        case FILE_BYTE:
01719               v = p->b;
01720               break;
01721 
01722        case FILE_SHORT:
01723        case FILE_BESHORT:
01724        case FILE_LESHORT:
01725               v = p->h;
01726               break;
01727 
01728        case FILE_LONG:
01729        case FILE_BELONG:
01730        case FILE_LELONG:
01731        case FILE_MELONG:
01732        case FILE_DATE:
01733        case FILE_BEDATE:
01734        case FILE_LEDATE:
01735        case FILE_MEDATE:
01736        case FILE_LDATE:
01737        case FILE_BELDATE:
01738        case FILE_LELDATE:
01739        case FILE_MELDATE:
01740               v = p->l;
01741               break;
01742 
01743        case FILE_QUAD:
01744        case FILE_LEQUAD:
01745        case FILE_BEQUAD:
01746        case FILE_QDATE:
01747        case FILE_BEQDATE:
01748        case FILE_LEQDATE:
01749        case FILE_QLDATE:
01750        case FILE_BEQLDATE:
01751        case FILE_LEQLDATE:
01752               v = p->q;
01753               break;
01754 
01755        case FILE_FLOAT:
01756        case FILE_BEFLOAT:
01757        case FILE_LEFLOAT:
01758               fl = m->value.f;
01759               fv = p->f;
01760               switch (m->reln) {
01761               case 'x':
01762                      matched = 1;
01763                      break;
01764 
01765               case '!':
01766                      matched = fv != fl;
01767                      break;
01768 
01769               case '=':
01770                      matched = fv == fl;
01771                      break;
01772 
01773               case '>':
01774                      matched = fv > fl;
01775                      break;
01776 
01777               case '<':
01778                      matched = fv < fl;
01779                      break;
01780 
01781               default:
01782                      matched = 0;
01783                      file_magerror(ms, "cannot happen with float: invalid relation `%c'",
01784                          m->reln);
01785                      return -1;
01786               }
01787               return matched;
01788 
01789        case FILE_DOUBLE:
01790        case FILE_BEDOUBLE:
01791        case FILE_LEDOUBLE:
01792               dl = m->value.d;
01793               dv = p->d;
01794               switch (m->reln) {
01795               case 'x':
01796                      matched = 1;
01797                      break;
01798 
01799               case '!':
01800                      matched = dv != dl;
01801                      break;
01802 
01803               case '=':
01804                      matched = dv == dl;
01805                      break;
01806 
01807               case '>':
01808                      matched = dv > dl;
01809                      break;
01810 
01811               case '<':
01812                      matched = dv < dl;
01813                      break;
01814 
01815               default:
01816                      matched = 0;
01817                      file_magerror(ms, "cannot happen with double: invalid relation `%c'", m->reln);
01818                      return -1;
01819               }
01820               return matched;
01821 
01822        case FILE_DEFAULT:
01823               l = 0;
01824               v = 0;
01825               break;
01826 
01827        case FILE_STRING:
01828        case FILE_PSTRING:
01829               l = 0;
01830               v = file_strncmp(m->value.s, p->s, (size_t)m->vallen, m->str_flags);
01831               break;
01832 
01833        case FILE_BESTRING16:
01834        case FILE_LESTRING16:
01835               l = 0;
01836               v = file_strncmp16(m->value.s, p->s, (size_t)m->vallen, m->str_flags);
01837               break;
01838 
01839        case FILE_SEARCH: { /* search ms->search.s for the string m->value.s */
01840               size_t slen;
01841               size_t idx;
01842 
01843               if (ms->search.s == NULL)
01844                      return 0;
01845 
01846               slen = MIN(m->vallen, sizeof(m->value.s));
01847               l = 0;
01848               v = 0;
01849 
01850               for (idx = 0; m->str_range == 0 || idx < m->str_range; idx++) {
01851                      if (slen + idx > ms->search.s_len)
01852                             break;
01853 
01854                      v = file_strncmp(m->value.s, ms->search.s + idx, slen, m->str_flags);
01855                      if (v == 0) { /* found match */
01856                             ms->search.offset += idx;
01857                             break;
01858                      }
01859               }
01860               break;
01861        }
01862        case FILE_REGEX: {
01863               zval *pattern;
01864               int options = 0;
01865               pcre_cache_entry *pce;
01866               TSRMLS_FETCH();
01867               
01868               MAKE_STD_ZVAL(pattern);
01869               ZVAL_STRINGL(pattern, (char *)m->value.s, m->vallen, 0);
01870        
01871               options |= PCRE_MULTILINE;
01872               
01873               if (m->str_flags & STRING_IGNORE_CASE) {
01874                      options |= PCRE_CASELESS;
01875               }
01876               
01877               convert_libmagic_pattern(pattern, options);
01878               
01879 #if (PHP_MAJOR_VERSION < 6)
01880               if ((pce = pcre_get_compiled_regex_cache(Z_STRVAL_P(pattern), Z_STRLEN_P(pattern) TSRMLS_CC)) == NULL) {
01881 #else
01882               if ((pce = pcre_get_compiled_regex_cache(IS_STRING, Z_STRVAL_P(pattern), Z_STRLEN_P(pattern) TSRMLS_CC)) == NULL) {
01883 #endif
01884                      zval_dtor(pattern);
01885                      FREE_ZVAL(pattern);
01886                      return -1;
01887               } else {
01888                      /* pce now contains the compiled regex */
01889                      zval *retval;
01890                      zval *subpats;
01891                      char *haystack;
01892                      
01893                      MAKE_STD_ZVAL(retval);
01894                      ALLOC_INIT_ZVAL(subpats);
01895                      
01896                      /* Cut the search len from haystack, equals to REG_STARTEND */
01897                      haystack = estrndup(ms->search.s, ms->search.s_len);
01898 
01899                      /* match v = 0, no match v = 1 */
01900 #if (PHP_MAJOR_VERSION < 6)
01901                      php_pcre_match_impl(pce, haystack, ms->search.s_len, retval, subpats, 1, 1, PREG_OFFSET_CAPTURE, 0 TSRMLS_CC);
01902 #else                
01903                      php_pcre_match_impl(pce, IS_STRING, haystack, ms->search.s_len, retval, subpats, 1, 1, PREG_OFFSET_CAPTURE, 0 TSRMLS_CC);
01904 #endif
01905                      /* Free haystack */
01906                      efree(haystack);
01907                      
01908                      if (Z_LVAL_P(retval) < 0) {
01909                             zval_ptr_dtor(&subpats);
01910                             FREE_ZVAL(retval);
01911                             zval_dtor(pattern);
01912                             FREE_ZVAL(pattern);
01913                             return -1;
01914                      } else if ((Z_LVAL_P(retval) > 0) && (Z_TYPE_P(subpats) == IS_ARRAY)) {
01915                             
01916                             /* Need to fetch global match which equals pmatch[0] */
01917                             HashTable *ht = Z_ARRVAL_P(subpats);
01918                             HashPosition outer_pos;
01919                             zval *pattern_match = NULL, *pattern_offset = NULL;
01920                             
01921                             zend_hash_internal_pointer_reset_ex(ht, &outer_pos); 
01922                             
01923                             if (zend_hash_has_more_elements_ex(ht, &outer_pos) == SUCCESS &&
01924                                    zend_hash_move_forward_ex(ht, &outer_pos)) {
01925                                    
01926                                    zval **ppzval;
01927                                    
01928                                    /* The first element (should be) is the global match 
01929                                       Need to move to the inner array to get the global match */
01930                                    
01931                                    if (zend_hash_get_current_data_ex(ht, (void**)&ppzval, &outer_pos) != FAILURE) { 
01932                                           
01933                                           HashTable *inner_ht;
01934                                           HashPosition inner_pos;
01935                                           zval **match, **offset;
01936                                           zval tmpcopy = **ppzval, matchcopy, offsetcopy;
01937                                           
01938                                           zval_copy_ctor(&tmpcopy); 
01939                                           INIT_PZVAL(&tmpcopy);
01940                                           
01941                                           inner_ht = Z_ARRVAL(tmpcopy);
01942                                           
01943                                           /* If everything goes according to the master plan
01944                                              tmpcopy now contains two elements:
01945                                              0 = the match
01946                                              1 = starting position of the match */
01947                                           zend_hash_internal_pointer_reset_ex(inner_ht, &inner_pos); 
01948                                           
01949                                           if (zend_hash_has_more_elements_ex(inner_ht, &inner_pos) == SUCCESS &&
01950                                                  zend_hash_move_forward_ex(inner_ht, &inner_pos)) {
01951                                           
01952                                                  if (zend_hash_get_current_data_ex(inner_ht, (void**)&match, &inner_pos) != FAILURE) { 
01953                                                                
01954                                                         matchcopy = **match;
01955                                                         zval_copy_ctor(&matchcopy);
01956                                                         INIT_PZVAL(&matchcopy);
01957                                                         convert_to_string(&matchcopy); 
01958                                                         
01959                                                         MAKE_STD_ZVAL(pattern_match);
01960                                                         Z_STRVAL_P(pattern_match) = (char *)Z_STRVAL(matchcopy);
01961                                                         Z_STRLEN_P(pattern_match) = Z_STRLEN(matchcopy);
01962                                                         Z_TYPE_P(pattern_match) = IS_STRING; 
01963 
01964                                                         zval_dtor(&matchcopy);
01965                                                  }
01966                                           }
01967                                           
01968                                           if (zend_hash_has_more_elements_ex(inner_ht, &inner_pos) == SUCCESS &&
01969                                                  zend_hash_move_forward_ex(inner_ht, &inner_pos)) {
01970                                                  
01971                                                  if (zend_hash_get_current_data_ex(inner_ht, (void**)&offset, &inner_pos) != FAILURE) { 
01972                                                         
01973                                                         offsetcopy = **offset;
01974                                                         zval_copy_ctor(&offsetcopy);
01975                                                         INIT_PZVAL(&offsetcopy);
01976                                                         convert_to_long(&offsetcopy); 
01977                                                         
01978                                                         MAKE_STD_ZVAL(pattern_offset);
01979                                                         Z_LVAL_P(pattern_offset) = Z_LVAL(offsetcopy);
01980                                                         Z_TYPE_P(pattern_offset) = IS_LONG;
01981                                                         
01982                                                         zval_dtor(&offsetcopy);
01983                                                  }
01984                                           }
01985                                           zval_dtor(&tmpcopy);        
01986                                    }
01987                                    
01988                                    if ((pattern_match != NULL) && (pattern_offset != NULL)) {
01989                                           ms->search.s += (int)Z_LVAL_P(pattern_offset); /* this is where the match starts */
01990                                           ms->search.offset += (size_t)Z_LVAL_P(pattern_offset); /* this is where the match starts as size_t */
01991                                           ms->search.rm_len = Z_STRLEN_P(pattern_match) /* This is the length of the matched pattern */;
01992                                           v = 0;
01993                                           
01994                                           efree(pattern_match);
01995                                           efree(pattern_offset);
01996                                           
01997                                    } else {
01998                                           zval_ptr_dtor(&subpats);
01999                                           FREE_ZVAL(retval);
02000                                           zval_dtor(pattern);
02001                                           FREE_ZVAL(pattern);
02002                                           return -1;
02003                                    }                                  
02004                             }
02005 
02006                             
02007                      } else {
02008                             v = 1;
02009                      }
02010                      zval_ptr_dtor(&subpats);
02011                      FREE_ZVAL(retval);
02012               }
02013               zval_dtor(pattern);
02014               FREE_ZVAL(pattern);
02015               break; 
02016        }
02017        case FILE_INDIRECT:
02018               return 1;      
02019        default:
02020               file_magerror(ms, "invalid type %d in magiccheck()", m->type);
02021               return -1;
02022        }
02023 
02024        v = file_signextend(ms, m, v);
02025 
02026        switch (m->reln) {
02027        case 'x':
02028               if ((ms->flags & MAGIC_DEBUG) != 0)
02029                      (void) fprintf(stderr, "%llu == *any* = 1\n",
02030                          (uint64_t)v);
02031               matched = 1;
02032               break;
02033 
02034        case '!':
02035               matched = v != l;
02036               if ((ms->flags & MAGIC_DEBUG) != 0)
02037                      (void) fprintf(stderr, "%llu != %llu = %d\n",
02038                          (uint64_t)v, (uint64_t)l,
02039                          matched);
02040               break;
02041 
02042        case '=':
02043               matched = v == l;
02044               if ((ms->flags & MAGIC_DEBUG) != 0)
02045                      (void) fprintf(stderr, "%llu == %llu = %d\n",
02046                          (uint64_t)v, (uint64_t)l,
02047                          matched);
02048               break;
02049 
02050        case '>':
02051               if (m->flag & UNSIGNED) {
02052                      matched = v > l;
02053                      if ((ms->flags & MAGIC_DEBUG) != 0)
02054                             (void) fprintf(stderr, "%llu > %llu = %d\n",
02055                                 (uint64_t)v,
02056                                 (uint64_t)l, matched);
02057               }
02058               else {
02059                      matched = (int64_t) v > (int64_t) l;
02060                      if ((ms->flags & MAGIC_DEBUG) != 0)
02061                             (void) fprintf(stderr, "%lld > %lld = %d\n",
02062                                 (uint64_t)v, (uint64_t)l, matched);
02063               }
02064               break;
02065 
02066        case '<':
02067               if (m->flag & UNSIGNED) {
02068                      matched = v < l;
02069                      if ((ms->flags & MAGIC_DEBUG) != 0)
02070                             (void) fprintf(stderr, "%llu < %llu = %d\n",
02071                                 (uint64_t)v,
02072                                 (uint64_t)l, matched);
02073               }
02074               else {
02075                      matched = (int64_t) v < (int64_t) l;
02076                      if ((ms->flags & MAGIC_DEBUG) != 0)
02077                             (void) fprintf(stderr, "%lld < %lld = %d\n",
02078                                    (int64_t)v, (int64_t)l, matched);
02079               }
02080               break;
02081 
02082        case '&':
02083               matched = (v & l) == l;
02084               if ((ms->flags & MAGIC_DEBUG) != 0)
02085                      (void) fprintf(stderr, "((%llx & %llx) == %llx) = %d\n",
02086                          (uint64_t)v, (uint64_t)l,
02087                          (uint64_t)l, matched);
02088               break;
02089 
02090        case '^':
02091               matched = (v & l) != l;
02092               if ((ms->flags & MAGIC_DEBUG) != 0)
02093                      (void) fprintf(stderr, "((%llx & %llx) != %llx) = %d\n",
02094                          (uint64_t)v, (uint64_t)l,
02095                          (uint64_t)l, matched);
02096               break;
02097 
02098        default:
02099               matched = 0;
02100               file_magerror(ms, "cannot happen: invalid relation `%c'",
02101                   m->reln);
02102               return -1;
02103        }
02104 
02105        return matched;
02106 }
02107 
02108 private int
02109 handle_annotation(struct magic_set *ms, struct magic *m)
02110 {
02111        if (ms->flags & MAGIC_APPLE) {
02112               if (file_printf(ms, "%.8s", m->apple) == -1)
02113                      return -1;
02114               return 1;
02115        }
02116        if ((ms->flags & MAGIC_MIME_TYPE) && m->mimetype[0]) {
02117               if (file_printf(ms, "%s", m->mimetype) == -1)
02118                      return -1;
02119               return 1;
02120        }
02121        return 0;
02122 }
02123 
02124 private int
02125 print_sep(struct magic_set *ms, int firstline)
02126 {
02127        if (ms->flags & MAGIC_MIME)
02128               return 0;
02129        if (firstline)
02130               return 0;
02131        /*
02132         * we found another match
02133         * put a newline and '-' to do some simple formatting
02134         */
02135        return file_printf(ms, "\n- ");
02136 }