00001
00005
00006
00007
00008
00009
00010
00011 #include "system.h"
00012 #include <langinfo.h>
00013 #include <iconv.h>
00014
00015 #define __HEADER_PROTOTYPES__
00016
00017 #include <header_internal.h>
00018
00019
00020 #include <rpmlib.h>
00021
00022 #include "debug.h"
00023
00024
00025 const char *const tagName(int tag) ;
00026
00027
00028
00029
00030
00031
00032
00033
00034
00035
00036 #define PARSER_BEGIN 0
00037 #define PARSER_IN_ARRAY 1
00038 #define PARSER_IN_EXPR 2
00039
00042
00043 static unsigned char header_magic[8] = {
00044 0x8e, 0xad, 0xe8, 0x01, 0x00, 0x00, 0x00, 0x00
00045 };
00046
00050
00051 static size_t headerMaxbytes = (32*1024*1024);
00052
00057 #define hdrchkTags(_ntags) ((_ntags) & 0xffff0000)
00058
00063 #define hdrchkData(_nbytes) ((_nbytes) & 0xff000000)
00064
00068
00069 static int typeSizes[] = {
00070 0,
00071 1,
00072 1,
00073 2,
00074 4,
00075 -1,
00076 -1,
00077 1,
00078 -1,
00079 -1
00080 };
00081
00082
00083 HV_t hdrVec;
00084
00085
00086 #if 0
00087
00092 static inline void *
00093 _free( const void * p)
00094 {
00095 if (p != NULL) free((void *)p);
00096 return NULL;
00097 }
00098 #endif
00099
00105 static
00106 Header headerLink(Header h)
00107
00108 {
00109 if (h != NULL) h->nrefs++;
00110
00111 return h;
00112
00113 }
00114
00120 static
00121 Header headerUnlink( Header h)
00122
00123 {
00124 if (h != NULL) h->nrefs--;
00125 return NULL;
00126 }
00127
00133 static
00134 Header headerFree( Header h)
00135
00136 {
00137 (void) headerUnlink(h);
00138
00139
00140 if (h == NULL || h->nrefs > 0)
00141 return NULL;
00142
00143 if (h->index) {
00144 indexEntry entry = h->index;
00145 int i;
00146 for (i = 0; i < h->indexUsed; i++, entry++) {
00147 if ((h->flags & HEADERFLAG_ALLOCATED) && ENTRY_IS_REGION(entry)) {
00148 if (entry->length > 0) {
00149 int_32 * ei = entry->data;
00150 if ((ei - 2) == h->blob) h->blob = _free(h->blob);
00151 entry->data = NULL;
00152 }
00153 } else if (!ENTRY_IN_REGION(entry)) {
00154 entry->data = _free(entry->data);
00155 }
00156 entry->data = NULL;
00157 }
00158 h->index = _free(h->index);
00159 }
00160
00161 h = _free(h);
00162 return h;
00163
00164 }
00165
00170 static
00171 Header headerNew(void)
00172
00173 {
00174 Header h = xcalloc(1, sizeof(*h));
00175
00176
00177 h->hv = *hdrVec;
00178
00179 h->blob = NULL;
00180 h->indexAlloced = INDEX_MALLOC_SIZE;
00181 h->indexUsed = 0;
00182 h->flags = HEADERFLAG_SORTED;
00183
00184 h->index = (h->indexAlloced
00185 ? xcalloc(h->indexAlloced, sizeof(*h->index))
00186 : NULL);
00187
00188
00189 h->nrefs = 0;
00190 return headerLink(h);
00191
00192 }
00193
00196 static int indexCmp(const void * avp, const void * bvp)
00197 {
00198
00199 indexEntry ap = (indexEntry) avp, bp = (indexEntry) bvp;
00200
00201 return (ap->info.tag - bp->info.tag);
00202 }
00203
00208 static
00209 void headerSort(Header h)
00210
00211 {
00212 if (!(h->flags & HEADERFLAG_SORTED)) {
00213 qsort(h->index, h->indexUsed, sizeof(*h->index), indexCmp);
00214 h->flags |= HEADERFLAG_SORTED;
00215 }
00216 }
00217
00220 static int offsetCmp(const void * avp, const void * bvp)
00221 {
00222
00223 indexEntry ap = (indexEntry) avp, bp = (indexEntry) bvp;
00224
00225 int rc = (ap->info.offset - bp->info.offset);
00226
00227 if (rc == 0) {
00228
00229 if (ap->info.offset < 0)
00230 rc = (((char *)ap->data) - ((char *)bp->data));
00231 else
00232 rc = (ap->info.tag - bp->info.tag);
00233 }
00234 return rc;
00235 }
00236
00241 static
00242 void headerUnsort(Header h)
00243
00244 {
00245 qsort(h->index, h->indexUsed, sizeof(*h->index), offsetCmp);
00246 }
00247
00254 static
00255 unsigned int headerSizeof( Header h, enum hMagic magicp)
00256
00257 {
00258 indexEntry entry;
00259 unsigned int size = 0;
00260 unsigned int pad = 0;
00261 int i;
00262
00263 if (h == NULL)
00264 return size;
00265
00266 headerSort(h);
00267
00268 switch (magicp) {
00269 case HEADER_MAGIC_YES:
00270 size += sizeof(header_magic);
00271 break;
00272 case HEADER_MAGIC_NO:
00273 break;
00274 }
00275
00276
00277 size += 2 * sizeof(int_32);
00278
00279
00280 for (i = 0, entry = h->index; i < h->indexUsed; i++, entry++) {
00281 unsigned diff;
00282 int_32 type;
00283
00284
00285 if (ENTRY_IS_REGION(entry)) {
00286 size += entry->length;
00287
00288
00289 if (i == 0 && (h->flags & HEADERFLAG_LEGACY))
00290 size += sizeof(struct entryInfo) + entry->info.count;
00291
00292 continue;
00293 }
00294
00295
00296 if (entry->info.offset < 0)
00297 continue;
00298
00299
00300 type = entry->info.type;
00301 if (typeSizes[type] > 1) {
00302 diff = typeSizes[type] - (size % typeSizes[type]);
00303 if (diff != typeSizes[type]) {
00304 size += diff;
00305 pad += diff;
00306 }
00307 }
00308
00309
00310 size += sizeof(struct entryInfo) + entry->length;
00311
00312 }
00313
00314 return size;
00315 }
00316
00326
00327 static int dataLength(int_32 type, hPTR_t p, int_32 count, int onDisk)
00328
00329 {
00330 int length = 0;
00331
00332 switch (type) {
00333 case RPM_STRING_TYPE:
00334 if (count == 1) {
00335 length = strlen(p) + 1;
00336 break;
00337 }
00338
00339
00340 fprintf(stderr, _("dataLength() RPM_STRING_TYPE count must be 1.\n"));
00341
00342 exit(EXIT_FAILURE);
00343 break;
00344
00345 case RPM_STRING_ARRAY_TYPE:
00346 case RPM_I18NSTRING_TYPE:
00347 { int i;
00348
00349
00350
00351 i = count;
00352
00353 if (onDisk) {
00354 const char * chptr = p;
00355 int thisLen;
00356
00357 while (i--) {
00358 thisLen = strlen(chptr) + 1;
00359 length += thisLen;
00360 chptr += thisLen;
00361 }
00362 } else {
00363 const char ** src = (const char **)p;
00364 while (i--) {
00365
00366 length += strlen(*src++) + 1;
00367 }
00368 }
00369 } break;
00370
00371 default:
00372 if (typeSizes[type] != -1) {
00373 length = typeSizes[type] * count;
00374 break;
00375 }
00376
00377 fprintf(stderr, _("Data type %d not supported\n"), (int) type);
00378
00379 exit(EXIT_FAILURE);
00380 break;
00381 }
00382
00383 return length;
00384 }
00385
00411 static int regionSwab( indexEntry entry, int il, int dl,
00412 entryInfo pe, char * dataStart, int regionid)
00413
00414 {
00415 char * tprev = NULL;
00416 char * t = NULL;
00417 int tdel, tl = dl;
00418 struct indexEntry ieprev;
00419
00420 memset(&ieprev, 0, sizeof(ieprev));
00421 for (; il > 0; il--, pe++) {
00422 struct indexEntry ie;
00423 int_32 type;
00424
00425 ie.info.tag = ntohl(pe->tag);
00426 ie.info.type = ntohl(pe->type);
00427 if (ie.info.type < RPM_MIN_TYPE || ie.info.type > RPM_MAX_TYPE)
00428 return -1;
00429 ie.info.count = ntohl(pe->count);
00430 ie.info.offset = ntohl(pe->offset);
00431 ie.data = t = dataStart + ie.info.offset;
00432 ie.length = dataLength(ie.info.type, ie.data, ie.info.count, 1);
00433 ie.rdlen = 0;
00434
00435 if (entry) {
00436 ie.info.offset = regionid;
00437 *entry = ie;
00438 entry++;
00439 }
00440
00441
00442 type = ie.info.type;
00443 if (typeSizes[type] > 1) {
00444 unsigned diff;
00445 diff = typeSizes[type] - (dl % typeSizes[type]);
00446 if (diff != typeSizes[type]) {
00447 dl += diff;
00448 if (ieprev.info.type == RPM_I18NSTRING_TYPE)
00449 ieprev.length += diff;
00450 }
00451 }
00452 tdel = (tprev ? (t - tprev) : 0);
00453 if (ieprev.info.type == RPM_I18NSTRING_TYPE)
00454 tdel = ieprev.length;
00455
00456 if (ie.info.tag >= HEADER_I18NTABLE) {
00457 tprev = t;
00458 } else {
00459 tprev = dataStart;
00460
00461
00462 if (ie.info.tag == HEADER_IMAGE)
00463 tprev -= REGION_TAG_COUNT;
00464
00465 }
00466
00467
00468 switch (ntohl(pe->type)) {
00469 case RPM_INT32_TYPE:
00470 { int_32 * it = (int_32 *)t;
00471 for (; ie.info.count > 0; ie.info.count--, it += 1)
00472 *it = htonl(*it);
00473 t = (char *) it;
00474 } break;
00475 case RPM_INT16_TYPE:
00476 { int_16 * it = (int_16 *) t;
00477 for (; ie.info.count > 0; ie.info.count--, it += 1)
00478 *it = htons(*it);
00479 t = (char *) it;
00480 } break;
00481 default:
00482 t += ie.length;
00483 break;
00484 }
00485
00486 dl += ie.length;
00487 tl += tdel;
00488 ieprev = ie;
00489
00490 }
00491 tdel = (tprev ? (t - tprev) : 0);
00492 tl += tdel;
00493
00494
00495
00496
00497
00498
00499
00500 if (tl+REGION_TAG_COUNT == dl)
00501 tl += REGION_TAG_COUNT;
00502
00503
00504 return dl;
00505 }
00506
00509 static void * doHeaderUnload(Header h,
00510 int * lengthPtr)
00511
00512 {
00513 int_32 * ei = NULL;
00514 entryInfo pe;
00515 char * dataStart;
00516 char * te;
00517 unsigned pad;
00518 unsigned len;
00519 int_32 il = 0;
00520 int_32 dl = 0;
00521 indexEntry entry;
00522 int_32 type;
00523 int i;
00524 int drlen, ndribbles;
00525 int driplen, ndrips;
00526 int legacy = 0;
00527
00528
00529 headerUnsort(h);
00530
00531
00532 pad = 0;
00533 drlen = ndribbles = driplen = ndrips = 0;
00534 for (i = 0, entry = h->index; i < h->indexUsed; i++, entry++) {
00535 if (ENTRY_IS_REGION(entry)) {
00536 int_32 rdl = -entry->info.offset;
00537 int_32 ril = rdl/sizeof(*pe);
00538 int rid = entry->info.offset;
00539
00540 il += ril;
00541 dl += entry->rdlen + entry->info.count;
00542
00543 if (i == 0 && (h->flags & HEADERFLAG_LEGACY))
00544 il += 1;
00545
00546
00547 for (; i < h->indexUsed && entry->info.offset <= rid+1; i++, entry++) {
00548 if (entry->info.offset <= rid)
00549 continue;
00550
00551
00552 type = entry->info.type;
00553 if (typeSizes[type] > 1) {
00554 unsigned diff;
00555 diff = typeSizes[type] - (dl % typeSizes[type]);
00556 if (diff != typeSizes[type]) {
00557 drlen += diff;
00558 pad += diff;
00559 dl += diff;
00560 }
00561 }
00562
00563 ndribbles++;
00564 il++;
00565 drlen += entry->length;
00566 dl += entry->length;
00567 }
00568 i--;
00569 entry--;
00570 continue;
00571 }
00572
00573
00574 if (entry->data == NULL || entry->length <= 0)
00575 continue;
00576
00577
00578 type = entry->info.type;
00579 if (typeSizes[type] > 1) {
00580 unsigned diff;
00581 diff = typeSizes[type] - (dl % typeSizes[type]);
00582 if (diff != typeSizes[type]) {
00583 driplen += diff;
00584 pad += diff;
00585 dl += diff;
00586 } else
00587 diff = 0;
00588 }
00589
00590 ndrips++;
00591 il++;
00592 driplen += entry->length;
00593 dl += entry->length;
00594 }
00595
00596
00597 if (hdrchkTags(il) || hdrchkData(dl))
00598 goto errxit;
00599
00600 len = sizeof(il) + sizeof(dl) + (il * sizeof(*pe)) + dl;
00601
00602 ei = xmalloc(len);
00603 ei[0] = htonl(il);
00604 ei[1] = htonl(dl);
00605
00606 pe = (entryInfo) &ei[2];
00607 dataStart = te = (char *) (pe + il);
00608
00609 pad = 0;
00610 for (i = 0, entry = h->index; i < h->indexUsed; i++, entry++) {
00611 const char * src;
00612 char *t;
00613 int count;
00614 int rdlen;
00615
00616 if (entry->data == NULL || entry->length <= 0)
00617 continue;
00618
00619 t = te;
00620 pe->tag = htonl(entry->info.tag);
00621 pe->type = htonl(entry->info.type);
00622 pe->count = htonl(entry->info.count);
00623
00624 if (ENTRY_IS_REGION(entry)) {
00625 int_32 rdl = -entry->info.offset;
00626 int_32 ril = rdl/sizeof(*pe) + ndribbles;
00627 int rid = entry->info.offset;
00628
00629 src = (char *)entry->data;
00630 rdlen = entry->rdlen;
00631
00632
00633 if (i == 0 && (h->flags & HEADERFLAG_LEGACY)) {
00634 int_32 stei[4];
00635
00636 legacy = 1;
00637 memcpy(pe+1, src, rdl);
00638 memcpy(te, src + rdl, rdlen);
00639 te += rdlen;
00640
00641 pe->offset = htonl(te - dataStart);
00642 stei[0] = pe->tag;
00643 stei[1] = pe->type;
00644 stei[2] = htonl(-rdl-entry->info.count);
00645 stei[3] = pe->count;
00646 memcpy(te, stei, entry->info.count);
00647 te += entry->info.count;
00648 ril++;
00649 rdlen += entry->info.count;
00650
00651 count = regionSwab(NULL, ril, 0, pe, t, 0);
00652 if (count != rdlen)
00653 goto errxit;
00654
00655 } else {
00656
00657 memcpy(pe+1, src + sizeof(*pe), ((ril-1) * sizeof(*pe)));
00658 memcpy(te, src + (ril * sizeof(*pe)), rdlen+entry->info.count+drlen);
00659 te += rdlen;
00660 {
00661 entryInfo se = (entryInfo)src;
00662
00663 int off = ntohl(se->offset);
00664 pe->offset = (off) ? htonl(te - dataStart) : htonl(off);
00665 }
00666 te += entry->info.count + drlen;
00667
00668 count = regionSwab(NULL, ril, 0, pe, t, 0);
00669 if (count != (rdlen + entry->info.count + drlen))
00670 goto errxit;
00671 }
00672
00673
00674 while (i < h->indexUsed && entry->info.offset <= rid+1) {
00675 i++;
00676 entry++;
00677 }
00678 i--;
00679 entry--;
00680 pe += ril;
00681 continue;
00682 }
00683
00684
00685 if (entry->data == NULL || entry->length <= 0)
00686 continue;
00687
00688
00689 type = entry->info.type;
00690 if (typeSizes[type] > 1) {
00691 unsigned diff;
00692 diff = typeSizes[type] - ((te - dataStart) % typeSizes[type]);
00693 if (diff != typeSizes[type]) {
00694 memset(te, 0, diff);
00695 te += diff;
00696 pad += diff;
00697 }
00698 }
00699
00700 pe->offset = htonl(te - dataStart);
00701
00702
00703 switch (entry->info.type) {
00704 case RPM_INT32_TYPE:
00705 count = entry->info.count;
00706 src = entry->data;
00707 while (count--) {
00708 *((int_32 *)te) = htonl(*((int_32 *)src));
00709
00710 te += sizeof(int_32);
00711 src += sizeof(int_32);
00712
00713 }
00714 break;
00715
00716 case RPM_INT16_TYPE:
00717 count = entry->info.count;
00718 src = entry->data;
00719 while (count--) {
00720 *((int_16 *)te) = htons(*((int_16 *)src));
00721
00722 te += sizeof(int_16);
00723 src += sizeof(int_16);
00724
00725 }
00726 break;
00727
00728 default:
00729 memcpy(te, entry->data, entry->length);
00730 te += entry->length;
00731 break;
00732 }
00733 pe++;
00734 }
00735
00736
00737 if (((char *)pe) != dataStart)
00738 goto errxit;
00739 if ((((char *)ei)+len) != te)
00740 goto errxit;
00741
00742 if (lengthPtr)
00743 *lengthPtr = len;
00744
00745 h->flags &= ~HEADERFLAG_SORTED;
00746 headerSort(h);
00747
00748 return (void *) ei;
00749
00750 errxit:
00751
00752 ei = _free(ei);
00753
00754 return (void *) ei;
00755 }
00756
00762 static
00763 void * headerUnload(Header h)
00764
00765 {
00766 int length;
00767 void * uh = doHeaderUnload(h, &length);
00768 return uh;
00769 }
00770
00778 static
00779 indexEntry findEntry( Header h, int_32 tag, int_32 type)
00780
00781 {
00782 indexEntry entry, entry2, last;
00783 struct indexEntry key;
00784
00785 if (h == NULL) return NULL;
00786 if (!(h->flags & HEADERFLAG_SORTED)) headerSort(h);
00787
00788 key.info.tag = tag;
00789
00790 entry2 = entry =
00791 bsearch(&key, h->index, h->indexUsed, sizeof(*h->index), indexCmp);
00792 if (entry == NULL)
00793 return NULL;
00794
00795 if (type == RPM_NULL_TYPE)
00796 return entry;
00797
00798
00799 while (entry->info.tag == tag && entry->info.type != type &&
00800 entry > h->index) entry--;
00801
00802 if (entry->info.tag == tag && entry->info.type == type)
00803 return entry;
00804
00805 last = h->index + h->indexUsed;
00806
00807 while (entry2->info.tag == tag && entry2->info.type != type &&
00808 entry2 < last) entry2++;
00809
00810
00811 if (entry->info.tag == tag && entry->info.type == type)
00812 return entry;
00813
00814 return NULL;
00815 }
00816
00826 static
00827 int headerRemoveEntry(Header h, int_32 tag)
00828
00829 {
00830 indexEntry last = h->index + h->indexUsed;
00831 indexEntry entry, first;
00832 int ne;
00833
00834 entry = findEntry(h, tag, RPM_NULL_TYPE);
00835 if (!entry) return 1;
00836
00837
00838 while (entry > h->index && (entry - 1)->info.tag == tag)
00839 entry--;
00840
00841
00842 for (first = entry; first < last; first++) {
00843 void * data;
00844 if (first->info.tag != tag)
00845 break;
00846 data = first->data;
00847 first->data = NULL;
00848 first->length = 0;
00849 if (ENTRY_IN_REGION(first))
00850 continue;
00851 data = _free(data);
00852 }
00853
00854 ne = (first - entry);
00855 if (ne > 0) {
00856 h->indexUsed -= ne;
00857 ne = last - first;
00858 if (ne > 0)
00859 memmove(entry, first, (ne * sizeof(*entry)));
00860 }
00861
00862 return 0;
00863 }
00864
00870 static
00871 Header headerLoad( void * uh)
00872
00873 {
00874 int_32 * ei = (int_32 *) uh;
00875 int_32 il = ntohl(ei[0]);
00876 int_32 dl = ntohl(ei[1]);
00877
00878 size_t pvlen = sizeof(il) + sizeof(dl) +
00879 (il * sizeof(struct entryInfo)) + dl;
00880
00881 void * pv = uh;
00882 Header h = NULL;
00883 entryInfo pe;
00884 char * dataStart;
00885 indexEntry entry;
00886 int rdlen;
00887 int i;
00888
00889
00890 if (hdrchkTags(il) || hdrchkData(dl))
00891 goto errxit;
00892
00893 ei = (int_32 *) pv;
00894
00895 pe = (entryInfo) &ei[2];
00896
00897 dataStart = (char *) (pe + il);
00898
00899 h = xcalloc(1, sizeof(*h));
00900
00901 h->hv = *hdrVec;
00902
00903
00904 h->blob = uh;
00905
00906 h->indexAlloced = il + 1;
00907 h->indexUsed = il;
00908 h->index = xcalloc(h->indexAlloced, sizeof(*h->index));
00909 h->flags = HEADERFLAG_SORTED;
00910 h->nrefs = 0;
00911 h = headerLink(h);
00912
00913
00914
00915
00916
00917 if (ntohl(pe->tag) == 15 &&
00918 ntohl(pe->type) == RPM_STRING_TYPE &&
00919 ntohl(pe->count) == 1)
00920 {
00921 pe->tag = htonl(1079);
00922 }
00923
00924 entry = h->index;
00925 i = 0;
00926 if (!(htonl(pe->tag) < HEADER_I18NTABLE)) {
00927 h->flags |= HEADERFLAG_LEGACY;
00928 entry->info.type = REGION_TAG_TYPE;
00929 entry->info.tag = HEADER_IMAGE;
00930
00931 entry->info.count = REGION_TAG_COUNT;
00932
00933 entry->info.offset = ((char *)pe - dataStart);
00934
00935
00936 entry->data = pe;
00937
00938 entry->length = pvlen - sizeof(il) - sizeof(dl);
00939 rdlen = regionSwab(entry+1, il, 0, pe, dataStart, entry->info.offset);
00940 #if 0
00941 if (rdlen != dl)
00942 goto errxit;
00943 #endif
00944 entry->rdlen = rdlen;
00945 entry++;
00946 h->indexUsed++;
00947 } else {
00948 int nb = ntohl(pe->count);
00949 int_32 rdl;
00950 int_32 ril;
00951
00952 h->flags &= ~HEADERFLAG_LEGACY;
00953
00954 entry->info.type = htonl(pe->type);
00955 if (entry->info.type < RPM_MIN_TYPE || entry->info.type > RPM_MAX_TYPE)
00956 goto errxit;
00957 entry->info.count = htonl(pe->count);
00958
00959 if (hdrchkTags(entry->info.count))
00960 goto errxit;
00961
00962 { int off = ntohl(pe->offset);
00963
00964 if (hdrchkData(off))
00965 goto errxit;
00966 if (off) {
00967 int_32 * stei = memcpy(alloca(nb), dataStart + off, nb);
00968 rdl = -ntohl(stei[2]);
00969 ril = rdl/sizeof(*pe);
00970 if (hdrchkTags(ril) || hdrchkData(rdl))
00971 goto errxit;
00972 entry->info.tag = htonl(pe->tag);
00973 } else {
00974 ril = il;
00975
00976 rdl = (ril * sizeof(struct entryInfo));
00977
00978 entry->info.tag = HEADER_IMAGE;
00979 }
00980 }
00981 entry->info.offset = -rdl;
00982
00983
00984 entry->data = pe;
00985
00986 entry->length = pvlen - sizeof(il) - sizeof(dl);
00987 rdlen = regionSwab(entry+1, ril-1, 0, pe+1, dataStart, entry->info.offset);
00988 if (rdlen < 0)
00989 goto errxit;
00990 entry->rdlen = rdlen;
00991
00992 if (ril < h->indexUsed) {
00993 indexEntry newEntry = entry + ril;
00994 int ne = (h->indexUsed - ril);
00995 int rid = entry->info.offset+1;
00996 int rc;
00997
00998
00999 rc = regionSwab(newEntry, ne, 0, pe+ril, dataStart, rid);
01000 if (rc < 0)
01001 goto errxit;
01002 rdlen += rc;
01003
01004 { indexEntry firstEntry = newEntry;
01005 int save = h->indexUsed;
01006 int j;
01007
01008
01009 h->indexUsed -= ne;
01010 for (j = 0; j < ne; j++, newEntry++) {
01011 (void) headerRemoveEntry(h, newEntry->info.tag);
01012 if (newEntry->info.tag == HEADER_BASENAMES)
01013 (void) headerRemoveEntry(h, HEADER_OLDFILENAMES);
01014 }
01015
01016
01017 if (h->indexUsed < (save - ne)) {
01018 memmove(h->index + h->indexUsed, firstEntry,
01019 (ne * sizeof(*entry)));
01020 }
01021 h->indexUsed += ne;
01022 }
01023 }
01024 }
01025
01026 h->flags &= ~HEADERFLAG_SORTED;
01027 headerSort(h);
01028
01029
01030 return h;
01031
01032
01033 errxit:
01034
01035 if (h) {
01036 h->index = _free(h->index);
01037
01038 h = _free(h);
01039
01040 }
01041
01042
01043 return h;
01044
01045 }
01046
01054 static
01055 Header headerReload( Header h, int tag)
01056
01057 {
01058 Header nh;
01059 int length;
01060
01061 void * uh = doHeaderUnload(h, &length);
01062
01063 h = headerFree(h);
01064
01065 if (uh == NULL)
01066 return NULL;
01067 nh = headerLoad(uh);
01068 if (nh == NULL) {
01069 uh = _free(uh);
01070 return NULL;
01071 }
01072 if (nh->flags & HEADERFLAG_ALLOCATED)
01073 uh = _free(uh);
01074 nh->flags |= HEADERFLAG_ALLOCATED;
01075 if (ENTRY_IS_REGION(nh->index)) {
01076 if (tag == HEADER_SIGNATURES || tag == HEADER_IMMUTABLE)
01077 nh->index[0].info.tag = tag;
01078 }
01079 return nh;
01080 }
01081
01087 static
01088 Header headerCopyLoad(const void * uh)
01089
01090 {
01091 int_32 * ei = (int_32 *) uh;
01092 int_32 il = ntohl(ei[0]);
01093 int_32 dl = ntohl(ei[1]);
01094
01095 size_t pvlen = sizeof(il) + sizeof(dl) +
01096 (il * sizeof(struct entryInfo)) + dl;
01097
01098 void * nuh = NULL;
01099 Header h = NULL;
01100
01101
01102
01103 if (!(hdrchkTags(il) || hdrchkData(dl)) && pvlen < headerMaxbytes) {
01104 nuh = memcpy(xmalloc(pvlen), uh, pvlen);
01105 if ((h = headerLoad(nuh)) != NULL)
01106 h->flags |= HEADERFLAG_ALLOCATED;
01107 }
01108
01109
01110 if (h == NULL)
01111 nuh = _free(nuh);
01112
01113 return h;
01114 }
01115
01122 static
01123 Header headerRead(FD_t fd, enum hMagic magicp)
01124
01125 {
01126 int_32 block[4];
01127 int_32 reserved;
01128 int_32 * ei = NULL;
01129 int_32 il;
01130 int_32 dl;
01131 int_32 magic;
01132 Header h = NULL;
01133 size_t len;
01134 int i;
01135
01136 memset(block, 0, sizeof(block));
01137 i = 2;
01138 if (magicp == HEADER_MAGIC_YES)
01139 i += 2;
01140
01141
01142 if (timedRead(fd, (char *)block, i*sizeof(*block)) != (i * sizeof(*block)))
01143 goto exit;
01144
01145
01146 i = 0;
01147
01148 if (magicp == HEADER_MAGIC_YES) {
01149 magic = block[i++];
01150 if (memcmp(&magic, header_magic, sizeof(magic)))
01151 goto exit;
01152 reserved = block[i++];
01153 }
01154
01155 il = ntohl(block[i]); i++;
01156 dl = ntohl(block[i]); i++;
01157
01158
01159 len = sizeof(il) + sizeof(dl) + (il * sizeof(struct entryInfo)) + dl;
01160
01161
01162
01163 if (hdrchkTags(il) || hdrchkData(dl) || len > headerMaxbytes)
01164 goto exit;
01165
01166 ei = xmalloc(len);
01167 ei[0] = htonl(il);
01168 ei[1] = htonl(dl);
01169 len -= sizeof(il) + sizeof(dl);
01170
01171
01172 if (timedRead(fd, (char *)&ei[2], len) != len)
01173 goto exit;
01174
01175
01176 h = headerLoad(ei);
01177
01178 exit:
01179 if (h) {
01180 if (h->flags & HEADERFLAG_ALLOCATED)
01181 ei = _free(ei);
01182 h->flags |= HEADERFLAG_ALLOCATED;
01183 } else if (ei)
01184 ei = _free(ei);
01185
01186 return h;
01187
01188 }
01189
01197 static
01198 int headerWrite(FD_t fd, Header h, enum hMagic magicp)
01199
01200
01201 {
01202 ssize_t nb;
01203 int length;
01204 const void * uh;
01205
01206 if (h == NULL)
01207 return 1;
01208 uh = doHeaderUnload(h, &length);
01209 if (uh == NULL)
01210 return 1;
01211 switch (magicp) {
01212 case HEADER_MAGIC_YES:
01213
01214 nb = Fwrite(header_magic, sizeof(char), sizeof(header_magic), fd);
01215
01216 if (nb != sizeof(header_magic))
01217 goto exit;
01218 break;
01219 case HEADER_MAGIC_NO:
01220 break;
01221 }
01222
01223
01224 nb = Fwrite(uh, sizeof(char), length, fd);
01225
01226
01227 exit:
01228 uh = _free(uh);
01229 return (nb == length ? 0 : 1);
01230 }
01231
01238 static
01239 int headerIsEntry(Header h, int_32 tag)
01240
01241 {
01242
01243 return (findEntry(h, tag, RPM_NULL_TYPE) ? 1 : 0);
01244
01245 }
01246
01257 static int copyEntry(const indexEntry entry,
01258 hTYP_t type,
01259 hPTR_t * p,
01260 hCNT_t c,
01261 int minMem)
01262
01263 {
01264 int_32 count = entry->info.count;
01265 int rc = 1;
01266
01267 if (p)
01268 switch (entry->info.type) {
01269 case RPM_BIN_TYPE:
01270
01271
01272
01273
01274
01275
01276 if (ENTRY_IS_REGION(entry)) {
01277 int_32 * ei = ((int_32 *)entry->data) - 2;
01278
01279 entryInfo pe = (entryInfo) (ei + 2);
01280
01281 char * dataStart = (char *) (pe + ntohl(ei[0]));
01282 int_32 rdl = -entry->info.offset;
01283 int_32 ril = rdl/sizeof(*pe);
01284
01285
01286 rdl = entry->rdlen;
01287 count = 2 * sizeof(*ei) + (ril * sizeof(*pe)) + rdl;
01288 if (entry->info.tag == HEADER_IMAGE) {
01289 ril -= 1;
01290 pe += 1;
01291 } else {
01292 count += REGION_TAG_COUNT;
01293 rdl += REGION_TAG_COUNT;
01294 }
01295
01296 *p = xmalloc(count);
01297 ei = (int_32 *) *p;
01298 ei[0] = htonl(ril);
01299 ei[1] = htonl(rdl);
01300
01301
01302 pe = (entryInfo) memcpy(ei + 2, pe, (ril * sizeof(*pe)));
01303
01304
01305 dataStart = (char *) memcpy(pe + ril, dataStart, rdl);
01306
01307
01308 rc = regionSwab(NULL, ril, 0, pe, dataStart, 0);
01309
01310 rc = (rc < 0) ? 0 : 1;
01311 } else {
01312 count = entry->length;
01313 *p = (!minMem
01314 ? memcpy(xmalloc(count), entry->data, count)
01315 : entry->data);
01316 }
01317 break;
01318 case RPM_STRING_TYPE:
01319 if (count == 1) {
01320 *p = entry->data;
01321 break;
01322 }
01323
01324 case RPM_STRING_ARRAY_TYPE:
01325 case RPM_I18NSTRING_TYPE:
01326 { const char ** ptrEntry;
01327
01328 int tableSize = count * sizeof(char *);
01329
01330 char * t;
01331 int i;
01332
01333
01334 if (minMem) {
01335 *p = xmalloc(tableSize);
01336 ptrEntry = (const char **) *p;
01337 t = entry->data;
01338 } else {
01339 t = xmalloc(tableSize + entry->length);
01340 *p = (void *)t;
01341 ptrEntry = (const char **) *p;
01342 t += tableSize;
01343 memcpy(t, entry->data, entry->length);
01344 }
01345
01346 for (i = 0; i < count; i++) {
01347 *ptrEntry++ = t;
01348 t = strchr(t, 0);
01349 t++;
01350 }
01351 } break;
01352
01353 default:
01354 *p = entry->data;
01355 break;
01356 }
01357 if (type) *type = entry->info.type;
01358 if (c) *c = count;
01359 return rc;
01360 }
01361
01362 static int
01363 locale_match (const char *sample, const char *l_b, const char *l_e,
01364 char delim)
01365 {
01366 const char *p = l_b;
01367
01368 for (; p < l_e && *p != delim; ++p)
01369 ;
01370 if (p < l_e && !strncmp (sample, l_b, (p - l_b)))
01371 return 1;
01372
01373 return 0;
01374 }
01375
01394 static int
01395 headerMatchLocale (const char *td, const char *l, const char *le,
01396 int strip_lang)
01397
01398 {
01399 switch (strip_lang)
01400 {
01401 case 0:
01402
01403 if (strlen (td) == (le - l)
01404 && !memcmp (td, l, (le - l)))
01405 return 1;
01406 return 0;
01407
01408 case 1:
01409
01410 return locale_match (td, l, le, '@');
01411
01412 case 2:
01413
01414 return locale_match (td, l, le, '.');
01415
01416 default:
01417
01418 return locale_match (td, l, le, '_');
01419 }
01420 }
01421
01422 static char *
01423 convert (char *ed, const char *td, const char *lang)
01424 {
01425 char *saved_ctype = 0, *from_codeset = 0, *to_codeset = 0;
01426 char *saved_ctype1, *from_codeset1, *to_codeset1, *result = 0;
01427 iconv_t icd;
01428
01429 if (!*ed)
01430 return ed;
01431
01432 if ((saved_ctype1 = setlocale (LC_CTYPE, 0)) &&
01433 (saved_ctype = strdup (saved_ctype1)) &&
01434 setlocale (LC_CTYPE, lang) &&
01435 (to_codeset1 = nl_langinfo (CODESET)) &&
01436 (to_codeset = strdup (to_codeset1)) &&
01437 setlocale (LC_CTYPE, td) &&
01438 (from_codeset1 = nl_langinfo (CODESET)) &&
01439 (from_codeset = strdup (from_codeset1)) &&
01440 strcmp (from_codeset, to_codeset) &&
01441 ((icd = iconv_open (to_codeset, from_codeset)) != (iconv_t) - 1))
01442 {
01443 size_t insize = strlen (ed);
01444 size_t inbufleft = insize, outbufleft = insize * 4 + 1;
01445 char buf[outbufleft];
01446 char *inbuf = ed, *outbuf = buf;
01447
01448 if (iconv (icd, &inbuf, &inbufleft, &outbuf, &outbufleft) >= 0)
01449 {
01450 *outbuf = '\0';
01451 if (strcmp (ed, buf))
01452
01453 result = strdup (buf);
01454 }
01455 iconv_close (icd);
01456 }
01457
01458 if (saved_ctype)
01459 setlocale (LC_CTYPE, saved_ctype);
01460 from_codeset = _free (from_codeset);
01461 to_codeset = _free (to_codeset);
01462 saved_ctype = _free (saved_ctype);
01463
01464 return result ? : ed;
01465 }
01466
01473 static char *
01474 headerFindI18NString(Header h, indexEntry entry)
01475
01476 {
01477 const char *lang, *l, *le;
01478 indexEntry table;
01479 int strip_lang;
01480
01481
01482 if ((lang = getenv("LANGUAGE")) == NULL &&
01483 (lang = getenv("LC_ALL")) == NULL &&
01484 (lang = getenv("LC_MESSAGES")) == NULL &&
01485 (lang = getenv("LANG")) == NULL)
01486 return entry->data;
01487
01488
01489 if ((table = findEntry(h, HEADER_I18NTABLE, RPM_STRING_ARRAY_TYPE)) == NULL)
01490 return entry->data;
01491
01492
01493 for (strip_lang = 0; strip_lang < 4; strip_lang++) {
01494 for (l = lang; *l; l = le) {
01495 const char *td;
01496 char *ed;
01497 int langNum;
01498
01499 while (*l && *l == ':')
01500 l++;
01501 if (*l == '\0')
01502 break;
01503 for (le = l; *le && *le != ':'; le++)
01504 ;
01505
01506
01507 for (langNum = 0, td = table->data, ed = entry->data;
01508 langNum < entry->info.count;
01509 langNum++, td += strlen(td) + 1, ed += strlen(ed) + 1) {
01510
01511 if (headerMatchLocale(td, l, le, strip_lang))
01512 return convert( ed, td, lang );
01513 }
01514 }
01515 }
01516
01517 return gettext(entry->data);
01518 }
01519
01530 static int intGetEntry(Header h, int_32 tag,
01531 hTAG_t type,
01532 hPTR_t * p,
01533 hCNT_t c,
01534 int minMem)
01535
01536 {
01537 indexEntry entry;
01538 int rc;
01539
01540
01541
01542 entry = findEntry(h, tag, RPM_NULL_TYPE);
01543
01544 if (entry == NULL) {
01545 if (type) type = 0;
01546 if (p) *p = NULL;
01547 if (c) *c = 0;
01548 return 0;
01549 }
01550
01551 switch (entry->info.type) {
01552 case RPM_I18NSTRING_TYPE:
01553 rc = 1;
01554 if (type) *type = RPM_STRING_TYPE;
01555 if (c) *c = 1;
01556
01557 if (p) *p = headerFindI18NString(h, entry);
01558
01559 break;
01560 default:
01561 rc = copyEntry(entry, type, p, c, minMem);
01562 break;
01563 }
01564
01565
01566 return ((rc == 1) ? 1 : 0);
01567 }
01568
01576 static void * headerFreeTag( Header h,
01577 const void * data, rpmTagType type)
01578
01579 {
01580 if (data) {
01581
01582 if (type == -1 ||
01583 type == RPM_STRING_ARRAY_TYPE ||
01584 type == RPM_I18NSTRING_TYPE ||
01585 type == RPM_BIN_TYPE)
01586 data = _free(data);
01587
01588 }
01589 return NULL;
01590 }
01591
01605 static
01606 int headerGetEntry(Header h, int_32 tag,
01607 hTYP_t type,
01608 void ** p,
01609 hCNT_t c)
01610
01611 {
01612 return intGetEntry(h, tag, type, (hPTR_t *)p, c, 0);
01613 }
01614
01627 static
01628 int headerGetEntryMinMemory(Header h, int_32 tag,
01629 hTYP_t type,
01630 hPTR_t * p,
01631 hCNT_t c)
01632
01633 {
01634 return intGetEntry(h, tag, type, p, c, 1);
01635 }
01636
01637 int headerGetRawEntry(Header h, int_32 tag, int_32 * type, hPTR_t * p,
01638 int_32 * c)
01639 {
01640 indexEntry entry;
01641 int rc;
01642
01643 if (p == NULL) return headerIsEntry(h, tag);
01644
01645
01646
01647 entry = findEntry(h, tag, RPM_NULL_TYPE);
01648
01649 if (!entry) {
01650 if (p) *p = NULL;
01651 if (c) *c = 0;
01652 return 0;
01653 }
01654
01655 rc = copyEntry(entry, type, p, c, 0);
01656
01657
01658 return ((rc == 1) ? 1 : 0);
01659 }
01660
01663 static void copyData(int_32 type, void * dstPtr, const void * srcPtr,
01664 int_32 c, int dataLength)
01665
01666 {
01667 const char ** src;
01668 char * dst;
01669 int i;
01670
01671 switch (type) {
01672 case RPM_STRING_ARRAY_TYPE:
01673 case RPM_I18NSTRING_TYPE:
01674
01675 i = c;
01676 src = (const char **) srcPtr;
01677 dst = dstPtr;
01678 while (i--) {
01679 if (*src) {
01680 int len = strlen(*src) + 1;
01681 memcpy(dst, *src, len);
01682 dst += len;
01683 }
01684 src++;
01685 }
01686 break;
01687
01688 default:
01689 memmove(dstPtr, srcPtr, dataLength);
01690 break;
01691 }
01692 }
01693
01702 static void * grabData(int_32 type, hPTR_t p, int_32 c,
01703 int * lengthPtr)
01704
01705 {
01706 int length = dataLength(type, p, c, 0);
01707 void * data = xmalloc(length);
01708
01709 copyData(type, data, p, c, length);
01710
01711 if (lengthPtr)
01712 *lengthPtr = length;
01713 return data;
01714 }
01715
01730 static
01731 int headerAddEntry(Header h, int_32 tag, int_32 type, const void * p, int_32 c)
01732
01733 {
01734 indexEntry entry;
01735
01736
01737 if (c <= 0)
01738 return 0;
01739
01740
01741 if (h->indexUsed == h->indexAlloced) {
01742 h->indexAlloced += INDEX_MALLOC_SIZE;
01743 h->index = xrealloc(h->index, h->indexAlloced * sizeof(*h->index));
01744 }
01745
01746
01747 entry = h->index + h->indexUsed;
01748 entry->info.tag = tag;
01749 entry->info.type = type;
01750 entry->info.count = c;
01751 entry->info.offset = 0;
01752 entry->data = grabData(type, p, c, &entry->length);
01753
01754 if (h->indexUsed > 0 && tag < h->index[h->indexUsed-1].info.tag)
01755 h->flags &= ~HEADERFLAG_SORTED;
01756 h->indexUsed++;
01757
01758 return 1;
01759 }
01760
01775 static
01776 int headerAppendEntry(Header h, int_32 tag, int_32 type,
01777 const void * p, int_32 c)
01778
01779 {
01780 indexEntry entry;
01781 int length;
01782
01783
01784 entry = findEntry(h, tag, type);
01785 if (!entry)
01786 return 0;
01787
01788 if (type == RPM_STRING_TYPE || type == RPM_I18NSTRING_TYPE) {
01789
01790 return 0;
01791 }
01792
01793 length = dataLength(type, p, c, 0);
01794
01795 if (ENTRY_IN_REGION(entry)) {
01796 char * t = xmalloc(entry->length + length);
01797 memcpy(t, entry->data, entry->length);
01798 entry->data = t;
01799 entry->info.offset = 0;
01800 } else
01801 entry->data = xrealloc(entry->data, entry->length + length);
01802
01803 copyData(type, ((char *) entry->data) + entry->length, p, c, length);
01804
01805 entry->length += length;
01806
01807 entry->info.count += c;
01808
01809 return 1;
01810 }
01811
01822 static
01823 int headerAddOrAppendEntry(Header h, int_32 tag, int_32 type,
01824 const void * p, int_32 c)
01825
01826 {
01827 return (findEntry(h, tag, type)
01828 ? headerAppendEntry(h, tag, type, p, c)
01829 : headerAddEntry(h, tag, type, p, c));
01830 }
01831
01852 static
01853 int headerAddI18NString(Header h, int_32 tag, const char * string,
01854 const char * lang)
01855
01856 {
01857 indexEntry table, entry;
01858 const char ** strArray;
01859 int length;
01860 int ghosts;
01861 int i, langNum;
01862 char * buf;
01863
01864 table = findEntry(h, HEADER_I18NTABLE, RPM_STRING_ARRAY_TYPE);
01865 entry = findEntry(h, tag, RPM_I18NSTRING_TYPE);
01866
01867 if (!table && entry)
01868 return 0;
01869
01870 if (!table && !entry) {
01871 const char * charArray[2];
01872 int count = 0;
01873 if (!lang || (lang[0] == 'C' && lang[1] == '\0')) {
01874
01875 charArray[count++] = "C";
01876
01877 } else {
01878
01879 charArray[count++] = "C";
01880
01881 charArray[count++] = lang;
01882 }
01883 if (!headerAddEntry(h, HEADER_I18NTABLE, RPM_STRING_ARRAY_TYPE,
01884 &charArray, count))
01885 return 0;
01886 table = findEntry(h, HEADER_I18NTABLE, RPM_STRING_ARRAY_TYPE);
01887 }
01888
01889 if (!table)
01890 return 0;
01891
01892 if (!lang) lang = "C";
01893
01894
01895 { const char * l = table->data;
01896 for (langNum = 0; langNum < table->info.count; langNum++) {
01897 if (!strcmp(l, lang)) break;
01898 l += strlen(l) + 1;
01899 }
01900 }
01901
01902 if (langNum >= table->info.count) {
01903 length = strlen(lang) + 1;
01904 if (ENTRY_IN_REGION(table)) {
01905 char * t = xmalloc(table->length + length);
01906 memcpy(t, table->data, table->length);
01907 table->data = t;
01908 table->info.offset = 0;
01909 } else
01910 table->data = xrealloc(table->data, table->length + length);
01911 memmove(((char *)table->data) + table->length, lang, length);
01912 table->length += length;
01913 table->info.count++;
01914 }
01915
01916 if (!entry) {
01917 strArray = alloca(sizeof(*strArray) * (langNum + 1));
01918 for (i = 0; i < langNum; i++)
01919 strArray[i] = "";
01920 strArray[langNum] = string;
01921 return headerAddEntry(h, tag, RPM_I18NSTRING_TYPE, strArray,
01922 langNum + 1);
01923 } else if (langNum >= entry->info.count) {
01924 ghosts = langNum - entry->info.count;
01925
01926 length = strlen(string) + 1 + ghosts;
01927 if (ENTRY_IN_REGION(entry)) {
01928 char * t = xmalloc(entry->length + length);
01929 memcpy(t, entry->data, entry->length);
01930 entry->data = t;
01931 entry->info.offset = 0;
01932 } else
01933 entry->data = xrealloc(entry->data, entry->length + length);
01934
01935 memset(((char *)entry->data) + entry->length, '\0', ghosts);
01936 memmove(((char *)entry->data) + entry->length + ghosts, string, strlen(string)+1);
01937
01938 entry->length += length;
01939 entry->info.count = langNum + 1;
01940 } else {
01941 char *b, *be, *e, *ee, *t;
01942 size_t bn, sn, en;
01943
01944
01945 b = be = e = ee = entry->data;
01946 for (i = 0; i < table->info.count; i++) {
01947 if (i == langNum)
01948 be = ee;
01949 ee += strlen(ee) + 1;
01950 if (i == langNum)
01951 e = ee;
01952 }
01953
01954
01955 bn = (be-b);
01956 sn = strlen(string) + 1;
01957 en = (ee-e);
01958 length = bn + sn + en;
01959 t = buf = xmalloc(length);
01960
01961
01962 memcpy(t, b, bn);
01963 t += bn;
01964
01965 memcpy(t, string, sn);
01966 t += sn;
01967 memcpy(t, e, en);
01968 t += en;
01969
01970
01971
01972 entry->length -= strlen(be) + 1;
01973 entry->length += sn;
01974
01975 if (ENTRY_IN_REGION(entry)) {
01976 entry->info.offset = 0;
01977 } else
01978 entry->data = _free(entry->data);
01979
01980 entry->data = buf;
01981
01982 }
01983
01984 return 0;
01985 }
01986
01997 static
01998 int headerModifyEntry(Header h, int_32 tag, int_32 type,
01999 const void * p, int_32 c)
02000
02001 {
02002 indexEntry entry;
02003 void * oldData;
02004
02005
02006 entry = findEntry(h, tag, type);
02007 if (!entry)
02008 return 0;
02009
02010
02011 while (entry > h->index && (entry - 1)->info.tag == tag)
02012 entry--;
02013
02014
02015
02016 oldData = entry->data;
02017
02018 entry->info.count = c;
02019 entry->info.type = type;
02020 entry->data = grabData(type, p, c, &entry->length);
02021
02022
02023 if (ENTRY_IN_REGION(entry)) {
02024 entry->info.offset = 0;
02025 } else
02026 oldData = _free(oldData);
02027
02028
02029 return 1;
02030 }
02031
02034 static char escapedChar(const char ch)
02035 {
02036 switch (ch) {
02037 case 'a': return '\a';
02038 case 'b': return '\b';
02039 case 'f': return '\f';
02040 case 'n': return '\n';
02041 case 'r': return '\r';
02042 case 't': return '\t';
02043 case 'v': return '\v';
02044 default: return ch;
02045 }
02046 }
02047
02054 static sprintfToken
02055 freeFormat( sprintfToken format, int num)
02056
02057 {
02058 int i;
02059
02060 if (format == NULL) return NULL;
02061 for (i = 0; i < num; i++) {
02062 switch (format[i].type) {
02063 case PTOK_ARRAY:
02064 format[i].u.array.format =
02065 freeFormat(format[i].u.array.format,
02066 format[i].u.array.numTokens);
02067 break;
02068 case PTOK_COND:
02069 format[i].u.cond.ifFormat =
02070 freeFormat(format[i].u.cond.ifFormat,
02071 format[i].u.cond.numIfTokens);
02072 format[i].u.cond.elseFormat =
02073 freeFormat(format[i].u.cond.elseFormat,
02074 format[i].u.cond.numElseTokens);
02075 switch (format[i].u.cond.test.type) {
02076 case TRIVIAL:
02077
02078 break;
02079 case StringTAG_String3:
02080
02081 format[i].u.cond.test.u.tag_str3.headFormat =
02082 freeFormat(format[i].u.cond.test.u.tag_str3.headFormat,
02083 format[i].u.cond.test.u.tag_str3.numHeadTokens);
02084
02085
02086 break;
02087 default:
02088
02089 rpmMessage(RPMMESS_WARNING, _("Unknown test type in \%|?:|; perhaps some memory is leaking right now.\n"));
02090 break;
02091 }
02092 break;
02093 case PTOK_NONE:
02094 case PTOK_TAG:
02095 case PTOK_STRING:
02096 default:
02097 break;
02098 }
02099 }
02100 format = _free(format);
02101 return NULL;
02102 }
02103
02106 static void findTag(char * name, const headerTagTableEntry tags,
02107 const headerSprintfExtension extensions,
02108 headerTagTableEntry * tagMatch,
02109 headerSprintfExtension * extMatch)
02110
02111 {
02112 headerTagTableEntry entry;
02113 headerSprintfExtension ext;
02114 const char * tagname;
02115
02116 *tagMatch = NULL;
02117 *extMatch = NULL;
02118
02119 if (strncmp("RPMTAG_", name, sizeof("RPMTAG_")-1)) {
02120 char * t = alloca(strlen(name) + sizeof("RPMTAG_"));
02121 (void) stpcpy( stpcpy(t, "RPMTAG_"), name);
02122 tagname = t;
02123 } else {
02124 tagname = name;
02125 }
02126
02127
02128 ext = extensions;
02129 while (ext->type != HEADER_EXT_LAST) {
02130 if (ext->name != NULL && ext->type == HEADER_EXT_TAG
02131 && !xstrcasecmp(ext->name, tagname))
02132 break;
02133
02134 if (ext->type == HEADER_EXT_MORE)
02135 ext = ext->u.more;
02136 else
02137 ext++;
02138 }
02139
02140 if (ext->type == HEADER_EXT_TAG) {
02141 *extMatch = ext;
02142 return;
02143 }
02144
02145
02146 for (entry = tags; entry->name; entry++)
02147 if (entry->name && !xstrcasecmp(entry->name, tagname))
02148 break;
02149
02150 if (entry->name) {
02151 *tagMatch = entry;
02152 return;
02153 }
02154 }
02155
02156
02157 static int parseExpression(sprintfToken token, char * str,
02158 const headerTagTableEntry tags,
02159 const headerSprintfExtension extensions,
02160 char ** endPtr, errmsg_t * errmsg)
02161 ;
02162
02165 static int parseFormat(char * str, const headerTagTableEntry tags,
02166 const headerSprintfExtension extensions,
02167 sprintfToken * formatPtr, int * numTokensPtr,
02168 char ** endPtr, int state,
02169 errmsg_t * errmsg)
02170
02171 {
02172 char * chptr, * start, * next, * dst;
02173 sprintfToken format;
02174 int numTokens;
02175 int currToken;
02176 headerTagTableEntry tag;
02177 headerSprintfExtension ext;
02178 int i;
02179 int done = 0;
02180
02181
02182 numTokens = 0;
02183 for (chptr = str; *chptr != '\0'; chptr++)
02184 if (*chptr == '%') numTokens++;
02185 numTokens = numTokens * 2 + 1;
02186
02187 format = xcalloc(numTokens, sizeof(*format));
02188 if (endPtr) *endPtr = NULL;
02189
02190
02191 dst = start = str;
02192 currToken = -1;
02193 while (*start != '\0') {
02194 switch (*start) {
02195 case '%':
02196
02197 if (*(start + 1) == '%') {
02198 if (currToken < 0 || format[currToken].type != PTOK_STRING) {
02199 currToken++;
02200 format[currToken].type = PTOK_STRING;
02201
02202 dst = format[currToken].u.string.string = start;
02203
02204 }
02205
02206 start++;
02207
02208 *dst++ = *start++;
02209
02210 break;
02211 }
02212
02213 currToken++;
02214 *dst++ = '\0';
02215 start++;
02216
02217 if (*start == '|') {
02218 char * newEnd;
02219
02220 start++;
02221 if (parseExpression(format + currToken, start, tags,
02222 extensions, &newEnd, errmsg))
02223 {
02224 format = freeFormat(format, numTokens);
02225 return 1;
02226 }
02227 start = newEnd;
02228 break;
02229 }
02230
02231
02232 format[currToken].u.tag.format = start;
02233
02234 format[currToken].u.tag.pad = 0;
02235 format[currToken].u.tag.justOne = 0;
02236 format[currToken].u.tag.arrayCount = 0;
02237
02238 chptr = start;
02239 while (*chptr && *chptr != '{' && *chptr != '%') chptr++;
02240 if (!*chptr || *chptr == '%') {
02241
02242 if (errmsg) *errmsg = _("missing { after %");
02243
02244 format = freeFormat(format, numTokens);
02245 return 1;
02246 }
02247
02248 *chptr++ = '\0';
02249
02250 while (start < chptr) {
02251 if (xisdigit(*start)) {
02252 i = strtoul(start, &start, 10);
02253 format[currToken].u.tag.pad += i;
02254 } else {
02255 start++;
02256 }
02257 }
02258
02259 if (*start == '=') {
02260 format[currToken].u.tag.justOne = 1;
02261 start++;
02262 } else if (*start == '#') {
02263 format[currToken].u.tag.justOne = 1;
02264 format[currToken].u.tag.arrayCount = 1;
02265 start++;
02266 }
02267
02268 next = start;
02269 while (*next && *next != '}') next++;
02270 if (!*next) {
02271
02272 if (errmsg) *errmsg = _("missing } after %{");
02273
02274 format = freeFormat(format, numTokens);
02275 return 1;
02276 }
02277 *next++ = '\0';
02278
02279 chptr = start;
02280 while (*chptr && *chptr != ':') chptr++;
02281
02282 if (*chptr != '\0') {
02283 *chptr++ = '\0';
02284 if (!*chptr) {
02285
02286 if (errmsg) *errmsg = _("empty tag format");
02287
02288 format = freeFormat(format, numTokens);
02289 return 1;
02290 }
02291
02292 format[currToken].u.tag.type = chptr;
02293
02294 } else {
02295 format[currToken].u.tag.type = NULL;
02296 }
02297
02298 if (!*start) {
02299
02300 if (errmsg) *errmsg = _("empty tag name");
02301
02302 format = freeFormat(format, numTokens);
02303 return 1;
02304 }
02305
02306 i = 0;
02307 findTag(start, tags, extensions, &tag, &ext);
02308
02309 if (tag) {
02310 format[currToken].u.tag.ext = NULL;
02311 format[currToken].u.tag.tag = tag->val;
02312 } else if (ext) {
02313 format[currToken].u.tag.ext = ext->u.tagFunction;
02314 format[currToken].u.tag.extNum = ext - extensions;
02315 } else {
02316
02317 if (errmsg) *errmsg = _("unknown tag");
02318
02319 format = freeFormat(format, numTokens);
02320 return 1;
02321 }
02322
02323 format[currToken].type = PTOK_TAG;
02324
02325 start = next;
02326
02327 break;
02328
02329 case '[':
02330 *dst++ = '\0';
02331 *start++ = '\0';
02332 currToken++;
02333
02334 if (parseFormat(start, tags, extensions,
02335 &format[currToken].u.array.format,
02336 &format[currToken].u.array.numTokens,
02337 &start, PARSER_IN_ARRAY, errmsg)) {
02338 format = freeFormat(format, numTokens);
02339 return 1;
02340 }
02341
02342 if (!start) {
02343
02344 if (errmsg) *errmsg = _("] expected at end of array");
02345
02346 format = freeFormat(format, numTokens);
02347 return 1;
02348 }
02349
02350 dst = start;
02351
02352 format[currToken].type = PTOK_ARRAY;
02353
02354 break;
02355
02356 case ']':
02357 case '}':
02358 if ((*start == ']' && state != PARSER_IN_ARRAY) ||
02359 (*start == '}' && state != PARSER_IN_EXPR)) {
02360 if (*start == ']') {
02361
02362 if (errmsg) *errmsg = _("unexpected ]");
02363
02364 } else {
02365
02366 if (errmsg) *errmsg = _("unexpected }");
02367
02368 }
02369 format = freeFormat(format, numTokens);
02370 return 1;
02371 }
02372 *start++ = '\0';
02373 if (endPtr) *endPtr = start;
02374 done = 1;
02375 break;
02376
02377 default:
02378 if (currToken < 0 || format[currToken].type != PTOK_STRING) {
02379 currToken++;
02380 format[currToken].type = PTOK_STRING;
02381
02382 dst = format[currToken].u.string.string = start;
02383
02384 }
02385
02386 if (*start == '\\') {
02387 start++;
02388 *dst++ = escapedChar(*start++);
02389 } else {
02390 *dst++ = *start++;
02391 }
02392 break;
02393 }
02394 if (done)
02395 break;
02396 }
02397
02398
02399 *dst = '\0';
02400
02401 currToken++;
02402 for (i = 0; i < currToken; i++) {
02403 if (format[i].type == PTOK_STRING)
02404 format[i].u.string.len = strlen(format[i].u.string.string);
02405 }
02406
02407 *numTokensPtr = currToken;
02408 *formatPtr = format;
02409
02410 return 0;
02411 }
02412
02415 static int parseExpression(sprintfToken token, char * str,
02416 const headerTagTableEntry tags,
02417 const headerSprintfExtension extensions,
02418 char ** endPtr,
02419 errmsg_t * errmsg)
02420 {
02421 headerTagTableEntry tag;
02422 headerSprintfExtension ext;
02423 char * chptr;
02424 char * end;
02425
02426 if (errmsg) *errmsg = NULL;
02427 chptr = str;
02428 while (*chptr && *chptr != '?') chptr++;
02429
02430 if (*chptr != '?') {
02431
02432 if (errmsg) *errmsg = _("? expected in expression");
02433
02434 return 1;
02435 }
02436
02437 *chptr++ = '\0';;
02438
02439 if (*chptr != '{') {
02440
02441 if (errmsg) *errmsg = _("{ expected after ? in expression");
02442
02443 return 1;
02444 }
02445
02446 chptr++;
02447
02448 if (parseFormat(chptr, tags, extensions, &token->u.cond.ifFormat,
02449 &token->u.cond.numIfTokens, &end, PARSER_IN_EXPR, errmsg))
02450 return 1;
02451
02452 if (!end || !*end) {
02453
02454 if (errmsg) *errmsg = _("} expected in expression");
02455
02456 token->u.cond.ifFormat =
02457 freeFormat(token->u.cond.ifFormat, token->u.cond.numIfTokens);
02458 return 1;
02459 }
02460
02461 chptr = end;
02462 if (*chptr != ':' && *chptr != '|') {
02463
02464 if (errmsg) *errmsg = _(": expected following ? subexpression");
02465
02466 token->u.cond.ifFormat =
02467 freeFormat(token->u.cond.ifFormat, token->u.cond.numIfTokens);
02468 return 1;
02469 }
02470
02471 if (*chptr == '|') {
02472 (void) parseFormat(xstrdup(""), tags, extensions,
02473 &token->u.cond.elseFormat,
02474 &token->u.cond.numElseTokens, &end, PARSER_IN_EXPR,
02475 errmsg);
02476 } else {
02477 chptr++;
02478
02479 if (*chptr != '{') {
02480
02481 if (errmsg) *errmsg = _("{ expected after : in expression");
02482
02483 token->u.cond.ifFormat =
02484 freeFormat(token->u.cond.ifFormat, token->u.cond.numIfTokens);
02485 return 1;
02486 }
02487
02488 chptr++;
02489
02490 if (parseFormat(chptr, tags, extensions, &token->u.cond.elseFormat,
02491 &token->u.cond.numElseTokens, &end, PARSER_IN_EXPR,
02492 errmsg))
02493 return 1;
02494 if (!end || !*end) {
02495
02496 if (errmsg) *errmsg = _("} expected in expression");
02497
02498 token->u.cond.ifFormat =
02499 freeFormat(token->u.cond.ifFormat, token->u.cond.numIfTokens);
02500 return 1;
02501 }
02502
02503 chptr = end;
02504 if (*chptr != '|') {
02505
02506 if (errmsg) *errmsg = _("| expected at end of expression");
02507
02508 token->u.cond.ifFormat =
02509 freeFormat(token->u.cond.ifFormat, token->u.cond.numIfTokens);
02510 token->u.cond.elseFormat =
02511 freeFormat(token->u.cond.elseFormat, token->u.cond.numElseTokens);
02512 return 1;
02513 }
02514 }
02515
02516 chptr++;
02517
02518 *endPtr = chptr;
02519
02520 {
02521
02522 char * str2 = strchr(str,'>');
02523 if (str2) {
02524 char * endOfParsed = NULL;
02525 rpmMessage(RPMMESS_WARNING, _("Parsing non-standard test (>) for \%|?{}:{}|.\n"));
02526 *str2 ='\0';
02527 ++str2;
02528
02529 if ( parseFormat(str, tags, extensions,
02530 &token->u.cond.test.u.tag_str3.headFormat,
02531 &token->u.cond.test.u.tag_str3.numHeadTokens,
02532 &endOfParsed, PARSER_IN_EXPR, errmsg)
02533 )
02534 {
02535
02536 if (errmsg
02537 && ! *errmsg )
02538 *errmsg = _("the left part of >-expr finished before the > sign");
02539
02540 token->u.cond.ifFormat =
02541 freeFormat(token->u.cond.ifFormat, token->u.cond.numIfTokens);
02542 token->u.cond.elseFormat =
02543 freeFormat(token->u.cond.elseFormat, token->u.cond.numElseTokens);
02544 return 1;
02545 }
02546
02547 token->u.cond.test.type = StringTAG_String3;
02548 token->u.cond.test.u.tag_str3.predicate = &isChangeNameMoreFresh;
02549
02550 parseEVR(str2,
02551 &token->u.cond.test.u.tag_str3.tail[0],
02552 &token->u.cond.test.u.tag_str3.tail[1],
02553 &token->u.cond.test.u.tag_str3.tail[2]);
02554
02555
02556 rpmMessage(RPMMESS_DEBUG, "Will cmp with e=%s, v=%s, r=%s\n",
02557 token->u.cond.test.u.tag_str3.tail[0],
02558 token->u.cond.test.u.tag_str3.tail[1],
02559 token->u.cond.test.u.tag_str3.tail[2]);
02560 }
02561 else {
02562 struct sprintfTag head;
02563 rpmMessage(RPMMESS_DEBUG, _("The usual way of parsing the test part for \%|?:|\n"));
02564 findTag(str, tags, extensions, &tag, &ext);
02565 if (tag) {
02566 head.ext = NULL;
02567 head.tag = tag->val;
02568 } else if (ext) {
02569 head.ext = ext->u.tagFunction;
02570 head.extNum = ext - extensions;
02571 } else {
02572 head.ext = NULL;
02573 head.tag = -1;
02574 }
02575 token->u.cond.test.type = TRIVIAL;
02576 token->u.cond.test.u.tag = head;
02577 }
02578
02579 }
02580
02581 token->type = PTOK_COND;
02582
02583 return 0;
02584 }
02585
02589 static int getExtension(Header h, headerTagTagFunction fn,
02590 hTYP_t typeptr,
02591 hPTR_t * data,
02592 hCNT_t countptr,
02593 extensionCache ext)
02594
02595 {
02596 if (!ext->avail) {
02597 if (fn(h, &ext->type, &ext->data, &ext->count, &ext->freeit))
02598 return 1;
02599 ext->avail = 1;
02600 }
02601
02602 if (typeptr) *typeptr = ext->type;
02603 if (data) *data = ext->data;
02604 if (countptr) *countptr = ext->count;
02605
02606 return 0;
02607 }
02608
02611 static char * formatValue(sprintfTag tag, Header h,
02612 const headerSprintfExtension extensions,
02613 extensionCache extCache, int element,
02614 char ** valp, int * vallenp, int * allocedp)
02615
02616 {
02617 char * val = NULL;
02618 int need = 0;
02619 char * t, * te;
02620 char buf[20];
02621 int_32 count, type;
02622 hPTR_t data;
02623 unsigned int intVal;
02624 const char ** strarray;
02625 int datafree = 0;
02626 int countBuf;
02627 headerTagFormatFunction tagtype = NULL;
02628 headerSprintfExtension ext;
02629
02630 memset(buf, 0, sizeof(buf));
02631
02632 if (tag->ext) {
02633 if (getExtension(h, tag->ext, &type, &data, &count,
02634 extCache + tag->extNum))
02635 {
02636 count = 1;
02637 type = RPM_STRING_TYPE;
02638 data = "(none)";
02639 }
02640 } else {
02641 if (!headerGetEntry(h, tag->tag, &type, (void **)&data, &count)) {
02642 count = 1;
02643 type = RPM_STRING_TYPE;
02644 data = "(none)";
02645 }
02646
02647 datafree = 1;
02648 }
02649
02650
02651 if (tag->arrayCount) {
02652
02653 data = headerFreeData(data, type);
02654
02655
02656 countBuf = count;
02657 data = &countBuf;
02658 count = 1;
02659 type = RPM_INT32_TYPE;
02660 }
02661
02662 (void) stpcpy( stpcpy(buf, "%"), tag->format);
02663
02664 if (tag->type) {
02665 ext = extensions;
02666 while (ext->type != HEADER_EXT_LAST) {
02667 if (ext->name != NULL && ext->type == HEADER_EXT_FORMAT
02668 && !strcmp(ext->name, tag->type))
02669 {
02670 tagtype = ext->u.formatFunction;
02671 break;
02672 }
02673
02674 if (ext->type == HEADER_EXT_MORE)
02675 ext = ext->u.more;
02676 else
02677 ext++;
02678 }
02679 }
02680
02681
02682 switch (type) {
02683 case RPM_STRING_ARRAY_TYPE:
02684 strarray = (const char **)data;
02685
02686 if (tagtype)
02687 val = tagtype(RPM_STRING_TYPE, strarray[element], buf, tag->pad, 0);
02688
02689 if (val) {
02690 need = strlen(val);
02691 } else {
02692 need = strlen(strarray[element]) + tag->pad + 20;
02693 val = xmalloc(need+1);
02694 strcat(buf, "s");
02695
02696 sprintf(val, buf, strarray[element]);
02697
02698 }
02699
02700
02701 if (datafree) data = _free(data);
02702
02703
02704 break;
02705
02706 case RPM_STRING_TYPE:
02707 if (tagtype)
02708 val = tagtype(RPM_STRING_ARRAY_TYPE, data, buf, tag->pad, 0);
02709
02710 if (val) {
02711 need = strlen(val);
02712 } else {
02713 need = strlen(data) + tag->pad + 20;
02714 val = xmalloc(need+1);
02715 strcat(buf, "s");
02716
02717 sprintf(val, buf, data);
02718
02719 }
02720 break;
02721
02722 case RPM_CHAR_TYPE:
02723 case RPM_INT8_TYPE:
02724 case RPM_INT16_TYPE:
02725 case RPM_INT32_TYPE:
02726 switch (type) {
02727 case RPM_CHAR_TYPE:
02728 case RPM_INT8_TYPE:
02729 intVal = *(((int_8 *) data) + element);
02730 break;
02731 case RPM_INT16_TYPE:
02732 intVal = *(((uint_16 *) data) + element);
02733 break;
02734 default:
02735 case RPM_INT32_TYPE:
02736 intVal = *(((int_32 *) data) + element);
02737 break;
02738 }
02739
02740 if (tagtype)
02741 val = tagtype(RPM_INT32_TYPE, &intVal, buf, tag->pad, element);
02742
02743 if (val) {
02744 need = strlen(val);
02745 } else {
02746 need = 10 + tag->pad + 20;
02747 val = xmalloc(need+1);
02748 strcat(buf, "d");
02749
02750 sprintf(val, buf, intVal);
02751
02752 }
02753 break;
02754
02755 case RPM_BIN_TYPE:
02756 if (tagtype)
02757 val = tagtype(RPM_BIN_TYPE, data, buf, tag->pad, count);
02758
02759 if (val) {
02760 need = count;
02761 } else {
02762 #ifdef NOTYET
02763 val = memcpy(xmalloc(count), data, count);
02764 #else
02765
02766 static char hex[] = "0123456789abcdef";
02767 const char * s = data;
02768
02769 need = 2*count + tag->pad;
02770 val = t = xmalloc(need+1);
02771 while (count-- > 0) {
02772 unsigned int i;
02773 i = *s++;
02774 *t++ = hex[ (i >> 4) & 0xf ];
02775 *t++ = hex[ (i ) & 0xf ];
02776 }
02777 *t = '\0';
02778 #endif
02779 }
02780 break;
02781
02782 default:
02783 need = sizeof("(unknown type)") - 1;
02784 val = xstrdup("(unknown type)");
02785 break;
02786 }
02787
02788
02789 if (val && need > 0) {
02790 if (((*vallenp) + need) >= (*allocedp)) {
02791 if ((*allocedp) <= need)
02792 (*allocedp) += need;
02793 (*allocedp) <<= 1;
02794 (*valp) = xrealloc((*valp), (*allocedp)+1);
02795 }
02796 t = (*valp) + (*vallenp);
02797 te = stpcpy(t, val);
02798 (*vallenp) += (te - t);
02799 val = _free(val);
02800 }
02801
02802 return ((*valp) + (*vallenp));
02803 }
02804
02807 static char * singleSprintf(Header h, sprintfToken token,
02808 const headerSprintfExtension extensions,
02809 extensionCache extCache, int element,
02810 char ** valp, int * vallenp, int * allocedp)
02811
02812 {
02813 char * t, * te;
02814 int i, j;
02815 int numElements;
02816 int type;
02817 sprintfToken condFormat;
02818 int condNumFormats;
02819 int need;
02820
02821
02822
02823 switch (token->type) {
02824 case PTOK_NONE:
02825 break;
02826
02827 case PTOK_STRING:
02828 need = token->u.string.len;
02829 if (need <= 0) break;
02830 if (((*vallenp) + need) >= (*allocedp)) {
02831 if ((*allocedp) <= need)
02832 (*allocedp) += need;
02833 (*allocedp) <<= 1;
02834 (*valp) = xrealloc((*valp), (*allocedp)+1);
02835 }
02836 t = (*valp) + (*vallenp);
02837 te = stpcpy(t, token->u.string.string);
02838 (*vallenp) += (te - t);
02839 break;
02840
02841 case PTOK_TAG:
02842 t = (*valp) + (*vallenp);
02843 te = formatValue(&token->u.tag, h, extensions, extCache,
02844 (token->u.tag.justOne ? 0 : element),
02845 valp, vallenp, allocedp);
02846 break;
02847
02848 case PTOK_COND:
02849 {
02850 int testResult = 0;
02851 switch (token->u.cond.test.type) {
02852 case TRIVIAL:
02853 testResult = token->u.cond.test.u.tag.ext ||
02854 headerIsEntry(h, token->u.cond.test.u.tag.tag);
02855 break;
02856 case StringTAG_String3:
02857 {
02858 char * head = NULL; int head_en = 0;
02859 int head_alloced = 0;
02860 head = xstrdup("");
02861 for (i = 0; i < token->u.cond.test.u.tag_str3.numHeadTokens; i++)
02862
02863 singleSprintf(h, token->u.cond.test.u.tag_str3.headFormat + i,
02864 extensions, extCache,
02865 element, &head, &head_en, &head_alloced);
02866 if (head != NULL && head_en < head_alloced)
02867 head = xrealloc(head, head_en+1);
02868 testResult = head
02869 && token->u.cond.test.u.tag_str3.predicate(head, token->u.cond.test.u.tag_str3.tail);
02870
02871 _free(head);
02872 }
02873 break;
02874 default:
02875
02876 rpmMessage(RPMMESS_WARNING, _("Unknown test type in \%|?:|; assuming false.\n"));
02877 testResult = 0;
02878 break;
02879 }
02880
02881 if (testResult) {
02882 condFormat = token->u.cond.ifFormat;
02883 condNumFormats = token->u.cond.numIfTokens;
02884 } else {
02885 condFormat = token->u.cond.elseFormat;
02886 condNumFormats = token->u.cond.numElseTokens;
02887 }
02888 }
02889
02890 need = condNumFormats * 20;
02891 if (condFormat == NULL || need <= 0) break;
02892 if (((*vallenp) + need) >= (*allocedp)) {
02893 if ((*allocedp) <= need)
02894 (*allocedp) += need;
02895 (*allocedp) <<= 1;
02896 (*valp) = xrealloc((*valp), (*allocedp)+1);
02897 }
02898
02899 t = (*valp) + (*vallenp);
02900 for (i = 0; i < condNumFormats; i++)
02901 te = singleSprintf(h, condFormat + i, extensions, extCache,
02902 element, valp, vallenp, allocedp);
02903 break;
02904
02905 case PTOK_ARRAY:
02906 numElements = -1;
02907 for (i = 0; i < token->u.array.numTokens; i++) {
02908 if (token->u.array.format[i].type != PTOK_TAG ||
02909 token->u.array.format[i].u.tag.arrayCount ||
02910 token->u.array.format[i].u.tag.justOne) continue;
02911
02912 if (token->u.array.format[i].u.tag.ext) {
02913 const void * data;
02914 if (getExtension(h, token->u.array.format[i].u.tag.ext,
02915 &type, &data, &numElements,
02916 extCache +
02917 token->u.array.format[i].u.tag.extNum))
02918 continue;
02919 } else {
02920 if (!headerGetEntry(h, token->u.array.format[i].u.tag.tag,
02921 &type, NULL, &numElements))
02922 continue;
02923 }
02924 break;
02925 }
02926
02927 if (numElements == -1) {
02928 need = sizeof("(none)") - 1;
02929 if (((*vallenp) + need) >= (*allocedp)) {
02930 if ((*allocedp) <= need)
02931 (*allocedp) += need;
02932 (*allocedp) <<= 1;
02933 (*valp) = xrealloc((*valp), (*allocedp)+1);
02934 }
02935 t = (*valp) + (*vallenp);
02936 te = stpcpy(t, "(none)");
02937 (*vallenp) += (te - t);
02938 } else {
02939 need = numElements * token->u.array.numTokens * 10;
02940 if (need <= 0) break;
02941 if (((*vallenp) + need) >= (*allocedp)) {
02942 if ((*allocedp) <= need)
02943 (*allocedp) += need;
02944 (*allocedp) <<= 1;
02945 (*valp) = xrealloc((*valp), (*allocedp)+1);
02946 }
02947
02948 t = (*valp) + (*vallenp);
02949 for (j = 0; j < numElements; j++) {
02950 for (i = 0; i < token->u.array.numTokens; i++)
02951 te = singleSprintf(h, token->u.array.format + i,
02952 extensions, extCache, j,
02953 valp, vallenp, allocedp);
02954 }
02955 }
02956 break;
02957 }
02958
02959 return ((*valp) + (*vallenp));
02960 }
02961
02964 static extensionCache
02965 allocateExtensionCache(const headerSprintfExtension extensions)
02966
02967 {
02968 headerSprintfExtension ext = extensions;
02969 int i = 0;
02970
02971 while (ext->type != HEADER_EXT_LAST) {
02972 i++;
02973 if (ext->type == HEADER_EXT_MORE)
02974 ext = ext->u.more;
02975 else
02976 ext++;
02977 }
02978
02979
02980 return xcalloc(i, sizeof(struct extensionCache));
02981
02982 }
02983
02987 static extensionCache
02988 freeExtensionCache(const headerSprintfExtension extensions,
02989 extensionCache cache)
02990
02991 {
02992 headerSprintfExtension ext = extensions;
02993 int i = 0;
02994
02995 while (ext->type != HEADER_EXT_LAST) {
02996 if (cache[i].freeit) cache[i].data = _free(cache[i].data);
02997
02998 i++;
02999 if (ext->type == HEADER_EXT_MORE)
03000 ext = ext->u.more;
03001 else
03002 ext++;
03003 }
03004
03005 cache = _free(cache);
03006 return NULL;
03007 }
03008
03020 static
03021 char * headerSprintf(Header h, const char * fmt,
03022 const struct headerTagTableEntry_s * tbltags,
03023 const struct headerSprintfExtension_s * extensions,
03024 errmsg_t * errmsg)
03025
03026 {
03027
03028 headerSprintfExtension exts = (headerSprintfExtension) extensions;
03029 headerTagTableEntry tags = (headerTagTableEntry) tbltags;
03030
03031 char * t;
03032 char * fmtString;
03033 sprintfToken format;
03034 int numTokens;
03035 char * val = NULL;
03036 int vallen = 0;
03037 int alloced = 0;
03038 int i;
03039 extensionCache extCache;
03040
03041
03042 fmtString = xstrdup(fmt);
03043
03044 if (parseFormat(fmtString, tags, exts, &format, &numTokens,
03045 NULL, PARSER_BEGIN, errmsg)) {
03046 fmtString = _free(fmtString);
03047 return NULL;
03048 }
03049
03050 extCache = allocateExtensionCache(exts);
03051
03052 val = xstrdup("");
03053 for (i = 0; i < numTokens; i++) {
03054
03055 t = singleSprintf(h, format + i, exts, extCache, 0,
03056 &val, &vallen, &alloced);
03057
03058 }
03059
03060 if (val != NULL && vallen < alloced)
03061 val = xrealloc(val, vallen+1);
03062
03063 fmtString = _free(fmtString);
03064 extCache = freeExtensionCache(exts, extCache);
03065 format = _free(format);
03066
03067 return val;
03068 }
03069
03072 static char * octalFormat(int_32 type, hPTR_t data,
03073 char * formatPrefix, int padding, int element)
03074
03075 {
03076 char * val;
03077
03078 if (type != RPM_INT32_TYPE) {
03079 val = xstrdup(_("(not a number)"));
03080 } else {
03081 val = xmalloc(20 + padding);
03082 strcat(formatPrefix, "o");
03083
03084 sprintf(val, formatPrefix, *((int_32 *) data));
03085
03086 }
03087
03088 return val;
03089 }
03090
03093 static char * hexFormat(int_32 type, hPTR_t data,
03094 char * formatPrefix, int padding, int element)
03095
03096 {
03097 char * val;
03098
03099 if (type != RPM_INT32_TYPE) {
03100 val = xstrdup(_("(not a number)"));
03101 } else {
03102 val = xmalloc(20 + padding);
03103 strcat(formatPrefix, "x");
03104
03105 sprintf(val, formatPrefix, *((int_32 *) data));
03106
03107 }
03108
03109 return val;
03110 }
03111
03114 static char * realDateFormat(int_32 type, hPTR_t data,
03115 char * formatPrefix, int padding, int element,
03116 const char * strftimeFormat)
03117
03118 {
03119 char * val;
03120
03121 if (type != RPM_INT32_TYPE) {
03122 val = xstrdup(_("(not a number)"));
03123 } else {
03124 struct tm * tstruct;
03125 char buf[50];
03126
03127 val = xmalloc(50 + padding);
03128 strcat(formatPrefix, "s");
03129
03130
03131 { time_t dateint = *((int_32 *) data);
03132 tstruct = localtime(&dateint);
03133 }
03134 buf[0] = '\0';
03135 if (tstruct)
03136 (void) strftime(buf, sizeof(buf) - 1, strftimeFormat, tstruct);
03137
03138 sprintf(val, formatPrefix, buf);
03139
03140 }
03141
03142 return val;
03143 }
03144
03147 static char * dateFormat(int_32 type, hPTR_t data,
03148 char * formatPrefix, int padding, int element)
03149
03150 {
03151 return realDateFormat(type, data, formatPrefix, padding, element, "%c");
03152 }
03153
03156 static char * dayFormat(int_32 type, hPTR_t data,
03157 char * formatPrefix, int padding, int element)
03158
03159 {
03160 return realDateFormat(type, data, formatPrefix, padding, element,
03161 "%a %b %d %Y");
03162 }
03163
03166 static char * shescapeFormat(int_32 type, hPTR_t data,
03167 char * formatPrefix, int padding, int element)
03168
03169 {
03170 char * result, * dst, * src, * buf;
03171
03172 if (type == RPM_INT32_TYPE) {
03173 result = xmalloc(padding + 20);
03174 strcat(formatPrefix, "d");
03175
03176 sprintf(result, formatPrefix, *((int_32 *) data));
03177
03178 } else {
03179 buf = alloca(strlen(data) + padding + 2);
03180 strcat(formatPrefix, "s");
03181
03182 sprintf(buf, formatPrefix, data);
03183
03184
03185 result = dst = xmalloc(strlen(buf) * 4 + 3);
03186 *dst++ = '\'';
03187 for (src = buf; *src != '\0'; src++) {
03188 if (*src == '\'') {
03189 *dst++ = '\'';
03190 *dst++ = '\\';
03191 *dst++ = '\'';
03192 *dst++ = '\'';
03193 } else {
03194 *dst++ = *src;
03195 }
03196 }
03197 *dst++ = '\'';
03198 *dst = '\0';
03199
03200 }
03201
03202 return result;
03203 }
03204
03205
03206 const struct headerSprintfExtension_s headerDefaultFormats[] = {
03207 { HEADER_EXT_FORMAT, "octal", { octalFormat } },
03208 { HEADER_EXT_FORMAT, "hex", { hexFormat } },
03209 { HEADER_EXT_FORMAT, "date", { dateFormat } },
03210 { HEADER_EXT_FORMAT, "day", { dayFormat } },
03211 { HEADER_EXT_FORMAT, "shescape", { shescapeFormat } },
03212 { HEADER_EXT_LAST, NULL, { NULL } }
03213 };
03214
03215
03222 static
03223 void headerCopyTags(Header headerFrom, Header headerTo, hTAG_t tagstocopy)
03224
03225 {
03226 int * p;
03227
03228 if (headerFrom == headerTo)
03229 return;
03230
03231 for (p = tagstocopy; *p != 0; p++) {
03232 char *s;
03233 int_32 type;
03234 int_32 count;
03235 if (headerIsEntry(headerTo, *p))
03236 continue;
03237 if (!headerGetEntryMinMemory(headerFrom, *p, &type,
03238 (hPTR_t *) &s, &count))
03239 continue;
03240 (void) headerAddEntry(headerTo, *p, type, s, count);
03241 s = headerFreeData(s, type);
03242 }
03243 }
03244
03248 struct headerIteratorS {
03249 Header h;
03250 int next_index;
03251 };
03252
03258 static
03259 HeaderIterator headerFreeIterator( HeaderIterator hi)
03260
03261 {
03262 hi->h = headerFree(hi->h);
03263 hi = _free(hi);
03264 return hi;
03265 }
03266
03272 static
03273 HeaderIterator headerInitIterator(Header h)
03274
03275 {
03276 HeaderIterator hi = xmalloc(sizeof(*hi));
03277
03278 headerSort(h);
03279
03280 hi->h = headerLink(h);
03281 hi->next_index = 0;
03282 return hi;
03283 }
03284
03294 static
03295 int headerNextIterator(HeaderIterator hi,
03296 hTAG_t tag,
03297 hTYP_t type,
03298 hPTR_t * p,
03299 hCNT_t c)
03300
03301 {
03302 Header h = hi->h;
03303 int slot = hi->next_index;
03304 indexEntry entry = NULL;
03305 int rc;
03306
03307 for (slot = hi->next_index; slot < h->indexUsed; slot++) {
03308 entry = h->index + slot;
03309 if (!ENTRY_IS_REGION(entry))
03310 break;
03311 }
03312 hi->next_index = slot;
03313 if (entry == NULL || slot >= h->indexUsed)
03314 return 0;
03315
03316 hi->next_index++;
03317
03318
03319 if (tag)
03320 *tag = entry->info.tag;
03321
03322 rc = copyEntry(entry, type, p, c, 0);
03323
03324
03325 return ((rc == 1) ? 1 : 0);
03326 }
03327
03333 static
03334 Header headerCopy(Header h)
03335
03336 {
03337 Header nh = headerNew();
03338 HeaderIterator hi;
03339 int_32 tag, type, count;
03340 hPTR_t ptr;
03341
03342
03343 for (hi = headerInitIterator(h);
03344 headerNextIterator(hi, &tag, &type, &ptr, &count);
03345 ptr = headerFreeData((void *)ptr, type))
03346 {
03347 if (ptr) (void) headerAddEntry(nh, tag, type, ptr, count);
03348 }
03349 hi = headerFreeIterator(hi);
03350
03351
03352 return headerReload(nh, HEADER_IMAGE);
03353 }
03354
03355
03356 static struct HV_s hdrVec1 = {
03357 headerNew,
03358 headerFree,
03359 headerLink,
03360 headerSort,
03361 headerUnsort,
03362 headerSizeof,
03363 headerUnload,
03364 headerReload,
03365 headerCopy,
03366 headerLoad,
03367 headerCopyLoad,
03368 headerRead,
03369 headerWrite,
03370 headerIsEntry,
03371 headerFreeTag,
03372 headerGetEntry,
03373 headerGetEntryMinMemory,
03374 headerAddEntry,
03375 headerAppendEntry,
03376 headerAddOrAppendEntry,
03377 headerAddI18NString,
03378 headerModifyEntry,
03379 headerRemoveEntry,
03380 headerSprintf,
03381 headerCopyTags,
03382 headerFreeIterator,
03383 headerInitIterator,
03384 headerNextIterator,
03385 headerUnlink,
03386 NULL, NULL,
03387 1
03388 };
03389
03390
03391
03392 HV_t hdrVec = &hdrVec1;
03393