file/src/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 #include "magic.h"
00034 #include <string.h>
00035 #include <ctype.h>
00036 #include <stdlib.h>
00037 #include <time.h>
00038 
00039 
00040 #ifndef lint
00041 FILE_RCSID("@(#)$File: softmagic.c,v 1.95 2007/03/03 19:09:25 christos Exp $")
00042 #endif  /* lint */
00043 
00044 private int match(struct magic_set *ms, struct magic *magic, uint32_t nmagic,
00045     const unsigned char *s, size_t nbytes)
00046         /*@globals fileSystem @*/
00047         /*@modifies ms, magic, fileSystem @*/;
00048 private int mget(struct magic_set *ms, const unsigned char *s,
00049     struct magic *m, size_t nbytes, unsigned int cont_level)
00050         /*@globals fileSystem @*/
00051         /*@modifies ms, m, fileSystem @*/;
00052 private int magiccheck(struct magic_set *ms, struct magic *m)
00053         /*@globals fileSystem @*/
00054         /*@modifies ms, fileSystem @*/;
00055 private int32_t mprint(struct magic_set *ms, struct magic *m)
00056         /*@globals fileSystem @*/
00057         /*@modifies ms, fileSystem @*/;
00058 private void mdebug(uint32_t offset, const char *str, size_t len)
00059         /*@globals fileSystem @*/
00060         /*@modifies ms, fileSystem @*/;
00061 private int mcopy(struct magic_set *ms, union VALUETYPE *p, int type, int indir,
00062     const unsigned char *s, uint32_t offset, size_t nbytes, size_t linecnt)
00063         /*@modifies ms, p @*/;
00064 private int mconvert(struct magic_set *ms, struct magic *m)
00065         /*@modifies ms @*/;
00066 private int print_sep(struct magic_set *ms, int firstline)
00067         /*@modifies ms @*/;
00068 private void cvt_8(union VALUETYPE *p, const struct magic *m)
00069         /*@modifies p @*/;
00070 private void cvt_16(union VALUETYPE *p, const struct magic *m)
00071         /*@modifies p @*/;
00072 private void cvt_32(union VALUETYPE *p, const struct magic *m)
00073         /*@modifies p @*/;
00074 private void cvt_64(union VALUETYPE *p, const struct magic *m)
00075         /*@modifies p @*/;
00076 
00077 /*
00078  * softmagic - lookup one file in parsed, in-memory copy of database
00079  * Passed the name and FILE * of one file to be typed.
00080  */
00081 /*ARGSUSED1*/           /* nbytes passed for regularity, maybe need later */
00082 protected int
00083 file_softmagic(struct magic_set *ms, const unsigned char *buf, size_t nbytes)
00084 {
00085         struct mlist *ml;
00086         int rv;
00087         for (ml = ms->mlist->next; ml != ms->mlist; ml = ml->next)
00088                 if ((rv = match(ms, ml->magic, ml->nmagic, buf, nbytes)) != 0)
00089                         return rv;
00090 
00091         return 0;
00092 }
00093 
00094 #ifdef ENABLE_CONDITIONALS
00095 protected int
00096 #else
00097 private int
00098 #endif
00099 file_check_mem(struct magic_set *ms, unsigned int level)
00100 {
00101         size_t len;
00102 
00103         if (level >= ms->c.len) {
00104                 len = (ms->c.len += 20) * sizeof(*ms->c.li);
00105                 ms->c.li = (ms->c.li == NULL) ? malloc(len) :
00106                     realloc(ms->c.li, len);
00107                 if (ms->c.li == NULL) {
00108                         file_oomem(ms, len);
00109                         return -1;
00110                 }
00111         }
00112         ms->c.li[level].got_match = 0;
00113 #ifdef ENABLE_CONDITIONALS
00114         ms->c.li[level].last_match = 0;
00115         ms->c.li[level].last_cond = COND_NONE;
00116 #endif /* ENABLE_CONDITIONALS */
00117         return 0;
00118 }
00119 
00120 /*
00121  * Go through the whole list, stopping if you find a match.  Process all
00122  * the continuations of that match before returning.
00123  *
00124  * We support multi-level continuations:
00125  *
00126  *      At any time when processing a successful top-level match, there is a
00127  *      current continuation level; it represents the level of the last
00128  *      successfully matched continuation.
00129  *
00130  *      Continuations above that level are skipped as, if we see one, it
00131  *      means that the continuation that controls them - i.e, the
00132  *      lower-level continuation preceding them - failed to match.
00133  *
00134  *      Continuations below that level are processed as, if we see one,
00135  *      it means we've finished processing or skipping higher-level
00136  *      continuations under the control of a successful or unsuccessful
00137  *      lower-level continuation, and are now seeing the next lower-level
00138  *      continuation and should process it.  The current continuation
00139  *      level reverts to the level of the one we're seeing.
00140  *
00141  *      Continuations at the current level are processed as, if we see
00142  *      one, there's no lower-level continuation that may have failed.
00143  *
00144  *      If a continuation matches, we bump the current continuation level
00145  *      so that higher-level continuations are processed.
00146  */
00147 private int
00148 match(struct magic_set *ms, struct magic *magic, uint32_t nmagic,
00149     const unsigned char *s, size_t nbytes)
00150 {
00151         uint32_t magindex = 0;
00152         unsigned int cont_level = 0;
00153         int need_separator = 0;
00154         int returnval = 0; /* if a match is found it is set to 1*/
00155         int firstline = 1; /* a flag to print X\n  X\n- X */
00156         int printed_something = 0;
00157 
00158         if (file_check_mem(ms, cont_level) == -1)
00159                 return -1;
00160 
00161         for (magindex = 0; magindex < nmagic; magindex++) {
00162                 int flush;
00163 
00164                 ms->offset = magic[magindex].offset;
00165                 ms->line = magic[magindex].lineno;
00166 
00167                 /* if main entry matches, print it... */
00168                 flush = !mget(ms, s, &magic[magindex], nbytes, cont_level);
00169                 if (flush) {
00170                         if (magic[magindex].reln == '!')
00171                                 flush = 0;
00172                 } else {        
00173                         switch (magiccheck(ms, &magic[magindex])) {
00174                         case -1:
00175                                 return -1;
00176                         case 0:
00177                                 flush++;
00178                                 /*@switchbreak@*/ break;
00179                         default:
00180                                 /*@switchbreak@*/ break;
00181                         }
00182                 }
00183                 if (flush) {
00184                         /* 
00185                          * main entry didn't match,
00186                          * flush its continuations
00187                          */
00188                         while (magindex < nmagic - 1 &&
00189                                magic[magindex + 1].cont_level != 0)
00190                                magindex++;
00191                         continue;
00192                 }
00193 
00194                 /*
00195                  * If we are going to print something, we'll need to print
00196                  * a blank before we print something else.
00197                  */
00198                 if (magic[magindex].desc[0]) {
00199                         need_separator = 1;
00200                         printed_something = 1;
00201                         if (print_sep(ms, firstline) == -1)
00202                                 return -1;
00203                 }
00204 
00205                 if ((ms->c.li[cont_level].off = mprint(ms, &magic[magindex]))
00206                     == -1)
00207                         return -1;
00208 
00209                 /* and any continuations that match */
00210                 if (file_check_mem(ms, ++cont_level) == -1)
00211                         return -1;
00212 
00213                 while (magic[magindex+1].cont_level != 0 && 
00214                        ++magindex < nmagic) {
00215                         ms->line = magic[magindex].lineno; /* for messages */
00216 
00217                         if (cont_level < magic[magindex].cont_level)
00218                                 /*@innercontinue@*/ continue;
00219                         if (cont_level > magic[magindex].cont_level) {
00220                                 /*
00221                                  * We're at the end of the level
00222                                  * "cont_level" continuations.
00223                                  */
00224                                 cont_level = magic[magindex].cont_level;
00225                         }
00226                         ms->offset = magic[magindex].offset;
00227                         if (magic[magindex].flag & OFFADD) {
00228                                 ms->offset +=
00229                                     ms->c.li[cont_level - 1].off;
00230                         }
00231 
00232 #ifdef ENABLE_CONDITIONALS
00233                         if (magic[magindex].cond == COND_ELSE ||
00234                             magic[magindex].cond == COND_ELIF) {
00235                                 if (ms->c.li[cont_level].last_match == 1)
00236                                         /*@innercontinue@*/ continue;
00237                         }
00238 #endif
00239                         flush = !mget(ms, s, &magic[magindex], nbytes,
00240                             cont_level);
00241                         if (flush && magic[magindex].reln != '!')
00242                                 /*@innercontinue@*/ continue;
00243                                 
00244                         switch (flush ? 1 : magiccheck(ms, &magic[magindex])) {
00245                         case -1:
00246                                 return -1;
00247                         case 0:
00248 #ifdef ENABLE_CONDITIONALS
00249                                 ms->c.li[cont_level].last_match = 0;
00250 #endif
00251                                 /*@switchbreak@*/ break;
00252                         default:
00253 #ifdef ENABLE_CONDITIONALS
00254                                 ms->c.li[cont_level].last_match = 1;
00255 #endif
00256                                 if (magic[magindex].type != FILE_DEFAULT)
00257                                         ms->c.li[cont_level].got_match = 1;
00258                                 else if (ms->c.li[cont_level].got_match) {
00259                                         ms->c.li[cont_level].got_match = 0;
00260                                         /*@switchbreak@*/ break;
00261                                 }
00262                                 /*
00263                                  * If we are going to print something,
00264                                  * make sure that we have a separator first.
00265                                  */
00266                                 if (magic[magindex].desc[0]) {
00267                                         printed_something = 1;
00268                                         if (print_sep(ms, firstline) == -1)
00269                                                 return -1;
00270                                 }
00271                                 /*
00272                                  * This continuation matched.  Print
00273                                  * its message, with a blank before it
00274                                  * if the previous item printed and
00275                                  * this item isn't empty.
00276                                  */
00277                                 /* space if previous printed */
00278                                 if (need_separator
00279                                     && (magic[magindex].nospflag == 0)
00280                                    && (magic[magindex].desc[0] != '\0')) {
00281                                         if (file_printf(ms, " ") == -1)
00282                                                 return -1;
00283                                         need_separator = 0;
00284                                 }
00285                                 if ((ms->c.li[cont_level].off = mprint(ms, &magic[magindex])) == -1)
00286                                         return -1;
00287                                 if (magic[magindex].desc[0])
00288                                         need_separator = 1;
00289 
00290                                 /*
00291                                  * If we see any continuations
00292                                  * at a higher level,
00293                                  * process them.
00294                                  */
00295                                 if (file_check_mem(ms, ++cont_level) == -1)
00296                                         return -1;
00297                                 /*@switchbreak@*/ break;
00298                         }
00299                 }
00300                 firstline = 0;
00301                 if (printed_something)
00302                 returnval = 1;
00303                 if ((ms->flags & MAGIC_CONTINUE) == 0 && printed_something) {
00304                         return 1; /* don't keep searching */
00305                 }                       
00306         }
00307         return returnval;  /* This is hit if -k is set or there is no match */
00308 }
00309 
00310 private int
00311 check_fmt(struct magic_set *ms, struct magic *m)
00312         /*@modifies ms @*/
00313 {
00314         regex_t rx;
00315         int rc;
00316 
00317         if (strchr(m->desc, '%') == NULL)
00318                 return 0;
00319 
00320         rc = regcomp(&rx, "%[-0-9\\.]*s", REG_EXTENDED|REG_NOSUB);
00321         if (rc) {
00322                 char errmsg[512];
00323                 (void)regerror(rc, &rx, errmsg, sizeof(errmsg));
00324                 file_magerror(ms, "regex error %d, (%s)", rc, errmsg);
00325         return -1;
00326         } else {
00327                 rc = regexec(&rx, m->desc, 0, 0, 0);
00328 /*@i@*/         regfree(&rx);
00329                 return !rc;
00330         }
00331 }
00332 
00333 #ifndef HAVE_STRNDUP
00334 char * strndup(const char *, size_t);
00335 
00336 char *
00337 strndup(const char *str, size_t n)
00338 {
00339         size_t len;
00340         char *copy;
00341 
00342         len = strlen(str);
00343         if (len > n)
00344                 len = n;
00345         if (!(copy = malloc(len + 1)))
00346                 return (NULL);
00347         (void) memcpy(copy, str, len + 1);
00348         copy[len] = '\0';
00349         return (copy);
00350 }
00351 #endif /* HAVE_STRNDUP */
00352 
00353 private int32_t
00354 mprint(struct magic_set *ms, struct magic *m)
00355 {
00356         uint64_t v;
00357         int32_t t=0 ;
00358         char buf[512];
00359         union VALUETYPE *p = &ms->ms_value;
00360 
00361         switch (m->type) {
00362         case FILE_BYTE:
00363                 v = file_signextend(ms, m, (uint64_t)p->b);
00364                 switch (check_fmt(ms, m)) {
00365                 case -1:
00366                         return -1;
00367                 case 1:
00368                         if (snprintf(buf, sizeof(buf), "%c",
00369                             (unsigned char)v) < 0)
00370                                 return -1;
00371                         if (file_printf(ms, m->desc, buf) == -1)
00372                                 return -1;
00373                         /*@innerbreak@*/ break;
00374                 default:
00375                 if (file_printf(ms, m->desc, (unsigned char) v) == -1)
00376                         return -1;
00377                         /*@innerbreak@*/ break;
00378                 }
00379                 t = ms->offset + sizeof(char);
00380                 break;
00381 
00382         case FILE_SHORT:
00383         case FILE_BESHORT:
00384         case FILE_LESHORT:
00385                 v = file_signextend(ms, m, (uint64_t)p->h);
00386                 switch (check_fmt(ms, m)) {
00387                 case -1:
00388                         return -1;
00389                 case 1:
00390                         if (snprintf(buf, sizeof(buf), "%hu",
00391                             (unsigned short)v) < 0)
00392                                 return -1;
00393                         if (file_printf(ms, m->desc, buf) == -1)
00394                                 return -1;
00395                         /*@innerbreak@*/ break;
00396                 default:
00397                 if (file_printf(ms, m->desc, (unsigned short) v) == -1)
00398                         return -1;
00399                         /*@innerbreak@*/ break;
00400                 }
00401                 t = ms->offset + sizeof(short);
00402                 break;
00403 
00404         case FILE_LONG:
00405         case FILE_BELONG:
00406         case FILE_LELONG:
00407         case FILE_MELONG:
00408                 v = file_signextend(ms, m, (uint64_t)p->l);
00409                 switch (check_fmt(ms, m)) {
00410                 case -1:
00411                         return -1;
00412                 case 1:
00413                         if (snprintf(buf, sizeof(buf), "%u", (uint32_t)v) < 0)
00414                                 return -1;
00415                         if (file_printf(ms, m->desc, buf) == -1)
00416                                 return -1;
00417                         /*@innerbreak@*/ break;
00418                 default:
00419                 if (file_printf(ms, m->desc, (uint32_t) v) == -1)
00420                         return -1;
00421                         /*@innerbreak@*/ break;
00422                 }
00423                 t = ms->offset + sizeof(int32_t);
00424                 break;
00425 
00426         case FILE_QUAD:
00427         case FILE_BEQUAD:
00428         case FILE_LEQUAD:
00429                 v = file_signextend(ms, m, p->q);
00430                 if (file_printf(ms, m->desc, (uint64_t) v) == -1)
00431                         return -1;
00432                 t = ms->offset + sizeof(int64_t);
00433                 break;
00434 
00435         case FILE_STRING:
00436         case FILE_PSTRING:
00437         case FILE_BESTRING16:
00438         case FILE_LESTRING16:
00439                 if (m->reln == '=' || m->reln == '!') {
00440                         if (file_printf(ms, m->desc, m->value.s) == -1)
00441                                 return -1;
00442                         t = ms->offset + m->vallen;
00443                 }
00444                 else {
00445                         if (*m->value.s == '\0') {
00446                                 char *cp = strchr(p->s,'\n');
00447                                 if (cp)
00448                                         *cp = '\0';
00449                         }
00450                         if (file_printf(ms, m->desc, p->s) == -1)
00451                                 return -1;
00452                         t = ms->offset + strlen(p->s);
00453                 }
00454                 break;
00455 
00456         case FILE_DATE:
00457         case FILE_BEDATE:
00458         case FILE_LEDATE:
00459         case FILE_MEDATE:
00460                 if (file_printf(ms, m->desc, file_fmttime(p->l, 1)) == -1)
00461                         return -1;
00462                 t = ms->offset + sizeof(time_t);
00463                 break;
00464 
00465         case FILE_LDATE:
00466         case FILE_BELDATE:
00467         case FILE_LELDATE:
00468         case FILE_MELDATE:
00469                 if (file_printf(ms, m->desc, file_fmttime(p->l, 0)) == -1)
00470                         return -1;
00471                 t = ms->offset + sizeof(time_t);
00472                 break;
00473 
00474         case FILE_QDATE:
00475         case FILE_BEQDATE:
00476         case FILE_LEQDATE:
00477                 if (file_printf(ms, m->desc, file_fmttime((uint32_t)p->q, 1))
00478                     == -1)
00479                         return -1;
00480                 t = ms->offset + sizeof(uint64_t);
00481                 break;
00482 
00483         case FILE_QLDATE:
00484         case FILE_BEQLDATE:
00485         case FILE_LEQLDATE:
00486                 if (file_printf(ms, m->desc, file_fmttime((uint32_t)p->q, 0))
00487                     == -1)
00488                         return -1;
00489                 t = ms->offset + sizeof(uint64_t);
00490                 break;
00491 
00492         case FILE_REGEX: {
00493                 char *cp;
00494                 int rval;
00495 
00496                 cp = strndup((const char *)ms->search.s, ms->search.rm_len);
00497                 if (cp == NULL) {
00498                         file_oomem(ms, ms->search.rm_len);
00499                         return -1;
00500                 }
00501                 rval = file_printf(ms, m->desc, cp);
00502                 free(cp);
00503 
00504                 if (rval == -1)
00505                         return -1;
00506 
00507                 if ((m->str_flags & REGEX_OFFSET_START))
00508                         t = ms->search.offset;
00509                 else
00510                         t = ms->search.offset + ms->search.rm_len;
00511                 break;
00512         }
00513 
00514         case FILE_SEARCH:
00515                 if (file_printf(ms, m->desc, m->value.s) == -1)
00516                         return -1;
00517                 if ((m->str_flags & REGEX_OFFSET_START))
00518                         t = ms->search.offset;
00519                 else
00520                         t = ms->search.offset + m->vallen;
00521                 break;
00522 
00523         case FILE_DEFAULT:
00524                 if (file_printf(ms, m->desc, m->value.s) == -1)
00525                         return -1;
00526                 t = ms->offset;
00527                 break;
00528 
00529         default:
00530                 file_magerror(ms, "invalid m->type (%d) in mprint()", m->type);
00531                 return -1;
00532         }
00533         return(t);
00534 }
00535 
00536 
00537 #define DO_CVT(fld, cast) \
00538         if (m->num_mask) \
00539                 switch (m->mask_op & FILE_OPS_MASK) { \
00540                 case FILE_OPAND: \
00541                         p->fld &= cast m->num_mask; \
00542                         break; \
00543                 case FILE_OPOR: \
00544                         p->fld |= cast m->num_mask; \
00545                         break; \
00546                 case FILE_OPXOR: \
00547                         p->fld ^= cast m->num_mask; \
00548                         break; \
00549                 case FILE_OPADD: \
00550                         p->fld += cast m->num_mask; \
00551                         break; \
00552                 case FILE_OPMINUS: \
00553                         p->fld -= cast m->num_mask; \
00554                         break; \
00555                 case FILE_OPMULTIPLY: \
00556                         p->fld *= cast m->num_mask; \
00557                         break; \
00558                 case FILE_OPDIVIDE: \
00559                         p->fld /= cast m->num_mask; \
00560                         break; \
00561                 case FILE_OPMODULO: \
00562                         p->fld %= cast m->num_mask; \
00563                         break; \
00564                 } \
00565         if (m->mask_op & FILE_OPINVERSE) \
00566                 p->fld = ~p->fld \
00567 
00568 private void
00569 cvt_8(union VALUETYPE *p, const struct magic *m)
00570 {
00571         DO_CVT(b, (uint8_t));
00572 }
00573 
00574 private void
00575 cvt_16(union VALUETYPE *p, const struct magic *m)
00576 {
00577         DO_CVT(h, (uint16_t));
00578 }
00579 
00580 private void
00581 cvt_32(union VALUETYPE *p, const struct magic *m)
00582 {
00583         DO_CVT(l, (uint32_t));
00584 }
00585 
00586 private void
00587 cvt_64(union VALUETYPE *p, const struct magic *m)
00588 {
00589         DO_CVT(q, (uint64_t));
00590 }
00591 
00592 /*
00593  * Convert the byte order of the data we are looking at
00594  * While we're here, let's apply the mask operation
00595  * (unless you have a better idea)
00596  */
00597 private int
00598 mconvert(struct magic_set *ms, struct magic *m)
00599 {
00600         union VALUETYPE *p = &ms->ms_value;
00601 
00602         switch (m->type) {
00603         case FILE_BYTE:
00604                 cvt_8(p, m);
00605                 return 1;
00606         case FILE_SHORT:
00607                 cvt_16(p, m);
00608                 return 1;
00609         case FILE_LONG:
00610         case FILE_DATE:
00611         case FILE_LDATE:
00612                 cvt_32(p, m);
00613                 return 1;
00614         case FILE_QUAD:
00615         case FILE_QDATE:
00616         case FILE_QLDATE:
00617                 cvt_64(p, m);
00618                 return 1;
00619         case FILE_STRING:
00620         case FILE_BESTRING16:
00621         case FILE_LESTRING16: {
00622                         size_t len;
00623 
00624                         /* Null terminate and eat *trailing* return */
00625                         p->s[sizeof(p->s) - 1] = '\0';
00626                         len = strlen(p->s);
00627                         if (len-- && p->s[len] == '\n')
00628                                 p->s[len] = '\0';
00629                         return 1;
00630                 }
00631         case FILE_PSTRING: {
00632                         char *ptr1 = p->s, *ptr2 = ptr1 + 1;
00633                         size_t len = *p->s;
00634                         if (len >= sizeof(p->s))
00635                                 len = sizeof(p->s) - 1;
00636                         while (len--)
00637                                 *ptr1++ = *ptr2++;
00638                         *ptr1 = '\0';
00639                         len = strlen(p->s);
00640                         if (len-- && p->s[len] == '\n')
00641                                 p->s[len] = '\0';
00642                         return 1;
00643                 }
00644         case FILE_BESHORT:
00645                 p->h = (short)((p->hs[0]<<8)|(p->hs[1]));
00646                 cvt_16(p, m);
00647                 return 1;
00648         case FILE_BELONG:
00649         case FILE_BEDATE:
00650         case FILE_BELDATE:
00651                 p->l = (int32_t)
00652                     ((p->hl[0]<<24)|(p->hl[1]<<16)|(p->hl[2]<<8)|(p->hl[3]));
00653                 cvt_32(p, m);
00654                 return 1;
00655         case FILE_BEQUAD:
00656         case FILE_BEQDATE:
00657         case FILE_BEQLDATE:
00658                 p->q = (int64_t)
00659                     (((int64_t)p->hq[0]<<56)|((int64_t)p->hq[1]<<48)|
00660                      ((int64_t)p->hq[2]<<40)|((int64_t)p->hq[3]<<32)|
00661                      (p->hq[4]<<24)|(p->hq[5]<<16)|(p->hq[6]<<8)|(p->hq[7]));
00662                 cvt_64(p, m);
00663                 return 1;
00664         case FILE_LESHORT:
00665                 p->h = (short)((p->hs[1]<<8)|(p->hs[0]));
00666                 cvt_16(p, m);
00667                 return 1;
00668         case FILE_LELONG:
00669         case FILE_LEDATE:
00670         case FILE_LELDATE:
00671                 p->l = (int32_t)
00672                     ((p->hl[3]<<24)|(p->hl[2]<<16)|(p->hl[1]<<8)|(p->hl[0]));
00673                 cvt_32(p, m);
00674                 return 1;
00675         case FILE_LEQUAD:
00676         case FILE_LEQDATE:
00677         case FILE_LEQLDATE:
00678                 p->q = (int64_t)
00679                     (((int64_t)p->hq[7]<<56)|((int64_t)p->hq[6]<<48)|
00680                      ((int64_t)p->hq[5]<<40)|((int64_t)p->hq[4]<<32)|
00681                      (p->hq[3]<<24)|(p->hq[2]<<16)|(p->hq[1]<<8)|(p->hq[0]));
00682                 cvt_64(p, m);
00683                 return 1;
00684         case FILE_MELONG:
00685         case FILE_MEDATE:
00686         case FILE_MELDATE:
00687                 p->l = (int32_t)
00688                     ((p->hl[1]<<24)|(p->hl[0]<<16)|(p->hl[3]<<8)|(p->hl[2]));
00689                 cvt_32(p, m);
00690                 return 1;
00691         case FILE_REGEX:
00692         case FILE_SEARCH:
00693         case FILE_DEFAULT:
00694                 return 1;
00695         default:
00696                 file_magerror(ms, "invalid type %d in mconvert()", m->type);
00697                 return 0;
00698         }
00699 }
00700 
00701 
00702 private void
00703 mdebug(uint32_t offset, const char *str, size_t len)
00704 {
00705         (void) fprintf(stderr, "mget @%d: ", offset);
00706         file_showstr(stderr, str, len);
00707         (void) fputc('\n', stderr);
00708         (void) fputc('\n', stderr);
00709 }
00710 
00711 private int
00712 mcopy(struct magic_set *ms, union VALUETYPE *p, int type, int indir,
00713     const unsigned char *s, uint32_t offset, size_t nbytes, size_t linecnt)
00714 {
00715         /*
00716          * Note: FILE_SEARCH and FILE_REGEX do not actually copy
00717          * anything, but setup pointers into the source
00718          */
00719         if (indir == 0) {
00720                 switch (type) {
00721                 case FILE_SEARCH:
00722                         ms->search.s = (const char *)s + offset;
00723                         ms->search.s_len = nbytes - offset;
00724                         return 0;
00725 
00726                 case FILE_REGEX: {
00727                 /*
00728                  * offset is interpreted as last line to search,
00729                  * (starting at 1), not as bytes-from start-of-file
00730                  */
00731                         const char *b;
00732                         const char *c;
00733                         const char *last;       /* end of search region */
00734                         const char *buf;        /* start of search region */
00735                         size_t lines;
00736 
00737                         if (s == NULL) {
00738                                 ms->search.s_len = 0;
00739                                 ms->search.s = NULL;
00740                                 return 0;
00741                         }
00742                         buf = (const char *)s + offset;
00743                         last = (const char *)s + nbytes;
00744                         /* mget() guarantees buf <= last */
00745                         for (lines = linecnt, b = buf;
00746                              lines && ((b = strchr(c = b, '\n')) || (b = strchr(c, '\r')));
00747                              lines--, b++) {
00748                         last = b;
00749                                 if (b[0] == '\r' && b[1] == '\n')
00750                                         b++;
00751                 }
00752                         if (lines)
00753                                 last = (const char *)s + nbytes;
00754                         
00755                         ms->search.s = buf;
00756                         ms->search.s_len = last - buf;
00757                         ms->search.offset = offset;
00758                         ms->search.rm_len = 0;
00759                 return 0;
00760         }
00761                 case FILE_BESTRING16:
00762                 case FILE_LESTRING16: {
00763                 const unsigned char *src = s + offset;
00764                 const unsigned char *esrc = s + nbytes;
00765                         char *dst = p->s;
00766                         char *edst = &p->s[sizeof(p->s) - 1];
00767 
00768                 if (type == FILE_BESTRING16)
00769                         src++;
00770 
00771                         /* check for pointer overflow */
00772                         if (src < s) {
00773                                 file_magerror(ms, "invalid offset %zu in mcopy()",
00774                                     offset);
00775                                 return -1;
00776                         }
00777                         for (/*EMPTY*/; src < esrc; src++, dst++) {
00778                         if (dst < edst)
00779                                 *dst = *src++;
00780                         else
00781                                         /*@loopbreak@*/ break;
00782                         if (*dst == '\0')
00783                                 *dst = ' ';
00784                 }
00785                 *edst = '\0';
00786                 return 0;
00787         }
00788                 case FILE_STRING:       /* XXX - these two should not need */
00789                 case FILE_PSTRING:      /* to copy anything, but do anyway. */
00790                 default:
00791                         break;
00792                 }
00793         }
00794 
00795         if (offset >= nbytes) {
00796                 (void)memset(p, '\0', sizeof(*p));
00797                 return 0;
00798         }
00799         if (nbytes - offset < sizeof(*p))
00800                 nbytes = nbytes - offset;
00801         else
00802                 nbytes = sizeof(*p);
00803 
00804         (void)memcpy(p, s + offset, nbytes);
00805 
00806         /*
00807          * the usefulness of padding with zeroes eludes me, it
00808          * might even cause problems
00809          */
00810         if (nbytes < sizeof(*p))
00811                 (void)memset(((char *)(void *)p) + nbytes, '\0',
00812                     sizeof(*p) - nbytes);
00813         return 0;
00814 }
00815 
00816 private int
00817 mget(struct magic_set *ms, const unsigned char *s,
00818     struct magic *m, size_t nbytes, unsigned int cont_level)
00819 {
00820         uint32_t offset = ms->offset;
00821         uint32_t count = m->str_count;
00822         union VALUETYPE *p = &ms->ms_value;
00823 
00824         if (mcopy(ms, p, m->type, m->flag & INDIR, s, offset, nbytes, count) == -1)
00825                 return -1;
00826 
00827         if ((ms->flags & MAGIC_DEBUG) != 0) {
00828                 mdebug(offset, (char *)(void *)p, sizeof(union VALUETYPE));
00829                 file_mdump(m);
00830         }
00831 
00832         if (m->flag & INDIR) {
00833                 int off = m->in_offset;
00834                 if (m->in_op & FILE_OPINDIRECT) {
00835                         const union VALUETYPE *q =
00836                             ((const void *)(s + offset + off));
00837                         switch (m->in_type) {
00838                         case FILE_BYTE:
00839                                 off = q->b;
00840                                 break;
00841                         case FILE_SHORT:
00842                                 off = q->h;
00843                                 break;
00844                         case FILE_BESHORT:
00845                                 off = (short)((q->hs[0]<<8)|(q->hs[1]));
00846                                 break;
00847                         case FILE_LESHORT:
00848                                 off = (short)((q->hs[1]<<8)|(q->hs[0]));
00849                                 break;
00850                         case FILE_LONG:
00851                                 off = q->l;
00852                                 break;
00853                         case FILE_BELONG:
00854                                 off = (int32_t)((q->hl[0]<<24)|(q->hl[1]<<16)|
00855                                                  (q->hl[2]<<8)|(q->hl[3]));
00856                                 break;
00857                         case FILE_LELONG:
00858                                 off = (int32_t)((q->hl[3]<<24)|(q->hl[2]<<16)|
00859                                                  (q->hl[1]<<8)|(q->hl[0]));
00860                                 break;
00861                         case FILE_MELONG:
00862                                 off = (int32_t)((q->hl[1]<<24)|(q->hl[0]<<16)|
00863                                                  (q->hl[3]<<8)|(q->hl[2]));
00864                                 break;
00865                         }
00866                 }
00867                 switch (m->in_type) {
00868                 case FILE_BYTE:
00869                         if (nbytes < (offset + 1))
00870                                 return 0;
00871                         if (off) {
00872                                 switch (m->in_op & FILE_OPS_MASK) {
00873                                 case FILE_OPAND:
00874                                         offset = p->b & off;
00875                                         /*@innerbreak@*/ break;
00876                                 case FILE_OPOR:
00877                                         offset = p->b | off;
00878                                         /*@innerbreak@*/ break;
00879                                 case FILE_OPXOR:
00880                                         offset = p->b ^ off;
00881                                         /*@innerbreak@*/ break;
00882                                 case FILE_OPADD:
00883                                         offset = p->b + off;
00884                                         /*@innerbreak@*/ break;
00885                                 case FILE_OPMINUS:
00886                                         offset = p->b - off;
00887                                         /*@innerbreak@*/ break;
00888                                 case FILE_OPMULTIPLY:
00889                                         offset = p->b * off;
00890                                         /*@innerbreak@*/ break;
00891                                 case FILE_OPDIVIDE:
00892                                         offset = p->b / off;
00893                                         /*@innerbreak@*/ break;
00894                                 case FILE_OPMODULO:
00895                                         offset = p->b % off;
00896                                         /*@innerbreak@*/ break;
00897                                 }
00898                         } else
00899                                 offset = p->b;
00900                         if (m->in_op & FILE_OPINVERSE)
00901                                 offset = ~offset;
00902                         break;
00903                 case FILE_BESHORT:
00904                         if (nbytes < (offset + 2))
00905                                 return 0;
00906                         if (off) {
00907                                 switch (m->in_op & FILE_OPS_MASK) {
00908                                 case FILE_OPAND:
00909                                         offset = (short)((p->hs[0]<<8)|
00910                                                          (p->hs[1])) &
00911                                                  off;
00912                                         /*@innerbreak@*/ break;
00913                                 case FILE_OPOR:
00914                                         offset = (short)((p->hs[0]<<8)|
00915                                                          (p->hs[1])) |
00916                                                  off;
00917                                         /*@innerbreak@*/ break;
00918                                 case FILE_OPXOR:
00919                                         offset = (short)((p->hs[0]<<8)|
00920                                                          (p->hs[1])) ^
00921                                                  off;
00922                                         /*@innerbreak@*/ break;
00923                                 case FILE_OPADD:
00924                                         offset = (short)((p->hs[0]<<8)|
00925                                                          (p->hs[1])) +
00926                                                  off;
00927                                         /*@innerbreak@*/ break;
00928                                 case FILE_OPMINUS:
00929                                         offset = (short)((p->hs[0]<<8)|
00930                                                          (p->hs[1])) -
00931                                                  off;
00932                                         /*@innerbreak@*/ break;
00933                                 case FILE_OPMULTIPLY:
00934                                         offset = (short)((p->hs[0]<<8)|
00935                                                          (p->hs[1])) *
00936                                                  off;
00937                                         /*@innerbreak@*/ break;
00938                                 case FILE_OPDIVIDE:
00939                                         offset = (short)((p->hs[0]<<8)|
00940                                                          (p->hs[1])) /
00941                                                  off;
00942                                         /*@innerbreak@*/ break;
00943                                 case FILE_OPMODULO:
00944                                         offset = (short)((p->hs[0]<<8)|
00945                                                          (p->hs[1])) %
00946                                                  off;
00947                                         /*@innerbreak@*/ break;
00948                                 }
00949                         } else
00950                                 offset = (short)((p->hs[0]<<8)|
00951                                                  (p->hs[1]));
00952                         if (m->in_op & FILE_OPINVERSE)
00953                                 offset = ~offset;
00954                         break;
00955                 case FILE_LESHORT:
00956                         if (nbytes < (offset + 2))
00957                                 return 0;
00958                         if (off) {
00959                                 switch (m->in_op & FILE_OPS_MASK) {
00960                                 case FILE_OPAND:
00961                                         offset = (short)((p->hs[1]<<8)|
00962                                                          (p->hs[0])) &
00963                                                  off;
00964                                         /*@innerbreak@*/ break;
00965                                 case FILE_OPOR:
00966                                         offset = (short)((p->hs[1]<<8)|
00967                                                          (p->hs[0])) |
00968                                                  off;
00969                                         /*@innerbreak@*/ break;
00970                                 case FILE_OPXOR:
00971                                         offset = (short)((p->hs[1]<<8)|
00972                                                          (p->hs[0])) ^
00973                                                  off;
00974                                         /*@innerbreak@*/ break;
00975                                 case FILE_OPADD:
00976                                         offset = (short)((p->hs[1]<<8)|
00977                                                          (p->hs[0])) +
00978                                                  off;
00979                                         /*@innerbreak@*/ break;
00980                                 case FILE_OPMINUS:
00981                                         offset = (short)((p->hs[1]<<8)|
00982                                                          (p->hs[0])) -
00983                                                  off;
00984                                         /*@innerbreak@*/ break;
00985                                 case FILE_OPMULTIPLY:
00986                                         offset = (short)((p->hs[1]<<8)|
00987                                                          (p->hs[0])) *
00988                                                  off;
00989                                         /*@innerbreak@*/ break;
00990                                 case FILE_OPDIVIDE:
00991                                         offset = (short)((p->hs[1]<<8)|
00992                                                          (p->hs[0])) /
00993                                                  off;
00994                                         /*@innerbreak@*/ break;
00995                                 case FILE_OPMODULO:
00996                                         offset = (short)((p->hs[1]<<8)|
00997                                                          (p->hs[0])) %
00998                                                  off;
00999                                         /*@innerbreak@*/ break;
01000                                 }
01001                         } else
01002                                 offset = (short)((p->hs[1]<<8)|
01003                                                  (p->hs[0]));
01004                         if (m->in_op & FILE_OPINVERSE)
01005                                 offset = ~offset;
01006                         break;
01007                 case FILE_SHORT:
01008                         if (nbytes < (offset + 2))
01009                                 return 0;
01010                         if (off) {
01011                                 switch (m->in_op & FILE_OPS_MASK) {
01012                                 case FILE_OPAND:
01013                                         offset = p->h & off;
01014                                         /*@innerbreak@*/ break;
01015                                 case FILE_OPOR:
01016                                         offset = p->h | off;
01017                                         /*@innerbreak@*/ break;
01018                                 case FILE_OPXOR:
01019                                         offset = p->h ^ off;
01020                                         /*@innerbreak@*/ break;
01021                                 case FILE_OPADD:
01022                                         offset = p->h + off;
01023                                         /*@innerbreak@*/ break;
01024                                 case FILE_OPMINUS:
01025                                         offset = p->h - off;
01026                                         /*@innerbreak@*/ break;
01027                                 case FILE_OPMULTIPLY:
01028                                         offset = p->h * off;
01029                                         /*@innerbreak@*/ break;
01030                                 case FILE_OPDIVIDE:
01031                                         offset = p->h / off;
01032                                         /*@innerbreak@*/ break;
01033                                 case FILE_OPMODULO:
01034                                         offset = p->h % off;
01035                                         /*@innerbreak@*/ break;
01036                                 }
01037                         }
01038                         else
01039                                 offset = p->h;
01040                         if (m->in_op & FILE_OPINVERSE)
01041                                 offset = ~offset;
01042                         break;
01043                 case FILE_BELONG:
01044                         if (nbytes < (offset + 4))
01045                                 return 0;
01046                         if (off) {
01047                                 switch (m->in_op & FILE_OPS_MASK) {
01048                                 case FILE_OPAND:
01049                                         offset = (int32_t)((p->hl[0]<<24)|
01050                                                          (p->hl[1]<<16)|
01051                                                          (p->hl[2]<<8)|
01052                                                          (p->hl[3])) &
01053                                                  off;
01054                                         /*@innerbreak@*/ break;
01055                                 case FILE_OPOR:
01056                                         offset = (int32_t)((p->hl[0]<<24)|
01057                                                          (p->hl[1]<<16)|
01058                                                          (p->hl[2]<<8)|
01059                                                          (p->hl[3])) |
01060                                                  off;
01061                                         /*@innerbreak@*/ break;
01062                                 case FILE_OPXOR:
01063                                         offset = (int32_t)((p->hl[0]<<24)|
01064                                                          (p->hl[1]<<16)|
01065                                                          (p->hl[2]<<8)|
01066                                                          (p->hl[3])) ^
01067                                                  off;
01068                                         /*@innerbreak@*/ break;
01069                                 case FILE_OPADD:
01070                                         offset = (int32_t)((p->hl[0]<<24)|
01071                                                          (p->hl[1]<<16)|
01072                                                          (p->hl[2]<<8)|
01073                                                          (p->hl[3])) +
01074                                                  off;
01075                                         /*@innerbreak@*/ break;
01076                                 case FILE_OPMINUS:
01077                                         offset = (int32_t)((p->hl[0]<<24)|
01078                                                          (p->hl[1]<<16)|
01079                                                          (p->hl[2]<<8)|
01080                                                          (p->hl[3])) -
01081                                                  off;
01082                                         /*@innerbreak@*/ break;
01083                                 case FILE_OPMULTIPLY:
01084                                         offset = (int32_t)((p->hl[0]<<24)|
01085                                                          (p->hl[1]<<16)|
01086                                                          (p->hl[2]<<8)|
01087                                                          (p->hl[3])) *
01088                                                  off;
01089                                         /*@innerbreak@*/ break;
01090                                 case FILE_OPDIVIDE:
01091                                         offset = (int32_t)((p->hl[0]<<24)|
01092                                                          (p->hl[1]<<16)|
01093                                                          (p->hl[2]<<8)|
01094                                                          (p->hl[3])) /
01095                                                  off;
01096                                         /*@innerbreak@*/ break;
01097                                 case FILE_OPMODULO:
01098                                         offset = (int32_t)((p->hl[0]<<24)|
01099                                                          (p->hl[1]<<16)|
01100                                                          (p->hl[2]<<8)|
01101                                                          (p->hl[3])) %
01102                                                  off;
01103                                         /*@innerbreak@*/ break;
01104                                 }
01105                         } else
01106                                 offset = (int32_t)((p->hl[0]<<24)|
01107                                                  (p->hl[1]<<16)|
01108                                                  (p->hl[2]<<8)|
01109                                                  (p->hl[3]));
01110                         if (m->in_op & FILE_OPINVERSE)
01111                                 offset = ~offset;
01112                         break;
01113                 case FILE_LELONG:
01114                         if (nbytes < (offset + 4))
01115                                 return 0;
01116                         if (off) {
01117                                 switch (m->in_op & FILE_OPS_MASK) {
01118                                 case FILE_OPAND:
01119                                         offset = (int32_t)((p->hl[3]<<24)|
01120                                                          (p->hl[2]<<16)|
01121                                                          (p->hl[1]<<8)|
01122                                                          (p->hl[0])) &
01123                                                  off;
01124                                         /*@innerbreak@*/ break;
01125                                 case FILE_OPOR:
01126                                         offset = (int32_t)((p->hl[3]<<24)|
01127                                                          (p->hl[2]<<16)|
01128                                                          (p->hl[1]<<8)|
01129                                                          (p->hl[0])) |
01130                                                  off;
01131                                         /*@innerbreak@*/ break;
01132                                 case FILE_OPXOR:
01133                                         offset = (int32_t)((p->hl[3]<<24)|
01134                                                          (p->hl[2]<<16)|
01135                                                          (p->hl[1]<<8)|
01136                                                          (p->hl[0])) ^
01137                                                  off;
01138                                         /*@innerbreak@*/ break;
01139                                 case FILE_OPADD:
01140                                         offset = (int32_t)((p->hl[3]<<24)|
01141                                                          (p->hl[2]<<16)|
01142                                                          (p->hl[1]<<8)|
01143                                                          (p->hl[0])) +
01144                                                  off;
01145                                         /*@innerbreak@*/ break;
01146                                 case FILE_OPMINUS:
01147                                         offset = (int32_t)((p->hl[3]<<24)|
01148                                                          (p->hl[2]<<16)|
01149                                                          (p->hl[1]<<8)|
01150                                                          (p->hl[0])) -
01151                                                  off;
01152                                         /*@innerbreak@*/ break;
01153                                 case FILE_OPMULTIPLY:
01154                                         offset = (int32_t)((p->hl[3]<<24)|
01155                                                          (p->hl[2]<<16)|
01156                                                          (p->hl[1]<<8)|
01157                                                          (p->hl[0])) *
01158                                                  off;
01159                                         /*@innerbreak@*/ break;
01160                                 case FILE_OPDIVIDE:
01161                                         offset = (int32_t)((p->hl[3]<<24)|
01162                                                          (p->hl[2]<<16)|
01163                                                          (p->hl[1]<<8)|
01164                                                          (p->hl[0])) /
01165                                                  off;
01166                                         /*@innerbreak@*/ break;
01167                                 case FILE_OPMODULO:
01168                                         offset = (int32_t)((p->hl[3]<<24)|
01169                                                          (p->hl[2]<<16)|
01170                                                          (p->hl[1]<<8)|
01171                                                          (p->hl[0])) %
01172                                                  off;
01173                                         /*@innerbreak@*/ break;
01174                                 }
01175                         } else
01176                                 offset = (int32_t)((p->hl[3]<<24)|
01177                                                  (p->hl[2]<<16)|
01178                                                  (p->hl[1]<<8)|
01179                                                  (p->hl[0]));
01180                         if (m->in_op & FILE_OPINVERSE)
01181                                 offset = ~offset;
01182                         break;
01183                 case FILE_MELONG:
01184                         if (nbytes < (offset + 4))
01185                                 return 0;
01186                         if (off) {
01187                                 switch (m->in_op & FILE_OPS_MASK) {
01188                                 case FILE_OPAND:
01189                                         offset = (int32_t)((p->hl[1]<<24)|
01190                                                          (p->hl[0]<<16)|
01191                                                          (p->hl[3]<<8)|
01192                                                          (p->hl[2])) &
01193                                                  off;
01194                                         /*@innerbreak@*/ break;
01195                                 case FILE_OPOR:
01196                                         offset = (int32_t)((p->hl[1]<<24)|
01197                                                          (p->hl[0]<<16)|
01198                                                          (p->hl[3]<<8)|
01199                                                          (p->hl[2])) |
01200                                                  off;
01201                                         /*@innerbreak@*/ break;
01202                                 case FILE_OPXOR:
01203                                         offset = (int32_t)((p->hl[1]<<24)|
01204                                                          (p->hl[0]<<16)|
01205                                                          (p->hl[3]<<8)|
01206                                                          (p->hl[2])) ^
01207                                                  off;
01208                                         /*@innerbreak@*/ break;
01209                                 case FILE_OPADD:
01210                                         offset = (int32_t)((p->hl[1]<<24)|
01211                                                          (p->hl[0]<<16)|
01212                                                          (p->hl[3]<<8)|
01213                                                          (p->hl[2])) +
01214                                                  off;
01215                                         /*@innerbreak@*/ break;
01216                                 case FILE_OPMINUS:
01217                                         offset = (int32_t)((p->hl[1]<<24)|
01218                                                          (p->hl[0]<<16)|
01219                                                          (p->hl[3]<<8)|
01220                                                          (p->hl[2])) -
01221                                                  off;
01222                                         /*@innerbreak@*/ break;
01223                                 case FILE_OPMULTIPLY:
01224                                         offset = (int32_t)((p->hl[1]<<24)|
01225                                                          (p->hl[0]<<16)|
01226                                                          (p->hl[3]<<8)|
01227                                                          (p->hl[2])) *
01228                                                  off;
01229                                         /*@innerbreak@*/ break;
01230                                 case FILE_OPDIVIDE:
01231                                         offset = (int32_t)((p->hl[1]<<24)|
01232                                                          (p->hl[0]<<16)|
01233                                                          (p->hl[3]<<8)|
01234                                                          (p->hl[2])) /
01235                                                  off;
01236                                         /*@innerbreak@*/ break;
01237                                 case FILE_OPMODULO:
01238                                         offset = (int32_t)((p->hl[1]<<24)|
01239                                                          (p->hl[0]<<16)|
01240                                                          (p->hl[3]<<8)|
01241                                                          (p->hl[2])) %
01242                                                  off;
01243                                         /*@innerbreak@*/ break;
01244                                 }
01245                         } else
01246                                 offset = (int32_t)((p->hl[1]<<24)|
01247                                                  (p->hl[0]<<16)|
01248                                                  (p->hl[3]<<8)|
01249                                                  (p->hl[2]));
01250                         if (m->in_op & FILE_OPINVERSE)
01251                                 offset = ~offset;
01252                         break;
01253                 case FILE_LONG:
01254                         if (nbytes < (offset + 4))
01255                                 return 0;
01256                         if (off) {
01257                                 switch (m->in_op & FILE_OPS_MASK) {
01258                                 case FILE_OPAND:
01259                                         offset = p->l & off;
01260                                         /*@innerbreak@*/ break;
01261                                 case FILE_OPOR:
01262                                         offset = p->l | off;
01263                                         /*@innerbreak@*/ break;
01264                                 case FILE_OPXOR:
01265                                         offset = p->l ^ off;
01266                                         /*@innerbreak@*/ break;
01267                                 case FILE_OPADD:
01268                                         offset = p->l + off;
01269                                         /*@innerbreak@*/ break;
01270                                 case FILE_OPMINUS:
01271                                         offset = p->l - off;
01272                                         /*@innerbreak@*/ break;
01273                                 case FILE_OPMULTIPLY:
01274                                         offset = p->l * off;
01275                                         /*@innerbreak@*/ break;
01276                                 case FILE_OPDIVIDE:
01277                                         offset = p->l / off;
01278                                         /*@innerbreak@*/ break;
01279                                 case FILE_OPMODULO:
01280                                         offset = p->l % off;
01281                                         /*@innerbreak@*/ break;
01282                         /*      case TOOMANYSWITCHBLOCKS:
01283                          *              ugh = p->eye % m->strain;
01284                          *              rub;
01285                          *      case BEER:
01286                          *              off = p->tab & m->in_gest;
01287                          *              sleep;
01288                          */
01289                                 }
01290                         } else
01291                                 offset = p->l;
01292                         if (m->in_op & FILE_OPINVERSE)
01293                                 offset = ~offset;
01294                         break;
01295                 }
01296 
01297                 if (m->flag & INDIROFFADD)
01298                         offset += ms->c.li[cont_level-1].off;
01299                 if (mcopy(ms, p, m->type, 0, s, offset, nbytes, count) == -1)
01300                         return -1;
01301                 ms->offset = offset;
01302 
01303                 if ((ms->flags & MAGIC_DEBUG) != 0) {
01304                         mdebug(offset, (char *)(void *)p,
01305                             sizeof(union VALUETYPE));
01306                         file_mdump(m);
01307                 }
01308         }
01309 
01310         /* Verify we have enough data to match magic type */
01311         switch (m->type) {
01312                 case FILE_BYTE:
01313                         if (nbytes < (offset + 1)) /* should alway be true */
01314                                 return 0;
01315                         break;
01316 
01317                 case FILE_SHORT:
01318                 case FILE_BESHORT:
01319                 case FILE_LESHORT:
01320                         if (nbytes < (offset + 2))
01321                                 return 0;
01322                         break;
01323 
01324                 case FILE_LONG:
01325                 case FILE_BELONG:
01326                 case FILE_LELONG:
01327         case FILE_MELONG:
01328                 case FILE_DATE:
01329                 case FILE_BEDATE:
01330                 case FILE_LEDATE:
01331         case FILE_MEDATE:
01332                 case FILE_LDATE:
01333                 case FILE_BELDATE:
01334                 case FILE_LELDATE:
01335         case FILE_MELDATE:
01336                         if (nbytes < (offset + 4))
01337                                 return 0;
01338                         break;
01339 
01340                 case FILE_STRING:
01341                 case FILE_PSTRING:
01342                 case FILE_SEARCH:
01343                         if (nbytes < (offset + m->vallen))
01344                                 return 0;
01345                         break;
01346 
01347         case FILE_REGEX:
01348                 if (nbytes < offset)
01349                         return 0;
01350                 break;
01351 
01352         case FILE_DEFAULT:      /* nothing to check */
01353         default:
01354                 break;
01355                 }
01356         if (!mconvert(ms, m))
01357                 return 0;
01358         return 1;
01359 }
01360 
01361 private uint64_t
01362 file_strncmp(const char *s1, const char *s2, size_t len, uint32_t flags)
01363         /*@*/
01364 {
01365         /*
01366          * Convert the source args to unsigned here so that (1) the
01367          * compare will be unsigned as it is in strncmp() and (2) so
01368          * the ctype functions will work correctly without extra
01369          * casting.
01370          */
01371         const unsigned char *a = (const unsigned char *)s1;
01372         const unsigned char *b = (const unsigned char *)s2;
01373         uint64_t v;
01374 
01375         /*
01376          * What we want here is:
01377          * v = strncmp(m->value.s, p->s, m->vallen);
01378          * but ignoring any nulls.  bcmp doesn't give -/+/0
01379          * and isn't universally available anyway.
01380          */
01381         v = 0;
01382         if (0L == flags) { /* normal string: do it fast */
01383                 while (len-- > 0)
01384                         if ((v = *b++ - *a++) != '\0')
01385                                 break; 
01386         }
01387         else { /* combine the others */
01388                 while (len-- > 0) {
01389                         if ((flags & STRING_IGNORE_LOWERCASE) &&
01390                             islower(*a)) {
01391                                 if ((v = tolower(*b++) - *a++) != '\0')
01392                                         break;
01393                         }
01394                         else if ((flags & STRING_IGNORE_UPPERCASE) &&
01395                             isupper(*a)) {
01396                                 if ((v = toupper(*b++) - *a++) != '\0')
01397                                         break;
01398                         }
01399                         else if ((flags & STRING_COMPACT_BLANK) && 
01400                             isspace(*a)) { 
01401                                 a++;
01402                                 if (isspace(*b++)) {
01403                                         while (isspace(*b))
01404                                                 b++;
01405                                 }
01406                                 else {
01407                                         v = 1;
01408                                         break;
01409                                 }
01410                         }
01411                         else if ((flags & STRING_COMPACT_OPTIONAL_BLANK) &&
01412                             isspace(*a)) {
01413                                 a++;
01414                                 while (isspace(*b))
01415                                         b++;
01416                         }
01417                         else {
01418                                 if ((v = *b++ - *a++) != '\0')
01419                                         break;
01420                         }
01421                 }
01422         }
01423         return v;
01424         }
01425 
01426 private uint64_t
01427 file_strncmp16(const char *a, const char *b, size_t len, uint32_t flags)
01428         /*@*/
01429 {
01430         /*
01431          * XXX - The 16-bit string compare probably needs to be done
01432          * differently, especially if the flags are to be supported.
01433          * At the moment, I am unsure.
01434          */
01435         flags = 0;
01436         return file_strncmp(a, b, len, flags);
01437 }
01438 
01439 private int
01440 magiccheck(struct magic_set *ms, struct magic *m)
01441 {
01442         uint64_t l = m->value.q;
01443         uint64_t v;
01444         int matched;
01445         union VALUETYPE *p = &ms->ms_value;
01446 
01447         switch (m->type) {
01448         case FILE_BYTE:
01449                 v = p->b;
01450                 break;
01451 
01452         case FILE_SHORT:
01453         case FILE_BESHORT:
01454         case FILE_LESHORT:
01455                 v = p->h;
01456                 break;
01457 
01458         case FILE_LONG:
01459         case FILE_BELONG:
01460         case FILE_LELONG:
01461         case FILE_MELONG:
01462         case FILE_DATE:
01463         case FILE_BEDATE:
01464         case FILE_LEDATE:
01465         case FILE_MEDATE:
01466         case FILE_LDATE:
01467         case FILE_BELDATE:
01468         case FILE_LELDATE:
01469         case FILE_MELDATE:
01470                 v = p->l;
01471                 break;
01472 
01473         case FILE_QUAD:
01474         case FILE_LEQUAD:
01475         case FILE_BEQUAD:
01476         case FILE_QDATE:
01477         case FILE_BEQDATE:
01478         case FILE_LEQDATE:
01479         case FILE_QLDATE:
01480         case FILE_BEQLDATE:
01481         case FILE_LEQLDATE:
01482                 v = p->q;
01483                 break;
01484 
01485         case FILE_DEFAULT:
01486                 l = 0;
01487                 v = 0;
01488                 break;
01489 
01490         case FILE_STRING:
01491         case FILE_PSTRING:
01492                 l = 0;
01493                 v = file_strncmp(m->value.s, p->s, (size_t)m->vallen, m->str_flags);
01494                 break;
01495 
01496         case FILE_BESTRING16:
01497         case FILE_LESTRING16:
01498                 l = 0;
01499                 v = file_strncmp16(m->value.s, p->s, (size_t)m->vallen, m->str_flags);
01500                 break;
01501 
01502         case FILE_SEARCH: { /* search ms->search.s for the string m->value.s */
01503                 size_t slen;
01504                 size_t idx;
01505 
01506                 if (ms->search.s == NULL)
01507                         return 0;
01508 
01509                 slen = MIN(m->vallen, sizeof(m->value.s));
01510                 l = 0;
01511                 v = 0;
01512                 ms->search.offset = m->offset;
01513 
01514                 for (idx = 0; m->str_count == 0 || idx < m->str_count; idx++) {
01515                         if (slen + idx > ms->search.s_len)
01516                                                 /*@loopbreak@*/ break;
01517 
01518                         v = file_strncmp(m->value.s, ms->search.s + idx, slen, m->str_flags);
01519                         if (v == 0) {   /* found match */
01520                                 ms->search.offset = m->offset + idx;
01521                                                 /*@loopbreak@*/ break;
01522                                 }
01523                         }
01524                 break;
01525         }
01526         case FILE_REGEX: {
01527                 int rc;
01528                 regex_t rx;
01529                 char errmsg[512];
01530 
01531                 if (ms->search.s == NULL)
01532                         return 0;
01533 
01534                 l = 0;
01535                 rc = regcomp(&rx, m->value.s,
01536                     REG_EXTENDED|REG_NEWLINE|
01537                     ((m->str_flags & STRING_IGNORE_CASE) ? REG_ICASE : 0));
01538                 if (rc) {
01539                         (void) regerror(rc, &rx, errmsg, sizeof(errmsg));
01540                         file_magerror(ms, "regex error %d, (%s)",
01541                             rc, errmsg);
01542                         v = (uint64_t)-1;
01543         }
01544                 else {
01545                         regmatch_t pmatch[1];
01546 #ifndef REG_STARTEND
01547 #define REG_STARTEND    0
01548                         size_t l = ms->search.s_len - 1;
01549                         char c = ms->search.s[l];
01550                         ((char *)(intptr_t)ms->search.s)[l] = '\0';
01551 #else
01552                         pmatch[0].rm_so = 0;
01553                         pmatch[0].rm_eo = ms->search.s_len;
01554 #endif
01555                         rc = regexec(&rx, (const char *)ms->search.s,
01556                             1, pmatch, REG_STARTEND);
01557 #if REG_STARTEND == 0
01558                         ((char *)(intptr_t)ms->search.s)[l] = c;
01559 #endif
01560                         switch (rc) {
01561                         case 0:
01562                                 ms->search.s += (int)pmatch[0].rm_so;
01563                                 ms->search.offset += (size_t)pmatch[0].rm_so;
01564                                 ms->search.rm_len =
01565                                     (size_t)(pmatch[0].rm_eo - pmatch[0].rm_so);
01566                 v = 0;
01567                                 /*@innerbreak@*/ break;
01568 
01569                         case REG_NOMATCH:
01570                                 v = 1;
01571                                 /*@innerbreak@*/ break;
01572 
01573                         default:
01574                                 (void)regerror(rc, &rx, errmsg, sizeof(errmsg));
01575                                 file_magerror(ms, "regexec error %d, (%s)",
01576                                     rc, errmsg);
01577                                 v = (uint64_t)-1;
01578                                 /*@innerbreak@*/ break;
01579                         }
01580 /*@i@*/                 regfree(&rx);
01581                 }
01582                 if (v == (uint64_t)-1)
01583                         return -1;
01584                 break;
01585         }
01586         default:
01587                 file_magerror(ms, "invalid type %d in magiccheck()", m->type);
01588                 return -1;
01589         }
01590 
01591                 v = file_signextend(ms, m, v);
01592 
01593         switch (m->reln) {
01594         case 'x':
01595                 if ((ms->flags & MAGIC_DEBUG) != 0)
01596                         (void) fprintf(stderr, "%llu == *any* = 1\n",
01597                             (unsigned long long)v);
01598                 matched = 1;
01599                 break;
01600 
01601         case '!':
01602                 matched = v != l;
01603                 if ((ms->flags & MAGIC_DEBUG) != 0)
01604                         (void) fprintf(stderr, "%llu != %llu = %d\n",
01605                             (unsigned long long)v, (unsigned long long)l,
01606                             matched);
01607                 break;
01608 
01609         case '=':
01610                 matched = v == l;
01611                 if ((ms->flags & MAGIC_DEBUG) != 0)
01612                         (void) fprintf(stderr, "%llu == %llu = %d\n",
01613                             (unsigned long long)v, (unsigned long long)l,
01614                             matched);
01615                 break;
01616 
01617         case '>':
01618                 if (m->flag & UNSIGNED) {
01619                         matched = v > l;
01620                         if ((ms->flags & MAGIC_DEBUG) != 0)
01621                                 (void) fprintf(stderr, "%llu > %llu = %d\n",
01622                                     (unsigned long long)v,
01623                                     (unsigned long long)l, matched);
01624                 }
01625                 else {
01626                         matched = (int64_t) v > (int64_t) l;
01627                         if ((ms->flags & MAGIC_DEBUG) != 0)
01628                                 (void) fprintf(stderr, "%lld > %lld = %d\n",
01629                                     (long long)v, (long long)l, matched);
01630                 }
01631                 break;
01632 
01633         case '<':
01634                 if (m->flag & UNSIGNED) {
01635                         matched = v < l;
01636                         if ((ms->flags & MAGIC_DEBUG) != 0)
01637                                 (void) fprintf(stderr, "%llu < %llu = %d\n",
01638                                     (unsigned long long)v,
01639                                     (unsigned long long)l, matched);
01640                 }
01641                 else {
01642                         matched = (int64_t) v < (int64_t) l;
01643                         if ((ms->flags & MAGIC_DEBUG) != 0)
01644                                 (void) fprintf(stderr, "%lld < %lld = %d\n",
01645                                        (long long)v, (long long)l, matched);
01646                 }
01647                 break;
01648 
01649         case '&':
01650                 matched = (v & l) == l;
01651                 if ((ms->flags & MAGIC_DEBUG) != 0)
01652                         (void) fprintf(stderr, "((%llx & %llx) == %llx) = %d\n",
01653                             (unsigned long long)v, (unsigned long long)l,
01654                             (unsigned long long)l, matched);
01655                 break;
01656 
01657         case '^':
01658                 matched = (v & l) != l;
01659                 if ((ms->flags & MAGIC_DEBUG) != 0)
01660                         (void) fprintf(stderr, "((%llx & %llx) != %llx) = %d\n",
01661                             (unsigned long long)v, (unsigned long long)l,
01662                             (unsigned long long)l, matched);
01663                 break;
01664 
01665         default:
01666                 matched = 0;
01667                 file_magerror(ms, "cannot happen: invalid relation `%c'",
01668                     m->reln);
01669                 return -1;
01670         }
01671 
01672         return matched;
01673 }
01674 
01675 private int
01676 print_sep(struct magic_set *ms, int firstline)
01677 {
01678         if (firstline)
01679                 return 0;
01680         /*
01681          * we found another match 
01682          * put a newline and '-' to do some simple formatting
01683          */
01684         return file_printf(ms, "\n- ");
01685 }

Generated on Fri May 25 21:18:11 2007 for rpm by  doxygen 1.5.2