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 if (tag->ext) {
02269 if (getExtension(h, tag->ext, &type, &data, &count,
02270 extCache + tag->extNum))
02271 {
02272 count = 1;
02273 type = RPM_STRING_TYPE;
02274 data = "(none)";
02275 }
02276 } else {
02277 if (!headerGetEntry(h, tag->tag, &type, (void **)&data, &count)) {
02278 count = 1;
02279 type = RPM_STRING_TYPE;
02280 data = "(none)";
02281 }
02282
02283 mayfree = 1;
02284 }
02285
02286 if (tag->arrayCount) {
02287
02288 data = headerFreeData(data, type);
02289
02290
02291 countBuf = count;
02292 data = &countBuf;
02293 count = 1;
02294 type = RPM_INT32_TYPE;
02295 }
02296
02297 (void) stpcpy( stpcpy(buf, "%"), tag->format);
02298
02299 if (tag->type) {
02300 ext = extensions;
02301 while (ext->type != HEADER_EXT_LAST) {
02302 if (ext->name != NULL && ext->type == HEADER_EXT_FORMAT
02303 && !strcmp(ext->name, tag->type))
02304 {
02305 tagtype = ext->u.formatFunction;
02306 break;
02307 }
02308
02309 if (ext->type == HEADER_EXT_MORE)
02310 ext = ext->u.more;
02311 else
02312 ext++;
02313 }
02314 }
02315
02316 switch (type) {
02317 case RPM_STRING_ARRAY_TYPE:
02318 strarray = (const char **)data;
02319
02320 if (tagtype)
02321 val = tagtype(RPM_STRING_TYPE, strarray[element], buf, tag->pad, 0);
02322
02323 if (!val) {
02324 strcat(buf, "s");
02325
02326 len = strlen(strarray[element]) + tag->pad + 20;
02327 val = xmalloc(len);
02328 sprintf(val, buf, strarray[element]);
02329 }
02330
02331
02332 if (mayfree) data = _free(data);
02333
02334
02335 break;
02336
02337 case RPM_STRING_TYPE:
02338 if (tagtype)
02339 val = tagtype(RPM_STRING_ARRAY_TYPE, data, buf, tag->pad, 0);
02340
02341 if (!val) {
02342 strcat(buf, "s");
02343
02344 len = strlen(data) + tag->pad + 20;
02345 val = xmalloc(len);
02346 sprintf(val, buf, data);
02347 }
02348 break;
02349
02350 case RPM_CHAR_TYPE:
02351 case RPM_INT8_TYPE:
02352 case RPM_INT16_TYPE:
02353 case RPM_INT32_TYPE:
02354 switch (type) {
02355 case RPM_CHAR_TYPE:
02356 case RPM_INT8_TYPE: intVal = *(((int_8 *) data) + element); break;
02357 case RPM_INT16_TYPE: intVal = *(((uint_16 *) data) + element); break;
02358 default:
02359 case RPM_INT32_TYPE: intVal = *(((int_32 *) data) + element); break;
02360 }
02361
02362 if (tagtype)
02363 val = tagtype(RPM_INT32_TYPE, &intVal, buf, tag->pad, element);
02364
02365 if (!val) {
02366 strcat(buf, "d");
02367 len = 10 + tag->pad + 20;
02368 val = xmalloc(len);
02369 sprintf(val, buf, intVal);
02370 }
02371 break;
02372
02373 default:
02374 val = xstrdup(_("(unknown type)"));
02375 break;
02376 }
02377
02378 return val;
02379 }
02380
02383 static const char * singleSprintf(Header h, sprintfToken token,
02384 const headerSprintfExtension extensions,
02385 extensionCache extCache, int element)
02386
02387 {
02388 char * val;
02389 const char * thisItem;
02390 int thisItemLen;
02391 int len, alloced;
02392 int i, j;
02393 int numElements;
02394 int type;
02395 sprintfToken condFormat;
02396 int condNumFormats;
02397
02398
02399
02400 switch (token->type) {
02401 case PTOK_NONE:
02402 break;
02403
02404 case PTOK_STRING:
02405 val = xmalloc(token->u.string.len + 1);
02406 strcpy(val, token->u.string.string);
02407 break;
02408
02409 case PTOK_TAG:
02410 val = formatValue(&token->u.tag, h, extensions, extCache,
02411 token->u.tag.justOne ? 0 : element);
02412 break;
02413
02414 case PTOK_COND:
02415 if (token->u.cond.tag.ext ||
02416 headerIsEntry(h, token->u.cond.tag.tag)) {
02417 condFormat = token->u.cond.ifFormat;
02418 condNumFormats = token->u.cond.numIfTokens;
02419 } else {
02420 condFormat = token->u.cond.elseFormat;
02421 condNumFormats = token->u.cond.numElseTokens;
02422 }
02423
02424 alloced = condNumFormats * 20;
02425 val = xmalloc(alloced ? alloced : 1);
02426 *val = '\0';
02427 len = 0;
02428
02429 if (condFormat)
02430 for (i = 0; i < condNumFormats; i++) {
02431 thisItem = singleSprintf(h, condFormat + i,
02432 extensions, extCache, element);
02433 thisItemLen = strlen(thisItem);
02434 if ((thisItemLen + len) >= alloced) {
02435 alloced = (thisItemLen + len) + 200;
02436 val = xrealloc(val, alloced);
02437 }
02438 strcat(val, thisItem);
02439 len += thisItemLen;
02440 thisItem = _free(thisItem);
02441 }
02442
02443 break;
02444
02445 case PTOK_ARRAY:
02446 numElements = -1;
02447 for (i = 0; i < token->u.array.numTokens; i++) {
02448 if (token->u.array.format[i].type != PTOK_TAG ||
02449 token->u.array.format[i].u.tag.arrayCount ||
02450 token->u.array.format[i].u.tag.justOne) continue;
02451
02452 if (token->u.array.format[i].u.tag.ext) {
02453 const void * data;
02454 if (getExtension(h, token->u.array.format[i].u.tag.ext,
02455 &type, &data, &numElements,
02456 extCache +
02457 token->u.array.format[i].u.tag.extNum))
02458 continue;
02459 } else {
02460 if (!headerGetEntry(h, token->u.array.format[i].u.tag.tag,
02461 &type, (void **) &val, &numElements))
02462 continue;
02463 val = headerFreeData(val, type);
02464 }
02465 break;
02466 }
02467
02468 if (numElements == -1) {
02469 val = xstrdup("(none)");
02470 } else {
02471 alloced = numElements * token->u.array.numTokens * 20;
02472 val = xmalloc(alloced);
02473 *val = '\0';
02474 len = 0;
02475
02476 for (j = 0; j < numElements; j++) {
02477 for (i = 0; i < token->u.array.numTokens; i++) {
02478 thisItem = singleSprintf(h, token->u.array.format + i,
02479 extensions, extCache, j);
02480 thisItemLen = strlen(thisItem);
02481 if ((thisItemLen + len) >= alloced) {
02482 alloced = (thisItemLen + len) + 200;
02483 val = xrealloc(val, alloced);
02484 }
02485 strcat(val, thisItem);
02486 len += thisItemLen;
02487 thisItem = _free(thisItem);
02488 }
02489 }
02490 }
02491
02492 break;
02493 }
02494
02495 return val;
02496 }
02497
02500 static extensionCache
02501 allocateExtensionCache(const headerSprintfExtension extensions)
02502
02503 {
02504 headerSprintfExtension ext = extensions;
02505 int i = 0;
02506
02507 while (ext->type != HEADER_EXT_LAST) {
02508 i++;
02509 if (ext->type == HEADER_EXT_MORE)
02510 ext = ext->u.more;
02511 else
02512 ext++;
02513 }
02514
02515 return xcalloc(i, sizeof(struct extensionCache));
02516 }
02517
02521 static extensionCache
02522 freeExtensionCache(const headerSprintfExtension extensions,
02523 extensionCache cache)
02524
02525 {
02526 headerSprintfExtension ext = extensions;
02527 int i = 0;
02528
02529 while (ext->type != HEADER_EXT_LAST) {
02530 if (cache[i].freeit) cache[i].data = _free(cache[i].data);
02531
02532 i++;
02533 if (ext->type == HEADER_EXT_MORE)
02534 ext = ext->u.more;
02535 else
02536 ext++;
02537 }
02538
02539 cache = _free(cache);
02540 return NULL;
02541 }
02542
02543 char * headerSprintf(Header h, const char * fmt,
02544 const struct headerTagTableEntry_s * tabletags,
02545 const struct headerSprintfExtension_s * extensions,
02546 errmsg_t * errmsg)
02547 {
02548
02549 headerSprintfExtension exts = (headerSprintfExtension) extensions;
02550 headerTagTableEntry tags = (headerTagTableEntry) tabletags;
02551
02552 char * fmtString;
02553 sprintfToken format;
02554 int numTokens;
02555 char * answer;
02556 int answerLength;
02557 int answerAlloced;
02558 int i;
02559 extensionCache extCache;
02560
02561
02562 fmtString = xstrdup(fmt);
02563
02564 if (parseFormat(fmtString, tags, exts, &format, &numTokens,
02565 NULL, PARSER_BEGIN, errmsg)) {
02566 fmtString = _free(fmtString);
02567 return NULL;
02568 }
02569
02570 extCache = allocateExtensionCache(exts);
02571
02572 answerAlloced = 1024;
02573 answerLength = 0;
02574 answer = xmalloc(answerAlloced);
02575 *answer = '\0';
02576
02577 for (i = 0; i < numTokens; i++) {
02578 const char * piece;
02579 int pieceLength;
02580
02581
02582 piece = singleSprintf(h, format + i, exts, extCache, 0);
02583
02584 if (piece) {
02585 pieceLength = strlen(piece);
02586 if ((answerLength + pieceLength) >= answerAlloced) {
02587 while ((answerLength + pieceLength) >= answerAlloced)
02588 answerAlloced += 1024;
02589 answer = xrealloc(answer, answerAlloced);
02590 }
02591
02592 strcat(answer, piece);
02593 answerLength += pieceLength;
02594 piece = _free(piece);
02595 }
02596 }
02597
02598 fmtString = _free(fmtString);
02599 extCache = freeExtensionCache(exts, extCache);
02600 format = _free(format);
02601
02602 return answer;
02603 }
02604
02607 static char * octalFormat(int_32 type, hPTR_t data,
02608 char * formatPrefix, int padding, int element)
02609
02610 {
02611 char * val;
02612
02613 if (type != RPM_INT32_TYPE) {
02614 val = xstrdup(_("(not a number)"));
02615 } else {
02616 val = xmalloc(20 + padding);
02617 strcat(formatPrefix, "o");
02618 sprintf(val, formatPrefix, *((int_32 *) data));
02619 }
02620
02621 return val;
02622 }
02623
02626 static char * hexFormat(int_32 type, hPTR_t data,
02627 char * formatPrefix, int padding, int element)
02628
02629 {
02630 char * val;
02631
02632 if (type != RPM_INT32_TYPE) {
02633 val = xstrdup(_("(not a number)"));
02634 } else {
02635 val = xmalloc(20 + padding);
02636 strcat(formatPrefix, "x");
02637 sprintf(val, formatPrefix, *((int_32 *) data));
02638 }
02639
02640 return val;
02641 }
02642
02645 static char * realDateFormat(int_32 type, hPTR_t data,
02646 char * formatPrefix, int padding, int element,
02647 const char * strftimeFormat)
02648
02649 {
02650 char * val;
02651
02652 if (type != RPM_INT32_TYPE) {
02653 val = xstrdup(_("(not a number)"));
02654 } else {
02655 struct tm * tstruct;
02656 char buf[50];
02657
02658 val = xmalloc(50 + padding);
02659 strcat(formatPrefix, "s");
02660
02661
02662 { time_t dateint = *((int_32 *) data);
02663 tstruct = localtime(&dateint);
02664 }
02665 buf[0] = '\0';
02666 if (tstruct)
02667 (void) strftime(buf, sizeof(buf) - 1, strftimeFormat, tstruct);
02668 sprintf(val, formatPrefix, buf);
02669 }
02670
02671 return val;
02672 }
02673
02676 static char * dateFormat(int_32 type, hPTR_t data,
02677 char * formatPrefix, int padding, int element)
02678
02679 {
02680 return realDateFormat(type, data, formatPrefix, padding, element, "%c");
02681 }
02682
02685 static char * dayFormat(int_32 type, hPTR_t data,
02686 char * formatPrefix, int padding, int element)
02687
02688 {
02689 return realDateFormat(type, data, formatPrefix, padding, element,
02690 "%a %b %d %Y");
02691 }
02692
02695 static char * shescapeFormat(int_32 type, hPTR_t data,
02696 char * formatPrefix, int padding, int element)
02697
02698 {
02699 char * result, * dst, * src, * buf;
02700
02701 if (type == RPM_INT32_TYPE) {
02702 result = xmalloc(padding + 20);
02703 strcat(formatPrefix, "d");
02704 sprintf(result, formatPrefix, *((int_32 *) data));
02705 } else {
02706 buf = alloca(strlen(data) + padding + 2);
02707 strcat(formatPrefix, "s");
02708 sprintf(buf, formatPrefix, data);
02709
02710 result = dst = xmalloc(strlen(buf) * 4 + 3);
02711 *dst++ = '\'';
02712 for (src = buf; *src != '\0'; src++) {
02713 if (*src == '\'') {
02714 *dst++ = '\'';
02715 *dst++ = '\\';
02716 *dst++ = '\'';
02717 *dst++ = '\'';
02718 } else {
02719 *dst++ = *src;
02720 }
02721 }
02722 *dst++ = '\'';
02723 *dst = '\0';
02724
02725 }
02726
02727 return result;
02728 }
02729
02730 const struct headerSprintfExtension_s headerDefaultFormats[] = {
02731 { HEADER_EXT_FORMAT, "octal", { octalFormat } },
02732 { HEADER_EXT_FORMAT, "hex", { hexFormat } },
02733 { HEADER_EXT_FORMAT, "date", { dateFormat } },
02734 { HEADER_EXT_FORMAT, "day", { dayFormat } },
02735 { HEADER_EXT_FORMAT, "shescape", { shescapeFormat } },
02736 { HEADER_EXT_LAST, NULL, { NULL } }
02737 };
02738
02739 void headerCopyTags(Header headerFrom, Header headerTo, hTAG_t tagstocopy)
02740 {
02741 int * p;
02742
02743 if (headerFrom == headerTo)
02744 return;
02745
02746 for (p = tagstocopy; *p != 0; p++) {
02747 char *s;
02748 int_32 type;
02749 int_32 count;
02750 if (headerIsEntry(headerTo, *p))
02751 continue;
02752 if (!headerGetEntryMinMemory(headerFrom, *p, &type,
02753 (hPTR_t *) &s, &count))
02754 continue;
02755 (void) headerAddEntry(headerTo, *p, type, s, count);
02756 s = headerFreeData(s, type);
02757 }
02758 }
02759
02763 struct headerIteratorS {
02764 Header h;
02765 int next_index;
02766 };
02767
02768 HeaderIterator headerFreeIterator(HeaderIterator hi)
02769 {
02770 hi->h = headerFree(hi->h);
02771 hi = _free(hi);
02772 return hi;
02773 }
02774
02775 HeaderIterator headerInitIterator(Header h)
02776 {
02777 HeaderIterator hi = xmalloc(sizeof(struct headerIteratorS));
02778
02779 headerSort(h);
02780
02781 hi->h = headerLink(h);
02782 hi->next_index = 0;
02783 return hi;
02784 }
02785
02786 int headerNextIterator(HeaderIterator hi,
02787 hTAG_t tag, hTYP_t type, hPTR_t * p, hCNT_t c)
02788 {
02789 Header h = hi->h;
02790 int slot = hi->next_index;
02791 indexEntry entry = NULL;
02792 int rc;
02793
02794 for (slot = hi->next_index; slot < h->indexUsed; slot++) {
02795 entry = h->index + slot;
02796 if (!ENTRY_IS_REGION(entry))
02797 break;
02798 }
02799 hi->next_index = slot;
02800 if (entry == NULL || slot >= h->indexUsed)
02801 return 0;
02802
02803 hi->next_index++;
02804
02805
02806 if (tag)
02807 *tag = entry->info.tag;
02808
02809 rc = copyEntry(entry, type, p, c, 0);
02810
02811
02812 return ((rc == 1) ? 1 : 0);
02813 }
02814 static struct HV_s hdrVec1 = {
02815 headerNew,
02816 headerFree,
02817 headerLink,
02818 headerSort,
02819 headerUnsort,
02820 headerSizeof,
02821 headerUnload,
02822 headerReload,
02823 headerCopy,
02824 headerLoad,
02825 headerCopyLoad,
02826 headerRead,
02827 headerWrite,
02828 headerIsEntry,
02829 headerFreeTag,
02830 headerGetEntry,
02831 headerGetEntryMinMemory,
02832 headerAddEntry,
02833 headerAppendEntry,
02834 headerAddOrAppendEntry,
02835 headerAddI18NString,
02836 headerModifyEntry,
02837 headerRemoveEntry,
02838 headerSprintf,
02839 headerCopyTags,
02840 headerFreeIterator,
02841 headerInitIterator,
02842 headerNextIterator,
02843 NULL, NULL,
02844 1
02845 };
02846
02847
02848 HV_t hdrVec = &hdrVec1;
02849