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

Generated on Tue Jan 15 14:31:12 2013 for rpm by  doxygen 1.4.7