rpmdb/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 <rpmio_internal.h>     /* XXX for fdGetOPath() */
00016 #include <header_internal.h>
00017 
00018 #include "debug.h"
00019 
00020 /*@unchecked@*/
00021 int _hdr_debug = 0;
00022 
00023 /*@access entryInfo @*/
00024 /*@access indexEntry @*/
00025 
00026 /*@access rpmec @*/
00027 /*@access sprintfTag @*/
00028 /*@access sprintfToken @*/
00029 /*@access HV_t @*/
00030 
00031 #define PARSER_BEGIN    0
00032 #define PARSER_IN_ARRAY 1
00033 #define PARSER_IN_EXPR  2
00034 
00037 /*@observer@*/ /*@unchecked@*/
00038 static unsigned char header_magic[8] = {
00039         0x8e, 0xad, 0xe8, 0x01, 0x00, 0x00, 0x00, 0x00
00040 };
00041 
00045 /*@observer@*/ /*@unchecked@*/
00046 static int typeAlign[16] =  {
00047     1,  
00048     1,  
00049     1,  
00050     2,  
00051     4,  
00052     8,  
00053     1,  
00054     1,  
00055     1,  
00056     1,  
00057     1,  
00058     1,  
00059     0,
00060     0,
00061     0,
00062     0
00063 };
00064 
00068 /*@observer@*/ /*@unchecked@*/
00069 static int typeSizes[16] =  { 
00070     0,  
00071     1,  
00072     1,  
00073     2,  
00074     4,  
00075     8,  
00076     -1, 
00077     1,  
00078     -1, 
00079     -1, 
00080     1,  
00081     1,  
00082     0,
00083     0,
00084     0,
00085     0
00086 };
00087 
00091 /*@unchecked@*/
00092 static size_t headerMaxbytes = (32*1024*1024);
00093 
00098 #define hdrchkTags(_ntags)      ((_ntags) & 0xffff0000)
00099 
00103 #define hdrchkType(_type) ((_type) < RPM_MIN_TYPE || (_type) > RPM_MAX_TYPE)
00104 
00109 #define hdrchkData(_nbytes)     ((_nbytes) & 0xff000000)
00110 
00114 #define hdrchkAlign(_type, _off)        ((_off) & (typeAlign[_type]-1))
00115 
00119 #define hdrchkRange(_dl, _off)          ((_off) < 0 || (_off) > (_dl))
00120 
00121 /*@observer@*/ /*@unchecked@*/
00122 HV_t hdrVec;    /* forward reference */
00123 
00129 static
00130 Header headerLink(Header h)
00131         /*@modifies h @*/
00132 {
00133 /*@-nullret@*/
00134     if (h == NULL) return NULL;
00135 /*@=nullret@*/
00136 
00137     h->nrefs++;
00138 /*@-modfilesys@*/
00139 if (_hdr_debug)
00140 fprintf(stderr, "--> h  %p ++ %d at %s:%u\n", h, h->nrefs, __FILE__, __LINE__);
00141 /*@=modfilesys@*/
00142 
00143     /*@-refcounttrans @*/
00144     return h;
00145     /*@=refcounttrans @*/
00146 }
00147 
00153 static /*@null@*/
00154 Header headerUnlink(/*@killref@*/ /*@null@*/ Header h)
00155         /*@modifies h @*/
00156 {
00157     if (h == NULL) return NULL;
00158 /*@-modfilesys@*/
00159 if (_hdr_debug)
00160 fprintf(stderr, "--> h  %p -- %d at %s:%u\n", h, h->nrefs, __FILE__, __LINE__);
00161 /*@=modfilesys@*/
00162     h->nrefs--;
00163     return NULL;
00164 }
00165 
00171 static /*@null@*/
00172 Header headerFree(/*@killref@*/ /*@null@*/ Header h)
00173         /*@modifies h @*/
00174 {
00175     (void) headerUnlink(h);
00176 
00177     /*@-usereleased@*/
00178     if (h == NULL || h->nrefs > 0)
00179         return NULL;    /* XXX return previous header? */
00180 
00181     if (h->index) {
00182         indexEntry entry = h->index;
00183         int i;
00184         for (i = 0; i < h->indexUsed; i++, entry++) {
00185             if ((h->flags & HEADERFLAG_ALLOCATED) && ENTRY_IS_REGION(entry)) {
00186                 if (entry->length > 0) {
00187                     int_32 * ei = entry->data;
00188                     if ((ei - 2) == h->blob) h->blob = _free(h->blob);
00189                     entry->data = NULL;
00190                 }
00191             } else if (!ENTRY_IN_REGION(entry)) {
00192                 entry->data = _free(entry->data);
00193             }
00194             entry->data = NULL;
00195         }
00196         h->index = _free(h->index);
00197     }
00198     h->origin = _free(h->origin);
00199 
00200     /*@-refcounttrans@*/ h = _free(h); /*@=refcounttrans@*/
00201     return h;
00202     /*@=usereleased@*/
00203 }
00204 
00209 static
00210 Header headerNew(void)
00211         /*@*/
00212 {
00213     Header h = xcalloc(1, sizeof(*h));
00214 
00215 /*@-boundsread@*/
00216     /*@-assignexpose@*/
00217     h->hv = *hdrVec;            /* structure assignment */
00218     /*@=assignexpose@*/
00219 /*@=boundsread@*/
00220     h->blob = NULL;
00221     h->origin = NULL;
00222     h->instance = 0;
00223     h->indexAlloced = INDEX_MALLOC_SIZE;
00224     h->indexUsed = 0;
00225     h->flags |= HEADERFLAG_SORTED;
00226 
00227     h->index = (h->indexAlloced
00228         ? xcalloc(h->indexAlloced, sizeof(*h->index))
00229         : NULL);
00230 
00231     h->nrefs = 0;
00232     /*@-globstate -observertrans @*/
00233     return headerLink(h);
00234     /*@=globstate =observertrans @*/
00235 }
00236 
00239 static int indexCmp(const void * avp, const void * bvp)
00240         /*@*/
00241 {
00242     /*@-castexpose@*/
00243     indexEntry ap = (indexEntry) avp, bp = (indexEntry) bvp;
00244     /*@=castexpose@*/
00245     return (ap->info.tag - bp->info.tag);
00246 }
00247 
00252 static
00253 void headerSort(Header h)
00254         /*@modifies h @*/
00255 {
00256     if (!(h->flags & HEADERFLAG_SORTED)) {
00257 /*@-boundsread@*/
00258         qsort(h->index, h->indexUsed, sizeof(*h->index), indexCmp);
00259 /*@=boundsread@*/
00260         h->flags |= HEADERFLAG_SORTED;
00261     }
00262 }
00263 
00266 static int offsetCmp(const void * avp, const void * bvp) /*@*/
00267 {
00268     /*@-castexpose@*/
00269     indexEntry ap = (indexEntry) avp, bp = (indexEntry) bvp;
00270     /*@=castexpose@*/
00271     int rc = (ap->info.offset - bp->info.offset);
00272 
00273     if (rc == 0) {
00274         /* Within a region, entries sort by address. Added drips sort by tag. */
00275         if (ap->info.offset < 0)
00276             rc = (((char *)ap->data) - ((char *)bp->data));
00277         else
00278             rc = (ap->info.tag - bp->info.tag);
00279     }
00280     return rc;
00281 }
00282 
00287 static
00288 void headerUnsort(Header h)
00289         /*@modifies h @*/
00290 {
00291 /*@-boundsread@*/
00292     qsort(h->index, h->indexUsed, sizeof(*h->index), offsetCmp);
00293 /*@=boundsread@*/
00294 }
00295 
00302 static
00303 unsigned int headerSizeof(/*@null@*/ Header h, enum hMagic magicp)
00304         /*@modifies h @*/
00305 {
00306     indexEntry entry;
00307     unsigned int size = 0;
00308     unsigned int pad = 0;
00309     int i;
00310 
00311     if (h == NULL)
00312         return size;
00313 
00314     headerSort(h);
00315 
00316     switch (magicp) {
00317     case HEADER_MAGIC_YES:
00318         size += sizeof(header_magic);
00319         break;
00320     case HEADER_MAGIC_NO:
00321         break;
00322     }
00323 
00324     /*@-sizeoftype@*/
00325     size += 2 * sizeof(int_32); /* count of index entries */
00326     /*@=sizeoftype@*/
00327 
00328     for (i = 0, entry = h->index; i < h->indexUsed; i++, entry++) {
00329         unsigned diff;
00330         int_32 type;
00331 
00332         /* Regions go in as is ... */
00333         if (ENTRY_IS_REGION(entry)) {
00334             size += entry->length;
00335             /* XXX Legacy regions do not include the region tag and data. */
00336             /*@-sizeoftype@*/
00337             if (i == 0 && (h->flags & HEADERFLAG_LEGACY))
00338                 size += sizeof(struct entryInfo_s) + entry->info.count;
00339             /*@=sizeoftype@*/
00340             continue;
00341         }
00342 
00343         /* ... and region elements are skipped. */
00344         if (entry->info.offset < 0)
00345             continue;
00346 
00347         /* Alignment */
00348         type = entry->info.type;
00349 /*@-boundsread@*/
00350         if (typeSizes[type] > 1) {
00351             diff = typeSizes[type] - (size % typeSizes[type]);
00352             if (diff != typeSizes[type]) {
00353                 size += diff;
00354                 pad += diff;
00355             }
00356         }
00357 /*@=boundsread@*/
00358 
00359         /*@-sizeoftype@*/
00360         size += sizeof(struct entryInfo_s) + entry->length;
00361         /*@=sizeoftype@*/
00362     }
00363 
00364     return size;
00365 }
00366 
00376 static int dataLength(int_32 type, hPTR_t p, int_32 count, int onDisk,
00377                 /*@null@*/ hPTR_t pend)
00378         /*@*/
00379 {
00380     const unsigned char * s = p;
00381     const unsigned char * se = pend;
00382     int length = 0;
00383 
00384     switch (type) {
00385     case RPM_STRING_TYPE:
00386         if (count != 1)
00387             return -1;
00388 /*@-boundsread@*/
00389         while (*s++) {
00390             if (se && s > se)
00391                 return -1;
00392             length++;
00393         }
00394 /*@=boundsread@*/
00395         length++;       /* count nul terminator too. */
00396         break;
00397 
00398     case RPM_STRING_ARRAY_TYPE:
00399     case RPM_I18NSTRING_TYPE:
00400         /* These are like RPM_STRING_TYPE, except they're *always* an array */
00401         /* Compute sum of length of all strings, including nul terminators */
00402 
00403         if (onDisk) {
00404             while (count--) {
00405                 length++;       /* count nul terminator too */
00406 /*@-boundsread@*/
00407                while (*s++) {
00408                     if (se && s > se)
00409                         return -1;
00410                     length++;
00411                 }
00412 /*@=boundsread@*/
00413             }
00414         } else {
00415             const char ** av = (const char **)p;
00416 /*@-boundsread@*/
00417             while (count--) {
00418                 /* add one for null termination */
00419                 length += strlen(*av++) + 1;
00420             }
00421 /*@=boundsread@*/
00422         }
00423         break;
00424 
00425     default:
00426 /*@-boundsread@*/
00427         if (typeSizes[type] == -1)
00428             return -1;
00429         length = typeSizes[(type & 0xf)] * count;
00430 /*@=boundsread@*/
00431         if (length < 0 || (se && (s + length) > se))
00432             return -1;
00433         break;
00434     }
00435 
00436     return length;
00437 }
00438 
00465 static int regionSwab(/*@null@*/ indexEntry entry, int il, int dl,
00466                 entryInfo pe,
00467                 unsigned char * dataStart,
00468                 /*@null@*/ const unsigned char * dataEnd,
00469                 int regionid)
00470         /*@modifies *entry, *dataStart @*/
00471 {
00472     unsigned char * tprev = NULL;
00473     unsigned char * t = NULL;
00474     int tdel = 0;
00475     int tl = dl;
00476     struct indexEntry_s ieprev;
00477 
00478 /*@-boundswrite@*/
00479     memset(&ieprev, 0, sizeof(ieprev));
00480 /*@=boundswrite@*/
00481     for (; il > 0; il--, pe++) {
00482         struct indexEntry_s ie;
00483         int_32 type;
00484 
00485         ie.info.tag = ntohl(pe->tag);
00486         ie.info.type = ntohl(pe->type);
00487         ie.info.count = ntohl(pe->count);
00488         ie.info.offset = ntohl(pe->offset);
00489 
00490         if (hdrchkType(ie.info.type))
00491             return -1;
00492         if (hdrchkData(ie.info.count))
00493             return -1;
00494         if (hdrchkData(ie.info.offset))
00495             return -1;
00496 /*@-boundsread@*/
00497         if (hdrchkAlign(ie.info.type, ie.info.offset))
00498             return -1;
00499 /*@=boundsread@*/
00500 
00501         ie.data = t = dataStart + ie.info.offset;
00502         if (dataEnd && t >= dataEnd)
00503             return -1;
00504 
00505         ie.length = dataLength(ie.info.type, ie.data, ie.info.count, 1, dataEnd);
00506         if (ie.length < 0 || hdrchkData(ie.length))
00507             return -1;
00508 
00509         ie.rdlen = 0;
00510 
00511         if (entry) {
00512             ie.info.offset = regionid;
00513 /*@-boundswrite@*/
00514             *entry = ie;        /* structure assignment */
00515 /*@=boundswrite@*/
00516             entry++;
00517         }
00518 
00519         /* Alignment */
00520         type = ie.info.type;
00521 /*@-boundsread@*/
00522         if (typeSizes[type] > 1) {
00523             unsigned diff;
00524             diff = typeSizes[type] - (dl % typeSizes[type]);
00525             if (diff != typeSizes[type]) {
00526                 dl += diff;
00527                 if (ieprev.info.type == RPM_I18NSTRING_TYPE)
00528                     ieprev.length += diff;
00529             }
00530         }
00531 /*@=boundsread@*/
00532         tdel = (tprev ? (t - tprev) : 0);
00533         if (ieprev.info.type == RPM_I18NSTRING_TYPE)
00534             tdel = ieprev.length;
00535 
00536         if (ie.info.tag >= HEADER_I18NTABLE) {
00537             tprev = t;
00538         } else {
00539             tprev = dataStart;
00540             /* XXX HEADER_IMAGE tags don't include region sub-tag. */
00541             /*@-sizeoftype@*/
00542             if (ie.info.tag == HEADER_IMAGE)
00543                 tprev -= REGION_TAG_COUNT;
00544             /*@=sizeoftype@*/
00545         }
00546 
00547         /* Perform endian conversions */
00548         switch (ntohl(pe->type)) {
00549 /*@-bounds@*/
00550         case RPM_INT64_TYPE:
00551         {   int_64 * it = (int_64 *)t;
00552             int_32 b[2];
00553             for (; ie.info.count > 0; ie.info.count--, it += 1) {
00554                 if (dataEnd && ((unsigned char *)it) >= dataEnd)
00555                     return -1;
00556                 b[1] = htonl(((int_32 *)it)[0]);
00557                 b[0] = htonl(((int_32 *)it)[1]);
00558                 if (b[1] != ((int_32 *)it)[0])
00559                     memcpy(it, b, sizeof(b));
00560             }
00561             t = (char *) it;
00562         }   /*@switchbreak@*/ break;
00563         case RPM_INT32_TYPE:
00564         {   int_32 * it = (int_32 *)t;
00565             for (; ie.info.count > 0; ie.info.count--, it += 1) {
00566                 if (dataEnd && ((unsigned char *)it) >= dataEnd)
00567                     return -1;
00568                 *it = htonl(*it);
00569             }
00570             t = (char *) it;
00571         }   /*@switchbreak@*/ break;
00572         case RPM_INT16_TYPE:
00573         {   int_16 * it = (int_16 *) t;
00574             for (; ie.info.count > 0; ie.info.count--, it += 1) {
00575                 if (dataEnd && ((unsigned char *)it) >= dataEnd)
00576                     return -1;
00577                 *it = htons(*it);
00578             }
00579             t = (char *) it;
00580         }   /*@switchbreak@*/ break;
00581 /*@=bounds@*/
00582         default:
00583             t += ie.length;
00584             /*@switchbreak@*/ break;
00585         }
00586 
00587         dl += ie.length;
00588         if (dataEnd && dataStart + dl > dataEnd) return -1;
00589         tl += tdel;
00590         ieprev = ie;    /* structure assignment */
00591 
00592     }
00593     tdel = (tprev ? (t - tprev) : 0);
00594     tl += tdel;
00595 
00596     /* XXX
00597      * There are two hacks here:
00598      *  1) tl is 16b (i.e. REGION_TAG_COUNT) short while doing headerReload().
00599      *  2) the 8/98 rpm bug with inserting i18n tags needs to use tl, not dl.
00600      */
00601     /*@-sizeoftype@*/
00602     if (tl+REGION_TAG_COUNT == dl)
00603         tl += REGION_TAG_COUNT;
00604     /*@=sizeoftype@*/
00605 
00606     return dl;
00607 }
00608 
00614 static /*@only@*/ /*@null@*/ void * doHeaderUnload(Header h,
00615                 /*@out@*/ int * lengthPtr)
00616         /*@modifies h, *lengthPtr @*/
00617         /*@requires maxSet(lengthPtr) >= 0 @*/
00618         /*@ensures maxRead(result) == (*lengthPtr) @*/
00619 {
00620     int_32 * ei = NULL;
00621     entryInfo pe;
00622     char * dataStart;
00623     char * te;
00624     unsigned pad;
00625     unsigned len;
00626     int_32 il = 0;
00627     int_32 dl = 0;
00628     indexEntry entry; 
00629     int_32 type;
00630     int i;
00631     int drlen, ndribbles;
00632     int driplen, ndrips;
00633     int legacy = 0;
00634 
00635     /* Sort entries by (offset,tag). */
00636     headerUnsort(h);
00637 
00638     /* Compute (il,dl) for all tags, including those deleted in region. */
00639     pad = 0;
00640     drlen = ndribbles = driplen = ndrips = 0;
00641     for (i = 0, entry = h->index; i < h->indexUsed; i++, entry++) {
00642         if (ENTRY_IS_REGION(entry)) {
00643             int_32 rdl = -entry->info.offset;   /* negative offset */
00644             int_32 ril = rdl/sizeof(*pe);
00645             int rid = entry->info.offset;
00646 
00647             il += ril;
00648             dl += entry->rdlen + entry->info.count;
00649             /* XXX Legacy regions do not include the region tag and data. */
00650             if (i == 0 && (h->flags & HEADERFLAG_LEGACY))
00651                 il += 1;
00652 
00653             /* Skip rest of entries in region, but account for dribbles. */
00654             for (; i < h->indexUsed && entry->info.offset <= rid+1; i++, entry++) {
00655                 if (entry->info.offset <= rid)
00656                     /*@innercontinue@*/ continue;
00657 
00658                 /* Alignment */
00659                 type = entry->info.type;
00660                 if (typeSizes[type] > 1) {
00661                     unsigned diff;
00662                     diff = typeSizes[type] - (dl % typeSizes[type]);
00663                     if (diff != typeSizes[type]) {
00664                         drlen += diff;
00665                         pad += diff;
00666                         dl += diff;
00667                     }
00668                 }
00669 
00670                 ndribbles++;
00671                 il++;
00672                 drlen += entry->length;
00673                 dl += entry->length;
00674             }
00675             i--;
00676             entry--;
00677             continue;
00678         }
00679 
00680         /* Ignore deleted drips. */
00681         if (entry->data == NULL || entry->length <= 0)
00682             continue;
00683 
00684         /* Alignment */
00685         type = entry->info.type;
00686         if (typeSizes[type] > 1) {
00687             unsigned diff;
00688             diff = typeSizes[type] - (dl % typeSizes[type]);
00689             if (diff != typeSizes[type]) {
00690                 driplen += diff;
00691                 pad += diff;
00692                 dl += diff;
00693             } else
00694                 diff = 0;
00695         }
00696 
00697         ndrips++;
00698         il++;
00699         driplen += entry->length;
00700         dl += entry->length;
00701     }
00702 
00703     /* Sanity checks on header intro. */
00704     if (hdrchkTags(il) || hdrchkData(dl))
00705         goto errxit;
00706 
00707     len = sizeof(il) + sizeof(dl) + (il * sizeof(*pe)) + dl;
00708 
00709 /*@-boundswrite@*/
00710     ei = xmalloc(len);
00711     ei[0] = htonl(il);
00712     ei[1] = htonl(dl);
00713 /*@=boundswrite@*/
00714 
00715     pe = (entryInfo) &ei[2];
00716     dataStart = te = (char *) (pe + il);
00717 
00718     pad = 0;
00719     for (i = 0, entry = h->index; i < h->indexUsed; i++, entry++) {
00720         const char * src;
00721 char *t;
00722         int count;
00723         int rdlen;
00724 
00725         if (entry->data == NULL || entry->length <= 0)
00726             continue;
00727 
00728 t = te;
00729         pe->tag = htonl(entry->info.tag);
00730         pe->type = htonl(entry->info.type);
00731         pe->count = htonl(entry->info.count);
00732 
00733         if (ENTRY_IS_REGION(entry)) {
00734             int_32 rdl = -entry->info.offset;   /* negative offset */
00735             int_32 ril = rdl/sizeof(*pe) + ndribbles;
00736             int rid = entry->info.offset;
00737 
00738             src = (char *)entry->data;
00739             rdlen = entry->rdlen;
00740 
00741             /* XXX Legacy regions do not include the region tag and data. */
00742             if (i == 0 && (h->flags & HEADERFLAG_LEGACY)) {
00743                 int_32 stei[4];
00744 
00745                 legacy = 1;
00746 /*@-boundswrite@*/
00747                 memcpy(pe+1, src, rdl);
00748                 memcpy(te, src + rdl, rdlen);
00749 /*@=boundswrite@*/
00750                 te += rdlen;
00751 
00752                 pe->offset = htonl(te - dataStart);
00753                 stei[0] = pe->tag;
00754                 stei[1] = pe->type;
00755                 stei[2] = htonl(-rdl-entry->info.count);
00756                 stei[3] = pe->count;
00757 /*@-boundswrite@*/
00758                 memcpy(te, stei, entry->info.count);
00759 /*@=boundswrite@*/
00760                 te += entry->info.count;
00761                 ril++;
00762                 rdlen += entry->info.count;
00763 
00764                 count = regionSwab(NULL, ril, 0, pe, t, NULL, 0);
00765                 if (count != rdlen)
00766                     goto errxit;
00767 
00768             } else {
00769 
00770 /*@-boundswrite@*/
00771                 memcpy(pe+1, src + sizeof(*pe), ((ril-1) * sizeof(*pe)));
00772                 memcpy(te, src + (ril * sizeof(*pe)), rdlen+entry->info.count+drlen);
00773 /*@=boundswrite@*/
00774                 te += rdlen;
00775                 {   /*@-castexpose@*/
00776                     entryInfo se = (entryInfo)src;
00777                     /*@=castexpose@*/
00778                     int off = ntohl(se->offset);
00779                     pe->offset = (off) ? htonl(te - dataStart) : htonl(off);
00780                 }
00781                 te += entry->info.count + drlen;
00782 
00783                 count = regionSwab(NULL, ril, 0, pe, t, NULL, 0);
00784                 if (count != (rdlen + entry->info.count + drlen))
00785                     goto errxit;
00786             }
00787 
00788             /* Skip rest of entries in region. */
00789             while (i < h->indexUsed && entry->info.offset <= rid+1) {
00790                 i++;
00791                 entry++;
00792             }
00793             i--;
00794             entry--;
00795             pe += ril;
00796             continue;
00797         }
00798 
00799         /* Ignore deleted drips. */
00800         if (entry->data == NULL || entry->length <= 0)
00801             continue;
00802 
00803         /* Alignment */
00804         type = entry->info.type;
00805         if (typeSizes[type] > 1) {
00806             unsigned diff;
00807             diff = typeSizes[type] - ((te - dataStart) % typeSizes[type]);
00808             if (diff != typeSizes[type]) {
00809 /*@-boundswrite@*/
00810                 memset(te, 0, diff);
00811 /*@=boundswrite@*/
00812                 te += diff;
00813                 pad += diff;
00814             }
00815         }
00816 
00817         pe->offset = htonl(te - dataStart);
00818 
00819         /* copy data w/ endian conversions */
00820 /*@-boundswrite@*/
00821         switch (entry->info.type) {
00822         case RPM_INT64_TYPE:
00823         {   int_32 b[2];
00824             count = entry->info.count;
00825             src = entry->data;
00826             while (count--) {
00827                 b[1] = htonl(((int_32 *)src)[0]);
00828                 b[0] = htonl(((int_32 *)src)[1]);
00829                 if (b[1] == ((int_32 *)src)[0])
00830                     memcpy(te, src, sizeof(b));
00831                 else
00832                     memcpy(te, b, sizeof(b));
00833                 te += sizeof(b);
00834                 src += sizeof(b);
00835             }
00836         }   /*@switchbreak@*/ break;
00837 
00838         case RPM_INT32_TYPE:
00839             count = entry->info.count;
00840             src = entry->data;
00841             while (count--) {
00842                 *((int_32 *)te) = htonl(*((int_32 *)src));
00843                 /*@-sizeoftype@*/
00844                 te += sizeof(int_32);
00845                 src += sizeof(int_32);
00846                 /*@=sizeoftype@*/
00847             }
00848             /*@switchbreak@*/ break;
00849 
00850         case RPM_INT16_TYPE:
00851             count = entry->info.count;
00852             src = entry->data;
00853             while (count--) {
00854                 *((int_16 *)te) = htons(*((int_16 *)src));
00855                 /*@-sizeoftype@*/
00856                 te += sizeof(int_16);
00857                 src += sizeof(int_16);
00858                 /*@=sizeoftype@*/
00859             }
00860             /*@switchbreak@*/ break;
00861 
00862         default:
00863             memcpy(te, entry->data, entry->length);
00864             te += entry->length;
00865             /*@switchbreak@*/ break;
00866         }
00867 /*@=boundswrite@*/
00868         pe++;
00869     }
00870    
00871     /* Insure that there are no memcpy underruns/overruns. */
00872     if (((char *)pe) != dataStart)
00873         goto errxit;
00874     if ((((char *)ei)+len) != te)
00875         goto errxit;
00876 
00877     if (lengthPtr)
00878         *lengthPtr = len;
00879 
00880     h->flags &= ~HEADERFLAG_SORTED;
00881     headerSort(h);
00882 
00883     return (void *) ei;
00884 
00885 errxit:
00886     /*@-usereleased@*/
00887     ei = _free(ei);
00888     /*@=usereleased@*/
00889     return (void *) ei;
00890 }
00891 
00897 static /*@only@*/ /*@null@*/
00898 void * headerUnload(Header h)
00899         /*@modifies h @*/
00900 {
00901     int length;
00902 /*@-boundswrite@*/
00903     void * uh = doHeaderUnload(h, &length);
00904 /*@=boundswrite@*/
00905     return uh;
00906 }
00907 
00915 static /*@null@*/
00916 indexEntry findEntry(/*@null@*/ Header h, int_32 tag, int_32 type)
00917         /*@modifies h @*/
00918 {
00919     indexEntry entry, entry2, last;
00920     struct indexEntry_s key;
00921 
00922     if (h == NULL) return NULL;
00923     if (!(h->flags & HEADERFLAG_SORTED)) headerSort(h);
00924 
00925     key.info.tag = tag;
00926 
00927 /*@-boundswrite@*/
00928     entry2 = entry = 
00929         bsearch(&key, h->index, h->indexUsed, sizeof(*h->index), indexCmp);
00930 /*@=boundswrite@*/
00931     if (entry == NULL)
00932         return NULL;
00933 
00934     if (type == RPM_NULL_TYPE)
00935         return entry;
00936 
00937     /* look backwards */
00938     while (entry->info.tag == tag && entry->info.type != type &&
00939            entry > h->index) entry--;
00940 
00941     if (entry->info.tag == tag && entry->info.type == type)
00942         return entry;
00943 
00944     last = h->index + h->indexUsed;
00945     /*@-usereleased@*/ /* FIX: entry2 = entry. Code looks bogus as well. */
00946     while (entry2->info.tag == tag && entry2->info.type != type &&
00947            entry2 < last) entry2++;
00948     /*@=usereleased@*/
00949 
00950     if (entry->info.tag == tag && entry->info.type == type)
00951         return entry;
00952 
00953     return NULL;
00954 }
00955 
00965 static
00966 int headerRemoveEntry(Header h, int_32 tag)
00967         /*@modifies h @*/
00968 {
00969     indexEntry last = h->index + h->indexUsed;
00970     indexEntry entry, first;
00971     int ne;
00972 
00973     entry = findEntry(h, tag, RPM_NULL_TYPE);
00974     if (!entry) return 1;
00975 
00976     /* Make sure entry points to the first occurence of this tag. */
00977     while (entry > h->index && (entry - 1)->info.tag == tag)  
00978         entry--;
00979 
00980     /* Free data for tags being removed. */
00981     for (first = entry; first < last; first++) {
00982         void * data;
00983         if (first->info.tag != tag)
00984             break;
00985         data = first->data;
00986         first->data = NULL;
00987         first->length = 0;
00988         if (ENTRY_IN_REGION(first))
00989             continue;
00990         data = _free(data);
00991     }
00992 
00993     ne = (first - entry);
00994     if (ne > 0) {
00995         h->indexUsed -= ne;
00996         ne = last - first;
00997 /*@-boundswrite@*/
00998         if (ne > 0)
00999             memmove(entry, first, (ne * sizeof(*entry)));
01000 /*@=boundswrite@*/
01001     }
01002 
01003     return 0;
01004 }
01005 
01011 static /*@null@*/
01012 Header headerLoad(/*@kept@*/ void * uh)
01013         /*@modifies uh @*/
01014 {
01015     int_32 * ei = (int_32 *) uh;
01016     int_32 il = ntohl(ei[0]);           /* index length */
01017     int_32 dl = ntohl(ei[1]);           /* data length */
01018     /*@-sizeoftype@*/
01019     size_t pvlen = sizeof(il) + sizeof(dl) +
01020                (il * sizeof(struct entryInfo_s)) + dl;
01021     /*@=sizeoftype@*/
01022     void * pv = uh;
01023     Header h = NULL;
01024     entryInfo pe;
01025     unsigned char * dataStart;
01026     unsigned char * dataEnd;
01027     indexEntry entry; 
01028     int rdlen;
01029     int i;
01030 
01031     /* Sanity checks on header intro. */
01032     if (hdrchkTags(il) || hdrchkData(dl))
01033         goto errxit;
01034 
01035     ei = (int_32 *) pv;
01036     /*@-castexpose@*/
01037     pe = (entryInfo) &ei[2];
01038     /*@=castexpose@*/
01039     dataStart = (unsigned char *) (pe + il);
01040     dataEnd = dataStart + dl;
01041 
01042     h = xcalloc(1, sizeof(*h));
01043     /*@-assignexpose@*/
01044     h->hv = *hdrVec;            /* structure assignment */
01045     /*@=assignexpose@*/
01046     /*@-assignexpose -kepttrans@*/
01047     h->blob = uh;
01048     /*@=assignexpose =kepttrans@*/
01049     h->indexAlloced = il + 1;
01050     h->indexUsed = il;
01051     h->index = xcalloc(h->indexAlloced, sizeof(*h->index));
01052     h->flags |= HEADERFLAG_SORTED;
01053     h->nrefs = 0;
01054     h = headerLink(h);
01055 
01056     /*
01057      * XXX XFree86-libs, ash, and pdksh from Red Hat 5.2 have bogus
01058      * %verifyscript tag that needs to be diddled.
01059      */
01060     if (ntohl(pe->tag) == 15 &&
01061         ntohl(pe->type) == RPM_STRING_TYPE &&
01062         ntohl(pe->count) == 1)
01063     {
01064         pe->tag = htonl(1079);
01065     }
01066 
01067     entry = h->index;
01068     i = 0;
01069     if (!(htonl(pe->tag) < HEADER_I18NTABLE)) {
01070         h->flags |= HEADERFLAG_LEGACY;
01071         entry->info.type = REGION_TAG_TYPE;
01072         entry->info.tag = HEADER_IMAGE;
01073         /*@-sizeoftype@*/
01074         entry->info.count = REGION_TAG_COUNT;
01075         /*@=sizeoftype@*/
01076         entry->info.offset = ((unsigned char *)pe - dataStart); /* negative offset */
01077 
01078         /*@-assignexpose@*/
01079         entry->data = pe;
01080         /*@=assignexpose@*/
01081         entry->length = pvlen - sizeof(il) - sizeof(dl);
01082         rdlen = regionSwab(entry+1, il, 0, pe, dataStart, dataEnd, entry->info.offset);
01083 #if 0   /* XXX don't check, the 8/98 i18n bug fails here. */
01084         if (rdlen != dl)
01085             goto errxit;
01086 #endif
01087         entry->rdlen = rdlen;
01088         entry++;
01089         h->indexUsed++;
01090     } else {
01091         int_32 rdl;
01092         int_32 ril;
01093 
01094         h->flags &= ~HEADERFLAG_LEGACY;
01095 
01096         entry->info.type = htonl(pe->type);
01097         entry->info.count = htonl(pe->count);
01098 
01099         if (hdrchkType(entry->info.type))
01100             goto errxit;
01101         if (hdrchkTags(entry->info.count))
01102             goto errxit;
01103 
01104         {   int off = ntohl(pe->offset);
01105 
01106             if (hdrchkData(off))
01107                 goto errxit;
01108             if (off) {
01109 /*@-sizeoftype@*/
01110                 size_t nb = REGION_TAG_COUNT;
01111 /*@=sizeoftype@*/
01112                 int_32 * stei = memcpy(alloca(nb), dataStart + off, nb);
01113                 rdl = -ntohl(stei[2]);  /* negative offset */
01114                 ril = rdl/sizeof(*pe);
01115                 if (hdrchkTags(ril) || hdrchkData(rdl))
01116                     goto errxit;
01117                 entry->info.tag = htonl(pe->tag);
01118             } else {
01119                 ril = il;
01120                 /*@-sizeoftype@*/
01121                 rdl = (ril * sizeof(struct entryInfo_s));
01122                 /*@=sizeoftype@*/
01123                 entry->info.tag = HEADER_IMAGE;
01124             }
01125         }
01126         entry->info.offset = -rdl;      /* negative offset */
01127 
01128         /*@-assignexpose@*/
01129         entry->data = pe;
01130         /*@=assignexpose@*/
01131         entry->length = pvlen - sizeof(il) - sizeof(dl);
01132         rdlen = regionSwab(entry+1, ril-1, 0, pe+1, dataStart, dataEnd, entry->info.offset);
01133         if (rdlen < 0)
01134             goto errxit;
01135         entry->rdlen = rdlen;
01136 
01137         if (ril < h->indexUsed) {
01138             indexEntry newEntry = entry + ril;
01139             int ne = (h->indexUsed - ril);
01140             int rid = entry->info.offset+1;
01141             int rc;
01142 
01143             /* Load dribble entries from region. */
01144             rc = regionSwab(newEntry, ne, 0, pe+ril, dataStart, dataEnd, rid);
01145             if (rc < 0)
01146                 goto errxit;
01147             rdlen += rc;
01148 
01149           { indexEntry firstEntry = newEntry;
01150             int save = h->indexUsed;
01151             int j;
01152 
01153             /* Dribble entries replace duplicate region entries. */
01154             h->indexUsed -= ne;
01155             for (j = 0; j < ne; j++, newEntry++) {
01156                 (void) headerRemoveEntry(h, newEntry->info.tag);
01157                 if (newEntry->info.tag == HEADER_BASENAMES)
01158                     (void) headerRemoveEntry(h, HEADER_OLDFILENAMES);
01159             }
01160 
01161             /* If any duplicate entries were replaced, move new entries down. */
01162 /*@-boundswrite@*/
01163             if (h->indexUsed < (save - ne)) {
01164                 memmove(h->index + h->indexUsed, firstEntry,
01165                         (ne * sizeof(*entry)));
01166             }
01167 /*@=boundswrite@*/
01168             h->indexUsed += ne;
01169           }
01170         }
01171     }
01172 
01173     h->flags &= ~HEADERFLAG_SORTED;
01174     headerSort(h);
01175 
01176     /*@-globstate -observertrans @*/
01177     return h;
01178     /*@=globstate =observertrans @*/
01179 
01180 errxit:
01181     /*@-usereleased@*/
01182     if (h) {
01183         h->index = _free(h->index);
01184         /*@-refcounttrans@*/
01185         h = _free(h);
01186         /*@=refcounttrans@*/
01187     }
01188     /*@=usereleased@*/
01189     /*@-refcounttrans -globstate@*/
01190     return h;
01191     /*@=refcounttrans =globstate@*/
01192 }
01193 
01199 static /*@observer@*/ /*@null@*/
01200 const char * headerGetOrigin(/*@null@*/ Header h)
01201         /*@*/
01202 {
01203     return (h != NULL ? h->origin : NULL);
01204 }
01205 
01212 static
01213 int headerSetOrigin(/*@null@*/ Header h, const char * origin)
01214         /*@modifies h @*/
01215 {
01216     if (h != NULL) {
01217         h->origin = _free(h->origin);
01218         h->origin = xstrdup(origin);
01219     }
01220     return 0;
01221 }
01222 
01228 static
01229 int headerGetInstance(/*@null@*/ Header h)
01230         /*@*/
01231 {
01232     return (h != NULL ? h->instance : 0);
01233 }
01234 
01241 static
01242 int headerSetInstance(/*@null@*/ Header h, int instance)
01243         /*@modifies h @*/
01244 {
01245     if (h != NULL)
01246         h->instance = instance;
01247     return 0;
01248 }
01249 
01257 static /*@null@*/
01258 Header headerReload(/*@only@*/ Header h, int tag)
01259         /*@modifies h @*/
01260 {
01261     Header nh;
01262     int length;
01263     /*@-onlytrans@*/
01264 /*@-boundswrite@*/
01265     void * uh = doHeaderUnload(h, &length);
01266 /*@=boundswrite@*/
01267     const char * origin;
01268     int_32 instance = h->instance;
01269     int xx;
01270 
01271     origin = (h->origin != NULL ? xstrdup(h->origin) : NULL);
01272     h = headerFree(h);
01273     /*@=onlytrans@*/
01274     if (uh == NULL)
01275         return NULL;
01276     nh = headerLoad(uh);
01277     if (nh == NULL) {
01278         uh = _free(uh);
01279         return NULL;
01280     }
01281     if (nh->flags & HEADERFLAG_ALLOCATED)
01282         uh = _free(uh);
01283     nh->flags |= HEADERFLAG_ALLOCATED;
01284     if (ENTRY_IS_REGION(nh->index)) {
01285 /*@-boundswrite@*/
01286         if (tag == HEADER_SIGNATURES || tag == HEADER_IMMUTABLE)
01287             nh->index[0].info.tag = tag;
01288 /*@=boundswrite@*/
01289     }
01290     if (origin != NULL) {
01291         xx = headerSetOrigin(nh, origin);
01292         origin = _free(origin);
01293     }
01294     xx = headerSetInstance(nh, instance);
01295     return nh;
01296 }
01297 
01303 static /*@null@*/
01304 Header headerCopyLoad(const void * uh)
01305         /*@*/
01306 {
01307     int_32 * ei = (int_32 *) uh;
01308 /*@-boundsread@*/
01309     int_32 il = ntohl(ei[0]);           /* index length */
01310     int_32 dl = ntohl(ei[1]);           /* data length */
01311 /*@=boundsread@*/
01312     /*@-sizeoftype@*/
01313     size_t pvlen = sizeof(il) + sizeof(dl) +
01314                         (il * sizeof(struct entryInfo_s)) + dl;
01315     /*@=sizeoftype@*/
01316     void * nuh = NULL;
01317     Header h = NULL;
01318 
01319     /* Sanity checks on header intro. */
01320     /*@-branchstate@*/
01321     if (!(hdrchkTags(il) || hdrchkData(dl)) && pvlen < headerMaxbytes) {
01322 /*@-boundsread@*/
01323         nuh = memcpy(xmalloc(pvlen), uh, pvlen);
01324 /*@=boundsread@*/
01325         if ((h = headerLoad(nuh)) != NULL)
01326             h->flags |= HEADERFLAG_ALLOCATED;
01327     }
01328     /*@=branchstate@*/
01329     /*@-branchstate@*/
01330     if (h == NULL)
01331         nuh = _free(nuh);
01332     /*@=branchstate@*/
01333     return h;
01334 }
01335 
01342 static /*@null@*/
01343 Header headerRead(FD_t fd, enum hMagic magicp)
01344         /*@modifies fd @*/
01345 {
01346     int_32 block[4];
01347     int_32 reserved;
01348     int_32 * ei = NULL;
01349     int_32 il;
01350     int_32 dl;
01351     int_32 magic;
01352     Header h = NULL;
01353     size_t len;
01354     int i;
01355 
01356     memset(block, 0, sizeof(block));
01357     i = 2;
01358     if (magicp == HEADER_MAGIC_YES)
01359         i += 2;
01360 
01361     /*@-type@*/ /* FIX: cast? */
01362     if (timedRead(fd, (char *)block, i*sizeof(*block)) != (i * sizeof(*block)))
01363         goto exit;
01364     /*@=type@*/
01365 
01366     i = 0;
01367 
01368 /*@-boundsread@*/
01369     if (magicp == HEADER_MAGIC_YES) {
01370         magic = block[i++];
01371         if (memcmp(&magic, header_magic, sizeof(magic)))
01372             goto exit;
01373         reserved = block[i++];
01374     }
01375     
01376     il = ntohl(block[i]);       i++;
01377     dl = ntohl(block[i]);       i++;
01378 /*@=boundsread@*/
01379 
01380     /*@-sizeoftype@*/
01381     len = sizeof(il) + sizeof(dl) + (il * sizeof(struct entryInfo_s)) + dl;
01382     /*@=sizeoftype@*/
01383 
01384     /* Sanity checks on header intro. */
01385     if (hdrchkTags(il) || hdrchkData(dl) || len > headerMaxbytes)
01386         goto exit;
01387 
01388 /*@-boundswrite@*/
01389     ei = xmalloc(len);
01390     ei[0] = htonl(il);
01391     ei[1] = htonl(dl);
01392     len -= sizeof(il) + sizeof(dl);
01393 /*@=boundswrite@*/
01394 
01395 /*@-boundsread@*/
01396     /*@-type@*/ /* FIX: cast? */
01397     if (timedRead(fd, (char *)&ei[2], len) != len)
01398         goto exit;
01399     /*@=type@*/
01400 /*@=boundsread@*/
01401     
01402     h = headerLoad(ei);
01403 
01404     {   const char * origin = fdGetOPath(fd);
01405         if (origin != NULL)
01406             (void) headerSetOrigin(h, origin);
01407     }
01408 
01409 exit:
01410     if (h) {
01411         if (h->flags & HEADERFLAG_ALLOCATED)
01412             ei = _free(ei);
01413         h->flags |= HEADERFLAG_ALLOCATED;
01414     } else if (ei)
01415         ei = _free(ei);
01416     /*@-mustmod@*/      /* FIX: timedRead macro obscures annotation */
01417     return h;
01418     /*@-mustmod@*/
01419 }
01420 
01428 static
01429 int headerWrite(FD_t fd, /*@null@*/ Header h, enum hMagic magicp)
01430         /*@globals fileSystem @*/
01431         /*@modifies fd, h, fileSystem @*/
01432 {
01433     ssize_t nb;
01434     int length;
01435     const void * uh;
01436 
01437     if (h == NULL)
01438         return 1;
01439 /*@-boundswrite@*/
01440     uh = doHeaderUnload(h, &length);
01441 /*@=boundswrite@*/
01442     if (uh == NULL)
01443         return 1;
01444     switch (magicp) {
01445     case HEADER_MAGIC_YES:
01446 /*@-boundsread@*/
01447         /*@-sizeoftype@*/
01448         nb = Fwrite(header_magic, sizeof(char), sizeof(header_magic), fd);
01449         /*@=sizeoftype@*/
01450 /*@=boundsread@*/
01451         if (nb != sizeof(header_magic))
01452             goto exit;
01453         break;
01454     case HEADER_MAGIC_NO:
01455         break;
01456     }
01457 
01458     /*@-sizeoftype@*/
01459     nb = Fwrite(uh, sizeof(char), length, fd);
01460     /*@=sizeoftype@*/
01461 
01462 exit:
01463     uh = _free(uh);
01464     return (nb == length ? 0 : 1);
01465 }
01466 
01473 static
01474 int headerIsEntry(/*@null@*/Header h, int_32 tag)
01475         /*@*/
01476 {
01477     /*@-mods@*/         /*@ FIX: h modified by sort. */
01478     return (findEntry(h, tag, RPM_NULL_TYPE) ? 1 : 0);
01479     /*@=mods@*/ 
01480 }
01481 
01492 static int copyEntry(const indexEntry entry,
01493                 /*@null@*/ /*@out@*/ hTYP_t type,
01494                 /*@null@*/ /*@out@*/ hPTR_t * p,
01495                 /*@null@*/ /*@out@*/ hCNT_t c,
01496                 int minMem)
01497         /*@modifies *type, *p, *c @*/
01498         /*@requires maxSet(type) >= 0 /\ maxSet(p) >= 0 /\ maxSet(c) >= 0 @*/
01499 {
01500     int_32 count = entry->info.count;
01501     int rc = 1;         /* XXX 1 on success. */
01502 
01503     if (p)
01504     switch (entry->info.type) {
01505     case RPM_BIN_TYPE:
01506         /*
01507          * XXX This only works for
01508          * XXX  "sealed" HEADER_IMMUTABLE/HEADER_SIGNATURES/HEADER_IMAGE.
01509          * XXX This will *not* work for unsealed legacy HEADER_IMAGE (i.e.
01510          * XXX a legacy header freshly read, but not yet unloaded to the rpmdb).
01511          */
01512         if (ENTRY_IS_REGION(entry)) {
01513             int_32 * ei = ((int_32 *)entry->data) - 2;
01514             /*@-castexpose@*/
01515             entryInfo pe = (entryInfo) (ei + 2);
01516             /*@=castexpose@*/
01517 /*@-boundsread@*/
01518             char * dataStart = (char *) (pe + ntohl(ei[0]));
01519 /*@=boundsread@*/
01520             int_32 rdl = -entry->info.offset;   /* negative offset */
01521             int_32 ril = rdl/sizeof(*pe);
01522 
01523             /*@-sizeoftype@*/
01524             rdl = entry->rdlen;
01525             count = 2 * sizeof(*ei) + (ril * sizeof(*pe)) + rdl;
01526             if (entry->info.tag == HEADER_IMAGE) {
01527                 ril -= 1;
01528                 pe += 1;
01529             } else {
01530                 count += REGION_TAG_COUNT;
01531                 rdl += REGION_TAG_COUNT;
01532             }
01533 
01534 /*@-bounds@*/
01535             *p = xmalloc(count);
01536             ei = (int_32 *) *p;
01537             ei[0] = htonl(ril);
01538             ei[1] = htonl(rdl);
01539 
01540             /*@-castexpose@*/
01541             pe = (entryInfo) memcpy(ei + 2, pe, (ril * sizeof(*pe)));
01542             /*@=castexpose@*/
01543 
01544             dataStart = (char *) memcpy(pe + ril, dataStart, rdl);
01545             /*@=sizeoftype@*/
01546 /*@=bounds@*/
01547 
01548             rc = regionSwab(NULL, ril, 0, pe, dataStart, NULL, 0);
01549             /* XXX 1 on success. */
01550             rc = (rc < 0) ? 0 : 1;
01551         } else {
01552             count = entry->length;
01553             *p = (!minMem
01554                 ? memcpy(xmalloc(count), entry->data, count)
01555                 : entry->data);
01556         }
01557         break;
01558     case RPM_STRING_TYPE:
01559         if (count == 1) {
01560             *p = entry->data;
01561             break;
01562         }
01563         /*@fallthrough@*/
01564     case RPM_STRING_ARRAY_TYPE:
01565     case RPM_I18NSTRING_TYPE:
01566     {   const char ** ptrEntry;
01567         /*@-sizeoftype@*/
01568         int tableSize = count * sizeof(char *);
01569         /*@=sizeoftype@*/
01570         char * t;
01571         int i;
01572 
01573 /*@-bounds@*/
01574         /*@-mods@*/
01575         if (minMem) {
01576             *p = xmalloc(tableSize);
01577             ptrEntry = (const char **) *p;
01578             t = entry->data;
01579         } else {
01580             t = xmalloc(tableSize + entry->length);
01581             *p = (void *)t;
01582             ptrEntry = (const char **) *p;
01583             t += tableSize;
01584             memcpy(t, entry->data, entry->length);
01585         }
01586         /*@=mods@*/
01587 /*@=bounds@*/
01588         for (i = 0; i < count; i++) {
01589 /*@-boundswrite@*/
01590             *ptrEntry++ = t;
01591 /*@=boundswrite@*/
01592             t = strchr(t, 0);
01593             t++;
01594         }
01595     }   break;
01596 
01597     case RPM_OPENPGP_TYPE:      /* XXX W2DO? */
01598     case RPM_ASN1_TYPE:         /* XXX W2DO? */
01599     default:
01600         *p = entry->data;
01601         break;
01602     }
01603     if (type) *type = entry->info.type;
01604     if (c) *c = count;
01605     return rc;
01606 }
01607 
01626 static int headerMatchLocale(const char *td, const char *l, const char *le)
01627         /*@*/
01628 {
01629     const char *fe;
01630 
01631 
01632 #if 0
01633   { const char *s, *ll, *CC, *EE, *dd;
01634     char *lbuf, *t.
01635 
01636     /* Copy the buffer and parse out components on the fly. */
01637     lbuf = alloca(le - l + 1);
01638     for (s = l, ll = t = lbuf; *s; s++, t++) {
01639         switch (*s) {
01640         case '_':
01641             *t = '\0';
01642             CC = t + 1;
01643             break;
01644         case '.':
01645             *t = '\0';
01646             EE = t + 1;
01647             break;
01648         case '@':
01649             *t = '\0';
01650             dd = t + 1;
01651             break;
01652         default:
01653             *t = *s;
01654             break;
01655         }
01656     }
01657 
01658     if (ll)     /* ISO language should be lower case */
01659         for (t = ll; *t; t++)   *t = tolower(*t);
01660     if (CC)     /* ISO country code should be upper case */
01661         for (t = CC; *t; t++)   *t = toupper(*t);
01662 
01663     /* There are a total of 16 cases to attempt to match. */
01664   }
01665 #endif
01666 
01667     /* First try a complete match. */
01668     if (strlen(td) == (le-l) && !strncmp(td, l, (le - l)))
01669         return 1;
01670 
01671     /* Next, try stripping optional dialect and matching.  */
01672     for (fe = l; fe < le && *fe != '@'; fe++)
01673         {};
01674     if (fe < le && !strncmp(td, l, (fe - l)))
01675         return 1;
01676 
01677     /* Next, try stripping optional codeset and matching.  */
01678     for (fe = l; fe < le && *fe != '.'; fe++)
01679         {};
01680     if (fe < le && !strncmp(td, l, (fe - l)))
01681         return 1;
01682 
01683     /* Finally, try stripping optional country code and matching. */
01684     for (fe = l; fe < le && *fe != '_'; fe++)
01685         {};
01686     if (fe < le && !strncmp(td, l, (fe - l)))
01687         return 1;
01688 
01689     return 0;
01690 }
01691 
01698 /*@dependent@*/ /*@exposed@*/ static char *
01699 headerFindI18NString(Header h, indexEntry entry)
01700         /*@*/
01701 {
01702     const char *lang, *l, *le;
01703     indexEntry table;
01704 
01705     /* XXX Drepper sez' this is the order. */
01706     if ((lang = getenv("LANGUAGE")) == NULL &&
01707         (lang = getenv("LC_ALL")) == NULL &&
01708         (lang = getenv("LC_MESSAGES")) == NULL &&
01709         (lang = getenv("LANG")) == NULL)
01710             return entry->data;
01711     
01712     /*@-mods@*/
01713     if ((table = findEntry(h, HEADER_I18NTABLE, RPM_STRING_ARRAY_TYPE)) == NULL)
01714         return entry->data;
01715     /*@=mods@*/
01716 
01717 /*@-boundsread@*/
01718     for (l = lang; *l != '\0'; l = le) {
01719         const char *td;
01720         char *ed;
01721         int langNum;
01722 
01723         while (*l && *l == ':')                 /* skip leading colons */
01724             l++;
01725         if (*l == '\0')
01726             break;
01727         for (le = l; *le && *le != ':'; le++)   /* find end of this locale */
01728             {};
01729 
01730         /* For each entry in the header ... */
01731         for (langNum = 0, td = table->data, ed = entry->data;
01732              langNum < entry->info.count;
01733              langNum++, td += strlen(td) + 1, ed += strlen(ed) + 1) {
01734 
01735                 if (headerMatchLocale(td, l, le))
01736                     return ed;
01737 
01738         }
01739     }
01740 /*@=boundsread@*/
01741 
01742     return entry->data;
01743 }
01744 
01755 static int intGetEntry(Header h, int_32 tag,
01756                 /*@null@*/ /*@out@*/ hTAG_t type,
01757                 /*@null@*/ /*@out@*/ hPTR_t * p,
01758                 /*@null@*/ /*@out@*/ hCNT_t c,
01759                 int minMem)
01760         /*@modifies *type, *p, *c @*/
01761         /*@requires maxSet(type) >= 0 /\ maxSet(p) >= 0 /\ maxSet(c) >= 0 @*/
01762 {
01763     indexEntry entry;
01764     int rc;
01765 
01766     /* First find the tag */
01767     /*@-mods@*/         /*@ FIX: h modified by sort. */
01768     entry = findEntry(h, tag, RPM_NULL_TYPE);
01769     /*@mods@*/
01770     if (entry == NULL) {
01771         if (type) type = 0;
01772         if (p) *p = NULL;
01773         if (c) *c = 0;
01774         return 0;
01775     }
01776 
01777     switch (entry->info.type) {
01778     case RPM_I18NSTRING_TYPE:
01779         rc = 1;
01780         if (type) *type = RPM_STRING_TYPE;
01781         if (c) *c = 1;
01782         /*@-dependenttrans@*/
01783         if (p) *p = headerFindI18NString(h, entry);
01784         /*@=dependenttrans@*/
01785         break;
01786     default:
01787         rc = copyEntry(entry, type, p, c, minMem);
01788         break;
01789     }
01790 
01791     /* XXX 1 on success */
01792     return ((rc == 1) ? 1 : 0);
01793 }
01794 
01802 static /*@null@*/ void * headerFreeTag(/*@unused@*/ Header h,
01803                 /*@only@*/ /*@null@*/ const void * data, rpmTagType type)
01804         /*@modifies data @*/
01805 {
01806     if (data) {
01807         /*@-branchstate@*/
01808         if (type == -1 ||
01809             type == RPM_STRING_ARRAY_TYPE ||
01810             type == RPM_I18NSTRING_TYPE ||
01811             type == RPM_BIN_TYPE ||
01812             type == RPM_ASN1_TYPE ||
01813             type == RPM_OPENPGP_TYPE)
01814                 data = _free(data);
01815         /*@=branchstate@*/
01816     }
01817     return NULL;
01818 }
01819 
01833 static
01834 int headerGetEntry(Header h, int_32 tag,
01835                         /*@null@*/ /*@out@*/ hTYP_t type,
01836                         /*@null@*/ /*@out@*/ void * p,
01837                         /*@null@*/ /*@out@*/ hCNT_t c)
01838         /*@modifies *type, *p, *c @*/
01839         /*@requires maxSet(type) >= 0 /\ maxSet(p) >= 0 /\ maxSet(c) >= 0 @*/
01840 {
01841     return intGetEntry(h, tag, type, (hPTR_t *)p, c, 0);
01842 }
01843 
01856 static
01857 int headerGetEntryMinMemory(Header h, int_32 tag,
01858                         /*@null@*/ /*@out@*/ hTYP_t type,
01859                         /*@null@*/ /*@out@*/ void * p,
01860                         /*@null@*/ /*@out@*/ hCNT_t c)
01861         /*@modifies *type, *p, *c @*/
01862         /*@requires maxSet(type) >= 0 /\ maxSet(p) >= 0 /\ maxSet(c) >= 0 @*/
01863 {
01864     return intGetEntry(h, tag, type, p, c, 1);
01865 }
01866 
01867 int headerGetRawEntry(Header h, int_32 tag, int_32 * type, void * p, int_32 * c)
01868 {
01869     indexEntry entry;
01870     int rc;
01871 
01872     if (p == NULL) return headerIsEntry(h, tag);
01873 
01874     /* First find the tag */
01875     /*@-mods@*/         /*@ FIX: h modified by sort. */
01876     entry = findEntry(h, tag, RPM_NULL_TYPE);
01877     /*@=mods@*/
01878     if (!entry) {
01879         if (p) *(void **)p = NULL;
01880         if (c) *c = 0;
01881         return 0;
01882     }
01883 
01884     rc = copyEntry(entry, type, p, c, 0);
01885 
01886     /* XXX 1 on success */
01887     return ((rc == 1) ? 1 : 0);
01888 }
01889 
01892 static void copyData(int_32 type, /*@out@*/ void * dstPtr, const void * srcPtr,
01893                 int_32 cnt, int dataLength)
01894         /*@modifies *dstPtr @*/
01895 {
01896     switch (type) {
01897     case RPM_STRING_ARRAY_TYPE:
01898     case RPM_I18NSTRING_TYPE:
01899     {   const char ** av = (const char **) srcPtr;
01900         char * t = dstPtr;
01901 
01902 /*@-bounds@*/
01903         while (cnt-- > 0 && dataLength > 0) {
01904             const char * s;
01905             if ((s = *av++) == NULL)
01906                 continue;
01907             do {
01908                 *t++ = *s++;
01909             } while (s[-1] && --dataLength > 0);
01910         }
01911 /*@=bounds@*/
01912     }   break;
01913 
01914     default:
01915 /*@-boundswrite@*/
01916         memmove(dstPtr, srcPtr, dataLength);
01917 /*@=boundswrite@*/
01918         break;
01919     }
01920 }
01921 
01930 /*@null@*/
01931 static void *
01932 grabData(int_32 type, hPTR_t p, int_32 c, /*@out@*/ int * lengthPtr)
01933         /*@modifies *lengthPtr @*/
01934         /*@requires maxSet(lengthPtr) >= 0 @*/
01935 {
01936     void * data = NULL;
01937     int length;
01938 
01939     length = dataLength(type, p, c, 0, NULL);
01940 /*@-branchstate@*/
01941     if (length > 0) {
01942         data = xmalloc(length);
01943         copyData(type, data, p, c, length);
01944     }
01945 /*@=branchstate@*/
01946 
01947     if (lengthPtr)
01948         *lengthPtr = length;
01949     return data;
01950 }
01951 
01966 static
01967 int headerAddEntry(Header h, int_32 tag, int_32 type, const void * p, int_32 c)
01968         /*@modifies h @*/
01969 {
01970     indexEntry entry;
01971     void * data;
01972     int length;
01973 
01974     /* Count must always be >= 1 for headerAddEntry. */
01975     if (c <= 0)
01976         return 0;
01977 
01978     if (hdrchkType(type))
01979         return 0;
01980     if (hdrchkData(c))
01981         return 0;
01982 
01983     length = 0;
01984 /*@-boundswrite@*/
01985     data = grabData(type, p, c, &length);
01986 /*@=boundswrite@*/
01987     if (data == NULL || length <= 0)
01988         return 0;
01989 
01990     /* Allocate more index space if necessary */
01991     if (h->indexUsed == h->indexAlloced) {
01992         h->indexAlloced += INDEX_MALLOC_SIZE;
01993         h->index = xrealloc(h->index, h->indexAlloced * sizeof(*h->index));
01994     }
01995 
01996     /* Fill in the index */
01997     entry = h->index + h->indexUsed;
01998     entry->info.tag = tag;
01999     entry->info.type = type;
02000     entry->info.count = c;
02001     entry->info.offset = 0;
02002     entry->data = data;
02003     entry->length = length;
02004 
02005 /*@-boundsread@*/
02006     if (h->indexUsed > 0 && tag < h->index[h->indexUsed-1].info.tag)
02007         h->flags &= ~HEADERFLAG_SORTED;
02008 /*@=boundsread@*/
02009     h->indexUsed++;
02010 
02011     return 1;
02012 }
02013 
02028 static
02029 int headerAppendEntry(Header h, int_32 tag, int_32 type,
02030                 const void * p, int_32 c)
02031         /*@modifies h @*/
02032 {
02033     indexEntry entry;
02034     int length;
02035 
02036     if (type == RPM_STRING_TYPE || type == RPM_I18NSTRING_TYPE) {
02037         /* we can't do this */
02038         return 0;
02039     }
02040 
02041     /* Find the tag entry in the header. */
02042     entry = findEntry(h, tag, type);
02043     if (!entry)
02044         return 0;
02045 
02046     length = dataLength(type, p, c, 0, NULL);
02047     if (length < 0)
02048         return 0;
02049 
02050     if (ENTRY_IN_REGION(entry)) {
02051         char * t = xmalloc(entry->length + length);
02052 /*@-bounds@*/
02053         memcpy(t, entry->data, entry->length);
02054 /*@=bounds@*/
02055         entry->data = t;
02056         entry->info.offset = 0;
02057     } else
02058         entry->data = xrealloc(entry->data, entry->length + length);
02059 
02060     copyData(type, ((char *) entry->data) + entry->length, p, c, length);
02061 
02062     entry->length += length;
02063 
02064     entry->info.count += c;
02065 
02066     return 1;
02067 }
02068 
02078 static
02079 int headerAddOrAppendEntry(Header h, int_32 tag, int_32 type,
02080                 const void * p, int_32 c)
02081         /*@modifies h @*/
02082 {
02083     return (findEntry(h, tag, type)
02084         ? headerAppendEntry(h, tag, type, p, c)
02085         : headerAddEntry(h, tag, type, p, c));
02086 }
02087 
02108 static
02109 int headerAddI18NString(Header h, int_32 tag, const char * string,
02110                 const char * lang)
02111         /*@modifies h @*/
02112 {
02113     indexEntry table, entry;
02114     const char ** strArray;
02115     int length;
02116     int ghosts;
02117     int i, langNum;
02118     char * buf;
02119 
02120     table = findEntry(h, HEADER_I18NTABLE, RPM_STRING_ARRAY_TYPE);
02121     entry = findEntry(h, tag, RPM_I18NSTRING_TYPE);
02122 
02123     if (!table && entry)
02124         return 0;               /* this shouldn't ever happen!! */
02125 
02126     if (!table && !entry) {
02127         const char * charArray[2];
02128         int count = 0;
02129         if (!lang || (lang[0] == 'C' && lang[1] == '\0')) {
02130             /*@-observertrans -readonlytrans@*/
02131             charArray[count++] = "C";
02132             /*@=observertrans =readonlytrans@*/
02133         } else {
02134             /*@-observertrans -readonlytrans@*/
02135             charArray[count++] = "C";
02136             /*@=observertrans =readonlytrans@*/
02137             charArray[count++] = lang;
02138         }
02139         if (!headerAddEntry(h, HEADER_I18NTABLE, RPM_STRING_ARRAY_TYPE, 
02140                         &charArray, count))
02141             return 0;
02142         table = findEntry(h, HEADER_I18NTABLE, RPM_STRING_ARRAY_TYPE);
02143     }
02144 
02145     if (!table)
02146         return 0;
02147     /*@-branchstate@*/
02148     if (!lang) lang = "C";
02149     /*@=branchstate@*/
02150 
02151     {   const char * l = table->data;
02152         for (langNum = 0; langNum < table->info.count; langNum++) {
02153             if (!strcmp(l, lang)) break;
02154             l += strlen(l) + 1;
02155         }
02156     }
02157 
02158     if (langNum >= table->info.count) {
02159         length = strlen(lang) + 1;
02160         if (ENTRY_IN_REGION(table)) {
02161             char * t = xmalloc(table->length + length);
02162             memcpy(t, table->data, table->length);
02163             table->data = t;
02164             table->info.offset = 0;
02165         } else
02166             table->data = xrealloc(table->data, table->length + length);
02167         memmove(((char *)table->data) + table->length, lang, length);
02168         table->length += length;
02169         table->info.count++;
02170     }
02171 
02172     if (!entry) {
02173         strArray = alloca(sizeof(*strArray) * (langNum + 1));
02174         for (i = 0; i < langNum; i++)
02175             strArray[i] = "";
02176         strArray[langNum] = string;
02177         return headerAddEntry(h, tag, RPM_I18NSTRING_TYPE, strArray, 
02178                                 langNum + 1);
02179     } else if (langNum >= entry->info.count) {
02180         ghosts = langNum - entry->info.count;
02181         
02182         length = strlen(string) + 1 + ghosts;
02183         if (ENTRY_IN_REGION(entry)) {
02184             char * t = xmalloc(entry->length + length);
02185             memcpy(t, entry->data, entry->length);
02186             entry->data = t;
02187             entry->info.offset = 0;
02188         } else
02189             entry->data = xrealloc(entry->data, entry->length + length);
02190 
02191         memset(((char *)entry->data) + entry->length, '\0', ghosts);
02192         memmove(((char *)entry->data) + entry->length + ghosts, string, strlen(string)+1);
02193 
02194         entry->length += length;
02195         entry->info.count = langNum + 1;
02196     } else {
02197         char *b, *be, *e, *ee, *t;
02198         size_t bn, sn, en;
02199 
02200         /* Set beginning/end pointers to previous data */
02201         b = be = e = ee = entry->data;
02202         for (i = 0; i < table->info.count; i++) {
02203             if (i == langNum)
02204                 be = ee;
02205             ee += strlen(ee) + 1;
02206             if (i == langNum)
02207                 e  = ee;
02208         }
02209 
02210         /* Get storage for new buffer */
02211         bn = (be-b);
02212         sn = strlen(string) + 1;
02213         en = (ee-e);
02214         length = bn + sn + en;
02215         t = buf = xmalloc(length);
02216 
02217         /* Copy values into new storage */
02218         memcpy(t, b, bn);
02219         t += bn;
02220 /*@-mayaliasunique@*/
02221         memcpy(t, string, sn);
02222         t += sn;
02223         memcpy(t, e, en);
02224         t += en;
02225 /*@=mayaliasunique@*/
02226 
02227         /* Replace i18N string array */
02228         entry->length -= strlen(be) + 1;
02229         entry->length += sn;
02230         
02231         if (ENTRY_IN_REGION(entry)) {
02232             entry->info.offset = 0;
02233         } else
02234             entry->data = _free(entry->data);
02235         /*@-dependenttrans@*/
02236         entry->data = buf;
02237         /*@=dependenttrans@*/
02238     }
02239 
02240     return 0;
02241 }
02242 
02253 static
02254 int headerModifyEntry(Header h, int_32 tag, int_32 type,
02255                         const void * p, int_32 c)
02256         /*@modifies h @*/
02257 {
02258     indexEntry entry;
02259     void * oldData;
02260     void * data;
02261     int length;
02262 
02263     /* First find the tag */
02264     entry = findEntry(h, tag, type);
02265     if (!entry)
02266         return 0;
02267 
02268     length = 0;
02269     data = grabData(type, p, c, &length);
02270     if (data == NULL || length <= 0)
02271         return 0;
02272 
02273     /* make sure entry points to the first occurence of this tag */
02274     while (entry > h->index && (entry - 1)->info.tag == tag)  
02275         entry--;
02276 
02277     /* free after we've grabbed the new data in case the two are intertwined;
02278        that's a bad idea but at least we won't break */
02279     oldData = entry->data;
02280 
02281     entry->info.count = c;
02282     entry->info.type = type;
02283     entry->data = data;
02284     entry->length = length;
02285 
02286     /*@-branchstate@*/
02287     if (ENTRY_IN_REGION(entry)) {
02288         entry->info.offset = 0;
02289     } else
02290         oldData = _free(oldData);
02291     /*@=branchstate@*/
02292 
02293     return 1;
02294 }
02295 
02298 static char escapedChar(const char ch)  /*@*/
02299 {
02300     switch (ch) {
02301     case 'a':   return '\a';
02302     case 'b':   return '\b';
02303     case 'f':   return '\f';
02304     case 'n':   return '\n';
02305     case 'r':   return '\r';
02306     case 't':   return '\t';
02307     case 'v':   return '\v';
02308     default:    return ch;
02309     }
02310 }
02311 
02318 static /*@null@*/ sprintfToken
02319 freeFormat( /*@only@*/ /*@null@*/ sprintfToken format, int num)
02320         /*@modifies *format @*/
02321 {
02322     int i;
02323 
02324     if (format == NULL) return NULL;
02325 
02326     for (i = 0; i < num; i++) {
02327         switch (format[i].type) {
02328         case PTOK_ARRAY:
02329 /*@-boundswrite@*/
02330             format[i].u.array.format =
02331                 freeFormat(format[i].u.array.format,
02332                         format[i].u.array.numTokens);
02333 /*@=boundswrite@*/
02334             /*@switchbreak@*/ break;
02335         case PTOK_COND:
02336 /*@-boundswrite@*/
02337             format[i].u.cond.ifFormat =
02338                 freeFormat(format[i].u.cond.ifFormat, 
02339                         format[i].u.cond.numIfTokens);
02340             format[i].u.cond.elseFormat =
02341                 freeFormat(format[i].u.cond.elseFormat, 
02342                         format[i].u.cond.numElseTokens);
02343 /*@=boundswrite@*/
02344             /*@switchbreak@*/ break;
02345         case PTOK_NONE:
02346         case PTOK_TAG:
02347         case PTOK_STRING:
02348         default:
02349             /*@switchbreak@*/ break;
02350         }
02351     }
02352     format = _free(format);
02353     return NULL;
02354 }
02355 
02359 struct headerIterator_s {
02360 /*@unused@*/
02361     Header h;           
02362 /*@unused@*/
02363     int next_index;     
02364 };
02365 
02371 static /*@null@*/
02372 HeaderIterator headerFreeIterator(/*@only@*/ HeaderIterator hi)
02373         /*@modifies hi @*/
02374 {
02375     if (hi != NULL) {
02376         hi->h = headerFree(hi->h);
02377         hi = _free(hi);
02378     }
02379     return hi;
02380 }
02381 
02387 static
02388 HeaderIterator headerInitIterator(Header h)
02389         /*@modifies h */
02390 {
02391     HeaderIterator hi = xmalloc(sizeof(*hi));
02392 
02393     headerSort(h);
02394 
02395     hi->h = headerLink(h);
02396     hi->next_index = 0;
02397     return hi;
02398 }
02399 
02409 static
02410 int headerNextIterator(HeaderIterator hi,
02411                 /*@null@*/ /*@out@*/ hTAG_t tag,
02412                 /*@null@*/ /*@out@*/ hTYP_t type,
02413                 /*@null@*/ /*@out@*/ hPTR_t * p,
02414                 /*@null@*/ /*@out@*/ hCNT_t c)
02415         /*@modifies hi, *tag, *type, *p, *c @*/
02416         /*@requires maxSet(tag) >= 0 /\ maxSet(type) >= 0
02417                 /\ maxSet(p) >= 0 /\ maxSet(c) >= 0 @*/
02418 {
02419     Header h = hi->h;
02420     int slot = hi->next_index;
02421     indexEntry entry = NULL;
02422     int rc;
02423 
02424     for (slot = hi->next_index; slot < h->indexUsed; slot++) {
02425         entry = h->index + slot;
02426         if (!ENTRY_IS_REGION(entry))
02427             break;
02428     }
02429     hi->next_index = slot;
02430     if (entry == NULL || slot >= h->indexUsed)
02431         return 0;
02432 
02433     /*@-noeffect@*/     /* LCL: no clue */
02434     hi->next_index++;
02435     /*@=noeffect@*/
02436 
02437     if (tag)
02438         *tag = entry->info.tag;
02439 
02440     rc = copyEntry(entry, type, p, c, 0);
02441 
02442     /* XXX 1 on success */
02443     return ((rc == 1) ? 1 : 0);
02444 }
02445 
02451 static /*@null@*/
02452 Header headerCopy(Header h)
02453         /*@modifies h @*/
02454 {
02455     Header nh = headerNew();
02456     HeaderIterator hi;
02457     int_32 tag, type, count;
02458     hPTR_t ptr;
02459    
02460     /*@-branchstate@*/
02461     for (hi = headerInitIterator(h);
02462         headerNextIterator(hi, &tag, &type, &ptr, &count);
02463         ptr = headerFreeData((void *)ptr, type))
02464     {
02465         if (ptr) (void) headerAddEntry(nh, tag, type, ptr, count);
02466     }
02467     hi = headerFreeIterator(hi);
02468     /*@=branchstate@*/
02469 
02470     return headerReload(nh, HEADER_IMAGE);
02471 }
02472 
02475 typedef struct headerSprintfArgs_s {
02476     Header h;
02477     char * fmt;
02478 /*@temp@*/
02479     headerTagTableEntry tags;
02480 /*@temp@*/
02481     headerSprintfExtension exts;
02482 /*@observer@*/ /*@null@*/
02483     const char * errmsg;
02484     rpmec ec;
02485     sprintfToken format;
02486 /*@relnull@*/
02487     HeaderIterator hi;
02488 /*@owned@*/
02489     char * val;
02490     size_t vallen;
02491     size_t alloced;
02492     int numTokens;
02493     int i;
02494 } * headerSprintfArgs;
02495 
02501 static headerSprintfArgs hsaInit(/*@returned@*/ headerSprintfArgs hsa)
02502         /*@modifies hsa */
02503 {
02504     sprintfTag tag =
02505         (hsa->format->type == PTOK_TAG
02506             ? &hsa->format->u.tag :
02507         (hsa->format->type == PTOK_ARRAY
02508             ? &hsa->format->u.array.format->u.tag :
02509         NULL));
02510 
02511     if (hsa != NULL) {
02512         hsa->i = 0;
02513         if (tag != NULL && tag->tag == -2)
02514             hsa->hi = headerInitIterator(hsa->h);
02515     }
02516 /*@-nullret@*/
02517     return hsa;
02518 /*@=nullret@*/
02519 }
02520 
02526 /*@null@*/
02527 static sprintfToken hsaNext(/*@returned@*/ headerSprintfArgs hsa)
02528         /*@modifies hsa */
02529 {
02530     sprintfToken fmt = NULL;
02531     sprintfTag tag =
02532         (hsa->format->type == PTOK_TAG
02533             ? &hsa->format->u.tag :
02534         (hsa->format->type == PTOK_ARRAY
02535             ? &hsa->format->u.array.format->u.tag :
02536         NULL));
02537 
02538     if (hsa != NULL && hsa->i >= 0 && hsa->i < hsa->numTokens) {
02539         fmt = hsa->format + hsa->i;
02540         if (hsa->hi == NULL) {
02541             hsa->i++;
02542         } else {
02543             int_32 tagno;
02544             int_32 type;
02545             int_32 count;
02546 
02547 /*@-boundswrite@*/
02548             if (!headerNextIterator(hsa->hi, &tagno, &type, NULL, &count))
02549                 fmt = NULL;
02550             tag->tag = tagno;
02551 /*@=boundswrite@*/
02552         }
02553     }
02554 
02555 /*@-dependenttrans -onlytrans@*/
02556     return fmt;
02557 /*@=dependenttrans =onlytrans@*/
02558 }
02559 
02565 static headerSprintfArgs hsaFini(/*@returned@*/ headerSprintfArgs hsa)
02566         /*@modifies hsa */
02567 {
02568     if (hsa != NULL) {
02569         hsa->hi = headerFreeIterator(hsa->hi);
02570         hsa->i = 0;
02571     }
02572 /*@-nullret@*/
02573     return hsa;
02574 /*@=nullret@*/
02575 }
02576 
02583 /*@dependent@*/ /*@exposed@*/
02584 static char * hsaReserve(headerSprintfArgs hsa, size_t need)
02585         /*@modifies hsa */
02586 {
02587     if ((hsa->vallen + need) >= hsa->alloced) {
02588         if (hsa->alloced <= need)
02589             hsa->alloced += need;
02590         hsa->alloced <<= 1;
02591         hsa->val = xrealloc(hsa->val, hsa->alloced+1);  
02592     }
02593     return hsa->val + hsa->vallen;
02594 }
02595 
02604 /*@observer@*/ /*@null@*/
02605 static const char * myTagName(headerTagTableEntry tbl, int val,
02606                 /*@null@*/ int *typep)
02607         /*@*/
02608 {
02609     static char name[128];
02610     const char * s;
02611     char *t;
02612 
02613     for (; tbl->name != NULL; tbl++) {
02614         if (tbl->val == val)
02615             break;
02616     }
02617     if ((s = tbl->name) == NULL)
02618         return NULL;
02619     s += sizeof("RPMTAG_") - 1;
02620     t = name;
02621     *t++ = *s++;
02622     while (*s != '\0')
02623         *t++ = xtolower(*s++);
02624     *t = '\0';
02625     if (typep)
02626         *typep = tbl->type;
02627     return name;
02628 }
02629 
02637 static int myTagValue(headerTagTableEntry tbl, const char * name)
02638         /*@*/
02639 {
02640     for (; tbl->name != NULL; tbl++) {
02641         if (!xstrcasecmp(tbl->name, name))
02642             return tbl->val;
02643     }
02644     return 0;
02645 }
02646 
02654 static int findTag(headerSprintfArgs hsa, sprintfToken token, const char * name)
02655         /*@modifies token @*/
02656 {
02657     headerSprintfExtension ext;
02658     sprintfTag stag = (token->type == PTOK_COND
02659         ? &token->u.cond.tag : &token->u.tag);
02660 
02661     stag->fmt = NULL;
02662     stag->ext = NULL;
02663     stag->extNum = 0;
02664     stag->tag = -1;
02665 
02666     if (!strcmp(name, "*")) {
02667         stag->tag = -2;
02668         goto bingo;
02669     }
02670 
02671 /*@-branchstate@*/
02672     if (strncmp("RPMTAG_", name, sizeof("RPMTAG_")-1)) {
02673 /*@-boundswrite@*/
02674         char * t = alloca(strlen(name) + sizeof("RPMTAG_"));
02675         (void) stpcpy( stpcpy(t, "RPMTAG_"), name);
02676         name = t;
02677 /*@=boundswrite@*/
02678     }
02679 /*@=branchstate@*/
02680 
02681     /* Search extensions for specific tag override. */
02682     for (ext = hsa->exts; ext != NULL && ext->type != HEADER_EXT_LAST;
02683         ext = (ext->type == HEADER_EXT_MORE ? ext->u.more : ext+1))
02684     {
02685         if (ext->name == NULL || ext->type != HEADER_EXT_TAG)
02686             continue;
02687         if (!xstrcasecmp(ext->name, name)) {
02688             stag->ext = ext->u.tagFunction;
02689             stag->extNum = ext - hsa->exts;
02690             goto bingo;
02691         }
02692     }
02693 
02694     /* Search tag names. */
02695     stag->tag = myTagValue(hsa->tags, name);
02696     if (stag->tag != 0)
02697         goto bingo;
02698 
02699     return 1;
02700 
02701 bingo:
02702     /* Search extensions for specific format. */
02703     if (stag->type != NULL)
02704     for (ext = hsa->exts; ext != NULL && ext->type != HEADER_EXT_LAST;
02705             ext = (ext->type == HEADER_EXT_MORE ? ext->u.more : ext+1))
02706     {
02707         if (ext->name == NULL || ext->type != HEADER_EXT_FORMAT)
02708             continue;
02709         if (!strcmp(ext->name, stag->type)) {
02710             stag->fmt = ext->u.formatFunction;
02711             break;
02712         }
02713     }
02714     return 0;
02715 }
02716 
02717 /* forward ref */
02726 static int parseExpression(headerSprintfArgs hsa, sprintfToken token,
02727                 char * str, /*@out@*/char ** endPtr)
02728         /*@modifies hsa, str, token, *endPtr @*/
02729         /*@requires maxSet(endPtr) >= 0 @*/;
02730 
02741 static int parseFormat(headerSprintfArgs hsa, /*@null@*/ char * str,
02742                 /*@out@*/sprintfToken * formatPtr, /*@out@*/int * numTokensPtr,
02743                 /*@null@*/ /*@out@*/ char ** endPtr, int state)
02744         /*@modifies hsa, str, *formatPtr, *numTokensPtr, *endPtr @*/
02745         /*@requires maxSet(formatPtr) >= 0 /\ maxSet(numTokensPtr) >= 0
02746                 /\ maxSet(endPtr) >= 0 @*/
02747 {
02748     char * chptr, * start, * next, * dst;
02749     sprintfToken format;
02750     sprintfToken token;
02751     int numTokens;
02752     int i;
02753     int done = 0;
02754 
02755     /* upper limit on number of individual formats */
02756     numTokens = 0;
02757     if (str != NULL)
02758     for (chptr = str; *chptr != '\0'; chptr++)
02759         if (*chptr == '%') numTokens++;
02760     numTokens = numTokens * 2 + 1;
02761 
02762     format = xcalloc(numTokens, sizeof(*format));
02763     if (endPtr) *endPtr = NULL;
02764 
02765     /*@-infloops@*/ /* LCL: can't detect done termination */
02766     dst = start = str;
02767     numTokens = 0;
02768     token = NULL;
02769     if (start != NULL)
02770     while (*start != '\0') {
02771         switch (*start) {
02772         case '%':
02773             /* handle %% */
02774             if (*(start + 1) == '%') {
02775                 if (token == NULL || token->type != PTOK_STRING) {
02776                     token = format + numTokens++;
02777                     token->type = PTOK_STRING;
02778                     /*@-temptrans -assignexpose@*/
02779                     dst = token->u.string.string = start;
02780                     /*@=temptrans =assignexpose@*/
02781                 }
02782                 start++;
02783 /*@-boundswrite@*/
02784                 *dst++ = *start++;
02785 /*@=boundswrite@*/
02786                 /*@switchbreak@*/ break;
02787             } 
02788 
02789             token = format + numTokens++;
02790 /*@-boundswrite@*/
02791             *dst++ = '\0';
02792 /*@=boundswrite@*/
02793             start++;
02794 
02795             if (*start == '|') {
02796                 char * newEnd;
02797 
02798                 start++;
02799 /*@-boundswrite@*/
02800                 if (parseExpression(hsa, token, start, &newEnd))
02801                 {
02802                     format = freeFormat(format, numTokens);
02803                     return 1;
02804                 }
02805 /*@=boundswrite@*/
02806                 start = newEnd;
02807                 /*@switchbreak@*/ break;
02808             }
02809 
02810             /*@-assignexpose@*/
02811             token->u.tag.format = start;
02812             /*@=assignexpose@*/
02813             token->u.tag.pad = 0;
02814             token->u.tag.justOne = 0;
02815             token->u.tag.arrayCount = 0;
02816 
02817             chptr = start;
02818             while (*chptr && *chptr != '{' && *chptr != '%') chptr++;
02819             if (!*chptr || *chptr == '%') {
02820                 hsa->errmsg = _("missing { after %");
02821                 format = freeFormat(format, numTokens);
02822                 return 1;
02823             }
02824 
02825 /*@-boundswrite@*/
02826             *chptr++ = '\0';
02827 /*@=boundswrite@*/
02828 
02829             while (start < chptr) {
02830                 if (xisdigit(*start)) {
02831                     i = strtoul(start, &start, 10);
02832                     token->u.tag.pad += i;
02833                 } else {
02834                     start++;
02835                 }
02836             }
02837 
02838             if (*start == '=') {
02839                 token->u.tag.justOne = 1;
02840                 start++;
02841             } else if (*start == '#') {
02842                 token->u.tag.justOne = 1;
02843                 token->u.tag.arrayCount = 1;
02844                 start++;
02845             }
02846 
02847             next = start;
02848             while (*next && *next != '}') next++;
02849             if (!*next) {
02850                 hsa->errmsg = _("missing } after %{");
02851                 format = freeFormat(format, numTokens);
02852                 return 1;
02853             }
02854 /*@-boundswrite@*/
02855             *next++ = '\0';
02856 /*@=boundswrite@*/
02857 
02858             chptr = start;
02859             while (*chptr && *chptr != ':') chptr++;
02860 
02861             if (*chptr != '\0') {
02862 /*@-boundswrite@*/
02863                 *chptr++ = '\0';
02864 /*@=boundswrite@*/
02865                 if (!*chptr) {
02866                     hsa->errmsg = _("empty tag format");
02867                     format = freeFormat(format, numTokens);
02868                     return 1;
02869                 }
02870                 /*@-assignexpose@*/
02871                 token->u.tag.type = chptr;
02872                 /*@=assignexpose@*/
02873             } else {
02874                 token->u.tag.type = NULL;
02875             }
02876             
02877             if (!*start) {
02878                 hsa->errmsg = _("empty tag name");
02879                 format = freeFormat(format, numTokens);
02880                 return 1;
02881             }
02882 
02883             i = 0;
02884             token->type = PTOK_TAG;
02885 
02886             if (findTag(hsa, token, start)) {
02887                 hsa->errmsg = _("unknown tag");
02888                 format = freeFormat(format, numTokens);
02889                 return 1;
02890             }
02891 
02892             start = next;
02893             /*@switchbreak@*/ break;
02894 
02895         case '[':
02896 /*@-boundswrite@*/
02897             *dst++ = '\0';
02898             *start++ = '\0';
02899 /*@=boundswrite@*/
02900             token = format + numTokens++;
02901 
02902 /*@-boundswrite@*/
02903             if (parseFormat(hsa, start,
02904                             &token->u.array.format,
02905                             &token->u.array.numTokens,
02906                             &start, PARSER_IN_ARRAY))
02907             {
02908                 format = freeFormat(format, numTokens);
02909                 return 1;
02910             }
02911 /*@=boundswrite@*/
02912 
02913             if (!start) {
02914                 hsa->errmsg = _("] expected at end of array");
02915                 format = freeFormat(format, numTokens);
02916                 return 1;
02917             }
02918 
02919             dst = start;
02920 
02921             token->type = PTOK_ARRAY;
02922 
02923             /*@switchbreak@*/ break;
02924 
02925         case ']':
02926             if (state != PARSER_IN_ARRAY) {
02927                 hsa->errmsg = _("unexpected ]");
02928                 format = freeFormat(format, numTokens);
02929                 return 1;
02930             }
02931 /*@-boundswrite@*/
02932             *start++ = '\0';
02933 /*@=boundswrite@*/
02934             if (endPtr) *endPtr = start;
02935             done = 1;
02936             /*@switchbreak@*/ break;
02937 
02938         case '}':
02939             if (state != PARSER_IN_EXPR) {
02940                 hsa->errmsg = _("unexpected }");
02941                 format = freeFormat(format, numTokens);
02942                 return 1;
02943             }
02944 /*@-boundswrite@*/
02945             *start++ = '\0';
02946 /*@=boundswrite@*/
02947             if (endPtr) *endPtr = start;
02948             done = 1;
02949             /*@switchbreak@*/ break;
02950 
02951         default:
02952             if (token == NULL || token->type != PTOK_STRING) {
02953                 token = format + numTokens++;
02954                 token->type = PTOK_STRING;
02955                 /*@-temptrans -assignexpose@*/
02956                 dst = token->u.string.string = start;
02957                 /*@=temptrans =assignexpose@*/
02958             }
02959 
02960 /*@-boundswrite@*/
02961             if (*start == '\\') {
02962                 start++;
02963                 *dst++ = escapedChar(*start++);
02964             } else {
02965                 *dst++ = *start++;
02966             }
02967 /*@=boundswrite@*/
02968             /*@switchbreak@*/ break;
02969         }
02970         if (done)
02971             break;
02972     }
02973     /*@=infloops@*/
02974 
02975 /*@-boundswrite@*/
02976     if (dst != NULL)
02977         *dst = '\0';
02978 /*@=boundswrite@*/
02979 
02980     for (i = 0; i < numTokens; i++) {
02981         token = format + i;
02982         if (token->type == PTOK_STRING)
02983             token->u.string.len = strlen(token->u.string.string);
02984     }
02985 
02986     *numTokensPtr = numTokens;
02987     *formatPtr = format;
02988 
02989     return 0;
02990 }
02991 
02992 /*@-boundswrite@*/
02993 static int parseExpression(headerSprintfArgs hsa, sprintfToken token,
02994                 char * str, /*@out@*/ char ** endPtr)
02995 {
02996     char * chptr;
02997     char * end;
02998 
02999     hsa->errmsg = NULL;
03000     chptr = str;
03001     while (*chptr && *chptr != '?') chptr++;
03002 
03003     if (*chptr != '?') {
03004         hsa->errmsg = _("? expected in expression");
03005         return 1;
03006     }
03007 
03008     *chptr++ = '\0';;
03009 
03010     if (*chptr != '{') {
03011         hsa->errmsg = _("{ expected after ? in expression");
03012         return 1;
03013     }
03014 
03015     chptr++;
03016 
03017     if (parseFormat(hsa, chptr, &token->u.cond.ifFormat, 
03018                     &token->u.cond.numIfTokens, &end, PARSER_IN_EXPR)) 
03019         return 1;
03020 
03021     /* XXX fix segfault on "rpm -q rpm --qf='%|NAME?{%}:{NAME}|\n'"*/
03022     if (!(end && *end)) {
03023         hsa->errmsg = _("} expected in expression");
03024         token->u.cond.ifFormat =
03025                 freeFormat(token->u.cond.ifFormat, token->u.cond.numIfTokens);
03026         return 1;
03027     }
03028 
03029     chptr = end;
03030     if (*chptr != ':' && *chptr != '|') {
03031         hsa->errmsg = _(": expected following ? subexpression");
03032         token->u.cond.ifFormat =
03033                 freeFormat(token->u.cond.ifFormat, token->u.cond.numIfTokens);
03034         return 1;
03035     }
03036 
03037     if (*chptr == '|') {
03038         if (parseFormat(hsa, NULL, &token->u.cond.elseFormat, 
03039                 &token->u.cond.numElseTokens, &end, PARSER_IN_EXPR))
03040         {
03041             token->u.cond.ifFormat =
03042                 freeFormat(token->u.cond.ifFormat, token->u.cond.numIfTokens);
03043             return 1;
03044         }
03045     } else {
03046         chptr++;
03047 
03048         if (*chptr != '{') {
03049             hsa->errmsg = _("{ expected after : in expression");
03050             token->u.cond.ifFormat =
03051                 freeFormat(token->u.cond.ifFormat, token->u.cond.numIfTokens);
03052             return 1;
03053         }
03054 
03055         chptr++;
03056 
03057         if (parseFormat(hsa, chptr, &token->u.cond.elseFormat, 
03058                         &token->u.cond.numElseTokens, &end, PARSER_IN_EXPR)) 
03059             return 1;
03060 
03061         /* XXX fix segfault on "rpm -q rpm --qf='%|NAME?{a}:{%}|{NAME}\n'" */
03062         if (!(end && *end)) {
03063             hsa->errmsg = _("} expected in expression");
03064             token->u.cond.ifFormat =
03065                 freeFormat(token->u.cond.ifFormat, token->u.cond.numIfTokens);
03066             return 1;
03067         }
03068 
03069         chptr = end;
03070         if (*chptr != '|') {
03071             hsa->errmsg = _("| expected at end of expression");
03072             token->u.cond.ifFormat =
03073                 freeFormat(token->u.cond.ifFormat, token->u.cond.numIfTokens);
03074             token->u.cond.elseFormat =
03075                 freeFormat(token->u.cond.elseFormat, token->u.cond.numElseTokens);
03076             return 1;
03077         }
03078     }
03079         
03080     chptr++;
03081 
03082     *endPtr = chptr;
03083 
03084     token->type = PTOK_COND;
03085 
03086     (void) findTag(hsa, token, str);
03087 
03088     return 0;
03089 }
03090 /*@=boundswrite@*/
03091 
03102 static int getExtension(headerSprintfArgs hsa, headerTagTagFunction fn,
03103                 /*@out@*/ hTYP_t typeptr,
03104                 /*@out@*/ hPTR_t * data,
03105                 /*@out@*/ hCNT_t countptr,
03106                 rpmec ec)
03107         /*@modifies *typeptr, *data, *countptr, ec @*/
03108         /*@requires maxSet(typeptr) >= 0 /\ maxSet(data) >= 0
03109                 /\ maxSet(countptr) >= 0 @*/
03110 {
03111     if (!ec->avail) {
03112         if (fn(hsa->h, &ec->type, &ec->data, &ec->count, &ec->freeit))
03113             return 1;
03114         ec->avail = 1;
03115     }
03116 
03117     if (typeptr) *typeptr = ec->type;
03118     if (data) *data = ec->data;
03119     if (countptr) *countptr = ec->count;
03120 
03121     return 0;
03122 }
03123 
03131 /*@observer@*/ /*@null@*/
03132 static char * formatValue(headerSprintfArgs hsa, sprintfTag tag, int element)
03133         /*@modifies hsa @*/
03134 {
03135     char * val = NULL;
03136     size_t need = 0;
03137     char * t, * te;
03138     char buf[20];
03139     int_32 count, type;
03140     hPTR_t data;
03141     unsigned int intVal;
03142     uint_64 llVal;
03143     const char ** strarray;
03144     int datafree = 0;
03145     int countBuf;
03146 
03147     memset(buf, 0, sizeof(buf));
03148     if (tag->ext) {
03149 /*@-boundswrite -branchstate @*/
03150         if (getExtension(hsa, tag->ext, &type, &data, &count, hsa->ec + tag->extNum))
03151         {
03152             count = 1;
03153             type = RPM_STRING_TYPE;     
03154             data = "(none)";
03155         }
03156 /*@=boundswrite =branchstate @*/
03157     } else {
03158 /*@-boundswrite -branchstate @*/
03159         if (!headerGetEntry(hsa->h, tag->tag, &type, &data, &count)) {
03160             count = 1;
03161             type = RPM_STRING_TYPE;     
03162             data = "(none)";
03163         }
03164 /*@=boundswrite =branchstate @*/
03165 
03166         /* XXX this test is unnecessary, array sizes are checked */
03167         switch (type) {
03168         default:
03169             if (element >= count) {
03170                 /*@-modobserver -observertrans@*/
03171                 data = headerFreeData(data, type);
03172                 /*@=modobserver =observertrans@*/
03173 
03174                 hsa->errmsg = _("(index out of range)");
03175                 return NULL;
03176             }
03177             break;
03178         case RPM_OPENPGP_TYPE:
03179         case RPM_ASN1_TYPE:
03180         case RPM_BIN_TYPE:
03181         case RPM_STRING_TYPE:
03182             break;
03183         }
03184         datafree = 1;
03185     }
03186 
03187     if (tag->arrayCount) {
03188         /*@-branchstate -observertrans -modobserver@*/
03189         if (datafree)
03190             data = headerFreeData(data, type);
03191         /*@=branchstate =observertrans =modobserver@*/
03192 
03193         countBuf = count;
03194         data = &countBuf;
03195         count = 1;
03196         type = RPM_INT32_TYPE;
03197     }
03198 
03199 /*@-boundswrite@*/
03200     (void) stpcpy( stpcpy(buf, "%"), tag->format);
03201 /*@=boundswrite@*/
03202 
03203     /*@-branchstate@*/
03204     if (data)
03205     switch (type) {
03206     case RPM_STRING_ARRAY_TYPE:
03207         strarray = (const char **)data;
03208 
03209         if (tag->fmt)
03210             val = tag->fmt(RPM_STRING_TYPE, strarray[element], buf, tag->pad, (count > 1 ? element : -1));
03211 
03212         if (val) {
03213             need = strlen(val);
03214         } else {
03215             need = strlen(strarray[element]) + tag->pad + 20;
03216             val = xmalloc(need+1);
03217             strcat(buf, "s");
03218             /*@-formatconst@*/
03219             sprintf(val, buf, strarray[element]);
03220             /*@=formatconst@*/
03221         }
03222 
03223         break;
03224 
03225     case RPM_STRING_TYPE:
03226         if (tag->fmt)
03227             val = tag->fmt(RPM_STRING_TYPE, data, buf, tag->pad,  -1);
03228 
03229         if (val) {
03230             need = strlen(val);
03231         } else {
03232             need = strlen(data) + tag->pad + 20;
03233             val = xmalloc(need+1);
03234             strcat(buf, "s");
03235             /*@-formatconst@*/
03236             sprintf(val, buf, data);
03237             /*@=formatconst@*/
03238         }
03239         break;
03240 
03241     case RPM_INT64_TYPE:
03242         llVal = *(((int_64 *) data) + element);
03243         if (tag->fmt)
03244             val = tag->fmt(RPM_INT64_TYPE, &llVal, buf, tag->pad, (count > 1 ? element : -1));
03245         if (val) {
03246             need = strlen(val);
03247         } else {
03248             need = 10 + tag->pad + 40;
03249             val = xmalloc(need+1);
03250             strcat(buf, "lld");
03251             /*@-formatconst@*/
03252             sprintf(val, buf, llVal);
03253             /*@=formatconst@*/
03254         }
03255         break;
03256 
03257     case RPM_CHAR_TYPE:
03258     case RPM_INT8_TYPE:
03259     case RPM_INT16_TYPE:
03260     case RPM_INT32_TYPE:
03261         switch (type) {
03262         case RPM_CHAR_TYPE:     
03263         case RPM_INT8_TYPE:
03264             intVal = *(((int_8 *) data) + element);
03265             /*@innerbreak@*/ break;
03266         case RPM_INT16_TYPE:
03267             intVal = *(((uint_16 *) data) + element);
03268             /*@innerbreak@*/ break;
03269         default:                /* keep -Wall quiet */
03270         case RPM_INT32_TYPE:
03271             intVal = *(((int_32 *) data) + element);
03272             /*@innerbreak@*/ break;
03273         }
03274 
03275         if (tag->fmt)
03276             val = tag->fmt(RPM_INT32_TYPE, &intVal, buf, tag->pad, (count > 1 ? element : -1));
03277 
03278         if (val) {
03279             need = strlen(val);
03280         } else {
03281             need = 10 + tag->pad + 20;
03282             val = xmalloc(need+1);
03283             strcat(buf, "d");
03284             /*@-formatconst@*/
03285             sprintf(val, buf, intVal);
03286             /*@=formatconst@*/
03287         }
03288         break;
03289 
03290     case RPM_OPENPGP_TYPE:      /* XXX W2DO? */
03291     case RPM_ASN1_TYPE:         /* XXX W2DO? */
03292     case RPM_BIN_TYPE:
03293         /* XXX HACK ALERT: element field abused as no. bytes of binary data. */
03294         if (tag->fmt)
03295             val = tag->fmt(RPM_BIN_TYPE, data, buf, tag->pad, count);
03296 
03297         if (val) {
03298             need = strlen(val);
03299         } else {
03300 #ifdef  NOTYET
03301             val = memcpy(xmalloc(count), data, count);
03302 #else
03303             /* XXX format string not used */
03304             static char hex[] = "0123456789abcdef";
03305             const char * s = data;
03306 
03307 /*@-boundswrite@*/
03308             need = 2*count + tag->pad;
03309             val = t = xmalloc(need+1);
03310             while (count-- > 0) {
03311                 unsigned int i;
03312                 i = *s++;
03313                 *t++ = hex[ (i >> 4) & 0xf ];
03314                 *t++ = hex[ (i     ) & 0xf ];
03315             }
03316             *t = '\0';
03317 /*@=boundswrite@*/
03318 #endif
03319         }
03320         break;
03321 
03322     default:
03323         need = sizeof("(unknown type)") - 1;
03324         val = xstrdup("(unknown type)");
03325         break;
03326     }
03327     /*@=branchstate@*/
03328 
03329     /*@-branchstate -observertrans -modobserver@*/
03330     if (datafree)
03331         data = headerFreeData(data, type);
03332     /*@=branchstate =observertrans =modobserver@*/
03333 
03334     /*@-branchstate@*/
03335     if (val && need > 0) {
03336         t = hsaReserve(hsa, need);
03337 /*@-boundswrite@*/
03338         te = stpcpy(t, val);
03339 /*@=boundswrite@*/
03340         hsa->vallen += (te - t);
03341         val = _free(val);
03342     }
03343     /*@=branchstate@*/
03344 
03345     return (hsa->val + hsa->vallen);
03346 }
03347 
03355 /*@observer@*/
03356 static char * singleSprintf(headerSprintfArgs hsa, sprintfToken token,
03357                 int element)
03358         /*@modifies hsa @*/
03359 {
03360     char numbuf[64];    /* XXX big enuf for "Tag_0x01234567" */
03361     char * t, * te;
03362     int i, j;
03363     int numElements;
03364     int_32 type;
03365     int_32 count;
03366     sprintfToken spft;
03367     int condNumFormats;
03368     size_t need;
03369 
03370     /* we assume the token and header have been validated already! */
03371 
03372     switch (token->type) {
03373     case PTOK_NONE:
03374         break;
03375 
03376     case PTOK_STRING:
03377         need = token->u.string.len;
03378         if (need == 0) break;
03379         t = hsaReserve(hsa, need);
03380 /*@-boundswrite@*/
03381         te = stpcpy(t, token->u.string.string);
03382 /*@=boundswrite@*/
03383         hsa->vallen += (te - t);
03384         break;
03385 
03386     case PTOK_TAG:
03387         t = hsa->val + hsa->vallen;
03388         te = formatValue(hsa, &token->u.tag,
03389                         (token->u.tag.justOne ? 0 : element));
03390         if (te == NULL)
03391             return NULL;
03392         break;
03393 
03394     case PTOK_COND:
03395         if (token->u.cond.tag.ext || headerIsEntry(hsa->h, token->u.cond.tag.tag)) {
03396             spft = token->u.cond.ifFormat;
03397             condNumFormats = token->u.cond.numIfTokens;
03398         } else {
03399             spft = token->u.cond.elseFormat;
03400             condNumFormats = token->u.cond.numElseTokens;
03401         }
03402 
03403         need = condNumFormats * 20;
03404         if (spft == NULL || need == 0) break;
03405 
03406         t = hsaReserve(hsa, need);
03407         for (i = 0; i < condNumFormats; i++, spft++) {
03408             te = singleSprintf(hsa, spft, element);
03409             if (te == NULL)
03410                 return NULL;
03411         }
03412         break;
03413 
03414     case PTOK_ARRAY:
03415         numElements = -1;
03416         spft = token->u.array.format;
03417         for (i = 0; i < token->u.array.numTokens; i++, spft++)
03418         {
03419             if (spft->type != PTOK_TAG ||
03420                 spft->u.tag.arrayCount ||
03421                 spft->u.tag.justOne) continue;
03422 
03423             if (spft->u.tag.ext) {
03424 /*@-boundswrite@*/
03425                 if (getExtension(hsa, spft->u.tag.ext, &type, NULL, &count, 
03426                                  hsa->ec + spft->u.tag.extNum))
03427                      continue;
03428 /*@=boundswrite@*/
03429             } else {
03430 /*@-boundswrite@*/
03431                 if (!headerGetEntry(hsa->h, spft->u.tag.tag, &type, NULL, &count))
03432                     continue;
03433 /*@=boundswrite@*/
03434             } 
03435 
03436             if (type == RPM_BIN_TYPE || type == RPM_ASN1_TYPE || type == RPM_OPENPGP_TYPE)
03437                 count = 1;      /* XXX count abused as no. of bytes. */
03438 
03439             if (numElements > 1 && count != numElements)
03440             switch (type) {
03441             default:
03442                 hsa->errmsg =
03443                         _("array iterator used with different sized arrays");
03444                 return NULL;
03445                 /*@notreached@*/ /*@switchbreak@*/ break;
03446             case RPM_OPENPGP_TYPE:
03447             case RPM_ASN1_TYPE:
03448             case RPM_BIN_TYPE:
03449             case RPM_STRING_TYPE:
03450                 /*@switchbreak@*/ break;
03451             }
03452             if (count > numElements)
03453                 numElements = count;
03454         }
03455 
03456         if (numElements == -1) {
03457 #ifdef  DYING   /* XXX lots of pugly "(none)" lines with --conflicts. */
03458             need = sizeof("(none)\n") - 1;
03459             t = hsaReserve(hsa, need);
03460 /*@-boundswrite@*/
03461             te = stpcpy(t, "(none)\n");
03462 /*@=boundswrite@*/
03463             hsa->vallen += (te - t);
03464 #endif
03465         } else {
03466             int isxml;
03467             int isyaml;
03468 
03469             need = numElements * token->u.array.numTokens;
03470             if (need == 0) break;
03471 
03472             spft = token->u.array.format;
03473             isxml = (spft->type == PTOK_TAG && spft->u.tag.type != NULL &&
03474                 !strcmp(spft->u.tag.type, "xml"));
03475             isyaml = (spft->type == PTOK_TAG && spft->u.tag.type != NULL &&
03476                 !strcmp(spft->u.tag.type, "yaml"));
03477 
03478             if (isxml) {
03479                 const char * tagN = myTagName(hsa->tags, spft->u.tag.tag, NULL);
03480                 /* XXX display "Tag_0x01234567" for unknown tags. */
03481                 if (tagN == NULL) {
03482                     (void) snprintf(numbuf, sizeof(numbuf), "Tag_0x%08x",
03483                                 spft->u.tag.tag);
03484                     numbuf[sizeof(numbuf)-1] = '\0';
03485                     tagN = numbuf;
03486                 }
03487                 need = sizeof("  <rpmTag name=\"\">\n") + strlen(tagN);
03488                 te = t = hsaReserve(hsa, need);
03489 /*@-boundswrite@*/
03490                 te = stpcpy( stpcpy( stpcpy(te, "  <rpmTag name=\""), tagN), "\">\n");
03491 /*@=boundswrite@*/
03492                 hsa->vallen += (te - t);
03493             }
03494             if (isyaml) {
03495                 int tagT = -1;
03496                 const char * tagN = myTagName(hsa->tags, spft->u.tag.tag, &tagT);
03497                 /* XXX display "Tag_0x01234567" for unknown tags. */
03498                 if (tagN == NULL) {
03499                     (void) snprintf(numbuf, sizeof(numbuf), "Tag_0x%08x",
03500                                 spft->u.tag.tag);
03501                     numbuf[sizeof(numbuf)-1] = '\0';
03502                     tagN = numbuf;
03503                     tagT = numElements > 1
03504                         ?  RPM_ARRAY_RETURN_TYPE : RPM_SCALAR_RETURN_TYPE;
03505                 }
03506                 need = sizeof("  :     - ") + strlen(tagN);
03507                 te = t = hsaReserve(hsa, need);
03508 /*@-boundswrite@*/
03509                 *te++ = ' ';
03510                 *te++ = ' ';
03511                 te = stpcpy(te, tagN);
03512                 *te++ = ':';
03513                 *te++ = (((tagT & RPM_MASK_RETURN_TYPE) == RPM_ARRAY_RETURN_TYPE)
03514                         ? '\n' : ' ');
03515                 /* XXX Dirnames: in srpms need "    " indent */
03516                 if (((tagT & RPM_MASK_RETURN_TYPE) == RPM_ARRAY_RETURN_TYPE)
03517                  && numElements == 1) {
03518                     te = stpcpy(te, "    ");
03519                     if (spft->u.tag.tag != 1118)
03520                         te = stpcpy(te, "- ");
03521                 }
03522                 *te = '\0';
03523 /*@=boundswrite@*/
03524                 hsa->vallen += (te - t);
03525             }
03526 
03527             need = numElements * token->u.array.numTokens * 10;
03528             t = hsaReserve(hsa, need);
03529             for (j = 0; j < numElements; j++) {
03530                 spft = token->u.array.format;
03531                 for (i = 0; i < token->u.array.numTokens; i++, spft++) {
03532                     te = singleSprintf(hsa, spft, j);
03533                     if (te == NULL)
03534                         return NULL;
03535                 }
03536             }
03537 
03538             if (isxml) {
03539                 need = sizeof("  </rpmTag>\n") - 1;
03540                 te = t = hsaReserve(hsa, need);
03541 /*@-boundswrite@*/
03542                 te = stpcpy(te, "  </rpmTag>\n");
03543 /*@=boundswrite@*/
03544                 hsa->vallen += (te - t);
03545             }
03546             if (isyaml) {
03547 #if 0
03548                 need = sizeof("\n") - 1;
03549                 te = t = hsaReserve(hsa, need);
03550 /*@-boundswrite@*/
03551                 te = stpcpy(te, "\n");
03552 /*@=boundswrite@*/
03553                 hsa->vallen += (te - t);
03554 #endif
03555             }
03556 
03557         }
03558         break;
03559     }
03560 
03561     return (hsa->val + hsa->vallen);
03562 }
03563 
03569 static /*@only@*/ rpmec
03570 rpmecNew(const headerSprintfExtension exts)
03571         /*@*/
03572 {
03573     headerSprintfExtension ext;
03574     rpmec ec;
03575     int i = 0;
03576 
03577     for (ext = exts; ext != NULL && ext->type != HEADER_EXT_LAST;
03578         ext = (ext->type == HEADER_EXT_MORE ? ext->u.more : ext+1))
03579     {
03580         i++;
03581     }
03582 
03583     ec = xcalloc(i, sizeof(*ec));
03584     return ec;
03585 }
03586 
03593 static /*@null@*/ rpmec
03594 rpmecFree(const headerSprintfExtension exts, /*@only@*/ rpmec ec)
03595         /*@modifies ec @*/
03596 {
03597     headerSprintfExtension ext;
03598     int i = 0;
03599 
03600     for (ext = exts; ext != NULL && ext->type != HEADER_EXT_LAST;
03601         ext = (ext->type == HEADER_EXT_MORE ? ext->u.more : ext+1))
03602     {
03603 /*@-boundswrite@*/
03604         if (ec[i].freeit) ec[i].data = _free(ec[i].data);
03605 /*@=boundswrite@*/
03606         i++;
03607     }
03608 
03609     ec = _free(ec);
03610     return NULL;
03611 }
03612 
03624 static /*@only@*/ /*@null@*/
03625 char * headerSprintf(Header h, const char * fmt,
03626                      const struct headerTagTableEntry_s * tbltags,
03627                      const struct headerSprintfExtension_s * extensions,
03628                      /*@null@*/ /*@out@*/ errmsg_t * errmsg)
03629         /*@modifies h, *errmsg @*/
03630         /*@requires maxSet(errmsg) >= 0 @*/
03631 {
03632     headerSprintfArgs hsa = memset(alloca(sizeof(*hsa)), 0, sizeof(*hsa));
03633     sprintfToken nextfmt;
03634     sprintfTag tag;
03635     char * t, * te;
03636     int isxml;
03637     int isyaml;
03638     int need;
03639  
03640     hsa->h = headerLink(h);
03641     hsa->fmt = xstrdup(fmt);
03642 /*@-castexpose@*/       /* FIX: legacy API shouldn't change. */
03643     hsa->exts = (headerSprintfExtension) extensions;
03644     hsa->tags = (headerTagTableEntry) tbltags;
03645 /*@=castexpose@*/
03646     hsa->errmsg = NULL;
03647 
03648 /*@-boundswrite@*/
03649     if (parseFormat(hsa, hsa->fmt, &hsa->format, &hsa->numTokens, NULL, PARSER_BEGIN))
03650         goto exit;
03651 /*@=boundswrite@*/
03652 
03653     hsa->ec = rpmecNew(hsa->exts);
03654     hsa->val = xstrdup("");
03655 
03656     tag =
03657         (hsa->format->type == PTOK_TAG
03658             ? &hsa->format->u.tag :
03659         (hsa->format->type == PTOK_ARRAY
03660             ? &hsa->format->u.array.format->u.tag :
03661         NULL));
03662     isxml = (tag != NULL && tag->tag == -2 && tag->type != NULL && !strcmp(tag->type, "xml"));
03663     isyaml = (tag != NULL && tag->tag == -2 && tag->type != NULL && !strcmp(tag->type, "yaml"));
03664 
03665     if (isxml) {
03666         need = sizeof("<rpmHeader>\n") - 1;
03667         t = hsaReserve(hsa, need);
03668 /*@-boundswrite@*/
03669         te = stpcpy(t, "<rpmHeader>\n");
03670 /*@=boundswrite@*/
03671         hsa->vallen += (te - t);
03672     }
03673     if (isyaml) {
03674         need = sizeof("- !!omap\n") - 1;
03675         t = hsaReserve(hsa, need);
03676 /*@-boundswrite@*/
03677         te = stpcpy(t, "- !!omap\n");
03678 /*@=boundswrite@*/
03679         hsa->vallen += (te - t);
03680     }
03681 
03682     hsa = hsaInit(hsa);
03683     while ((nextfmt = hsaNext(hsa)) != NULL) {
03684         te = singleSprintf(hsa, nextfmt, 0);
03685         if (te == NULL) {
03686             hsa->val = _free(hsa->val);
03687             break;
03688         }
03689     }
03690     hsa = hsaFini(hsa);
03691 
03692     if (isxml) {
03693         need = sizeof("</rpmHeader>\n") - 1;
03694         t = hsaReserve(hsa, need);
03695 /*@-boundswrite@*/
03696         te = stpcpy(t, "</rpmHeader>\n");
03697 /*@=boundswrite@*/
03698         hsa->vallen += (te - t);
03699     }
03700     if (isyaml) {
03701         need = sizeof("\n") - 1;
03702         t = hsaReserve(hsa, need);
03703 /*@-boundswrite@*/
03704         te = stpcpy(t, "\n");
03705 /*@=boundswrite@*/
03706         hsa->vallen += (te - t);
03707     }
03708 
03709     if (hsa->val != NULL && hsa->vallen < hsa->alloced)
03710         hsa->val = xrealloc(hsa->val, hsa->vallen+1);   
03711 
03712     hsa->ec = rpmecFree(hsa->exts, hsa->ec);
03713     hsa->format = freeFormat(hsa->format, hsa->numTokens);
03714 
03715 exit:
03716 /*@-dependenttrans -observertrans @*/
03717     if (errmsg)
03718         *errmsg = hsa->errmsg;
03719 /*@=dependenttrans =observertrans @*/
03720     hsa->h = headerFree(hsa->h);
03721     hsa->fmt = _free(hsa->fmt);
03722     return hsa->val;
03723 }
03724 
03734 static char * octalFormat(int_32 type, hPTR_t data, 
03735                 char * formatPrefix, int padding, /*@unused@*/int element)
03736         /*@modifies formatPrefix @*/
03737 {
03738     char * val;
03739 
03740     if (type == RPM_INT32_TYPE) {
03741         val = xmalloc(20 + padding);
03742 /*@-boundswrite@*/
03743         strcat(formatPrefix, "o");
03744 /*@=boundswrite@*/
03745         /*@-formatconst@*/
03746         sprintf(val, formatPrefix, *((int_32 *) data));
03747         /*@=formatconst@*/
03748     } else if (type == RPM_INT64_TYPE) {
03749         val = xmalloc(40 + padding);
03750 /*@-boundswrite@*/
03751         strcat(formatPrefix, "llo");
03752 /*@=boundswrite@*/
03753         /*@-formatconst@*/
03754         sprintf(val, formatPrefix, *((int_64 *) data));
03755         /*@=formatconst@*/
03756     } else
03757         val = xstrdup(_("(not a number)"));
03758 
03759     return val;
03760 }
03761 
03771 static char * hexFormat(int_32 type, hPTR_t data, 
03772                 char * formatPrefix, int padding, /*@unused@*/int element)
03773         /*@modifies formatPrefix @*/
03774 {
03775     char * val;
03776 
03777     if (type == RPM_INT32_TYPE) {
03778         val = xmalloc(20 + padding);
03779 /*@-boundswrite@*/
03780         strcat(formatPrefix, "x");
03781 /*@=boundswrite@*/
03782         /*@-formatconst@*/
03783         sprintf(val, formatPrefix, *((int_32 *) data));
03784         /*@=formatconst@*/
03785     } else if (type == RPM_INT64_TYPE) {
03786         val = xmalloc(40 + padding);
03787 /*@-boundswrite@*/
03788         strcat(formatPrefix, "llx");
03789 /*@=boundswrite@*/
03790         /*@-formatconst@*/
03791         sprintf(val, formatPrefix, *((int_64 *) data));
03792         /*@=formatconst@*/
03793     } else
03794         val = xstrdup(_("(not a number)"));
03795 
03796     return val;
03797 }
03798 
03809 static char * realDateFormat(int_32 type, hPTR_t data, 
03810                 char * formatPrefix, int padding, /*@unused@*/int element,
03811                 const char * strftimeFormat)
03812         /*@modifies formatPrefix @*/
03813 {
03814     char * val;
03815 
03816     if (type != RPM_INT32_TYPE) {
03817         val = xstrdup(_("(not a number)"));
03818     } else {
03819         struct tm * tstruct;
03820         char buf[50];
03821 
03822         val = xmalloc(50 + padding);
03823 /*@-boundswrite@*/
03824         strcat(formatPrefix, "s");
03825 /*@=boundswrite@*/
03826 
03827         /* this is important if sizeof(int_32) ! sizeof(time_t) */
03828         {   time_t dateint = *((int_32 *) data);
03829             tstruct = localtime(&dateint);
03830         }
03831         buf[0] = '\0';
03832         if (tstruct)
03833             (void) strftime(buf, sizeof(buf) - 1, strftimeFormat, tstruct);
03834         /*@-formatconst@*/
03835         sprintf(val, formatPrefix, buf);
03836         /*@=formatconst@*/
03837     }
03838 
03839     return val;
03840 }
03841 
03851 static char * dateFormat(int_32 type, hPTR_t data, 
03852                          char * formatPrefix, int padding, int element)
03853         /*@modifies formatPrefix @*/
03854 {
03855     return realDateFormat(type, data, formatPrefix, padding, element,
03856                         _("%c"));
03857 }
03858 
03868 static char * dayFormat(int_32 type, hPTR_t data, 
03869                          char * formatPrefix, int padding, int element)
03870         /*@modifies formatPrefix @*/
03871 {
03872     return realDateFormat(type, data, formatPrefix, padding, element, 
03873                           _("%a %b %d %Y"));
03874 }
03875 
03885 static char * shescapeFormat(int_32 type, hPTR_t data, 
03886                 char * formatPrefix, int padding, /*@unused@*/int element)
03887         /*@modifies formatPrefix @*/
03888 {
03889     char * result, * dst, * src, * buf;
03890 
03891     if (type == RPM_INT32_TYPE) {
03892         result = xmalloc(padding + 20);
03893 /*@-boundswrite@*/
03894         strcat(formatPrefix, "d");
03895 /*@=boundswrite@*/
03896         /*@-formatconst@*/
03897         sprintf(result, formatPrefix, *((int_32 *) data));
03898         /*@=formatconst@*/
03899     } else if (type == RPM_INT64_TYPE) {
03900         result = xmalloc(padding + 40);
03901 /*@-boundswrite@*/
03902         strcat(formatPrefix, "lld");
03903 /*@=boundswrite@*/
03904         /*@-formatconst@*/
03905         sprintf(result, formatPrefix, *((int_64 *) data));
03906         /*@=formatconst@*/
03907     } else {
03908         buf = alloca(strlen(data) + padding + 2);
03909 /*@-boundswrite@*/
03910         strcat(formatPrefix, "s");
03911 /*@=boundswrite@*/
03912         /*@-formatconst@*/
03913         sprintf(buf, formatPrefix, data);
03914         /*@=formatconst@*/
03915 
03916 /*@-boundswrite@*/
03917         result = dst = xmalloc(strlen(buf) * 4 + 3);
03918         *dst++ = '\'';
03919         for (src = buf; *src != '\0'; src++) {
03920             if (*src == '\'') {
03921                 *dst++ = '\'';
03922                 *dst++ = '\\';
03923                 *dst++ = '\'';
03924                 *dst++ = '\'';
03925             } else {
03926                 *dst++ = *src;
03927             }
03928         }
03929         *dst++ = '\'';
03930         *dst = '\0';
03931 /*@=boundswrite@*/
03932 
03933     }
03934 
03935     return result;
03936 }
03937 
03938 /*@-type@*/ /* FIX: cast? */
03939 const struct headerSprintfExtension_s headerDefaultFormats[] = {
03940     { HEADER_EXT_FORMAT, "octal", { octalFormat } },
03941     { HEADER_EXT_FORMAT, "hex", { hexFormat } },
03942     { HEADER_EXT_FORMAT, "date", { dateFormat } },
03943     { HEADER_EXT_FORMAT, "day", { dayFormat } },
03944     { HEADER_EXT_FORMAT, "shescape", { shescapeFormat } },
03945     { HEADER_EXT_LAST, NULL, { NULL } }
03946 };
03947 /*@=type@*/
03948 
03955 static
03956 void headerCopyTags(Header headerFrom, Header headerTo, hTAG_t tagstocopy)
03957         /*@modifies headerTo @*/
03958 {
03959     int * p;
03960 
03961     if (headerFrom == headerTo)
03962         return;
03963 
03964     for (p = tagstocopy; *p != 0; p++) {
03965         char *s;
03966         int_32 type;
03967         int_32 count;
03968         if (headerIsEntry(headerTo, *p))
03969             continue;
03970 /*@-boundswrite@*/
03971         if (!headerGetEntryMinMemory(headerFrom, *p, &type, &s, &count))
03972             continue;
03973 /*@=boundswrite@*/
03974         (void) headerAddEntry(headerTo, *p, type, s, count);
03975         s = headerFreeData(s, type);
03976     }
03977 }
03978 
03979 /*@observer@*/ /*@unchecked@*/
03980 static struct HV_s hdrVec1 = {
03981     headerLink,
03982     headerUnlink,
03983     headerFree,
03984     headerNew,
03985     headerSort,
03986     headerUnsort,
03987     headerSizeof,
03988     headerUnload,
03989     headerReload,
03990     headerCopy,
03991     headerLoad,
03992     headerCopyLoad,
03993     headerRead,
03994     headerWrite,
03995     headerIsEntry,
03996     headerFreeTag,
03997     headerGetEntry,
03998     headerGetEntryMinMemory,
03999     headerAddEntry,
04000     headerAppendEntry,
04001     headerAddOrAppendEntry,
04002     headerAddI18NString,
04003     headerModifyEntry,
04004     headerRemoveEntry,
04005     headerSprintf,
04006     headerCopyTags,
04007     headerFreeIterator,
04008     headerInitIterator,
04009     headerNextIterator,
04010     headerGetOrigin,
04011     headerSetOrigin,
04012     headerGetInstance,
04013     headerSetInstance,
04014     NULL, NULL,
04015     1
04016 };
04017 
04018 /*@-compmempass -redef@*/
04019 /*@observer@*/ /*@unchecked@*/
04020 HV_t hdrVec = &hdrVec1;
04021 /*@=compmempass =redef@*/

Generated on Fri Aug 31 12:48:25 2007 for rpm by  doxygen 1.5.1