Main Page | Modules | Data Structures | Directories | File List | Data Fields | Globals | Related Pages

header.c

Go to the documentation of this file.
00001 
00005 /* RPM - Copyright (C) 1995-2002 Red Hat Software */
00006 
00007 /* Data written to file descriptors is in network byte order.    */
00008 /* Data read from file descriptors is expected to be in          */
00009 /* network byte order and is converted on the fly to host order. */
00010 
00011 #include "system.h"
00012 
00013 #define __HEADER_PROTOTYPES__
00014 
00015 #include <header_internal.h>
00016 
00017 #include "debug.h"
00018 
00019 /*@unchecked@*/
00020 int _hdr_debug = 0;
00021 
00022 /*@-redecl@*/   /* FIX: avoid rpmlib.h, need for debugging. */
00023 /*@observer@*/ const char *const tagName(int tag)       /*@*/;
00024 /*@=redecl@*/
00025 
00026 /*@access entryInfo @*/
00027 /*@access indexEntry @*/
00028 
00029 /*@access rpmec @*/
00030 /*@access sprintfTag @*/
00031 /*@access sprintfToken @*/
00032 /*@access HV_t @*/
00033 
00034 #define PARSER_BEGIN    0
00035 #define PARSER_IN_ARRAY 1
00036 #define PARSER_IN_EXPR  2
00037 
00038 /* XXX for xml support */
00039 /*@-redecl@*/
00040 /*@observer@*/ extern const char *const tagName(int tag)
00041         /*@*/;
00042 /*@=redecl@*/
00043 
00046 /*@observer@*/ /*@unchecked@*/
00047 static unsigned char header_magic[8] = {
00048         0x8e, 0xad, 0xe8, 0x01, 0x00, 0x00, 0x00, 0x00
00049 };
00050 
00054 /*@observer@*/ /*@unchecked@*/
00055 static int typeAlign[16] =  {
00056     1,  
00057     1,  
00058     1,  
00059     2,  
00060     4,  
00061     8,  
00062     1,  
00063     1,  
00064     1,  
00065     1,  
00066     0,
00067     0,
00068     0,
00069     0,
00070     0,
00071     0
00072 };
00073 
00077 /*@observer@*/ /*@unchecked@*/
00078 static int typeSizes[16] =  { 
00079     0,  
00080     1,  
00081     1,  
00082     2,  
00083     4,  
00084     -1, 
00085     -1, 
00086     1,  
00087     -1, 
00088     -1, 
00089     0,
00090     0,
00091     0,
00092     0,
00093     0,
00094     0
00095 };
00096 
00100 /*@unchecked@*/
00101 static size_t headerMaxbytes = (32*1024*1024);
00102 
00107 #define hdrchkTags(_ntags)      ((_ntags) & 0xffff0000)
00108 
00112 #define hdrchkType(_type) ((_type) < RPM_MIN_TYPE || (_type) > RPM_MAX_TYPE)
00113 
00118 #define hdrchkData(_nbytes)     ((_nbytes) & 0xff000000)
00119 
00123 #define hdrchkAlign(_type, _off)        ((_off) & (typeAlign[_type]-1))
00124 
00128 #define hdrchkRange(_dl, _off)          ((_off) < 0 || (_off) > (_dl))
00129 
00130 /*@observer@*/ /*@unchecked@*/
00131 HV_t hdrVec;    /* forward reference */
00132 
00138 /*@unused@*/ static inline /*@null@*/ void *
00139 _free(/*@only@*/ /*@null@*/ /*@out@*/ const void * p) /*@modifies *p @*/
00140 {
00141     if (p != NULL)      free((void *)p);
00142     return NULL;
00143 }
00144 
00150 static
00151 Header headerLink(Header h)
00152         /*@modifies h @*/
00153 {
00154 /*@-nullret@*/
00155     if (h == NULL) return NULL;
00156 /*@=nullret@*/
00157 
00158     h->nrefs++;
00159 /*@-modfilesys@*/
00160 if (_hdr_debug)
00161 fprintf(stderr, "--> h  %p ++ %d at %s:%u\n", h, h->nrefs, __FILE__, __LINE__);
00162 /*@=modfilesys@*/
00163 
00164     /*@-refcounttrans @*/
00165     return h;
00166     /*@=refcounttrans @*/
00167 }
00168 
00174 static /*@null@*/
00175 Header headerUnlink(/*@killref@*/ /*@null@*/ Header h)
00176         /*@modifies h @*/
00177 {
00178     if (h == NULL) return NULL;
00179 /*@-modfilesys@*/
00180 if (_hdr_debug)
00181 fprintf(stderr, "--> h  %p -- %d at %s:%u\n", h, h->nrefs, __FILE__, __LINE__);
00182 /*@=modfilesys@*/
00183     h->nrefs--;
00184     return NULL;
00185 }
00186 
00192 static /*@null@*/
00193 Header headerFree(/*@killref@*/ /*@null@*/ Header h)
00194         /*@modifies h @*/
00195 {
00196     (void) headerUnlink(h);
00197 
00198     /*@-usereleased@*/
00199     if (h == NULL || h->nrefs > 0)
00200         return NULL;    /* XXX return previous header? */
00201 
00202     if (h->index) {
00203         indexEntry entry = h->index;
00204         int i;
00205         for (i = 0; i < h->indexUsed; i++, entry++) {
00206             if ((h->flags & HEADERFLAG_ALLOCATED) && ENTRY_IS_REGION(entry)) {
00207                 if (entry->length > 0) {
00208                     int_32 * ei = entry->data;
00209                     if ((ei - 2) == h->blob) h->blob = _free(h->blob);
00210                     entry->data = NULL;
00211                 }
00212             } else if (!ENTRY_IN_REGION(entry)) {
00213                 entry->data = _free(entry->data);
00214             }
00215             entry->data = NULL;
00216         }
00217         h->index = _free(h->index);
00218     }
00219 
00220     /*@-refcounttrans@*/ h = _free(h); /*@=refcounttrans@*/
00221     return h;
00222     /*@=usereleased@*/
00223 }
00224 
00229 static
00230 Header headerNew(void)
00231         /*@*/
00232 {
00233     Header h = xcalloc(1, sizeof(*h));
00234 
00235 /*@-boundsread@*/
00236     /*@-assignexpose@*/
00237     h->hv = *hdrVec;            /* structure assignment */
00238     /*@=assignexpose@*/
00239 /*@=boundsread@*/
00240     h->blob = NULL;
00241     h->indexAlloced = INDEX_MALLOC_SIZE;
00242     h->indexUsed = 0;
00243     h->flags |= HEADERFLAG_SORTED;
00244 
00245     h->index = (h->indexAlloced
00246         ? xcalloc(h->indexAlloced, sizeof(*h->index))
00247         : NULL);
00248 
00249     h->nrefs = 0;
00250     /*@-globstate -observertrans @*/
00251     return headerLink(h);
00252     /*@=globstate =observertrans @*/
00253 }
00254 
00257 static int indexCmp(const void * avp, const void * bvp)
00258         /*@*/
00259 {
00260     /*@-castexpose@*/
00261     indexEntry ap = (indexEntry) avp, bp = (indexEntry) bvp;
00262     /*@=castexpose@*/
00263     return (ap->info.tag - bp->info.tag);
00264 }
00265 
00270 static
00271 void headerSort(Header h)
00272         /*@modifies h @*/
00273 {
00274     if (!(h->flags & HEADERFLAG_SORTED)) {
00275 /*@-boundsread@*/
00276         qsort(h->index, h->indexUsed, sizeof(*h->index), indexCmp);
00277 /*@=boundsread@*/
00278         h->flags |= HEADERFLAG_SORTED;
00279     }
00280 }
00281 
00284 static int offsetCmp(const void * avp, const void * bvp) /*@*/
00285 {
00286     /*@-castexpose@*/
00287     indexEntry ap = (indexEntry) avp, bp = (indexEntry) bvp;
00288     /*@=castexpose@*/
00289     int rc = (ap->info.offset - bp->info.offset);
00290 
00291     if (rc == 0) {
00292         /* Within a region, entries sort by address. Added drips sort by tag. */
00293         if (ap->info.offset < 0)
00294             rc = (((char *)ap->data) - ((char *)bp->data));
00295         else
00296             rc = (ap->info.tag - bp->info.tag);
00297     }
00298     return rc;
00299 }
00300 
00305 static
00306 void headerUnsort(Header h)
00307         /*@modifies h @*/
00308 {
00309 /*@-boundsread@*/
00310     qsort(h->index, h->indexUsed, sizeof(*h->index), offsetCmp);
00311 /*@=boundsread@*/
00312 }
00313 
00320 static
00321 unsigned int headerSizeof(/*@null@*/ Header h, enum hMagic magicp)
00322         /*@modifies h @*/
00323 {
00324     indexEntry entry;
00325     unsigned int size = 0;
00326     unsigned int pad = 0;
00327     int i;
00328 
00329     if (h == NULL)
00330         return size;
00331 
00332     headerSort(h);
00333 
00334     switch (magicp) {
00335     case HEADER_MAGIC_YES:
00336         size += sizeof(header_magic);
00337         break;
00338     case HEADER_MAGIC_NO:
00339         break;
00340     }
00341 
00342     /*@-sizeoftype@*/
00343     size += 2 * sizeof(int_32); /* count of index entries */
00344     /*@=sizeoftype@*/
00345 
00346     for (i = 0, entry = h->index; i < h->indexUsed; i++, entry++) {
00347         unsigned diff;
00348         int_32 type;
00349 
00350         /* Regions go in as is ... */
00351         if (ENTRY_IS_REGION(entry)) {
00352             size += entry->length;
00353             /* XXX Legacy regions do not include the region tag and data. */
00354             /*@-sizeoftype@*/
00355             if (i == 0 && (h->flags & HEADERFLAG_LEGACY))
00356                 size += sizeof(struct entryInfo_s) + entry->info.count;
00357             /*@=sizeoftype@*/
00358             continue;
00359         }
00360 
00361         /* ... and region elements are skipped. */
00362         if (entry->info.offset < 0)
00363             continue;
00364 
00365         /* Alignment */
00366         type = entry->info.type;
00367 /*@-boundsread@*/
00368         if (typeSizes[type] > 1) {
00369             diff = typeSizes[type] - (size % typeSizes[type]);
00370             if (diff != typeSizes[type]) {
00371                 size += diff;
00372                 pad += diff;
00373             }
00374         }
00375 /*@=boundsread@*/
00376 
00377         /*@-sizeoftype@*/
00378         size += sizeof(struct entryInfo_s) + entry->length;
00379         /*@=sizeoftype@*/
00380     }
00381 
00382     return size;
00383 }
00384 
00394 static int dataLength(int_32 type, hPTR_t p, int_32 count, int onDisk,
00395                 /*@null@*/ hPTR_t pend)
00396         /*@*/
00397 {
00398     const unsigned char * s = p;
00399     const unsigned char * se = pend;
00400     int length = 0;
00401 
00402     switch (type) {
00403     case RPM_STRING_TYPE:
00404         if (count != 1)
00405             return -1;
00406 /*@-boundsread@*/
00407         while (*s++) {
00408             if (se && s > se)
00409                 return -1;
00410             length++;
00411         }
00412 /*@=boundsread@*/
00413         length++;       /* count nul terminator too. */
00414         break;
00415 
00416     case RPM_STRING_ARRAY_TYPE:
00417     case RPM_I18NSTRING_TYPE:
00418         /* These are like RPM_STRING_TYPE, except they're *always* an array */
00419         /* Compute sum of length of all strings, including nul terminators */
00420 
00421         if (onDisk) {
00422             while (count--) {
00423                 length++;       /* count nul terminator too */
00424 /*@-boundsread@*/
00425                while (*s++) {
00426                     if (se && s > se)
00427                         return -1;
00428                     length++;
00429                 }
00430 /*@=boundsread@*/
00431             }
00432         } else {
00433             const char ** av = (const char **)p;
00434 /*@-boundsread@*/
00435             while (count--) {
00436                 /* add one for null termination */
00437                 length += strlen(*av++) + 1;
00438             }
00439 /*@=boundsread@*/
00440         }
00441         break;
00442 
00443     default:
00444 /*@-boundsread@*/
00445         if (typeSizes[type] == -1)
00446             return -1;
00447         length = typeSizes[(type & 0xf)] * count;
00448 /*@=boundsread@*/
00449         if (length < 0 || (se && (s + length) > se))
00450             return -1;
00451         break;
00452     }
00453 
00454     return length;
00455 }
00456 
00483 static int regionSwab(/*@null@*/ indexEntry entry, int il, int dl,
00484                 entryInfo pe,
00485                 unsigned char * dataStart,
00486                 /*@null@*/ const unsigned char * dataEnd,
00487                 int regionid)
00488         /*@modifies *entry, *dataStart @*/
00489 {
00490     unsigned char * tprev = NULL;
00491     unsigned char * t = NULL;
00492     int tdel = 0;
00493     int tl = dl;
00494     struct indexEntry_s ieprev;
00495 
00496     if (regionid > 0)
00497        return -1;
00498 /*@-boundswrite@*/
00499     memset(&ieprev, 0, sizeof(ieprev));
00500 /*@=boundswrite@*/
00501     for (; il > 0; il--, pe++) {
00502         struct indexEntry_s ie;
00503         int_32 type;
00504 
00505         ie.info.tag = ntohl(pe->tag);
00506         ie.info.type = ntohl(pe->type);
00507         ie.info.count = ntohl(pe->count);
00508         ie.info.offset = ntohl(pe->offset);
00509 
00510         if (hdrchkType(ie.info.type))
00511             return -1;
00512         if (hdrchkData(ie.info.count))
00513             return -1;
00514         if (hdrchkData(ie.info.offset))
00515             return -1;
00516 /*@-boundsread@*/
00517         if (hdrchkAlign(ie.info.type, ie.info.offset))
00518             return -1;
00519 /*@=boundsread@*/
00520 
00521         ie.data = t = dataStart + ie.info.offset;
00522         if (dataEnd && t >= dataEnd)
00523             return -1;
00524 
00525         ie.length = dataLength(ie.info.type, ie.data, ie.info.count, 1, dataEnd);
00526         if (ie.length < 0 || hdrchkData(ie.length))
00527             return -1;
00528 
00529         ie.rdlen = 0;
00530 
00531         if (entry) {
00532             ie.info.offset = regionid;
00533 /*@-boundswrite@*/
00534             *entry = ie;        /* structure assignment */
00535 /*@=boundswrite@*/
00536             entry++;
00537         }
00538 
00539         /* Alignment */
00540         type = ie.info.type;
00541 /*@-boundsread@*/
00542         if (typeSizes[type] > 1) {
00543             unsigned diff;
00544             diff = typeSizes[type] - (dl % typeSizes[type]);
00545             if (diff != typeSizes[type]) {
00546                 dl += diff;
00547                 if (ieprev.info.type == RPM_I18NSTRING_TYPE)
00548                     ieprev.length += diff;
00549             }
00550         }
00551 /*@=boundsread@*/
00552         tdel = (tprev ? (t - tprev) : 0);
00553         if (ieprev.info.type == RPM_I18NSTRING_TYPE)
00554             tdel = ieprev.length;
00555 
00556         if (ie.info.tag >= HEADER_I18NTABLE) {
00557             tprev = t;
00558         } else {
00559             tprev = dataStart;
00560             /* XXX HEADER_IMAGE tags don't include region sub-tag. */
00561             /*@-sizeoftype@*/
00562             if (ie.info.tag == HEADER_IMAGE)
00563                 tprev -= REGION_TAG_COUNT;
00564             /*@=sizeoftype@*/
00565         }
00566 
00567         /* Perform endian conversions */
00568         switch (ntohl(pe->type)) {
00569 /*@-bounds@*/
00570         case RPM_INT32_TYPE:
00571         {   int_32 * it = (int_32 *)t;
00572             for (; ie.info.count > 0; ie.info.count--, it += 1) {
00573                 if (dataEnd && ((unsigned char *)it) >= dataEnd)
00574                     return -1;
00575                 *it = htonl(*it);
00576             }
00577             t = (char *) it;
00578         }   /*@switchbreak@*/ break;
00579         case RPM_INT16_TYPE:
00580         {   int_16 * it = (int_16 *) t;
00581             for (; ie.info.count > 0; ie.info.count--, it += 1) {
00582                 if (dataEnd && ((unsigned char *)it) >= dataEnd)
00583                     return -1;
00584                 *it = htons(*it);
00585             }
00586             t = (char *) it;
00587         }   /*@switchbreak@*/ break;
00588 /*@=bounds@*/
00589         default:
00590             t += ie.length;
00591             /*@switchbreak@*/ break;
00592         }
00593 
00594         dl += ie.length;
00595         tl += tdel;
00596         ieprev = ie;    /* structure assignment */
00597 
00598     }
00599     tdel = (tprev ? (t - tprev) : 0);
00600     tl += tdel;
00601 
00602     /* XXX
00603      * There are two hacks here:
00604      *  1) tl is 16b (i.e. REGION_TAG_COUNT) short while doing headerReload().
00605      *  2) the 8/98 rpm bug with inserting i18n tags needs to use tl, not dl.
00606      */
00607     /*@-sizeoftype@*/
00608     if (tl+REGION_TAG_COUNT == dl)
00609         tl += REGION_TAG_COUNT;
00610     /*@=sizeoftype@*/
00611 
00612     return dl;
00613 }
00614 
00620 static /*@only@*/ /*@null@*/ void * doHeaderUnload(Header h,
00621                 /*@out@*/ int * lengthPtr)
00622         /*@modifies h, *lengthPtr @*/
00623         /*@requires maxSet(lengthPtr) >= 0 @*/
00624         /*@ensures maxRead(result) == (*lengthPtr) @*/
00625 {
00626     int_32 * ei = NULL;
00627     entryInfo pe;
00628     char * dataStart;
00629     char * te;
00630     unsigned pad;
00631     unsigned len;
00632     int_32 il = 0;
00633     int_32 dl = 0;
00634     indexEntry entry; 
00635     int_32 type;
00636     int i;
00637     int drlen, ndribbles;
00638     int driplen, ndrips;
00639     int legacy = 0;
00640 
00641     /* Sort entries by (offset,tag). */
00642     headerUnsort(h);
00643 
00644     /* Compute (il,dl) for all tags, including those deleted in region. */
00645     pad = 0;
00646     drlen = ndribbles = driplen = ndrips = 0;
00647     for (i = 0, entry = h->index; i < h->indexUsed; i++, entry++) {
00648         if (ENTRY_IS_REGION(entry)) {
00649             int_32 rdl = -entry->info.offset;   /* negative offset */
00650             int_32 ril = rdl/sizeof(*pe);
00651             int rid = entry->info.offset;
00652 
00653             il += ril;
00654             dl += entry->rdlen + entry->info.count;
00655             /* XXX Legacy regions do not include the region tag and data. */
00656             if (i == 0 && (h->flags & HEADERFLAG_LEGACY))
00657                 il += 1;
00658 
00659             /* Skip rest of entries in region, but account for dribbles. */
00660             for (; i < h->indexUsed && entry->info.offset <= rid+1; i++, entry++) {
00661                 if (entry->info.offset <= rid)
00662                     /*@innercontinue@*/ continue;
00663 
00664                 /* Alignment */
00665                 type = entry->info.type;
00666                 if (typeSizes[type] > 1) {
00667                     unsigned diff;
00668                     diff = typeSizes[type] - (dl % typeSizes[type]);
00669                     if (diff != typeSizes[type]) {
00670                         drlen += diff;
00671                         pad += diff;
00672                         dl += diff;
00673                     }
00674                 }
00675 
00676                 ndribbles++;
00677                 il++;
00678                 drlen += entry->length;
00679                 dl += entry->length;
00680             }
00681             i--;
00682             entry--;
00683             continue;
00684         }
00685 
00686         /* Ignore deleted drips. */
00687         if (entry->data == NULL || entry->length <= 0)
00688             continue;
00689 
00690         /* Alignment */
00691         type = entry->info.type;
00692         if (typeSizes[type] > 1) {
00693             unsigned diff;
00694             diff = typeSizes[type] - (dl % typeSizes[type]);
00695             if (diff != typeSizes[type]) {
00696                 driplen += diff;
00697                 pad += diff;
00698                 dl += diff;
00699             } else
00700                 diff = 0;
00701         }
00702 
00703         ndrips++;
00704         il++;
00705         driplen += entry->length;
00706         dl += entry->length;
00707     }
00708 
00709     /* Sanity checks on header intro. */
00710     if (hdrchkTags(il) || hdrchkData(dl))
00711         goto errxit;
00712 
00713     len = sizeof(il) + sizeof(dl) + (il * sizeof(*pe)) + dl;
00714 
00715 /*@-boundswrite@*/
00716     ei = xmalloc(len);
00717     ei[0] = htonl(il);
00718     ei[1] = htonl(dl);
00719 /*@=boundswrite@*/
00720 
00721     pe = (entryInfo) &ei[2];
00722     dataStart = te = (char *) (pe + il);
00723 
00724     pad = 0;
00725     for (i = 0, entry = h->index; i < h->indexUsed; i++, entry++) {
00726         const char * src;
00727 char *t;
00728         int count;
00729         int rdlen;
00730 
00731         if (entry->data == NULL || entry->length <= 0)
00732             continue;
00733 
00734 t = te;
00735         pe->tag = htonl(entry->info.tag);
00736         pe->type = htonl(entry->info.type);
00737         pe->count = htonl(entry->info.count);
00738 
00739         if (ENTRY_IS_REGION(entry)) {
00740             int_32 rdl = -entry->info.offset;   /* negative offset */
00741             int_32 ril = rdl/sizeof(*pe) + ndribbles;
00742             int rid = entry->info.offset;
00743 
00744             src = (char *)entry->data;
00745             rdlen = entry->rdlen;
00746 
00747             /* XXX Legacy regions do not include the region tag and data. */
00748             if (i == 0 && (h->flags & HEADERFLAG_LEGACY)) {
00749                 int_32 stei[4];
00750 
00751                 legacy = 1;
00752 /*@-boundswrite@*/
00753                 memcpy(pe+1, src, rdl);
00754                 memcpy(te, src + rdl, rdlen);
00755 /*@=boundswrite@*/
00756                 te += rdlen;
00757 
00758                 pe->offset = htonl(te - dataStart);
00759                 stei[0] = pe->tag;
00760                 stei[1] = pe->type;
00761                 stei[2] = htonl(-rdl-entry->info.count);
00762                 stei[3] = pe->count;
00763 /*@-boundswrite@*/
00764                 memcpy(te, stei, entry->info.count);
00765 /*@=boundswrite@*/
00766                 te += entry->info.count;
00767                 ril++;
00768                 rdlen += entry->info.count;
00769 
00770                 count = regionSwab(NULL, ril, 0, pe, t, NULL, 0);
00771                 if (count != rdlen)
00772                     goto errxit;
00773 
00774             } else {
00775 
00776 /*@-boundswrite@*/
00777                 memcpy(pe+1, src + sizeof(*pe), ((ril-1) * sizeof(*pe)));
00778                 memcpy(te, src + (ril * sizeof(*pe)), rdlen+entry->info.count+drlen);
00779 /*@=boundswrite@*/
00780                 te += rdlen;
00781                 {   /*@-castexpose@*/
00782                     entryInfo se = (entryInfo)src;
00783                     /*@=castexpose@*/
00784                     int off = ntohl(se->offset);
00785                     pe->offset = (off) ? htonl(te - dataStart) : htonl(off);
00786                 }
00787                 te += entry->info.count + drlen;
00788 
00789                 count = regionSwab(NULL, ril, 0, pe, t, NULL, 0);
00790                 if (count != (rdlen + entry->info.count + drlen))
00791                     goto errxit;
00792             }
00793 
00794             /* Skip rest of entries in region. */
00795             while (i < h->indexUsed && entry->info.offset <= rid+1) {
00796                 i++;
00797                 entry++;
00798             }
00799             i--;
00800             entry--;
00801             pe += ril;
00802             continue;
00803         }
00804 
00805         /* Ignore deleted drips. */
00806         if (entry->data == NULL || entry->length <= 0)
00807             continue;
00808 
00809         /* Alignment */
00810         type = entry->info.type;
00811         if (typeSizes[type] > 1) {
00812             unsigned diff;
00813             diff = typeSizes[type] - ((te - dataStart) % typeSizes[type]);
00814             if (diff != typeSizes[type]) {
00815 /*@-boundswrite@*/
00816                 memset(te, 0, diff);
00817 /*@=boundswrite@*/
00818                 te += diff;
00819                 pad += diff;
00820             }
00821         }
00822 
00823         pe->offset = htonl(te - dataStart);
00824 
00825         /* copy data w/ endian conversions */
00826 /*@-boundswrite@*/
00827         switch (entry->info.type) {
00828         case RPM_INT32_TYPE:
00829             count = entry->info.count;
00830             src = entry->data;
00831             while (count--) {
00832                 *((int_32 *)te) = htonl(*((int_32 *)src));
00833                 /*@-sizeoftype@*/
00834                 te += sizeof(int_32);
00835                 src += sizeof(int_32);
00836                 /*@=sizeoftype@*/
00837             }
00838             /*@switchbreak@*/ break;
00839 
00840         case RPM_INT16_TYPE:
00841             count = entry->info.count;
00842             src = entry->data;
00843             while (count--) {
00844                 *((int_16 *)te) = htons(*((int_16 *)src));
00845                 /*@-sizeoftype@*/
00846                 te += sizeof(int_16);
00847                 src += sizeof(int_16);
00848                 /*@=sizeoftype@*/
00849             }
00850             /*@switchbreak@*/ break;
00851 
00852         default:
00853             memcpy(te, entry->data, entry->length);
00854             te += entry->length;
00855             /*@switchbreak@*/ break;
00856         }
00857 /*@=boundswrite@*/
00858         pe++;
00859     }
00860    
00861     /* Insure that there are no memcpy underruns/overruns. */
00862     if (((char *)pe) != dataStart)
00863         goto errxit;
00864     if ((((char *)ei)+len) != te)
00865         goto errxit;
00866 
00867     if (lengthPtr)
00868         *lengthPtr = len;
00869 
00870     h->flags &= ~HEADERFLAG_SORTED;
00871     headerSort(h);
00872 
00873     return (void *) ei;
00874 
00875 errxit:
00876     /*@-usereleased@*/
00877     ei = _free(ei);
00878     /*@=usereleased@*/
00879     return (void *) ei;
00880 }
00881 
00887 static /*@only@*/ /*@null@*/
00888 void * headerUnload(Header h)
00889         /*@modifies h @*/
00890 {
00891     int length;
00892 /*@-boundswrite@*/
00893     void * uh = doHeaderUnload(h, &length);
00894 /*@=boundswrite@*/
00895     return uh;
00896 }
00897 
00905 static /*@null@*/
00906 indexEntry findEntry(/*@null@*/ Header h, int_32 tag, int_32 type)
00907         /*@modifies h @*/
00908 {
00909     indexEntry entry, entry2, last;
00910     struct indexEntry_s key;
00911 
00912     if (h == NULL) return NULL;
00913     if (!(h->flags & HEADERFLAG_SORTED)) headerSort(h);
00914 
00915     key.info.tag = tag;
00916 
00917 /*@-boundswrite@*/
00918     entry2 = entry = 
00919         bsearch(&key, h->index, h->indexUsed, sizeof(*h->index), indexCmp);
00920 /*@=boundswrite@*/
00921     if (entry == NULL)
00922         return NULL;
00923 
00924     if (type == RPM_NULL_TYPE)
00925         return entry;
00926 
00927     /* look backwards */
00928     while (entry->info.tag == tag && entry->info.type != type &&
00929            entry > h->index) entry--;
00930 
00931     if (entry->info.tag == tag && entry->info.type == type)
00932         return entry;
00933 
00934     last = h->index + h->indexUsed;
00935     /*@-usereleased@*/ /* FIX: entry2 = entry. Code looks bogus as well. */
00936     while (entry2->info.tag == tag && entry2->info.type != type &&
00937            entry2 < last) entry2++;
00938     /*@=usereleased@*/
00939 
00940     if (entry->info.tag == tag && entry->info.type == type)
00941         return entry;
00942 
00943     return NULL;
00944 }
00945 
00955 static
00956 int headerRemoveEntry(Header h, int_32 tag)
00957         /*@modifies h @*/
00958 {
00959     indexEntry last = h->index + h->indexUsed;
00960     indexEntry entry, first;
00961     int ne;
00962 
00963     entry = findEntry(h, tag, RPM_NULL_TYPE);
00964     if (!entry) return 1;
00965 
00966     /* Make sure entry points to the first occurence of this tag. */
00967     while (entry > h->index && (entry - 1)->info.tag == tag)  
00968         entry--;
00969 
00970     /* Free data for tags being removed. */
00971     for (first = entry; first < last; first++) {
00972         void * data;
00973         if (first->info.tag != tag)
00974             break;
00975         data = first->data;
00976         first->data = NULL;
00977         first->length = 0;
00978         if (ENTRY_IN_REGION(first))
00979             continue;
00980         data = _free(data);
00981     }
00982 
00983     ne = (first - entry);
00984     if (ne > 0) {
00985         h->indexUsed -= ne;
00986         ne = last - first;
00987 /*@-boundswrite@*/
00988         if (ne > 0)
00989             memmove(entry, first, (ne * sizeof(*entry)));
00990 /*@=boundswrite@*/
00991     }
00992 
00993     return 0;
00994 }
00995 
01001 static /*@null@*/
01002 Header headerLoad(/*@kept@*/ void * uh)
01003         /*@modifies uh @*/
01004 {
01005     int_32 * ei = (int_32 *) uh;
01006     int_32 il = ntohl(ei[0]);           /* index length */
01007     int_32 dl = ntohl(ei[1]);           /* data length */
01008     /*@-sizeoftype@*/
01009     size_t pvlen = sizeof(il) + sizeof(dl) +
01010                (il * sizeof(struct entryInfo_s)) + dl;
01011     /*@=sizeoftype@*/
01012     void * pv = uh;
01013     Header h = NULL;
01014     entryInfo pe;
01015     unsigned char * dataStart;
01016     unsigned char * dataEnd;
01017     indexEntry entry; 
01018     int rdlen;
01019     int i;
01020 
01021     /* Sanity checks on header intro. */
01022     if (hdrchkTags(il) || hdrchkData(dl))
01023         goto errxit;
01024 
01025     ei = (int_32 *) pv;
01026     /*@-castexpose@*/
01027     pe = (entryInfo) &ei[2];
01028     /*@=castexpose@*/
01029     dataStart = (unsigned char *) (pe + il);
01030     dataEnd = dataStart + dl;
01031 
01032     h = xcalloc(1, sizeof(*h));
01033     /*@-assignexpose@*/
01034     h->hv = *hdrVec;            /* structure assignment */
01035     /*@=assignexpose@*/
01036     /*@-assignexpose -kepttrans@*/
01037     h->blob = uh;
01038     /*@=assignexpose =kepttrans@*/
01039     h->indexAlloced = il + 1;
01040     h->indexUsed = il;
01041     h->index = xcalloc(h->indexAlloced, sizeof(*h->index));
01042     h->flags |= HEADERFLAG_SORTED;
01043     h->nrefs = 0;
01044     h = headerLink(h);
01045 
01046     /*
01047      * XXX XFree86-libs, ash, and pdksh from Red Hat 5.2 have bogus
01048      * %verifyscript tag that needs to be diddled.
01049      */
01050     if (ntohl(pe->tag) == 15 &&
01051         ntohl(pe->type) == RPM_STRING_TYPE &&
01052         ntohl(pe->count) == 1)
01053     {
01054         pe->tag = htonl(1079);
01055     }
01056 
01057     entry = h->index;
01058     i = 0;
01059     if (!(htonl(pe->tag) < HEADER_I18NTABLE)) {
01060         h->flags |= HEADERFLAG_LEGACY;
01061         entry->info.type = REGION_TAG_TYPE;
01062         entry->info.tag = HEADER_IMAGE;
01063         /*@-sizeoftype@*/
01064         entry->info.count = REGION_TAG_COUNT;
01065         /*@=sizeoftype@*/
01066         entry->info.offset = ((unsigned char *)pe - dataStart); /* negative offset */
01067 
01068         /*@-assignexpose@*/
01069         entry->data = pe;
01070         /*@=assignexpose@*/
01071         entry->length = pvlen - sizeof(il) - sizeof(dl);
01072         rdlen = regionSwab(entry+1, il, 0, pe, dataStart, dataEnd, entry->info.offset);
01073         if (rdlen != dl)
01074             goto errxit;
01075         entry->rdlen = rdlen;
01076         entry++;
01077         h->indexUsed++;
01078     } else {
01079         int_32 rdl;
01080         int_32 ril;
01081 
01082         h->flags &= ~HEADERFLAG_LEGACY;
01083 
01084         entry->info.type = htonl(pe->type);
01085         entry->info.count = htonl(pe->count);
01086         entry->info.tag = htonl(pe->tag);
01087 
01088         if (!ENTRY_IS_REGION(entry))
01089             goto errxit;
01090         if (entry->info.type != REGION_TAG_TYPE)
01091             goto errxit;
01092         if (entry->info.count != REGION_TAG_COUNT)
01093             goto errxit;
01094 
01095         {   int off = ntohl(pe->offset);
01096 
01097             if (hdrchkData(off))
01098                 goto errxit;
01099             if (off) {
01100 /*@-sizeoftype@*/
01101                 size_t nb = REGION_TAG_COUNT;
01102 /*@=sizeoftype@*/
01103                 int_32 * stei;
01104                 if (dataStart + off + nb > dataEnd)
01105                     goto errxit;
01106                 stei = memcpy(alloca(nb), dataStart + off, nb);
01107                 rdl = -ntohl(stei[2]);  /* negative offset */
01108                 ril = rdl/sizeof(*pe);
01109                 if (hdrchkTags(ril) || hdrchkData(rdl))
01110                     goto errxit;
01111             } else {
01112                 ril = il;
01113                 /*@-sizeoftype@*/
01114                 rdl = (ril * sizeof(struct entryInfo_s));
01115                 /*@=sizeoftype@*/
01116                 entry->info.tag = HEADER_IMAGE;
01117             }
01118         }
01119         entry->info.offset = -rdl;      /* negative offset */
01120 
01121         /*@-assignexpose@*/
01122         entry->data = pe;
01123         /*@=assignexpose@*/
01124         entry->length = pvlen - sizeof(il) - sizeof(dl);
01125         rdlen = regionSwab(entry+1, ril-1, 0, pe+1, dataStart, dataEnd, entry->info.offset);
01126         if (rdlen < 0)
01127             goto errxit;
01128         entry->rdlen = rdlen;
01129 
01130         if (ril < h->indexUsed) {
01131             indexEntry newEntry = entry + ril;
01132             int ne = (h->indexUsed - ril);
01133             int rid = entry->info.offset+1;
01134 
01135             /* Load dribble entries from region. */
01136             rdlen = regionSwab(newEntry, ne, rdlen, pe+ril,
01137                                 dataStart, dataEnd, rid);
01138             if (rdlen < 0)
01139                 goto errxit;
01140 
01141           { indexEntry firstEntry = newEntry;
01142             int save = h->indexUsed;
01143             int j;
01144 
01145             /* Dribble entries replace duplicate region entries. */
01146             h->indexUsed -= ne;
01147             for (j = 0; j < ne; j++, newEntry++) {
01148                 (void) headerRemoveEntry(h, newEntry->info.tag);
01149                 if (newEntry->info.tag == HEADER_BASENAMES)
01150                     (void) headerRemoveEntry(h, HEADER_OLDFILENAMES);
01151             }
01152 
01153             /* If any duplicate entries were replaced, move new entries down. */
01154 /*@-boundswrite@*/
01155             if (h->indexUsed < (save - ne)) {
01156                 memmove(h->index + h->indexUsed, firstEntry,
01157                         (ne * sizeof(*entry)));
01158             }
01159 /*@=boundswrite@*/
01160             h->indexUsed += ne;
01161           }
01162         }
01163 
01164         rdlen += REGION_TAG_COUNT;
01165 
01166         if (rdlen != dl)
01167             goto errxit;
01168     }
01169 
01170     h->flags &= ~HEADERFLAG_SORTED;
01171     headerSort(h);
01172 
01173     /*@-globstate -observertrans @*/
01174     return h;
01175     /*@=globstate =observertrans @*/
01176 
01177 errxit:
01178     /*@-usereleased@*/
01179     if (h) {
01180         h->index = _free(h->index);
01181         /*@-refcounttrans@*/
01182         h = _free(h);
01183         /*@=refcounttrans@*/
01184     }
01185     /*@=usereleased@*/
01186     /*@-refcounttrans -globstate@*/
01187     return h;
01188     /*@=refcounttrans =globstate@*/
01189 }
01190 
01198 static /*@null@*/
01199 Header headerReload(/*@only@*/ Header h, int tag)
01200         /*@modifies h @*/
01201 {
01202     Header nh;
01203     int length;
01204     /*@-onlytrans@*/
01205 /*@-boundswrite@*/
01206     void * uh = doHeaderUnload(h, &length);
01207 /*@=boundswrite@*/
01208 
01209     h = headerFree(h);
01210     /*@=onlytrans@*/
01211     if (uh == NULL)
01212         return NULL;
01213     nh = headerLoad(uh);
01214     if (nh == NULL) {
01215         uh = _free(uh);
01216         return NULL;
01217     }
01218     if (nh->flags & HEADERFLAG_ALLOCATED)
01219         uh = _free(uh);
01220     nh->flags |= HEADERFLAG_ALLOCATED;
01221     if (ENTRY_IS_REGION(nh->index)) {
01222 /*@-boundswrite@*/
01223         if (tag == HEADER_SIGNATURES || tag == HEADER_IMMUTABLE)
01224             nh->index[0].info.tag = tag;
01225 /*@=boundswrite@*/
01226     }
01227     return nh;
01228 }
01229 
01235 static /*@null@*/
01236 Header headerCopyLoad(const void * uh)
01237         /*@*/
01238 {
01239     int_32 * ei = (int_32 *) uh;
01240 /*@-boundsread@*/
01241     int_32 il = ntohl(ei[0]);           /* index length */
01242     int_32 dl = ntohl(ei[1]);           /* data length */
01243 /*@=boundsread@*/
01244     /*@-sizeoftype@*/
01245     size_t pvlen = sizeof(il) + sizeof(dl) +
01246                         (il * sizeof(struct entryInfo_s)) + dl;
01247     /*@=sizeoftype@*/
01248     void * nuh = NULL;
01249     Header h = NULL;
01250 
01251     /* Sanity checks on header intro. */
01252     /*@-branchstate@*/
01253     if (!(hdrchkTags(il) || hdrchkData(dl)) && pvlen < headerMaxbytes) {
01254 /*@-boundsread@*/
01255         nuh = memcpy(xmalloc(pvlen), uh, pvlen);
01256 /*@=boundsread@*/
01257         if ((h = headerLoad(nuh)) != NULL)
01258             h->flags |= HEADERFLAG_ALLOCATED;
01259     }
01260     /*@=branchstate@*/
01261     /*@-branchstate@*/
01262     if (h == NULL)
01263         nuh = _free(nuh);
01264     /*@=branchstate@*/
01265     return h;
01266 }
01267 
01274 static /*@null@*/
01275 Header headerRead(FD_t fd, enum hMagic magicp)
01276         /*@modifies fd @*/
01277 {
01278     int_32 block[4];
01279     int_32 reserved;
01280     int_32 * ei = NULL;
01281     int_32 il;
01282     int_32 dl;
01283     int_32 magic;
01284     Header h = NULL;
01285     size_t len;
01286     int i;
01287 
01288     memset(block, 0, sizeof(block));
01289     i = 2;
01290     if (magicp == HEADER_MAGIC_YES)
01291         i += 2;
01292 
01293     /*@-type@*/ /* FIX: cast? */
01294     if (timedRead(fd, (char *)block, i*sizeof(*block)) != (i * sizeof(*block)))
01295         goto exit;
01296     /*@=type@*/
01297 
01298     i = 0;
01299 
01300 /*@-boundsread@*/
01301     if (magicp == HEADER_MAGIC_YES) {
01302         magic = block[i++];
01303         if (memcmp(&magic, header_magic, sizeof(magic)))
01304             goto exit;
01305         reserved = block[i++];
01306     }
01307     
01308     il = ntohl(block[i]);       i++;
01309     dl = ntohl(block[i]);       i++;
01310 /*@=boundsread@*/
01311 
01312     /*@-sizeoftype@*/
01313     len = sizeof(il) + sizeof(dl) + (il * sizeof(struct entryInfo_s)) + dl;
01314     /*@=sizeoftype@*/
01315 
01316     /* Sanity checks on header intro. */
01317     if (hdrchkTags(il) || hdrchkData(dl) || len > headerMaxbytes)
01318         goto exit;
01319 
01320 /*@-boundswrite@*/
01321     ei = xmalloc(len);
01322     ei[0] = htonl(il);
01323     ei[1] = htonl(dl);
01324     len -= sizeof(il) + sizeof(dl);
01325 /*@=boundswrite@*/
01326 
01327 /*@-boundsread@*/
01328     /*@-type@*/ /* FIX: cast? */
01329     if (timedRead(fd, (char *)&ei[2], len) != len)
01330         goto exit;
01331     /*@=type@*/
01332 /*@=boundsread@*/
01333     
01334     h = headerLoad(ei);
01335 
01336 exit:
01337     if (h) {
01338         if (h->flags & HEADERFLAG_ALLOCATED)
01339             ei = _free(ei);
01340         h->flags |= HEADERFLAG_ALLOCATED;
01341     } else if (ei)
01342         ei = _free(ei);
01343     /*@-mustmod@*/      /* FIX: timedRead macro obscures annotation */
01344     return h;
01345     /*@-mustmod@*/
01346 }
01347 
01355 static
01356 int headerWrite(FD_t fd, /*@null@*/ Header h, enum hMagic magicp)
01357         /*@globals fileSystem @*/
01358         /*@modifies fd, h, fileSystem @*/
01359 {
01360     ssize_t nb;
01361     int length;
01362     const void * uh;
01363 
01364     if (h == NULL)
01365         return 1;
01366 /*@-boundswrite@*/
01367     uh = doHeaderUnload(h, &length);
01368 /*@=boundswrite@*/
01369     if (uh == NULL)
01370         return 1;
01371     switch (magicp) {
01372     case HEADER_MAGIC_YES:
01373 /*@-boundsread@*/
01374         /*@-sizeoftype@*/
01375         nb = Fwrite(header_magic, sizeof(char), sizeof(header_magic), fd);
01376         /*@=sizeoftype@*/
01377 /*@=boundsread@*/
01378         if (nb != sizeof(header_magic))
01379             goto exit;
01380         break;
01381     case HEADER_MAGIC_NO:
01382         break;
01383     }
01384 
01385     /*@-sizeoftype@*/
01386     nb = Fwrite(uh, sizeof(char), length, fd);
01387     /*@=sizeoftype@*/
01388 
01389 exit:
01390     uh = _free(uh);
01391     return (nb == length ? 0 : 1);
01392 }
01393 
01400 static
01401 int headerIsEntry(/*@null@*/Header h, int_32 tag)
01402         /*@*/
01403 {
01404     /*@-mods@*/         /*@ FIX: h modified by sort. */
01405     return (findEntry(h, tag, RPM_NULL_TYPE) ? 1 : 0);
01406     /*@=mods@*/ 
01407 }
01408 
01419 static int copyEntry(const indexEntry entry,
01420                 /*@null@*/ /*@out@*/ hTYP_t type,
01421                 /*@null@*/ /*@out@*/ hPTR_t * p,
01422                 /*@null@*/ /*@out@*/ hCNT_t c,
01423                 int minMem)
01424         /*@modifies *type, *p, *c @*/
01425         /*@requires maxSet(type) >= 0 /\ maxSet(p) >= 0 /\ maxSet(c) >= 0 @*/
01426 {
01427     int_32 count = entry->info.count;
01428     int rc = 1;         /* XXX 1 on success. */
01429 
01430     if (p)
01431     switch (entry->info.type) {
01432     case RPM_BIN_TYPE:
01433         /*
01434          * XXX This only works for
01435          * XXX  "sealed" HEADER_IMMUTABLE/HEADER_SIGNATURES/HEADER_IMAGE.
01436          * XXX This will *not* work for unsealed legacy HEADER_IMAGE (i.e.
01437          * XXX a legacy header freshly read, but not yet unloaded to the rpmdb).
01438          */
01439         if (ENTRY_IS_REGION(entry)) {
01440             int_32 * ei = ((int_32 *)entry->data) - 2;
01441             /*@-castexpose@*/
01442             entryInfo pe = (entryInfo) (ei + 2);
01443             /*@=castexpose@*/
01444 /*@-boundsread@*/
01445             char * dataStart = (char *) (pe + ntohl(ei[0]));
01446 /*@=boundsread@*/
01447             int_32 rdl = -entry->info.offset;   /* negative offset */
01448             int_32 ril = rdl/sizeof(*pe);
01449 
01450             /*@-sizeoftype@*/
01451             rdl = entry->rdlen;
01452             count = 2 * sizeof(*ei) + (ril * sizeof(*pe)) + rdl;
01453             if (entry->info.tag == HEADER_IMAGE) {
01454                 ril -= 1;
01455                 pe += 1;
01456             } else {
01457                 count += REGION_TAG_COUNT;
01458                 rdl += REGION_TAG_COUNT;
01459             }
01460 
01461 /*@-bounds@*/
01462             *p = xmalloc(count);
01463             ei = (int_32 *) *p;
01464             ei[0] = htonl(ril);
01465             ei[1] = htonl(rdl);
01466 
01467             /*@-castexpose@*/
01468             pe = (entryInfo) memcpy(ei + 2, pe, (ril * sizeof(*pe)));
01469             /*@=castexpose@*/
01470 
01471             dataStart = (char *) memcpy(pe + ril, dataStart, rdl);
01472             /*@=sizeoftype@*/
01473 /*@=bounds@*/
01474 
01475             rc = regionSwab(NULL, ril, 0, pe, dataStart, NULL, 0);
01476             /* XXX 1 on success. */
01477             rc = (rc < 0) ? 0 : 1;
01478         } else {
01479             count = entry->length;
01480             *p = (!minMem
01481                 ? memcpy(xmalloc(count), entry->data, count)
01482                 : entry->data);
01483         }
01484         break;
01485     case RPM_STRING_TYPE:
01486         if (count == 1) {
01487             *p = entry->data;
01488             break;
01489         }
01490         /*@fallthrough@*/
01491     case RPM_STRING_ARRAY_TYPE:
01492     case RPM_I18NSTRING_TYPE:
01493     {   const char ** ptrEntry;
01494         /*@-sizeoftype@*/
01495         int tableSize = count * sizeof(char *);
01496         /*@=sizeoftype@*/
01497         char * t;
01498         int i;
01499 
01500 /*@-bounds@*/
01501         /*@-mods@*/
01502         if (minMem) {
01503             *p = xmalloc(tableSize);
01504             ptrEntry = (const char **) *p;
01505             t = entry->data;
01506         } else {
01507             t = xmalloc(tableSize + entry->length);
01508             *p = (void *)t;
01509             ptrEntry = (const char **) *p;
01510             t += tableSize;
01511             memcpy(t, entry->data, entry->length);
01512         }
01513         /*@=mods@*/
01514 /*@=bounds@*/
01515         for (i = 0; i < count; i++) {
01516 /*@-boundswrite@*/
01517             *ptrEntry++ = t;
01518 /*@=boundswrite@*/
01519             t = strchr(t, 0);
01520             t++;
01521         }
01522     }   break;
01523 
01524     default:
01525         *p = entry->data;
01526         break;
01527     }
01528     if (type) *type = entry->info.type;
01529     if (c) *c = count;
01530     return rc;
01531 }
01532 
01551 static int headerMatchLocale(const char *td, const char *l, const char *le)
01552         /*@*/
01553 {
01554     const char *fe;
01555 
01556 
01557 #if 0
01558   { const char *s, *ll, *CC, *EE, *dd;
01559     char *lbuf, *t.
01560 
01561     /* Copy the buffer and parse out components on the fly. */
01562     lbuf = alloca(le - l + 1);
01563     for (s = l, ll = t = lbuf; *s; s++, t++) {
01564         switch (*s) {
01565         case '_':
01566             *t = '\0';
01567             CC = t + 1;
01568             break;
01569         case '.':
01570             *t = '\0';
01571             EE = t + 1;
01572             break;
01573         case '@':
01574             *t = '\0';
01575             dd = t + 1;
01576             break;
01577         default:
01578             *t = *s;
01579             break;
01580         }
01581     }
01582 
01583     if (ll)     /* ISO language should be lower case */
01584         for (t = ll; *t; t++)   *t = tolower(*t);
01585     if (CC)     /* ISO country code should be upper case */
01586         for (t = CC; *t; t++)   *t = toupper(*t);
01587 
01588     /* There are a total of 16 cases to attempt to match. */
01589   }
01590 #endif
01591 
01592     /* First try a complete match. */
01593     if (strlen(td) == (le-l) && !strncmp(td, l, (le - l)))
01594         return 1;
01595 
01596     /* Next, try stripping optional dialect and matching.  */
01597     for (fe = l; fe < le && *fe != '@'; fe++)
01598         {};
01599     if (fe < le && !strncmp(td, l, (fe - l)))
01600         return 1;
01601 
01602     /* Next, try stripping optional codeset and matching.  */
01603     for (fe = l; fe < le && *fe != '.'; fe++)
01604         {};
01605     if (fe < le && !strncmp(td, l, (fe - l)))
01606         return 1;
01607 
01608     /* Finally, try stripping optional country code and matching. */
01609     for (fe = l; fe < le && *fe != '_'; fe++)
01610         {};
01611     if (fe < le && !strncmp(td, l, (fe - l)))
01612         return 1;
01613 
01614     return 0;
01615 }
01616 
01623 /*@dependent@*/ /*@exposed@*/ static char *
01624 headerFindI18NString(Header h, indexEntry entry)
01625         /*@*/
01626 {
01627     const char *lang, *l, *le;
01628     indexEntry table;
01629 
01630     /* XXX Drepper sez' this is the order. */
01631     if ((lang = getenv("LANGUAGE")) == NULL &&
01632         (lang = getenv("LC_ALL")) == NULL &&
01633         (lang = getenv("LC_MESSAGES")) == NULL &&
01634         (lang = getenv("LANG")) == NULL)
01635             return entry->data;
01636     
01637     /*@-mods@*/
01638     if ((table = findEntry(h, HEADER_I18NTABLE, RPM_STRING_ARRAY_TYPE)) == NULL)
01639         return entry->data;
01640     /*@=mods@*/
01641 
01642 /*@-boundsread@*/
01643     for (l = lang; *l != '\0'; l = le) {
01644         const char *td;
01645         char *ed;
01646         int langNum;
01647 
01648         while (*l && *l == ':')                 /* skip leading colons */
01649             l++;
01650         if (*l == '\0')
01651             break;
01652         for (le = l; *le && *le != ':'; le++)   /* find end of this locale */
01653             {};
01654 
01655         /* For each entry in the header ... */
01656         for (langNum = 0, td = table->data, ed = entry->data;
01657              langNum < entry->info.count;
01658              langNum++, td += strlen(td) + 1, ed += strlen(ed) + 1) {
01659 
01660                 if (headerMatchLocale(td, l, le))
01661                     return ed;
01662 
01663         }
01664     }
01665 /*@=boundsread@*/
01666 
01667     return entry->data;
01668 }
01669 
01680 static int intGetEntry(Header h, int_32 tag,
01681                 /*@null@*/ /*@out@*/ hTAG_t type,
01682                 /*@null@*/ /*@out@*/ hPTR_t * p,
01683                 /*@null@*/ /*@out@*/ hCNT_t c,
01684                 int minMem)
01685         /*@modifies *type, *p, *c @*/
01686         /*@requires maxSet(type) >= 0 /\ maxSet(p) >= 0 /\ maxSet(c) >= 0 @*/
01687 {
01688     indexEntry entry;
01689     int rc;
01690 
01691     /* First find the tag */
01692     /*@-mods@*/         /*@ FIX: h modified by sort. */
01693     entry = findEntry(h, tag, RPM_NULL_TYPE);
01694     /*@mods@*/
01695     if (entry == NULL) {
01696         if (type) type = 0;
01697         if (p) *p = NULL;
01698         if (c) *c = 0;
01699         return 0;
01700     }
01701 
01702     switch (entry->info.type) {
01703     case RPM_I18NSTRING_TYPE:
01704         rc = 1;
01705         if (type) *type = RPM_STRING_TYPE;
01706         if (c) *c = 1;
01707         /*@-dependenttrans@*/
01708         if (p) *p = headerFindI18NString(h, entry);
01709         /*@=dependenttrans@*/
01710         break;
01711     default:
01712         rc = copyEntry(entry, type, p, c, minMem);
01713         break;
01714     }
01715 
01716     /* XXX 1 on success */
01717     return ((rc == 1) ? 1 : 0);
01718 }
01719 
01727 static /*@null@*/ void * headerFreeTag(/*@unused@*/ Header h,
01728                 /*@only@*/ /*@null@*/ const void * data, rpmTagType type)
01729         /*@modifies data @*/
01730 {
01731     if (data) {
01732         /*@-branchstate@*/
01733         if (type == -1 ||
01734             type == RPM_STRING_ARRAY_TYPE ||
01735             type == RPM_I18NSTRING_TYPE ||
01736             type == RPM_BIN_TYPE)
01737                 data = _free(data);
01738         /*@=branchstate@*/
01739     }
01740     return NULL;
01741 }
01742 
01756 static
01757 int headerGetEntry(Header h, int_32 tag,
01758                         /*@null@*/ /*@out@*/ hTYP_t type,
01759                         /*@null@*/ /*@out@*/ void ** p,
01760                         /*@null@*/ /*@out@*/ hCNT_t c)
01761         /*@modifies *type, *p, *c @*/
01762         /*@requires maxSet(type) >= 0 /\ maxSet(p) >= 0 /\ maxSet(c) >= 0 @*/
01763 {
01764     return intGetEntry(h, tag, type, (hPTR_t *)p, c, 0);
01765 }
01766 
01779 static
01780 int headerGetEntryMinMemory(Header h, int_32 tag,
01781                         /*@null@*/ /*@out@*/ hTYP_t type,
01782                         /*@null@*/ /*@out@*/ hPTR_t * p,
01783                         /*@null@*/ /*@out@*/ hCNT_t c)
01784         /*@modifies *type, *p, *c @*/
01785         /*@requires maxSet(type) >= 0 /\ maxSet(p) >= 0 /\ maxSet(c) >= 0 @*/
01786 {
01787     return intGetEntry(h, tag, type, p, c, 1);
01788 }
01789 
01790 int headerGetRawEntry(Header h, int_32 tag, int_32 * type, hPTR_t * p,
01791                 int_32 * c)
01792 {
01793     indexEntry entry;
01794     int rc;
01795 
01796     if (p == NULL) return headerIsEntry(h, tag);
01797 
01798     /* First find the tag */
01799     /*@-mods@*/         /*@ FIX: h modified by sort. */
01800     entry = findEntry(h, tag, RPM_NULL_TYPE);
01801     /*@=mods@*/
01802     if (!entry) {
01803         if (p) *p = NULL;
01804         if (c) *c = 0;
01805         return 0;
01806     }
01807 
01808     rc = copyEntry(entry, type, p, c, 0);
01809 
01810     /* XXX 1 on success */
01811     return ((rc == 1) ? 1 : 0);
01812 }
01813 
01816 static void copyData(int_32 type, /*@out@*/ void * dstPtr, const void * srcPtr,
01817                 int_32 cnt, int dataLength)
01818         /*@modifies *dstPtr @*/
01819 {
01820     switch (type) {
01821     case RPM_STRING_ARRAY_TYPE:
01822     case RPM_I18NSTRING_TYPE:
01823     {   const char ** av = (const char **) srcPtr;
01824         char * t = dstPtr;
01825 
01826 /*@-bounds@*/
01827         while (cnt-- > 0 && dataLength > 0) {
01828             const char * s;
01829             if ((s = *av++) == NULL)
01830                 continue;
01831             do {
01832                 *t++ = *s++;
01833             } while (s[-1] && --dataLength > 0);
01834         }
01835 /*@=bounds@*/
01836     }   break;
01837 
01838     default:
01839 /*@-boundswrite@*/
01840         memmove(dstPtr, srcPtr, dataLength);
01841 /*@=boundswrite@*/
01842         break;
01843     }
01844 }
01845 
01854 /*@null@*/
01855 static void *
01856 grabData(int_32 type, hPTR_t p, int_32 c, /*@out@*/ int * lengthPtr)
01857         /*@modifies *lengthPtr @*/
01858         /*@requires maxSet(lengthPtr) >= 0 @*/
01859 {
01860     void * data = NULL;
01861     int length;
01862 
01863     length = dataLength(type, p, c, 0, NULL);
01864 /*@-branchstate@*/
01865     if (length > 0) {
01866         data = xmalloc(length);
01867         copyData(type, data, p, c, length);
01868     }
01869 /*@=branchstate@*/
01870 
01871     if (lengthPtr)
01872         *lengthPtr = length;
01873     return data;
01874 }
01875 
01890 static
01891 int headerAddEntry(Header h, int_32 tag, int_32 type, const void * p, int_32 c)
01892         /*@modifies h @*/
01893 {
01894     indexEntry entry;
01895     void * data;
01896     int length;
01897 
01898     /* Count must always be >= 1 for headerAddEntry. */
01899     if (c <= 0)
01900         return 0;
01901 
01902     if (hdrchkType(type))
01903         return 0;
01904     if (hdrchkData(c))
01905         return 0;
01906 
01907     length = 0;
01908 /*@-boundswrite@*/
01909     data = grabData(type, p, c, &length);
01910 /*@=boundswrite@*/
01911     if (data == NULL || length <= 0)
01912         return 0;
01913 
01914     /* Allocate more index space if necessary */
01915     if (h->indexUsed == h->indexAlloced) {
01916         h->indexAlloced += INDEX_MALLOC_SIZE;
01917         h->index = xrealloc(h->index, h->indexAlloced * sizeof(*h->index));
01918     }
01919 
01920     /* Fill in the index */
01921     entry = h->index + h->indexUsed;
01922     entry->info.tag = tag;
01923     entry->info.type = type;
01924     entry->info.count = c;
01925     entry->info.offset = 0;
01926     entry->data = data;
01927     entry->length = length;
01928 
01929 /*@-boundsread@*/
01930     if (h->indexUsed > 0 && tag < h->index[h->indexUsed-1].info.tag)
01931         h->flags &= ~HEADERFLAG_SORTED;
01932 /*@=boundsread@*/
01933     h->indexUsed++;
01934 
01935     return 1;
01936 }
01937 
01952 static
01953 int headerAppendEntry(Header h, int_32 tag, int_32 type,
01954                 const void * p, int_32 c)
01955         /*@modifies h @*/
01956 {
01957     indexEntry entry;
01958     int length;
01959 
01960     if (type == RPM_STRING_TYPE || type == RPM_I18NSTRING_TYPE) {
01961         /* we can't do this */
01962         return 0;
01963     }
01964 
01965     /* Find the tag entry in the header. */
01966     entry = findEntry(h, tag, type);
01967     if (!entry)
01968         return 0;
01969 
01970     length = dataLength(type, p, c, 0, NULL);
01971     if (length < 0)
01972         return 0;
01973 
01974     if (ENTRY_IN_REGION(entry)) {
01975         char * t = xmalloc(entry->length + length);
01976 /*@-bounds@*/
01977         memcpy(t, entry->data, entry->length);
01978 /*@=bounds@*/
01979         entry->data = t;
01980         entry->info.offset = 0;
01981     } else
01982         entry->data = xrealloc(entry->data, entry->length + length);
01983 
01984     copyData(type, ((char *) entry->data) + entry->length, p, c, length);
01985 
01986     entry->length += length;
01987 
01988     entry->info.count += c;
01989 
01990     return 1;
01991 }
01992 
02003 static
02004 int headerAddOrAppendEntry(Header h, int_32 tag, int_32 type,
02005                 const void * p, int_32 c)
02006         /*@modifies h @*/
02007 {
02008     return (findEntry(h, tag, type)
02009         ? headerAppendEntry(h, tag, type, p, c)
02010         : headerAddEntry(h, tag, type, p, c));
02011 }
02012 
02033 static
02034 int headerAddI18NString(Header h, int_32 tag, const char * string,
02035                 const char * lang)
02036         /*@modifies h @*/
02037 {
02038     indexEntry table, entry;
02039     const char ** strArray;
02040     int length;
02041     int ghosts;
02042     int i, langNum;
02043     char * buf;
02044 
02045     table = findEntry(h, HEADER_I18NTABLE, RPM_STRING_ARRAY_TYPE);
02046     entry = findEntry(h, tag, RPM_I18NSTRING_TYPE);
02047 
02048     if (!table && entry)
02049         return 0;               /* this shouldn't ever happen!! */
02050 
02051     if (!table && !entry) {
02052         const char * charArray[2];
02053         int count = 0;
02054         if (!lang || (lang[0] == 'C' && lang[1] == '\0')) {
02055             /*@-observertrans -readonlytrans@*/
02056             charArray[count++] = "C";
02057             /*@=observertrans =readonlytrans@*/
02058         } else {
02059             /*@-observertrans -readonlytrans@*/
02060             charArray[count++] = "C";
02061             /*@=observertrans =readonlytrans@*/
02062             charArray[count++] = lang;
02063         }
02064         if (!headerAddEntry(h, HEADER_I18NTABLE, RPM_STRING_ARRAY_TYPE, 
02065                         &charArray, count))
02066             return 0;
02067         table = findEntry(h, HEADER_I18NTABLE, RPM_STRING_ARRAY_TYPE);
02068     }
02069 
02070     if (!table)
02071         return 0;
02072     /*@-branchstate@*/
02073     if (!lang) lang = "C";
02074     /*@=branchstate@*/
02075 
02076     {   const char * l = table->data;
02077         for (langNum = 0; langNum < table->info.count; langNum++) {
02078             if (!strcmp(l, lang)) break;
02079             l += strlen(l) + 1;
02080         }
02081     }
02082 
02083     if (langNum >= table->info.count) {
02084         length = strlen(lang) + 1;
02085         if (ENTRY_IN_REGION(table)) {
02086             char * t = xmalloc(table->length + length);
02087             memcpy(t, table->data, table->length);
02088             table->data = t;
02089             table->info.offset = 0;
02090         } else
02091             table->data = xrealloc(table->data, table->length + length);
02092         memmove(((char *)table->data) + table->length, lang, length);
02093         table->length += length;
02094         table->info.count++;
02095     }
02096 
02097     if (!entry) {
02098         strArray = alloca(sizeof(*strArray) * (langNum + 1));
02099         for (i = 0; i < langNum; i++)
02100             strArray[i] = "";
02101         strArray[langNum] = string;
02102         return headerAddEntry(h, tag, RPM_I18NSTRING_TYPE, strArray, 
02103                                 langNum + 1);
02104     } else if (langNum >= entry->info.count) {
02105         ghosts = langNum - entry->info.count;
02106         
02107         length = strlen(string) + 1 + ghosts;
02108         if (ENTRY_IN_REGION(entry)) {
02109             char * t = xmalloc(entry->length + length);
02110             memcpy(t, entry->data, entry->length);
02111             entry->data = t;
02112             entry->info.offset = 0;
02113         } else
02114             entry->data = xrealloc(entry->data, entry->length + length);
02115 
02116         memset(((char *)entry->data) + entry->length, '\0', ghosts);
02117         memmove(((char *)entry->data) + entry->length + ghosts, string, strlen(string)+1);
02118 
02119         entry->length += length;
02120         entry->info.count = langNum + 1;
02121     } else {
02122         char *b, *be, *e, *ee, *t;
02123         size_t bn, sn, en;
02124 
02125         /* Set beginning/end pointers to previous data */
02126         b = be = e = ee = entry->data;
02127         for (i = 0; i < table->info.count; i++) {
02128             if (i == langNum)
02129                 be = ee;
02130             ee += strlen(ee) + 1;
02131             if (i == langNum)
02132                 e  = ee;
02133         }
02134 
02135         /* Get storage for new buffer */
02136         bn = (be-b);
02137         sn = strlen(string) + 1;
02138         en = (ee-e);
02139         length = bn + sn + en;
02140         t = buf = xmalloc(length);
02141 
02142         /* Copy values into new storage */
02143         memcpy(t, b, bn);
02144         t += bn;
02145 /*@-mayaliasunique@*/
02146         memcpy(t, string, sn);
02147         t += sn;
02148         memcpy(t, e, en);
02149         t += en;
02150 /*@=mayaliasunique@*/
02151 
02152         /* Replace i18N string array */
02153         entry->length -= strlen(be) + 1;
02154         entry->length += sn;
02155         
02156         if (ENTRY_IN_REGION(entry)) {
02157             entry->info.offset = 0;
02158         } else
02159             entry->data = _free(entry->data);
02160         /*@-dependenttrans@*/
02161         entry->data = buf;
02162         /*@=dependenttrans@*/
02163     }
02164 
02165     return 0;
02166 }
02167 
02178 static
02179 int headerModifyEntry(Header h, int_32 tag, int_32 type,
02180                         const void * p, int_32 c)
02181         /*@modifies h @*/
02182 {
02183     indexEntry entry;
02184     void * oldData;
02185     void * data;
02186     int length;
02187 
02188     /* First find the tag */
02189     entry = findEntry(h, tag, type);
02190     if (!entry)
02191         return 0;
02192 
02193     length = 0;
02194     data = grabData(type, p, c, &length);
02195     if (data == NULL || length <= 0)
02196         return 0;
02197 
02198     /* make sure entry points to the first occurence of this tag */
02199     while (entry > h->index && (entry - 1)->info.tag == tag)  
02200         entry--;
02201 
02202     /* free after we've grabbed the new data in case the two are intertwined;
02203        that's a bad idea but at least we won't break */
02204     oldData = entry->data;
02205 
02206     entry->info.count = c;
02207     entry->info.type = type;
02208     entry->data = data;
02209     entry->length = length;
02210 
02211     /*@-branchstate@*/
02212     if (ENTRY_IN_REGION(entry)) {
02213         entry->info.offset = 0;
02214     } else
02215         oldData = _free(oldData);
02216     /*@=branchstate@*/
02217 
02218     return 1;
02219 }
02220 
02223 static char escapedChar(const char ch)  /*@*/
02224 {
02225     switch (ch) {
02226     case 'a':   return '\a';
02227     case 'b':   return '\b';
02228     case 'f':   return '\f';
02229     case 'n':   return '\n';
02230     case 'r':   return '\r';
02231     case 't':   return '\t';
02232     case 'v':   return '\v';
02233     default:    return ch;
02234     }
02235 }
02236 
02243 static /*@null@*/ sprintfToken
02244 freeFormat( /*@only@*/ /*@null@*/ sprintfToken format, int num)
02245         /*@modifies *format @*/
02246 {
02247     int i;
02248 
02249     if (format == NULL) return NULL;
02250 
02251     for (i = 0; i < num; i++) {
02252         switch (format[i].type) {
02253         case PTOK_ARRAY:
02254 /*@-boundswrite@*/
02255             format[i].u.array.format =
02256                 freeFormat(format[i].u.array.format,
02257                         format[i].u.array.numTokens);
02258 /*@=boundswrite@*/
02259             /*@switchbreak@*/ break;
02260         case PTOK_COND:
02261 /*@-boundswrite@*/
02262             format[i].u.cond.ifFormat =
02263                 freeFormat(format[i].u.cond.ifFormat, 
02264                         format[i].u.cond.numIfTokens);
02265             format[i].u.cond.elseFormat =
02266                 freeFormat(format[i].u.cond.elseFormat, 
02267                         format[i].u.cond.numElseTokens);
02268 /*@=boundswrite@*/
02269             /*@switchbreak@*/ break;
02270         case PTOK_NONE:
02271         case PTOK_TAG:
02272         case PTOK_STRING:
02273         default:
02274             /*@switchbreak@*/ break;
02275         }
02276     }
02277     format = _free(format);
02278     return NULL;
02279 }
02280 
02284 struct headerIterator_s {
02285 /*@unused@*/
02286     Header h;           
02287 /*@unused@*/
02288     int next_index;     
02289 };
02290 
02296 static /*@null@*/
02297 HeaderIterator headerFreeIterator(/*@only@*/ HeaderIterator hi)
02298         /*@modifies hi @*/
02299 {
02300     if (hi != NULL) {
02301         hi->h = headerFree(hi->h);
02302         hi = _free(hi);
02303     }
02304     return hi;
02305 }
02306 
02312 static
02313 HeaderIterator headerInitIterator(Header h)
02314         /*@modifies h */
02315 {
02316     HeaderIterator hi = xmalloc(sizeof(*hi));
02317 
02318     headerSort(h);
02319 
02320     hi->h = headerLink(h);
02321     hi->next_index = 0;
02322     return hi;
02323 }
02324 
02334 static
02335 int headerNextIterator(HeaderIterator hi,
02336                 /*@null@*/ /*@out@*/ hTAG_t tag,
02337                 /*@null@*/ /*@out@*/ hTYP_t type,
02338                 /*@null@*/ /*@out@*/ hPTR_t * p,
02339                 /*@null@*/ /*@out@*/ hCNT_t c)
02340         /*@modifies hi, *tag, *type, *p, *c @*/
02341         /*@requires maxSet(tag) >= 0 /\ maxSet(type) >= 0
02342                 /\ maxSet(p) >= 0 /\ maxSet(c) >= 0 @*/
02343 {
02344     Header h = hi->h;
02345     int slot = hi->next_index;
02346     indexEntry entry = NULL;
02347     int rc;
02348 
02349     for (slot = hi->next_index; slot < h->indexUsed; slot++) {
02350         entry = h->index + slot;
02351         if (!ENTRY_IS_REGION(entry))
02352             break;
02353     }
02354     hi->next_index = slot;
02355     if (entry == NULL || slot >= h->indexUsed)
02356         return 0;
02357 
02358     /*@-noeffect@*/     /* LCL: no clue */
02359     hi->next_index++;
02360     /*@=noeffect@*/
02361 
02362     if (tag)
02363         *tag = entry->info.tag;
02364 
02365     rc = copyEntry(entry, type, p, c, 0);
02366 
02367     /* XXX 1 on success */
02368     return ((rc == 1) ? 1 : 0);
02369 }
02370 
02376 static /*@null@*/
02377 Header headerCopy(Header h)
02378         /*@modifies h @*/
02379 {
02380     Header nh = headerNew();
02381     HeaderIterator hi;
02382     int_32 tag, type, count;
02383     hPTR_t ptr;
02384    
02385     /*@-branchstate@*/
02386     for (hi = headerInitIterator(h);
02387         headerNextIterator(hi, &tag, &type, &ptr, &count);
02388         ptr = headerFreeData((void *)ptr, type))
02389     {
02390         if (ptr) (void) headerAddEntry(nh, tag, type, ptr, count);
02391     }
02392     hi = headerFreeIterator(hi);
02393     /*@=branchstate@*/
02394 
02395     return headerReload(nh, HEADER_IMAGE);
02396 }
02397 
02400 typedef struct headerSprintfArgs_s {
02401     Header h;
02402     char * fmt;
02403 /*@temp@*/
02404     headerTagTableEntry tags;
02405 /*@temp@*/
02406     headerSprintfExtension exts;
02407 /*@observer@*/ /*@null@*/
02408     const char * errmsg;
02409     rpmec ec;
02410     sprintfToken format;
02411 /*@relnull@*/
02412     HeaderIterator hi;
02413 /*@owned@*/
02414     char * val;
02415     size_t vallen;
02416     size_t alloced;
02417     int numTokens;
02418     int i;
02419 } * headerSprintfArgs;
02420 
02426 static headerSprintfArgs hsaInit(/*@returned@*/ headerSprintfArgs hsa)
02427         /*@modifies hsa */
02428 {
02429     sprintfTag tag =
02430         (hsa->format->type == PTOK_TAG
02431             ? &hsa->format->u.tag :
02432         (hsa->format->type == PTOK_ARRAY
02433             ? &hsa->format->u.array.format->u.tag :
02434         NULL));
02435 
02436     if (hsa != NULL) {
02437         hsa->i = 0;
02438         if (tag != NULL && tag->tag == -2)
02439             hsa->hi = headerInitIterator(hsa->h);
02440     }
02441 /*@-nullret@*/
02442     return hsa;
02443 /*@=nullret@*/
02444 }
02445 
02451 /*@null@*/
02452 static sprintfToken hsaNext(/*@returned@*/ headerSprintfArgs hsa)
02453         /*@modifies hsa */
02454 {
02455     sprintfToken fmt = NULL;
02456     sprintfTag tag =
02457         (hsa->format->type == PTOK_TAG
02458             ? &hsa->format->u.tag :
02459         (hsa->format->type == PTOK_ARRAY
02460             ? &hsa->format->u.array.format->u.tag :
02461         NULL));
02462 
02463     if (hsa != NULL && hsa->i >= 0 && hsa->i < hsa->numTokens) {
02464         fmt = hsa->format + hsa->i;
02465         if (hsa->hi == NULL) {
02466             hsa->i++;
02467         } else {
02468             int_32 tagno;
02469             int_32 type;
02470             int_32 count;
02471 
02472 /*@-boundswrite@*/
02473             if (!headerNextIterator(hsa->hi, &tagno, &type, NULL, &count))
02474                 fmt = NULL;
02475             tag->tag = tagno;
02476 /*@=boundswrite@*/
02477         }
02478     }
02479 
02480 /*@-dependenttrans -onlytrans@*/
02481     return fmt;
02482 /*@=dependenttrans =onlytrans@*/
02483 }
02484 
02490 static headerSprintfArgs hsaFini(/*@returned@*/ headerSprintfArgs hsa)
02491         /*@modifies hsa */
02492 {
02493     if (hsa != NULL) {
02494         hsa->hi = headerFreeIterator(hsa->hi);
02495         hsa->i = 0;
02496     }
02497 /*@-nullret@*/
02498     return hsa;
02499 /*@=nullret@*/
02500 }
02501 
02508 /*@dependent@*/ /*@exposed@*/
02509 static char * hsaReserve(headerSprintfArgs hsa, size_t need)
02510         /*@modifies hsa */
02511 {
02512     if ((hsa->vallen + need) >= hsa->alloced) {
02513         if (hsa->alloced <= need)
02514             hsa->alloced += need;
02515         hsa->alloced <<= 1;
02516         hsa->val = xrealloc(hsa->val, hsa->alloced+1);  
02517     }
02518     return hsa->val + hsa->vallen;
02519 }
02520 
02527 static int findTag(headerSprintfArgs hsa, sprintfToken token, const char * name)
02528         /*@modifies token @*/
02529 {
02530     headerTagTableEntry tag;
02531     headerSprintfExtension ext;
02532     sprintfTag stag = (token->type == PTOK_COND
02533         ? &token->u.cond.tag : &token->u.tag);
02534 
02535     stag->fmt = NULL;
02536     stag->ext = NULL;
02537     stag->extNum = 0;
02538     stag->tag = -1;
02539 
02540     if (!strcmp(name, "*")) {
02541         stag->tag = -2;
02542         goto bingo;
02543     }
02544 
02545 /*@-branchstate@*/
02546     if (strncmp("RPMTAG_", name, sizeof("RPMTAG_")-1)) {
02547 /*@-boundswrite@*/
02548         char * t = alloca(strlen(name) + sizeof("RPMTAG_"));
02549         (void) stpcpy( stpcpy(t, "RPMTAG_"), name);
02550         name = t;
02551 /*@=boundswrite@*/
02552     }
02553 /*@=branchstate@*/
02554 
02555     /* Search extensions for specific tag override. */
02556     for (ext = hsa->exts; ext != NULL && ext->type != HEADER_EXT_LAST;
02557         ext = (ext->type == HEADER_EXT_MORE ? ext->u.more : ext+1))
02558     {
02559         if (ext->name == NULL || ext->type != HEADER_EXT_TAG)
02560             continue;
02561         if (!xstrcasecmp(ext->name, name)) {
02562             stag->ext = ext->u.tagFunction;
02563             stag->extNum = ext - hsa->exts;
02564             goto bingo;
02565         }
02566     }
02567 
02568     /* Search tag names. */
02569     for (tag = hsa->tags; tag->name != NULL; tag++) {
02570         if (!xstrcasecmp(tag->name, name)) {
02571             stag->tag = tag->val;
02572             goto bingo;
02573         }
02574     }
02575 
02576     return 1;
02577 
02578 bingo:
02579     /* Search extensions for specific format. */
02580     if (stag->type != NULL)
02581     for (ext = hsa->exts; ext != NULL && ext->type != HEADER_EXT_LAST;
02582             ext = (ext->type == HEADER_EXT_MORE ? ext->u.more : ext+1))
02583     {
02584         if (ext->name == NULL || ext->type != HEADER_EXT_FORMAT)
02585             continue;
02586         if (!strcmp(ext->name, stag->type)) {
02587             stag->fmt = ext->u.formatFunction;
02588             break;
02589         }
02590     }
02591     return 0;
02592 }
02593 
02594 /* forward ref */
02602 static int parseExpression(headerSprintfArgs hsa, sprintfToken token,
02603                 char * str, /*@out@*/char ** endPtr)
02604         /*@modifies hsa, str, token, *endPtr @*/
02605         /*@requires maxSet(endPtr) >= 0 @*/;
02606 
02616 static int parseFormat(headerSprintfArgs hsa, /*@null@*/ char * str,
02617                 /*@out@*/sprintfToken * formatPtr, /*@out@*/int * numTokensPtr,
02618                 /*@null@*/ /*@out@*/ char ** endPtr, int state)
02619         /*@modifies hsa, str, *formatPtr, *numTokensPtr, *endPtr @*/
02620         /*@requires maxSet(formatPtr) >= 0 /\ maxSet(numTokensPtr) >= 0
02621                 /\ maxSet(endPtr) >= 0 @*/
02622 {
02623     char * chptr, * start, * next, * dst;
02624     sprintfToken format;
02625     sprintfToken token;
02626     int numTokens;
02627     int i;
02628     int done = 0;
02629 
02630     /* upper limit on number of individual formats */
02631     numTokens = 0;
02632     if (str != NULL)
02633     for (chptr = str; *chptr != '\0'; chptr++)
02634         if (*chptr == '%') numTokens++;
02635     numTokens = numTokens * 2 + 1;
02636 
02637     format = xcalloc(numTokens, sizeof(*format));
02638     if (endPtr) *endPtr = NULL;
02639 
02640     /*@-infloops@*/ /* LCL: can't detect done termination */
02641     dst = start = str;
02642     numTokens = 0;
02643     token = NULL;
02644     if (start != NULL)
02645     while (*start != '\0') {
02646         switch (*start) {
02647         case '%':
02648             /* handle %% */
02649             if (*(start + 1) == '%') {
02650                 if (token == NULL || token->type != PTOK_STRING) {
02651                     token = format + numTokens++;
02652                     token->type = PTOK_STRING;
02653                     /*@-temptrans -assignexpose@*/
02654                     dst = token->u.string.string = start;
02655                     /*@=temptrans =assignexpose@*/
02656                 }
02657                 start++;
02658 /*@-boundswrite@*/
02659                 *dst++ = *start++;
02660 /*@=boundswrite@*/
02661                 /*@switchbreak@*/ break;
02662             } 
02663 
02664             token = format + numTokens++;
02665 /*@-boundswrite@*/
02666             *dst++ = '\0';
02667 /*@=boundswrite@*/
02668             start++;
02669 
02670             if (*start == '|') {
02671                 char * newEnd;
02672 
02673                 start++;
02674 /*@-boundswrite@*/
02675                 if (parseExpression(hsa, token, start, &newEnd))
02676                 {
02677                     format = freeFormat(format, numTokens);
02678                     return 1;
02679                 }
02680 /*@=boundswrite@*/
02681                 start = newEnd;
02682                 /*@switchbreak@*/ break;
02683             }
02684 
02685             /*@-assignexpose@*/
02686             token->u.tag.format = start;
02687             /*@=assignexpose@*/
02688             token->u.tag.pad = 0;
02689             token->u.tag.justOne = 0;
02690             token->u.tag.arrayCount = 0;
02691 
02692             chptr = start;
02693             while (*chptr && *chptr != '{' && *chptr != '%') chptr++;
02694             if (!*chptr || *chptr == '%') {
02695                 hsa->errmsg = _("missing { after %");
02696                 format = freeFormat(format, numTokens);
02697                 return 1;
02698             }
02699 
02700 /*@-boundswrite@*/
02701             *chptr++ = '\0';
02702 /*@=boundswrite@*/
02703 
02704             while (start < chptr) {
02705                 if (xisdigit(*start)) {
02706                     i = strtoul(start, &start, 10);
02707                     token->u.tag.pad += i;
02708                 } else {
02709                     start++;
02710                 }
02711             }
02712 
02713             if (*start == '=') {
02714                 token->u.tag.justOne = 1;
02715                 start++;
02716             } else if (*start == '#') {
02717                 token->u.tag.justOne = 1;
02718                 token->u.tag.arrayCount = 1;
02719                 start++;
02720             }
02721 
02722             next = start;
02723             while (*next && *next != '}') next++;
02724             if (!*next) {
02725                 hsa->errmsg = _("missing } after %{");
02726                 format = freeFormat(format, numTokens);
02727                 return 1;
02728             }
02729 /*@-boundswrite@*/
02730             *next++ = '\0';
02731 /*@=boundswrite@*/
02732 
02733             chptr = start;
02734             while (*chptr && *chptr != ':') chptr++;
02735 
02736             if (*chptr != '\0') {
02737 /*@-boundswrite@*/
02738                 *chptr++ = '\0';
02739 /*@=boundswrite@*/
02740                 if (!*chptr) {
02741                     hsa->errmsg = _("empty tag format");
02742                     format = freeFormat(format, numTokens);
02743                     return 1;
02744                 }
02745                 /*@-assignexpose@*/
02746                 token->u.tag.type = chptr;
02747                 /*@=assignexpose@*/
02748             } else {
02749                 token->u.tag.type = NULL;
02750             }
02751             
02752             if (!*start) {
02753                 hsa->errmsg = _("empty tag name");
02754                 format = freeFormat(format, numTokens);
02755                 return 1;
02756             }
02757 
02758             i = 0;
02759             token->type = PTOK_TAG;
02760 
02761             if (findTag(hsa, token, start)) {
02762                 hsa->errmsg = _("unknown tag");
02763                 format = freeFormat(format, numTokens);
02764                 return 1;
02765             }
02766 
02767             start = next;
02768             /*@switchbreak@*/ break;
02769 
02770         case '[':
02771 /*@-boundswrite@*/
02772             *dst++ = '\0';
02773             *start++ = '\0';
02774 /*@=boundswrite@*/
02775             token = format + numTokens++;
02776 
02777 /*@-boundswrite@*/
02778             if (parseFormat(hsa, start,
02779                             &token->u.array.format,
02780                             &token->u.array.numTokens,
02781                             &start, PARSER_IN_ARRAY))
02782             {
02783                 format = freeFormat(format, numTokens);
02784                 return 1;
02785             }
02786 /*@=boundswrite@*/
02787 
02788             if (!start) {
02789                 hsa->errmsg = _("] expected at end of array");
02790                 format = freeFormat(format, numTokens);
02791                 return 1;
02792             }
02793 
02794             dst = start;
02795 
02796             token->type = PTOK_ARRAY;
02797 
02798             /*@switchbreak@*/ break;
02799 
02800         case ']':
02801             if (state != PARSER_IN_ARRAY) {
02802                 hsa->errmsg = _("unexpected ]");
02803                 format = freeFormat(format, numTokens);
02804                 return 1;
02805             }
02806 /*@-boundswrite@*/
02807             *start++ = '\0';
02808 /*@=boundswrite@*/
02809             if (endPtr) *endPtr = start;
02810             done = 1;
02811             /*@switchbreak@*/ break;
02812 
02813         case '}':
02814             if (state != PARSER_IN_EXPR) {
02815                 hsa->errmsg = _("unexpected }");
02816                 format = freeFormat(format, numTokens);
02817                 return 1;
02818             }
02819 /*@-boundswrite@*/
02820             *start++ = '\0';
02821 /*@=boundswrite@*/
02822             if (endPtr) *endPtr = start;
02823             done = 1;
02824             /*@switchbreak@*/ break;
02825 
02826         default:
02827             if (token == NULL || token->type != PTOK_STRING) {
02828                 token = format + numTokens++;
02829                 token->type = PTOK_STRING;
02830                 /*@-temptrans -assignexpose@*/
02831                 dst = token->u.string.string = start;
02832                 /*@=temptrans =assignexpose@*/
02833             }
02834 
02835 /*@-boundswrite@*/
02836             if (*start == '\\') {
02837                 start++;
02838                 *dst++ = escapedChar(*start++);
02839             } else {
02840                 *dst++ = *start++;
02841             }
02842 /*@=boundswrite@*/
02843             /*@switchbreak@*/ break;
02844         }
02845         if (done)
02846             break;
02847     }
02848     /*@=infloops@*/
02849 
02850 /*@-boundswrite@*/
02851     if (dst != NULL)
02852         *dst = '\0';
02853 /*@=boundswrite@*/
02854 
02855     for (i = 0; i < numTokens; i++) {
02856         token = format + i;
02857         if (token->type == PTOK_STRING)
02858             token->u.string.len = strlen(token->u.string.string);
02859     }
02860 
02861     *numTokensPtr = numTokens;
02862     *formatPtr = format;
02863 
02864     return 0;
02865 }
02866 
02867 /*@-boundswrite@*/
02868 static int parseExpression(headerSprintfArgs hsa, sprintfToken token,
02869                 char * str, /*@out@*/ char ** endPtr)
02870 {
02871     char * chptr;
02872     char * end;
02873 
02874     hsa->errmsg = NULL;
02875     chptr = str;
02876     while (*chptr && *chptr != '?') chptr++;
02877 
02878     if (*chptr != '?') {
02879         hsa->errmsg = _("? expected in expression");
02880         return 1;
02881     }
02882 
02883     *chptr++ = '\0';;
02884 
02885     if (*chptr != '{') {
02886         hsa->errmsg = _("{ expected after ? in expression");
02887         return 1;
02888     }
02889 
02890     chptr++;
02891 
02892     if (parseFormat(hsa, chptr, &token->u.cond.ifFormat, 
02893                     &token->u.cond.numIfTokens, &end, PARSER_IN_EXPR)) 
02894         return 1;
02895 
02896     /* XXX fix segfault on "rpm -q rpm --qf='%|NAME?{%}:{NAME}|\n'"*/
02897     if (!(end && *end)) {
02898         hsa->errmsg = _("} expected in expression");
02899         token->u.cond.ifFormat =
02900                 freeFormat(token->u.cond.ifFormat, token->u.cond.numIfTokens);
02901         return 1;
02902     }
02903 
02904     chptr = end;
02905     if (*chptr != ':' && *chptr != '|') {
02906         hsa->errmsg = _(": expected following ? subexpression");
02907         token->u.cond.ifFormat =
02908                 freeFormat(token->u.cond.ifFormat, token->u.cond.numIfTokens);
02909         return 1;
02910     }
02911 
02912     if (*chptr == '|') {
02913         if (parseFormat(hsa, NULL, &token->u.cond.elseFormat, 
02914                 &token->u.cond.numElseTokens, &end, PARSER_IN_EXPR))
02915         {
02916             token->u.cond.ifFormat =
02917                 freeFormat(token->u.cond.ifFormat, token->u.cond.numIfTokens);
02918             return 1;
02919         }
02920     } else {
02921         chptr++;
02922 
02923         if (*chptr != '{') {
02924             hsa->errmsg = _("{ expected after : in expression");
02925             token->u.cond.ifFormat =
02926                 freeFormat(token->u.cond.ifFormat, token->u.cond.numIfTokens);
02927             return 1;
02928         }
02929 
02930         chptr++;
02931 
02932         if (parseFormat(hsa, chptr, &token->u.cond.elseFormat, 
02933                         &token->u.cond.numElseTokens, &end, PARSER_IN_EXPR)) 
02934             return 1;
02935 
02936         /* XXX fix segfault on "rpm -q rpm --qf='%|NAME?{a}:{%}|{NAME}\n'" */
02937         if (!(end && *end)) {
02938             hsa->errmsg = _("} expected in expression");
02939             token->u.cond.ifFormat =
02940                 freeFormat(token->u.cond.ifFormat, token->u.cond.numIfTokens);
02941             return 1;
02942         }
02943 
02944         chptr = end;
02945         if (*chptr != '|') {
02946             hsa->errmsg = _("| expected at end of expression");
02947             token->u.cond.ifFormat =
02948                 freeFormat(token->u.cond.ifFormat, token->u.cond.numIfTokens);
02949             token->u.cond.elseFormat =
02950                 freeFormat(token->u.cond.elseFormat, token->u.cond.numElseTokens);
02951             return 1;
02952         }
02953     }
02954         
02955     chptr++;
02956 
02957     *endPtr = chptr;
02958 
02959     token->type = PTOK_COND;
02960 
02961     (void) findTag(hsa, token, str);
02962 
02963     return 0;
02964 }
02965 /*@=boundswrite@*/
02966 
02977 static int getExtension(headerSprintfArgs hsa, headerTagTagFunction fn,
02978                 /*@out@*/ hTYP_t typeptr,
02979                 /*@out@*/ hPTR_t * data,
02980                 /*@out@*/ hCNT_t countptr,
02981                 rpmec ec)
02982         /*@modifies *typeptr, *data, *countptr, ec @*/
02983         /*@requires maxSet(typeptr) >= 0 /\ maxSet(data) >= 0
02984                 /\ maxSet(countptr) >= 0 @*/
02985 {
02986     if (!ec->avail) {
02987         if (fn(hsa->h, &ec->type, &ec->data, &ec->count, &ec->freeit))
02988             return 1;
02989         ec->avail = 1;
02990     }
02991 
02992     if (typeptr) *typeptr = ec->type;
02993     if (data) *data = ec->data;
02994     if (countptr) *countptr = ec->count;
02995 
02996     return 0;
02997 }
02998 
03005 /*@observer@*/ /*@null@*/
03006 static char * formatValue(headerSprintfArgs hsa, sprintfTag tag, int element)
03007         /*@modifies hsa @*/
03008 {
03009     char * val = NULL;
03010     size_t need = 0;
03011     char * t, * te;
03012     char buf[20];
03013     int_32 count, type;
03014     hPTR_t data;
03015     unsigned int intVal;
03016     const char ** strarray;
03017     int datafree = 0;
03018     int countBuf;
03019 
03020     memset(buf, 0, sizeof(buf));
03021     if (tag->ext) {
03022 /*@-boundswrite -branchstate @*/
03023         if (getExtension(hsa, tag->ext, &type, &data, &count, hsa->ec + tag->extNum))
03024         {
03025             count = 1;
03026             type = RPM_STRING_TYPE;     
03027             data = "(none)";
03028         }
03029 /*@=boundswrite =branchstate @*/
03030     } else {
03031 /*@-boundswrite -branchstate @*/
03032         if (!headerGetEntry(hsa->h, tag->tag, &type, (void **)&data, &count)) {
03033             count = 1;
03034             type = RPM_STRING_TYPE;     
03035             data = "(none)";
03036         }
03037 /*@=boundswrite =branchstate @*/
03038 
03039         /* XXX this test is unnecessary, array sizes are checked */
03040         switch (type) {
03041         default:
03042             if (element >= count) {
03043                 /*@-modobserver -observertrans@*/
03044                 data = headerFreeData(data, type);
03045                 /*@=modobserver =observertrans@*/
03046 
03047                 hsa->errmsg = _("(index out of range)");
03048                 return NULL;
03049             }
03050             break;
03051         case RPM_BIN_TYPE:
03052         case RPM_STRING_TYPE:
03053             break;
03054         }
03055         datafree = 1;
03056     }
03057 
03058     if (tag->arrayCount) {
03059         /*@-branchstate -observertrans -modobserver@*/
03060         if (datafree)
03061             data = headerFreeData(data, type);
03062         /*@=branchstate =observertrans =modobserver@*/
03063 
03064         countBuf = count;
03065         data = &countBuf;
03066         count = 1;
03067         type = RPM_INT32_TYPE;
03068     }
03069 
03070 /*@-boundswrite@*/
03071     (void) stpcpy( stpcpy(buf, "%"), tag->format);
03072 /*@=boundswrite@*/
03073 
03074     /*@-branchstate@*/
03075     if (data)
03076     switch (type) {
03077     case RPM_STRING_ARRAY_TYPE:
03078         strarray = (const char **)data;
03079 
03080         if (tag->fmt)
03081             val = tag->fmt(RPM_STRING_TYPE, strarray[element], buf, tag->pad, element);
03082 
03083         if (val) {
03084             need = strlen(val);
03085         } else {
03086             need = strlen(strarray[element]) + tag->pad + 20;
03087             val = xmalloc(need+1);
03088             strcat(buf, "s");
03089             /*@-formatconst@*/
03090             sprintf(val, buf, strarray[element]);
03091             /*@=formatconst@*/
03092         }
03093 
03094         break;
03095 
03096     case RPM_STRING_TYPE:
03097         if (tag->fmt)
03098             val = tag->fmt(RPM_STRING_TYPE, data, buf, tag->pad,  0);
03099 
03100         if (val) {
03101             need = strlen(val);
03102         } else {
03103             need = strlen(data) + tag->pad + 20;
03104             val = xmalloc(need+1);
03105             strcat(buf, "s");
03106             /*@-formatconst@*/
03107             sprintf(val, buf, data);
03108             /*@=formatconst@*/
03109         }
03110         break;
03111 
03112     case RPM_CHAR_TYPE:
03113     case RPM_INT8_TYPE:
03114     case RPM_INT16_TYPE:
03115     case RPM_INT32_TYPE:
03116         switch (type) {
03117         case RPM_CHAR_TYPE:     
03118         case RPM_INT8_TYPE:
03119             intVal = *(((int_8 *) data) + element);
03120             /*@innerbreak@*/ break;
03121         case RPM_INT16_TYPE:
03122             intVal = *(((uint_16 *) data) + element);
03123             /*@innerbreak@*/ break;
03124         default:                /* keep -Wall quiet */
03125         case RPM_INT32_TYPE:
03126             intVal = *(((int_32 *) data) + element);
03127             /*@innerbreak@*/ break;
03128         }
03129 
03130         if (tag->fmt)
03131             val = tag->fmt(RPM_INT32_TYPE, &intVal, buf, tag->pad, element);
03132 
03133         if (val) {
03134             need = strlen(val);
03135         } else {
03136             need = 10 + tag->pad + 20;
03137             val = xmalloc(need+1);
03138             strcat(buf, "d");
03139             /*@-formatconst@*/
03140             sprintf(val, buf, intVal);
03141             /*@=formatconst@*/
03142         }
03143         break;
03144 
03145     case RPM_BIN_TYPE:
03146         /* XXX HACK ALERT: element field abused as no. bytes of binary data. */
03147         if (tag->fmt)
03148             val = tag->fmt(RPM_BIN_TYPE, data, buf, tag->pad, count);
03149 
03150         if (val) {
03151             need = strlen(val);
03152         } else {
03153 #ifdef  NOTYET
03154             val = memcpy(xmalloc(count), data, count);
03155 #else
03156             /* XXX format string not used */
03157             static char hex[] = "0123456789abcdef";
03158             const char * s = data;
03159 
03160 /*@-boundswrite@*/
03161             need = 2*count + tag->pad;
03162             val = t = xmalloc(need+1);
03163             while (count-- > 0) {
03164                 unsigned int i;
03165                 i = *s++;
03166                 *t++ = hex[ (i >> 4) & 0xf ];
03167                 *t++ = hex[ (i     ) & 0xf ];
03168             }
03169             *t = '\0';
03170 /*@=boundswrite@*/
03171 #endif
03172         }
03173         break;
03174 
03175     default:
03176         need = sizeof("(unknown type)") - 1;
03177         val = xstrdup("(unknown type)");
03178         break;
03179     }
03180     /*@=branchstate@*/
03181 
03182     /*@-branchstate -observertrans -modobserver@*/
03183     if (datafree)
03184         data = headerFreeData(data, type);
03185     /*@=branchstate =observertrans =modobserver@*/
03186 
03187     /*@-branchstate@*/
03188     if (val && need > 0) {
03189         t = hsaReserve(hsa, need);
03190 /*@-boundswrite@*/
03191         te = stpcpy(t, val);
03192 /*@=boundswrite@*/
03193         hsa->vallen += (te - t);
03194         val = _free(val);
03195     }
03196     /*@=branchstate@*/
03197 
03198     return (hsa->val + hsa->vallen);
03199 }
03200 
03207 /*@observer@*/
03208 static char * singleSprintf(headerSprintfArgs hsa, sprintfToken token,
03209                 int element)
03210         /*@modifies hsa @*/
03211 {
03212     char * t, * te;
03213     int i, j;
03214     int numElements;
03215     int_32 type;
03216     int_32 count;
03217     sprintfToken spft;
03218     int condNumFormats;
03219     size_t need;
03220 
03221     /* we assume the token and header have been validated already! */
03222 
03223     switch (token->type) {
03224     case PTOK_NONE:
03225         break;
03226 
03227     case PTOK_STRING:
03228         need = token->u.string.len;
03229         if (need == 0) break;
03230         t = hsaReserve(hsa, need);
03231 /*@-boundswrite@*/
03232         te = stpcpy(t, token->u.string.string);
03233 /*@=boundswrite@*/
03234         hsa->vallen += (te - t);
03235         break;
03236 
03237     case PTOK_TAG:
03238         t = hsa->val + hsa->vallen;
03239         te = formatValue(hsa, &token->u.tag,
03240                         (token->u.tag.justOne ? 0 : element));
03241         if (te == NULL)
03242             return NULL;
03243         break;
03244 
03245     case PTOK_COND:
03246         if (token->u.cond.tag.ext || headerIsEntry(hsa->h, token->u.cond.tag.tag)) {
03247             spft = token->u.cond.ifFormat;
03248             condNumFormats = token->u.cond.numIfTokens;
03249         } else {
03250             spft = token->u.cond.elseFormat;
03251             condNumFormats = token->u.cond.numElseTokens;
03252         }
03253 
03254         need = condNumFormats * 20;
03255         if (spft == NULL || need == 0) break;
03256 
03257         t = hsaReserve(hsa, need);
03258         for (i = 0; i < condNumFormats; i++, spft++) {
03259             te = singleSprintf(hsa, spft, element);
03260             if (te == NULL)
03261                 return NULL;
03262         }
03263         break;
03264 
03265     case PTOK_ARRAY:
03266         numElements = -1;
03267         spft = token->u.array.format;
03268         for (i = 0; i < token->u.array.numTokens; i++, spft++)
03269         {
03270             if (spft->type != PTOK_TAG ||
03271                 spft->u.tag.arrayCount ||
03272                 spft->u.tag.justOne) continue;
03273 
03274             if (spft->u.tag.ext) {
03275 /*@-boundswrite@*/
03276                 if (getExtension(hsa, spft->u.tag.ext, &type, NULL, &count, 
03277                                  hsa->ec + spft->u.tag.extNum))
03278                      continue;
03279 /*@=boundswrite@*/
03280             } else {
03281 /*@-boundswrite@*/
03282                 if (!headerGetEntry(hsa->h, spft->u.tag.tag, &type, NULL, &count))
03283                     continue;
03284 /*@=boundswrite@*/
03285             } 
03286 
03287             if (type == RPM_BIN_TYPE)
03288                 count = 1;      /* XXX count abused as no. of bytes. */
03289 
03290             if (numElements > 1 && count != numElements)
03291             switch (type) {
03292             default:
03293                 hsa->errmsg =
03294                         _("array iterator used with different sized arrays");
03295                 return NULL;
03296                 /*@notreached@*/ /*@switchbreak@*/ break;
03297             case RPM_BIN_TYPE:
03298             case RPM_STRING_TYPE:
03299                 /*@switchbreak@*/ break;
03300             }
03301             if (count > numElements)
03302                 numElements = count;
03303         }
03304 
03305         if (numElements == -1) {
03306             need = sizeof("(none)") - 1;
03307             t = hsaReserve(hsa, need);
03308 /*@-boundswrite@*/
03309             te = stpcpy(t, "(none)");
03310 /*@=boundswrite@*/
03311             hsa->vallen += (te - t);
03312         } else {
03313             int isxml;
03314 
03315             need = numElements * token->u.array.numTokens * 10;
03316             if (need == 0) break;
03317 
03318             spft = token->u.array.format;
03319             isxml = (spft->type == PTOK_TAG && spft->u.tag.type != NULL &&
03320                 !strcmp(spft->u.tag.type, "xml"));
03321 
03322             if (isxml) {
03323                 const char * tagN = tagName(spft->u.tag.tag);
03324 
03325                 need = strlen(tagN) + sizeof("  <rpmTag name=\"\">\n") - 1;
03326                 t = hsaReserve(hsa, need);
03327 /*@-boundswrite@*/
03328                 te = stpcpy(t, "  <rpmTag name=\"");
03329                 te = stpcpy(te, tagN);
03330                 te = stpcpy(te, "\">\n");
03331 /*@=boundswrite@*/
03332                 hsa->vallen += (te - t);
03333             }
03334 
03335             t = hsaReserve(hsa, need);
03336             for (j = 0; j < numElements; j++) {
03337                 spft = token->u.array.format;
03338                 for (i = 0; i < token->u.array.numTokens; i++, spft++) {
03339                     te = singleSprintf(hsa, spft, j);
03340                     if (te == NULL)
03341                         return NULL;
03342                 }
03343             }
03344 
03345             if (isxml) {
03346                 need = sizeof("  </rpmTag>\n") - 1;
03347                 t = hsaReserve(hsa, need);
03348 /*@-boundswrite@*/
03349                 te = stpcpy(t, "  </rpmTag>\n");
03350 /*@=boundswrite@*/
03351                 hsa->vallen += (te - t);
03352             }
03353 
03354         }
03355         break;
03356     }
03357 
03358     return (hsa->val + hsa->vallen);
03359 }
03360 
03366 static /*@only@*/ rpmec
03367 rpmecNew(const headerSprintfExtension exts)
03368         /*@*/
03369 {
03370     headerSprintfExtension ext;
03371     rpmec ec;
03372     int i = 0;
03373 
03374     for (ext = exts; ext != NULL && ext->type != HEADER_EXT_LAST;
03375         ext = (ext->type == HEADER_EXT_MORE ? ext->u.more : ext+1))
03376     {
03377         i++;
03378     }
03379 
03380     ec = xcalloc(i, sizeof(*ec));
03381     return ec;
03382 }
03383 
03390 static /*@null@*/ rpmec
03391 rpmecFree(const headerSprintfExtension exts, /*@only@*/ rpmec ec)
03392         /*@modifies ec @*/
03393 {
03394     headerSprintfExtension ext;
03395     int i = 0;
03396 
03397     for (ext = exts; ext != NULL && ext->type != HEADER_EXT_LAST;
03398         ext = (ext->type == HEADER_EXT_MORE ? ext->u.more : ext+1))
03399     {
03400 /*@-boundswrite@*/
03401         if (ec[i].freeit) ec[i].data = _free(ec[i].data);
03402 /*@=boundswrite@*/
03403         i++;
03404     }
03405 
03406     ec = _free(ec);
03407     return NULL;
03408 }
03409 
03421 static /*@only@*/ /*@null@*/
03422 char * headerSprintf(Header h, const char * fmt,
03423                      const struct headerTagTableEntry_s * tbltags,
03424                      const struct headerSprintfExtension_s * extensions,
03425                      /*@null@*/ /*@out@*/ errmsg_t * errmsg)
03426         /*@modifies h, *errmsg @*/
03427         /*@requires maxSet(errmsg) >= 0 @*/
03428 {
03429     headerSprintfArgs hsa = memset(alloca(sizeof(*hsa)), 0, sizeof(*hsa));
03430     sprintfToken nextfmt;
03431     sprintfTag tag;
03432     char * t, * te;
03433     int isxml;
03434     int need;
03435  
03436     hsa->h = headerLink(h);
03437     hsa->fmt = xstrdup(fmt);
03438 /*@-castexpose@*/       /* FIX: legacy API shouldn't change. */
03439     hsa->exts = (headerSprintfExtension) extensions;
03440     hsa->tags = (headerTagTableEntry) tbltags;
03441 /*@=castexpose@*/
03442     hsa->errmsg = NULL;
03443 
03444 /*@-boundswrite@*/
03445     if (parseFormat(hsa, hsa->fmt, &hsa->format, &hsa->numTokens, NULL, PARSER_BEGIN))
03446         goto exit;
03447 /*@=boundswrite@*/
03448 
03449     hsa->ec = rpmecNew(hsa->exts);
03450     hsa->val = xstrdup("");
03451 
03452     tag =
03453         (hsa->format->type == PTOK_TAG
03454             ? &hsa->format->u.tag :
03455         (hsa->format->type == PTOK_ARRAY
03456             ? &hsa->format->u.array.format->u.tag :
03457         NULL));
03458     isxml = (tag != NULL && tag->tag == -2 && tag->type != NULL && !strcmp(tag->type, "xml"));
03459 
03460     if (isxml) {
03461         need = sizeof("<rpmHeader>\n") - 1;
03462         t = hsaReserve(hsa, need);
03463 /*@-boundswrite@*/
03464         te = stpcpy(t, "<rpmHeader>\n");
03465 /*@=boundswrite@*/
03466         hsa->vallen += (te - t);
03467     }
03468 
03469     hsa = hsaInit(hsa);
03470     while ((nextfmt = hsaNext(hsa)) != NULL) {
03471         te = singleSprintf(hsa, nextfmt, 0);
03472         if (te == NULL) {
03473             hsa->val = _free(hsa->val);
03474             break;
03475         }
03476     }
03477     hsa = hsaFini(hsa);
03478 
03479     if (isxml) {
03480         need = sizeof("</rpmHeader>\n") - 1;
03481         t = hsaReserve(hsa, need);
03482 /*@-boundswrite@*/
03483         te = stpcpy(t, "</rpmHeader>\n");
03484 /*@=boundswrite@*/
03485         hsa->vallen += (te - t);
03486     }
03487 
03488     if (hsa->val != NULL && hsa->vallen < hsa->alloced)
03489         hsa->val = xrealloc(hsa->val, hsa->vallen+1);   
03490 
03491     hsa->ec = rpmecFree(hsa->exts, hsa->ec);
03492     hsa->format = freeFormat(hsa->format, hsa->numTokens);
03493 
03494 exit:
03495 /*@-dependenttrans -observertrans @*/
03496     if (errmsg)
03497         *errmsg = hsa->errmsg;
03498 /*@=dependenttrans =observertrans @*/
03499     hsa->h = headerFree(hsa->h);
03500     hsa->fmt = _free(hsa->fmt);
03501     return hsa->val;
03502 }
03503 
03512 static char * octalFormat(int_32 type, hPTR_t data, 
03513                 char * formatPrefix, int padding, /*@unused@*/int element)
03514         /*@modifies formatPrefix @*/
03515 {
03516     char * val;
03517 
03518     if (type != RPM_INT32_TYPE) {
03519         val = xstrdup(_("(not a number)"));
03520     } else {
03521         val = xmalloc(20 + padding);
03522 /*@-boundswrite@*/
03523         strcat(formatPrefix, "o");
03524 /*@=boundswrite@*/
03525         /*@-formatconst@*/
03526         sprintf(val, formatPrefix, *((int_32 *) data));
03527         /*@=formatconst@*/
03528     }
03529 
03530     return val;
03531 }
03532 
03541 static char * hexFormat(int_32 type, hPTR_t data, 
03542                 char * formatPrefix, int padding, /*@unused@*/int element)
03543         /*@modifies formatPrefix @*/
03544 {
03545     char * val;
03546 
03547     if (type != RPM_INT32_TYPE) {
03548         val = xstrdup(_("(not a number)"));
03549     } else {
03550         val = xmalloc(20 + padding);
03551 /*@-boundswrite@*/
03552         strcat(formatPrefix, "x");
03553 /*@=boundswrite@*/
03554         /*@-formatconst@*/
03555         sprintf(val, formatPrefix, *((int_32 *) data));
03556         /*@=formatconst@*/
03557     }
03558 
03559     return val;
03560 }
03561 
03564 static char * realDateFormat(int_32 type, hPTR_t data, 
03565                 char * formatPrefix, int padding, /*@unused@*/int element,
03566                 const char * strftimeFormat)
03567         /*@modifies formatPrefix @*/
03568 {
03569     char * val;
03570 
03571     if (type != RPM_INT32_TYPE) {
03572         val = xstrdup(_("(not a number)"));
03573     } else {
03574         struct tm * tstruct;
03575         char buf[50];
03576 
03577         val = xmalloc(50 + padding);
03578 /*@-boundswrite@*/
03579         strcat(formatPrefix, "s");
03580 /*@=boundswrite@*/
03581 
03582         /* this is important if sizeof(int_32) ! sizeof(time_t) */
03583         {   time_t dateint = *((int_32 *) data);
03584             tstruct = localtime(&dateint);
03585         }
03586         buf[0] = '\0';
03587         if (tstruct)
03588             (void) strftime(buf, sizeof(buf) - 1, strftimeFormat, tstruct);
03589         /*@-formatconst@*/
03590         sprintf(val, formatPrefix, buf);
03591         /*@=formatconst@*/
03592     }
03593 
03594     return val;
03595 }
03596 
03605 static char * dateFormat(int_32 type, hPTR_t data, 
03606                          char * formatPrefix, int padding, int element)
03607         /*@modifies formatPrefix @*/
03608 {
03609     return realDateFormat(type, data, formatPrefix, padding, element,
03610                         _("%c"));
03611 }
03612 
03621 static char * dayFormat(int_32 type, hPTR_t data, 
03622                          char * formatPrefix, int padding, int element)
03623         /*@modifies formatPrefix @*/
03624 {
03625     return realDateFormat(type, data, formatPrefix, padding, element, 
03626                           _("%a %b %d %Y"));
03627 }
03628 
03637 static char * shescapeFormat(int_32 type, hPTR_t data, 
03638                 char * formatPrefix, int padding, /*@unused@*/int element)
03639         /*@modifies formatPrefix @*/
03640 {
03641     char * result, * dst, * src, * buf;
03642 
03643     if (type == RPM_INT32_TYPE) {
03644         result = xmalloc(padding + 20);
03645 /*@-boundswrite@*/
03646         strcat(formatPrefix, "d");
03647 /*@=boundswrite@*/
03648         /*@-formatconst@*/
03649         sprintf(result, formatPrefix, *((int_32 *) data));
03650         /*@=formatconst@*/
03651     } else {
03652         buf = alloca(strlen(data) + padding + 2);
03653 /*@-boundswrite@*/
03654         strcat(formatPrefix, "s");
03655 /*@=boundswrite@*/
03656         /*@-formatconst@*/
03657         sprintf(buf, formatPrefix, data);
03658         /*@=formatconst@*/
03659 
03660 /*@-boundswrite@*/
03661         result = dst = xmalloc(strlen(buf) * 4 + 3);
03662         *dst++ = '\'';
03663         for (src = buf; *src != '\0'; src++) {
03664             if (*src == '\'') {
03665                 *dst++ = '\'';
03666                 *dst++ = '\\';
03667                 *dst++ = '\'';
03668                 *dst++ = '\'';
03669             } else {
03670                 *dst++ = *src;
03671             }
03672         }
03673         *dst++ = '\'';
03674         *dst = '\0';
03675 /*@=boundswrite@*/
03676 
03677     }
03678 
03679     return result;
03680 }
03681 
03682 /*@-type@*/ /* FIX: cast? */
03683 const struct headerSprintfExtension_s headerDefaultFormats[] = {
03684     { HEADER_EXT_FORMAT, "octal", { octalFormat } },
03685     { HEADER_EXT_FORMAT, "hex", { hexFormat } },
03686     { HEADER_EXT_FORMAT, "date", { dateFormat } },
03687     { HEADER_EXT_FORMAT, "day", { dayFormat } },
03688     { HEADER_EXT_FORMAT, "shescape", { shescapeFormat } },
03689     { HEADER_EXT_LAST, NULL, { NULL } }
03690 };
03691 /*@=type@*/
03692 
03699 static
03700 void headerCopyTags(Header headerFrom, Header headerTo, hTAG_t tagstocopy)
03701         /*@modifies headerTo @*/
03702 {
03703     int * p;
03704 
03705     if (headerFrom == headerTo)
03706         return;
03707 
03708     for (p = tagstocopy; *p != 0; p++) {
03709         char *s;
03710         int_32 type;
03711         int_32 count;
03712         if (headerIsEntry(headerTo, *p))
03713             continue;
03714 /*@-boundswrite@*/
03715         if (!headerGetEntryMinMemory(headerFrom, *p, &type,
03716                                 (hPTR_t *) &s, &count))
03717             continue;
03718 /*@=boundswrite@*/
03719         (void) headerAddEntry(headerTo, *p, type, s, count);
03720         s = headerFreeData(s, type);
03721     }
03722 }
03723 
03724 /*@observer@*/ /*@unchecked@*/
03725 static struct HV_s hdrVec1 = {
03726     headerLink,
03727     headerUnlink,
03728     headerFree,
03729     headerNew,
03730     headerSort,
03731     headerUnsort,
03732     headerSizeof,
03733     headerUnload,
03734     headerReload,
03735     headerCopy,
03736     headerLoad,
03737     headerCopyLoad,
03738     headerRead,
03739     headerWrite,
03740     headerIsEntry,
03741     headerFreeTag,
03742     headerGetEntry,
03743     headerGetEntryMinMemory,
03744     headerAddEntry,
03745     headerAppendEntry,
03746     headerAddOrAppendEntry,
03747     headerAddI18NString,
03748     headerModifyEntry,
03749     headerRemoveEntry,
03750     headerSprintf,
03751     headerCopyTags,
03752     headerFreeIterator,
03753     headerInitIterator,
03754     headerNextIterator,
03755     NULL, NULL,
03756     1
03757 };
03758 
03759 /*@-compmempass -redef@*/
03760 /*@observer@*/ /*@unchecked@*/
03761 HV_t hdrVec = &hdrVec1;
03762 /*@=compmempass =redef@*/

Generated on Sun Apr 8 21:11:09 2012 for rpm by  doxygen 1.3.9.1