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