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
00038 static unsigned char header_magic[8] = {
00039 0x8e, 0xad, 0xe8, 0x01, 0x00, 0x00, 0x00, 0x00
00040 };
00041
00045
00046 static size_t headerMaxbytes = (32*1024*1024);
00047
00052 #define hdrchkTags(_ntags) ((_ntags) & 0xffff0000)
00053
00058 #define hdrchkData(_nbytes) ((_nbytes) & 0xff000000)
00059
00063
00064 static int typeSizes[] = {
00065 0,
00066 1,
00067 1,
00068 2,
00069 4,
00070 -1,
00071 -1,
00072 1,
00073 -1,
00074 -1
00075 };
00076
00077
00078 HV_t hdrVec;
00079
00085 static inline void *
00086 _free( const void * p)
00087 {
00088 if (p != NULL) free((void *)p);
00089 return NULL;
00090 }
00091
00097 static
00098 Header headerLink(Header h)
00099
00100 {
00101 if (h != NULL) h->nrefs++;
00102
00103 return h;
00104
00105 }
00106
00112 static
00113 Header headerUnlink( Header h)
00114
00115 {
00116 if (h != NULL) h->nrefs--;
00117 return NULL;
00118 }
00119
00125 static
00126 Header headerFree( Header h)
00127
00128 {
00129 (void) headerUnlink(h);
00130
00131
00132 if (h == NULL || h->nrefs > 0)
00133 return NULL;
00134
00135 if (h->index) {
00136 indexEntry entry = h->index;
00137 int i;
00138 for (i = 0; i < h->indexUsed; i++, entry++) {
00139 if ((h->flags & HEADERFLAG_ALLOCATED) && ENTRY_IS_REGION(entry)) {
00140 if (entry->length > 0) {
00141 int_32 * ei = entry->data;
00142 if ((ei - 2) == h->blob) h->blob = _free(h->blob);
00143 entry->data = NULL;
00144 }
00145 } else if (!ENTRY_IN_REGION(entry)) {
00146 entry->data = _free(entry->data);
00147 }
00148 entry->data = NULL;
00149 }
00150 h->index = _free(h->index);
00151 }
00152
00153 h = _free(h);
00154 return h;
00155
00156 }
00157
00162 static
00163 Header headerNew(void)
00164
00165 {
00166 Header h = xcalloc(1, sizeof(*h));
00167
00168
00169 h->hv = *hdrVec;
00170
00171 h->blob = NULL;
00172 h->indexAlloced = INDEX_MALLOC_SIZE;
00173 h->indexUsed = 0;
00174 h->flags = HEADERFLAG_SORTED;
00175
00176 h->index = (h->indexAlloced
00177 ? xcalloc(h->indexAlloced, sizeof(*h->index))
00178 : NULL);
00179
00180
00181 h->nrefs = 0;
00182 return headerLink(h);
00183
00184 }
00185
00188 static int indexCmp(const void * avp, const void * bvp)
00189 {
00190
00191 indexEntry ap = (indexEntry) avp, bp = (indexEntry) bvp;
00192
00193 return (ap->info.tag - bp->info.tag);
00194 }
00195
00200 static
00201 void headerSort(Header h)
00202
00203 {
00204 if (!(h->flags & HEADERFLAG_SORTED)) {
00205 qsort(h->index, h->indexUsed, sizeof(*h->index), indexCmp);
00206 h->flags |= HEADERFLAG_SORTED;
00207 }
00208 }
00209
00212 static int offsetCmp(const void * avp, const void * bvp)
00213 {
00214
00215 indexEntry ap = (indexEntry) avp, bp = (indexEntry) bvp;
00216
00217 int rc = (ap->info.offset - bp->info.offset);
00218
00219 if (rc == 0) {
00220
00221 if (ap->info.offset < 0)
00222 rc = (((char *)ap->data) - ((char *)bp->data));
00223 else
00224 rc = (ap->info.tag - bp->info.tag);
00225 }
00226 return rc;
00227 }
00228
00233 static
00234 void headerUnsort(Header h)
00235
00236 {
00237 qsort(h->index, h->indexUsed, sizeof(*h->index), offsetCmp);
00238 }
00239
00246 static
00247 unsigned int headerSizeof( Header h, enum hMagic magicp)
00248
00249 {
00250 indexEntry entry;
00251 unsigned int size = 0;
00252 unsigned int pad = 0;
00253 int i;
00254
00255 if (h == NULL)
00256 return size;
00257
00258 headerSort(h);
00259
00260 switch (magicp) {
00261 case HEADER_MAGIC_YES:
00262 size += sizeof(header_magic);
00263 break;
00264 case HEADER_MAGIC_NO:
00265 break;
00266 }
00267
00268
00269 size += 2 * sizeof(int_32);
00270
00271
00272 for (i = 0, entry = h->index; i < h->indexUsed; i++, entry++) {
00273 unsigned diff;
00274 int_32 type;
00275
00276
00277 if (ENTRY_IS_REGION(entry)) {
00278 size += entry->length;
00279
00280
00281 if (i == 0 && (h->flags & HEADERFLAG_LEGACY))
00282 size += sizeof(struct entryInfo) + entry->info.count;
00283
00284 continue;
00285 }
00286
00287
00288 if (entry->info.offset < 0)
00289 continue;
00290
00291
00292 type = entry->info.type;
00293 if (typeSizes[type] > 1) {
00294 diff = typeSizes[type] - (size % typeSizes[type]);
00295 if (diff != typeSizes[type]) {
00296 size += diff;
00297 pad += diff;
00298 }
00299 }
00300
00301
00302 size += sizeof(struct entryInfo) + entry->length;
00303
00304 }
00305
00306 return size;
00307 }
00308
00318
00319 static int dataLength(int_32 type, hPTR_t p, int_32 count, int onDisk)
00320
00321 {
00322 int length = 0;
00323
00324 switch (type) {
00325 case RPM_STRING_TYPE:
00326 if (count == 1) {
00327 length = strlen(p) + 1;
00328 break;
00329 }
00330
00331
00332 fprintf(stderr, _("dataLength() RPM_STRING_TYPE count must be 1.\n"));
00333
00334 exit(EXIT_FAILURE);
00335 break;
00336
00337 case RPM_STRING_ARRAY_TYPE:
00338 case RPM_I18NSTRING_TYPE:
00339 { int i;
00340
00341
00342
00343 i = count;
00344
00345 if (onDisk) {
00346 const char * chptr = p;
00347 int thisLen;
00348
00349 while (i--) {
00350 thisLen = strlen(chptr) + 1;
00351 length += thisLen;
00352 chptr += thisLen;
00353 }
00354 } else {
00355 const char ** src = (const char **)p;
00356 while (i--) {
00357
00358 length += strlen(*src++) + 1;
00359 }
00360 }
00361 } break;
00362
00363 default:
00364 if (typeSizes[type] != -1) {
00365 length = typeSizes[type] * count;
00366 break;
00367 }
00368
00369 fprintf(stderr, _("Data type %d not supported\n"), (int) type);
00370
00371 exit(EXIT_FAILURE);
00372 break;
00373 }
00374
00375 return length;
00376 }
00377
00403 static int regionSwab( indexEntry entry, int il, int dl,
00404 entryInfo pe, char * dataStart, int regionid)
00405
00406 {
00407 char * tprev = NULL;
00408 char * t = NULL;
00409 int tdel, tl = dl;
00410 struct indexEntry ieprev;
00411
00412 memset(&ieprev, 0, sizeof(ieprev));
00413 for (; il > 0; il--, pe++) {
00414 struct indexEntry ie;
00415 int_32 type;
00416
00417 ie.info.tag = ntohl(pe->tag);
00418 ie.info.type = ntohl(pe->type);
00419 if (ie.info.type < RPM_MIN_TYPE || ie.info.type > RPM_MAX_TYPE)
00420 return -1;
00421 ie.info.count = ntohl(pe->count);
00422 ie.info.offset = ntohl(pe->offset);
00423 ie.data = t = dataStart + ie.info.offset;
00424 ie.length = dataLength(ie.info.type, ie.data, ie.info.count, 1);
00425 ie.rdlen = 0;
00426
00427 if (entry) {
00428 ie.info.offset = regionid;
00429 *entry = ie;
00430 entry++;
00431 }
00432
00433
00434 type = ie.info.type;
00435 if (typeSizes[type] > 1) {
00436 unsigned diff;
00437 diff = typeSizes[type] - (dl % typeSizes[type]);
00438 if (diff != typeSizes[type]) {
00439 dl += diff;
00440 if (ieprev.info.type == RPM_I18NSTRING_TYPE)
00441 ieprev.length += diff;
00442 }
00443 }
00444 tdel = (tprev ? (t - tprev) : 0);
00445 if (ieprev.info.type == RPM_I18NSTRING_TYPE)
00446 tdel = ieprev.length;
00447
00448 if (ie.info.tag >= HEADER_I18NTABLE) {
00449 tprev = t;
00450 } else {
00451 tprev = dataStart;
00452
00453
00454 if (ie.info.tag == HEADER_IMAGE)
00455 tprev -= REGION_TAG_COUNT;
00456
00457 }
00458
00459
00460 switch (ntohl(pe->type)) {
00461 case RPM_INT32_TYPE:
00462 { int_32 * it = (int_32 *)t;
00463 for (; ie.info.count > 0; ie.info.count--, it += 1)
00464 *it = htonl(*it);
00465 t = (char *) it;
00466 } break;
00467 case RPM_INT16_TYPE:
00468 { int_16 * it = (int_16 *) t;
00469 for (; ie.info.count > 0; ie.info.count--, it += 1)
00470 *it = htons(*it);
00471 t = (char *) it;
00472 } break;
00473 default:
00474 t += ie.length;
00475 break;
00476 }
00477
00478 dl += ie.length;
00479 tl += tdel;
00480 ieprev = ie;
00481
00482 }
00483 tdel = (tprev ? (t - tprev) : 0);
00484 tl += tdel;
00485
00486
00487
00488
00489
00490
00491
00492 if (tl+REGION_TAG_COUNT == dl)
00493 tl += REGION_TAG_COUNT;
00494
00495
00496 return dl;
00497 }
00498
00501 static void * doHeaderUnload(Header h,
00502 int * lengthPtr)
00503
00504 {
00505 int_32 * ei = NULL;
00506 entryInfo pe;
00507 char * dataStart;
00508 char * te;
00509 unsigned pad;
00510 unsigned len;
00511 int_32 il = 0;
00512 int_32 dl = 0;
00513 indexEntry entry;
00514 int_32 type;
00515 int i;
00516 int drlen, ndribbles;
00517 int driplen, ndrips;
00518 int legacy = 0;
00519
00520
00521 headerUnsort(h);
00522
00523
00524 pad = 0;
00525 drlen = ndribbles = driplen = ndrips = 0;
00526 for (i = 0, entry = h->index; i < h->indexUsed; i++, entry++) {
00527 if (ENTRY_IS_REGION(entry)) {
00528 int_32 rdl = -entry->info.offset;
00529 int_32 ril = rdl/sizeof(*pe);
00530 int rid = entry->info.offset;
00531
00532 il += ril;
00533 dl += entry->rdlen + entry->info.count;
00534
00535 if (i == 0 && (h->flags & HEADERFLAG_LEGACY))
00536 il += 1;
00537
00538
00539 for (; i < h->indexUsed && entry->info.offset <= rid+1; i++, entry++) {
00540 if (entry->info.offset <= rid)
00541 continue;
00542
00543
00544 type = entry->info.type;
00545 if (typeSizes[type] > 1) {
00546 unsigned diff;
00547 diff = typeSizes[type] - (dl % typeSizes[type]);
00548 if (diff != typeSizes[type]) {
00549 drlen += diff;
00550 pad += diff;
00551 dl += diff;
00552 }
00553 }
00554
00555 ndribbles++;
00556 il++;
00557 drlen += entry->length;
00558 dl += entry->length;
00559 }
00560 i--;
00561 entry--;
00562 continue;
00563 }
00564
00565
00566 if (entry->data == NULL || entry->length <= 0)
00567 continue;
00568
00569
00570 type = entry->info.type;
00571 if (typeSizes[type] > 1) {
00572 unsigned diff;
00573 diff = typeSizes[type] - (dl % typeSizes[type]);
00574 if (diff != typeSizes[type]) {
00575 driplen += diff;
00576 pad += diff;
00577 dl += diff;
00578 } else
00579 diff = 0;
00580 }
00581
00582 ndrips++;
00583 il++;
00584 driplen += entry->length;
00585 dl += entry->length;
00586 }
00587
00588
00589 if (hdrchkTags(il) || hdrchkData(dl))
00590 goto errxit;
00591
00592 len = sizeof(il) + sizeof(dl) + (il * sizeof(*pe)) + dl;
00593
00594 ei = xmalloc(len);
00595 ei[0] = htonl(il);
00596 ei[1] = htonl(dl);
00597
00598 pe = (entryInfo) &ei[2];
00599 dataStart = te = (char *) (pe + il);
00600
00601 pad = 0;
00602 for (i = 0, entry = h->index; i < h->indexUsed; i++, entry++) {
00603 const char * src;
00604 char *t;
00605 int count;
00606 int rdlen;
00607
00608 if (entry->data == NULL || entry->length <= 0)
00609 continue;
00610
00611 t = te;
00612 pe->tag = htonl(entry->info.tag);
00613 pe->type = htonl(entry->info.type);
00614 pe->count = htonl(entry->info.count);
00615
00616 if (ENTRY_IS_REGION(entry)) {
00617 int_32 rdl = -entry->info.offset;
00618 int_32 ril = rdl/sizeof(*pe) + ndribbles;
00619 int rid = entry->info.offset;
00620
00621 src = (char *)entry->data;
00622 rdlen = entry->rdlen;
00623
00624
00625 if (i == 0 && (h->flags & HEADERFLAG_LEGACY)) {
00626 int_32 stei[4];
00627
00628 legacy = 1;
00629 memcpy(pe+1, src, rdl);
00630 memcpy(te, src + rdl, rdlen);
00631 te += rdlen;
00632
00633 pe->offset = htonl(te - dataStart);
00634 stei[0] = pe->tag;
00635 stei[1] = pe->type;
00636 stei[2] = htonl(-rdl-entry->info.count);
00637 stei[3] = pe->count;
00638 memcpy(te, stei, entry->info.count);
00639 te += entry->info.count;
00640 ril++;
00641 rdlen += entry->info.count;
00642
00643 count = regionSwab(NULL, ril, 0, pe, t, 0);
00644 if (count != rdlen)
00645 goto errxit;
00646
00647 } else {
00648
00649 memcpy(pe+1, src + sizeof(*pe), ((ril-1) * sizeof(*pe)));
00650 memcpy(te, src + (ril * sizeof(*pe)), rdlen+entry->info.count+drlen);
00651 te += rdlen;
00652 {
00653 entryInfo se = (entryInfo)src;
00654
00655 int off = ntohl(se->offset);
00656 pe->offset = (off) ? htonl(te - dataStart) : htonl(off);
00657 }
00658 te += entry->info.count + drlen;
00659
00660 count = regionSwab(NULL, ril, 0, pe, t, 0);
00661 if (count != (rdlen + entry->info.count + drlen))
00662 goto errxit;
00663 }
00664
00665
00666 while (i < h->indexUsed && entry->info.offset <= rid+1) {
00667 i++;
00668 entry++;
00669 }
00670 i--;
00671 entry--;
00672 pe += ril;
00673 continue;
00674 }
00675
00676
00677 if (entry->data == NULL || entry->length <= 0)
00678 continue;
00679
00680
00681 type = entry->info.type;
00682 if (typeSizes[type] > 1) {
00683 unsigned diff;
00684 diff = typeSizes[type] - ((te - dataStart) % typeSizes[type]);
00685 if (diff != typeSizes[type]) {
00686 memset(te, 0, diff);
00687 te += diff;
00688 pad += diff;
00689 }
00690 }
00691
00692 pe->offset = htonl(te - dataStart);
00693
00694
00695 switch (entry->info.type) {
00696 case RPM_INT32_TYPE:
00697 count = entry->info.count;
00698 src = entry->data;
00699 while (count--) {
00700 *((int_32 *)te) = htonl(*((int_32 *)src));
00701
00702 te += sizeof(int_32);
00703 src += sizeof(int_32);
00704
00705 }
00706 break;
00707
00708 case RPM_INT16_TYPE:
00709 count = entry->info.count;
00710 src = entry->data;
00711 while (count--) {
00712 *((int_16 *)te) = htons(*((int_16 *)src));
00713
00714 te += sizeof(int_16);
00715 src += sizeof(int_16);
00716
00717 }
00718 break;
00719
00720 default:
00721 memcpy(te, entry->data, entry->length);
00722 te += entry->length;
00723 break;
00724 }
00725 pe++;
00726 }
00727
00728
00729 if (((char *)pe) != dataStart)
00730 goto errxit;
00731 if ((((char *)ei)+len) != te)
00732 goto errxit;
00733
00734 if (lengthPtr)
00735 *lengthPtr = len;
00736
00737 h->flags &= ~HEADERFLAG_SORTED;
00738 headerSort(h);
00739
00740 return (void *) ei;
00741
00742 errxit:
00743
00744 ei = _free(ei);
00745
00746 return (void *) ei;
00747 }
00748
00754 static
00755 void * headerUnload(Header h)
00756
00757 {
00758 int length;
00759 void * uh = doHeaderUnload(h, &length);
00760 return uh;
00761 }
00762
00770 static
00771 indexEntry findEntry( Header h, int_32 tag, int_32 type)
00772
00773 {
00774 indexEntry entry, entry2, last;
00775 struct indexEntry key;
00776
00777 if (h == NULL) return NULL;
00778 if (!(h->flags & HEADERFLAG_SORTED)) headerSort(h);
00779
00780 key.info.tag = tag;
00781
00782 entry2 = entry =
00783 bsearch(&key, h->index, h->indexUsed, sizeof(*h->index), indexCmp);
00784 if (entry == NULL)
00785 return NULL;
00786
00787 if (type == RPM_NULL_TYPE)
00788 return entry;
00789
00790
00791 while (entry->info.tag == tag && entry->info.type != type &&
00792 entry > h->index) entry--;
00793
00794 if (entry->info.tag == tag && entry->info.type == type)
00795 return entry;
00796
00797 last = h->index + h->indexUsed;
00798
00799 while (entry2->info.tag == tag && entry2->info.type != type &&
00800 entry2 < last) entry2++;
00801
00802
00803 if (entry->info.tag == tag && entry->info.type == type)
00804 return entry;
00805
00806 return NULL;
00807 }
00808
00818 static
00819 int headerRemoveEntry(Header h, int_32 tag)
00820
00821 {
00822 indexEntry last = h->index + h->indexUsed;
00823 indexEntry entry, first;
00824 int ne;
00825
00826 entry = findEntry(h, tag, RPM_NULL_TYPE);
00827 if (!entry) return 1;
00828
00829
00830 while (entry > h->index && (entry - 1)->info.tag == tag)
00831 entry--;
00832
00833
00834 for (first = entry; first < last; first++) {
00835 void * data;
00836 if (first->info.tag != tag)
00837 break;
00838 data = first->data;
00839 first->data = NULL;
00840 first->length = 0;
00841 if (ENTRY_IN_REGION(first))
00842 continue;
00843 data = _free(data);
00844 }
00845
00846 ne = (first - entry);
00847 if (ne > 0) {
00848 h->indexUsed -= ne;
00849 ne = last - first;
00850 if (ne > 0)
00851 memmove(entry, first, (ne * sizeof(*entry)));
00852 }
00853
00854 return 0;
00855 }
00856
00862 static
00863 Header headerLoad( void * uh)
00864
00865 {
00866 int_32 * ei = (int_32 *) uh;
00867 int_32 il = ntohl(ei[0]);
00868 int_32 dl = ntohl(ei[1]);
00869
00870 size_t pvlen = sizeof(il) + sizeof(dl) +
00871 (il * sizeof(struct entryInfo)) + dl;
00872
00873 void * pv = uh;
00874 Header h = NULL;
00875 entryInfo pe;
00876 char * dataStart;
00877 indexEntry entry;
00878 int rdlen;
00879 int i;
00880
00881
00882 if (hdrchkTags(il) || hdrchkData(dl))
00883 goto errxit;
00884
00885 ei = (int_32 *) pv;
00886
00887 pe = (entryInfo) &ei[2];
00888
00889 dataStart = (char *) (pe + il);
00890
00891 h = xcalloc(1, sizeof(*h));
00892
00893 h->hv = *hdrVec;
00894
00895
00896 h->blob = uh;
00897
00898 h->indexAlloced = il + 1;
00899 h->indexUsed = il;
00900 h->index = xcalloc(h->indexAlloced, sizeof(*h->index));
00901 h->flags = HEADERFLAG_SORTED;
00902 h->nrefs = 0;
00903 h = headerLink(h);
00904
00905
00906
00907
00908
00909 if (ntohl(pe->tag) == 15 &&
00910 ntohl(pe->type) == RPM_STRING_TYPE &&
00911 ntohl(pe->count) == 1)
00912 {
00913 pe->tag = htonl(1079);
00914 }
00915
00916 entry = h->index;
00917 i = 0;
00918 if (!(htonl(pe->tag) < HEADER_I18NTABLE)) {
00919 h->flags |= HEADERFLAG_LEGACY;
00920 entry->info.type = REGION_TAG_TYPE;
00921 entry->info.tag = HEADER_IMAGE;
00922
00923 entry->info.count = REGION_TAG_COUNT;
00924
00925 entry->info.offset = ((char *)pe - dataStart);
00926
00927
00928 entry->data = pe;
00929
00930 entry->length = pvlen - sizeof(il) - sizeof(dl);
00931 rdlen = regionSwab(entry+1, il, 0, pe, dataStart, entry->info.offset);
00932 #if 0
00933 if (rdlen != dl)
00934 goto errxit;
00935 #endif
00936 entry->rdlen = rdlen;
00937 entry++;
00938 h->indexUsed++;
00939 } else {
00940 int nb = ntohl(pe->count);
00941 int_32 rdl;
00942 int_32 ril;
00943
00944 h->flags &= ~HEADERFLAG_LEGACY;
00945
00946 entry->info.type = htonl(pe->type);
00947 if (entry->info.type < RPM_MIN_TYPE || entry->info.type > RPM_MAX_TYPE)
00948 goto errxit;
00949 entry->info.count = htonl(pe->count);
00950
00951 if (hdrchkTags(entry->info.count))
00952 goto errxit;
00953
00954 { int off = ntohl(pe->offset);
00955
00956 if (hdrchkData(off))
00957 goto errxit;
00958 if (off) {
00959 int_32 * stei = memcpy(alloca(nb), dataStart + off, nb);
00960 rdl = -ntohl(stei[2]);
00961 ril = rdl/sizeof(*pe);
00962 if (hdrchkTags(ril) || hdrchkData(rdl))
00963 goto errxit;
00964 entry->info.tag = htonl(pe->tag);
00965 } else {
00966 ril = il;
00967
00968 rdl = (ril * sizeof(struct entryInfo));
00969
00970 entry->info.tag = HEADER_IMAGE;
00971 }
00972 }
00973 entry->info.offset = -rdl;
00974
00975
00976 entry->data = pe;
00977
00978 entry->length = pvlen - sizeof(il) - sizeof(dl);
00979 rdlen = regionSwab(entry+1, ril-1, 0, pe+1, dataStart, entry->info.offset);
00980 if (rdlen < 0)
00981 goto errxit;
00982 entry->rdlen = rdlen;
00983
00984 if (ril < h->indexUsed) {
00985 indexEntry newEntry = entry + ril;
00986 int ne = (h->indexUsed - ril);
00987 int rid = entry->info.offset+1;
00988 int rc;
00989
00990
00991 rc = regionSwab(newEntry, ne, 0, pe+ril, dataStart, rid);
00992 if (rc < 0)
00993 goto errxit;
00994 rdlen += rc;
00995
00996 { indexEntry firstEntry = newEntry;
00997 int save = h->indexUsed;
00998 int j;
00999
01000
01001 h->indexUsed -= ne;
01002 for (j = 0; j < ne; j++, newEntry++) {
01003 (void) headerRemoveEntry(h, newEntry->info.tag);
01004 if (newEntry->info.tag == HEADER_BASENAMES)
01005 (void) headerRemoveEntry(h, HEADER_OLDFILENAMES);
01006 }
01007
01008
01009 if (h->indexUsed < (save - ne)) {
01010 memmove(h->index + h->indexUsed, firstEntry,
01011 (ne * sizeof(*entry)));
01012 }
01013 h->indexUsed += ne;
01014 }
01015 }
01016 }
01017
01018 h->flags &= ~HEADERFLAG_SORTED;
01019 headerSort(h);
01020
01021
01022 return h;
01023
01024
01025 errxit:
01026
01027 if (h) {
01028 h->index = _free(h->index);
01029
01030 h = _free(h);
01031
01032 }
01033
01034
01035 return h;
01036
01037 }
01038
01046 static
01047 Header headerReload( Header h, int tag)
01048
01049 {
01050 Header nh;
01051 int length;
01052
01053 void * uh = doHeaderUnload(h, &length);
01054
01055 h = headerFree(h);
01056
01057 if (uh == NULL)
01058 return NULL;
01059 nh = headerLoad(uh);
01060 if (nh == NULL) {
01061 uh = _free(uh);
01062 return NULL;
01063 }
01064 if (nh->flags & HEADERFLAG_ALLOCATED)
01065 uh = _free(uh);
01066 nh->flags |= HEADERFLAG_ALLOCATED;
01067 if (ENTRY_IS_REGION(nh->index)) {
01068 if (tag == HEADER_SIGNATURES || tag == HEADER_IMMUTABLE)
01069 nh->index[0].info.tag = tag;
01070 }
01071 return nh;
01072 }
01073
01079 static
01080 Header headerCopyLoad(const void * uh)
01081
01082 {
01083 int_32 * ei = (int_32 *) uh;
01084 int_32 il = ntohl(ei[0]);
01085 int_32 dl = ntohl(ei[1]);
01086
01087 size_t pvlen = sizeof(il) + sizeof(dl) +
01088 (il * sizeof(struct entryInfo)) + dl;
01089
01090 void * nuh = NULL;
01091 Header h = NULL;
01092
01093
01094
01095 if (!(hdrchkTags(il) || hdrchkData(dl)) && pvlen < headerMaxbytes) {
01096 nuh = memcpy(xmalloc(pvlen), uh, pvlen);
01097 if ((h = headerLoad(nuh)) != NULL)
01098 h->flags |= HEADERFLAG_ALLOCATED;
01099 }
01100
01101
01102 if (h == NULL)
01103 nuh = _free(nuh);
01104
01105 return h;
01106 }
01107
01114 static
01115 Header headerRead(FD_t fd, enum hMagic magicp)
01116
01117 {
01118 int_32 block[4];
01119 int_32 reserved;
01120 int_32 * ei = NULL;
01121 int_32 il;
01122 int_32 dl;
01123 int_32 magic;
01124 Header h = NULL;
01125 size_t len;
01126 int i;
01127
01128 memset(block, 0, sizeof(block));
01129 i = 2;
01130 if (magicp == HEADER_MAGIC_YES)
01131 i += 2;
01132
01133
01134 if (timedRead(fd, (char *)block, i*sizeof(*block)) != (i * sizeof(*block)))
01135 goto exit;
01136
01137
01138 i = 0;
01139
01140 if (magicp == HEADER_MAGIC_YES) {
01141 magic = block[i++];
01142 if (memcmp(&magic, header_magic, sizeof(magic)))
01143 goto exit;
01144 reserved = block[i++];
01145 }
01146
01147 il = ntohl(block[i]); i++;
01148 dl = ntohl(block[i]); i++;
01149
01150
01151 len = sizeof(il) + sizeof(dl) + (il * sizeof(struct entryInfo)) + dl;
01152
01153
01154
01155 if (hdrchkTags(il) || hdrchkData(dl) || len > headerMaxbytes)
01156 goto exit;
01157
01158 ei = xmalloc(len);
01159 ei[0] = htonl(il);
01160 ei[1] = htonl(dl);
01161 len -= sizeof(il) + sizeof(dl);
01162
01163
01164 if (timedRead(fd, (char *)&ei[2], len) != len)
01165 goto exit;
01166
01167
01168 h = headerLoad(ei);
01169
01170 exit:
01171 if (h) {
01172 if (h->flags & HEADERFLAG_ALLOCATED)
01173 ei = _free(ei);
01174 h->flags |= HEADERFLAG_ALLOCATED;
01175 } else if (ei)
01176 ei = _free(ei);
01177
01178 return h;
01179
01180 }
01181
01189 static
01190 int headerWrite(FD_t fd, Header h, enum hMagic magicp)
01191
01192
01193 {
01194 ssize_t nb;
01195 int length;
01196 const void * uh;
01197
01198 if (h == NULL)
01199 return 1;
01200 uh = doHeaderUnload(h, &length);
01201 if (uh == NULL)
01202 return 1;
01203 switch (magicp) {
01204 case HEADER_MAGIC_YES:
01205
01206 nb = Fwrite(header_magic, sizeof(char), sizeof(header_magic), fd);
01207
01208 if (nb != sizeof(header_magic))
01209 goto exit;
01210 break;
01211 case HEADER_MAGIC_NO:
01212 break;
01213 }
01214
01215
01216 nb = Fwrite(uh, sizeof(char), length, fd);
01217
01218
01219 exit:
01220 uh = _free(uh);
01221 return (nb == length ? 0 : 1);
01222 }
01223
01230 static
01231 int headerIsEntry(Header h, int_32 tag)
01232
01233 {
01234
01235 return (findEntry(h, tag, RPM_NULL_TYPE) ? 1 : 0);
01236
01237 }
01238
01249 static int copyEntry(const indexEntry entry,
01250 hTYP_t type,
01251 hPTR_t * p,
01252 hCNT_t c,
01253 int minMem)
01254
01255 {
01256 int_32 count = entry->info.count;
01257 int rc = 1;
01258
01259 if (p)
01260 switch (entry->info.type) {
01261 case RPM_BIN_TYPE:
01262
01263
01264
01265
01266
01267
01268 if (ENTRY_IS_REGION(entry)) {
01269 int_32 * ei = ((int_32 *)entry->data) - 2;
01270
01271 entryInfo pe = (entryInfo) (ei + 2);
01272
01273 char * dataStart = (char *) (pe + ntohl(ei[0]));
01274 int_32 rdl = -entry->info.offset;
01275 int_32 ril = rdl/sizeof(*pe);
01276
01277
01278 rdl = entry->rdlen;
01279 count = 2 * sizeof(*ei) + (ril * sizeof(*pe)) + rdl;
01280 if (entry->info.tag == HEADER_IMAGE) {
01281 ril -= 1;
01282 pe += 1;
01283 } else {
01284 count += REGION_TAG_COUNT;
01285 rdl += REGION_TAG_COUNT;
01286 }
01287
01288 *p = xmalloc(count);
01289 ei = (int_32 *) *p;
01290 ei[0] = htonl(ril);
01291 ei[1] = htonl(rdl);
01292
01293
01294 pe = (entryInfo) memcpy(ei + 2, pe, (ril * sizeof(*pe)));
01295
01296
01297 dataStart = (char *) memcpy(pe + ril, dataStart, rdl);
01298
01299
01300 rc = regionSwab(NULL, ril, 0, pe, dataStart, 0);
01301
01302 rc = (rc < 0) ? 0 : 1;
01303 } else {
01304 count = entry->length;
01305 *p = (!minMem
01306 ? memcpy(xmalloc(count), entry->data, count)
01307 : entry->data);
01308 }
01309 break;
01310 case RPM_STRING_TYPE:
01311 if (count == 1) {
01312 *p = entry->data;
01313 break;
01314 }
01315
01316 case RPM_STRING_ARRAY_TYPE:
01317 case RPM_I18NSTRING_TYPE:
01318 { const char ** ptrEntry;
01319
01320 int tableSize = count * sizeof(char *);
01321
01322 char * t;
01323 int i;
01324
01325
01326 if (minMem) {
01327 *p = xmalloc(tableSize);
01328 ptrEntry = (const char **) *p;
01329 t = entry->data;
01330 } else {
01331 t = xmalloc(tableSize + entry->length);
01332 *p = (void *)t;
01333 ptrEntry = (const char **) *p;
01334 t += tableSize;
01335 memcpy(t, entry->data, entry->length);
01336 }
01337
01338 for (i = 0; i < count; i++) {
01339 *ptrEntry++ = t;
01340 t = strchr(t, 0);
01341 t++;
01342 }
01343 } break;
01344
01345 default:
01346 *p = entry->data;
01347 break;
01348 }
01349 if (type) *type = entry->info.type;
01350 if (c) *c = count;
01351 return rc;
01352 }
01353
01372 static int headerMatchLocale(const char *td, const char *l, const char *le)
01373
01374 {
01375 const char *fe;
01376
01377
01378 #if 0
01379 { const char *s, *ll, *CC, *EE, *dd;
01380 char *lbuf, *t.
01381
01382
01383 lbuf = alloca(le - l + 1);
01384 for (s = l, ll = t = lbuf; *s; s++, t++) {
01385 switch (*s) {
01386 case '_':
01387 *t = '\0';
01388 CC = t + 1;
01389 break;
01390 case '.':
01391 *t = '\0';
01392 EE = t + 1;
01393 break;
01394 case '@':
01395 *t = '\0';
01396 dd = t + 1;
01397 break;
01398 default:
01399 *t = *s;
01400 break;
01401 }
01402 }
01403
01404 if (ll)
01405 for (t = ll; *t; t++) *t = tolower(*t);
01406 if (CC)
01407 for (t = CC; *t; t++) *t = toupper(*t);
01408
01409
01410 }
01411 #endif
01412
01413
01414 if (strlen(td) == (le-l) && !strncmp(td, l, (le - l)))
01415 return 1;
01416
01417
01418 for (fe = l; fe < le && *fe != '@'; fe++)
01419 {};
01420 if (fe < le && !strncmp(td, l, (fe - l)))
01421 return 1;
01422
01423
01424 for (fe = l; fe < le && *fe != '.'; fe++)
01425 {};
01426 if (fe < le && !strncmp(td, l, (fe - l)))
01427 return 1;
01428
01429
01430 for (fe = l; fe < le && *fe != '_'; fe++)
01431 {};
01432 if (fe < le && !strncmp(td, l, (fe - l)))
01433 return 1;
01434
01435 return 0;
01436 }
01437
01444 static char *
01445 headerFindI18NString(Header h, indexEntry entry)
01446
01447 {
01448 const char *lang, *l, *le;
01449 indexEntry table;
01450
01451
01452 if ((lang = getenv("LANGUAGE")) == NULL &&
01453 (lang = getenv("LC_ALL")) == NULL &&
01454 (lang = getenv("LC_MESSAGES")) == NULL &&
01455 (lang = getenv("LANG")) == NULL)
01456 return entry->data;
01457
01458
01459 if ((table = findEntry(h, HEADER_I18NTABLE, RPM_STRING_ARRAY_TYPE)) == NULL)
01460 return entry->data;
01461
01462
01463 for (l = lang; *l != '\0'; l = le) {
01464 const char *td;
01465 char *ed;
01466 int langNum;
01467
01468 while (*l && *l == ':')
01469 l++;
01470 if (*l == '\0')
01471 break;
01472 for (le = l; *le && *le != ':'; le++)
01473 {};
01474
01475
01476 for (langNum = 0, td = table->data, ed = entry->data;
01477 langNum < entry->info.count;
01478 langNum++, td += strlen(td) + 1, ed += strlen(ed) + 1) {
01479
01480 if (headerMatchLocale(td, l, le))
01481 return ed;
01482
01483 }
01484 }
01485
01486 return entry->data;
01487 }
01488
01499 static int intGetEntry(Header h, int_32 tag,
01500 hTAG_t type,
01501 hPTR_t * p,
01502 hCNT_t c,
01503 int minMem)
01504
01505 {
01506 indexEntry entry;
01507 int rc;
01508
01509
01510
01511 entry = findEntry(h, tag, RPM_NULL_TYPE);
01512
01513 if (entry == NULL) {
01514 if (type) type = 0;
01515 if (p) *p = NULL;
01516 if (c) *c = 0;
01517 return 0;
01518 }
01519
01520 switch (entry->info.type) {
01521 case RPM_I18NSTRING_TYPE:
01522 rc = 1;
01523 if (type) *type = RPM_STRING_TYPE;
01524 if (c) *c = 1;
01525
01526 if (p) *p = headerFindI18NString(h, entry);
01527
01528 break;
01529 default:
01530 rc = copyEntry(entry, type, p, c, minMem);
01531 break;
01532 }
01533
01534
01535 return ((rc == 1) ? 1 : 0);
01536 }
01537
01545 static void * headerFreeTag( Header h,
01546 const void * data, rpmTagType type)
01547
01548 {
01549 if (data) {
01550
01551 if (type == -1 ||
01552 type == RPM_STRING_ARRAY_TYPE ||
01553 type == RPM_I18NSTRING_TYPE ||
01554 type == RPM_BIN_TYPE)
01555 data = _free(data);
01556
01557 }
01558 return NULL;
01559 }
01560
01574 static
01575 int headerGetEntry(Header h, int_32 tag,
01576 hTYP_t type,
01577 void ** p,
01578 hCNT_t c)
01579
01580 {
01581 return intGetEntry(h, tag, type, (hPTR_t *)p, c, 0);
01582 }
01583
01596 static
01597 int headerGetEntryMinMemory(Header h, int_32 tag,
01598 hTYP_t type,
01599 hPTR_t * p,
01600 hCNT_t c)
01601
01602 {
01603 return intGetEntry(h, tag, type, p, c, 1);
01604 }
01605
01606 int headerGetRawEntry(Header h, int_32 tag, int_32 * type, hPTR_t * p,
01607 int_32 * c)
01608 {
01609 indexEntry entry;
01610 int rc;
01611
01612 if (p == NULL) return headerIsEntry(h, tag);
01613
01614
01615
01616 entry = findEntry(h, tag, RPM_NULL_TYPE);
01617
01618 if (!entry) {
01619 if (p) *p = NULL;
01620 if (c) *c = 0;
01621 return 0;
01622 }
01623
01624 rc = copyEntry(entry, type, p, c, 0);
01625
01626
01627 return ((rc == 1) ? 1 : 0);
01628 }
01629
01632 static void copyData(int_32 type, void * dstPtr, const void * srcPtr,
01633 int_32 c, int dataLength)
01634
01635 {
01636 const char ** src;
01637 char * dst;
01638 int i;
01639
01640 switch (type) {
01641 case RPM_STRING_ARRAY_TYPE:
01642 case RPM_I18NSTRING_TYPE:
01643
01644 i = c;
01645 src = (const char **) srcPtr;
01646 dst = dstPtr;
01647 while (i--) {
01648 if (*src) {
01649 int len = strlen(*src) + 1;
01650 memcpy(dst, *src, len);
01651 dst += len;
01652 }
01653 src++;
01654 }
01655 break;
01656
01657 default:
01658 memmove(dstPtr, srcPtr, dataLength);
01659 break;
01660 }
01661 }
01662
01671 static void * grabData(int_32 type, hPTR_t p, int_32 c,
01672 int * lengthPtr)
01673
01674 {
01675 int length = dataLength(type, p, c, 0);
01676 void * data = xmalloc(length);
01677
01678 copyData(type, data, p, c, length);
01679
01680 if (lengthPtr)
01681 *lengthPtr = length;
01682 return data;
01683 }
01684
01699 static
01700 int headerAddEntry(Header h, int_32 tag, int_32 type, const void * p, int_32 c)
01701
01702 {
01703 indexEntry entry;
01704
01705
01706 if (c <= 0)
01707 return 0;
01708
01709
01710 if (h->indexUsed == h->indexAlloced) {
01711 h->indexAlloced += INDEX_MALLOC_SIZE;
01712 h->index = xrealloc(h->index, h->indexAlloced * sizeof(*h->index));
01713 }
01714
01715
01716 entry = h->index + h->indexUsed;
01717 entry->info.tag = tag;
01718 entry->info.type = type;
01719 entry->info.count = c;
01720 entry->info.offset = 0;
01721 entry->data = grabData(type, p, c, &entry->length);
01722
01723 if (h->indexUsed > 0 && tag < h->index[h->indexUsed-1].info.tag)
01724 h->flags &= ~HEADERFLAG_SORTED;
01725 h->indexUsed++;
01726
01727 return 1;
01728 }
01729
01744 static
01745 int headerAppendEntry(Header h, int_32 tag, int_32 type,
01746 const void * p, int_32 c)
01747
01748 {
01749 indexEntry entry;
01750 int length;
01751
01752
01753 entry = findEntry(h, tag, type);
01754 if (!entry)
01755 return 0;
01756
01757 if (type == RPM_STRING_TYPE || type == RPM_I18NSTRING_TYPE) {
01758
01759 return 0;
01760 }
01761
01762 length = dataLength(type, p, c, 0);
01763
01764 if (ENTRY_IN_REGION(entry)) {
01765 char * t = xmalloc(entry->length + length);
01766 memcpy(t, entry->data, entry->length);
01767 entry->data = t;
01768 entry->info.offset = 0;
01769 } else
01770 entry->data = xrealloc(entry->data, entry->length + length);
01771
01772 copyData(type, ((char *) entry->data) + entry->length, p, c, length);
01773
01774 entry->length += length;
01775
01776 entry->info.count += c;
01777
01778 return 1;
01779 }
01780
01791 static
01792 int headerAddOrAppendEntry(Header h, int_32 tag, int_32 type,
01793 const void * p, int_32 c)
01794
01795 {
01796 return (findEntry(h, tag, type)
01797 ? headerAppendEntry(h, tag, type, p, c)
01798 : headerAddEntry(h, tag, type, p, c));
01799 }
01800
01821 static
01822 int headerAddI18NString(Header h, int_32 tag, const char * string,
01823 const char * lang)
01824
01825 {
01826 indexEntry table, entry;
01827 const char ** strArray;
01828 int length;
01829 int ghosts;
01830 int i, langNum;
01831 char * buf;
01832
01833 table = findEntry(h, HEADER_I18NTABLE, RPM_STRING_ARRAY_TYPE);
01834 entry = findEntry(h, tag, RPM_I18NSTRING_TYPE);
01835
01836 if (!table && entry)
01837 return 0;
01838
01839 if (!table && !entry) {
01840 const char * charArray[2];
01841 int count = 0;
01842 if (!lang || (lang[0] == 'C' && lang[1] == '\0')) {
01843
01844 charArray[count++] = "C";
01845
01846 } else {
01847
01848 charArray[count++] = "C";
01849
01850 charArray[count++] = lang;
01851 }
01852 if (!headerAddEntry(h, HEADER_I18NTABLE, RPM_STRING_ARRAY_TYPE,
01853 &charArray, count))
01854 return 0;
01855 table = findEntry(h, HEADER_I18NTABLE, RPM_STRING_ARRAY_TYPE);
01856 }
01857
01858 if (!table)
01859 return 0;
01860
01861 if (!lang) lang = "C";
01862
01863
01864 { const char * l = table->data;
01865 for (langNum = 0; langNum < table->info.count; langNum++) {
01866 if (!strcmp(l, lang)) break;
01867 l += strlen(l) + 1;
01868 }
01869 }
01870
01871 if (langNum >= table->info.count) {
01872 length = strlen(lang) + 1;
01873 if (ENTRY_IN_REGION(table)) {
01874 char * t = xmalloc(table->length + length);
01875 memcpy(t, table->data, table->length);
01876 table->data = t;
01877 table->info.offset = 0;
01878 } else
01879 table->data = xrealloc(table->data, table->length + length);
01880 memmove(((char *)table->data) + table->length, lang, length);
01881 table->length += length;
01882 table->info.count++;
01883 }
01884
01885 if (!entry) {
01886 strArray = alloca(sizeof(*strArray) * (langNum + 1));
01887 for (i = 0; i < langNum; i++)
01888 strArray[i] = "";
01889 strArray[langNum] = string;
01890 return headerAddEntry(h, tag, RPM_I18NSTRING_TYPE, strArray,
01891 langNum + 1);
01892 } else if (langNum >= entry->info.count) {
01893 ghosts = langNum - entry->info.count;
01894
01895 length = strlen(string) + 1 + ghosts;
01896 if (ENTRY_IN_REGION(entry)) {
01897 char * t = xmalloc(entry->length + length);
01898 memcpy(t, entry->data, entry->length);
01899 entry->data = t;
01900 entry->info.offset = 0;
01901 } else
01902 entry->data = xrealloc(entry->data, entry->length + length);
01903
01904 memset(((char *)entry->data) + entry->length, '\0', ghosts);
01905 memmove(((char *)entry->data) + entry->length + ghosts, string, strlen(string)+1);
01906
01907 entry->length += length;
01908 entry->info.count = langNum + 1;
01909 } else {
01910 char *b, *be, *e, *ee, *t;
01911 size_t bn, sn, en;
01912
01913
01914 b = be = e = ee = entry->data;
01915 for (i = 0; i < table->info.count; i++) {
01916 if (i == langNum)
01917 be = ee;
01918 ee += strlen(ee) + 1;
01919 if (i == langNum)
01920 e = ee;
01921 }
01922
01923
01924 bn = (be-b);
01925 sn = strlen(string) + 1;
01926 en = (ee-e);
01927 length = bn + sn + en;
01928 t = buf = xmalloc(length);
01929
01930
01931 memcpy(t, b, bn);
01932 t += bn;
01933
01934 memcpy(t, string, sn);
01935 t += sn;
01936 memcpy(t, e, en);
01937 t += en;
01938
01939
01940
01941 entry->length -= strlen(be) + 1;
01942 entry->length += sn;
01943
01944 if (ENTRY_IN_REGION(entry)) {
01945 entry->info.offset = 0;
01946 } else
01947 entry->data = _free(entry->data);
01948
01949 entry->data = buf;
01950
01951 }
01952
01953 return 0;
01954 }
01955
01966 static
01967 int headerModifyEntry(Header h, int_32 tag, int_32 type,
01968 const void * p, int_32 c)
01969
01970 {
01971 indexEntry entry;
01972 void * oldData;
01973
01974
01975 entry = findEntry(h, tag, type);
01976 if (!entry)
01977 return 0;
01978
01979
01980 while (entry > h->index && (entry - 1)->info.tag == tag)
01981 entry--;
01982
01983
01984
01985 oldData = entry->data;
01986
01987 entry->info.count = c;
01988 entry->info.type = type;
01989 entry->data = grabData(type, p, c, &entry->length);
01990
01991
01992 if (ENTRY_IN_REGION(entry)) {
01993 entry->info.offset = 0;
01994 } else
01995 oldData = _free(oldData);
01996
01997
01998 return 1;
01999 }
02000
02003 static char escapedChar(const char ch)
02004 {
02005 switch (ch) {
02006 case 'a': return '\a';
02007 case 'b': return '\b';
02008 case 'f': return '\f';
02009 case 'n': return '\n';
02010 case 'r': return '\r';
02011 case 't': return '\t';
02012 case 'v': return '\v';
02013 default: return ch;
02014 }
02015 }
02016
02023 static sprintfToken
02024 freeFormat( sprintfToken format, int num)
02025
02026 {
02027 int i;
02028
02029 if (format == NULL) return NULL;
02030 for (i = 0; i < num; i++) {
02031 switch (format[i].type) {
02032 case PTOK_ARRAY:
02033 format[i].u.array.format =
02034 freeFormat(format[i].u.array.format,
02035 format[i].u.array.numTokens);
02036 break;
02037 case PTOK_COND:
02038 format[i].u.cond.ifFormat =
02039 freeFormat(format[i].u.cond.ifFormat,
02040 format[i].u.cond.numIfTokens);
02041 format[i].u.cond.elseFormat =
02042 freeFormat(format[i].u.cond.elseFormat,
02043 format[i].u.cond.numElseTokens);
02044 break;
02045 case PTOK_NONE:
02046 case PTOK_TAG:
02047 case PTOK_STRING:
02048 default:
02049 break;
02050 }
02051 }
02052 format = _free(format);
02053 return NULL;
02054 }
02055
02058 static void findTag(char * name, const headerTagTableEntry tags,
02059 const headerSprintfExtension extensions,
02060 headerTagTableEntry * tagMatch,
02061 headerSprintfExtension * extMatch)
02062
02063 {
02064 headerTagTableEntry entry;
02065 headerSprintfExtension ext;
02066 const char * tagname;
02067
02068 *tagMatch = NULL;
02069 *extMatch = NULL;
02070
02071 if (strncmp("RPMTAG_", name, sizeof("RPMTAG_")-1)) {
02072 char * t = alloca(strlen(name) + sizeof("RPMTAG_"));
02073 (void) stpcpy( stpcpy(t, "RPMTAG_"), name);
02074 tagname = t;
02075 } else {
02076 tagname = name;
02077 }
02078
02079
02080 ext = extensions;
02081 while (ext->type != HEADER_EXT_LAST) {
02082 if (ext->name != NULL && ext->type == HEADER_EXT_TAG
02083 && !xstrcasecmp(ext->name, tagname))
02084 break;
02085
02086 if (ext->type == HEADER_EXT_MORE)
02087 ext = ext->u.more;
02088 else
02089 ext++;
02090 }
02091
02092 if (ext->type == HEADER_EXT_TAG) {
02093 *extMatch = ext;
02094 return;
02095 }
02096
02097
02098 for (entry = tags; entry->name; entry++)
02099 if (entry->name && !xstrcasecmp(entry->name, tagname))
02100 break;
02101
02102 if (entry->name) {
02103 *tagMatch = entry;
02104 return;
02105 }
02106 }
02107
02108
02109 static int parseExpression(sprintfToken token, char * str,
02110 const headerTagTableEntry tags,
02111 const headerSprintfExtension extensions,
02112 char ** endPtr, errmsg_t * errmsg)
02113 ;
02114
02117 static int parseFormat(char * str, const headerTagTableEntry tags,
02118 const headerSprintfExtension extensions,
02119 sprintfToken * formatPtr, int * numTokensPtr,
02120 char ** endPtr, int state,
02121 errmsg_t * errmsg)
02122
02123 {
02124 char * chptr, * start, * next, * dst;
02125 sprintfToken format;
02126 int numTokens;
02127 int currToken;
02128 headerTagTableEntry tag;
02129 headerSprintfExtension ext;
02130 int i;
02131 int done = 0;
02132
02133
02134 numTokens = 0;
02135 for (chptr = str; *chptr != '\0'; chptr++)
02136 if (*chptr == '%') numTokens++;
02137 numTokens = numTokens * 2 + 1;
02138
02139 format = xcalloc(numTokens, sizeof(*format));
02140 if (endPtr) *endPtr = NULL;
02141
02142
02143 dst = start = str;
02144 currToken = -1;
02145 while (*start != '\0') {
02146 switch (*start) {
02147 case '%':
02148
02149 if (*(start + 1) == '%') {
02150 if (currToken < 0 || format[currToken].type != PTOK_STRING) {
02151 currToken++;
02152 format[currToken].type = PTOK_STRING;
02153
02154 dst = format[currToken].u.string.string = start;
02155
02156 }
02157
02158 start++;
02159
02160 *dst++ = *start++;
02161
02162 break;
02163 }
02164
02165 currToken++;
02166 *dst++ = '\0';
02167 start++;
02168
02169 if (*start == '|') {
02170 char * newEnd;
02171
02172 start++;
02173 if (parseExpression(format + currToken, start, tags,
02174 extensions, &newEnd, errmsg))
02175 {
02176 format = freeFormat(format, numTokens);
02177 return 1;
02178 }
02179 start = newEnd;
02180 break;
02181 }
02182
02183
02184 format[currToken].u.tag.format = start;
02185
02186 format[currToken].u.tag.pad = 0;
02187 format[currToken].u.tag.justOne = 0;
02188 format[currToken].u.tag.arrayCount = 0;
02189
02190 chptr = start;
02191 while (*chptr && *chptr != '{' && *chptr != '%') chptr++;
02192 if (!*chptr || *chptr == '%') {
02193
02194 if (errmsg) *errmsg = _("missing { after %");
02195
02196 format = freeFormat(format, numTokens);
02197 return 1;
02198 }
02199
02200 *chptr++ = '\0';
02201
02202 while (start < chptr) {
02203 if (xisdigit(*start)) {
02204 i = strtoul(start, &start, 10);
02205 format[currToken].u.tag.pad += i;
02206 } else {
02207 start++;
02208 }
02209 }
02210
02211 if (*start == '=') {
02212 format[currToken].u.tag.justOne = 1;
02213 start++;
02214 } else if (*start == '#') {
02215 format[currToken].u.tag.justOne = 1;
02216 format[currToken].u.tag.arrayCount = 1;
02217 start++;
02218 }
02219
02220 next = start;
02221 while (*next && *next != '}') next++;
02222 if (!*next) {
02223
02224 if (errmsg) *errmsg = _("missing } after %{");
02225
02226 format = freeFormat(format, numTokens);
02227 return 1;
02228 }
02229 *next++ = '\0';
02230
02231 chptr = start;
02232 while (*chptr && *chptr != ':') chptr++;
02233
02234 if (*chptr != '\0') {
02235 *chptr++ = '\0';
02236 if (!*chptr) {
02237
02238 if (errmsg) *errmsg = _("empty tag format");
02239
02240 format = freeFormat(format, numTokens);
02241 return 1;
02242 }
02243
02244 format[currToken].u.tag.type = chptr;
02245
02246 } else {
02247 format[currToken].u.tag.type = NULL;
02248 }
02249
02250 if (!*start) {
02251
02252 if (errmsg) *errmsg = _("empty tag name");
02253
02254 format = freeFormat(format, numTokens);
02255 return 1;
02256 }
02257
02258 i = 0;
02259 findTag(start, tags, extensions, &tag, &ext);
02260
02261 if (tag) {
02262 format[currToken].u.tag.ext = NULL;
02263 format[currToken].u.tag.tag = tag->val;
02264 } else if (ext) {
02265 format[currToken].u.tag.ext = ext->u.tagFunction;
02266 format[currToken].u.tag.extNum = ext - extensions;
02267 } else {
02268
02269 if (errmsg) *errmsg = _("unknown tag");
02270
02271 format = freeFormat(format, numTokens);
02272 return 1;
02273 }
02274
02275 format[currToken].type = PTOK_TAG;
02276
02277 start = next;
02278
02279 break;
02280
02281 case '[':
02282 *dst++ = '\0';
02283 *start++ = '\0';
02284 currToken++;
02285
02286 if (parseFormat(start, tags, extensions,
02287 &format[currToken].u.array.format,
02288 &format[currToken].u.array.numTokens,
02289 &start, PARSER_IN_ARRAY, errmsg)) {
02290 format = freeFormat(format, numTokens);
02291 return 1;
02292 }
02293
02294 if (!start) {
02295
02296 if (errmsg) *errmsg = _("] expected at end of array");
02297
02298 format = freeFormat(format, numTokens);
02299 return 1;
02300 }
02301
02302 dst = start;
02303
02304 format[currToken].type = PTOK_ARRAY;
02305
02306 break;
02307
02308 case ']':
02309 case '}':
02310 if ((*start == ']' && state != PARSER_IN_ARRAY) ||
02311 (*start == '}' && state != PARSER_IN_EXPR)) {
02312 if (*start == ']') {
02313
02314 if (errmsg) *errmsg = _("unexpected ]");
02315
02316 } else {
02317
02318 if (errmsg) *errmsg = _("unexpected }");
02319
02320 }
02321 format = freeFormat(format, numTokens);
02322 return 1;
02323 }
02324 *start++ = '\0';
02325 if (endPtr) *endPtr = start;
02326 done = 1;
02327 break;
02328
02329 default:
02330 if (currToken < 0 || format[currToken].type != PTOK_STRING) {
02331 currToken++;
02332 format[currToken].type = PTOK_STRING;
02333
02334 dst = format[currToken].u.string.string = start;
02335
02336 }
02337
02338 if (*start == '\\') {
02339 start++;
02340 *dst++ = escapedChar(*start++);
02341 } else {
02342 *dst++ = *start++;
02343 }
02344 break;
02345 }
02346 if (done)
02347 break;
02348 }
02349
02350
02351 *dst = '\0';
02352
02353 currToken++;
02354 for (i = 0; i < currToken; i++) {
02355 if (format[i].type == PTOK_STRING)
02356 format[i].u.string.len = strlen(format[i].u.string.string);
02357 }
02358
02359 *numTokensPtr = currToken;
02360 *formatPtr = format;
02361
02362 return 0;
02363 }
02364
02367 static int parseExpression(sprintfToken token, char * str,
02368 const headerTagTableEntry tags,
02369 const headerSprintfExtension extensions,
02370 char ** endPtr,
02371 errmsg_t * errmsg)
02372 {
02373 headerTagTableEntry tag;
02374 headerSprintfExtension ext;
02375 char * chptr;
02376 char * end;
02377
02378 if (errmsg) *errmsg = NULL;
02379 chptr = str;
02380 while (*chptr && *chptr != '?') chptr++;
02381
02382 if (*chptr != '?') {
02383
02384 if (errmsg) *errmsg = _("? expected in expression");
02385
02386 return 1;
02387 }
02388
02389 *chptr++ = '\0';;
02390
02391 if (*chptr != '{') {
02392
02393 if (errmsg) *errmsg = _("{ expected after ? in expression");
02394
02395 return 1;
02396 }
02397
02398 chptr++;
02399
02400 if (parseFormat(chptr, tags, extensions, &token->u.cond.ifFormat,
02401 &token->u.cond.numIfTokens, &end, PARSER_IN_EXPR, errmsg))
02402 return 1;
02403
02404 if (!*end) {
02405
02406 if (errmsg) *errmsg = _("} expected in expression");
02407
02408 token->u.cond.ifFormat =
02409 freeFormat(token->u.cond.ifFormat, token->u.cond.numIfTokens);
02410 return 1;
02411 }
02412
02413 chptr = end;
02414 if (*chptr != ':' && *chptr != '|') {
02415
02416 if (errmsg) *errmsg = _(": expected following ? subexpression");
02417
02418 token->u.cond.ifFormat =
02419 freeFormat(token->u.cond.ifFormat, token->u.cond.numIfTokens);
02420 return 1;
02421 }
02422
02423 if (*chptr == '|') {
02424 (void) parseFormat(xstrdup(""), tags, extensions,
02425 &token->u.cond.elseFormat,
02426 &token->u.cond.numElseTokens, &end, PARSER_IN_EXPR,
02427 errmsg);
02428 } else {
02429 chptr++;
02430
02431 if (*chptr != '{') {
02432
02433 if (errmsg) *errmsg = _("{ expected after : in expression");
02434
02435 token->u.cond.ifFormat =
02436 freeFormat(token->u.cond.ifFormat, token->u.cond.numIfTokens);
02437 return 1;
02438 }
02439
02440 chptr++;
02441
02442 if (parseFormat(chptr, tags, extensions, &token->u.cond.elseFormat,
02443 &token->u.cond.numElseTokens, &end, PARSER_IN_EXPR,
02444 errmsg))
02445 return 1;
02446 if (!*end) {
02447
02448 if (errmsg) *errmsg = _("} expected in expression");
02449
02450 token->u.cond.ifFormat =
02451 freeFormat(token->u.cond.ifFormat, token->u.cond.numIfTokens);
02452 return 1;
02453 }
02454
02455 chptr = end;
02456 if (*chptr != '|') {
02457
02458 if (errmsg) *errmsg = _("| expected at end of expression");
02459
02460 token->u.cond.ifFormat =
02461 freeFormat(token->u.cond.ifFormat, token->u.cond.numIfTokens);
02462 token->u.cond.elseFormat =
02463 freeFormat(token->u.cond.elseFormat, token->u.cond.numElseTokens);
02464 return 1;
02465 }
02466 }
02467
02468 chptr++;
02469
02470 *endPtr = chptr;
02471
02472 findTag(str, tags, extensions, &tag, &ext);
02473
02474 if (tag) {
02475 token->u.cond.tag.ext = NULL;
02476 token->u.cond.tag.tag = tag->val;
02477 } else if (ext) {
02478 token->u.cond.tag.ext = ext->u.tagFunction;
02479 token->u.cond.tag.extNum = ext - extensions;
02480 } else {
02481 token->u.cond.tag.ext = NULL;
02482 token->u.cond.tag.tag = -1;
02483 }
02484
02485 token->type = PTOK_COND;
02486
02487 return 0;
02488 }
02489
02493 static int getExtension(Header h, headerTagTagFunction fn,
02494 hTYP_t typeptr,
02495 hPTR_t * data,
02496 hCNT_t countptr,
02497 extensionCache ext)
02498
02499 {
02500 if (!ext->avail) {
02501 if (fn(h, &ext->type, &ext->data, &ext->count, &ext->freeit))
02502 return 1;
02503 ext->avail = 1;
02504 }
02505
02506 if (typeptr) *typeptr = ext->type;
02507 if (data) *data = ext->data;
02508 if (countptr) *countptr = ext->count;
02509
02510 return 0;
02511 }
02512
02515 static char * formatValue(sprintfTag tag, Header h,
02516 const headerSprintfExtension extensions,
02517 extensionCache extCache, int element)
02518
02519 {
02520 int len;
02521 char buf[20];
02522 int_32 count, type;
02523 hPTR_t data;
02524 unsigned int intVal;
02525 char * val = NULL;
02526 const char ** strarray;
02527 int mayfree = 0;
02528 int countBuf;
02529 headerTagFormatFunction tagtype = NULL;
02530 headerSprintfExtension ext;
02531
02532 memset(buf, 0, sizeof(buf));
02533
02534 if (tag->ext) {
02535 if (getExtension(h, tag->ext, &type, &data, &count,
02536 extCache + tag->extNum))
02537 {
02538 count = 1;
02539 type = RPM_STRING_TYPE;
02540 data = "(none)";
02541 }
02542 } else {
02543 if (!headerGetEntry(h, tag->tag, &type, (void **)&data, &count)) {
02544 count = 1;
02545 type = RPM_STRING_TYPE;
02546 data = "(none)";
02547 }
02548
02549 mayfree = 1;
02550 }
02551
02552
02553 if (tag->arrayCount) {
02554
02555 data = headerFreeData(data, type);
02556
02557
02558 countBuf = count;
02559 data = &countBuf;
02560 count = 1;
02561 type = RPM_INT32_TYPE;
02562 }
02563
02564 (void) stpcpy( stpcpy(buf, "%"), tag->format);
02565
02566 if (tag->type) {
02567 ext = extensions;
02568 while (ext->type != HEADER_EXT_LAST) {
02569 if (ext->name != NULL && ext->type == HEADER_EXT_FORMAT
02570 && !strcmp(ext->name, tag->type))
02571 {
02572 tagtype = ext->u.formatFunction;
02573 break;
02574 }
02575
02576 if (ext->type == HEADER_EXT_MORE)
02577 ext = ext->u.more;
02578 else
02579 ext++;
02580 }
02581 }
02582
02583
02584 switch (type) {
02585 case RPM_STRING_ARRAY_TYPE:
02586 strarray = (const char **)data;
02587
02588 if (tagtype)
02589 val = tagtype(RPM_STRING_TYPE, strarray[element], buf, tag->pad, 0);
02590
02591 if (!val) {
02592 strcat(buf, "s");
02593
02594 len = strlen(strarray[element]) + tag->pad + 20;
02595 val = xmalloc(len);
02596
02597 sprintf(val, buf, strarray[element]);
02598
02599 }
02600
02601
02602 if (mayfree) data = _free(data);
02603
02604
02605 break;
02606
02607 case RPM_STRING_TYPE:
02608 if (tagtype)
02609 val = tagtype(RPM_STRING_ARRAY_TYPE, data, buf, tag->pad, 0);
02610
02611 if (!val) {
02612 strcat(buf, "s");
02613
02614 len = strlen(data) + tag->pad + 20;
02615 val = xmalloc(len);
02616
02617 sprintf(val, buf, data);
02618
02619 }
02620 break;
02621
02622 case RPM_CHAR_TYPE:
02623 case RPM_INT8_TYPE:
02624 case RPM_INT16_TYPE:
02625 case RPM_INT32_TYPE:
02626 switch (type) {
02627 case RPM_CHAR_TYPE:
02628 case RPM_INT8_TYPE:
02629 intVal = *(((int_8 *) data) + element);
02630 break;
02631 case RPM_INT16_TYPE:
02632 intVal = *(((uint_16 *) data) + element);
02633 break;
02634 default:
02635 case RPM_INT32_TYPE:
02636 intVal = *(((int_32 *) data) + element);
02637 break;
02638 }
02639
02640 if (tagtype)
02641 val = tagtype(RPM_INT32_TYPE, &intVal, buf, tag->pad, element);
02642
02643 if (!val) {
02644 strcat(buf, "d");
02645 len = 10 + tag->pad + 20;
02646 val = xmalloc(len);
02647
02648 sprintf(val, buf, intVal);
02649
02650 }
02651 break;
02652
02653 case RPM_BIN_TYPE:
02654 if (tagtype)
02655 val = tagtype(RPM_BIN_TYPE, data, buf, tag->pad, count);
02656
02657 if (!val) {
02658 #ifdef NOTYET
02659 val = memcpy(xmalloc(count), data, count);
02660 #else
02661
02662 static char hex[] = "0123456789abcdef";
02663 const char * s = data;
02664 char * t;
02665
02666 strcat(buf, "s");
02667 len = 2*count + tag->pad + 1;
02668 val = t = xmalloc(len);
02669 while (count-- > 0) {
02670 unsigned int i;
02671 i = *s++;
02672 *t++ = hex[ (i >> 4) & 0xf ];
02673 *t++ = hex[ (i ) & 0xf ];
02674 }
02675 *t = '\0';
02676 #endif
02677 }
02678 break;
02679
02680 default:
02681 val = xstrdup(_("(unknown type)"));
02682 break;
02683 }
02684
02685
02686 return val;
02687 }
02688
02691 static const char * singleSprintf(Header h, sprintfToken token,
02692 const headerSprintfExtension extensions,
02693 extensionCache extCache, int element)
02694
02695 {
02696 char * val;
02697 const char * thisItem;
02698 int thisItemLen;
02699 int len, alloced;
02700 int i, j;
02701 int numElements;
02702 int type;
02703 sprintfToken condFormat;
02704 int condNumFormats;
02705
02706
02707
02708 switch (token->type) {
02709 case PTOK_NONE:
02710 break;
02711
02712 case PTOK_STRING:
02713 val = xmalloc(token->u.string.len + 1);
02714 strcpy(val, token->u.string.string);
02715 break;
02716
02717 case PTOK_TAG:
02718 val = formatValue(&token->u.tag, h, extensions, extCache,
02719 token->u.tag.justOne ? 0 : element);
02720 break;
02721
02722 case PTOK_COND:
02723 if (token->u.cond.tag.ext ||
02724 headerIsEntry(h, token->u.cond.tag.tag)) {
02725 condFormat = token->u.cond.ifFormat;
02726 condNumFormats = token->u.cond.numIfTokens;
02727 } else {
02728 condFormat = token->u.cond.elseFormat;
02729 condNumFormats = token->u.cond.numElseTokens;
02730 }
02731
02732 alloced = condNumFormats * 20;
02733 val = xmalloc(alloced ? alloced : 1);
02734 *val = '\0';
02735 len = 0;
02736
02737 if (condFormat)
02738 for (i = 0; i < condNumFormats; i++) {
02739 thisItem = singleSprintf(h, condFormat + i,
02740 extensions, extCache, element);
02741 thisItemLen = strlen(thisItem);
02742 if ((thisItemLen + len) >= alloced) {
02743 alloced = (thisItemLen + len) + 200;
02744 val = xrealloc(val, alloced);
02745 }
02746 strcat(val, thisItem);
02747 len += thisItemLen;
02748 thisItem = _free(thisItem);
02749 }
02750
02751 break;
02752
02753 case PTOK_ARRAY:
02754 numElements = -1;
02755 for (i = 0; i < token->u.array.numTokens; i++) {
02756 if (token->u.array.format[i].type != PTOK_TAG ||
02757 token->u.array.format[i].u.tag.arrayCount ||
02758 token->u.array.format[i].u.tag.justOne) continue;
02759
02760 if (token->u.array.format[i].u.tag.ext) {
02761 const void * data;
02762 if (getExtension(h, token->u.array.format[i].u.tag.ext,
02763 &type, &data, &numElements,
02764 extCache +
02765 token->u.array.format[i].u.tag.extNum))
02766 continue;
02767 } else {
02768 if (!headerGetEntry(h, token->u.array.format[i].u.tag.tag,
02769 &type, (void **) &val, &numElements))
02770 continue;
02771 val = headerFreeData(val, type);
02772 }
02773 break;
02774 }
02775
02776 if (numElements == -1) {
02777 val = xstrdup("(none)");
02778 } else {
02779 alloced = numElements * token->u.array.numTokens * 20;
02780 val = xmalloc(alloced);
02781 *val = '\0';
02782 len = 0;
02783
02784 for (j = 0; j < numElements; j++) {
02785 for (i = 0; i < token->u.array.numTokens; i++) {
02786 thisItem = singleSprintf(h, token->u.array.format + i,
02787 extensions, extCache, j);
02788 thisItemLen = strlen(thisItem);
02789 if ((thisItemLen + len) >= alloced) {
02790 alloced = (thisItemLen + len) + 200;
02791 val = xrealloc(val, alloced);
02792 }
02793 strcat(val, thisItem);
02794 len += thisItemLen;
02795 thisItem = _free(thisItem);
02796 }
02797 }
02798 }
02799
02800 break;
02801 }
02802
02803 return val;
02804 }
02805
02808 static extensionCache
02809 allocateExtensionCache(const headerSprintfExtension extensions)
02810
02811 {
02812 headerSprintfExtension ext = extensions;
02813 int i = 0;
02814
02815 while (ext->type != HEADER_EXT_LAST) {
02816 i++;
02817 if (ext->type == HEADER_EXT_MORE)
02818 ext = ext->u.more;
02819 else
02820 ext++;
02821 }
02822
02823
02824 return xcalloc(i, sizeof(struct extensionCache));
02825
02826 }
02827
02831 static extensionCache
02832 freeExtensionCache(const headerSprintfExtension extensions,
02833 extensionCache cache)
02834
02835 {
02836 headerSprintfExtension ext = extensions;
02837 int i = 0;
02838
02839 while (ext->type != HEADER_EXT_LAST) {
02840 if (cache[i].freeit) cache[i].data = _free(cache[i].data);
02841
02842 i++;
02843 if (ext->type == HEADER_EXT_MORE)
02844 ext = ext->u.more;
02845 else
02846 ext++;
02847 }
02848
02849 cache = _free(cache);
02850 return NULL;
02851 }
02852
02864 static
02865 char * headerSprintf(Header h, const char * fmt,
02866 const struct headerTagTableEntry_s * tbltags,
02867 const struct headerSprintfExtension_s * extensions,
02868 errmsg_t * errmsg)
02869
02870 {
02871
02872 headerSprintfExtension exts = (headerSprintfExtension) extensions;
02873 headerTagTableEntry tags = (headerTagTableEntry) tbltags;
02874
02875 char * fmtString;
02876 sprintfToken format;
02877 int numTokens;
02878 char * answer;
02879 int answerLength;
02880 int answerAlloced;
02881 int i;
02882 extensionCache extCache;
02883
02884
02885 fmtString = xstrdup(fmt);
02886
02887 if (parseFormat(fmtString, tags, exts, &format, &numTokens,
02888 NULL, PARSER_BEGIN, errmsg)) {
02889 fmtString = _free(fmtString);
02890 return NULL;
02891 }
02892
02893 extCache = allocateExtensionCache(exts);
02894
02895 answerAlloced = 1024;
02896 answerLength = 0;
02897 answer = xmalloc(answerAlloced);
02898 *answer = '\0';
02899
02900 for (i = 0; i < numTokens; i++) {
02901 const char * piece;
02902 int pieceLength;
02903
02904
02905 piece = singleSprintf(h, format + i, exts, extCache, 0);
02906
02907 if (piece) {
02908 pieceLength = strlen(piece);
02909 if ((answerLength + pieceLength) >= answerAlloced) {
02910 while ((answerLength + pieceLength) >= answerAlloced)
02911 answerAlloced += 1024;
02912 answer = xrealloc(answer, answerAlloced);
02913 }
02914
02915 strcat(answer, piece);
02916 answerLength += pieceLength;
02917 piece = _free(piece);
02918 }
02919 }
02920
02921 fmtString = _free(fmtString);
02922 extCache = freeExtensionCache(exts, extCache);
02923 format = _free(format);
02924
02925 return answer;
02926 }
02927
02930 static char * octalFormat(int_32 type, hPTR_t data,
02931 char * formatPrefix, int padding, int element)
02932
02933 {
02934 char * val;
02935
02936 if (type != RPM_INT32_TYPE) {
02937 val = xstrdup(_("(not a number)"));
02938 } else {
02939 val = xmalloc(20 + padding);
02940 strcat(formatPrefix, "o");
02941
02942 sprintf(val, formatPrefix, *((int_32 *) data));
02943
02944 }
02945
02946 return val;
02947 }
02948
02951 static char * hexFormat(int_32 type, hPTR_t data,
02952 char * formatPrefix, int padding, int element)
02953
02954 {
02955 char * val;
02956
02957 if (type != RPM_INT32_TYPE) {
02958 val = xstrdup(_("(not a number)"));
02959 } else {
02960 val = xmalloc(20 + padding);
02961 strcat(formatPrefix, "x");
02962
02963 sprintf(val, formatPrefix, *((int_32 *) data));
02964
02965 }
02966
02967 return val;
02968 }
02969
02972 static char * realDateFormat(int_32 type, hPTR_t data,
02973 char * formatPrefix, int padding, int element,
02974 const char * strftimeFormat)
02975
02976 {
02977 char * val;
02978
02979 if (type != RPM_INT32_TYPE) {
02980 val = xstrdup(_("(not a number)"));
02981 } else {
02982 struct tm * tstruct;
02983 char buf[50];
02984
02985 val = xmalloc(50 + padding);
02986 strcat(formatPrefix, "s");
02987
02988
02989 { time_t dateint = *((int_32 *) data);
02990 tstruct = localtime(&dateint);
02991 }
02992 buf[0] = '\0';
02993 if (tstruct)
02994 (void) strftime(buf, sizeof(buf) - 1, strftimeFormat, tstruct);
02995
02996 sprintf(val, formatPrefix, buf);
02997
02998 }
02999
03000 return val;
03001 }
03002
03005 static char * dateFormat(int_32 type, hPTR_t data,
03006 char * formatPrefix, int padding, int element)
03007
03008 {
03009 return realDateFormat(type, data, formatPrefix, padding, element, "%c");
03010 }
03011
03014 static char * dayFormat(int_32 type, hPTR_t data,
03015 char * formatPrefix, int padding, int element)
03016
03017 {
03018 return realDateFormat(type, data, formatPrefix, padding, element,
03019 "%a %b %d %Y");
03020 }
03021
03024 static char * shescapeFormat(int_32 type, hPTR_t data,
03025 char * formatPrefix, int padding, int element)
03026
03027 {
03028 char * result, * dst, * src, * buf;
03029
03030 if (type == RPM_INT32_TYPE) {
03031 result = xmalloc(padding + 20);
03032 strcat(formatPrefix, "d");
03033
03034 sprintf(result, formatPrefix, *((int_32 *) data));
03035
03036 } else {
03037 buf = alloca(strlen(data) + padding + 2);
03038 strcat(formatPrefix, "s");
03039
03040 sprintf(buf, formatPrefix, data);
03041
03042
03043 result = dst = xmalloc(strlen(buf) * 4 + 3);
03044 *dst++ = '\'';
03045 for (src = buf; *src != '\0'; src++) {
03046 if (*src == '\'') {
03047 *dst++ = '\'';
03048 *dst++ = '\\';
03049 *dst++ = '\'';
03050 *dst++ = '\'';
03051 } else {
03052 *dst++ = *src;
03053 }
03054 }
03055 *dst++ = '\'';
03056 *dst = '\0';
03057
03058 }
03059
03060 return result;
03061 }
03062
03063
03064 const struct headerSprintfExtension_s headerDefaultFormats[] = {
03065 { HEADER_EXT_FORMAT, "octal", { octalFormat } },
03066 { HEADER_EXT_FORMAT, "hex", { hexFormat } },
03067 { HEADER_EXT_FORMAT, "date", { dateFormat } },
03068 { HEADER_EXT_FORMAT, "day", { dayFormat } },
03069 { HEADER_EXT_FORMAT, "shescape", { shescapeFormat } },
03070 { HEADER_EXT_LAST, NULL, { NULL } }
03071 };
03072
03073
03080 static
03081 void headerCopyTags(Header headerFrom, Header headerTo, hTAG_t tagstocopy)
03082
03083 {
03084 int * p;
03085
03086 if (headerFrom == headerTo)
03087 return;
03088
03089 for (p = tagstocopy; *p != 0; p++) {
03090 char *s;
03091 int_32 type;
03092 int_32 count;
03093 if (headerIsEntry(headerTo, *p))
03094 continue;
03095 if (!headerGetEntryMinMemory(headerFrom, *p, &type,
03096 (hPTR_t *) &s, &count))
03097 continue;
03098 (void) headerAddEntry(headerTo, *p, type, s, count);
03099 s = headerFreeData(s, type);
03100 }
03101 }
03102
03106 struct headerIteratorS {
03107 Header h;
03108 int next_index;
03109 };
03110
03116 static
03117 HeaderIterator headerFreeIterator( HeaderIterator hi)
03118
03119 {
03120 hi->h = headerFree(hi->h);
03121 hi = _free(hi);
03122 return hi;
03123 }
03124
03130 static
03131 HeaderIterator headerInitIterator(Header h)
03132
03133 {
03134 HeaderIterator hi = xmalloc(sizeof(*hi));
03135
03136 headerSort(h);
03137
03138 hi->h = headerLink(h);
03139 hi->next_index = 0;
03140 return hi;
03141 }
03142
03152 static
03153 int headerNextIterator(HeaderIterator hi,
03154 hTAG_t tag,
03155 hTYP_t type,
03156 hPTR_t * p,
03157 hCNT_t c)
03158
03159 {
03160 Header h = hi->h;
03161 int slot = hi->next_index;
03162 indexEntry entry = NULL;
03163 int rc;
03164
03165 for (slot = hi->next_index; slot < h->indexUsed; slot++) {
03166 entry = h->index + slot;
03167 if (!ENTRY_IS_REGION(entry))
03168 break;
03169 }
03170 hi->next_index = slot;
03171 if (entry == NULL || slot >= h->indexUsed)
03172 return 0;
03173
03174 hi->next_index++;
03175
03176
03177 if (tag)
03178 *tag = entry->info.tag;
03179
03180 rc = copyEntry(entry, type, p, c, 0);
03181
03182
03183 return ((rc == 1) ? 1 : 0);
03184 }
03185
03191 static
03192 Header headerCopy(Header h)
03193
03194 {
03195 Header nh = headerNew();
03196 HeaderIterator hi;
03197 int_32 tag, type, count;
03198 hPTR_t ptr;
03199
03200
03201 for (hi = headerInitIterator(h);
03202 headerNextIterator(hi, &tag, &type, &ptr, &count);
03203 ptr = headerFreeData((void *)ptr, type))
03204 {
03205 if (ptr) (void) headerAddEntry(nh, tag, type, ptr, count);
03206 }
03207 hi = headerFreeIterator(hi);
03208
03209
03210 return headerReload(nh, HEADER_IMAGE);
03211 }
03212
03213
03214 static struct HV_s hdrVec1 = {
03215 headerNew,
03216 headerFree,
03217 headerLink,
03218 headerSort,
03219 headerUnsort,
03220 headerSizeof,
03221 headerUnload,
03222 headerReload,
03223 headerCopy,
03224 headerLoad,
03225 headerCopyLoad,
03226 headerRead,
03227 headerWrite,
03228 headerIsEntry,
03229 headerFreeTag,
03230 headerGetEntry,
03231 headerGetEntryMinMemory,
03232 headerAddEntry,
03233 headerAppendEntry,
03234 headerAddOrAppendEntry,
03235 headerAddI18NString,
03236 headerModifyEntry,
03237 headerRemoveEntry,
03238 headerSprintf,
03239 headerCopyTags,
03240 headerFreeIterator,
03241 headerInitIterator,
03242 headerNextIterator,
03243 headerUnlink,
03244 NULL, NULL,
03245 1
03246 };
03247
03248
03249
03250 HV_t hdrVec = &hdrVec1;
03251