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

lib/header.c

Go to the documentation of this file.
00001 
00005 /* RPM - Copyright (C) 1995-2000 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 /*@-redecl@*/   /* FIX: avoid rpmlib.h, need for debugging. */
00020 /*@observer@*/ const char *const tagName(int tag)       /*@*/;
00021 /*@=redecl@*/
00022 
00023 /*@access entryInfo @*/
00024 /*@access indexEntry @*/
00025 
00026 /*@access extensionCache @*/
00027 /*@access sprintfTag @*/
00028 /*@access sprintfToken @*/
00029 /*@access HV_t @*/
00030 
00031 #define PARSER_BEGIN    0
00032 #define PARSER_IN_ARRAY 1
00033 #define PARSER_IN_EXPR  2
00034 
00037 static unsigned char header_magic[8] = {
00038         0x8e, 0xad, 0xe8, 0x01, 0x00, 0x00, 0x00, 0x00
00039 };
00040 
00044 static size_t headerMaxbytes = (32*1024*1024);
00045 
00050 #define hdrchkTags(_ntags)      ((_ntags) & 0xffff0000)
00051 
00056 #define hdrchkData(_nbytes)     ((_nbytes) & 0xff000000)
00057 
00061 static int typeSizes[] =  { 
00062         0,      
00063         1,      
00064         1,      
00065         2,      
00066         4,      
00067         -1,     
00068         -1,     
00069         1,      
00070         -1,     
00071         -1      
00072 };
00073 
00074 HV_t hdrVec;    /* forward reference */
00075 
00081 /*@unused@*/ static inline /*@null@*/ void *
00082 _free(/*@only@*/ /*@null@*/ const void * p) /*@modifies *p @*/
00083 {
00084     if (p != NULL)      free((void *)p);
00085     return NULL;
00086 }
00087 
00088 Header headerNew()
00089 {
00090     Header h = xcalloc(1, sizeof(*h));
00091 
00092     /*@-assignexpose@*/
00093     h->hv = *hdrVec;            /* structure assignment */
00094     /*@=assignexpose@*/
00095     h->blob = NULL;
00096     h->indexAlloced = INDEX_MALLOC_SIZE;
00097     h->indexUsed = 0;
00098     h->flags = HEADERFLAG_SORTED;
00099     h->nrefs = 1;
00100 
00101     h->index = (h->indexAlloced
00102         ? xcalloc(h->indexAlloced, sizeof(*h->index))
00103         : NULL);
00104 
00105     /*@-globstate@*/
00106     return h;
00107     /*@=globstate@*/
00108 }
00109 
00110 Header headerFree(Header h)
00111 {
00112     if (h == NULL || --h->nrefs > 0)
00113         return NULL;    /* XXX return previous header? */
00114 
00115     if (h->index) {
00116         indexEntry entry = h->index;
00117         int i;
00118         for (i = 0; i < h->indexUsed; i++, entry++) {
00119             if ((h->flags & HEADERFLAG_ALLOCATED) && ENTRY_IS_REGION(entry)) {
00120                 if (entry->length > 0) {
00121                     int_32 * ei = entry->data;
00122                     if ((ei - 2) == h->blob) h->blob = _free(h->blob);
00123                     entry->data = NULL;
00124                 }
00125             } else if (!ENTRY_IN_REGION(entry)) {
00126                 entry->data = _free(entry->data);
00127             }
00128             entry->data = NULL;
00129         }
00130         h->index = _free(h->index);
00131     }
00132 
00133     /*@-refcounttrans@*/ h = _free(h); /*@=refcounttrans@*/
00134     return h;
00135 }
00136 
00137 Header headerLink(Header h)
00138 {
00139     h->nrefs++;
00140     /*@-refcounttrans@*/ return h; /*@=refcounttrans@*/
00141 }
00142 
00145 static int indexCmp(const void * avp, const void * bvp) /*@*/
00146 {
00147     /*@-castexpose@*/
00148     indexEntry ap = (indexEntry) avp, bp = (indexEntry) bvp;
00149     /*@=castexpose@*/
00150     return (ap->info.tag - bp->info.tag);
00151 }
00152 
00153 void headerSort(Header h)
00154 {
00155     if (!(h->flags & HEADERFLAG_SORTED)) {
00156         qsort(h->index, h->indexUsed, sizeof(*h->index), indexCmp);
00157         h->flags |= HEADERFLAG_SORTED;
00158     }
00159 }
00160 
00163 static int offsetCmp(const void * avp, const void * bvp) /*@*/
00164 {
00165     /*@-castexpose@*/
00166     indexEntry ap = (indexEntry) avp, bp = (indexEntry) bvp;
00167     /*@=castexpose@*/
00168     int rc = (ap->info.offset - bp->info.offset);
00169 
00170     if (rc == 0) {
00171         /* Within a region, entries sort by address. Added drips sort by tag. */
00172         if (ap->info.offset < 0)
00173             rc = (((char *)ap->data) - ((char *)bp->data));
00174         else
00175             rc = (ap->info.tag - bp->info.tag);
00176     }
00177     return rc;
00178 }
00179 
00180 void headerUnsort(Header h)
00181 {
00182     qsort(h->index, h->indexUsed, sizeof(*h->index), offsetCmp);
00183 }
00184 
00185 unsigned int headerSizeof(Header h, enum hMagic magicp)
00186 {
00187     indexEntry entry;
00188     unsigned int size = 0;
00189     unsigned int pad = 0;
00190     int i;
00191 
00192     if (h == NULL)
00193         return size;
00194 
00195     headerSort(h);
00196 
00197     switch (magicp) {
00198     case HEADER_MAGIC_YES:
00199         size += sizeof(header_magic);
00200         break;
00201     case HEADER_MAGIC_NO:
00202         break;
00203     }
00204 
00205     size += 2 * sizeof(int_32); /* count of index entries */
00206 
00207     for (i = 0, entry = h->index; i < h->indexUsed; i++, entry++) {
00208         unsigned diff;
00209         int_32 type;
00210 
00211         /* Regions go in as is ... */
00212         if (ENTRY_IS_REGION(entry)) {
00213             size += entry->length;
00214             /* XXX Legacy regions do not include the region tag and data. */
00215             if (i == 0 && (h->flags & HEADERFLAG_LEGACY))
00216                 size += sizeof(struct entryInfo) + entry->info.count;
00217             continue;
00218         }
00219 
00220         /* ... and region elements are skipped. */
00221         if (entry->info.offset < 0)
00222             continue;
00223 
00224         /* Alignment */
00225         type = entry->info.type;
00226         if (typeSizes[type] > 1) {
00227             diff = typeSizes[type] - (size % typeSizes[type]);
00228             if (diff != typeSizes[type]) {
00229                 size += diff;
00230                 pad += diff;
00231             }
00232         }
00233 
00234         size += sizeof(struct entryInfo) + entry->length;
00235     }
00236 
00237     return size;
00238 }
00239 
00248 /*@mayexit@*/
00249 static int dataLength(int_32 type, hPTR_t p, int_32 count, int onDisk)
00250         /*@modifies fileSystem @*/
00251 {
00252     int length = 0;
00253 
00254     switch (type) {
00255     case RPM_STRING_TYPE:
00256         if (count == 1) {       /* Special case -- p is just the string */
00257             length = strlen(p) + 1;
00258             break;
00259         }
00260         /* This should not be allowed */
00261         fprintf(stderr, _("dataLength() RPM_STRING_TYPE count must be 1.\n"));
00262         exit(EXIT_FAILURE);
00263         /*@notreached@*/ break;
00264 
00265     case RPM_STRING_ARRAY_TYPE:
00266     case RPM_I18NSTRING_TYPE:
00267     {   int i;
00268 
00269         /* This is like RPM_STRING_TYPE, except it's *always* an array */
00270         /* Compute sum of length of all strings, including null terminators */
00271         i = count;
00272 
00273         if (onDisk) {
00274             const char * chptr = p;
00275             int thisLen;
00276 
00277             while (i--) {
00278                 thisLen = strlen(chptr) + 1;
00279                 length += thisLen;
00280                 chptr += thisLen;
00281             }
00282         } else {
00283             const char ** src = (const char **)p;
00284             while (i--) {
00285                 /* add one for null termination */
00286                 length += strlen(*src++) + 1;
00287             }
00288         }
00289     }   break;
00290 
00291     default:
00292         if (typeSizes[type] != -1) {
00293             length = typeSizes[type] * count;
00294             break;
00295         }
00296         fprintf(stderr, _("Data type %d not supported\n"), (int) type);
00297         exit(EXIT_FAILURE);
00298         /*@notreached@*/ break;
00299     }
00300 
00301     return length;
00302 }
00303 
00329 static int regionSwab(/*@null@*/ indexEntry entry, int il, int dl,
00330                 entryInfo pe, char * dataStart, int regionid)
00331         /*@modifies *entry, *dataStart @*/
00332 {
00333     char * tprev = NULL;
00334     char * t = NULL;
00335     int tdel, tl = dl;
00336     struct indexEntry ieprev;
00337 
00338     memset(&ieprev, 0, sizeof(ieprev));
00339     for (; il > 0; il--, pe++) {
00340         struct indexEntry ie;
00341         int_32 type;
00342 
00343         ie.info.tag = ntohl(pe->tag);
00344         ie.info.type = ntohl(pe->type);
00345         if (ie.info.type < RPM_MIN_TYPE || ie.info.type > RPM_MAX_TYPE)
00346             return -1;
00347         ie.info.count = ntohl(pe->count);
00348         ie.info.offset = ntohl(pe->offset);
00349         ie.data = t = dataStart + ie.info.offset;
00350         ie.length = dataLength(ie.info.type, ie.data, ie.info.count, 1);
00351         ie.rdlen = 0;
00352 
00353         if (entry) {
00354             ie.info.offset = regionid;
00355             *entry = ie;        /* structure assignment */
00356             entry++;
00357         }
00358 
00359         /* Alignment */
00360         type = ie.info.type;
00361         if (typeSizes[type] > 1) {
00362             unsigned diff;
00363             diff = typeSizes[type] - (dl % typeSizes[type]);
00364             if (diff != typeSizes[type]) {
00365                 dl += diff;
00366                 if (ieprev.info.type == RPM_I18NSTRING_TYPE)
00367                     ieprev.length += diff;
00368             }
00369         }
00370         tdel = (tprev ? (t - tprev) : 0);
00371         if (ieprev.info.type == RPM_I18NSTRING_TYPE)
00372             tdel = ieprev.length;
00373 
00374         if (ie.info.tag >= HEADER_I18NTABLE) {
00375             tprev = t;
00376         } else {
00377             tprev = dataStart;
00378             /* XXX HEADER_IMAGE tags don't include region sub-tag. */
00379             if (ie.info.tag != HEADER_IMMUTABLE)
00380                 tprev -= REGION_TAG_COUNT;
00381         }
00382 
00383         /* Perform endian conversions */
00384         switch (ntohl(pe->type)) {
00385         case RPM_INT32_TYPE:
00386         {   int_32 * it = (int_32 *)t;
00387             for (; ie.info.count > 0; ie.info.count--, it += 1)
00388                 *it = htonl(*it);
00389             t = (char *) it;
00390         }   break;
00391         case RPM_INT16_TYPE:
00392         {   int_16 * it = (int_16 *) t;
00393             for (; ie.info.count > 0; ie.info.count--, it += 1)
00394                 *it = htons(*it);
00395             t = (char *) it;
00396         }   break;
00397         default:
00398             t += ie.length;
00399             break;
00400         }
00401 
00402         dl += ie.length;
00403         tl += tdel;
00404         ieprev = ie;    /* structure assignment */
00405 
00406     }
00407     tdel = (tprev ? (t - tprev) : 0);
00408     tl += tdel;
00409 
00410     /* XXX
00411      * There are two hacks here:
00412      *  1) tl is 16b (i.e. REGION_TAG_COUNT) short while doing headerReload().
00413      *  2) the 8/98 rpm bug with inserting i18n tags needs to use tl, not dl.
00414      */
00415     if (tl+REGION_TAG_COUNT == dl)
00416         tl += REGION_TAG_COUNT;
00417 
00418     return dl;
00419 }
00420 
00421 #if 0
00422 int headerDrips(const Header h)
00423 {
00424     indexEntry entry; 
00425     int i;
00426 
00427     for (i = 0, entry = h->index; i < h->indexUsed; i++, entry++) {
00428         if (ENTRY_IS_REGION(entry)) {
00429             int rid = entry->info.offset;
00430 
00431             for (; i < h->indexUsed && entry->info.offset <= rid+1; i++, entry++) {
00432                 if (entry->info.offset <= rid)
00433                     continue;
00434             }
00435             i--;
00436             entry--;
00437             continue;
00438         }
00439 
00440         /* Ignore deleted drips. */
00441         if (entry->data == NULL || entry->length <= 0)
00442             continue;
00443     }
00444     return 0;
00445 }
00446 #endif
00447 
00450 static /*@only@*/ /*@null@*/ void * doHeaderUnload(Header h,
00451                 /*@out@*/ int * lengthPtr)
00452         /*@modifies h, *lengthPtr @*/
00453 {
00454     int_32 * ei = NULL;
00455     entryInfo pe;
00456     char * dataStart;
00457     char * te;
00458     unsigned pad;
00459     unsigned len;
00460     int_32 il = 0;
00461     int_32 dl = 0;
00462     indexEntry entry; 
00463     int_32 type;
00464     int i;
00465     int drlen, ndribbles;
00466     int driplen, ndrips;
00467     int legacy = 0;
00468 
00469     /* Sort entries by (offset,tag). */
00470     headerUnsort(h);
00471 
00472     /* Compute (il,dl) for all tags, including those deleted in region. */
00473     pad = 0;
00474     drlen = ndribbles = driplen = ndrips = 0;
00475     for (i = 0, entry = h->index; i < h->indexUsed; i++, entry++) {
00476         if (ENTRY_IS_REGION(entry)) {
00477             int_32 rdl = -entry->info.offset;   /* negative offset */
00478             int_32 ril = rdl/sizeof(*pe);
00479             int rid = entry->info.offset;
00480 
00481             il += ril;
00482             dl += entry->rdlen + entry->info.count;
00483             /* XXX Legacy regions do not include the region tag and data. */
00484             if (i == 0 && (h->flags & HEADERFLAG_LEGACY))
00485                 il += 1;
00486 
00487             /* Skip rest of entries in region, but account for dribbles. */
00488             for (; i < h->indexUsed && entry->info.offset <= rid+1; i++, entry++) {
00489                 if (entry->info.offset <= rid)
00490                     continue;
00491 
00492                 /* Alignment */
00493                 type = entry->info.type;
00494                 if (typeSizes[type] > 1) {
00495                     unsigned diff;
00496                     diff = typeSizes[type] - (dl % typeSizes[type]);
00497                     if (diff != typeSizes[type]) {
00498                         drlen += diff;
00499                         pad += diff;
00500                         dl += diff;
00501                     }
00502                 }
00503 
00504                 ndribbles++;
00505                 il++;
00506                 drlen += entry->length;
00507                 dl += entry->length;
00508             }
00509             i--;
00510             entry--;
00511             continue;
00512         }
00513 
00514         /* Ignore deleted drips. */
00515         if (entry->data == NULL || entry->length <= 0)
00516             continue;
00517 
00518         /* Alignment */
00519         type = entry->info.type;
00520         if (typeSizes[type] > 1) {
00521             unsigned diff;
00522             diff = typeSizes[type] - (dl % typeSizes[type]);
00523             if (diff != typeSizes[type]) {
00524                 driplen += diff;
00525                 pad += diff;
00526                 dl += diff;
00527             } else
00528                 diff = 0;
00529         }
00530 
00531         ndrips++;
00532         il++;
00533         driplen += entry->length;
00534         dl += entry->length;
00535     }
00536 
00537     /* Sanity checks on header intro. */
00538     if (hdrchkTags(il) || hdrchkData(dl))
00539         goto errxit;
00540 
00541     len = sizeof(il) + sizeof(dl) + (il * sizeof(*pe)) + dl;
00542 
00543     ei = xmalloc(len);
00544     ei[0] = htonl(il);
00545     ei[1] = htonl(dl);
00546 
00547     pe = (entryInfo) &ei[2];
00548     dataStart = te = (char *) (pe + il);
00549 
00550     pad = 0;
00551     for (i = 0, entry = h->index; i < h->indexUsed; i++, entry++) {
00552         const char * src;
00553 char *t;
00554         int count;
00555         int rdlen;
00556 
00557         if (entry->data == NULL || entry->length <= 0)
00558             continue;
00559 
00560 t = te;
00561         pe->tag = htonl(entry->info.tag);
00562         pe->type = htonl(entry->info.type);
00563         pe->count = htonl(entry->info.count);
00564 
00565         if (ENTRY_IS_REGION(entry)) {
00566             int_32 rdl = -entry->info.offset;   /* negative offset */
00567             int_32 ril = rdl/sizeof(*pe) + ndribbles;
00568             int rid = entry->info.offset;
00569 
00570             src = (char *)entry->data;
00571             rdlen = entry->rdlen;
00572 
00573             /* XXX Legacy regions do not include the region tag and data. */
00574             if (i == 0 && (h->flags & HEADERFLAG_LEGACY)) {
00575                 int_32 stei[4];
00576 
00577                 legacy = 1;
00578                 memcpy(pe+1, src, rdl);
00579                 memcpy(te, src + rdl, rdlen);
00580                 te += rdlen;
00581 
00582                 pe->offset = htonl(te - dataStart);
00583                 stei[0] = pe->tag;
00584                 stei[1] = pe->type;
00585                 stei[2] = htonl(-rdl-entry->info.count);
00586                 stei[3] = pe->count;
00587                 memcpy(te, stei, entry->info.count);
00588                 te += entry->info.count;
00589                 ril++;
00590                 rdlen += entry->info.count;
00591 
00592                 count = regionSwab(NULL, ril, 0, pe, t, 0);
00593                 if (count != rdlen)
00594                     goto errxit;
00595 
00596             } else {
00597 
00598                 memcpy(pe+1, src + sizeof(*pe), ((ril-1) * sizeof(*pe)));
00599                 memcpy(te, src + (ril * sizeof(*pe)), rdlen+entry->info.count+drlen);
00600                 te += rdlen;
00601                 {   /*@-castexpose@*/
00602                     entryInfo se = (entryInfo)src;
00603                     /*@=castexpose@*/
00604                     int off = ntohl(se->offset);
00605                     pe->offset = (off) ? htonl(te - dataStart) : htonl(off);
00606                 }
00607                 te += entry->info.count + drlen;
00608 
00609                 count = regionSwab(NULL, ril, 0, pe, t, 0);
00610                 if (count != (rdlen + entry->info.count + drlen))
00611                     goto errxit;
00612             }
00613 
00614             /* Skip rest of entries in region. */
00615             while (i < h->indexUsed && entry->info.offset <= rid+1) {
00616                 i++;
00617                 entry++;
00618             }
00619             i--;
00620             entry--;
00621             pe += ril;
00622             continue;
00623         }
00624 
00625         /* Ignore deleted drips. */
00626         if (entry->data == NULL || entry->length <= 0)
00627             continue;
00628 
00629         /* Alignment */
00630         type = entry->info.type;
00631         if (typeSizes[type] > 1) {
00632             unsigned diff;
00633             diff = typeSizes[type] - ((te - dataStart) % typeSizes[type]);
00634             if (diff != typeSizes[type]) {
00635                 memset(te, 0, diff);
00636                 te += diff;
00637                 pad += diff;
00638             }
00639         }
00640 
00641         pe->offset = htonl(te - dataStart);
00642 
00643         /* copy data w/ endian conversions */
00644         switch (entry->info.type) {
00645         case RPM_INT32_TYPE:
00646             count = entry->info.count;
00647             src = entry->data;
00648             while (count--) {
00649                 *((int_32 *)te) = htonl(*((int_32 *)src));
00650                 te += sizeof(int_32);
00651                 src += sizeof(int_32);
00652             }
00653             break;
00654 
00655         case RPM_INT16_TYPE:
00656             count = entry->info.count;
00657             src = entry->data;
00658             while (count--) {
00659                 *((int_16 *)te) = htons(*((int_16 *)src));
00660                 te += sizeof(int_16);
00661                 src += sizeof(int_16);
00662             }
00663             break;
00664 
00665         default:
00666             memcpy(te, entry->data, entry->length);
00667             te += entry->length;
00668             break;
00669         }
00670         pe++;
00671     }
00672    
00673     /* Insure that there are no memcpy underruns/overruns. */
00674     if (((char *)pe) != dataStart)
00675         goto errxit;
00676     if ((((char *)ei)+len) != te)
00677         goto errxit;
00678 
00679     if (lengthPtr)
00680         *lengthPtr = len;
00681 
00682     h->flags &= ~HEADERFLAG_SORTED;
00683     headerSort(h);
00684 
00685     return (void *) ei;
00686 
00687 errxit:
00688     /*@-usereleased@*/
00689     ei = _free(ei);
00690     /*@=usereleased@*/
00691     return (void *) ei;
00692 }
00693 
00694 void * headerUnload(Header h)
00695 {
00696     int length;
00697     void * uh = doHeaderUnload(h, &length);
00698     return uh;
00699 }
00700 
00701 Header headerReload(Header h, int tag)
00702 {
00703     Header nh;
00704     int length;
00705     /*@-onlytrans@*/
00706     void * uh = doHeaderUnload(h, &length);
00707 
00708     h = headerFree(h);
00709     /*@=onlytrans@*/
00710     if (uh == NULL)
00711         return NULL;
00712     nh = headerLoad(uh);
00713     if (nh == NULL) {
00714         uh = _free(uh);
00715         return NULL;
00716     }
00717     if (nh->flags & HEADERFLAG_ALLOCATED)
00718         uh = _free(uh);
00719     nh->flags |= HEADERFLAG_ALLOCATED;
00720     if (ENTRY_IS_REGION(nh->index)) {
00721         if (tag == HEADER_SIGNATURES || tag == HEADER_IMMUTABLE)
00722             nh->index[0].info.tag = tag;
00723     }
00724     return nh;
00725 }
00726 
00727 Header headerCopy(Header h)
00728 {
00729     Header nh = headerNew();
00730     HeaderIterator hi;
00731     int_32 tag, type, count;
00732     hPTR_t ptr;
00733    
00734     for (hi = headerInitIterator(h);
00735         headerNextIterator(hi, &tag, &type, &ptr, &count);
00736         ptr = headerFreeData((void *)ptr, type))
00737     {
00738         if (ptr) (void) headerAddEntry(nh, tag, type, ptr, count);
00739     }
00740     hi = headerFreeIterator(hi);
00741 
00742     return headerReload(nh, HEADER_IMAGE);
00743 }
00744 
00745 Header headerLoad(void * uh)
00746 {
00747     int_32 * ei = (int_32 *) uh;
00748     int_32 il = ntohl(ei[0]);           /* index length */
00749     int_32 dl = ntohl(ei[1]);           /* data length */
00750     size_t pvlen = sizeof(il) + sizeof(dl) +
00751                (il * sizeof(struct entryInfo)) + dl;
00752     void * pv = uh;
00753     Header h = NULL;
00754     entryInfo pe;
00755     char * dataStart;
00756     indexEntry entry; 
00757     int rdlen;
00758     int i;
00759 
00760     /* Sanity checks on header intro. */
00761     if (hdrchkTags(il) || hdrchkData(dl))
00762         goto errxit;
00763 
00764     ei = (int_32 *) pv;
00765     /*@-castexpose@*/
00766     pe = (entryInfo) &ei[2];
00767     /*@=castexpose@*/
00768     dataStart = (char *) (pe + il);
00769 
00770     h = xcalloc(1, sizeof(*h));
00771     /*@-assignexpose@*/
00772     h->hv = *hdrVec;            /* structure assignment */
00773     /*@=assignexpose@*/
00774     /*@-assignexpose -kepttrans@*/
00775     h->blob = uh;
00776     /*@=assignexpose =kepttrans@*/
00777     h->indexAlloced = il + 1;
00778     h->indexUsed = il;
00779     h->index = xcalloc(h->indexAlloced, sizeof(*h->index));
00780     h->flags = HEADERFLAG_SORTED;
00781     h->nrefs = 1;
00782 
00783     /*
00784      * XXX XFree86-libs, ash, and pdksh from Red Hat 5.2 have bogus
00785      * %verifyscript tag that needs to be diddled.
00786      */
00787     if (ntohl(pe->tag) == 15 &&
00788         ntohl(pe->type) == RPM_STRING_TYPE &&
00789         ntohl(pe->count) == 1)
00790     {
00791         pe->tag = htonl(1079);
00792     }
00793 
00794     entry = h->index;
00795     i = 0;
00796     if (!(htonl(pe->tag) < HEADER_I18NTABLE)) {
00797         h->flags |= HEADERFLAG_LEGACY;
00798         entry->info.type = REGION_TAG_TYPE;
00799         entry->info.tag = HEADER_IMAGE;
00800         entry->info.count = REGION_TAG_COUNT;
00801         entry->info.offset = ((char *)pe - dataStart); /* negative offset */
00802 
00803         /*@-assignexpose@*/
00804         entry->data = pe;
00805         /*@=assignexpose@*/
00806         entry->length = pvlen - sizeof(il) - sizeof(dl);
00807         rdlen = regionSwab(entry+1, il, 0, pe, dataStart, entry->info.offset);
00808 #if 0   /* XXX don't check, the 8/98 i18n bug fails here. */
00809         if (rdlen != dl)
00810             goto errxit;
00811 #endif
00812         entry->rdlen = rdlen;
00813         entry++;
00814         h->indexUsed++;
00815     } else {
00816         int nb = ntohl(pe->count);
00817         int_32 rdl;
00818         int_32 ril;
00819 
00820         h->flags &= ~HEADERFLAG_LEGACY;
00821 
00822         entry->info.type = htonl(pe->type);
00823         if (entry->info.type < RPM_MIN_TYPE || entry->info.type > RPM_MAX_TYPE)
00824             goto errxit;
00825         entry->info.count = htonl(pe->count);
00826 
00827         if (hdrchkTags(entry->info.count))
00828             goto errxit;
00829 
00830         {   int off = ntohl(pe->offset);
00831 
00832             if (hdrchkData(off))
00833                 goto errxit;
00834             if (off) {
00835                 int_32 * stei = memcpy(alloca(nb), dataStart + off, nb);
00836                 rdl = -ntohl(stei[2]);  /* negative offset */
00837                 ril = rdl/sizeof(*pe);
00838                 if (hdrchkTags(ril) || hdrchkData(rdl))
00839                     goto errxit;
00840                 entry->info.tag = htonl(pe->tag);
00841             } else {
00842                 ril = il;
00843                 rdl = (ril * sizeof(struct entryInfo));
00844                 entry->info.tag = HEADER_IMAGE;
00845             }
00846         }
00847         entry->info.offset = -rdl;      /* negative offset */
00848 
00849         /*@-assignexpose@*/
00850         entry->data = pe;
00851         /*@=assignexpose@*/
00852         entry->length = pvlen - sizeof(il) - sizeof(dl);
00853         rdlen = regionSwab(entry+1, ril-1, 0, pe+1, dataStart, entry->info.offset);
00854         if (rdlen < 0)
00855             goto errxit;
00856         entry->rdlen = rdlen;
00857 
00858         if (ril < h->indexUsed) {
00859             indexEntry newEntry = entry + ril;
00860             int ne = (h->indexUsed - ril);
00861             int rid = entry->info.offset+1;
00862             int rc;
00863 
00864             /* Load dribble entries from region. */
00865             rc = regionSwab(newEntry, ne, 0, pe+ril, dataStart, rid);
00866             if (rc < 0)
00867                 goto errxit;
00868             rdlen += rc;
00869 
00870           { indexEntry firstEntry = newEntry;
00871             int save = h->indexUsed;
00872             int j;
00873 
00874             /* Dribble entries replace duplicate region entries. */
00875             h->indexUsed -= ne;
00876             for (j = 0; j < ne; j++, newEntry++) {
00877                 (void) headerRemoveEntry(h, newEntry->info.tag);
00878                 if (newEntry->info.tag == HEADER_BASENAMES)
00879                     (void) headerRemoveEntry(h, HEADER_OLDFILENAMES);
00880             }
00881 
00882             /* If any duplicate entries were replaced, move new entries down. */
00883             if (h->indexUsed < (save - ne)) {
00884                 memmove(h->index + h->indexUsed, firstEntry,
00885                         (ne * sizeof(*entry)));
00886             }
00887             h->indexUsed += ne;
00888           }
00889         }
00890     }
00891 
00892     h->flags &= ~HEADERFLAG_SORTED;
00893     headerSort(h);
00894 
00895     /*@-globstate@*/
00896     return h;
00897     /*@=globstate@*/
00898 
00899 errxit:
00900     /*@-usereleased@*/
00901     if (h) {
00902         h->index = _free(h->index);
00903         /*@-refcounttrans@*/
00904         h = _free(h);
00905         /*@=refcounttrans@*/
00906     }
00907     /*@=usereleased@*/
00908     /*@-refcounttrans -globstate@*/
00909     return h;
00910     /*@=refcounttrans =globstate@*/
00911 }
00912 
00913 Header headerCopyLoad(const void * uh)
00914 {
00915     int_32 * ei = (int_32 *) uh;
00916     int_32 il = ntohl(ei[0]);           /* index length */
00917     int_32 dl = ntohl(ei[1]);           /* data length */
00918     size_t pvlen = sizeof(il) + sizeof(dl) +
00919                         (il * sizeof(struct entryInfo)) + dl;
00920     void * nuh = NULL;
00921     Header h = NULL;
00922 
00923     /* Sanity checks on header intro. */
00924     if (!(hdrchkTags(il) || hdrchkData(dl)) && pvlen < headerMaxbytes) {
00925         nuh = memcpy(xmalloc(pvlen), uh, pvlen);
00926         if ((h = headerLoad(nuh)) != NULL)
00927             h->flags |= HEADERFLAG_ALLOCATED;
00928     }
00929     if (h == NULL)
00930         nuh = _free(nuh);
00931     return h;
00932 }
00933 
00934 Header headerRead(FD_t fd, enum hMagic magicp)
00935 {
00936     int_32 block[4];
00937     int_32 reserved;
00938     int_32 * ei = NULL;
00939     int_32 il;
00940     int_32 dl;
00941     int_32 magic;
00942     Header h = NULL;
00943     size_t len;
00944     int i;
00945 
00946     memset(block, 0, sizeof(block));
00947     i = 2;
00948     if (magicp == HEADER_MAGIC_YES)
00949         i += 2;
00950 
00951     if (timedRead(fd, (char *)block, i*sizeof(*block)) != (i * sizeof(*block)))
00952         goto exit;
00953 
00954     i = 0;
00955 
00956     if (magicp == HEADER_MAGIC_YES) {
00957         magic = block[i++];
00958         if (memcmp(&magic, header_magic, sizeof(magic)))
00959             goto exit;
00960         reserved = block[i++];
00961     }
00962     
00963     il = ntohl(block[i++]);
00964     dl = ntohl(block[i++]);
00965 
00966     len = sizeof(il) + sizeof(dl) + (il * sizeof(struct entryInfo)) + dl;
00967 
00968     /* Sanity checks on header intro. */
00969     if (hdrchkTags(il) || hdrchkData(dl) || len > headerMaxbytes)
00970         goto exit;
00971 
00972     ei = xmalloc(len);
00973     ei[0] = htonl(il);
00974     ei[1] = htonl(dl);
00975     len -= sizeof(il) + sizeof(dl);
00976 
00977     if (timedRead(fd, (char *)&ei[2], len) != len)
00978         goto exit;
00979     
00980     h = headerLoad(ei);
00981 
00982 exit:
00983     if (h) {
00984         if (h->flags & HEADERFLAG_ALLOCATED)
00985             ei = _free(ei);
00986         h->flags |= HEADERFLAG_ALLOCATED;
00987     } else if (ei)
00988         ei = _free(ei);
00989     /*@-mustmod@*/      /* FIX: timedRead macro obscures annotation */
00990     return h;
00991     /*@-mustmod@*/
00992 }
00993 
00994 int headerWrite(FD_t fd, Header h, enum hMagic magicp)
00995 {
00996     ssize_t nb;
00997     int length;
00998     const void * uh;
00999 
01000     if (h == NULL)
01001         return 1;
01002     uh = doHeaderUnload(h, &length);
01003     if (uh == NULL)
01004         return 1;
01005     switch (magicp) {
01006     case HEADER_MAGIC_YES:
01007         nb = Fwrite(header_magic, sizeof(char), sizeof(header_magic), fd);
01008         if (nb != sizeof(header_magic))
01009             goto exit;
01010         break;
01011     case HEADER_MAGIC_NO:
01012         break;
01013     }
01014 
01015     nb = Fwrite(uh, sizeof(char), length, fd);
01016 
01017 exit:
01018     uh = _free(uh);
01019     return (nb == length ? 0 : 1);
01020 }
01021 
01029 static /*@null@*/
01030 indexEntry findEntry(/*@null@*/ Header h, int_32 tag, int_32 type)
01031         /*@modifies h @*/
01032 {
01033     indexEntry entry, entry2, last;
01034     struct indexEntry key;
01035 
01036     if (h == NULL) return NULL;
01037     if (!(h->flags & HEADERFLAG_SORTED)) headerSort(h);
01038 
01039     key.info.tag = tag;
01040 
01041     entry2 = entry = 
01042         bsearch(&key, h->index, h->indexUsed, sizeof(*h->index), indexCmp);
01043     if (entry == NULL)
01044         return NULL;
01045 
01046     if (type == RPM_NULL_TYPE)
01047         return entry;
01048 
01049     /* look backwards */
01050     while (entry->info.tag == tag && entry->info.type != type &&
01051            entry > h->index) entry--;
01052 
01053     if (entry->info.tag == tag && entry->info.type == type)
01054         return entry;
01055 
01056     last = h->index + h->indexUsed;
01057     while (entry2->info.tag == tag && entry2->info.type != type &&
01058            entry2 < last) entry2++;
01059 
01060     if (entry->info.tag == tag && entry->info.type == type)
01061         return entry;
01062 
01063     return NULL;
01064 }
01065 
01066 int headerIsEntry(Header h, int_32 tag)
01067 {
01068     /*@-mods@*/         /*@ FIX: h modified by sort. */
01069     return (findEntry(h, tag, RPM_NULL_TYPE) ? 1 : 0);
01070     /*@=mods@*/ 
01071 }
01072 
01083 static int copyEntry(const indexEntry entry,
01084                 /*@null@*/ /*@out@*/ hTYP_t type,
01085                 /*@null@*/ /*@out@*/ hPTR_t * p,
01086                 /*@null@*/ /*@out@*/ hCNT_t c,
01087                 int minMem)
01088         /*@modifies *type, *p, *c @*/
01089 {
01090     int_32 count = entry->info.count;
01091     int rc = 1;         /* XXX 1 on success. */
01092 
01093     if (p)
01094     switch (entry->info.type) {
01095     case RPM_BIN_TYPE:
01096         /* XXX this only works for HEADER_IMMUTABLE */
01097         if (ENTRY_IS_REGION(entry)) {
01098             int_32 * ei = ((int_32 *)entry->data) - 2;
01099             /*@-castexpose@*/
01100             entryInfo pe = (entryInfo) (ei + 2);
01101             /*@=castexpose@*/
01102             char * dataStart = (char *) (pe + ntohl(ei[0]));
01103             int_32 rdl = -entry->info.offset;   /* negative offset */
01104             int_32 ril = rdl/sizeof(*pe);
01105 
01106             count = 2 * sizeof(*ei) + (ril * sizeof(*pe)) +
01107                         entry->rdlen + REGION_TAG_COUNT;
01108             *p = xmalloc(count);
01109             ei = (int_32 *) *p;
01110             ei[0] = htonl(ril);
01111             ei[1] = htonl(entry->rdlen + REGION_TAG_COUNT);
01112             /*@-castexpose@*/
01113             pe = (entryInfo) memcpy(ei + 2, pe, (ril * sizeof(*pe)));
01114             /*@=castexpose@*/
01115             dataStart = (char *) memcpy(pe + ril, dataStart,
01116                                         (entry->rdlen + REGION_TAG_COUNT));
01117 
01118             rc = regionSwab(NULL, ril, 0, pe, dataStart, 0);
01119             /* XXX 1 on success. */
01120             rc = (rc < 0) ? 0 : 1;
01121         } else {
01122             count = entry->length;
01123             *p = (!minMem
01124                 ? memcpy(xmalloc(count), entry->data, count)
01125                 : entry->data);
01126         }
01127         break;
01128     case RPM_STRING_TYPE:
01129         if (count == 1) {
01130             *p = entry->data;
01131             break;
01132         }
01133         /*@fallthrough@*/
01134     case RPM_STRING_ARRAY_TYPE:
01135     case RPM_I18NSTRING_TYPE:
01136     {   const char ** ptrEntry;
01137         int tableSize = count * sizeof(char *);
01138         char * t;
01139         int i;
01140 
01141         /*@-mods@*/
01142         if (minMem) {
01143             *p = xmalloc(tableSize);
01144             ptrEntry = (const char **) *p;
01145             t = entry->data;
01146         } else {
01147             t = xmalloc(tableSize + entry->length);
01148             *p = (void *)t;
01149             ptrEntry = (const char **) *p;
01150             t += tableSize;
01151             memcpy(t, entry->data, entry->length);
01152         }
01153         /*@=mods@*/
01154         for (i = 0; i < count; i++) {
01155             *ptrEntry++ = t;
01156             t = strchr(t, 0);
01157             t++;
01158         }
01159     }   break;
01160 
01161     default:
01162         *p = entry->data;
01163         break;
01164     }
01165     if (type) *type = entry->info.type;
01166     if (c) *c = count;
01167     return rc;
01168 }
01169 
01188 static int headerMatchLocale(const char *td, const char *l, const char *le)
01189         /*@*/
01190 {
01191     const char *fe;
01192 
01193 
01194 #if 0
01195   { const char *s, *ll, *CC, *EE, *dd;
01196     char *lbuf, *t.
01197 
01198     /* Copy the buffer and parse out components on the fly. */
01199     lbuf = alloca(le - l + 1);
01200     for (s = l, ll = t = lbuf; *s; s++, t++) {
01201         switch (*s) {
01202         case '_':
01203             *t = '\0';
01204             CC = t + 1;
01205             break;
01206         case '.':
01207             *t = '\0';
01208             EE = t + 1;
01209             break;
01210         case '@':
01211             *t = '\0';
01212             dd = t + 1;
01213             break;
01214         default:
01215             *t = *s;
01216             break;
01217         }
01218     }
01219 
01220     if (ll)     /* ISO language should be lower case */
01221         for (t = ll; *t; t++)   *t = tolower(*t);
01222     if (CC)     /* ISO country code should be upper case */
01223         for (t = CC; *t; t++)   *t = toupper(*t);
01224 
01225     /* There are a total of 16 cases to attempt to match. */
01226   }
01227 #endif
01228 
01229     /* First try a complete match. */
01230     if (strlen(td) == (le-l) && !strncmp(td, l, (le - l)))
01231         return 1;
01232 
01233     /* Next, try stripping optional dialect and matching.  */
01234     for (fe = l; fe < le && *fe != '@'; fe++)
01235         {};
01236     if (fe < le && !strncmp(td, l, (fe - l)))
01237         return 1;
01238 
01239     /* Next, try stripping optional codeset and matching.  */
01240     for (fe = l; fe < le && *fe != '.'; fe++)
01241         {};
01242     if (fe < le && !strncmp(td, l, (fe - l)))
01243         return 1;
01244 
01245     /* Finally, try stripping optional country code and matching. */
01246     for (fe = l; fe < le && *fe != '_'; fe++)
01247         {};
01248     if (fe < le && !strncmp(td, l, (fe - l)))
01249         return 1;
01250 
01251     return 0;
01252 }
01253 
01260 /*@dependent@*/ static char *
01261 headerFindI18NString(Header h, indexEntry entry)
01262 {
01263     const char *lang, *l, *le;
01264     indexEntry table;
01265 
01266     /* XXX Drepper sez' this is the order. */
01267     if ((lang = getenv("LANGUAGE")) == NULL &&
01268         (lang = getenv("LC_ALL")) == NULL &&
01269         (lang = getenv("LC_MESSAGES")) == NULL &&
01270         (lang = getenv("LANG")) == NULL)
01271             /*@-retalias -retexpose@*/
01272             return entry->data;
01273             /*@=retalias =retexpose@*/
01274     
01275     if ((table = findEntry(h, HEADER_I18NTABLE, RPM_STRING_ARRAY_TYPE)) == NULL)
01276         /*@-retalias -retexpose@*/
01277         return entry->data;
01278         /*@=retalias =retexpose@*/
01279 
01280     for (l = lang; *l != '\0'; l = le) {
01281         const char *td;
01282         char *ed;
01283         int langNum;
01284 
01285         while (*l && *l == ':')                 /* skip leading colons */
01286             l++;
01287         if (*l == '\0')
01288             break;
01289         for (le = l; *le && *le != ':'; le++)   /* find end of this locale */
01290             {};
01291 
01292         /* For each entry in the header ... */
01293         for (langNum = 0, td = table->data, ed = entry->data;
01294              langNum < entry->info.count;
01295              langNum++, td += strlen(td) + 1, ed += strlen(ed) + 1) {
01296 
01297                 if (headerMatchLocale(td, l, le))
01298                     return ed;
01299 
01300         }
01301     }
01302 
01303     /*@-retalias -retexpose@*/
01304     return entry->data;
01305     /*@=retalias =retexpose@*/
01306 }
01307 
01318 static int intGetEntry(Header h, int_32 tag,
01319                 /*@null@*/ /*@out@*/ hTAG_t type,
01320                 /*@null@*/ /*@out@*/ hPTR_t * p,
01321                 /*@null@*/ /*@out@*/ hCNT_t c,
01322                 int minMem)
01323         /*@modifies *type, *p, *c @*/
01324 {
01325     indexEntry entry;
01326     int rc;
01327 
01328     /* First find the tag */
01329     /*@-mods@*/         /*@ FIX: h modified by sort. */
01330     entry = findEntry(h, tag, RPM_NULL_TYPE);
01331     /*@mods@*/
01332     if (entry == NULL) {
01333         if (type) type = 0;
01334         if (p) *p = NULL;
01335         if (c) *c = 0;
01336         return 0;
01337     }
01338 
01339     switch (entry->info.type) {
01340     case RPM_I18NSTRING_TYPE:
01341         rc = 1;
01342         if (type) *type = RPM_STRING_TYPE;
01343         if (c) *c = 1;
01344         /*@-dependenttrans@*/
01345         if (p) *p = headerFindI18NString(h, entry);
01346         /*@=dependenttrans@*/
01347         break;
01348     default:
01349         rc = copyEntry(entry, type, p, c, minMem);
01350         break;
01351     }
01352 
01353     /* XXX 1 on success */
01354     return ((rc == 1) ? 1 : 0);
01355 }
01356 
01364 static /*@null@*/ void * headerFreeTag(/*@unused@*/ Header h,
01365                 /*@only@*/ /*@null@*/ const void * data, rpmTagType type)
01366         /*@modifies data @*/
01367 {
01368     if (data) {
01369         /*@-branchstate@*/
01370         if (type == -1 ||
01371             type == RPM_STRING_ARRAY_TYPE ||
01372             type == RPM_I18NSTRING_TYPE ||
01373             type == RPM_BIN_TYPE)
01374                 data = _free(data);
01375         /*@=branchstate@*/
01376     }
01377     return NULL;
01378 }
01379 
01380 int headerGetEntry(Header h, int_32 tag, hTYP_t type, void **p, hCNT_t c)
01381 {
01382     return intGetEntry(h, tag, type, (hPTR_t *)p, c, 0);
01383 }
01384 
01385 int headerGetEntryMinMemory(Header h, int_32 tag, hTYP_t type, hPTR_t * p, 
01386                             hCNT_t c)
01387 {
01388     return intGetEntry(h, tag, type, p, c, 1);
01389 }
01390 
01391 int headerGetRawEntry(Header h, int_32 tag, int_32 * type, hPTR_t * p,
01392                 int_32 * c)
01393 {
01394     indexEntry entry;
01395     int rc;
01396 
01397     if (p == NULL) return headerIsEntry(h, tag);
01398 
01399     /* First find the tag */
01400     /*@-mods@*/         /*@ FIX: h modified by sort. */
01401     entry = findEntry(h, tag, RPM_NULL_TYPE);
01402     /*@=mods@*/
01403     if (!entry) {
01404         if (p) *p = NULL;
01405         if (c) *c = 0;
01406         return 0;
01407     }
01408 
01409     rc = copyEntry(entry, type, p, c, 0);
01410 
01411     /* XXX 1 on success */
01412     return ((rc == 1) ? 1 : 0);
01413 }
01414 
01417 static void copyData(int_32 type, /*@out@*/ void * dstPtr, const void * srcPtr,
01418                 int_32 c, int dataLength)
01419         /*@modifies *dstPtr @*/
01420 {
01421     const char ** src;
01422     char * dst;
01423     int i;
01424 
01425     switch (type) {
01426     case RPM_STRING_ARRAY_TYPE:
01427     case RPM_I18NSTRING_TYPE:
01428         /* Otherwise, p is char** */
01429         i = c;
01430         src = (const char **) srcPtr;
01431         dst = dstPtr;
01432         while (i--) {
01433             if (*src) {
01434                 int len = strlen(*src) + 1;
01435                 memcpy(dst, *src, len);
01436                 dst += len;
01437             }
01438             src++;
01439         }
01440         break;
01441 
01442     default:
01443         memmove(dstPtr, srcPtr, dataLength);
01444         break;
01445     }
01446 }
01447 
01456 static void * grabData(int_32 type, hPTR_t p, int_32 c,
01457                 /*@out@*/ int * lengthPtr)
01458         /*@modifies *lengthPtr @*/
01459 {
01460     int length = dataLength(type, p, c, 0);
01461     void * data = xmalloc(length);
01462 
01463     copyData(type, data, p, c, length);
01464 
01465     if (lengthPtr)
01466         *lengthPtr = length;
01467     return data;
01468 }
01469 
01470 int headerAddEntry(Header h, int_32 tag, int_32 type, hPTR_t p, int_32 c)
01471 {
01472     indexEntry entry;
01473 
01474     /* Count must always be >= 1 for headerAddEntry. */
01475     if (c <= 0)
01476         return 0;
01477 
01478     /* Allocate more index space if necessary */
01479     if (h->indexUsed == h->indexAlloced) {
01480         h->indexAlloced += INDEX_MALLOC_SIZE;
01481         h->index = xrealloc(h->index, h->indexAlloced * sizeof(*h->index));
01482     }
01483 
01484     /* Fill in the index */
01485     entry = h->index + h->indexUsed;
01486     entry->info.tag = tag;
01487     entry->info.type = type;
01488     entry->info.count = c;
01489     entry->info.offset = 0;
01490     entry->data = grabData(type, p, c, &entry->length);
01491 
01492     if (h->indexUsed > 0 && tag < h->index[h->indexUsed-1].info.tag)
01493         h->flags &= ~HEADERFLAG_SORTED;
01494     h->indexUsed++;
01495 
01496     return 1;
01497 }
01498 
01499 int headerAppendEntry(Header h, int_32 tag, int_32 type,
01500                         hPTR_t p, int_32 c)
01501 {
01502     indexEntry entry;
01503     int length;
01504 
01505     /* First find the tag */
01506     entry = findEntry(h, tag, type);
01507     if (!entry)
01508         return 0;
01509 
01510     if (type == RPM_STRING_TYPE || type == RPM_I18NSTRING_TYPE) {
01511         /* we can't do this */
01512         return 0;
01513     }
01514 
01515     length = dataLength(type, p, c, 0);
01516 
01517     if (ENTRY_IN_REGION(entry)) {
01518         char * t = xmalloc(entry->length + length);
01519         memcpy(t, entry->data, entry->length);
01520         entry->data = t;
01521         entry->info.offset = 0;
01522     } else
01523         entry->data = xrealloc(entry->data, entry->length + length);
01524 
01525     copyData(type, ((char *) entry->data) + entry->length, p, c, length);
01526 
01527     entry->length += length;
01528 
01529     entry->info.count += c;
01530 
01531     return 1;
01532 }
01533 
01534 int headerAddOrAppendEntry(Header h, int_32 tag, int_32 type,
01535                            hPTR_t p, int_32 c)
01536 {
01537     return (findEntry(h, tag, type)
01538         ? headerAppendEntry(h, tag, type, p, c)
01539         : headerAddEntry(h, tag, type, p, c));
01540 }
01541 
01542 int headerAddI18NString(Header h, int_32 tag, const char * string, const char * lang)
01543 {
01544     indexEntry table, entry;
01545     const char ** strArray;
01546     int length;
01547     int ghosts;
01548     int i, langNum;
01549     char * buf;
01550 
01551     table = findEntry(h, HEADER_I18NTABLE, RPM_STRING_ARRAY_TYPE);
01552     entry = findEntry(h, tag, RPM_I18NSTRING_TYPE);
01553 
01554     if (!table && entry)
01555         return 0;               /* this shouldn't ever happen!! */
01556 
01557     if (!table && !entry) {
01558         const char * charArray[2];
01559         int count = 0;
01560         if (!lang || (lang[0] == 'C' && lang[1] == '\0')) {
01561             /*@-observertrans -readonlytrans@*/
01562             charArray[count++] = "C";
01563             /*@=observertrans =readonlytrans@*/
01564         } else {
01565             /*@-observertrans -readonlytrans@*/
01566             charArray[count++] = "C";
01567             /*@=observertrans =readonlytrans@*/
01568             charArray[count++] = lang;
01569         }
01570         if (!headerAddEntry(h, HEADER_I18NTABLE, RPM_STRING_ARRAY_TYPE, 
01571                         &charArray, count))
01572             return 0;
01573         table = findEntry(h, HEADER_I18NTABLE, RPM_STRING_ARRAY_TYPE);
01574     }
01575 
01576     if (!table)
01577         return 0;
01578     if (!lang) lang = "C";
01579 
01580     {   const char * l = table->data;
01581         for (langNum = 0; langNum < table->info.count; langNum++) {
01582             if (!strcmp(l, lang)) break;
01583             l += strlen(l) + 1;
01584         }
01585     }
01586 
01587     if (langNum >= table->info.count) {
01588         length = strlen(lang) + 1;
01589         if (ENTRY_IN_REGION(table)) {
01590             char * t = xmalloc(table->length + length);
01591             memcpy(t, table->data, table->length);
01592             table->data = t;
01593             table->info.offset = 0;
01594         } else
01595             table->data = xrealloc(table->data, table->length + length);
01596         memmove(((char *)table->data) + table->length, lang, length);
01597         table->length += length;
01598         table->info.count++;
01599     }
01600 
01601     if (!entry) {
01602         strArray = alloca(sizeof(*strArray) * (langNum + 1));
01603         for (i = 0; i < langNum; i++)
01604             strArray[i] = "";
01605         strArray[langNum] = string;
01606         return headerAddEntry(h, tag, RPM_I18NSTRING_TYPE, strArray, 
01607                                 langNum + 1);
01608     } else if (langNum >= entry->info.count) {
01609         ghosts = langNum - entry->info.count;
01610         
01611         length = strlen(string) + 1 + ghosts;
01612         if (ENTRY_IN_REGION(entry)) {
01613             char * t = xmalloc(entry->length + length);
01614             memcpy(t, entry->data, entry->length);
01615             entry->data = t;
01616             entry->info.offset = 0;
01617         } else
01618             entry->data = xrealloc(entry->data, entry->length + length);
01619 
01620         memset(((char *)entry->data) + entry->length, '\0', ghosts);
01621         memmove(((char *)entry->data) + entry->length + ghosts, string, strlen(string)+1);
01622 
01623         entry->length += length;
01624         entry->info.count = langNum + 1;
01625     } else {
01626         char *b, *be, *e, *ee, *t;
01627         size_t bn, sn, en;
01628 
01629         /* Set beginning/end pointers to previous data */
01630         b = be = e = ee = entry->data;
01631         for (i = 0; i < table->info.count; i++) {
01632             if (i == langNum)
01633                 be = ee;
01634             ee += strlen(ee) + 1;
01635             if (i == langNum)
01636                 e  = ee;
01637         }
01638 
01639         /* Get storage for new buffer */
01640         bn = (be-b);
01641         sn = strlen(string) + 1;
01642         en = (ee-e);
01643         length = bn + sn + en;
01644         t = buf = xmalloc(length);
01645 
01646         /* Copy values into new storage */
01647         memcpy(t, b, bn);
01648         t += bn;
01649         memcpy(t, string, sn);
01650         t += sn;
01651         memcpy(t, e, en);
01652         t += en;
01653 
01654         /* Replace I18N string array */
01655         entry->length -= strlen(be) + 1;
01656         entry->length += sn;
01657         
01658         if (ENTRY_IN_REGION(entry)) {
01659             entry->info.offset = 0;
01660         } else
01661             entry->data = _free(entry->data);
01662         /*@-dependenttrans@*/
01663         entry->data = buf;
01664         /*@=dependenttrans@*/
01665     }
01666 
01667     return 0;
01668 }
01669 
01670 int headerModifyEntry(Header h, int_32 tag, int_32 type, hPTR_t p, int_32 c)
01671 {
01672     indexEntry entry;
01673     void * oldData;
01674 
01675     /* First find the tag */
01676     entry = findEntry(h, tag, type);
01677     if (!entry)
01678         return 0;
01679 
01680     /* make sure entry points to the first occurence of this tag */
01681     while (entry > h->index && (entry - 1)->info.tag == tag)  
01682         entry--;
01683 
01684     /* free after we've grabbed the new data in case the two are intertwined;
01685        that's a bad idea but at least we won't break */
01686     oldData = entry->data;
01687 
01688     entry->info.count = c;
01689     entry->info.type = type;
01690     entry->data = grabData(type, p, c, &entry->length);
01691 
01692     if (ENTRY_IN_REGION(entry)) {
01693         entry->info.offset = 0;
01694     } else
01695         oldData = _free(oldData);
01696 
01697     return 1;
01698 }
01699 
01700 int headerRemoveEntry(Header h, int_32 tag)
01701 {
01702     indexEntry last = h->index + h->indexUsed;
01703     indexEntry entry, first;
01704     int ne;
01705 
01706     entry = findEntry(h, tag, RPM_NULL_TYPE);
01707     if (!entry) return 1;
01708 
01709     /* Make sure entry points to the first occurence of this tag. */
01710     while (entry > h->index && (entry - 1)->info.tag == tag)  
01711         entry--;
01712 
01713     /* Free data for tags being removed. */
01714     for (first = entry; first < last; first++) {
01715         void * data;
01716         if (first->info.tag != tag)
01717             break;
01718         data = first->data;
01719         first->data = NULL;
01720         first->length = 0;
01721         if (ENTRY_IN_REGION(first))
01722             continue;
01723         data = _free(data);
01724     }
01725 
01726     ne = (first - entry);
01727     if (ne > 0) {
01728         h->indexUsed -= ne;
01729         ne = last - first;
01730         if (ne > 0)
01731             memmove(entry, first, (ne * sizeof(*entry)));
01732     }
01733 
01734     return 0;
01735 }
01736 
01739 static char escapedChar(const char ch)  /*@*/
01740 {
01741     switch (ch) {
01742     case 'a':   return '\a';
01743     case 'b':   return '\b';
01744     case 'f':   return '\f';
01745     case 'n':   return '\n';
01746     case 'r':   return '\r';
01747     case 't':   return '\t';
01748     case 'v':   return '\v';
01749     default:    return ch;
01750     }
01751 }
01752 
01759 static /*@null@*/ sprintfToken
01760 freeFormat( /*@only@*/ /*@null@*/ sprintfToken format, int num)
01761         /*@modifies *format @*/
01762 {
01763     int i;
01764 
01765     if (format == NULL) return NULL;
01766     for (i = 0; i < num; i++) {
01767         switch (format[i].type) {
01768         case PTOK_ARRAY:
01769             format[i].u.array.format =
01770                 freeFormat(format[i].u.array.format,
01771                         format[i].u.array.numTokens);
01772             break;
01773         case PTOK_COND:
01774             format[i].u.cond.ifFormat =
01775                 freeFormat(format[i].u.cond.ifFormat, 
01776                         format[i].u.cond.numIfTokens);
01777             format[i].u.cond.elseFormat =
01778                 freeFormat(format[i].u.cond.elseFormat, 
01779                         format[i].u.cond.numElseTokens);
01780             break;
01781         case PTOK_NONE:
01782         case PTOK_TAG:
01783         case PTOK_STRING:
01784         default:
01785             break;
01786         }
01787     }
01788     format = _free(format);
01789     return NULL;
01790 }
01791 
01794 static void findTag(char * name, const headerTagTableEntry tags, 
01795                     const headerSprintfExtension extensions,
01796                     /*@out@*/ headerTagTableEntry * tagMatch,
01797                     /*@out@*/ headerSprintfExtension * extMatch)
01798         /*@modifies *tagMatch, *extMatch @*/
01799 {
01800     headerTagTableEntry entry;
01801     headerSprintfExtension ext;
01802     const char * tagname;
01803 
01804     *tagMatch = NULL;
01805     *extMatch = NULL;
01806 
01807     if (strncmp("RPMTAG_", name, sizeof("RPMTAG_")-1)) {
01808         char * t = alloca(strlen(name) + sizeof("RPMTAG_"));
01809         (void) stpcpy( stpcpy(t, "RPMTAG_"), name);
01810         tagname = t;
01811     } else {
01812         tagname = name;
01813     }
01814 
01815     /* Search extensions first to permit overriding header tags. */
01816     ext = extensions;
01817     while (ext->type != HEADER_EXT_LAST) {
01818         if (ext->name != NULL && ext->type == HEADER_EXT_TAG
01819         && !xstrcasecmp(ext->name, tagname))
01820             break;
01821 
01822         if (ext->type == HEADER_EXT_MORE)
01823             ext = ext->u.more;
01824         else
01825             ext++;
01826     }
01827 
01828     if (ext->type == HEADER_EXT_TAG) {
01829         *extMatch = ext;
01830         return;
01831     }
01832 
01833     /* Search header tags. */
01834     for (entry = tags; entry->name; entry++)
01835         if (entry->name && !xstrcasecmp(entry->name, tagname))
01836             break;
01837 
01838     if (entry->name) {
01839         *tagMatch = entry;
01840         return;
01841     }
01842 }
01843 
01844 /* forward ref */
01845 static int parseExpression(sprintfToken token, char * str, 
01846                 const headerTagTableEntry tags, 
01847                 const headerSprintfExtension extensions,
01848                 /*@out@*/char ** endPtr, /*@null@*/ /*@out@*/ errmsg_t * errmsg)
01849         /*@modifies str, *str, *token, *endPtr, *errmsg @*/;
01850 
01853 static int parseFormat(char * str, const headerTagTableEntry tags,
01854                 const headerSprintfExtension extensions,
01855                 /*@out@*/sprintfToken * formatPtr, /*@out@*/int * numTokensPtr,
01856                 /*@null@*/ /*@out@*/ char ** endPtr, int state,
01857                 /*@null@*/ /*@out@*/ errmsg_t * errmsg)
01858         /*@modifies str, *str, *formatPtr, *numTokensPtr, *endPtr, *errmsg @*/
01859 {
01860     char * chptr, * start, * next, * dst;
01861     sprintfToken format;
01862     int numTokens;
01863     int currToken;
01864     headerTagTableEntry tag;
01865     headerSprintfExtension ext;
01866     int i;
01867     int done = 0;
01868 
01869     /* upper limit on number of individual formats */
01870     numTokens = 0;
01871     for (chptr = str; *chptr != '\0'; chptr++)
01872         if (*chptr == '%') numTokens++;
01873     numTokens = numTokens * 2 + 1;
01874 
01875     format = xcalloc(numTokens, sizeof(*format));
01876     if (endPtr) *endPtr = NULL;
01877 
01878     /*@-infloops@*/
01879     dst = start = str;
01880     currToken = -1;
01881     while (*start != '\0') {
01882         switch (*start) {
01883         case '%':
01884             /* handle %% */
01885             if (*(start + 1) == '%') {
01886                 if (currToken < 0 || format[currToken].type != PTOK_STRING) {
01887                     currToken++;
01888                     format[currToken].type = PTOK_STRING;
01889                     /*@-temptrans -assignexpose@*/
01890                     dst = format[currToken].u.string.string = start;
01891                     /*@=temptrans =assignexpose@*/
01892                 }
01893 
01894                 start++;
01895 
01896                 *dst++ = *start++;
01897 
01898                 break; /* out of switch */
01899             } 
01900 
01901             currToken++;
01902             *dst++ = '\0';
01903             start++;
01904 
01905             if (*start == '|') {
01906                 char * newEnd;
01907 
01908                 start++;
01909                 if (parseExpression(format + currToken, start, tags, 
01910                                     extensions, &newEnd, errmsg))
01911                 {
01912                     format = freeFormat(format, numTokens);
01913                     return 1;
01914                 }
01915                 start = newEnd;
01916                 break; /* out of switch */
01917             }
01918 
01919             /*@-assignexpose@*/
01920             format[currToken].u.tag.format = start;
01921             /*@=assignexpose@*/
01922             format[currToken].u.tag.pad = 0;
01923             format[currToken].u.tag.justOne = 0;
01924             format[currToken].u.tag.arrayCount = 0;
01925 
01926             chptr = start;
01927             while (*chptr && *chptr != '{' && *chptr != '%') chptr++;
01928             if (!*chptr || *chptr == '%') {
01929                 /*@-observertrans -readonlytrans@*/
01930                 if (errmsg) *errmsg = _("missing { after %");
01931                 /*@=observertrans =readonlytrans@*/
01932                 format = freeFormat(format, numTokens);
01933                 return 1;
01934             }
01935 
01936             *chptr++ = '\0';
01937 
01938             while (start < chptr) {
01939                 if (xisdigit(*start)) {
01940                     i = strtoul(start, &start, 10);
01941                     format[currToken].u.tag.pad += i;
01942                 } else {
01943                     start++;
01944                 }
01945             }
01946 
01947             if (*start == '=') {
01948                 format[currToken].u.tag.justOne = 1;
01949                 start++;
01950             } else if (*start == '#') {
01951                 format[currToken].u.tag.justOne = 1;
01952                 format[currToken].u.tag.arrayCount = 1;
01953                 start++;
01954             }
01955 
01956             next = start;
01957             while (*next && *next != '}') next++;
01958             if (!*next) {
01959                 /*@-observertrans -readonlytrans@*/
01960                 if (errmsg) *errmsg = _("missing } after %{");
01961                 /*@=observertrans =readonlytrans@*/
01962                 format = freeFormat(format, numTokens);
01963                 return 1;
01964             }
01965             *next++ = '\0';
01966 
01967             chptr = start;
01968             while (*chptr && *chptr != ':') chptr++;
01969 
01970             if (*chptr != '\0') {
01971                 *chptr++ = '\0';
01972                 if (!*chptr) {
01973                     /*@-observertrans -readonlytrans@*/
01974                     if (errmsg) *errmsg = _("empty tag format");
01975                     /*@=observertrans =readonlytrans@*/
01976                     format = freeFormat(format, numTokens);
01977                     return 1;
01978                 }
01979                 /*@-assignexpose@*/
01980                 format[currToken].u.tag.type = chptr;
01981                 /*@=assignexpose@*/
01982             } else {
01983                 format[currToken].u.tag.type = NULL;
01984             }
01985             
01986             if (!*start) {
01987                 /*@-observertrans -readonlytrans@*/
01988                 if (errmsg) *errmsg = _("empty tag name");
01989                 /*@=observertrans =readonlytrans@*/
01990                 format = freeFormat(format, numTokens);
01991                 return 1;
01992             }
01993 
01994             i = 0;
01995             findTag(start, tags, extensions, &tag, &ext);
01996 
01997             if (tag) {
01998                 format[currToken].u.tag.ext = NULL;
01999                 format[currToken].u.tag.tag = tag->val;
02000             } else if (ext) {
02001                 format[currToken].u.tag.ext = ext->u.tagFunction;
02002                 format[currToken].u.tag.extNum = ext - extensions;
02003             } else {
02004                 /*@-observertrans -readonlytrans@*/
02005                 if (errmsg) *errmsg = _("unknown tag");
02006                 /*@=observertrans =readonlytrans@*/
02007                 format = freeFormat(format, numTokens);
02008                 return 1;
02009             }
02010 
02011             format[currToken].type = PTOK_TAG;
02012 
02013             start = next;
02014 
02015             break;
02016 
02017         case '[':
02018             *dst++ = '\0';
02019             *start++ = '\0';
02020             currToken++;
02021 
02022             if (parseFormat(start, tags, extensions, 
02023                             &format[currToken].u.array.format,
02024                             &format[currToken].u.array.numTokens,
02025                             &start, PARSER_IN_ARRAY, errmsg)) {
02026                 format = freeFormat(format, numTokens);
02027                 return 1;
02028             }
02029 
02030             if (!start) {
02031                 /*@-observertrans -readonlytrans@*/
02032                 if (errmsg) *errmsg = _("] expected at end of array");
02033                 /*@=observertrans =readonlytrans@*/
02034                 format = freeFormat(format, numTokens);
02035                 return 1;
02036             }
02037 
02038             dst = start;
02039 
02040             format[currToken].type = PTOK_ARRAY;
02041 
02042             break;
02043 
02044         case ']':
02045         case '}':
02046             if ((*start == ']' && state != PARSER_IN_ARRAY) ||
02047                 (*start == '}' && state != PARSER_IN_EXPR)) {
02048                 if (*start == ']') {
02049                     /*@-observertrans -readonlytrans@*/
02050                     if (errmsg) *errmsg = _("unexpected ]");
02051                     /*@=observertrans =readonlytrans@*/
02052                 } else {
02053                     /*@-observertrans -readonlytrans@*/
02054                     if (errmsg) *errmsg = _("unexpected }");
02055                     /*@=observertrans =readonlytrans@*/
02056                 }
02057                 format = freeFormat(format, numTokens);
02058                 return 1;
02059             }
02060             *start++ = '\0';
02061             if (endPtr) *endPtr = start;
02062             done = 1;
02063             break;
02064 
02065         default:
02066             if (currToken < 0 || format[currToken].type != PTOK_STRING) {
02067                 currToken++;
02068                 format[currToken].type = PTOK_STRING;
02069                 /*@-temptrans -assignexpose@*/
02070                 dst = format[currToken].u.string.string = start;
02071                 /*@=temptrans =assignexpose@*/
02072             }
02073 
02074             if (*start == '\\') {
02075                 start++;
02076                 *dst++ = escapedChar(*start++);
02077             } else {
02078                 *dst++ = *start++;
02079             }
02080             break;
02081         }
02082         if (done)
02083             break;
02084     }
02085     /*@=infloops@*/
02086 
02087     *dst = '\0';
02088 
02089     currToken++;
02090     for (i = 0; i < currToken; i++) {
02091         if (format[i].type == PTOK_STRING)
02092             format[i].u.string.len = strlen(format[i].u.string.string);
02093     }
02094 
02095     *numTokensPtr = currToken;
02096     *formatPtr = format;
02097 
02098     return 0;
02099 }
02100 
02103 static int parseExpression(sprintfToken token, char * str, 
02104                 const headerTagTableEntry tags, 
02105                 const headerSprintfExtension extensions,
02106                 /*@out@*/ char ** endPtr,
02107                 /*@null@*/ /*@out@*/ errmsg_t * errmsg)
02108 {
02109     headerTagTableEntry tag;
02110     headerSprintfExtension ext;
02111     char * chptr;
02112     char * end;
02113 
02114     if (errmsg) *errmsg = NULL;
02115     chptr = str;
02116     while (*chptr && *chptr != '?') chptr++;
02117 
02118     if (*chptr != '?') {
02119         /*@-observertrans -readonlytrans@*/
02120         if (errmsg) *errmsg = _("? expected in expression");
02121         /*@=observertrans =readonlytrans@*/
02122         return 1;
02123     }
02124 
02125     *chptr++ = '\0';;
02126 
02127     if (*chptr != '{') {
02128         /*@-observertrans -readonlytrans@*/
02129         if (errmsg) *errmsg = _("{ expected after ? in expression");
02130         /*@=observertrans =readonlytrans@*/
02131         return 1;
02132     }
02133 
02134     chptr++;
02135 
02136     if (parseFormat(chptr, tags, extensions, &token->u.cond.ifFormat, 
02137                     &token->u.cond.numIfTokens, &end, PARSER_IN_EXPR, errmsg)) 
02138         return 1;
02139 
02140     if (!*end) {
02141         /*@-observertrans -readonlytrans@*/
02142         if (errmsg) *errmsg = _("} expected in expression");
02143         /*@=observertrans =readonlytrans@*/
02144         token->u.cond.ifFormat =
02145                 freeFormat(token->u.cond.ifFormat, token->u.cond.numIfTokens);
02146         return 1;
02147     }
02148 
02149     chptr = end;
02150     if (*chptr != ':' && *chptr != '|') {
02151         /*@-observertrans -readonlytrans@*/
02152         if (errmsg) *errmsg = _(": expected following ? subexpression");
02153         /*@=observertrans =readonlytrans@*/
02154         token->u.cond.ifFormat =
02155                 freeFormat(token->u.cond.ifFormat, token->u.cond.numIfTokens);
02156         return 1;
02157     }
02158 
02159     if (*chptr == '|') {
02160         (void) parseFormat(xstrdup(""), tags, extensions,
02161                         &token->u.cond.elseFormat, 
02162                         &token->u.cond.numElseTokens, &end, PARSER_IN_EXPR, 
02163                         errmsg);
02164     } else {
02165         chptr++;
02166 
02167         if (*chptr != '{') {
02168             /*@-observertrans -readonlytrans@*/
02169             if (errmsg) *errmsg = _("{ expected after : in expression");
02170             /*@=observertrans =readonlytrans@*/
02171             token->u.cond.ifFormat =
02172                 freeFormat(token->u.cond.ifFormat, token->u.cond.numIfTokens);
02173             return 1;
02174         }
02175 
02176         chptr++;
02177 
02178         if (parseFormat(chptr, tags, extensions, &token->u.cond.elseFormat, 
02179                         &token->u.cond.numElseTokens, &end, PARSER_IN_EXPR, 
02180                         errmsg)) 
02181             return 1;
02182         if (!*end) {
02183             /*@-observertrans -readonlytrans@*/
02184             if (errmsg) *errmsg = _("} expected in expression");
02185             /*@=observertrans =readonlytrans@*/
02186             token->u.cond.ifFormat =
02187                 freeFormat(token->u.cond.ifFormat, token->u.cond.numIfTokens);
02188             return 1;
02189         }
02190 
02191         chptr = end;
02192         if (*chptr != '|') {
02193             /*@-observertrans -readonlytrans@*/
02194             if (errmsg) *errmsg = _("| expected at end of expression");
02195             /*@=observertrans =readonlytrans@*/
02196             token->u.cond.ifFormat =
02197                 freeFormat(token->u.cond.ifFormat, token->u.cond.numIfTokens);
02198             token->u.cond.elseFormat =
02199                 freeFormat(token->u.cond.elseFormat, token->u.cond.numElseTokens);
02200             return 1;
02201         }
02202     }
02203         
02204     chptr++;
02205 
02206     *endPtr = chptr;
02207 
02208     findTag(str, tags, extensions, &tag, &ext);
02209 
02210     if (tag) {
02211         token->u.cond.tag.ext = NULL;
02212         token->u.cond.tag.tag = tag->val;
02213     } else if (ext) {
02214         token->u.cond.tag.ext = ext->u.tagFunction;
02215         token->u.cond.tag.extNum = ext - extensions;
02216     } else {
02217         token->u.cond.tag.ext = NULL;
02218         token->u.cond.tag.tag = -1;
02219     }
02220         
02221     token->type = PTOK_COND;
02222 
02223     return 0;
02224 }
02225 
02229 static int getExtension(Header h, headerTagTagFunction fn,
02230                 /*@out@*/ hTYP_t typeptr,
02231                 /*@out@*/ hPTR_t * data,
02232                 /*@out@*/ hCNT_t countptr,
02233                 extensionCache ext)
02234         /*@modifies *typeptr, *data, *countptr, ext @*/
02235 {
02236     if (!ext->avail) {
02237         if (fn(h, &ext->type, &ext->data, &ext->count, &ext->freeit))
02238             return 1;
02239         ext->avail = 1;
02240     }
02241 
02242     if (typeptr) *typeptr = ext->type;
02243     if (data) *data = ext->data;
02244     if (countptr) *countptr = ext->count;
02245 
02246     return 0;
02247 }
02248 
02251 static char * formatValue(sprintfTag tag, Header h, 
02252                 const headerSprintfExtension extensions,
02253                 extensionCache extCache, int element)
02254         /*@modifies extCache @*/
02255 {
02256     int len;
02257     char buf[20];
02258     int_32 count, type;
02259     hPTR_t data;
02260     unsigned int intVal;
02261     char * val = NULL;
02262     const char ** strarray;
02263     int mayfree = 0;
02264     int countBuf;
02265     headerTagFormatFunction tagtype = NULL;
02266     headerSprintfExtension ext;
02267 
02268     if (tag->ext) {
02269         if (getExtension(h, tag->ext, &type, &data, &count, 
02270                          extCache + tag->extNum))
02271         {
02272             count = 1;
02273             type = RPM_STRING_TYPE;     
02274             data = "(none)";            /* XXX i18n? NO!, sez; gafton */
02275         }
02276     } else {
02277         if (!headerGetEntry(h, tag->tag, &type, (void **)&data, &count)) {
02278             count = 1;
02279             type = RPM_STRING_TYPE;     
02280             data = "(none)";            /* XXX i18n? NO!, sez; gafton */
02281         }
02282 
02283         mayfree = 1;
02284     }
02285 
02286     if (tag->arrayCount) {
02287         /*@-observertrans -modobserver@*/
02288         data = headerFreeData(data, type);
02289         /*@=observertrans =modobserver@*/
02290 
02291         countBuf = count;
02292         data = &countBuf;
02293         count = 1;
02294         type = RPM_INT32_TYPE;
02295     }
02296 
02297     (void) stpcpy( stpcpy(buf, "%"), tag->format);
02298 
02299     if (tag->type) {
02300         ext = extensions;
02301         while (ext->type != HEADER_EXT_LAST) {
02302             if (ext->name != NULL && ext->type == HEADER_EXT_FORMAT
02303             && !strcmp(ext->name, tag->type))
02304             {
02305                 tagtype = ext->u.formatFunction;
02306                 break;
02307             }
02308 
02309             if (ext->type == HEADER_EXT_MORE)
02310                 ext = ext->u.more;
02311             else
02312                 ext++;
02313         }
02314     }
02315     
02316     switch (type) {
02317     case RPM_STRING_ARRAY_TYPE:
02318         strarray = (const char **)data;
02319 
02320         if (tagtype)
02321             val = tagtype(RPM_STRING_TYPE, strarray[element], buf, tag->pad, 0);
02322 
02323         if (!val) {
02324             strcat(buf, "s");
02325 
02326             len = strlen(strarray[element]) + tag->pad + 20;
02327             val = xmalloc(len);
02328             sprintf(val, buf, strarray[element]);
02329         }
02330 
02331         /*@-observertrans -modobserver@*/
02332         if (mayfree) data = _free(data);
02333         /*@=observertrans =modobserver@*/
02334 
02335         break;
02336 
02337     case RPM_STRING_TYPE:
02338         if (tagtype)
02339             val = tagtype(RPM_STRING_ARRAY_TYPE, data, buf, tag->pad,  0);
02340 
02341         if (!val) {
02342             strcat(buf, "s");
02343 
02344             len = strlen(data) + tag->pad + 20;
02345             val = xmalloc(len);
02346             sprintf(val, buf, data);
02347         }
02348         break;
02349 
02350     case RPM_CHAR_TYPE:
02351     case RPM_INT8_TYPE:
02352     case RPM_INT16_TYPE:
02353     case RPM_INT32_TYPE:
02354         switch (type) {
02355         case RPM_CHAR_TYPE:     
02356         case RPM_INT8_TYPE:     intVal = *(((int_8 *) data) + element); break;
02357         case RPM_INT16_TYPE:    intVal = *(((uint_16 *) data) + element); break;
02358         default:                /* keep -Wall quiet */
02359         case RPM_INT32_TYPE:    intVal = *(((int_32 *) data) + element); break;
02360         }
02361 
02362         if (tagtype)
02363             val = tagtype(RPM_INT32_TYPE, &intVal, buf, tag->pad,  element);
02364 
02365         if (!val) {
02366             strcat(buf, "d");
02367             len = 10 + tag->pad + 20;
02368             val = xmalloc(len);
02369             sprintf(val, buf, intVal);
02370         }
02371         break;
02372 
02373     default:
02374         val = xstrdup(_("(unknown type)"));
02375         break;
02376     }
02377 
02378     return val;
02379 }
02380 
02383 static const char * singleSprintf(Header h, sprintfToken token,
02384                 const headerSprintfExtension extensions,
02385                 extensionCache extCache, int element)
02386         /*@modifies h, extCache @*/
02387 {
02388     char * val;
02389     const char * thisItem;
02390     int thisItemLen;
02391     int len, alloced;
02392     int i, j;
02393     int numElements;
02394     int type;
02395     sprintfToken condFormat;
02396     int condNumFormats;
02397 
02398     /* we assume the token and header have been validated already! */
02399 
02400     switch (token->type) {
02401     case PTOK_NONE:
02402         break;
02403 
02404     case PTOK_STRING:
02405         val = xmalloc(token->u.string.len + 1);
02406         strcpy(val, token->u.string.string);
02407         break;
02408 
02409     case PTOK_TAG:
02410         val = formatValue(&token->u.tag, h, extensions, extCache,
02411                           token->u.tag.justOne ? 0 : element);
02412         break;
02413 
02414     case PTOK_COND:
02415         if (token->u.cond.tag.ext ||
02416             headerIsEntry(h, token->u.cond.tag.tag)) {
02417             condFormat = token->u.cond.ifFormat;
02418             condNumFormats = token->u.cond.numIfTokens;
02419         } else {
02420             condFormat = token->u.cond.elseFormat;
02421             condNumFormats = token->u.cond.numElseTokens;
02422         }
02423 
02424         alloced = condNumFormats * 20;
02425         val = xmalloc(alloced ? alloced : 1);
02426         *val = '\0';
02427         len = 0;
02428 
02429         if (condFormat)
02430         for (i = 0; i < condNumFormats; i++) {
02431             thisItem = singleSprintf(h, condFormat + i, 
02432                                      extensions, extCache, element);
02433             thisItemLen = strlen(thisItem);
02434             if ((thisItemLen + len) >= alloced) {
02435                 alloced = (thisItemLen + len) + 200;
02436                 val = xrealloc(val, alloced);   
02437             }
02438             strcat(val, thisItem);
02439             len += thisItemLen;
02440             thisItem = _free(thisItem);
02441         }
02442 
02443         break;
02444 
02445     case PTOK_ARRAY:
02446         numElements = -1;
02447         for (i = 0; i < token->u.array.numTokens; i++) {
02448             if (token->u.array.format[i].type != PTOK_TAG ||
02449                 token->u.array.format[i].u.tag.arrayCount ||
02450                 token->u.array.format[i].u.tag.justOne) continue;
02451 
02452             if (token->u.array.format[i].u.tag.ext) {
02453                 const void * data;
02454                 if (getExtension(h, token->u.array.format[i].u.tag.ext,
02455                                  &type, &data, &numElements, 
02456                                  extCache + 
02457                                    token->u.array.format[i].u.tag.extNum))
02458                      continue;
02459             } else {
02460                 if (!headerGetEntry(h, token->u.array.format[i].u.tag.tag, 
02461                                     &type, (void **) &val, &numElements))
02462                     continue;
02463                 val = headerFreeData(val, type);
02464             } 
02465             /*@loopbreak@*/ break;
02466         }
02467 
02468         if (numElements == -1) {
02469             val = xstrdup("(none)");    /* XXX i18n? NO!, sez; gafton */
02470         } else {
02471             alloced = numElements * token->u.array.numTokens * 20;
02472             val = xmalloc(alloced);
02473             *val = '\0';
02474             len = 0;
02475 
02476             for (j = 0; j < numElements; j++) {
02477                 for (i = 0; i < token->u.array.numTokens; i++) {
02478                     thisItem = singleSprintf(h, token->u.array.format + i, 
02479                                              extensions, extCache, j);
02480                     thisItemLen = strlen(thisItem);
02481                     if ((thisItemLen + len) >= alloced) {
02482                         alloced = (thisItemLen + len) + 200;
02483                         val = xrealloc(val, alloced);   
02484                     }
02485                     strcat(val, thisItem);
02486                     len += thisItemLen;
02487                     thisItem = _free(thisItem);
02488                 }
02489             }
02490         }
02491            
02492         break;
02493     }
02494 
02495     return val;
02496 }
02497 
02500 static /*@only@*/ extensionCache
02501 allocateExtensionCache(const headerSprintfExtension extensions)
02502         /*@*/
02503 {
02504     headerSprintfExtension ext = extensions;
02505     int i = 0;
02506 
02507     while (ext->type != HEADER_EXT_LAST) {
02508         i++;
02509         if (ext->type == HEADER_EXT_MORE)
02510             ext = ext->u.more;
02511         else
02512             ext++;
02513     }
02514 
02515     return xcalloc(i, sizeof(struct extensionCache));
02516 }
02517 
02521 static /*@null@*/ extensionCache
02522 freeExtensionCache(const headerSprintfExtension extensions,
02523                         /*@only@*/ extensionCache cache)
02524         /*@*/
02525 {
02526     headerSprintfExtension ext = extensions;
02527     int i = 0;
02528 
02529     while (ext->type != HEADER_EXT_LAST) {
02530         if (cache[i].freeit) cache[i].data = _free(cache[i].data);
02531 
02532         i++;
02533         if (ext->type == HEADER_EXT_MORE)
02534             ext = ext->u.more;
02535         else
02536             ext++;
02537     }
02538 
02539     cache = _free(cache);
02540     return NULL;
02541 }
02542 
02543 char * headerSprintf(Header h, const char * fmt, 
02544                 const struct headerTagTableEntry_s * tabletags,
02545                 const struct headerSprintfExtension_s * extensions,
02546                 errmsg_t * errmsg)
02547 {
02548     /*@-castexpose@*/   /* FIX: legacy API shouldn't change. */
02549     headerSprintfExtension exts = (headerSprintfExtension) extensions;
02550     headerTagTableEntry tags = (headerTagTableEntry) tabletags;
02551     /*@=castexpose@*/
02552     char * fmtString;
02553     sprintfToken format;
02554     int numTokens;
02555     char * answer;
02556     int answerLength;
02557     int answerAlloced;
02558     int i;
02559     extensionCache extCache;
02560  
02561     /*fmtString = escapeString(fmt);*/
02562     fmtString = xstrdup(fmt);
02563    
02564     if (parseFormat(fmtString, tags, exts, &format, &numTokens, 
02565                     NULL, PARSER_BEGIN, errmsg)) {
02566         fmtString = _free(fmtString);
02567         return NULL;
02568     }
02569 
02570     extCache = allocateExtensionCache(exts);
02571 
02572     answerAlloced = 1024;
02573     answerLength = 0;
02574     answer = xmalloc(answerAlloced);
02575     *answer = '\0';
02576 
02577     for (i = 0; i < numTokens; i++) {
02578         const char * piece;
02579         int pieceLength;
02580 
02581         /*@-mods@*/
02582         piece = singleSprintf(h, format + i, exts, extCache, 0);
02583         /*@=mods@*/
02584         if (piece) {
02585             pieceLength = strlen(piece);
02586             if ((answerLength + pieceLength) >= answerAlloced) {
02587                 while ((answerLength + pieceLength) >= answerAlloced) 
02588                     answerAlloced += 1024;
02589                 answer = xrealloc(answer, answerAlloced);
02590             }
02591 
02592             strcat(answer, piece);
02593             answerLength += pieceLength;
02594             piece = _free(piece);
02595         }
02596     }
02597 
02598     fmtString = _free(fmtString);
02599     extCache = freeExtensionCache(exts, extCache);
02600     format = _free(format);
02601 
02602     return answer;
02603 }
02604 
02607 static char * octalFormat(int_32 type, hPTR_t data, 
02608                 char * formatPrefix, int padding, /*@unused@*/int element)
02609         /*@modifies formatPrefix @*/
02610 {
02611     char * val;
02612 
02613     if (type != RPM_INT32_TYPE) {
02614         val = xstrdup(_("(not a number)"));
02615     } else {
02616         val = xmalloc(20 + padding);
02617         strcat(formatPrefix, "o");
02618         sprintf(val, formatPrefix, *((int_32 *) data));
02619     }
02620 
02621     return val;
02622 }
02623 
02626 static char * hexFormat(int_32 type, hPTR_t data, 
02627                 char * formatPrefix, int padding, /*@unused@*/int element)
02628         /*@modifies formatPrefix @*/
02629 {
02630     char * val;
02631 
02632     if (type != RPM_INT32_TYPE) {
02633         val = xstrdup(_("(not a number)"));
02634     } else {
02635         val = xmalloc(20 + padding);
02636         strcat(formatPrefix, "x");
02637         sprintf(val, formatPrefix, *((int_32 *) data));
02638     }
02639 
02640     return val;
02641 }
02642 
02645 static char * realDateFormat(int_32 type, hPTR_t data, 
02646                 char * formatPrefix, int padding, /*@unused@*/int element,
02647                 const char * strftimeFormat)
02648         /*@modifies formatPrefix @*/
02649 {
02650     char * val;
02651 
02652     if (type != RPM_INT32_TYPE) {
02653         val = xstrdup(_("(not a number)"));
02654     } else {
02655         struct tm * tstruct;
02656         char buf[50];
02657 
02658         val = xmalloc(50 + padding);
02659         strcat(formatPrefix, "s");
02660 
02661         /* this is important if sizeof(int_32) ! sizeof(time_t) */
02662         {   time_t dateint = *((int_32 *) data);
02663             tstruct = localtime(&dateint);
02664         }
02665         buf[0] = '\0';
02666         if (tstruct)
02667             (void) strftime(buf, sizeof(buf) - 1, strftimeFormat, tstruct);
02668         sprintf(val, formatPrefix, buf);
02669     }
02670 
02671     return val;
02672 }
02673 
02676 static char * dateFormat(int_32 type, hPTR_t data, 
02677                          char * formatPrefix, int padding, int element)
02678         /*@modifies formatPrefix @*/
02679 {
02680     return realDateFormat(type, data, formatPrefix, padding, element, "%c");
02681 }
02682 
02685 static char * dayFormat(int_32 type, hPTR_t data, 
02686                          char * formatPrefix, int padding, int element)
02687         /*@modifies formatPrefix @*/
02688 {
02689     return realDateFormat(type, data, formatPrefix, padding, element, 
02690                           "%a %b %d %Y");
02691 }
02692 
02695 static char * shescapeFormat(int_32 type, hPTR_t data, 
02696                 char * formatPrefix, int padding, /*@unused@*/int element)
02697         /*@modifies formatPrefix @*/
02698 {
02699     char * result, * dst, * src, * buf;
02700 
02701     if (type == RPM_INT32_TYPE) {
02702         result = xmalloc(padding + 20);
02703         strcat(formatPrefix, "d");
02704         sprintf(result, formatPrefix, *((int_32 *) data));
02705     } else {
02706         buf = alloca(strlen(data) + padding + 2);
02707         strcat(formatPrefix, "s");
02708         sprintf(buf, formatPrefix, data);
02709 
02710         result = dst = xmalloc(strlen(buf) * 4 + 3);
02711         *dst++ = '\'';
02712         for (src = buf; *src != '\0'; src++) {
02713             if (*src == '\'') {
02714                 *dst++ = '\'';
02715                 *dst++ = '\\';
02716                 *dst++ = '\'';
02717                 *dst++ = '\'';
02718             } else {
02719                 *dst++ = *src;
02720             }
02721         }
02722         *dst++ = '\'';
02723         *dst = '\0';
02724 
02725     }
02726 
02727     return result;
02728 }
02729 
02730 const struct headerSprintfExtension_s headerDefaultFormats[] = {
02731     { HEADER_EXT_FORMAT, "octal", { octalFormat } },
02732     { HEADER_EXT_FORMAT, "hex", { hexFormat } },
02733     { HEADER_EXT_FORMAT, "date", { dateFormat } },
02734     { HEADER_EXT_FORMAT, "day", { dayFormat } },
02735     { HEADER_EXT_FORMAT, "shescape", { shescapeFormat } },
02736     { HEADER_EXT_LAST, NULL, { NULL } }
02737 };
02738 
02739 void headerCopyTags(Header headerFrom, Header headerTo, hTAG_t tagstocopy)
02740 {
02741     int * p;
02742 
02743     if (headerFrom == headerTo)
02744         return;
02745 
02746     for (p = tagstocopy; *p != 0; p++) {
02747         char *s;
02748         int_32 type;
02749         int_32 count;
02750         if (headerIsEntry(headerTo, *p))
02751             continue;
02752         if (!headerGetEntryMinMemory(headerFrom, *p, &type,
02753                                 (hPTR_t *) &s, &count))
02754             continue;
02755         (void) headerAddEntry(headerTo, *p, type, s, count);
02756         s = headerFreeData(s, type);
02757     }
02758 }
02759 
02763 struct headerIteratorS {
02764 /*@unused@*/ Header h;          
02765 /*@unused@*/ int next_index;    
02766 };
02767 
02768 HeaderIterator headerFreeIterator(HeaderIterator hi)
02769 {
02770     hi->h = headerFree(hi->h);
02771     hi = _free(hi);
02772     return hi;
02773 }
02774 
02775 HeaderIterator headerInitIterator(Header h)
02776 {
02777     HeaderIterator hi = xmalloc(sizeof(struct headerIteratorS));
02778 
02779     headerSort(h);
02780 
02781     hi->h = headerLink(h);
02782     hi->next_index = 0;
02783     return hi;
02784 }
02785 
02786 int headerNextIterator(HeaderIterator hi,
02787                  hTAG_t tag, hTYP_t type, hPTR_t * p, hCNT_t c)
02788 {
02789     Header h = hi->h;
02790     int slot = hi->next_index;
02791     indexEntry entry = NULL;
02792     int rc;
02793 
02794     for (slot = hi->next_index; slot < h->indexUsed; slot++) {
02795         entry = h->index + slot;
02796         if (!ENTRY_IS_REGION(entry))
02797             break;
02798     }
02799     hi->next_index = slot;
02800     if (entry == NULL || slot >= h->indexUsed)
02801         return 0;
02802     /*@-noeffect@*/     /* LCL: no clue */
02803     hi->next_index++;
02804     /*@=noeffect@*/
02805 
02806     if (tag)
02807         *tag = entry->info.tag;
02808 
02809     rc = copyEntry(entry, type, p, c, 0);
02810 
02811     /* XXX 1 on success */
02812     return ((rc == 1) ? 1 : 0);
02813 }
02814 static struct HV_s hdrVec1 = {
02815     headerNew,
02816     headerFree,
02817     headerLink,
02818     headerSort,
02819     headerUnsort,
02820     headerSizeof,
02821     headerUnload,
02822     headerReload,
02823     headerCopy,
02824     headerLoad,
02825     headerCopyLoad,
02826     headerRead,
02827     headerWrite,
02828     headerIsEntry,
02829     headerFreeTag,
02830     headerGetEntry,
02831     headerGetEntryMinMemory,
02832     headerAddEntry,
02833     headerAppendEntry,
02834     headerAddOrAppendEntry,
02835     headerAddI18NString,
02836     headerModifyEntry,
02837     headerRemoveEntry,
02838     headerSprintf,
02839     headerCopyTags,
02840     headerFreeIterator,
02841     headerInitIterator,
02842     headerNextIterator,
02843     NULL, NULL,
02844     1
02845 };
02846 
02847 /*@-compmempass -redef@*/
02848 HV_t hdrVec = &hdrVec1;
02849 /*@=compmempass =redef@*/

Generated at Wed Mar 27 03:56:49 2002 for rpm by doxygen1.2.8.1 written by Dimitri van Heesch, © 1997-2001