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 int _hdr_debug = 0;
00021
00022
00023
00024
00025
00026
00027
00028
00029
00030 #define PARSER_BEGIN 0
00031 #define PARSER_IN_ARRAY 1
00032 #define PARSER_IN_EXPR 2
00033
00036
00037 static unsigned char header_magic[8] = {
00038 0x8e, 0xad, 0xe8, 0x01, 0x00, 0x00, 0x00, 0x00
00039 };
00040
00044
00045 static int typeAlign[16] = {
00046 1,
00047 1,
00048 1,
00049 2,
00050 4,
00051 8,
00052 1,
00053 1,
00054 1,
00055 1,
00056 0,
00057 0,
00058 0,
00059 0,
00060 0,
00061 0
00062 };
00063
00067
00068 static int typeSizes[16] = {
00069 0,
00070 1,
00071 1,
00072 2,
00073 4,
00074 -1,
00075 -1,
00076 1,
00077 -1,
00078 -1,
00079 0,
00080 0,
00081 0,
00082 0,
00083 0,
00084 0
00085 };
00086
00090
00091 static size_t headerMaxbytes = (32*1024*1024);
00092
00097 #define hdrchkTags(_ntags) ((_ntags) & 0xffff0000)
00098
00102 #define hdrchkType(_type) ((_type) < RPM_MIN_TYPE || (_type) > RPM_MAX_TYPE)
00103
00108 #define hdrchkData(_nbytes) ((_nbytes) & 0xff000000)
00109
00113 #define hdrchkAlign(_type, _off) ((_off) & (typeAlign[_type]-1))
00114
00118 #define hdrchkRange(_dl, _off) ((_off) < 0 || (_off) > (_dl))
00119
00120
00121 HV_t hdrVec;
00122
00128 static inline void *
00129 _free( const void * p)
00130 {
00131 if (p != NULL) free((void *)p);
00132 return NULL;
00133 }
00134
00140 static
00141 Header headerLink(Header h)
00142
00143 {
00144
00145 if (h == NULL) return NULL;
00146
00147
00148 h->nrefs++;
00149
00150 if (_hdr_debug)
00151 fprintf(stderr, "--> h %p ++ %d at %s:%u\n", h, h->nrefs, __FILE__, __LINE__);
00152
00153
00154
00155 return h;
00156
00157 }
00158
00164 static
00165 Header headerUnlink( Header h)
00166
00167 {
00168 if (h == NULL) return NULL;
00169
00170 if (_hdr_debug)
00171 fprintf(stderr, "--> h %p -- %d at %s:%u\n", h, h->nrefs, __FILE__, __LINE__);
00172
00173 h->nrefs--;
00174 return NULL;
00175 }
00176
00182 static
00183 Header headerFree( Header h)
00184
00185 {
00186 (void) headerUnlink(h);
00187
00188
00189 if (h == NULL || h->nrefs > 0)
00190 return NULL;
00191
00192 if (h->index) {
00193 indexEntry entry = h->index;
00194 int i;
00195 for (i = 0; i < h->indexUsed; i++, entry++) {
00196 if ((h->flags & HEADERFLAG_ALLOCATED) && ENTRY_IS_REGION(entry)) {
00197 if (entry->length > 0) {
00198 int_32 * ei = entry->data;
00199 if ((ei - 2) == h->blob) h->blob = _free(h->blob);
00200 entry->data = NULL;
00201 }
00202 } else if (!ENTRY_IN_REGION(entry)) {
00203 entry->data = _free(entry->data);
00204 }
00205 entry->data = NULL;
00206 }
00207 h->index = _free(h->index);
00208 }
00209
00210 h = _free(h);
00211 return h;
00212
00213 }
00214
00219 static
00220 Header headerNew(void)
00221
00222 {
00223 Header h = xcalloc(1, sizeof(*h));
00224
00225
00226
00227 h->hv = *hdrVec;
00228
00229
00230 h->blob = NULL;
00231 h->indexAlloced = INDEX_MALLOC_SIZE;
00232 h->indexUsed = 0;
00233 h->flags |= HEADERFLAG_SORTED;
00234
00235 h->index = (h->indexAlloced
00236 ? xcalloc(h->indexAlloced, sizeof(*h->index))
00237 : NULL);
00238
00239 h->nrefs = 0;
00240
00241 return headerLink(h);
00242
00243 }
00244
00247 static int indexCmp(const void * avp, const void * bvp)
00248
00249 {
00250
00251 indexEntry ap = (indexEntry) avp, bp = (indexEntry) bvp;
00252
00253 return (ap->info.tag - bp->info.tag);
00254 }
00255
00260 static
00261 void headerSort(Header h)
00262
00263 {
00264 if (!(h->flags & HEADERFLAG_SORTED)) {
00265
00266 qsort(h->index, h->indexUsed, sizeof(*h->index), indexCmp);
00267
00268 h->flags |= HEADERFLAG_SORTED;
00269 }
00270 }
00271
00274 static int offsetCmp(const void * avp, const void * bvp)
00275 {
00276
00277 indexEntry ap = (indexEntry) avp, bp = (indexEntry) bvp;
00278
00279 int rc = (ap->info.offset - bp->info.offset);
00280
00281 if (rc == 0) {
00282
00283 if (ap->info.offset < 0)
00284 rc = (((char *)ap->data) - ((char *)bp->data));
00285 else
00286 rc = (ap->info.tag - bp->info.tag);
00287 }
00288 return rc;
00289 }
00290
00295 static
00296 void headerUnsort(Header h)
00297
00298 {
00299
00300 qsort(h->index, h->indexUsed, sizeof(*h->index), offsetCmp);
00301
00302 }
00303
00310 static
00311 unsigned int headerSizeof( Header h, enum hMagic magicp)
00312
00313 {
00314 indexEntry entry;
00315 unsigned int size = 0;
00316 unsigned int pad = 0;
00317 int i;
00318
00319 if (h == NULL)
00320 return size;
00321
00322 headerSort(h);
00323
00324 switch (magicp) {
00325 case HEADER_MAGIC_YES:
00326 size += sizeof(header_magic);
00327 break;
00328 case HEADER_MAGIC_NO:
00329 break;
00330 }
00331
00332
00333 size += 2 * sizeof(int_32);
00334
00335
00336 for (i = 0, entry = h->index; i < h->indexUsed; i++, entry++) {
00337 unsigned diff;
00338 int_32 type;
00339
00340
00341 if (ENTRY_IS_REGION(entry)) {
00342 size += entry->length;
00343
00344
00345 if (i == 0 && (h->flags & HEADERFLAG_LEGACY))
00346 size += sizeof(struct entryInfo_s) + entry->info.count;
00347
00348 continue;
00349 }
00350
00351
00352 if (entry->info.offset < 0)
00353 continue;
00354
00355
00356 type = entry->info.type;
00357
00358 if (typeSizes[type] > 1) {
00359 diff = typeSizes[type] - (size % typeSizes[type]);
00360 if (diff != typeSizes[type]) {
00361 size += diff;
00362 pad += diff;
00363 }
00364 }
00365
00366
00367
00368 size += sizeof(struct entryInfo_s) + entry->length;
00369
00370 }
00371
00372 return size;
00373 }
00374
00384 static int dataLength(int_32 type, hPTR_t p, int_32 count, int onDisk,
00385 hPTR_t pend)
00386
00387 {
00388 const unsigned char * s = p;
00389 const unsigned char * se = pend;
00390 int length = 0;
00391
00392 switch (type) {
00393 case RPM_STRING_TYPE:
00394 if (count != 1)
00395 return -1;
00396
00397 while (*s++) {
00398 if (se && s > se)
00399 return -1;
00400 length++;
00401 }
00402
00403 length++;
00404 break;
00405
00406 case RPM_STRING_ARRAY_TYPE:
00407 case RPM_I18NSTRING_TYPE:
00408
00409
00410
00411 if (onDisk) {
00412 while (count--) {
00413 length++;
00414
00415 while (*s++) {
00416 if (se && s > se)
00417 return -1;
00418 length++;
00419 }
00420
00421 }
00422 } else {
00423 const char ** av = (const char **)p;
00424
00425 while (count--) {
00426
00427 length += strlen(*av++) + 1;
00428 }
00429
00430 }
00431 break;
00432
00433 default:
00434
00435 if (typeSizes[type] == -1)
00436 return -1;
00437 length = typeSizes[(type & 0xf)] * count;
00438
00439 if (length < 0 || (se && (s + length) > se))
00440 return -1;
00441 break;
00442 }
00443
00444 return length;
00445 }
00446
00473 static int regionSwab( indexEntry entry, int il, int dl,
00474 entryInfo pe,
00475 unsigned char * dataStart,
00476 const unsigned char * dataEnd,
00477 int regionid)
00478
00479 {
00480 unsigned char * tprev = NULL;
00481 unsigned char * t = NULL;
00482 int tdel = 0;
00483 int tl = dl;
00484 struct indexEntry_s ieprev;
00485
00486
00487 memset(&ieprev, 0, sizeof(ieprev));
00488
00489 for (; il > 0; il--, pe++) {
00490 struct indexEntry_s ie;
00491 int_32 type;
00492
00493 ie.info.tag = ntohl(pe->tag);
00494 ie.info.type = ntohl(pe->type);
00495 ie.info.count = ntohl(pe->count);
00496 ie.info.offset = ntohl(pe->offset);
00497
00498 if (hdrchkType(ie.info.type))
00499 return -1;
00500 if (hdrchkData(ie.info.count))
00501 return -1;
00502 if (hdrchkData(ie.info.offset))
00503 return -1;
00504
00505 if (hdrchkAlign(ie.info.type, ie.info.offset))
00506 return -1;
00507
00508
00509 ie.data = t = dataStart + ie.info.offset;
00510 if (dataEnd && t >= dataEnd)
00511 return -1;
00512
00513 ie.length = dataLength(ie.info.type, ie.data, ie.info.count, 1, dataEnd);
00514 if (ie.length < 0 || hdrchkData(ie.length))
00515 return -1;
00516
00517 ie.rdlen = 0;
00518
00519 if (entry) {
00520 ie.info.offset = regionid;
00521
00522 *entry = ie;
00523
00524 entry++;
00525 }
00526
00527
00528 type = ie.info.type;
00529
00530 if (typeSizes[type] > 1) {
00531 unsigned diff;
00532 diff = typeSizes[type] - (dl % typeSizes[type]);
00533 if (diff != typeSizes[type]) {
00534 dl += diff;
00535 if (ieprev.info.type == RPM_I18NSTRING_TYPE)
00536 ieprev.length += diff;
00537 }
00538 }
00539
00540 tdel = (tprev ? (t - tprev) : 0);
00541 if (ieprev.info.type == RPM_I18NSTRING_TYPE)
00542 tdel = ieprev.length;
00543
00544 if (ie.info.tag >= HEADER_I18NTABLE) {
00545 tprev = t;
00546 } else {
00547 tprev = dataStart;
00548
00549
00550 if (ie.info.tag == HEADER_IMAGE)
00551 tprev -= REGION_TAG_COUNT;
00552
00553 }
00554
00555
00556 switch (ntohl(pe->type)) {
00557
00558 case RPM_INT32_TYPE:
00559 { int_32 * it = (int_32 *)t;
00560 for (; ie.info.count > 0; ie.info.count--, it += 1) {
00561 if (dataEnd && ((unsigned char *)it) >= dataEnd)
00562 return -1;
00563 *it = htonl(*it);
00564 }
00565 t = (char *) it;
00566 } break;
00567 case RPM_INT16_TYPE:
00568 { int_16 * it = (int_16 *) t;
00569 for (; ie.info.count > 0; ie.info.count--, it += 1) {
00570 if (dataEnd && ((unsigned char *)it) >= dataEnd)
00571 return -1;
00572 *it = htons(*it);
00573 }
00574 t = (char *) it;
00575 } break;
00576
00577 default:
00578 t += ie.length;
00579 break;
00580 }
00581
00582 dl += ie.length;
00583 tl += tdel;
00584 ieprev = ie;
00585
00586 }
00587 tdel = (tprev ? (t - tprev) : 0);
00588 tl += tdel;
00589
00590
00591
00592
00593
00594
00595
00596 if (tl+REGION_TAG_COUNT == dl)
00597 tl += REGION_TAG_COUNT;
00598
00599
00600 return dl;
00601 }
00602
00608 static void * doHeaderUnload(Header h,
00609 int * lengthPtr)
00610
00611
00612
00613 {
00614 int_32 * ei = NULL;
00615 entryInfo pe;
00616 char * dataStart;
00617 char * te;
00618 unsigned pad;
00619 unsigned len;
00620 int_32 il = 0;
00621 int_32 dl = 0;
00622 indexEntry entry;
00623 int_32 type;
00624 int i;
00625 int drlen, ndribbles;
00626 int driplen, ndrips;
00627 int legacy = 0;
00628
00629
00630 headerUnsort(h);
00631
00632
00633 pad = 0;
00634 drlen = ndribbles = driplen = ndrips = 0;
00635 for (i = 0, entry = h->index; i < h->indexUsed; i++, entry++) {
00636 if (ENTRY_IS_REGION(entry)) {
00637 int_32 rdl = -entry->info.offset;
00638 int_32 ril = rdl/sizeof(*pe);
00639 int rid = entry->info.offset;
00640
00641 il += ril;
00642 dl += entry->rdlen + entry->info.count;
00643
00644 if (i == 0 && (h->flags & HEADERFLAG_LEGACY))
00645 il += 1;
00646
00647
00648 for (; i < h->indexUsed && entry->info.offset <= rid+1; i++, entry++) {
00649 if (entry->info.offset <= rid)
00650 continue;
00651
00652
00653 type = entry->info.type;
00654 if (typeSizes[type] > 1) {
00655 unsigned diff;
00656 diff = typeSizes[type] - (dl % typeSizes[type]);
00657 if (diff != typeSizes[type]) {
00658 drlen += diff;
00659 pad += diff;
00660 dl += diff;
00661 }
00662 }
00663
00664 ndribbles++;
00665 il++;
00666 drlen += entry->length;
00667 dl += entry->length;
00668 }
00669 i--;
00670 entry--;
00671 continue;
00672 }
00673
00674
00675 if (entry->data == NULL || entry->length <= 0)
00676 continue;
00677
00678
00679 type = entry->info.type;
00680 if (typeSizes[type] > 1) {
00681 unsigned diff;
00682 diff = typeSizes[type] - (dl % typeSizes[type]);
00683 if (diff != typeSizes[type]) {
00684 driplen += diff;
00685 pad += diff;
00686 dl += diff;
00687 } else
00688 diff = 0;
00689 }
00690
00691 ndrips++;
00692 il++;
00693 driplen += entry->length;
00694 dl += entry->length;
00695 }
00696
00697
00698 if (hdrchkTags(il) || hdrchkData(dl))
00699 goto errxit;
00700
00701 len = sizeof(il) + sizeof(dl) + (il * sizeof(*pe)) + dl;
00702
00703
00704 ei = xmalloc(len);
00705 ei[0] = htonl(il);
00706 ei[1] = htonl(dl);
00707
00708
00709 pe = (entryInfo) &ei[2];
00710 dataStart = te = (char *) (pe + il);
00711
00712 pad = 0;
00713 for (i = 0, entry = h->index; i < h->indexUsed; i++, entry++) {
00714 const char * src;
00715 char *t;
00716 int count;
00717 int rdlen;
00718
00719 if (entry->data == NULL || entry->length <= 0)
00720 continue;
00721
00722 t = te;
00723 pe->tag = htonl(entry->info.tag);
00724 pe->type = htonl(entry->info.type);
00725 pe->count = htonl(entry->info.count);
00726
00727 if (ENTRY_IS_REGION(entry)) {
00728 int_32 rdl = -entry->info.offset;
00729 int_32 ril = rdl/sizeof(*pe) + ndribbles;
00730 int rid = entry->info.offset;
00731
00732 src = (char *)entry->data;
00733 rdlen = entry->rdlen;
00734
00735
00736 if (i == 0 && (h->flags & HEADERFLAG_LEGACY)) {
00737 int_32 stei[4];
00738
00739 legacy = 1;
00740
00741 memcpy(pe+1, src, rdl);
00742 memcpy(te, src + rdl, rdlen);
00743
00744 te += rdlen;
00745
00746 pe->offset = htonl(te - dataStart);
00747 stei[0] = pe->tag;
00748 stei[1] = pe->type;
00749 stei[2] = htonl(-rdl-entry->info.count);
00750 stei[3] = pe->count;
00751
00752 memcpy(te, stei, entry->info.count);
00753
00754 te += entry->info.count;
00755 ril++;
00756 rdlen += entry->info.count;
00757
00758 count = regionSwab(NULL, ril, 0, pe, t, NULL, 0);
00759 if (count != rdlen)
00760 goto errxit;
00761
00762 } else {
00763
00764
00765 memcpy(pe+1, src + sizeof(*pe), ((ril-1) * sizeof(*pe)));
00766 memcpy(te, src + (ril * sizeof(*pe)), rdlen+entry->info.count+drlen);
00767
00768 te += rdlen;
00769 {
00770 entryInfo se = (entryInfo)src;
00771
00772 int off = ntohl(se->offset);
00773 pe->offset = (off) ? htonl(te - dataStart) : htonl(off);
00774 }
00775 te += entry->info.count + drlen;
00776
00777 count = regionSwab(NULL, ril, 0, pe, t, NULL, 0);
00778 if (count != (rdlen + entry->info.count + drlen))
00779 goto errxit;
00780 }
00781
00782
00783 while (i < h->indexUsed && entry->info.offset <= rid+1) {
00784 i++;
00785 entry++;
00786 }
00787 i--;
00788 entry--;
00789 pe += ril;
00790 continue;
00791 }
00792
00793
00794 if (entry->data == NULL || entry->length <= 0)
00795 continue;
00796
00797
00798 type = entry->info.type;
00799 if (typeSizes[type] > 1) {
00800 unsigned diff;
00801 diff = typeSizes[type] - ((te - dataStart) % typeSizes[type]);
00802 if (diff != typeSizes[type]) {
00803
00804 memset(te, 0, diff);
00805
00806 te += diff;
00807 pad += diff;
00808 }
00809 }
00810
00811 pe->offset = htonl(te - dataStart);
00812
00813
00814
00815 switch (entry->info.type) {
00816 case RPM_INT32_TYPE:
00817 count = entry->info.count;
00818 src = entry->data;
00819 while (count--) {
00820 *((int_32 *)te) = htonl(*((int_32 *)src));
00821
00822 te += sizeof(int_32);
00823 src += sizeof(int_32);
00824
00825 }
00826 break;
00827
00828 case RPM_INT16_TYPE:
00829 count = entry->info.count;
00830 src = entry->data;
00831 while (count--) {
00832 *((int_16 *)te) = htons(*((int_16 *)src));
00833
00834 te += sizeof(int_16);
00835 src += sizeof(int_16);
00836
00837 }
00838 break;
00839
00840 default:
00841 memcpy(te, entry->data, entry->length);
00842 te += entry->length;
00843 break;
00844 }
00845
00846 pe++;
00847 }
00848
00849
00850 if (((char *)pe) != dataStart)
00851 goto errxit;
00852 if ((((char *)ei)+len) != te)
00853 goto errxit;
00854
00855 if (lengthPtr)
00856 *lengthPtr = len;
00857
00858 h->flags &= ~HEADERFLAG_SORTED;
00859 headerSort(h);
00860
00861 return (void *) ei;
00862
00863 errxit:
00864
00865 ei = _free(ei);
00866
00867 return (void *) ei;
00868 }
00869
00875 static
00876 void * headerUnload(Header h)
00877
00878 {
00879 int length;
00880
00881 void * uh = doHeaderUnload(h, &length);
00882
00883 return uh;
00884 }
00885
00893 static
00894 indexEntry findEntry( Header h, int_32 tag, int_32 type)
00895
00896 {
00897 indexEntry entry, entry2, last;
00898 struct indexEntry_s key;
00899
00900 if (h == NULL) return NULL;
00901 if (!(h->flags & HEADERFLAG_SORTED)) headerSort(h);
00902
00903 key.info.tag = tag;
00904
00905
00906 entry2 = entry =
00907 bsearch(&key, h->index, h->indexUsed, sizeof(*h->index), indexCmp);
00908
00909 if (entry == NULL)
00910 return NULL;
00911
00912 if (type == RPM_NULL_TYPE)
00913 return entry;
00914
00915
00916 while (entry->info.tag == tag && entry->info.type != type &&
00917 entry > h->index) entry--;
00918
00919 if (entry->info.tag == tag && entry->info.type == type)
00920 return entry;
00921
00922 last = h->index + h->indexUsed;
00923
00924 while (entry2->info.tag == tag && entry2->info.type != type &&
00925 entry2 < last) entry2++;
00926
00927
00928 if (entry->info.tag == tag && entry->info.type == type)
00929 return entry;
00930
00931 return NULL;
00932 }
00933
00943 static
00944 int headerRemoveEntry(Header h, int_32 tag)
00945
00946 {
00947 indexEntry last = h->index + h->indexUsed;
00948 indexEntry entry, first;
00949 int ne;
00950
00951 entry = findEntry(h, tag, RPM_NULL_TYPE);
00952 if (!entry) return 1;
00953
00954
00955 while (entry > h->index && (entry - 1)->info.tag == tag)
00956 entry--;
00957
00958
00959 for (first = entry; first < last; first++) {
00960 void * data;
00961 if (first->info.tag != tag)
00962 break;
00963 data = first->data;
00964 first->data = NULL;
00965 first->length = 0;
00966 if (ENTRY_IN_REGION(first))
00967 continue;
00968 data = _free(data);
00969 }
00970
00971 ne = (first - entry);
00972 if (ne > 0) {
00973 h->indexUsed -= ne;
00974 ne = last - first;
00975
00976 if (ne > 0)
00977 memmove(entry, first, (ne * sizeof(*entry)));
00978
00979 }
00980
00981 return 0;
00982 }
00983
00989 static
00990 Header headerLoad( void * uh)
00991
00992 {
00993 int_32 * ei = (int_32 *) uh;
00994 int_32 il = ntohl(ei[0]);
00995 int_32 dl = ntohl(ei[1]);
00996
00997 size_t pvlen = sizeof(il) + sizeof(dl) +
00998 (il * sizeof(struct entryInfo_s)) + dl;
00999
01000 void * pv = uh;
01001 Header h = NULL;
01002 entryInfo pe;
01003 unsigned char * dataStart;
01004 unsigned char * dataEnd;
01005 indexEntry entry;
01006 int rdlen;
01007 int i;
01008
01009
01010 if (hdrchkTags(il) || hdrchkData(dl))
01011 goto errxit;
01012
01013 ei = (int_32 *) pv;
01014
01015 pe = (entryInfo) &ei[2];
01016
01017 dataStart = (unsigned char *) (pe + il);
01018 dataEnd = dataStart + dl;
01019
01020 h = xcalloc(1, sizeof(*h));
01021
01022 h->hv = *hdrVec;
01023
01024
01025 h->blob = uh;
01026
01027 h->indexAlloced = il + 1;
01028 h->indexUsed = il;
01029 h->index = xcalloc(h->indexAlloced, sizeof(*h->index));
01030 h->flags |= HEADERFLAG_SORTED;
01031 h->nrefs = 0;
01032 h = headerLink(h);
01033
01034
01035
01036
01037
01038 if (ntohl(pe->tag) == 15 &&
01039 ntohl(pe->type) == RPM_STRING_TYPE &&
01040 ntohl(pe->count) == 1)
01041 {
01042 pe->tag = htonl(1079);
01043 }
01044
01045 entry = h->index;
01046 i = 0;
01047 if (!(htonl(pe->tag) < HEADER_I18NTABLE)) {
01048 h->flags |= HEADERFLAG_LEGACY;
01049 entry->info.type = REGION_TAG_TYPE;
01050 entry->info.tag = HEADER_IMAGE;
01051
01052 entry->info.count = REGION_TAG_COUNT;
01053
01054 entry->info.offset = ((unsigned char *)pe - dataStart);
01055
01056
01057 entry->data = pe;
01058
01059 entry->length = pvlen - sizeof(il) - sizeof(dl);
01060 rdlen = regionSwab(entry+1, il, 0, pe, dataStart, dataEnd, entry->info.offset);
01061 #if 0
01062 if (rdlen != dl)
01063 goto errxit;
01064 #endif
01065 entry->rdlen = rdlen;
01066 entry++;
01067 h->indexUsed++;
01068 } else {
01069 int_32 rdl;
01070 int_32 ril;
01071
01072 h->flags &= ~HEADERFLAG_LEGACY;
01073
01074 entry->info.type = htonl(pe->type);
01075 entry->info.count = htonl(pe->count);
01076 entry->info.tag = htonl(pe->tag);
01077
01078 if (!ENTRY_IS_REGION(entry))
01079 goto errxit;
01080 if (entry->info.type != REGION_TAG_TYPE)
01081 goto errxit;
01082 if (entry->info.count != REGION_TAG_COUNT)
01083 goto errxit;
01084
01085 { int off = ntohl(pe->offset);
01086
01087 if (hdrchkData(off))
01088 goto errxit;
01089 if (off) {
01090
01091 size_t nb = REGION_TAG_COUNT;
01092
01093 int_32 * stei = memcpy(alloca(nb), dataStart + off, nb);
01094 rdl = -ntohl(stei[2]);
01095 ril = rdl/sizeof(*pe);
01096 if (hdrchkTags(ril) || hdrchkData(rdl))
01097 goto errxit;
01098 } else {
01099 ril = il;
01100
01101 rdl = (ril * sizeof(struct entryInfo_s));
01102
01103 entry->info.tag = HEADER_IMAGE;
01104 }
01105 }
01106 entry->info.offset = -rdl;
01107
01108
01109 entry->data = pe;
01110
01111 entry->length = pvlen - sizeof(il) - sizeof(dl);
01112 rdlen = regionSwab(entry+1, ril-1, 0, pe+1, dataStart, dataEnd, entry->info.offset);
01113 if (rdlen < 0)
01114 goto errxit;
01115 entry->rdlen = rdlen;
01116
01117 if (ril < h->indexUsed) {
01118 indexEntry newEntry = entry + ril;
01119 int ne = (h->indexUsed - ril);
01120 int rid = entry->info.offset+1;
01121 int rc;
01122
01123
01124 rc = regionSwab(newEntry, ne, 0, pe+ril, dataStart, dataEnd, rid);
01125 if (rc < 0)
01126 goto errxit;
01127 rdlen += rc;
01128
01129 { indexEntry firstEntry = newEntry;
01130 int save = h->indexUsed;
01131 int j;
01132
01133
01134 h->indexUsed -= ne;
01135 for (j = 0; j < ne; j++, newEntry++) {
01136 (void) headerRemoveEntry(h, newEntry->info.tag);
01137 if (newEntry->info.tag == HEADER_BASENAMES)
01138 (void) headerRemoveEntry(h, HEADER_OLDFILENAMES);
01139 }
01140
01141
01142
01143 if (h->indexUsed < (save - ne)) {
01144 memmove(h->index + h->indexUsed, firstEntry,
01145 (ne * sizeof(*entry)));
01146 }
01147
01148 h->indexUsed += ne;
01149 }
01150 }
01151 }
01152
01153 h->flags &= ~HEADERFLAG_SORTED;
01154 headerSort(h);
01155
01156
01157 return h;
01158
01159
01160 errxit:
01161
01162 if (h) {
01163 h->index = _free(h->index);
01164
01165 h = _free(h);
01166
01167 }
01168
01169
01170 return h;
01171
01172 }
01173
01181 static
01182 Header headerReload( Header h, int tag)
01183
01184 {
01185 Header nh;
01186 int length;
01187
01188
01189 void * uh = doHeaderUnload(h, &length);
01190
01191
01192 h = headerFree(h);
01193
01194 if (uh == NULL)
01195 return NULL;
01196 nh = headerLoad(uh);
01197 if (nh == NULL) {
01198 uh = _free(uh);
01199 return NULL;
01200 }
01201 if (nh->flags & HEADERFLAG_ALLOCATED)
01202 uh = _free(uh);
01203 nh->flags |= HEADERFLAG_ALLOCATED;
01204 if (ENTRY_IS_REGION(nh->index)) {
01205
01206 if (tag == HEADER_SIGNATURES || tag == HEADER_IMMUTABLE)
01207 nh->index[0].info.tag = tag;
01208
01209 }
01210 return nh;
01211 }
01212
01218 static
01219 Header headerCopyLoad(const void * uh)
01220
01221 {
01222 int_32 * ei = (int_32 *) uh;
01223
01224 int_32 il = ntohl(ei[0]);
01225 int_32 dl = ntohl(ei[1]);
01226
01227
01228 size_t pvlen = sizeof(il) + sizeof(dl) +
01229 (il * sizeof(struct entryInfo_s)) + dl;
01230
01231 void * nuh = NULL;
01232 Header h = NULL;
01233
01234
01235
01236 if (!(hdrchkTags(il) || hdrchkData(dl)) && pvlen < headerMaxbytes) {
01237
01238 nuh = memcpy(xmalloc(pvlen), uh, pvlen);
01239
01240 if ((h = headerLoad(nuh)) != NULL)
01241 h->flags |= HEADERFLAG_ALLOCATED;
01242 }
01243
01244
01245 if (h == NULL)
01246 nuh = _free(nuh);
01247
01248 return h;
01249 }
01250
01257 static
01258 Header headerRead(FD_t fd, enum hMagic magicp)
01259
01260 {
01261 int_32 block[4];
01262 int_32 reserved;
01263 int_32 * ei = NULL;
01264 int_32 il;
01265 int_32 dl;
01266 int_32 magic;
01267 Header h = NULL;
01268 size_t len;
01269 int i;
01270
01271 memset(block, 0, sizeof(block));
01272 i = 2;
01273 if (magicp == HEADER_MAGIC_YES)
01274 i += 2;
01275
01276
01277 if (timedRead(fd, (char *)block, i*sizeof(*block)) != (i * sizeof(*block)))
01278 goto exit;
01279
01280
01281 i = 0;
01282
01283
01284 if (magicp == HEADER_MAGIC_YES) {
01285 magic = block[i++];
01286 if (memcmp(&magic, header_magic, sizeof(magic)))
01287 goto exit;
01288 reserved = block[i++];
01289 }
01290
01291 il = ntohl(block[i]); i++;
01292 dl = ntohl(block[i]); i++;
01293
01294
01295
01296 len = sizeof(il) + sizeof(dl) + (il * sizeof(struct entryInfo_s)) + dl;
01297
01298
01299
01300 if (hdrchkTags(il) || hdrchkData(dl) || len > headerMaxbytes)
01301 goto exit;
01302
01303
01304 ei = xmalloc(len);
01305 ei[0] = htonl(il);
01306 ei[1] = htonl(dl);
01307 len -= sizeof(il) + sizeof(dl);
01308
01309
01310
01311
01312 if (timedRead(fd, (char *)&ei[2], len) != len)
01313 goto exit;
01314
01315
01316
01317 h = headerLoad(ei);
01318
01319 exit:
01320 if (h) {
01321 if (h->flags & HEADERFLAG_ALLOCATED)
01322 ei = _free(ei);
01323 h->flags |= HEADERFLAG_ALLOCATED;
01324 } else if (ei)
01325 ei = _free(ei);
01326
01327 return h;
01328
01329 }
01330
01338 static
01339 int headerWrite(FD_t fd, Header h, enum hMagic magicp)
01340
01341
01342 {
01343 ssize_t nb;
01344 int length;
01345 const void * uh;
01346
01347 if (h == NULL)
01348 return 1;
01349
01350 uh = doHeaderUnload(h, &length);
01351
01352 if (uh == NULL)
01353 return 1;
01354 switch (magicp) {
01355 case HEADER_MAGIC_YES:
01356
01357
01358 nb = Fwrite(header_magic, sizeof(char), sizeof(header_magic), fd);
01359
01360
01361 if (nb != sizeof(header_magic))
01362 goto exit;
01363 break;
01364 case HEADER_MAGIC_NO:
01365 break;
01366 }
01367
01368
01369 nb = Fwrite(uh, sizeof(char), length, fd);
01370
01371
01372 exit:
01373 uh = _free(uh);
01374 return (nb == length ? 0 : 1);
01375 }
01376
01383 static
01384 int headerIsEntry(Header h, int_32 tag)
01385
01386 {
01387
01388 return (findEntry(h, tag, RPM_NULL_TYPE) ? 1 : 0);
01389
01390 }
01391
01402 static int copyEntry(const indexEntry entry,
01403 hTYP_t type,
01404 hPTR_t * p,
01405 hCNT_t c,
01406 int minMem)
01407
01408
01409 {
01410 int_32 count = entry->info.count;
01411 int rc = 1;
01412
01413 if (p)
01414 switch (entry->info.type) {
01415 case RPM_BIN_TYPE:
01416
01417
01418
01419
01420
01421
01422 if (ENTRY_IS_REGION(entry)) {
01423 int_32 * ei = ((int_32 *)entry->data) - 2;
01424
01425 entryInfo pe = (entryInfo) (ei + 2);
01426
01427
01428 char * dataStart = (char *) (pe + ntohl(ei[0]));
01429
01430 int_32 rdl = -entry->info.offset;
01431 int_32 ril = rdl/sizeof(*pe);
01432
01433
01434 rdl = entry->rdlen;
01435 count = 2 * sizeof(*ei) + (ril * sizeof(*pe)) + rdl;
01436 if (entry->info.tag == HEADER_IMAGE) {
01437 ril -= 1;
01438 pe += 1;
01439 } else {
01440 count += REGION_TAG_COUNT;
01441 rdl += REGION_TAG_COUNT;
01442 }
01443
01444
01445 *p = xmalloc(count);
01446 ei = (int_32 *) *p;
01447 ei[0] = htonl(ril);
01448 ei[1] = htonl(rdl);
01449
01450
01451 pe = (entryInfo) memcpy(ei + 2, pe, (ril * sizeof(*pe)));
01452
01453
01454 dataStart = (char *) memcpy(pe + ril, dataStart, rdl);
01455
01456
01457
01458 rc = regionSwab(NULL, ril, 0, pe, dataStart, dataStart + rdl, 0);
01459
01460 rc = (rc < 0) ? 0 : 1;
01461 } else {
01462 count = entry->length;
01463 *p = (!minMem
01464 ? memcpy(xmalloc(count), entry->data, count)
01465 : entry->data);
01466 }
01467 break;
01468 case RPM_STRING_TYPE:
01469 if (count == 1) {
01470 *p = entry->data;
01471 break;
01472 }
01473
01474 case RPM_STRING_ARRAY_TYPE:
01475 case RPM_I18NSTRING_TYPE:
01476 { const char ** ptrEntry;
01477
01478 int tableSize = count * sizeof(char *);
01479
01480 char * t;
01481 int i;
01482
01483
01484
01485 if (minMem) {
01486 *p = xmalloc(tableSize);
01487 ptrEntry = (const char **) *p;
01488 t = entry->data;
01489 } else {
01490 t = xmalloc(tableSize + entry->length);
01491 *p = (void *)t;
01492 ptrEntry = (const char **) *p;
01493 t += tableSize;
01494 memcpy(t, entry->data, entry->length);
01495 }
01496
01497
01498 for (i = 0; i < count; i++) {
01499
01500 *ptrEntry++ = t;
01501
01502 t = strchr(t, 0);
01503 t++;
01504 }
01505 } break;
01506
01507 default:
01508 *p = entry->data;
01509 break;
01510 }
01511 if (type) *type = entry->info.type;
01512 if (c) *c = count;
01513 return rc;
01514 }
01515
01534 static int headerMatchLocale(const char *td, const char *l, const char *le)
01535
01536 {
01537 const char *fe;
01538
01539
01540 #if 0
01541 { const char *s, *ll, *CC, *EE, *dd;
01542 char *lbuf, *t.
01543
01544
01545 lbuf = alloca(le - l + 1);
01546 for (s = l, ll = t = lbuf; *s; s++, t++) {
01547 switch (*s) {
01548 case '_':
01549 *t = '\0';
01550 CC = t + 1;
01551 break;
01552 case '.':
01553 *t = '\0';
01554 EE = t + 1;
01555 break;
01556 case '@':
01557 *t = '\0';
01558 dd = t + 1;
01559 break;
01560 default:
01561 *t = *s;
01562 break;
01563 }
01564 }
01565
01566 if (ll)
01567 for (t = ll; *t; t++) *t = tolower(*t);
01568 if (CC)
01569 for (t = CC; *t; t++) *t = toupper(*t);
01570
01571
01572 }
01573 #endif
01574
01575
01576 if (strlen(td) == (le-l) && !strncmp(td, l, (le - l)))
01577 return 1;
01578
01579
01580 for (fe = l; fe < le && *fe != '@'; fe++)
01581 {};
01582 if (fe < le && !strncmp(td, l, (fe - l)))
01583 return 1;
01584
01585
01586 for (fe = l; fe < le && *fe != '.'; fe++)
01587 {};
01588 if (fe < le && !strncmp(td, l, (fe - l)))
01589 return 1;
01590
01591
01592 for (fe = l; fe < le && *fe != '_'; fe++)
01593 {};
01594 if (fe < le && !strncmp(td, l, (fe - l)))
01595 return 2;
01596
01597 return 0;
01598 }
01599
01606 static char *
01607 headerFindI18NString(Header h, indexEntry entry)
01608
01609 {
01610 const char *lang, *l, *le;
01611 indexEntry table;
01612
01613
01614 if ((lang = getenv("LANGUAGE")) == NULL &&
01615 (lang = getenv("LC_ALL")) == NULL &&
01616 (lang = getenv("LC_MESSAGES")) == NULL &&
01617 (lang = getenv("LANG")) == NULL)
01618 return entry->data;
01619
01620
01621 if ((table = findEntry(h, HEADER_I18NTABLE, RPM_STRING_ARRAY_TYPE)) == NULL)
01622 return entry->data;
01623
01624
01625
01626 for (l = lang; *l != '\0'; l = le) {
01627 const char *td;
01628 char *ed, *ed_weak = NULL;
01629 int langNum;
01630
01631 while (*l && *l == ':')
01632 l++;
01633 if (*l == '\0')
01634 break;
01635 for (le = l; *le && *le != ':'; le++)
01636 {};
01637
01638
01639 for (langNum = 0, td = table->data, ed = entry->data;
01640 langNum < entry->info.count;
01641 langNum++, td += strlen(td) + 1, ed += strlen(ed) + 1) {
01642
01643 int match = headerMatchLocale(td, l, le);
01644 if (match == 1) return ed;
01645 else if (match == 2) ed_weak = ed;
01646
01647 }
01648 if (ed_weak) return ed_weak;
01649 }
01650
01651
01652 return entry->data;
01653 }
01654
01665 static int intGetEntry(Header h, int_32 tag,
01666 hTAG_t type,
01667 hPTR_t * p,
01668 hCNT_t c,
01669 int minMem)
01670
01671
01672 {
01673 indexEntry entry;
01674 int rc;
01675
01676
01677
01678 entry = findEntry(h, tag, RPM_NULL_TYPE);
01679
01680 if (entry == NULL) {
01681 if (type) type = 0;
01682 if (p) *p = NULL;
01683 if (c) *c = 0;
01684 return 0;
01685 }
01686
01687 switch (entry->info.type) {
01688 case RPM_I18NSTRING_TYPE:
01689 rc = 1;
01690 if (type) *type = RPM_STRING_TYPE;
01691 if (c) *c = 1;
01692
01693 if (p) *p = headerFindI18NString(h, entry);
01694
01695 break;
01696 default:
01697 rc = copyEntry(entry, type, p, c, minMem);
01698 break;
01699 }
01700
01701
01702 return ((rc == 1) ? 1 : 0);
01703 }
01704
01712 static void * headerFreeTag( Header h,
01713 const void * data, rpmTagType type)
01714
01715 {
01716 if (data) {
01717
01718 if (type == -1 ||
01719 type == RPM_STRING_ARRAY_TYPE ||
01720 type == RPM_I18NSTRING_TYPE ||
01721 type == RPM_BIN_TYPE)
01722 data = _free(data);
01723
01724 }
01725 return NULL;
01726 }
01727
01741 static
01742 int headerGetEntry(Header h, int_32 tag,
01743 hTYP_t type,
01744 void ** p,
01745 hCNT_t c)
01746
01747
01748 {
01749 return intGetEntry(h, tag, type, (hPTR_t *)p, c, 0);
01750 }
01751
01764 static
01765 int headerGetEntryMinMemory(Header h, int_32 tag,
01766 hTYP_t type,
01767 hPTR_t * p,
01768 hCNT_t c)
01769
01770
01771 {
01772 return intGetEntry(h, tag, type, p, c, 1);
01773 }
01774
01775 int headerGetRawEntry(Header h, int_32 tag, int_32 * type, hPTR_t * p,
01776 int_32 * c)
01777 {
01778 indexEntry entry;
01779 int rc;
01780
01781 if (p == NULL) return headerIsEntry(h, tag);
01782
01783
01784
01785 entry = findEntry(h, tag, RPM_NULL_TYPE);
01786
01787 if (!entry) {
01788 if (p) *p = NULL;
01789 if (c) *c = 0;
01790 return 0;
01791 }
01792
01793 rc = copyEntry(entry, type, p, c, 0);
01794
01795
01796 return ((rc == 1) ? 1 : 0);
01797 }
01798
01801 static void copyData(int_32 type, void * dstPtr, const void * srcPtr,
01802 int_32 cnt, int dataLength)
01803
01804 {
01805 switch (type) {
01806 case RPM_STRING_ARRAY_TYPE:
01807 case RPM_I18NSTRING_TYPE:
01808 { const char ** av = (const char **) srcPtr;
01809 char * t = dstPtr;
01810
01811
01812 while (cnt-- > 0 && dataLength > 0) {
01813 const char * s;
01814 if ((s = *av++) == NULL)
01815 continue;
01816 do {
01817 *t++ = *s++;
01818 } while (s[-1] && --dataLength > 0);
01819 }
01820
01821 } break;
01822
01823 default:
01824
01825 memmove(dstPtr, srcPtr, dataLength);
01826
01827 break;
01828 }
01829 }
01830
01839
01840 static void *
01841 grabData(int_32 type, hPTR_t p, int_32 c, int * lengthPtr)
01842
01843
01844 {
01845 void * data = NULL;
01846 int length;
01847
01848 length = dataLength(type, p, c, 0, NULL);
01849
01850 if (length > 0) {
01851 data = xmalloc(length);
01852 copyData(type, data, p, c, length);
01853 }
01854
01855
01856 if (lengthPtr)
01857 *lengthPtr = length;
01858 return data;
01859 }
01860
01875 static
01876 int headerAddEntry(Header h, int_32 tag, int_32 type, const void * p, int_32 c)
01877
01878 {
01879 indexEntry entry;
01880 void * data;
01881 int length;
01882
01883
01884 if (c <= 0)
01885 return 0;
01886
01887 if (hdrchkType(type))
01888 return 0;
01889 if (hdrchkData(c))
01890 return 0;
01891
01892 length = 0;
01893
01894 data = grabData(type, p, c, &length);
01895
01896 if (data == NULL || length <= 0)
01897 return 0;
01898
01899
01900 if (h->indexUsed == h->indexAlloced) {
01901 h->indexAlloced += INDEX_MALLOC_SIZE;
01902 h->index = xrealloc(h->index, h->indexAlloced * sizeof(*h->index));
01903 }
01904
01905
01906 entry = h->index + h->indexUsed;
01907 entry->info.tag = tag;
01908 entry->info.type = type;
01909 entry->info.count = c;
01910 entry->info.offset = 0;
01911 entry->data = data;
01912 entry->length = length;
01913
01914
01915 if (h->indexUsed > 0 && tag < h->index[h->indexUsed-1].info.tag)
01916 h->flags &= ~HEADERFLAG_SORTED;
01917
01918 h->indexUsed++;
01919
01920 return 1;
01921 }
01922
01937 static
01938 int headerAppendEntry(Header h, int_32 tag, int_32 type,
01939 const void * p, int_32 c)
01940
01941 {
01942 indexEntry entry;
01943 int length;
01944
01945 if (type == RPM_STRING_TYPE || type == RPM_I18NSTRING_TYPE) {
01946
01947 return 0;
01948 }
01949
01950
01951 entry = findEntry(h, tag, type);
01952 if (!entry)
01953 return 0;
01954
01955 length = dataLength(type, p, c, 0, NULL);
01956 if (length < 0)
01957 return 0;
01958
01959 if (ENTRY_IN_REGION(entry)) {
01960 char * t = xmalloc(entry->length + length);
01961
01962 memcpy(t, entry->data, entry->length);
01963
01964 entry->data = t;
01965 entry->info.offset = 0;
01966 } else
01967 entry->data = xrealloc(entry->data, entry->length + length);
01968
01969 copyData(type, ((char *) entry->data) + entry->length, p, c, length);
01970
01971 entry->length += length;
01972
01973 entry->info.count += c;
01974
01975 return 1;
01976 }
01977
01988 static
01989 int headerAddOrAppendEntry(Header h, int_32 tag, int_32 type,
01990 const void * p, int_32 c)
01991
01992 {
01993 return (findEntry(h, tag, type)
01994 ? headerAppendEntry(h, tag, type, p, c)
01995 : headerAddEntry(h, tag, type, p, c));
01996 }
01997
02018 static
02019 int headerAddI18NString(Header h, int_32 tag, const char * string,
02020 const char * lang)
02021
02022 {
02023 indexEntry table, entry;
02024 const char ** strArray;
02025 int length;
02026 int ghosts;
02027 int i, langNum;
02028 char * buf;
02029
02030 table = findEntry(h, HEADER_I18NTABLE, RPM_STRING_ARRAY_TYPE);
02031 entry = findEntry(h, tag, RPM_I18NSTRING_TYPE);
02032
02033 if (!table && entry)
02034 return 0;
02035
02036 if (!table && !entry) {
02037 const char * charArray[2];
02038 int count = 0;
02039 if (!lang || (lang[0] == 'C' && lang[1] == '\0')) {
02040
02041 charArray[count++] = "C";
02042
02043 } else {
02044
02045 charArray[count++] = "C";
02046
02047 charArray[count++] = lang;
02048 }
02049 if (!headerAddEntry(h, HEADER_I18NTABLE, RPM_STRING_ARRAY_TYPE,
02050 &charArray, count))
02051 return 0;
02052 table = findEntry(h, HEADER_I18NTABLE, RPM_STRING_ARRAY_TYPE);
02053 }
02054
02055 if (!table)
02056 return 0;
02057
02058 if (!lang) lang = "C";
02059
02060
02061 { const char * l = table->data;
02062 for (langNum = 0; langNum < table->info.count; langNum++) {
02063 if (!strcmp(l, lang)) break;
02064 l += strlen(l) + 1;
02065 }
02066 }
02067
02068 if (langNum >= table->info.count) {
02069 length = strlen(lang) + 1;
02070 if (ENTRY_IN_REGION(table)) {
02071 char * t = xmalloc(table->length + length);
02072 memcpy(t, table->data, table->length);
02073 table->data = t;
02074 table->info.offset = 0;
02075 } else
02076 table->data = xrealloc(table->data, table->length + length);
02077 memmove(((char *)table->data) + table->length, lang, length);
02078 table->length += length;
02079 table->info.count++;
02080 }
02081
02082 if (!entry) {
02083 strArray = alloca(sizeof(*strArray) * (langNum + 1));
02084 for (i = 0; i < langNum; i++)
02085 strArray[i] = "";
02086 strArray[langNum] = string;
02087 return headerAddEntry(h, tag, RPM_I18NSTRING_TYPE, strArray,
02088 langNum + 1);
02089 } else if (langNum >= entry->info.count) {
02090 ghosts = langNum - entry->info.count;
02091
02092 length = strlen(string) + 1 + ghosts;
02093 if (ENTRY_IN_REGION(entry)) {
02094 char * t = xmalloc(entry->length + length);
02095 memcpy(t, entry->data, entry->length);
02096 entry->data = t;
02097 entry->info.offset = 0;
02098 } else
02099 entry->data = xrealloc(entry->data, entry->length + length);
02100
02101 memset(((char *)entry->data) + entry->length, '\0', ghosts);
02102 memmove(((char *)entry->data) + entry->length + ghosts, string, strlen(string)+1);
02103
02104 entry->length += length;
02105 entry->info.count = langNum + 1;
02106 } else {
02107 char *b, *be, *e, *ee, *t;
02108 size_t bn, sn, en;
02109
02110
02111 b = be = e = ee = entry->data;
02112 for (i = 0; i < table->info.count; i++) {
02113 if (i == langNum)
02114 be = ee;
02115 ee += strlen(ee) + 1;
02116 if (i == langNum)
02117 e = ee;
02118 }
02119
02120
02121 bn = (be-b);
02122 sn = strlen(string) + 1;
02123 en = (ee-e);
02124 length = bn + sn + en;
02125 t = buf = xmalloc(length);
02126
02127
02128 memcpy(t, b, bn);
02129 t += bn;
02130
02131 memcpy(t, string, sn);
02132 t += sn;
02133 memcpy(t, e, en);
02134 t += en;
02135
02136
02137
02138 entry->length -= strlen(be) + 1;
02139 entry->length += sn;
02140
02141 if (ENTRY_IN_REGION(entry)) {
02142 entry->info.offset = 0;
02143 } else
02144 entry->data = _free(entry->data);
02145
02146 entry->data = buf;
02147
02148 }
02149
02150 return 0;
02151 }
02152
02163 static
02164 int headerModifyEntry(Header h, int_32 tag, int_32 type,
02165 const void * p, int_32 c)
02166
02167 {
02168 indexEntry entry;
02169 void * oldData;
02170 void * data;
02171 int length;
02172
02173
02174 entry = findEntry(h, tag, type);
02175 if (!entry)
02176 return 0;
02177
02178 length = 0;
02179 data = grabData(type, p, c, &length);
02180 if (data == NULL || length <= 0)
02181 return 0;
02182
02183
02184 while (entry > h->index && (entry - 1)->info.tag == tag)
02185 entry--;
02186
02187
02188
02189 oldData = entry->data;
02190
02191 entry->info.count = c;
02192 entry->info.type = type;
02193 entry->data = data;
02194 entry->length = length;
02195
02196
02197 if (ENTRY_IN_REGION(entry)) {
02198 entry->info.offset = 0;
02199 } else
02200 oldData = _free(oldData);
02201
02202
02203 return 1;
02204 }
02205
02208 static char escapedChar(const char ch)
02209 {
02210 switch (ch) {
02211 case 'a': return '\a';
02212 case 'b': return '\b';
02213 case 'f': return '\f';
02214 case 'n': return '\n';
02215 case 'r': return '\r';
02216 case 't': return '\t';
02217 case 'v': return '\v';
02218 default: return ch;
02219 }
02220 }
02221
02228 static sprintfToken
02229 freeFormat( sprintfToken format, int num)
02230
02231 {
02232 int i;
02233
02234 if (format == NULL) return NULL;
02235
02236 for (i = 0; i < num; i++) {
02237 switch (format[i].type) {
02238 case PTOK_ARRAY:
02239
02240 format[i].u.array.format =
02241 freeFormat(format[i].u.array.format,
02242 format[i].u.array.numTokens);
02243
02244 break;
02245 case PTOK_COND:
02246
02247 format[i].u.cond.ifFormat =
02248 freeFormat(format[i].u.cond.ifFormat,
02249 format[i].u.cond.numIfTokens);
02250 format[i].u.cond.elseFormat =
02251 freeFormat(format[i].u.cond.elseFormat,
02252 format[i].u.cond.numElseTokens);
02253
02254 break;
02255 case PTOK_NONE:
02256 case PTOK_TAG:
02257 case PTOK_STRING:
02258 default:
02259 break;
02260 }
02261 }
02262 format = _free(format);
02263 return NULL;
02264 }
02265
02269 struct headerIterator_s {
02270
02271 Header h;
02272
02273 int next_index;
02274 };
02275
02281 static
02282 HeaderIterator headerFreeIterator( HeaderIterator hi)
02283
02284 {
02285 if (hi != NULL) {
02286 hi->h = headerFree(hi->h);
02287 hi = _free(hi);
02288 }
02289 return hi;
02290 }
02291
02297 static
02298 HeaderIterator headerInitIterator(Header h)
02299
02300 {
02301 HeaderIterator hi = xmalloc(sizeof(*hi));
02302
02303 headerSort(h);
02304
02305 hi->h = headerLink(h);
02306 hi->next_index = 0;
02307 return hi;
02308 }
02309
02319 static
02320 int headerNextIterator(HeaderIterator hi,
02321 hTAG_t tag,
02322 hTYP_t type,
02323 hPTR_t * p,
02324 hCNT_t c)
02325
02326
02327
02328 {
02329 Header h = hi->h;
02330 int slot = hi->next_index;
02331 indexEntry entry = NULL;
02332 int rc;
02333
02334 for (slot = hi->next_index; slot < h->indexUsed; slot++) {
02335 entry = h->index + slot;
02336 if (!ENTRY_IS_REGION(entry))
02337 break;
02338 }
02339 hi->next_index = slot;
02340 if (entry == NULL || slot >= h->indexUsed)
02341 return 0;
02342
02343
02344 hi->next_index++;
02345
02346
02347 if (tag)
02348 *tag = entry->info.tag;
02349
02350 rc = copyEntry(entry, type, p, c, 0);
02351
02352
02353 return ((rc == 1) ? 1 : 0);
02354 }
02355
02361 static
02362 Header headerCopy(Header h)
02363
02364 {
02365 Header nh = headerNew();
02366 HeaderIterator hi;
02367 int_32 tag, type, count;
02368 hPTR_t ptr;
02369
02370
02371 for (hi = headerInitIterator(h);
02372 headerNextIterator(hi, &tag, &type, &ptr, &count);
02373 ptr = headerFreeData((void *)ptr, type))
02374 {
02375 if (ptr) (void) headerAddEntry(nh, tag, type, ptr, count);
02376 }
02377 hi = headerFreeIterator(hi);
02378
02379
02380 return headerReload(nh, HEADER_IMAGE);
02381 }
02382
02385 typedef struct headerSprintfArgs_s {
02386 Header h;
02387 char * fmt;
02388
02389 headerTagTableEntry tags;
02390
02391 headerSprintfExtension exts;
02392
02393 const char * errmsg;
02394 rpmec ec;
02395 sprintfToken format;
02396
02397 HeaderIterator hi;
02398
02399 char * val;
02400 size_t vallen;
02401 size_t alloced;
02402 int numTokens;
02403 int i;
02404 } * headerSprintfArgs;
02405
02411 static headerSprintfArgs hsaInit( headerSprintfArgs hsa)
02412
02413 {
02414 sprintfTag tag =
02415 (hsa->format->type == PTOK_TAG
02416 ? &hsa->format->u.tag :
02417 (hsa->format->type == PTOK_ARRAY
02418 ? &hsa->format->u.array.format->u.tag :
02419 NULL));
02420
02421 if (hsa != NULL) {
02422 hsa->i = 0;
02423 if (tag != NULL && tag->tag == -2)
02424 hsa->hi = headerInitIterator(hsa->h);
02425 }
02426
02427 return hsa;
02428
02429 }
02430
02436
02437 static sprintfToken hsaNext( headerSprintfArgs hsa)
02438
02439 {
02440 sprintfToken fmt = NULL;
02441 sprintfTag tag =
02442 (hsa->format->type == PTOK_TAG
02443 ? &hsa->format->u.tag :
02444 (hsa->format->type == PTOK_ARRAY
02445 ? &hsa->format->u.array.format->u.tag :
02446 NULL));
02447
02448 if (hsa != NULL && hsa->i >= 0 && hsa->i < hsa->numTokens) {
02449 fmt = hsa->format + hsa->i;
02450 if (hsa->hi == NULL) {
02451 hsa->i++;
02452 } else {
02453 int_32 tagno;
02454 int_32 type;
02455 int_32 count;
02456
02457
02458 if (!headerNextIterator(hsa->hi, &tagno, &type, NULL, &count))
02459 fmt = NULL;
02460 tag->tag = tagno;
02461
02462 }
02463 }
02464
02465
02466 return fmt;
02467
02468 }
02469
02475 static headerSprintfArgs hsaFini( headerSprintfArgs hsa)
02476
02477 {
02478 if (hsa != NULL) {
02479 hsa->hi = headerFreeIterator(hsa->hi);
02480 hsa->i = 0;
02481 }
02482
02483 return hsa;
02484
02485 }
02486
02493
02494 static char * hsaReserve(headerSprintfArgs hsa, size_t need)
02495
02496 {
02497 if ((hsa->vallen + need) >= hsa->alloced) {
02498 if (hsa->alloced <= need)
02499 hsa->alloced += need;
02500 hsa->alloced <<= 1;
02501 hsa->val = xrealloc(hsa->val, hsa->alloced+1);
02502 }
02503 return hsa->val + hsa->vallen;
02504 }
02505
02513
02514 static const char * myTagName(headerTagTableEntry tbl, int val)
02515
02516 {
02517 static char name[128];
02518 const char * s;
02519 char *t;
02520
02521 for (; tbl->name != NULL; tbl++) {
02522 if (tbl->val == val)
02523 break;
02524 }
02525 if ((s = tbl->name) == NULL)
02526 return NULL;
02527 s += sizeof("RPMTAG_") - 1;
02528 t = name;
02529 *t++ = *s++;
02530 while (*s != '\0')
02531 *t++ = xtolower(*s++);
02532 *t = '\0';
02533 return name;
02534 }
02535
02543 static int myTagValue(headerTagTableEntry tbl, const char * name)
02544
02545 {
02546 for (; tbl->name != NULL; tbl++) {
02547 if (!xstrcasecmp(tbl->name, name))
02548 return tbl->val;
02549 }
02550 return 0;
02551 }
02552
02559 static int findTag(headerSprintfArgs hsa, sprintfToken token, const char * name)
02560
02561 {
02562 headerSprintfExtension ext;
02563 sprintfTag stag = (token->type == PTOK_COND
02564 ? &token->u.cond.tag : &token->u.tag);
02565
02566 stag->fmt = NULL;
02567 stag->ext = NULL;
02568 stag->extNum = 0;
02569 stag->tag = -1;
02570
02571 if (!strcmp(name, "*")) {
02572 stag->tag = -2;
02573 goto bingo;
02574 }
02575
02576
02577 if (strncmp("RPMTAG_", name, sizeof("RPMTAG_")-1)) {
02578
02579 char * t = alloca(strlen(name) + sizeof("RPMTAG_"));
02580 (void) stpcpy( stpcpy(t, "RPMTAG_"), name);
02581 name = t;
02582
02583 }
02584
02585
02586
02587 for (ext = hsa->exts; ext != NULL && ext->type != HEADER_EXT_LAST;
02588 ext = (ext->type == HEADER_EXT_MORE ? ext->u.more : ext+1))
02589 {
02590 if (ext->name == NULL || ext->type != HEADER_EXT_TAG)
02591 continue;
02592 if (!xstrcasecmp(ext->name, name)) {
02593 stag->ext = ext->u.tagFunction;
02594 stag->extNum = ext - hsa->exts;
02595 goto bingo;
02596 }
02597 }
02598
02599
02600 stag->tag = myTagValue(hsa->tags, name);
02601 if (stag->tag != 0)
02602 goto bingo;
02603
02604 return 1;
02605
02606 bingo:
02607
02608 if (stag->type != NULL)
02609 for (ext = hsa->exts; ext != NULL && ext->type != HEADER_EXT_LAST;
02610 ext = (ext->type == HEADER_EXT_MORE ? ext->u.more : ext+1))
02611 {
02612 if (ext->name == NULL || ext->type != HEADER_EXT_FORMAT)
02613 continue;
02614 if (!strcmp(ext->name, stag->type)) {
02615 stag->fmt = ext->u.formatFunction;
02616 break;
02617 }
02618 }
02619 return 0;
02620 }
02621
02622
02630 static int parseExpression(headerSprintfArgs hsa, sprintfToken token,
02631 char * str, char ** endPtr)
02632
02633 ;
02634
02644 static int parseFormat(headerSprintfArgs hsa, char * str,
02645 sprintfToken * formatPtr, int * numTokensPtr,
02646 char ** endPtr, int state)
02647
02648
02649
02650 {
02651 char * chptr, * start, * next, * dst;
02652 sprintfToken format;
02653 sprintfToken token;
02654 int numTokens;
02655 int i;
02656 int done = 0;
02657
02658
02659 numTokens = 0;
02660 if (str != NULL)
02661 for (chptr = str; *chptr != '\0'; chptr++)
02662 if (*chptr == '%') numTokens++;
02663 numTokens = numTokens * 2 + 1;
02664
02665 format = xcalloc(numTokens, sizeof(*format));
02666 if (endPtr) *endPtr = NULL;
02667
02668
02669 dst = start = str;
02670 numTokens = 0;
02671 token = NULL;
02672 if (start != NULL)
02673 while (*start != '\0') {
02674 switch (*start) {
02675 case '%':
02676
02677 if (*(start + 1) == '%') {
02678 if (token == NULL || token->type != PTOK_STRING) {
02679 token = format + numTokens++;
02680 token->type = PTOK_STRING;
02681
02682 dst = token->u.string.string = start;
02683
02684 }
02685 start++;
02686
02687 *dst++ = *start++;
02688
02689 break;
02690 }
02691
02692 token = format + numTokens++;
02693
02694 *dst++ = '\0';
02695
02696 start++;
02697
02698 if (*start == '|') {
02699 char * newEnd;
02700
02701 start++;
02702
02703 if (parseExpression(hsa, token, start, &newEnd))
02704 {
02705 format = freeFormat(format, numTokens);
02706 return 1;
02707 }
02708
02709 start = newEnd;
02710 break;
02711 }
02712
02713
02714 token->u.tag.format = start;
02715
02716 token->u.tag.pad = 0;
02717 token->u.tag.justOne = 0;
02718 token->u.tag.arrayCount = 0;
02719
02720 chptr = start;
02721 while (*chptr && *chptr != '{' && *chptr != '%') chptr++;
02722 if (!*chptr || *chptr == '%') {
02723 hsa->errmsg = _("missing { after %");
02724 format = freeFormat(format, numTokens);
02725 return 1;
02726 }
02727
02728
02729 *chptr++ = '\0';
02730
02731
02732 while (start < chptr) {
02733 if (xisdigit(*start)) {
02734 i = strtoul(start, &start, 10);
02735 token->u.tag.pad += i;
02736 start = chptr;
02737 break;
02738 } else {
02739 start++;
02740 }
02741 }
02742
02743 if (*start == '=') {
02744 token->u.tag.justOne = 1;
02745 start++;
02746 } else if (*start == '#') {
02747 token->u.tag.justOne = 1;
02748 token->u.tag.arrayCount = 1;
02749 start++;
02750 }
02751
02752 dst = next = start;
02753 while (*next && *next != '}') next++;
02754 if (!*next) {
02755 hsa->errmsg = _("missing } after %{");
02756 format = freeFormat(format, numTokens);
02757 return 1;
02758 }
02759
02760 *next++ = '\0';
02761
02762
02763 chptr = start;
02764 while (*chptr && *chptr != ':') chptr++;
02765
02766 if (*chptr != '\0') {
02767
02768 *chptr++ = '\0';
02769
02770 if (!*chptr) {
02771 hsa->errmsg = _("empty tag format");
02772 format = freeFormat(format, numTokens);
02773 return 1;
02774 }
02775
02776 token->u.tag.type = chptr;
02777
02778 } else {
02779 token->u.tag.type = NULL;
02780 }
02781
02782 if (!*start) {
02783 hsa->errmsg = _("empty tag name");
02784 format = freeFormat(format, numTokens);
02785 return 1;
02786 }
02787
02788 i = 0;
02789 token->type = PTOK_TAG;
02790
02791 if (findTag(hsa, token, start)) {
02792 hsa->errmsg = _("unknown tag");
02793 format = freeFormat(format, numTokens);
02794 return 1;
02795 }
02796
02797 start = next;
02798 break;
02799
02800 case '[':
02801
02802 *dst++ = '\0';
02803 *start++ = '\0';
02804
02805 token = format + numTokens++;
02806
02807
02808 if (parseFormat(hsa, start,
02809 &token->u.array.format,
02810 &token->u.array.numTokens,
02811 &start, PARSER_IN_ARRAY))
02812 {
02813 format = freeFormat(format, numTokens);
02814 return 1;
02815 }
02816
02817
02818 if (!start) {
02819 hsa->errmsg = _("] expected at end of array");
02820 format = freeFormat(format, numTokens);
02821 return 1;
02822 }
02823
02824 dst = start;
02825
02826 token->type = PTOK_ARRAY;
02827
02828 break;
02829
02830 case ']':
02831 if (state != PARSER_IN_ARRAY) {
02832 hsa->errmsg = _("unexpected ]");
02833 format = freeFormat(format, numTokens);
02834 return 1;
02835 }
02836
02837 *start++ = '\0';
02838
02839 if (endPtr) *endPtr = start;
02840 done = 1;
02841 break;
02842
02843 case '}':
02844 if (state != PARSER_IN_EXPR) {
02845 hsa->errmsg = _("unexpected }");
02846 format = freeFormat(format, numTokens);
02847 return 1;
02848 }
02849
02850 *start++ = '\0';
02851
02852 if (endPtr) *endPtr = start;
02853 done = 1;
02854 break;
02855
02856 default:
02857 if (token == NULL || token->type != PTOK_STRING) {
02858 token = format + numTokens++;
02859 token->type = PTOK_STRING;
02860
02861 dst = token->u.string.string = start;
02862
02863 }
02864
02865
02866 if (*start == '\\') {
02867 start++;
02868 *dst++ = escapedChar(*start++);
02869 } else {
02870 *dst++ = *start++;
02871 }
02872
02873 break;
02874 }
02875 if (done)
02876 break;
02877 }
02878
02879
02880
02881 if (dst != NULL)
02882 *dst = '\0';
02883
02884
02885 for (i = 0; i < numTokens; i++) {
02886 token = format + i;
02887 if (token->type == PTOK_STRING)
02888 token->u.string.len = strlen(token->u.string.string);
02889 }
02890
02891 *numTokensPtr = numTokens;
02892 *formatPtr = format;
02893
02894 return 0;
02895 }
02896
02897
02898 static int parseExpression(headerSprintfArgs hsa, sprintfToken token,
02899 char * str, char ** endPtr)
02900 {
02901 char * chptr;
02902 char * end;
02903
02904 hsa->errmsg = NULL;
02905 chptr = str;
02906 while (*chptr && *chptr != '?') chptr++;
02907
02908 if (*chptr != '?') {
02909 hsa->errmsg = _("? expected in expression");
02910 return 1;
02911 }
02912
02913 *chptr++ = '\0';;
02914
02915 if (*chptr != '{') {
02916 hsa->errmsg = _("{ expected after ? in expression");
02917 return 1;
02918 }
02919
02920 chptr++;
02921
02922 if (parseFormat(hsa, chptr, &token->u.cond.ifFormat,
02923 &token->u.cond.numIfTokens, &end, PARSER_IN_EXPR))
02924 return 1;
02925
02926
02927 if (!(end && *end)) {
02928 hsa->errmsg = _("} expected in expression");
02929 token->u.cond.ifFormat =
02930 freeFormat(token->u.cond.ifFormat, token->u.cond.numIfTokens);
02931 return 1;
02932 }
02933
02934 chptr = end;
02935 if (*chptr != ':' && *chptr != '|') {
02936 hsa->errmsg = _(": expected following ? subexpression");
02937 token->u.cond.ifFormat =
02938 freeFormat(token->u.cond.ifFormat, token->u.cond.numIfTokens);
02939 return 1;
02940 }
02941
02942 if (*chptr == '|') {
02943 if (parseFormat(hsa, NULL, &token->u.cond.elseFormat,
02944 &token->u.cond.numElseTokens, &end, PARSER_IN_EXPR))
02945 {
02946 token->u.cond.ifFormat =
02947 freeFormat(token->u.cond.ifFormat, token->u.cond.numIfTokens);
02948 return 1;
02949 }
02950 } else {
02951 chptr++;
02952
02953 if (*chptr != '{') {
02954 hsa->errmsg = _("{ expected after : in expression");
02955 token->u.cond.ifFormat =
02956 freeFormat(token->u.cond.ifFormat, token->u.cond.numIfTokens);
02957 return 1;
02958 }
02959
02960 chptr++;
02961
02962 if (parseFormat(hsa, chptr, &token->u.cond.elseFormat,
02963 &token->u.cond.numElseTokens, &end, PARSER_IN_EXPR))
02964 return 1;
02965
02966
02967 if (!(end && *end)) {
02968 hsa->errmsg = _("} expected in expression");
02969 token->u.cond.ifFormat =
02970 freeFormat(token->u.cond.ifFormat, token->u.cond.numIfTokens);
02971 return 1;
02972 }
02973
02974 chptr = end;
02975 if (*chptr != '|') {
02976 hsa->errmsg = _("| expected at end of expression");
02977 token->u.cond.ifFormat =
02978 freeFormat(token->u.cond.ifFormat, token->u.cond.numIfTokens);
02979 token->u.cond.elseFormat =
02980 freeFormat(token->u.cond.elseFormat, token->u.cond.numElseTokens);
02981 return 1;
02982 }
02983 }
02984
02985 chptr++;
02986
02987 *endPtr = chptr;
02988
02989 token->type = PTOK_COND;
02990
02991 (void) findTag(hsa, token, str);
02992
02993 return 0;
02994 }
02995
02996
03007 static int getExtension(headerSprintfArgs hsa, headerTagTagFunction fn,
03008 hTYP_t typeptr,
03009 hPTR_t * data,
03010 hCNT_t countptr,
03011 rpmec ec)
03012
03013
03014
03015 {
03016 if (!ec->avail) {
03017 if (fn(hsa->h, &ec->type, &ec->data, &ec->count, &ec->freeit))
03018 return 1;
03019 ec->avail = 1;
03020 }
03021
03022 if (typeptr) *typeptr = ec->type;
03023 if (data) *data = ec->data;
03024 if (countptr) *countptr = ec->count;
03025
03026 return 0;
03027 }
03028
03035
03036 static char * formatValue(headerSprintfArgs hsa, sprintfTag tag, int element)
03037
03038 {
03039 char * val = NULL;
03040 size_t need = 0;
03041 char * t, * te;
03042 char buf[20];
03043 int_32 count, type;
03044 hPTR_t data;
03045 unsigned int intVal;
03046 const char ** strarray;
03047 int datafree = 0;
03048 int countBuf;
03049
03050 memset(buf, 0, sizeof(buf));
03051 if (tag->ext) {
03052
03053 if (getExtension(hsa, tag->ext, &type, &data, &count, hsa->ec + tag->extNum))
03054 {
03055 count = 1;
03056 type = RPM_STRING_TYPE;
03057 data = "(none)";
03058 }
03059
03060 } else {
03061
03062 if (!headerGetEntry(hsa->h, tag->tag, &type, (void **)&data, &count)) {
03063 count = 1;
03064 type = RPM_STRING_TYPE;
03065 data = "(none)";
03066 }
03067
03068
03069
03070 switch (type) {
03071 default:
03072 if (element >= count) {
03073
03074 data = headerFreeData(data, type);
03075
03076
03077 hsa->errmsg = _("(index out of range)");
03078 return NULL;
03079 }
03080 break;
03081 case RPM_BIN_TYPE:
03082 case RPM_STRING_TYPE:
03083 break;
03084 }
03085 datafree = 1;
03086 }
03087
03088 if (tag->arrayCount) {
03089
03090 if (datafree)
03091 data = headerFreeData(data, type);
03092
03093
03094 countBuf = count;
03095 data = &countBuf;
03096 count = 1;
03097 type = RPM_INT32_TYPE;
03098 }
03099
03100
03101 (void) stpcpy( stpcpy(buf, "%"), tag->format);
03102
03103
03104
03105 if (data)
03106 switch (type) {
03107 case RPM_STRING_ARRAY_TYPE:
03108 strarray = (const char **)data;
03109
03110 if (tag->fmt)
03111 val = tag->fmt(RPM_STRING_TYPE, strarray[element], buf, tag->pad, element);
03112
03113 if (val) {
03114 need = strlen(val);
03115 } else {
03116 need = strlen(strarray[element]) + tag->pad + 20;
03117 val = xmalloc(need+1);
03118 strcat(buf, "s");
03119
03120 sprintf(val, buf, strarray[element]);
03121
03122 }
03123
03124 break;
03125
03126 case RPM_STRING_TYPE:
03127 if (tag->fmt)
03128 val = tag->fmt(RPM_STRING_TYPE, data, buf, tag->pad, 0);
03129
03130 if (val) {
03131 need = strlen(val);
03132 } else {
03133 need = strlen(data) + tag->pad + 20;
03134 val = xmalloc(need+1);
03135 strcat(buf, "s");
03136
03137 sprintf(val, buf, data);
03138
03139 }
03140 break;
03141
03142 case RPM_CHAR_TYPE:
03143 case RPM_INT8_TYPE:
03144 case RPM_INT16_TYPE:
03145 case RPM_INT32_TYPE:
03146 switch (type) {
03147 case RPM_CHAR_TYPE:
03148 case RPM_INT8_TYPE:
03149 intVal = *(((int_8 *) data) + element);
03150 break;
03151 case RPM_INT16_TYPE:
03152 intVal = *(((uint_16 *) data) + element);
03153 break;
03154 default:
03155 case RPM_INT32_TYPE:
03156 intVal = *(((int_32 *) data) + element);
03157 break;
03158 }
03159
03160 if (tag->fmt)
03161 val = tag->fmt(RPM_INT32_TYPE, &intVal, buf, tag->pad, element);
03162
03163 if (val) {
03164 need = strlen(val);
03165 } else {
03166 need = 10 + tag->pad + 20;
03167 val = xmalloc(need+1);
03168 strcat(buf, "d");
03169
03170 sprintf(val, buf, intVal);
03171
03172 }
03173 break;
03174
03175 case RPM_BIN_TYPE:
03176
03177 if (tag->fmt)
03178 val = tag->fmt(RPM_BIN_TYPE, data, buf, tag->pad, count);
03179
03180 if (val) {
03181 need = strlen(val);
03182 } else {
03183 val = bin2hex(data, count);
03184 need = strlen(val) + tag->pad;
03185 }
03186 break;
03187
03188 default:
03189 need = sizeof("(unknown type)") - 1;
03190 val = xstrdup("(unknown type)");
03191 break;
03192 }
03193
03194
03195
03196 if (datafree)
03197 data = headerFreeData(data, type);
03198
03199
03200
03201 if (val && need > 0) {
03202 t = hsaReserve(hsa, need);
03203
03204 te = stpcpy(t, val);
03205
03206 hsa->vallen += (te - t);
03207 val = _free(val);
03208 }
03209
03210
03211 return (hsa->val + hsa->vallen);
03212 }
03213
03220
03221 static char * singleSprintf(headerSprintfArgs hsa, sprintfToken token,
03222 int element)
03223
03224 {
03225 char * t, * te;
03226 int i, j;
03227 int numElements;
03228 int_32 type;
03229 int_32 count;
03230 sprintfToken spft;
03231 int condNumFormats;
03232 size_t need;
03233
03234
03235
03236 switch (token->type) {
03237 case PTOK_NONE:
03238 break;
03239
03240 case PTOK_STRING:
03241 need = token->u.string.len;
03242 if (need == 0) break;
03243 t = hsaReserve(hsa, need);
03244
03245 te = stpcpy(t, token->u.string.string);
03246
03247 hsa->vallen += (te - t);
03248 break;
03249
03250 case PTOK_TAG:
03251 t = hsa->val + hsa->vallen;
03252 te = formatValue(hsa, &token->u.tag,
03253 (token->u.tag.justOne ? 0 : element));
03254 if (te == NULL)
03255 return NULL;
03256 break;
03257
03258 case PTOK_COND:
03259 if (token->u.cond.tag.ext || headerIsEntry(hsa->h, token->u.cond.tag.tag)) {
03260 spft = token->u.cond.ifFormat;
03261 condNumFormats = token->u.cond.numIfTokens;
03262 } else {
03263 spft = token->u.cond.elseFormat;
03264 condNumFormats = token->u.cond.numElseTokens;
03265 }
03266
03267 need = condNumFormats * 20;
03268 if (spft == NULL || need == 0) break;
03269
03270 t = hsaReserve(hsa, need);
03271 for (i = 0; i < condNumFormats; i++, spft++) {
03272 te = singleSprintf(hsa, spft, element);
03273 if (te == NULL)
03274 return NULL;
03275 }
03276 break;
03277
03278 case PTOK_ARRAY:
03279 numElements = -1;
03280 spft = token->u.array.format;
03281 for (i = 0; i < token->u.array.numTokens; i++, spft++)
03282 {
03283 if (spft->type != PTOK_TAG ||
03284 spft->u.tag.arrayCount ||
03285 spft->u.tag.justOne) continue;
03286
03287 if (spft->u.tag.ext) {
03288
03289 if (getExtension(hsa, spft->u.tag.ext, &type, NULL, &count,
03290 hsa->ec + spft->u.tag.extNum))
03291 continue;
03292
03293 } else {
03294
03295 if (!headerGetEntry(hsa->h, spft->u.tag.tag, &type, NULL, &count))
03296 continue;
03297
03298 }
03299
03300 if (type == RPM_BIN_TYPE)
03301 count = 1;
03302
03303 if (numElements > 1 && count != numElements)
03304 switch (type) {
03305 default:
03306 hsa->errmsg =
03307 _("array iterator used with different sized arrays");
03308 return NULL;
03309 break;
03310 case RPM_BIN_TYPE:
03311 case RPM_STRING_TYPE:
03312 break;
03313 }
03314 if (count > numElements)
03315 numElements = count;
03316 }
03317
03318 if (numElements == -1) {
03319 need = sizeof("(none)") - 1;
03320 t = hsaReserve(hsa, need);
03321
03322 te = stpcpy(t, "(none)");
03323
03324 hsa->vallen += (te - t);
03325 } else {
03326 int isxml;
03327
03328 need = numElements * token->u.array.numTokens * 10;
03329 if (need == 0) break;
03330
03331 spft = token->u.array.format;
03332 isxml = (spft->type == PTOK_TAG && spft->u.tag.type != NULL &&
03333 !strcmp(spft->u.tag.type, "xml"));
03334
03335 if (isxml) {
03336 const char * tagN = myTagName(hsa->tags, spft->u.tag.tag);
03337
03338 need = sizeof(" <rpmTag name=\"\">\n") - 1;
03339 if (tagN != NULL)
03340 need += strlen(tagN);
03341 t = hsaReserve(hsa, need);
03342
03343 te = stpcpy(t, " <rpmTag name=\"");
03344 if (tagN != NULL)
03345 te = stpcpy(te, tagN);
03346 te = stpcpy(te, "\">\n");
03347
03348 hsa->vallen += (te - t);
03349 }
03350
03351 t = hsaReserve(hsa, need);
03352 for (j = 0; j < numElements; j++) {
03353 spft = token->u.array.format;
03354 for (i = 0; i < token->u.array.numTokens; i++, spft++) {
03355 te = singleSprintf(hsa, spft, j);
03356 if (te == NULL)
03357 return NULL;
03358 }
03359 }
03360
03361 if (isxml) {
03362 need = sizeof(" </rpmTag>\n") - 1;
03363 t = hsaReserve(hsa, need);
03364
03365 te = stpcpy(t, " </rpmTag>\n");
03366
03367 hsa->vallen += (te - t);
03368 }
03369
03370 }
03371 break;
03372 }
03373
03374 return (hsa->val + hsa->vallen);
03375 }
03376
03382 static rpmec
03383 rpmecNew(const headerSprintfExtension exts)
03384
03385 {
03386 headerSprintfExtension ext;
03387 rpmec ec;
03388 int i = 0;
03389
03390 for (ext = exts; ext != NULL && ext->type != HEADER_EXT_LAST;
03391 ext = (ext->type == HEADER_EXT_MORE ? ext->u.more : ext+1))
03392 {
03393 i++;
03394 }
03395
03396 ec = xcalloc(i, sizeof(*ec));
03397 return ec;
03398 }
03399
03406 static rpmec
03407 rpmecFree(const headerSprintfExtension exts, rpmec ec)
03408
03409 {
03410 headerSprintfExtension ext;
03411 int i = 0;
03412
03413 for (ext = exts; ext != NULL && ext->type != HEADER_EXT_LAST;
03414 ext = (ext->type == HEADER_EXT_MORE ? ext->u.more : ext+1))
03415 {
03416
03417 if (ec[i].freeit) ec[i].data = _free(ec[i].data);
03418
03419 i++;
03420 }
03421
03422 ec = _free(ec);
03423 return NULL;
03424 }
03425
03437 static
03438 char * headerSprintf(Header h, const char * fmt,
03439 const struct headerTagTableEntry_s * tbltags,
03440 const struct headerSprintfExtension_s * extensions,
03441 errmsg_t * errmsg)
03442
03443
03444 {
03445 headerSprintfArgs hsa = memset(alloca(sizeof(*hsa)), 0, sizeof(*hsa));
03446 sprintfToken nextfmt;
03447 sprintfTag tag;
03448 char * t, * te;
03449 int isxml;
03450 int need;
03451
03452 hsa->h = headerLink(h);
03453 hsa->fmt = xstrdup(fmt);
03454
03455 hsa->exts = (headerSprintfExtension) extensions;
03456 hsa->tags = (headerTagTableEntry) tbltags;
03457
03458 hsa->errmsg = NULL;
03459
03460
03461 if (parseFormat(hsa, hsa->fmt, &hsa->format, &hsa->numTokens, NULL, PARSER_BEGIN))
03462 goto exit;
03463
03464
03465 hsa->ec = rpmecNew(hsa->exts);
03466 hsa->val = xstrdup("");
03467
03468 tag =
03469 (hsa->format->type == PTOK_TAG
03470 ? &hsa->format->u.tag :
03471 (hsa->format->type == PTOK_ARRAY
03472 ? &hsa->format->u.array.format->u.tag :
03473 NULL));
03474 isxml = (tag != NULL && tag->tag == -2 && tag->type != NULL && !strcmp(tag->type, "xml"));
03475
03476 if (isxml) {
03477 need = sizeof("<rpmHeader>\n") - 1;
03478 t = hsaReserve(hsa, need);
03479
03480 te = stpcpy(t, "<rpmHeader>\n");
03481
03482 hsa->vallen += (te - t);
03483 }
03484
03485 hsa = hsaInit(hsa);
03486 while ((nextfmt = hsaNext(hsa)) != NULL) {
03487 te = singleSprintf(hsa, nextfmt, 0);
03488 if (te == NULL) {
03489 hsa->val = _free(hsa->val);
03490 break;
03491 }
03492 }
03493 hsa = hsaFini(hsa);
03494
03495 if (isxml) {
03496 need = sizeof("</rpmHeader>\n") - 1;
03497 t = hsaReserve(hsa, need);
03498
03499 te = stpcpy(t, "</rpmHeader>\n");
03500
03501 hsa->vallen += (te - t);
03502 }
03503
03504 if (hsa->val != NULL && hsa->vallen < hsa->alloced)
03505 hsa->val = xrealloc(hsa->val, hsa->vallen+1);
03506
03507 hsa->ec = rpmecFree(hsa->exts, hsa->ec);
03508 hsa->format = freeFormat(hsa->format, hsa->numTokens);
03509
03510 exit:
03511
03512 if (errmsg)
03513 *errmsg = hsa->errmsg;
03514
03515 hsa->h = headerFree(hsa->h);
03516 hsa->fmt = _free(hsa->fmt);
03517 return hsa->val;
03518 }
03519
03528 static char * octalFormat(int_32 type, hPTR_t data,
03529 char * formatPrefix, int padding, int element)
03530
03531 {
03532 char * val;
03533
03534 if (type != RPM_INT32_TYPE) {
03535 val = xstrdup(_("(not a number)"));
03536 } else {
03537 val = xmalloc(20 + padding);
03538
03539 strcat(formatPrefix, "o");
03540
03541
03542 sprintf(val, formatPrefix, *((int_32 *) data));
03543
03544 }
03545
03546 return val;
03547 }
03548
03557 static char * hexFormat(int_32 type, hPTR_t data,
03558 char * formatPrefix, int padding, int element)
03559
03560 {
03561 char * val;
03562
03563 if (type != RPM_INT32_TYPE) {
03564 val = xstrdup(_("(not a number)"));
03565 } else {
03566 val = xmalloc(20 + padding);
03567
03568 strcat(formatPrefix, "x");
03569
03570
03571 sprintf(val, formatPrefix, *((int_32 *) data));
03572
03573 }
03574
03575 return val;
03576 }
03577
03580 static char * realDateFormat(int_32 type, hPTR_t data,
03581 char * formatPrefix, int padding, int element,
03582 const char * strftimeFormat)
03583
03584 {
03585 char * val;
03586
03587 if (type != RPM_INT32_TYPE) {
03588 val = xstrdup(_("(not a number)"));
03589 } else {
03590 struct tm * tstruct;
03591 char buf[50];
03592
03593 val = xmalloc(50 + padding);
03594
03595 strcat(formatPrefix, "s");
03596
03597
03598
03599 { time_t dateint = *((int_32 *) data);
03600 tstruct = localtime(&dateint);
03601 }
03602 buf[0] = '\0';
03603 if (tstruct)
03604 (void) strftime(buf, sizeof(buf) - 1, strftimeFormat, tstruct);
03605
03606 sprintf(val, formatPrefix, buf);
03607
03608 }
03609
03610 return val;
03611 }
03612
03621 static char * dateFormat(int_32 type, hPTR_t data,
03622 char * formatPrefix, int padding, int element)
03623
03624 {
03625 return realDateFormat(type, data, formatPrefix, padding, element,
03626 _("%c"));
03627 }
03628
03637 static char * dayFormat(int_32 type, hPTR_t data,
03638 char * formatPrefix, int padding, int element)
03639
03640 {
03641 return realDateFormat(type, data, formatPrefix, padding, element,
03642 _("%a %b %d %Y"));
03643 }
03644
03653 static char * shescapeFormat(int_32 type, hPTR_t data,
03654 char * formatPrefix, int padding, int element)
03655
03656 {
03657 char * result, * dst, * src, * buf;
03658
03659 if (type == RPM_INT32_TYPE) {
03660 result = xmalloc(padding + 20);
03661
03662 strcat(formatPrefix, "d");
03663
03664
03665 sprintf(result, formatPrefix, *((int_32 *) data));
03666
03667 } else {
03668 buf = alloca(strlen(data) + padding + 2);
03669
03670 strcat(formatPrefix, "s");
03671
03672
03673 sprintf(buf, formatPrefix, data);
03674
03675
03676
03677 result = dst = xmalloc(strlen(buf) * 4 + 3);
03678 *dst++ = '\'';
03679 for (src = buf; *src != '\0'; src++) {
03680 if (*src == '\'') {
03681 *dst++ = '\'';
03682 *dst++ = '\\';
03683 *dst++ = '\'';
03684 *dst++ = '\'';
03685 } else {
03686 *dst++ = *src;
03687 }
03688 }
03689 *dst++ = '\'';
03690 *dst = '\0';
03691
03692
03693 }
03694
03695 return result;
03696 }
03697
03698
03699 const struct headerSprintfExtension_s headerDefaultFormats[] = {
03700 { HEADER_EXT_FORMAT, "octal", { octalFormat } },
03701 { HEADER_EXT_FORMAT, "hex", { hexFormat } },
03702 { HEADER_EXT_FORMAT, "date", { dateFormat } },
03703 { HEADER_EXT_FORMAT, "day", { dayFormat } },
03704 { HEADER_EXT_FORMAT, "shescape", { shescapeFormat } },
03705 { HEADER_EXT_LAST, NULL, { NULL } }
03706 };
03707
03708
03715 static
03716 void headerCopyTags(Header headerFrom, Header headerTo, hTAG_t tagstocopy)
03717
03718 {
03719 int * p;
03720
03721 if (headerFrom == headerTo)
03722 return;
03723
03724 for (p = tagstocopy; *p != 0; p++) {
03725 char *s;
03726 int_32 type;
03727 int_32 count;
03728 if (headerIsEntry(headerTo, *p))
03729 continue;
03730
03731 if (!headerGetEntryMinMemory(headerFrom, *p, &type,
03732 (hPTR_t *) &s, &count))
03733 continue;
03734
03735 (void) headerAddEntry(headerTo, *p, type, s, count);
03736 s = headerFreeData(s, type);
03737 }
03738 }
03739
03740
03741 static struct HV_s hdrVec1 = {
03742 headerLink,
03743 headerUnlink,
03744 headerFree,
03745 headerNew,
03746 headerSort,
03747 headerUnsort,
03748 headerSizeof,
03749 headerUnload,
03750 headerReload,
03751 headerCopy,
03752 headerLoad,
03753 headerCopyLoad,
03754 headerRead,
03755 headerWrite,
03756 headerIsEntry,
03757 headerFreeTag,
03758 headerGetEntry,
03759 headerGetEntryMinMemory,
03760 headerAddEntry,
03761 headerAppendEntry,
03762 headerAddOrAppendEntry,
03763 headerAddI18NString,
03764 headerModifyEntry,
03765 headerRemoveEntry,
03766 headerSprintf,
03767 headerCopyTags,
03768 headerFreeIterator,
03769 headerInitIterator,
03770 headerNextIterator,
03771 NULL, NULL,
03772 1
03773 };
03774
03775
03776
03777 HV_t hdrVec = &hdrVec1;
03778