00001
00005 #undef REMALLOC_HEADER_REGION
00006 #define _DEBUG_SWAB 1
00007 #define _DEBUG_INDEX 1
00008
00009
00010
00011
00012
00013
00014
00015 #include "system.h"
00016
00017 #if !defined(__LCLINT__)
00018 #include <netinet/in.h>
00019 #endif
00020
00021 #include <header.h>
00022
00023 #include "debug.h"
00024
00025
00026 const char *const tagName(int tag) ;
00027
00028
00029
00030
00031 #define HEADER_OLDFILENAMES 1027
00032 #define HEADER_BASENAMES 1117
00033
00034 #define INDEX_MALLOC_SIZE 8
00035
00036 #define PARSER_BEGIN 0
00037 #define PARSER_IN_ARRAY 1
00038 #define PARSER_IN_EXPR 2
00039
00040 static unsigned char header_magic[8] = {
00041 0x8e, 0xad, 0xe8, 0x01, 0x00, 0x00, 0x00, 0x00
00042 };
00043
00047 static int typeSizes[] = {
00048 0,
00049 1,
00050 1,
00051 2,
00052 4,
00053 -1,
00054 -1,
00055 1,
00056 -1,
00057 -1
00058 };
00059
00063 struct entryInfo {
00064 int_32 tag;
00065 int_32 type;
00066 int_32 offset;
00067 int_32 count;
00068 };
00069
00070 #define REGION_TAG_TYPE RPM_BIN_TYPE
00071 #define REGION_TAG_COUNT sizeof(struct entryInfo)
00072
00073 #define ENTRY_IS_REGION(_e) ((_e)->info.tag < HEADER_I18NTABLE)
00074 #define ENTRY_IN_REGION(_e) ((_e)->info.offset < 0)
00075
00079 struct indexEntry {
00080 struct entryInfo info;
00081 void * data;
00082 int length;
00083 int rdlen;
00084 };
00085
00089 struct headerToken {
00090 struct indexEntry *index;
00091 int indexUsed;
00092 int indexAlloced;
00093 int region_allocated;
00094 int sorted;
00095 int legacy;
00096 int nrefs;
00097 };
00098
00101 struct sprintfTag {
00102 headerTagTagFunction ext;
00103 int extNum;
00104 int_32 tag;
00105 int justOne;
00106 int arrayCount;
00107 char * format;
00108 char * type;
00109 int pad;
00110 };
00111
00114 struct extensionCache {
00115 int_32 type;
00116 int_32 count;
00117 int avail;
00118 int freeit;
00119 const void * data;
00120 };
00121
00124 struct sprintfToken {
00125 enum {
00126 PTOK_NONE = 0,
00127 PTOK_TAG,
00128 PTOK_ARRAY,
00129 PTOK_STRING,
00130 PTOK_COND
00131 } type;
00132 union {
00133 struct {
00134 struct sprintfToken * format;
00135 int numTokens;
00136 } array;
00137 struct sprintfTag tag;
00138 struct {
00139 char * string;
00140 int len;
00141 } string;
00142 struct {
00143 struct sprintfToken * ifFormat;
00144 int numIfTokens;
00145 struct sprintfToken * elseFormat;
00146 int numElseTokens;
00147 struct sprintfTag tag;
00148 } cond;
00149 } u;
00150 };
00151
00160 static int dataLength(int_32 type, const void * p, int_32 count, int onDisk)
00161
00162 {
00163 int length = 0;
00164
00165 switch (type) {
00166 case RPM_STRING_TYPE:
00167 if (count == 1) {
00168 length = strlen(p) + 1;
00169 break;
00170 }
00171
00172 fprintf(stderr, _("dataLength() RPM_STRING_TYPE count must be 1.\n"));
00173 exit(EXIT_FAILURE);
00174 break;
00175
00176 case RPM_STRING_ARRAY_TYPE:
00177 case RPM_I18NSTRING_TYPE:
00178 { int i;
00179
00180
00181
00182 i = count;
00183
00184 if (onDisk) {
00185 const char * chptr = p;
00186 int thisLen;
00187
00188 while (i--) {
00189 thisLen = strlen(chptr) + 1;
00190 length += thisLen;
00191 chptr += thisLen;
00192 }
00193 } else {
00194 const char ** src = (const char **)p;
00195 while (i--) {
00196
00197 length += strlen(*src++) + 1;
00198 }
00199 }
00200 } break;
00201
00202 default:
00203 if (typeSizes[type] != -1) {
00204 length = typeSizes[type] * count;
00205 break;
00206 }
00207 fprintf(stderr, _("Data type %d not supported\n"), (int) type);
00208 exit(EXIT_FAILURE);
00209 break;
00210 }
00211
00212 return length;
00213 }
00214
00225 static int regionSwab(struct indexEntry * entry, int il, int dl,
00226 const struct entryInfo * pe, char * dataStart, int regionid)
00227 {
00228 for (; il > 0; il--, pe++) {
00229 struct indexEntry ie;
00230 int_32 type;
00231 void * t;
00232
00233 ie.info.tag = ntohl(pe->tag);
00234 ie.info.type = ntohl(pe->type);
00235 ie.info.count = ntohl(pe->count);
00236 ie.info.offset = ntohl(pe->offset);
00237 ie.data = t = dataStart + ie.info.offset;
00238 ie.length = dataLength(ie.info.type, ie.data, ie.info.count, 1);
00239 ie.rdlen = 0;
00240
00241 assert(ie.info.type >= RPM_MIN_TYPE && ie.info.type <= RPM_MAX_TYPE);
00242
00243 if (entry) {
00244 ie.info.offset = regionid;
00245 *entry = ie;
00246 entry++;
00247 }
00248
00249
00250 type = ie.info.type;
00251 if (typeSizes[type] > 1) {
00252 unsigned diff;
00253 diff = typeSizes[type] - (dl % typeSizes[type]);
00254 if (diff != typeSizes[type]) {
00255 dl += diff;
00256 }
00257 }
00258 dl += ie.length;
00259
00260
00261 switch (ntohl(pe->type)) {
00262 case RPM_INT32_TYPE:
00263 for (; ie.info.count > 0; ie.info.count--, ((int_32 *)t) += 1)
00264 *((int_32 *)t) = htonl(*((int_32 *)t));
00265 break;
00266 case RPM_INT16_TYPE:
00267 for (; ie.info.count > 0; ie.info.count--, ((int_16 *)t) += 1)
00268 *((int_16 *)t) = htons(*((int_16 *)t));
00269 break;
00270 }
00271 }
00272 return dl;
00273 }
00274
00283 static void copyEntry(const struct indexEntry * entry, int_32 * type,
00284 const void ** p, int_32 * c, int minMem)
00285
00286 {
00287 int_32 count = entry->info.count;
00288
00289 if (p)
00290 switch (entry->info.type) {
00291 case RPM_BIN_TYPE:
00292
00293 if (ENTRY_IS_REGION(entry)) {
00294 int_32 * ei = ((int_32 *)entry->data) - 2;
00295 struct entryInfo * pe = (struct entryInfo *) (ei + 2);
00296 char * dataStart = (char *) (pe + ntohl(ei[0]));
00297 int_32 rdl = -entry->info.offset;
00298 int_32 ril = rdl/sizeof(*pe);
00299
00300 count = 2 * sizeof(*ei) + (ril * sizeof(*pe)) +
00301 entry->rdlen + REGION_TAG_COUNT;
00302 ei = (int_32 *) *p = xmalloc(count);
00303 ei[0] = htonl(ril);
00304 ei[1] = htonl(entry->rdlen + REGION_TAG_COUNT);
00305 pe = (struct entryInfo *) memcpy(ei + 2, pe, (ril * sizeof(*pe)));
00306 dataStart = (char *) memcpy(pe + ril, dataStart,
00307 (entry->rdlen + REGION_TAG_COUNT));
00308
00309 (void) regionSwab(NULL, ril, 0, pe, dataStart, 0);
00310 } else {
00311 count = entry->length;
00312 *p = (!minMem
00313 ? memcpy(xmalloc(count), entry->data, count)
00314 : entry->data);
00315 }
00316 break;
00317 case RPM_STRING_TYPE:
00318 if (count == 1) {
00319 *p = entry->data;
00320 break;
00321 }
00322
00323 case RPM_STRING_ARRAY_TYPE:
00324 case RPM_I18NSTRING_TYPE:
00325 { const char ** ptrEntry;
00326 int tableSize = count * sizeof(char *);
00327 char * t;
00328 int i;
00329
00330 if (minMem) {
00331 *p = xmalloc(tableSize);
00332 ptrEntry = (const char **) *p;
00333 t = entry->data;
00334 } else {
00335 t = xmalloc(tableSize + entry->length);
00336 *p = (void *)t;
00337 ptrEntry = (const char **) *p;
00338 t += tableSize;
00339 memcpy(t, entry->data, entry->length);
00340 }
00341 for (i = 0; i < count; i++) {
00342 *ptrEntry++ = t;
00343 t = strchr(t, 0);
00344 t++;
00345 }
00346 } break;
00347
00348 default:
00349 *p = entry->data;
00350 break;
00351 }
00352 if (type) *type = entry->info.type;
00353 if (c) *c = count;
00354 }
00355
00359 struct headerIteratorS {
00360 Header h;
00361 int next_index;
00362 };
00363
00364 HeaderIterator headerInitIterator(Header h)
00365 {
00366 HeaderIterator hi = xmalloc(sizeof(struct headerIteratorS));
00367
00368 headerSort(h);
00369
00370 hi->h = headerLink(h);
00371 hi->next_index = 0;
00372 return hi;
00373 }
00374
00375 void headerFreeIterator(HeaderIterator iter)
00376 {
00377 headerFree(iter->h);
00378 free(iter);
00379 }
00380
00381 int headerNextIterator(HeaderIterator hi,
00382 int_32 * tag, int_32 * type, const void ** p, int_32 * c)
00383 {
00384 Header h = hi->h;
00385 int slot = hi->next_index;
00386 struct indexEntry * entry = NULL;;
00387
00388 for (slot = hi->next_index; slot < h->indexUsed; slot++) {
00389 entry = h->index + slot;
00390 if (!ENTRY_IS_REGION(entry))
00391 break;
00392 }
00393 hi->next_index = slot;
00394 if (entry == NULL || slot >= h->indexUsed)
00395 return 0;
00396 hi->next_index++;
00397
00398 if (tag)
00399 *tag = entry->info.tag;
00400
00401 copyEntry(entry, type, p, c, 0);
00402
00403 return 1;
00404 }
00405
00406 static int indexCmp(const void *avp, const void *bvp)
00407 {
00408 const struct indexEntry * ap = avp, * bp = bvp;
00409 return (ap->info.tag - bp->info.tag);
00410 }
00411
00412 void headerSort(Header h)
00413 {
00414 if (!h->sorted) {
00415 qsort(h->index, h->indexUsed, sizeof(*h->index), indexCmp);
00416 h->sorted = 1;
00417 }
00418 }
00419
00420 static int offsetCmp(const void *avp, const void *bvp)
00421 {
00422 const struct indexEntry * ap = avp, * bp = bvp;
00423 int rc = (ap->info.offset - bp->info.offset);
00424
00425 if (rc == 0)
00426 rc = (ap->info.tag - bp->info.tag);
00427 return rc;
00428 }
00429
00430 void headerUnsort(Header h)
00431 {
00432 qsort(h->index, h->indexUsed, sizeof(*h->index), offsetCmp);
00433 }
00434
00435 Header headerCopy(Header h)
00436 {
00437 Header nh = headerNew();
00438 HeaderIterator hi;
00439 int_32 tag, type, count;
00440 const void *ptr;
00441
00442 for (hi = headerInitIterator(h);
00443 headerNextIterator(hi, &tag, &type, &ptr, &count);
00444 ptr = headerFreeData((void *)ptr, type))
00445 {
00446 headerAddEntry(nh, tag, type, ptr, count);
00447 }
00448 headerFreeIterator(hi);
00449
00450 return headerReload(nh, HEADER_IMAGE);
00451 }
00452
00453 Header headerLoad(void *uh)
00454 {
00455 int_32 *ei = (int_32 *) uh;
00456 int_32 il = ntohl(ei[0]);
00457 int_32 dl = ntohl(ei[1]);
00458 int pvlen = sizeof(il) + sizeof(dl) +
00459 (il * sizeof(struct entryInfo)) + dl;
00460 #ifdef REMALLOC_HEADER_REGION
00461 void * pv = memcpy(xmalloc(pvlen), uh, pvlen);
00462 #else
00463 void * pv = uh;
00464 #endif
00465 Header h = xcalloc(1, sizeof(*h));
00466 struct entryInfo * pe;
00467 char * dataStart;
00468 struct indexEntry * entry;
00469 int rdlen;
00470 int i;
00471
00472 ei = (int_32 *) pv;
00473 pe = (struct entryInfo *) &ei[2];
00474 dataStart = (char *) (pe + il);
00475
00476 h->indexAlloced = il + 1;
00477 h->indexUsed = il;
00478 h->index = xcalloc(h->indexAlloced, sizeof(*h->index));
00479 h->sorted = 1;
00480 #ifdef REMALLOC_HEADER_REGION
00481 h->region_allocated = 1;
00482 #else
00483 h->region_allocated = 0;
00484 #endif
00485 h->nrefs = 1;
00486
00487
00488
00489
00490
00491 if (ntohl(pe->tag) == 15 &&
00492 ntohl(pe->type) == RPM_STRING_TYPE &&
00493 ntohl(pe->count) == 1)
00494 {
00495 pe->tag = htonl(1079);
00496 }
00497
00498 entry = h->index;
00499 i = 0;
00500 if (!(htonl(pe->tag) < HEADER_I18NTABLE)) {
00501 h->legacy = 1;
00502 entry->info.type = REGION_TAG_TYPE;
00503 entry->info.tag = HEADER_IMAGE;
00504 entry->info.count = REGION_TAG_COUNT;
00505 entry->info.offset = ((char *)pe - dataStart);
00506
00507 entry->data = pe;
00508 entry->length = pvlen - sizeof(il) - sizeof(dl);
00509 rdlen = regionSwab(entry+1, il, 0, pe, dataStart, entry->info.offset);
00510 entry->rdlen = rdlen;
00511 assert(rdlen == dl);
00512
00513 entry++;
00514 h->indexUsed++;
00515 } else {
00516 int nb = ntohl(pe->count);
00517 int_32 rdl;
00518 int_32 ril;
00519
00520 h->legacy = 0;
00521 entry->info.type = htonl(pe->type);
00522 if (entry->info.type < RPM_MIN_TYPE || entry->info.type > RPM_MAX_TYPE)
00523 return NULL;
00524 entry->info.count = htonl(pe->count);
00525
00526 { int off = ntohl(pe->offset);
00527 if (off) {
00528 int_32 * stei = memcpy(alloca(nb), dataStart + off, nb);
00529 rdl = -ntohl(stei[2]);
00530 ril = rdl/sizeof(*pe);
00531 entry->info.tag = htonl(pe->tag);
00532 } else {
00533 ril = il;
00534 rdl = (ril * sizeof(struct entryInfo));
00535 entry->info.tag = HEADER_IMAGE;
00536 }
00537 }
00538 entry->info.offset = -rdl;
00539
00540 entry->data = pe;
00541 entry->length = pvlen - sizeof(il) - sizeof(dl);
00542 rdlen = regionSwab(entry+1, ril-1, 0, pe+1, dataStart, entry->info.offset);
00543 entry->rdlen = rdlen;
00544
00545 if (ril < h->indexUsed) {
00546 struct indexEntry * newEntry = entry + ril;
00547 int ne = (h->indexUsed - ril);
00548 int rid = entry->info.offset+1;
00549
00550
00551 rdlen += regionSwab(newEntry, ne, 0, pe+ril, dataStart, rid);
00552
00553 { struct indexEntry * firstEntry = newEntry;
00554 int save = h->indexUsed;
00555 int j;
00556
00557
00558 h->indexUsed -= ne;
00559 for (j = 0; j < ne; j++, newEntry++) {
00560 headerRemoveEntry(h, newEntry->info.tag);
00561 if (newEntry->info.tag == HEADER_BASENAMES)
00562 headerRemoveEntry(h, HEADER_OLDFILENAMES);
00563 }
00564
00565
00566 if (h->indexUsed < (save - ne)) {
00567 memmove(h->index + h->indexUsed, firstEntry,
00568 (ne * sizeof(*entry)));
00569 }
00570 h->indexUsed += ne;
00571 }
00572
00573 }
00574 }
00575
00576 h->sorted = 0;
00577 headerSort(h);
00578
00579 return h;
00580 }
00581
00582 Header headerCopyLoad(void *uh)
00583 {
00584 int_32 *ei = (int_32 *) uh;
00585 int_32 il = ntohl(ei[0]);
00586 int_32 dl = ntohl(ei[1]);
00587 int pvlen = sizeof(il) + sizeof(dl) +
00588 (il * sizeof(struct entryInfo)) + dl;
00589 void * nuh = memcpy(xmalloc(pvlen), uh, pvlen);
00590 Header h;
00591
00592 h = headerLoad(nuh);
00593 if (h == NULL) {
00594 free(nuh);
00595 return h;
00596 }
00597 h->region_allocated = 1;
00598 return h;
00599 }
00600
00601 #if 0
00602 int headerDrips(const Header h)
00603 {
00604 struct indexEntry * entry;
00605 int i;
00606
00607 for (i = 0, entry = h->index; i < h->indexUsed; i++, entry++) {
00608 if (ENTRY_IS_REGION(entry)) {
00609 int rid = entry->info.offset;
00610
00611 for (; i < h->indexUsed && entry->info.offset <= rid+1; i++, entry++) {
00612 if (entry->info.offset <= rid)
00613 continue;
00614
00615 fprintf(stderr, "***\t%3d dribble %s\n", i, tagName(entry->info.tag));
00616 }
00617 i--;
00618 entry--;
00619 continue;
00620 }
00621
00622
00623 if (entry->data == NULL || entry->length <= 0)
00624 continue;
00625
00626 fprintf(stderr, "***\t%3d drip %s\n", i, tagName(entry->info.tag));
00627
00628 }
00629 return 0;
00630 }
00631 #endif
00632
00633 static void * doHeaderUnload(Header h, int * lengthPtr)
00634
00635 {
00636 int_32 * ei;
00637 struct entryInfo * pe;
00638 char * dataStart;
00639 char * te;
00640 unsigned pad;
00641 unsigned len;
00642 int_32 il = 0;
00643 int_32 dl = 0;
00644 struct indexEntry * entry;
00645 int_32 type;
00646 int i;
00647 int drlen, ndribbles;
00648 int driplen, ndrips;
00649 int legacy = 0;
00650
00651
00652 headerUnsort(h);
00653
00654
00655 pad = 0;
00656 drlen = ndribbles = driplen = ndrips = 0;
00657 for (i = 0, entry = h->index; i < h->indexUsed; i++, entry++) {
00658 if (ENTRY_IS_REGION(entry)) {
00659 int_32 rdl = -entry->info.offset;
00660 int_32 ril = rdl/sizeof(*pe);
00661 int rid = entry->info.offset;
00662
00663 il += ril;
00664 dl += entry->rdlen + entry->info.count;
00665
00666 if (i == 0 && h->legacy)
00667 il += 1;
00668
00669
00670 for (; i < h->indexUsed && entry->info.offset <= rid+1; i++, entry++) {
00671 if (entry->info.offset <= rid)
00672 continue;
00673
00674
00675 type = entry->info.type;
00676 if (typeSizes[type] > 1) {
00677 unsigned diff;
00678 diff = typeSizes[type] - (dl % typeSizes[type]);
00679 if (diff != typeSizes[type]) {
00680 drlen += diff;
00681 pad += diff;
00682 dl += diff;
00683 }
00684 }
00685
00686 ndribbles++;
00687 il++;
00688 drlen += entry->length;
00689 dl += entry->length;
00690 }
00691 i--;
00692 entry--;
00693 continue;
00694 }
00695
00696
00697 if (entry->data == NULL || entry->length <= 0)
00698 continue;
00699
00700
00701 type = entry->info.type;
00702 if (typeSizes[type] > 1) {
00703 unsigned diff;
00704 diff = typeSizes[type] - (dl % typeSizes[type]);
00705 if (diff != typeSizes[type]) {
00706 driplen += diff;
00707 pad += diff;
00708 dl += diff;
00709 } else
00710 diff = 0;
00711 }
00712
00713 ndrips++;
00714 il++;
00715 driplen += entry->length;
00716 dl += entry->length;
00717 }
00718 len = sizeof(il) + sizeof(dl) + (il * sizeof(*pe)) + dl;
00719
00720 ei = xmalloc(len);
00721 ei[0] = htonl(il);
00722 ei[1] = htonl(dl);
00723
00724 pe = (struct entryInfo *) &ei[2];
00725 dataStart = te = (char *) (pe + il);
00726
00727 pad = 0;
00728 for (i = 0, entry = h->index; i < h->indexUsed; i++, entry++) {
00729 const char * src;
00730 char *t;
00731 int count;
00732 int rdlen;
00733
00734 if (entry->data == NULL || entry->length <= 0)
00735 continue;
00736
00737 t = te;
00738 pe->tag = htonl(entry->info.tag);
00739 pe->type = htonl(entry->info.type);
00740 pe->count = htonl(entry->info.count);
00741
00742 if (ENTRY_IS_REGION(entry)) {
00743 int_32 rdl = -entry->info.offset;
00744 int_32 ril = rdl/sizeof(*pe) + ndribbles;
00745 int rid = entry->info.offset;
00746
00747 src = (char *)entry->data;
00748 rdlen = entry->rdlen;
00749
00750
00751 if (i == 0 && h->legacy) {
00752 int_32 stei[4];
00753
00754 legacy = 1;
00755 memcpy(pe+1, src, rdl);
00756 memcpy(te, src + rdl, rdlen);
00757 te += rdlen;
00758
00759 pe->offset = htonl(te - dataStart);
00760 stei[0] = pe->tag;
00761 stei[1] = pe->type;
00762 stei[2] = htonl(-rdl-entry->info.count);
00763 stei[3] = pe->count;
00764 memcpy(te, stei, entry->info.count);
00765 te += entry->info.count;
00766 ril++;
00767 rdlen += entry->info.count;
00768
00769 count = regionSwab(NULL, ril, 0, pe, t, 0);
00770 assert(count == rdlen);
00771
00772 } else {
00773
00774 memcpy(pe+1, src + sizeof(*pe), ((ril-1) * sizeof(*pe)));
00775 memcpy(te, src + (ril * sizeof(*pe)), rdlen+entry->info.count+drlen);
00776 te += rdlen;
00777 { struct entryInfo * se = (struct entryInfo *)src;
00778 int off = ntohl(se->offset);
00779 pe->offset = (off) ? htonl(te - dataStart) : htonl(off);
00780 }
00781 te += entry->info.count + drlen;
00782
00783 count = regionSwab(NULL, ril, 0, pe, t, 0);
00784 assert(count == rdlen+entry->info.count+drlen);
00785 }
00786
00787
00788 while (i < h->indexUsed && entry->info.offset <= rid+1) {
00789 i++;
00790 entry++;
00791 }
00792 i--;
00793 entry--;
00794 pe += ril;
00795 continue;
00796 }
00797
00798
00799 if (entry->data == NULL || entry->length <= 0)
00800 continue;
00801
00802
00803 type = entry->info.type;
00804 if (typeSizes[type] > 1) {
00805 unsigned diff;
00806 diff = typeSizes[type] - ((te - dataStart) % typeSizes[type]);
00807 if (diff != typeSizes[type]) {
00808 memset(te, 0, diff);
00809 te += diff;
00810 pad += diff;
00811 }
00812 }
00813
00814 pe->offset = htonl(te - dataStart);
00815
00816
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 te += sizeof(int_32);
00824 src += sizeof(int_32);
00825 }
00826 break;
00827
00828 case RPM_INT16_TYPE:
00829 count = entry->info.count;
00830 src = entry->data;
00831 while (count--) {
00832 *((int_16 *)te) = htons(*((int_16 *)src));
00833 te += sizeof(int_16);
00834 src += sizeof(int_16);
00835 }
00836 break;
00837
00838 default:
00839 memcpy(te, entry->data, entry->length);
00840 te += entry->length;
00841 break;
00842 }
00843 pe++;
00844 }
00845
00846
00847 assert(((char *)pe) == dataStart);
00848 assert((((char *)ei)+len) == te);
00849
00850 if (lengthPtr)
00851 *lengthPtr = len;
00852
00853 h->sorted = 0;
00854 headerSort(h);
00855
00856 return (void *)ei;
00857 }
00858
00859 void *headerUnload(Header h)
00860 {
00861 int length;
00862 void * uh = doHeaderUnload(h, &length);
00863 return uh;
00864 }
00865
00866 Header headerReload(Header h, int tag)
00867 {
00868 Header nh;
00869 int length;
00870 void * uh = doHeaderUnload(h, &length);
00871
00872 headerFree(h);
00873 nh = headerLoad(uh);
00874 if (nh == NULL) {
00875 free(uh);
00876 return nh;
00877 }
00878 if (nh->region_allocated)
00879 free(uh);
00880 nh->region_allocated = 1;
00881 if (ENTRY_IS_REGION(nh->index)) {
00882 if (tag == HEADER_SIGNATURES || tag == HEADER_IMMUTABLE)
00883 nh->index[0].info.tag = tag;
00884 }
00885 return nh;
00886 }
00887
00888 int headerWrite(FD_t fd, Header h, enum hMagic magicp)
00889 {
00890 ssize_t nb;
00891 int length;
00892 const void * uh;
00893
00894 uh = doHeaderUnload(h, &length);
00895 switch (magicp) {
00896 case HEADER_MAGIC_YES:
00897 nb = Fwrite(header_magic, sizeof(char), sizeof(header_magic), fd);
00898 if (nb != sizeof(header_magic))
00899 goto exit;
00900 break;
00901 case HEADER_MAGIC_NO:
00902 break;
00903 }
00904
00905 nb = Fwrite(uh, sizeof(char), length, fd);
00906
00907 exit:
00908 free((void *)uh);
00909 return (nb == length ? 0 : 1);
00910 }
00911
00912 Header headerRead(FD_t fd, enum hMagic magicp)
00913 {
00914 int_32 block[4];
00915 int_32 reserved;
00916 int_32 * ei = NULL;
00917 int_32 il;
00918 int_32 dl;
00919 int_32 magic;
00920 Header h = NULL;
00921 int len;
00922 int i;
00923
00924 memset(block, 0, sizeof(block));
00925 i = 2;
00926 if (magicp == HEADER_MAGIC_YES)
00927 i += 2;
00928
00929 if (timedRead(fd, (char *)block, i*sizeof(*block)) != (i * sizeof(*block)))
00930 goto exit;
00931
00932 i = 0;
00933
00934 if (magicp == HEADER_MAGIC_YES) {
00935 magic = block[i++];
00936 if (memcmp(&magic, header_magic, sizeof(magic)))
00937 goto exit;
00938 reserved = block[i++];
00939 }
00940
00941 il = ntohl(block[i++]);
00942 dl = ntohl(block[i++]);
00943
00944 len = sizeof(il) + sizeof(dl) + (il * sizeof(struct entryInfo)) + dl;
00945
00946
00947
00948
00949 if (len > (32*1024*1024))
00950 goto exit;
00951
00952 ei = xmalloc(len);
00953 ei[0] = htonl(il);
00954 ei[1] = htonl(dl);
00955 len -= sizeof(il) + sizeof(dl);
00956
00957 if (timedRead(fd, (char *)&ei[2], len) != len)
00958 goto exit;
00959
00960 h = headerLoad(ei);
00961
00962 exit:
00963 if (h) {
00964 if (h->region_allocated)
00965 free(ei);
00966 h->region_allocated = 1;
00967 } else if (ei)
00968 free(ei);
00969 return h;
00970 }
00971
00972 void headerDump(Header h, FILE *f, int flags,
00973 const struct headerTagTableEntry * tags)
00974 {
00975 int i;
00976 struct indexEntry *p;
00977 const struct headerTagTableEntry * tage;
00978 const char *tag;
00979 char *type;
00980
00981
00982 fprintf(f, "Entry count: %d\n", h->indexUsed);
00983
00984
00985 p = h->index;
00986 fprintf(f, "\n CT TAG TYPE "
00987 " OFSET COUNT\n");
00988 for (i = 0; i < h->indexUsed; i++) {
00989 switch (p->info.type) {
00990 case RPM_NULL_TYPE: type = "NULL_TYPE"; break;
00991 case RPM_CHAR_TYPE: type = "CHAR_TYPE"; break;
00992 case RPM_BIN_TYPE: type = "BIN_TYPE"; break;
00993 case RPM_INT8_TYPE: type = "INT8_TYPE"; break;
00994 case RPM_INT16_TYPE: type = "INT16_TYPE"; break;
00995 case RPM_INT32_TYPE: type = "INT32_TYPE"; break;
00996
00997 case RPM_STRING_TYPE: type = "STRING_TYPE"; break;
00998 case RPM_STRING_ARRAY_TYPE: type = "STRING_ARRAY_TYPE"; break;
00999 case RPM_I18NSTRING_TYPE: type = "I18N_STRING_TYPE"; break;
01000 default: type = "(unknown)"; break;
01001 }
01002
01003 tage = tags;
01004 while (tage->name && tage->val != p->info.tag) tage++;
01005
01006 if (!tage->name)
01007 tag = "(unknown)";
01008 else
01009 tag = tage->name;
01010
01011 fprintf(f, "Entry : %.3d (%d)%-14s %-18s 0x%.8x %.8d\n", i,
01012 p->info.tag, tag, type, (unsigned) p->info.offset, (int)
01013 p->info.count);
01014
01015 if (flags & HEADER_DUMP_INLINE) {
01016 char *dp = p->data;
01017 int c = p->info.count;
01018 int ct = 0;
01019
01020
01021 switch (p->info.type) {
01022 case RPM_INT32_TYPE:
01023 while (c--) {
01024 fprintf(f, " Data: %.3d 0x%08x (%d)\n", ct++,
01025 (unsigned) *((int_32 *) dp),
01026 (int) *((int_32 *) dp));
01027 dp += sizeof(int_32);
01028 }
01029 break;
01030
01031 case RPM_INT16_TYPE:
01032 while (c--) {
01033 fprintf(f, " Data: %.3d 0x%04x (%d)\n", ct++,
01034 (unsigned) (*((int_16 *) dp) & 0xffff),
01035 (int) *((int_16 *) dp));
01036 dp += sizeof(int_16);
01037 }
01038 break;
01039 case RPM_INT8_TYPE:
01040 while (c--) {
01041 fprintf(f, " Data: %.3d 0x%02x (%d)\n", ct++,
01042 (unsigned) (*((int_8 *) dp) & 0xff),
01043 (int) *((int_8 *) dp));
01044 dp += sizeof(int_8);
01045 }
01046 break;
01047 case RPM_BIN_TYPE:
01048 while (c > 0) {
01049 fprintf(f, " Data: %.3d ", ct);
01050 while (c--) {
01051 fprintf(f, "%02x ", (unsigned) (*(int_8 *)dp & 0xff));
01052 ct++;
01053 dp += sizeof(int_8);
01054 if (! (ct % 8)) {
01055 break;
01056 }
01057 }
01058 fprintf(f, "\n");
01059 }
01060 break;
01061 case RPM_CHAR_TYPE:
01062 while (c--) {
01063 char ch = (char) *((char *) dp);
01064 fprintf(f, " Data: %.3d 0x%2x %c (%d)\n", ct++,
01065 (unsigned)(ch & 0xff),
01066 (isprint(ch) ? ch : ' '),
01067 (int) *((char *) dp));
01068 dp += sizeof(char);
01069 }
01070 break;
01071 case RPM_STRING_TYPE:
01072 case RPM_STRING_ARRAY_TYPE:
01073 case RPM_I18NSTRING_TYPE:
01074 while (c--) {
01075 fprintf(f, " Data: %.3d %s\n", ct++, (char *) dp);
01076 dp = strchr(dp, 0);
01077 dp++;
01078 }
01079 break;
01080 default:
01081 fprintf(stderr, _("Data type %d not supported\n"),
01082 (int) p->info.type);
01083 exit(EXIT_FAILURE);
01084 break;
01085 }
01086 }
01087 p++;
01088 }
01089 }
01090
01098 static struct indexEntry *findEntry(Header h, int_32 tag, int_32 type)
01099 {
01100 struct indexEntry * entry, * entry2, * last;
01101 struct indexEntry key;
01102
01103 if (!h->sorted) headerSort(h);
01104
01105 key.info.tag = tag;
01106
01107 entry2 = entry =
01108 bsearch(&key, h->index, h->indexUsed, sizeof(*h->index), indexCmp);
01109 if (entry == NULL)
01110 return NULL;
01111
01112 if (type == RPM_NULL_TYPE)
01113 return entry;
01114
01115
01116 while (entry->info.tag == tag && entry->info.type != type &&
01117 entry > h->index) entry--;
01118
01119 if (entry->info.tag == tag && entry->info.type == type)
01120 return entry;
01121
01122 last = h->index + h->indexUsed;
01123 while (entry2->info.tag == tag && entry2->info.type != type &&
01124 entry2 < last) entry2++;
01125
01126 if (entry->info.tag == tag && entry->info.type == type)
01127 return entry;
01128
01129 return NULL;
01130 }
01131
01132 int headerIsEntry(Header h, int_32 tag)
01133 {
01134 return (findEntry(h, tag, RPM_NULL_TYPE) ? 1 : 0);
01135 }
01136
01137 int headerGetRawEntry(Header h, int_32 tag, int_32 * type, const void ** p,
01138 int_32 *c)
01139 {
01140 struct indexEntry * entry;
01141
01142 if (p == NULL) return headerIsEntry(h, tag);
01143
01144
01145 entry = findEntry(h, tag, RPM_NULL_TYPE);
01146 if (!entry) {
01147 if (p) *p = NULL;
01148 if (c) *c = 0;
01149 return 0;
01150 }
01151
01152 copyEntry(entry, type, p, c, 0);
01153
01154 return 1;
01155 }
01156
01175 static int headerMatchLocale(const char *td, const char *l, const char *le)
01176
01177 {
01178 const char *fe;
01179
01180
01181 #if 0
01182 { const char *s, *ll, *CC, *EE, *dd;
01183 char *lbuf, *t.
01184
01185
01186 lbuf = alloca(le - l + 1);
01187 for (s = l, ll = t = lbuf; *s; s++, t++) {
01188 switch (*s) {
01189 case '_':
01190 *t = '\0';
01191 CC = t + 1;
01192 break;
01193 case '.':
01194 *t = '\0';
01195 EE = t + 1;
01196 break;
01197 case '@':
01198 *t = '\0';
01199 dd = t + 1;
01200 break;
01201 default:
01202 *t = *s;
01203 break;
01204 }
01205 }
01206
01207 if (ll)
01208 for (t = ll; *t; t++) *t = tolower(*t);
01209 if (CC)
01210 for (t = CC; *t; t++) *t = toupper(*t);
01211
01212
01213 }
01214 #endif
01215
01216
01217 if (strlen(td) == (le-l) && !strncmp(td, l, (le - l)))
01218 return 1;
01219
01220
01221 for (fe = l; fe < le && *fe != '@'; fe++)
01222 ;
01223 if (fe < le && !strncmp(td, l, (fe - l)))
01224 return 1;
01225
01226
01227 for (fe = l; fe < le && *fe != '.'; fe++)
01228 ;
01229 if (fe < le && !strncmp(td, l, (fe - l)))
01230 return 1;
01231
01232
01233 for (fe = l; fe < le && *fe != '_'; fe++)
01234 ;
01235 if (fe < le && !strncmp(td, l, (fe - l)))
01236 return 1;
01237
01238 return 0;
01239 }
01240
01247 static char *
01248 headerFindI18NString(Header h, struct indexEntry *entry)
01249 {
01250 const char *lang, *l, *le;
01251 struct indexEntry * table;
01252
01253
01254 if ((lang = getenv("LANGUAGE")) == NULL &&
01255 (lang = getenv("LC_ALL")) == NULL &&
01256 (lang = getenv("LC_MESSAGES")) == NULL &&
01257 (lang = getenv("LANG")) == NULL)
01258 return entry->data;
01259
01260 if ((table = findEntry(h, HEADER_I18NTABLE, RPM_STRING_ARRAY_TYPE)) == NULL)
01261 return entry->data;
01262
01263 for (l = lang; *l; l = le) {
01264 const char *td;
01265 char *ed;
01266 int langNum;
01267
01268 while (*l && *l == ':')
01269 l++;
01270 if (*l == '\0')
01271 break;
01272 for (le = l; *le && *le != ':'; le++)
01273 ;
01274
01275
01276 for (langNum = 0, td = table->data, ed = entry->data;
01277 langNum < entry->info.count;
01278 langNum++, td += strlen(td) + 1, ed += strlen(ed) + 1) {
01279
01280 if (headerMatchLocale(td, l, le))
01281 return ed;
01282
01283 }
01284 }
01285
01286 return entry->data;
01287 }
01288
01299 static int intGetEntry(Header h, int_32 tag, int_32 *type,
01300 const void **p, int_32 *c, int minMem)
01301
01302 {
01303 struct indexEntry * entry;
01304
01305
01306 entry = findEntry(h, tag, RPM_NULL_TYPE);
01307 if (entry == NULL) {
01308 if (type) type = 0;
01309 if (p) *p = NULL;
01310 if (c) *c = 0;
01311 return 0;
01312 }
01313
01314 switch (entry->info.type) {
01315 case RPM_I18NSTRING_TYPE:
01316 if (type) *type = RPM_STRING_TYPE;
01317 if (c) *c = 1;
01318
01319 if (p) *p = headerFindI18NString(h, entry);
01320
01321 break;
01322 default:
01323 copyEntry(entry, type, p, c, minMem);
01324 break;
01325 }
01326
01327 return 1;
01328 }
01329
01330 int headerGetEntryMinMemory(Header h, int_32 tag, int_32 *type, const void **p,
01331 int_32 *c)
01332 {
01333 return intGetEntry(h, tag, type, p, c, 1);
01334 }
01335
01336 int headerGetEntry(Header h, int_32 tag, int_32 * type, void **p, int_32 * c)
01337 {
01338 return intGetEntry(h, tag, type, (const void **)p, c, 0);
01339 }
01340
01341 Header headerNew()
01342 {
01343 Header h = xcalloc(1, sizeof(*h));
01344
01345 h->indexAlloced = INDEX_MALLOC_SIZE;
01346 h->indexUsed = 0;
01347 h->region_allocated = 0;
01348 h->sorted = 1;
01349 h->legacy = 0;
01350 h->nrefs = 1;
01351
01352 h->index = (h->indexAlloced
01353 ? xcalloc(h->indexAlloced, sizeof(*h->index))
01354 : NULL);
01355
01356 return h;
01357 }
01358
01359 void headerFree(Header h)
01360 {
01361 if (h == NULL || --h->nrefs > 0)
01362 return;
01363
01364 if (h->index) {
01365 struct indexEntry * entry = h->index;
01366 int i;
01367 for (i = 0; i < h->indexUsed; i++, entry++) {
01368 if (h->region_allocated && ENTRY_IS_REGION(entry)) {
01369 if (entry->length > 0) {
01370 int_32 * ei = entry->data;
01371 ei -= 2;
01372 free(ei);
01373 }
01374 } else if (!ENTRY_IN_REGION(entry)) {
01375 free(entry->data);
01376 }
01377 entry->data = NULL;
01378 }
01379 free(h->index);
01380 h->index = NULL;
01381 }
01382
01383 free(h);
01384 }
01385
01386 Header headerLink(Header h)
01387 {
01388 h->nrefs++;
01389 return h;
01390 }
01391
01392 int headerUsageCount(Header h)
01393 {
01394 return h->nrefs;
01395 }
01396
01397 unsigned int headerSizeof(Header h, enum hMagic magicp)
01398 {
01399 struct indexEntry * entry;
01400 unsigned int size = 0, pad = 0;
01401 int i;
01402
01403 headerSort(h);
01404
01405 switch (magicp) {
01406 case HEADER_MAGIC_YES:
01407 size += sizeof(header_magic);
01408 break;
01409 case HEADER_MAGIC_NO:
01410 break;
01411 }
01412
01413 size += 2 * sizeof(int_32);
01414
01415 for (i = 0, entry = h->index; i < h->indexUsed; i++, entry++) {
01416 unsigned diff;
01417 int_32 type;
01418
01419
01420 if (ENTRY_IS_REGION(entry)) {
01421 size += entry->length;
01422
01423 if (i == 0 && h->legacy)
01424 size += sizeof(struct entryInfo) + entry->info.count;
01425 continue;
01426 }
01427
01428
01429 if (entry->info.offset < 0)
01430 continue;
01431
01432
01433 type = entry->info.type;
01434 if (typeSizes[type] > 1) {
01435 diff = typeSizes[type] - (size % typeSizes[type]);
01436 if (diff != typeSizes[type]) {
01437 size += diff;
01438 pad += diff;
01439 }
01440 }
01441
01442 size += sizeof(struct entryInfo) + entry->length;
01443 }
01444
01445 return size;
01446 }
01447
01448 static void copyData(int_32 type, void * dstPtr, const void * srcPtr,
01449 int_32 c, int dataLength)
01450
01451 {
01452 const char ** src;
01453 char * dst;
01454 int i, len;
01455
01456 switch (type) {
01457 case RPM_STRING_ARRAY_TYPE:
01458 case RPM_I18NSTRING_TYPE:
01459
01460 i = c;
01461 src = (const char **) srcPtr;
01462 dst = dstPtr;
01463 while (i--) {
01464 len = *src ? strlen(*src) + 1 : 0;
01465 memcpy(dst, *src, len);
01466 dst += len;
01467 src++;
01468 }
01469 break;
01470
01471 default:
01472 memcpy(dstPtr, srcPtr, dataLength);
01473 break;
01474 }
01475 }
01476
01485 static void * grabData(int_32 type, const void * p, int_32 c,
01486 int * lengthPtr)
01487
01488 {
01489 int length = dataLength(type, p, c, 0);
01490 void * data = xmalloc(length);
01491
01492 copyData(type, data, p, c, length);
01493
01494 if (lengthPtr)
01495 *lengthPtr = length;
01496 return data;
01497 }
01498
01499 int headerAddEntry(Header h, int_32 tag, int_32 type, const void *p, int_32 c)
01500 {
01501 struct indexEntry *entry;
01502
01503 if (c <= 0) {
01504 fprintf(stderr, _("Bad count for headerAddEntry(): %d\n"), (int) c);
01505 exit(EXIT_FAILURE);
01506
01507 }
01508
01509
01510 if (h->indexUsed == h->indexAlloced) {
01511 h->indexAlloced += INDEX_MALLOC_SIZE;
01512 h->index = xrealloc(h->index,
01513 h->indexAlloced * sizeof(struct indexEntry));
01514 }
01515
01516
01517 entry = h->index + h->indexUsed;
01518 entry->info.tag = tag;
01519 entry->info.type = type;
01520 entry->info.count = c;
01521 entry->info.offset = 0;
01522 entry->data = grabData(type, p, c, &entry->length);
01523
01524 if (h->indexUsed > 0 && tag < h->index[h->indexUsed-1].info.tag)
01525 h->sorted = 0;
01526 h->indexUsed++;
01527
01528 return 1;
01529 }
01530
01531 char **
01532 headerGetLangs(Header h)
01533 {
01534 char **s, *e, **table;
01535 int i, type, count;
01536
01537 if (!headerGetRawEntry(h, HEADER_I18NTABLE, &type, (const void **)&s, &count))
01538 return NULL;
01539
01540 if ((table = (char **)xcalloc((count+1), sizeof(char *))) == NULL)
01541 return NULL;
01542
01543 for (i = 0, e = *s; i < count > 0; i++, e += strlen(e)+1)
01544 table[i] = e;
01545 table[count] = NULL;
01546
01547 return table;
01548 }
01549
01550 int headerAddI18NString(Header h, int_32 tag, const char * string, const char * lang)
01551 {
01552 struct indexEntry * table, * entry;
01553 char * chptr;
01554 const char ** strArray;
01555 int length;
01556 int ghosts;
01557 int i, langNum;
01558 char * buf;
01559
01560 table = findEntry(h, HEADER_I18NTABLE, RPM_STRING_ARRAY_TYPE);
01561 entry = findEntry(h, tag, RPM_I18NSTRING_TYPE);
01562
01563 if (!table && entry)
01564 return 0;
01565
01566 if (!table && !entry) {
01567 const char * charArray[2];
01568 int count = 0;
01569 if (!lang || (lang[0] == 'C' && lang[1] == '\0')) {
01570
01571 charArray[count++] = "C";
01572
01573 } else {
01574
01575 charArray[count++] = "C";
01576
01577 charArray[count++] = lang;
01578 }
01579 if (!headerAddEntry(h, HEADER_I18NTABLE, RPM_STRING_ARRAY_TYPE,
01580 &charArray, count))
01581 return 0;
01582 table = findEntry(h, HEADER_I18NTABLE, RPM_STRING_ARRAY_TYPE);
01583 }
01584
01585 if (!lang) lang = "C";
01586
01587 chptr = table->data;
01588 for (langNum = 0; langNum < table->info.count; langNum++) {
01589 if (!strcmp(chptr, lang)) break;
01590 chptr += strlen(chptr) + 1;
01591 }
01592
01593 if (langNum >= table->info.count) {
01594 length = strlen(lang) + 1;
01595 if (ENTRY_IN_REGION(table)) {
01596 char * t = xmalloc(table->length + length);
01597 memcpy(t, table->data, table->length);
01598 table->data = t;
01599 table->info.offset = 0;
01600 } else
01601 table->data = xrealloc(table->data, table->length + length);
01602 memcpy(((char *)table->data) + table->length, lang, length);
01603 table->length += length;
01604 table->info.count++;
01605 }
01606
01607 if (!entry) {
01608 strArray = alloca(sizeof(*strArray) * (langNum + 1));
01609 for (i = 0; i < langNum; i++)
01610 strArray[i] = "";
01611 strArray[langNum] = string;
01612 return headerAddEntry(h, tag, RPM_I18NSTRING_TYPE, strArray,
01613 langNum + 1);
01614 } else if (langNum >= entry->info.count) {
01615 ghosts = langNum - entry->info.count;
01616
01617 length = strlen(string) + 1 + ghosts;
01618 if (ENTRY_IN_REGION(entry)) {
01619 char * t = xmalloc(entry->length + length);
01620 memcpy(t, entry->data, entry->length);
01621 entry->data = t;
01622 entry->info.offset = 0;
01623 } else
01624 entry->data = xrealloc(entry->data, entry->length + length);
01625
01626 memset(((char *)entry->data) + entry->length, '\0', ghosts);
01627 strcpy(((char *)entry->data) + entry->length + ghosts, string);
01628
01629 entry->length += length;
01630 entry->info.count = langNum + 1;
01631 } else {
01632 char *b, *be, *e, *ee, *t;
01633 size_t bn, sn, en;
01634
01635
01636 b = be = e = ee = entry->data;
01637 for (i = 0; i < table->info.count; i++) {
01638 if (i == langNum)
01639 be = ee;
01640 ee += strlen(ee) + 1;
01641 if (i == langNum)
01642 e = ee;
01643 }
01644
01645
01646 bn = (be-b);
01647 sn = strlen(string) + 1;
01648 en = (ee-e);
01649 length = bn + sn + en;
01650 t = buf = xmalloc(length);
01651
01652
01653 memcpy(t, b, bn);
01654 t += bn;
01655 memcpy(t, string, sn);
01656 t += sn;
01657 memcpy(t, e, en);
01658 t += en;
01659
01660
01661 entry->length -= strlen(be) + 1;
01662 entry->length += sn;
01663
01664 if (ENTRY_IN_REGION(entry)) {
01665 entry->info.offset = 0;
01666 } else
01667 free(entry->data);
01668 entry->data = buf;
01669 }
01670
01671 return 0;
01672 }
01673
01674
01675 int headerModifyEntry(Header h, int_32 tag, int_32 type, void *p, int_32 c)
01676 {
01677 struct indexEntry *entry;
01678 void * oldData;
01679
01680
01681 entry = findEntry(h, tag, type);
01682 if (!entry)
01683 return 0;
01684
01685
01686 while (entry > h->index && (entry - 1)->info.tag == tag)
01687 entry--;
01688
01689
01690
01691 oldData = entry->data;
01692
01693 entry->info.count = c;
01694 entry->info.type = type;
01695 entry->data = grabData(type, p, c, &entry->length);
01696
01697 if (ENTRY_IN_REGION(entry)) {
01698 entry->info.offset = 0;
01699 } else
01700 free(oldData);
01701
01702 return 1;
01703 }
01704
01705 int headerAddOrAppendEntry(Header h, int_32 tag, int_32 type,
01706 void * p, int_32 c)
01707 {
01708 return (findEntry(h, tag, type)
01709 ? headerAppendEntry(h, tag, type, p, c)
01710 : headerAddEntry(h, tag, type, p, c));
01711 }
01712
01713 int headerAppendEntry(Header h, int_32 tag, int_32 type, void * p, int_32 c)
01714 {
01715 struct indexEntry *entry;
01716 int length;
01717
01718
01719 entry = findEntry(h, tag, type);
01720 if (!entry)
01721 return 0;
01722
01723 if (type == RPM_STRING_TYPE || type == RPM_I18NSTRING_TYPE) {
01724
01725 return 0;
01726 }
01727
01728 length = dataLength(type, p, c, 0);
01729
01730 if (ENTRY_IN_REGION(entry)) {
01731 char * t = xmalloc(entry->length + length);
01732 memcpy(t, entry->data, entry->length);
01733 entry->data = t;
01734 entry->info.offset = 0;
01735 } else
01736 entry->data = xrealloc(entry->data, entry->length + length);
01737
01738 copyData(type, ((char *) entry->data) + entry->length, p, c, length);
01739
01740 entry->length += length;
01741
01742 entry->info.count += c;
01743
01744 return 1;
01745 }
01746
01747 int headerRemoveEntry(Header h, int_32 tag)
01748 {
01749 struct indexEntry * last = h->index + h->indexUsed;
01750 struct indexEntry * entry, * first;
01751 int ne;
01752
01753 entry = findEntry(h, tag, RPM_NULL_TYPE);
01754 if (!entry) return 1;
01755
01756
01757 while (entry > h->index && (entry - 1)->info.tag == tag)
01758 entry--;
01759
01760
01761 for (first = entry; first < last; first++) {
01762 void * data;
01763 if (first->info.tag != tag)
01764 break;
01765 data = first->data;
01766 first->data = NULL;
01767 first->length = 0;
01768 if (ENTRY_IN_REGION(first))
01769 continue;
01770 free(data);
01771 }
01772
01773 ne = (first - entry);
01774 if (ne > 0) {
01775 h->indexUsed -= ne;
01776 ne = last - first;
01777 if (ne > 0)
01778 memmove(entry, first, (ne * sizeof(*entry)));
01779 }
01780
01781 return 0;
01782 }
01783
01784 static char escapedChar(const char ch)
01785 {
01786 switch (ch) {
01787 case 'a': return '\a';
01788 case 'b': return '\b';
01789 case 'f': return '\f';
01790 case 'n': return '\n';
01791 case 'r': return '\r';
01792 case 't': return '\t';
01793 case 'v': return '\v';
01794 default: return ch;
01795 }
01796 }
01797
01798 static void freeFormat( struct sprintfToken * format, int num)
01799 {
01800 int i;
01801
01802 for (i = 0; i < num; i++) {
01803 switch (format[i].type) {
01804 case PTOK_ARRAY:
01805 freeFormat(format[i].u.array.format, format[i].u.array.numTokens);
01806 break;
01807 case PTOK_COND:
01808 freeFormat(format[i].u.cond.ifFormat,
01809 format[i].u.cond.numIfTokens);
01810 freeFormat(format[i].u.cond.elseFormat,
01811 format[i].u.cond.numElseTokens);
01812 break;
01813 case PTOK_NONE:
01814 case PTOK_TAG:
01815 case PTOK_STRING:
01816 default:
01817 break;
01818 }
01819 }
01820 free(format);
01821 }
01822
01823 static void findTag(char * name, const struct headerTagTableEntry * tags,
01824 const struct headerSprintfExtension * extensions,
01825 const struct headerTagTableEntry ** tagMatch,
01826 const struct headerSprintfExtension ** extMatch)
01827
01828 {
01829 const struct headerTagTableEntry * entry;
01830 const struct headerSprintfExtension * ext;
01831 const char * tagname;
01832
01833 *tagMatch = NULL;
01834 *extMatch = NULL;
01835
01836 if (strncmp("RPMTAG_", name, sizeof("RPMTAG_")-1)) {
01837 char * t = alloca(strlen(name) + sizeof("RPMTAG_"));
01838 (void) stpcpy( stpcpy(t, "RPMTAG_"), name);
01839 tagname = t;
01840 } else {
01841 tagname = name;
01842 }
01843
01844
01845 ext = extensions;
01846 while (ext->type != HEADER_EXT_LAST) {
01847 if (ext->type == HEADER_EXT_TAG && !strcasecmp(ext->name, tagname))
01848 break;
01849
01850 if (ext->type == HEADER_EXT_MORE)
01851 ext = ext->u.more;
01852 else
01853 ext++;
01854 }
01855
01856 if (ext->type == HEADER_EXT_TAG) {
01857 *extMatch = ext;
01858 return;
01859 }
01860
01861
01862 for (entry = tags; entry->name; entry++)
01863 if (!strcasecmp(entry->name, tagname)) break;
01864
01865 if (entry->name) {
01866 *tagMatch = entry;
01867 return;
01868 }
01869 }
01870
01871
01872 static int parseExpression(struct sprintfToken * token, char * str,
01873 const struct headerTagTableEntry * tags,
01874 const struct headerSprintfExtension * extensions,
01875 char ** endPtr, const char ** errmsg)
01876 ;
01877
01878 static int parseFormat(char * str, const struct headerTagTableEntry * tags,
01879 const struct headerSprintfExtension * extensions,
01880 struct sprintfToken ** formatPtr, int * numTokensPtr,
01881 char ** endPtr, int state, const char ** errmsg)
01882
01883 {
01884 char * chptr, * start, * next, * dst;
01885 struct sprintfToken * format;
01886 int numTokens;
01887 int currToken;
01888 const struct headerTagTableEntry * tag;
01889 const struct headerSprintfExtension * ext;
01890 int i;
01891 int done = 0;
01892
01893
01894 numTokens = 0;
01895 for (chptr = str; *chptr; chptr++)
01896 if (*chptr == '%') numTokens++;
01897 numTokens = numTokens * 2 + 1;
01898
01899 format = xcalloc(numTokens, sizeof(*format));
01900 if (endPtr) *endPtr = NULL;
01901
01902
01903 dst = start = str;
01904 currToken = -1;
01905 while (*start) {
01906 switch (*start) {
01907 case '%':
01908
01909 if (*(start + 1) == '%') {
01910 if (currToken < 0 || format[currToken].type != PTOK_STRING) {
01911 currToken++;
01912 format[currToken].type = PTOK_STRING;
01913 dst = format[currToken].u.string.string = start;
01914 }
01915
01916 start++;
01917
01918 *dst++ = *start++;
01919
01920 break;
01921 }
01922
01923 currToken++;
01924 *dst++ = '\0';
01925 start++;
01926
01927 if (*start == '|') {
01928 char * newEnd;
01929
01930 start++;
01931 if (parseExpression(format + currToken, start, tags,
01932 extensions, &newEnd, errmsg)) {
01933 freeFormat(format, numTokens);
01934 return 1;
01935 }
01936 start = newEnd;
01937 break;
01938 }
01939
01940 format[currToken].u.tag.format = start;
01941 format[currToken].u.tag.pad = 0;
01942 format[currToken].u.tag.justOne = 0;
01943 format[currToken].u.tag.arrayCount = 0;
01944
01945 chptr = start;
01946 while (*chptr && *chptr != '{' && *chptr != '%') chptr++;
01947 if (!*chptr || *chptr == '%') {
01948
01949 *errmsg = _("missing { after %");
01950
01951 freeFormat(format, numTokens);
01952 return 1;
01953 }
01954
01955 *chptr++ = '\0';
01956
01957 while (start < chptr) {
01958 if (isdigit(*start)) {
01959 i = strtoul(start, &start, 10);
01960 format[currToken].u.tag.pad += i;
01961 } else {
01962 start++;
01963 }
01964 }
01965
01966 if (*start == '=') {
01967 format[currToken].u.tag.justOne = 1;
01968 start++;
01969 } else if (*start == '#') {
01970 format[currToken].u.tag.justOne = 1;
01971 format[currToken].u.tag.arrayCount = 1;
01972 start++;
01973 }
01974
01975 next = start;
01976 while (*next && *next != '}') next++;
01977 if (!*next) {
01978
01979 *errmsg = _("missing } after %{");
01980
01981 freeFormat(format, numTokens);
01982 return 1;
01983 }
01984 *next++ = '\0';
01985
01986 chptr = start;
01987 while (*chptr && *chptr != ':') chptr++;
01988
01989 if (*chptr) {
01990 *chptr++ = '\0';
01991 if (!*chptr) {
01992
01993 *errmsg = _("empty tag format");
01994
01995 freeFormat(format, numTokens);
01996 return 1;
01997 }
01998 format[currToken].u.tag.type = chptr;
01999 } else {
02000 format[currToken].u.tag.type = NULL;
02001 }
02002
02003 if (!*start) {
02004
02005 *errmsg = _("empty tag name");
02006
02007 freeFormat(format, numTokens);
02008 return 1;
02009 }
02010
02011 i = 0;
02012 findTag(start, tags, extensions, &tag, &ext);
02013
02014 if (tag) {
02015 format[currToken].u.tag.ext = NULL;
02016 format[currToken].u.tag.tag = tag->val;
02017 } else if (ext) {
02018 format[currToken].u.tag.ext = ext->u.tagFunction;
02019 format[currToken].u.tag.extNum = ext - extensions;
02020 } else {
02021
02022 *errmsg = _("unknown tag");
02023
02024 freeFormat(format, numTokens);
02025 return 1;
02026 }
02027
02028 format[currToken].type = PTOK_TAG;
02029
02030 start = next;
02031
02032 break;
02033
02034 case '[':
02035 *dst++ = '\0';
02036 *start++ = '\0';
02037 currToken++;
02038
02039 if (parseFormat(start, tags, extensions,
02040 &format[currToken].u.array.format,
02041 &format[currToken].u.array.numTokens,
02042 &start, PARSER_IN_ARRAY, errmsg)) {
02043 freeFormat(format, numTokens);
02044 return 1;
02045 }
02046
02047 if (!start) {
02048
02049 *errmsg = _("] expected at end of array");
02050
02051 freeFormat(format, numTokens);
02052 return 1;
02053 }
02054
02055 dst = start;
02056
02057 format[currToken].type = PTOK_ARRAY;
02058
02059 break;
02060
02061 case ']':
02062 case '}':
02063 if ((*start == ']' && state != PARSER_IN_ARRAY) ||
02064 (*start == '}' && state != PARSER_IN_EXPR)) {
02065 if (*start == ']')
02066
02067 *errmsg = _("unexpected ]");
02068
02069 else
02070
02071 *errmsg = _("unexpected }");
02072
02073 freeFormat(format, numTokens);
02074 return 1;
02075 }
02076 *start++ = '\0';
02077 *endPtr = start;
02078 done = 1;
02079 break;
02080
02081 default:
02082 if (currToken < 0 || format[currToken].type != PTOK_STRING) {
02083 currToken++;
02084 format[currToken].type = PTOK_STRING;
02085 dst = format[currToken].u.string.string = start;
02086 }
02087
02088 if (*start == '\\') {
02089 start++;
02090 *dst++ = escapedChar(*start++);
02091 } else {
02092 *dst++ = *start++;
02093 }
02094 break;
02095 }
02096 if (done)
02097 break;
02098 }
02099
02100
02101 *dst = '\0';
02102
02103 currToken++;
02104 for (i = 0; i < currToken; i++) {
02105 if (format[i].type == PTOK_STRING)
02106 format[i].u.string.len = strlen(format[i].u.string.string);
02107 }
02108
02109 *numTokensPtr = currToken;
02110 *formatPtr = format;
02111
02112 return 0;
02113 }
02114
02115 static int parseExpression(struct sprintfToken * token, char * str,
02116 const struct headerTagTableEntry * tags,
02117 const struct headerSprintfExtension * extensions,
02118 char ** endPtr, const char ** errmsg)
02119 {
02120 const struct headerTagTableEntry * tag;
02121 const struct headerSprintfExtension * ext;
02122 char * chptr;
02123 char * end;
02124
02125 *errmsg = NULL;
02126 chptr = str;
02127 while (*chptr && *chptr != '?') chptr++;
02128
02129 if (*chptr != '?') {
02130
02131 *errmsg = _("? expected in expression");
02132
02133 return 1;
02134 }
02135
02136 *chptr++ = '\0';;
02137
02138 if (*chptr != '{') {
02139
02140 *errmsg = _("{ expected after ? in expression");
02141
02142 return 1;
02143 }
02144
02145 chptr++;
02146
02147 if (parseFormat(chptr, tags, extensions, &token->u.cond.ifFormat,
02148 &token->u.cond.numIfTokens, &end, PARSER_IN_EXPR, errmsg))
02149 return 1;
02150
02151 if (!*end) {
02152
02153 *errmsg = _("} expected in expression");
02154
02155 freeFormat(token->u.cond.ifFormat, token->u.cond.numIfTokens);
02156 token->u.cond.ifFormat = NULL;
02157 return 1;
02158 }
02159
02160 chptr = end;
02161 if (*chptr != ':' && *chptr != '|') {
02162
02163 *errmsg = _(": expected following ? subexpression");
02164
02165 freeFormat(token->u.cond.ifFormat, token->u.cond.numIfTokens);
02166 token->u.cond.ifFormat = NULL;
02167 return 1;
02168 }
02169
02170 if (*chptr == '|') {
02171 parseFormat(xstrdup(""), tags, extensions, &token->u.cond.elseFormat,
02172 &token->u.cond.numElseTokens, &end, PARSER_IN_EXPR,
02173 errmsg);
02174 } else {
02175 chptr++;
02176
02177 if (*chptr != '{') {
02178
02179 *errmsg = _("{ expected after : in expression");
02180
02181 freeFormat(token->u.cond.ifFormat, token->u.cond.numIfTokens);
02182 token->u.cond.ifFormat = NULL;
02183 return 1;
02184 }
02185
02186 chptr++;
02187
02188 if (parseFormat(chptr, tags, extensions, &token->u.cond.elseFormat,
02189 &token->u.cond.numElseTokens, &end, PARSER_IN_EXPR,
02190 errmsg))
02191 return 1;
02192 if (!*end) {
02193
02194 *errmsg = _("} expected in expression");
02195
02196 freeFormat(token->u.cond.ifFormat, token->u.cond.numIfTokens);
02197 token->u.cond.ifFormat = NULL;
02198 return 1;
02199 }
02200
02201 chptr = end;
02202 if (*chptr != '|') {
02203
02204 *errmsg = _("| expected at end of expression");
02205
02206 freeFormat(token->u.cond.ifFormat, token->u.cond.numIfTokens);
02207 token->u.cond.ifFormat = NULL;
02208 freeFormat(token->u.cond.elseFormat, token->u.cond.numElseTokens);
02209 token->u.cond.elseFormat = NULL;
02210 return 1;
02211 }
02212 }
02213
02214 chptr++;
02215
02216 *endPtr = chptr;
02217
02218 findTag(str, tags, extensions, &tag, &ext);
02219
02220 if (tag) {
02221 token->u.cond.tag.ext = NULL;
02222 token->u.cond.tag.tag = tag->val;
02223 } else if (ext) {
02224 token->u.cond.tag.ext = ext->u.tagFunction;
02225 token->u.cond.tag.extNum = ext - extensions;
02226 } else {
02227 token->u.cond.tag.ext = NULL;
02228 token->u.cond.tag.tag = -1;
02229 }
02230
02231 token->type = PTOK_COND;
02232
02233 return 0;
02234 }
02235
02236 static int getExtension(Header h, headerTagTagFunction fn,
02237 int_32 * typeptr, const void ** data,
02238 int_32 * countptr, struct extensionCache * ext)
02239
02240 {
02241 if (!ext->avail) {
02242 if (fn(h, &ext->type, &ext->data, &ext->count, &ext->freeit))
02243 return 1;
02244 ext->avail = 1;
02245 }
02246
02247 *typeptr = ext->type;
02248 *data = ext->data;
02249 *countptr = ext->count;
02250
02251 return 0;
02252 }
02253
02254 static char * formatValue(struct sprintfTag * tag, Header h,
02255 const struct headerSprintfExtension * extensions,
02256 struct extensionCache * extCache, int element)
02257
02258 {
02259 int len;
02260 char buf[20];
02261 int_32 count, type;
02262 const void * data;
02263 unsigned int intVal;
02264 char * val = NULL;
02265 const char ** strarray;
02266 int mayfree = 0;
02267 int countBuf;
02268 headerTagFormatFunction tagtype = NULL;
02269 const struct headerSprintfExtension * ext;
02270
02271 if (tag->ext) {
02272 if (getExtension(h, tag->ext, &type, &data, &count,
02273 extCache + tag->extNum)) {
02274 count = 1;
02275 type = RPM_STRING_TYPE;
02276 data = "(none)";
02277 }
02278 } else {
02279 if (!headerGetEntry(h, tag->tag, &type, (void **)&data, &count)){
02280 count = 1;
02281 type = RPM_STRING_TYPE;
02282 data = "(none)";
02283 }
02284
02285 mayfree = 1;
02286 }
02287
02288 if (tag->arrayCount) {
02289
02290 data = headerFreeData(data, type);
02291
02292
02293 countBuf = count;
02294 data = &countBuf;
02295 count = 1;
02296 type = RPM_INT32_TYPE;
02297 }
02298
02299 (void) stpcpy( stpcpy(buf, "%"), tag->format);
02300
02301 if (tag->type) {
02302 ext = extensions;
02303 while (ext->type != HEADER_EXT_LAST) {
02304 if (ext->type == HEADER_EXT_FORMAT &&
02305 !strcmp(ext->name, tag->type)) {
02306 tagtype = ext->u.formatFunction;
02307 break;
02308 }
02309
02310 if (ext->type == HEADER_EXT_MORE)
02311 ext = ext->u.more;
02312 else
02313 ext++;
02314 }
02315 }
02316
02317 switch (type) {
02318 case RPM_STRING_ARRAY_TYPE:
02319 strarray = (const char **)data;
02320
02321 if (tagtype)
02322 val = tagtype(RPM_STRING_TYPE, strarray[element], buf, tag->pad, 0);
02323
02324 if (!val) {
02325 strcat(buf, "s");
02326
02327 len = strlen(strarray[element]) + tag->pad + 20;
02328 val = xmalloc(len);
02329 sprintf(val, buf, strarray[element]);
02330 }
02331
02332
02333 if (mayfree) free((void *)data);
02334
02335
02336 break;
02337
02338 case RPM_STRING_TYPE:
02339 if (tagtype)
02340 val = tagtype(RPM_STRING_ARRAY_TYPE, data, buf, tag->pad, 0);
02341
02342 if (!val) {
02343 strcat(buf, "s");
02344
02345 len = strlen(data) + tag->pad + 20;
02346 val = xmalloc(len);
02347 sprintf(val, buf, data);
02348 }
02349 break;
02350
02351 case RPM_CHAR_TYPE:
02352 case RPM_INT8_TYPE:
02353 case RPM_INT16_TYPE:
02354 case RPM_INT32_TYPE:
02355 switch (type) {
02356 case RPM_CHAR_TYPE:
02357 case RPM_INT8_TYPE: intVal = *(((int_8 *) data) + element); break;
02358 case RPM_INT16_TYPE: intVal = *(((uint_16 *) data) + element); break;
02359 default:
02360 case RPM_INT32_TYPE: intVal = *(((int_32 *) data) + element); break;
02361 }
02362
02363 if (tagtype)
02364 val = tagtype(RPM_INT32_TYPE, &intVal, buf, tag->pad, element);
02365
02366 if (!val) {
02367 strcat(buf, "d");
02368 len = 10 + tag->pad + 20;
02369 val = xmalloc(len);
02370 sprintf(val, buf, intVal);
02371 }
02372 break;
02373
02374 default:
02375 val = xstrdup(_("(unknown type)"));
02376 break;
02377 }
02378
02379 return val;
02380 }
02381
02382 static const char * singleSprintf(Header h, struct sprintfToken * token,
02383 const struct headerSprintfExtension * extensions,
02384 struct extensionCache * extCache, int element)
02385
02386 {
02387 char * val;
02388 const char * thisItem;
02389 int thisItemLen;
02390 int len, alloced;
02391 int i, j;
02392 int numElements;
02393 int type;
02394 struct sprintfToken * condFormat;
02395 int condNumFormats;
02396
02397
02398
02399 switch (token->type) {
02400 case PTOK_NONE:
02401 break;
02402
02403 case PTOK_STRING:
02404 val = xmalloc(token->u.string.len + 1);
02405 strcpy(val, token->u.string.string);
02406 break;
02407
02408 case PTOK_TAG:
02409 val = formatValue(&token->u.tag, h, extensions, extCache,
02410 token->u.tag.justOne ? 0 : element);
02411 break;
02412
02413 case PTOK_COND:
02414 if (token->u.cond.tag.ext ||
02415 headerIsEntry(h, token->u.cond.tag.tag)) {
02416 condFormat = token->u.cond.ifFormat;
02417 condNumFormats = token->u.cond.numIfTokens;
02418 } else {
02419 condFormat = token->u.cond.elseFormat;
02420 condNumFormats = token->u.cond.numElseTokens;
02421 }
02422
02423 alloced = condNumFormats * 20;
02424 val = xmalloc(alloced ? alloced : 1);
02425 *val = '\0';
02426 len = 0;
02427
02428 for (i = 0; i < condNumFormats; i++) {
02429 thisItem = singleSprintf(h, condFormat + i,
02430 extensions, extCache, element);
02431 thisItemLen = strlen(thisItem);
02432 if ((thisItemLen + len) >= alloced) {
02433 alloced = (thisItemLen + len) + 200;
02434 val = xrealloc(val, alloced);
02435 }
02436 strcat(val, thisItem);
02437 len += thisItemLen;
02438 free((void *)thisItem);
02439 }
02440
02441 break;
02442
02443 case PTOK_ARRAY:
02444 numElements = -1;
02445 for (i = 0; i < token->u.array.numTokens; i++) {
02446 if (token->u.array.format[i].type != PTOK_TAG ||
02447 token->u.array.format[i].u.tag.arrayCount ||
02448 token->u.array.format[i].u.tag.justOne) continue;
02449
02450 if (token->u.array.format[i].u.tag.ext) {
02451 const void * data;
02452 if (getExtension(h, token->u.array.format[i].u.tag.ext,
02453 &type, &data, &numElements,
02454 extCache +
02455 token->u.array.format[i].u.tag.extNum))
02456 continue;
02457 } else {
02458 if (!headerGetEntry(h, token->u.array.format[i].u.tag.tag,
02459 &type, (void **) &val, &numElements))
02460 continue;
02461 val = headerFreeData(val, type);
02462 }
02463 break;
02464 }
02465
02466 if (numElements == -1) {
02467 val = xstrdup("(none)");
02468 } else {
02469 alloced = numElements * token->u.array.numTokens * 20;
02470 val = xmalloc(alloced);
02471 *val = '\0';
02472 len = 0;
02473
02474 for (j = 0; j < numElements; j++) {
02475 for (i = 0; i < token->u.array.numTokens; i++) {
02476 thisItem = singleSprintf(h, token->u.array.format + i,
02477 extensions, extCache, j);
02478 thisItemLen = strlen(thisItem);
02479 if ((thisItemLen + len) >= alloced) {
02480 alloced = (thisItemLen + len) + 200;
02481 val = xrealloc(val, alloced);
02482 }
02483 strcat(val, thisItem);
02484 len += thisItemLen;
02485 free((void *)thisItem);
02486 }
02487 }
02488 }
02489
02490 break;
02491 }
02492
02493 return val;
02494 }
02495
02496 static struct extensionCache * allocateExtensionCache(
02497 const struct headerSprintfExtension * extensions)
02498
02499 {
02500 const struct headerSprintfExtension * ext = extensions;
02501 int i = 0;
02502
02503 while (ext->type != HEADER_EXT_LAST) {
02504 i++;
02505 if (ext->type == HEADER_EXT_MORE)
02506 ext = ext->u.more;
02507 else
02508 ext++;
02509 }
02510
02511 return xcalloc(i, sizeof(struct extensionCache));
02512 }
02513
02514 static void freeExtensionCache(const struct headerSprintfExtension * extensions,
02515 struct extensionCache * cache)
02516 {
02517 const struct headerSprintfExtension * ext = extensions;
02518 int i = 0;
02519
02520 while (ext->type != HEADER_EXT_LAST) {
02521 if (cache[i].freeit) free((void *)cache[i].data);
02522
02523 i++;
02524 if (ext->type == HEADER_EXT_MORE)
02525 ext = ext->u.more;
02526 else
02527 ext++;
02528 }
02529
02530 free(cache);
02531 }
02532
02533 char * headerSprintf(Header h, const char * origFmt,
02534 const struct headerTagTableEntry * tags,
02535 const struct headerSprintfExtension * extensions,
02536 const char ** errmsg)
02537 {
02538 char * fmtString;
02539 struct sprintfToken * format;
02540 int numTokens;
02541 char * answer;
02542 int answerLength;
02543 int answerAlloced;
02544 int i;
02545 struct extensionCache * extCache;
02546
02547
02548 fmtString = xstrdup(origFmt);
02549
02550 if (parseFormat(fmtString, tags, extensions, &format, &numTokens,
02551 NULL, PARSER_BEGIN, errmsg)) {
02552 free(fmtString);
02553 return NULL;
02554 }
02555
02556 extCache = allocateExtensionCache(extensions);
02557
02558 answerAlloced = 1024;
02559 answerLength = 0;
02560 answer = xmalloc(answerAlloced);
02561 *answer = '\0';
02562
02563 for (i = 0; i < numTokens; i++) {
02564 const char * piece;
02565 int pieceLength;
02566
02567 piece = singleSprintf(h, format + i, extensions, extCache, 0);
02568 if (piece) {
02569 pieceLength = strlen(piece);
02570 if ((answerLength + pieceLength) >= answerAlloced) {
02571 while ((answerLength + pieceLength) >= answerAlloced)
02572 answerAlloced += 1024;
02573 answer = xrealloc(answer, answerAlloced);
02574 }
02575
02576 strcat(answer, piece);
02577 answerLength += pieceLength;
02578 free((void *)piece);
02579 }
02580 }
02581
02582 free(fmtString);
02583 freeExtensionCache(extensions, extCache);
02584 free(format);
02585
02586 return answer;
02587 }
02588
02589 static char * octalFormat(int_32 type, const void * data,
02590 char * formatPrefix, int padding, int element)
02591
02592 {
02593 char * val;
02594
02595 if (type != RPM_INT32_TYPE) {
02596 val = xstrdup(_("(not a number)"));
02597 } else {
02598 val = xmalloc(20 + padding);
02599 strcat(formatPrefix, "o");
02600 sprintf(val, formatPrefix, *((int_32 *) data));
02601 }
02602
02603 return val;
02604 }
02605
02606 static char * hexFormat(int_32 type, const void * data,
02607 char * formatPrefix, int padding, int element)
02608
02609 {
02610 char * val;
02611
02612 if (type != RPM_INT32_TYPE) {
02613 val = xstrdup(_("(not a number)"));
02614 } else {
02615 val = xmalloc(20 + padding);
02616 strcat(formatPrefix, "x");
02617 sprintf(val, formatPrefix, *((int_32 *) data));
02618 }
02619
02620 return val;
02621 }
02622
02623 static char * realDateFormat(int_32 type, const void * data,
02624 char * formatPrefix, int padding, int element,
02625 char * strftimeFormat)
02626
02627 {
02628 char * val;
02629 struct tm * tstruct;
02630 char buf[50];
02631
02632 if (type != RPM_INT32_TYPE) {
02633 val = xstrdup(_("(not a number)"));
02634 } else {
02635 val = xmalloc(50 + padding);
02636 strcat(formatPrefix, "s");
02637
02638
02639 { time_t dateint = *((int_32 *) data);
02640 tstruct = localtime(&dateint);
02641 }
02642 (void)strftime(buf, sizeof(buf) - 1, strftimeFormat, tstruct);
02643 sprintf(val, formatPrefix, buf);
02644 }
02645
02646 return val;
02647 }
02648
02649 static char * dateFormat(int_32 type, const void * data,
02650 char * formatPrefix, int padding, int element)
02651
02652 {
02653 return realDateFormat(type, data, formatPrefix, padding, element, "%c");
02654 }
02655
02656 static char * dayFormat(int_32 type, const void * data,
02657 char * formatPrefix, int padding, int element)
02658
02659 {
02660 return realDateFormat(type, data, formatPrefix, padding, element,
02661 "%a %b %d %Y");
02662 }
02663
02664 static char * shescapeFormat(int_32 type, const void * data,
02665 char * formatPrefix, int padding, int element)
02666
02667 {
02668 char * result, * dst, * src, * buf;
02669
02670 if (type == RPM_INT32_TYPE) {
02671 result = xmalloc(padding + 20);
02672 strcat(formatPrefix, "d");
02673 sprintf(result, formatPrefix, *((int_32 *) data));
02674 } else {
02675 buf = alloca(strlen(data) + padding + 2);
02676 strcat(formatPrefix, "s");
02677 sprintf(buf, formatPrefix, data);
02678
02679 result = dst = xmalloc(strlen(buf) * 4 + 3);
02680 *dst++ = '\'';
02681 for (src = buf; *src; src++) {
02682 if (*src == '\'') {
02683 *dst++ = '\'';
02684 *dst++ = '\\';
02685 *dst++ = '\'';
02686 *dst++ = '\'';
02687 } else {
02688 *dst++ = *src;
02689 }
02690 }
02691 *dst++ = '\'';
02692 *dst = '\0';
02693
02694 }
02695
02696 return result;
02697 }
02698
02699 const struct headerSprintfExtension headerDefaultFormats[] = {
02700 { HEADER_EXT_FORMAT, "octal", { octalFormat } },
02701 { HEADER_EXT_FORMAT, "hex", { hexFormat } },
02702 { HEADER_EXT_FORMAT, "date", { dateFormat } },
02703 { HEADER_EXT_FORMAT, "day", { dayFormat } },
02704 { HEADER_EXT_FORMAT, "shescape", { shescapeFormat } },
02705 { HEADER_EXT_LAST, NULL, { NULL } }
02706 };
02707
02708 void headerCopyTags(Header headerFrom, Header headerTo, int *tagstocopy)
02709 {
02710 int *p;
02711
02712 if (headerFrom == headerTo)
02713 return;
02714
02715 for (p = tagstocopy; *p != 0; p++) {
02716 char *s;
02717 int type, count;
02718 if (headerIsEntry(headerTo, *p))
02719 continue;
02720 if (!headerGetEntryMinMemory(headerFrom, *p, &type,
02721 (const void **) &s, &count))
02722 continue;
02723 headerAddEntry(headerTo, *p, type, s, count);
02724 s = headerFreeData(s, type);
02725 }
02726 }