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