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 (rdlen != dl)
01062 goto errxit;
01063 entry->rdlen = rdlen;
01064 entry++;
01065 h->indexUsed++;
01066 } else {
01067 int_32 rdl;
01068 int_32 ril;
01069
01070 h->flags &= ~HEADERFLAG_LEGACY;
01071
01072 entry->info.type = htonl(pe->type);
01073 entry->info.count = htonl(pe->count);
01074 entry->info.tag = htonl(pe->tag);
01075
01076 if (!ENTRY_IS_REGION(entry))
01077 goto errxit;
01078 if (entry->info.type != REGION_TAG_TYPE)
01079 goto errxit;
01080 if (entry->info.count != REGION_TAG_COUNT)
01081 goto errxit;
01082
01083 { int off = ntohl(pe->offset);
01084
01085 if (hdrchkData(off))
01086 goto errxit;
01087 if (off) {
01088
01089 size_t nb = REGION_TAG_COUNT;
01090
01091 int_32 * stei = memcpy(alloca(nb), dataStart + off, nb);
01092 rdl = -ntohl(stei[2]);
01093 ril = rdl/sizeof(*pe);
01094 if (hdrchkTags(ril) || hdrchkData(rdl))
01095 goto errxit;
01096 } else {
01097 ril = il;
01098
01099 rdl = (ril * sizeof(struct entryInfo_s));
01100
01101 entry->info.tag = HEADER_IMAGE;
01102 }
01103 }
01104 entry->info.offset = -rdl;
01105
01106
01107 entry->data = pe;
01108
01109 entry->length = pvlen - sizeof(il) - sizeof(dl);
01110 rdlen = regionSwab(entry+1, ril-1, 0, pe+1, dataStart, dataEnd, entry->info.offset);
01111 if (rdlen < 0)
01112 goto errxit;
01113 entry->rdlen = rdlen;
01114
01115 if (ril < h->indexUsed) {
01116 indexEntry newEntry = entry + ril;
01117 int ne = (h->indexUsed - ril);
01118 int rid = entry->info.offset+1;
01119
01120
01121 rdlen = regionSwab(newEntry, ne, rdlen, pe+ril,
01122 dataStart, dataEnd, rid);
01123 if (rdlen < 0)
01124 goto errxit;
01125
01126 { indexEntry firstEntry = newEntry;
01127 int save = h->indexUsed;
01128 int j;
01129
01130
01131 h->indexUsed -= ne;
01132 for (j = 0; j < ne; j++, newEntry++) {
01133 (void) headerRemoveEntry(h, newEntry->info.tag);
01134 if (newEntry->info.tag == HEADER_BASENAMES)
01135 (void) headerRemoveEntry(h, HEADER_OLDFILENAMES);
01136 }
01137
01138
01139
01140 if (h->indexUsed < (save - ne)) {
01141 memmove(h->index + h->indexUsed, firstEntry,
01142 (ne * sizeof(*entry)));
01143 }
01144
01145 h->indexUsed += ne;
01146 }
01147 }
01148
01149 rdlen += REGION_TAG_COUNT;
01150
01151 if (rdlen != dl)
01152 goto errxit;
01153 }
01154
01155 h->flags &= ~HEADERFLAG_SORTED;
01156 headerSort(h);
01157
01158
01159 return h;
01160
01161
01162 errxit:
01163
01164 if (h) {
01165 h->index = _free(h->index);
01166
01167 h = _free(h);
01168
01169 }
01170
01171
01172 return h;
01173
01174 }
01175
01183 static
01184 Header headerReload( Header h, int tag)
01185
01186 {
01187 Header nh;
01188 int length;
01189
01190
01191 void * uh = doHeaderUnload(h, &length);
01192
01193
01194 h = headerFree(h);
01195
01196 if (uh == NULL)
01197 return NULL;
01198 nh = headerLoad(uh);
01199 if (nh == NULL) {
01200 uh = _free(uh);
01201 return NULL;
01202 }
01203 if (nh->flags & HEADERFLAG_ALLOCATED)
01204 uh = _free(uh);
01205 nh->flags |= HEADERFLAG_ALLOCATED;
01206 if (ENTRY_IS_REGION(nh->index)) {
01207
01208 if (tag == HEADER_SIGNATURES || tag == HEADER_IMMUTABLE)
01209 nh->index[0].info.tag = tag;
01210
01211 }
01212 return nh;
01213 }
01214
01220 static
01221 Header headerCopyLoad(const void * uh)
01222
01223 {
01224 int_32 * ei = (int_32 *) uh;
01225
01226 int_32 il = ntohl(ei[0]);
01227 int_32 dl = ntohl(ei[1]);
01228
01229
01230 size_t pvlen = sizeof(il) + sizeof(dl) +
01231 (il * sizeof(struct entryInfo_s)) + dl;
01232
01233 void * nuh = NULL;
01234 Header h = NULL;
01235
01236
01237
01238 if (!(hdrchkTags(il) || hdrchkData(dl)) && pvlen < headerMaxbytes) {
01239
01240 nuh = memcpy(xmalloc(pvlen), uh, pvlen);
01241
01242 if ((h = headerLoad(nuh)) != NULL)
01243 h->flags |= HEADERFLAG_ALLOCATED;
01244 }
01245
01246
01247 if (h == NULL)
01248 nuh = _free(nuh);
01249
01250 return h;
01251 }
01252
01259 static
01260 Header headerRead(FD_t fd, enum hMagic magicp)
01261
01262 {
01263 int_32 block[4];
01264 int_32 reserved;
01265 int_32 * ei = NULL;
01266 int_32 il;
01267 int_32 dl;
01268 int_32 magic;
01269 Header h = NULL;
01270 size_t len;
01271 int i;
01272
01273 memset(block, 0, sizeof(block));
01274 i = 2;
01275 if (magicp == HEADER_MAGIC_YES)
01276 i += 2;
01277
01278
01279 if (timedRead(fd, (char *)block, i*sizeof(*block)) != (i * sizeof(*block)))
01280 goto exit;
01281
01282
01283 i = 0;
01284
01285
01286 if (magicp == HEADER_MAGIC_YES) {
01287 magic = block[i++];
01288 if (memcmp(&magic, header_magic, sizeof(magic)))
01289 goto exit;
01290 reserved = block[i++];
01291 }
01292
01293 il = ntohl(block[i]); i++;
01294 dl = ntohl(block[i]); i++;
01295
01296
01297
01298 len = sizeof(il) + sizeof(dl) + (il * sizeof(struct entryInfo_s)) + dl;
01299
01300
01301
01302 if (hdrchkTags(il) || hdrchkData(dl) || len > headerMaxbytes)
01303 goto exit;
01304
01305
01306 ei = xmalloc(len);
01307 ei[0] = htonl(il);
01308 ei[1] = htonl(dl);
01309 len -= sizeof(il) + sizeof(dl);
01310
01311
01312
01313
01314 if (timedRead(fd, (char *)&ei[2], len) != len)
01315 goto exit;
01316
01317
01318
01319 h = headerLoad(ei);
01320
01321 exit:
01322 if (h) {
01323 if (h->flags & HEADERFLAG_ALLOCATED)
01324 ei = _free(ei);
01325 h->flags |= HEADERFLAG_ALLOCATED;
01326 } else if (ei)
01327 ei = _free(ei);
01328
01329 return h;
01330
01331 }
01332
01340 static
01341 int headerWrite(FD_t fd, Header h, enum hMagic magicp)
01342
01343
01344 {
01345 ssize_t nb;
01346 int length;
01347 const void * uh;
01348
01349 if (h == NULL)
01350 return 1;
01351
01352 uh = doHeaderUnload(h, &length);
01353
01354 if (uh == NULL)
01355 return 1;
01356 switch (magicp) {
01357 case HEADER_MAGIC_YES:
01358
01359
01360 nb = Fwrite(header_magic, sizeof(char), sizeof(header_magic), fd);
01361
01362
01363 if (nb != sizeof(header_magic))
01364 goto exit;
01365 break;
01366 case HEADER_MAGIC_NO:
01367 break;
01368 }
01369
01370
01371 nb = Fwrite(uh, sizeof(char), length, fd);
01372
01373
01374 exit:
01375 uh = _free(uh);
01376 return (nb == length ? 0 : 1);
01377 }
01378
01385 static
01386 int headerIsEntry(Header h, int_32 tag)
01387
01388 {
01389
01390 return (findEntry(h, tag, RPM_NULL_TYPE) ? 1 : 0);
01391
01392 }
01393
01404 static int copyEntry(const indexEntry entry,
01405 hTYP_t type,
01406 hPTR_t * p,
01407 hCNT_t c,
01408 int minMem)
01409
01410
01411 {
01412 int_32 count = entry->info.count;
01413 int rc = 1;
01414
01415 if (p)
01416 switch (entry->info.type) {
01417 case RPM_BIN_TYPE:
01418
01419
01420
01421
01422
01423
01424 if (ENTRY_IS_REGION(entry)) {
01425 int_32 * ei = ((int_32 *)entry->data) - 2;
01426
01427 entryInfo pe = (entryInfo) (ei + 2);
01428
01429
01430 char * dataStart = (char *) (pe + ntohl(ei[0]));
01431
01432 int_32 rdl = -entry->info.offset;
01433 int_32 ril = rdl/sizeof(*pe);
01434
01435
01436 rdl = entry->rdlen;
01437 count = 2 * sizeof(*ei) + (ril * sizeof(*pe)) + rdl;
01438 if (entry->info.tag == HEADER_IMAGE) {
01439 ril -= 1;
01440 pe += 1;
01441 } else {
01442 count += REGION_TAG_COUNT;
01443 rdl += REGION_TAG_COUNT;
01444 }
01445
01446
01447 *p = xmalloc(count);
01448 ei = (int_32 *) *p;
01449 ei[0] = htonl(ril);
01450 ei[1] = htonl(rdl);
01451
01452
01453 pe = (entryInfo) memcpy(ei + 2, pe, (ril * sizeof(*pe)));
01454
01455
01456 dataStart = (char *) memcpy(pe + ril, dataStart, rdl);
01457
01458
01459
01460 rc = regionSwab(NULL, ril, 0, pe, dataStart, dataStart + rdl, 0);
01461
01462 rc = (rc < 0) ? 0 : 1;
01463 } else {
01464 count = entry->length;
01465 *p = (!minMem
01466 ? memcpy(xmalloc(count), entry->data, count)
01467 : entry->data);
01468 }
01469 break;
01470 case RPM_STRING_TYPE:
01471 if (count == 1) {
01472 *p = entry->data;
01473 break;
01474 }
01475
01476 case RPM_STRING_ARRAY_TYPE:
01477 case RPM_I18NSTRING_TYPE:
01478 { const char ** ptrEntry;
01479
01480 int tableSize = count * sizeof(char *);
01481
01482 char * t;
01483 int i;
01484
01485
01486
01487 if (minMem) {
01488 *p = xmalloc(tableSize);
01489 ptrEntry = (const char **) *p;
01490 t = entry->data;
01491 } else {
01492 t = xmalloc(tableSize + entry->length);
01493 *p = (void *)t;
01494 ptrEntry = (const char **) *p;
01495 t += tableSize;
01496 memcpy(t, entry->data, entry->length);
01497 }
01498
01499
01500 for (i = 0; i < count; i++) {
01501
01502 *ptrEntry++ = t;
01503
01504 t = strchr(t, 0);
01505 t++;
01506 }
01507 } break;
01508
01509 default:
01510 *p = entry->data;
01511 break;
01512 }
01513 if (type) *type = entry->info.type;
01514 if (c) *c = count;
01515 return rc;
01516 }
01517
01536 static int headerMatchLocale(const char *td, const char *l, const char *le)
01537
01538 {
01539 const char *fe;
01540
01541
01542 #if 0
01543 { const char *s, *ll, *CC, *EE, *dd;
01544 char *lbuf, *t.
01545
01546
01547 lbuf = alloca(le - l + 1);
01548 for (s = l, ll = t = lbuf; *s; s++, t++) {
01549 switch (*s) {
01550 case '_':
01551 *t = '\0';
01552 CC = t + 1;
01553 break;
01554 case '.':
01555 *t = '\0';
01556 EE = t + 1;
01557 break;
01558 case '@':
01559 *t = '\0';
01560 dd = t + 1;
01561 break;
01562 default:
01563 *t = *s;
01564 break;
01565 }
01566 }
01567
01568 if (ll)
01569 for (t = ll; *t; t++) *t = tolower(*t);
01570 if (CC)
01571 for (t = CC; *t; t++) *t = toupper(*t);
01572
01573
01574 }
01575 #endif
01576
01577
01578 if (strlen(td) == (le-l) && !strncmp(td, l, (le - l)))
01579 return 1;
01580
01581
01582 for (fe = l; fe < le && *fe != '@'; fe++)
01583 {};
01584 if (fe < le && !strncmp(td, l, (fe - l)))
01585 return 1;
01586
01587
01588 for (fe = l; fe < le && *fe != '.'; fe++)
01589 {};
01590 if (fe < le && !strncmp(td, l, (fe - l)))
01591 return 1;
01592
01593
01594 for (fe = l; fe < le && *fe != '_'; fe++)
01595 {};
01596 if (fe < le && !strncmp(td, l, (fe - l)))
01597 return 2;
01598
01599 return 0;
01600 }
01601
01608 static char *
01609 headerFindI18NString(Header h, indexEntry entry)
01610
01611 {
01612 const char *lang, *l, *le;
01613 indexEntry table;
01614
01615
01616 if ((lang = getenv("LANGUAGE")) == NULL &&
01617 (lang = getenv("LC_ALL")) == NULL &&
01618 (lang = getenv("LC_MESSAGES")) == NULL &&
01619 (lang = getenv("LANG")) == NULL)
01620 return entry->data;
01621
01622
01623 if ((table = findEntry(h, HEADER_I18NTABLE, RPM_STRING_ARRAY_TYPE)) == NULL)
01624 return entry->data;
01625
01626
01627
01628 for (l = lang; *l != '\0'; l = le) {
01629 const char *td;
01630 char *ed, *ed_weak = NULL;
01631 int langNum;
01632
01633 while (*l && *l == ':')
01634 l++;
01635 if (*l == '\0')
01636 break;
01637 for (le = l; *le && *le != ':'; le++)
01638 {};
01639
01640
01641 for (langNum = 0, td = table->data, ed = entry->data;
01642 langNum < entry->info.count;
01643 langNum++, td += strlen(td) + 1, ed += strlen(ed) + 1) {
01644
01645 int match = headerMatchLocale(td, l, le);
01646 if (match == 1) return ed;
01647 else if (match == 2) ed_weak = ed;
01648
01649 }
01650 if (ed_weak) return ed_weak;
01651 }
01652
01653
01654 return entry->data;
01655 }
01656
01667 static int intGetEntry(Header h, int_32 tag,
01668 hTAG_t type,
01669 hPTR_t * p,
01670 hCNT_t c,
01671 int minMem)
01672
01673
01674 {
01675 indexEntry entry;
01676 int rc;
01677
01678
01679
01680 entry = findEntry(h, tag, RPM_NULL_TYPE);
01681
01682 if (entry == NULL) {
01683 if (type) type = 0;
01684 if (p) *p = NULL;
01685 if (c) *c = 0;
01686 return 0;
01687 }
01688
01689 switch (entry->info.type) {
01690 case RPM_I18NSTRING_TYPE:
01691 rc = 1;
01692 if (type) *type = RPM_STRING_TYPE;
01693 if (c) *c = 1;
01694
01695 if (p) *p = headerFindI18NString(h, entry);
01696
01697 break;
01698 default:
01699 rc = copyEntry(entry, type, p, c, minMem);
01700 break;
01701 }
01702
01703
01704 return ((rc == 1) ? 1 : 0);
01705 }
01706
01714 static void * headerFreeTag( Header h,
01715 const void * data, rpmTagType type)
01716
01717 {
01718 if (data) {
01719
01720 if (type == -1 ||
01721 type == RPM_STRING_ARRAY_TYPE ||
01722 type == RPM_I18NSTRING_TYPE ||
01723 type == RPM_BIN_TYPE)
01724 data = _free(data);
01725
01726 }
01727 return NULL;
01728 }
01729
01743 static
01744 int headerGetEntry(Header h, int_32 tag,
01745 hTYP_t type,
01746 void ** p,
01747 hCNT_t c)
01748
01749
01750 {
01751 return intGetEntry(h, tag, type, (hPTR_t *)p, c, 0);
01752 }
01753
01766 static
01767 int headerGetEntryMinMemory(Header h, int_32 tag,
01768 hTYP_t type,
01769 hPTR_t * p,
01770 hCNT_t c)
01771
01772
01773 {
01774 return intGetEntry(h, tag, type, p, c, 1);
01775 }
01776
01777 int headerGetRawEntry(Header h, int_32 tag, int_32 * type, hPTR_t * p,
01778 int_32 * c)
01779 {
01780 indexEntry entry;
01781 int rc;
01782
01783 if (p == NULL) return headerIsEntry(h, tag);
01784
01785
01786
01787 entry = findEntry(h, tag, RPM_NULL_TYPE);
01788
01789 if (!entry) {
01790 if (p) *p = NULL;
01791 if (c) *c = 0;
01792 return 0;
01793 }
01794
01795 rc = copyEntry(entry, type, p, c, 0);
01796
01797
01798 return ((rc == 1) ? 1 : 0);
01799 }
01800
01803 static void copyData(int_32 type, void * dstPtr, const void * srcPtr,
01804 int_32 cnt, int dataLength)
01805
01806 {
01807 switch (type) {
01808 case RPM_STRING_ARRAY_TYPE:
01809 case RPM_I18NSTRING_TYPE:
01810 { const char ** av = (const char **) srcPtr;
01811 char * t = dstPtr;
01812
01813
01814 while (cnt-- > 0 && dataLength > 0) {
01815 const char * s;
01816 if ((s = *av++) == NULL)
01817 continue;
01818 do {
01819 *t++ = *s++;
01820 } while (s[-1] && --dataLength > 0);
01821 }
01822
01823 } break;
01824
01825 default:
01826
01827 memmove(dstPtr, srcPtr, dataLength);
01828
01829 break;
01830 }
01831 }
01832
01841
01842 static void *
01843 grabData(int_32 type, hPTR_t p, int_32 c, int * lengthPtr)
01844
01845
01846 {
01847 void * data = NULL;
01848 int length;
01849
01850 length = dataLength(type, p, c, 0, NULL);
01851
01852 if (length > 0) {
01853 data = xmalloc(length);
01854 copyData(type, data, p, c, length);
01855 }
01856
01857
01858 if (lengthPtr)
01859 *lengthPtr = length;
01860 return data;
01861 }
01862
01877 static
01878 int headerAddEntry(Header h, int_32 tag, int_32 type, const void * p, int_32 c)
01879
01880 {
01881 indexEntry entry;
01882 void * data;
01883 int length;
01884
01885
01886 if (c <= 0)
01887 return 0;
01888
01889 if (hdrchkType(type))
01890 return 0;
01891 if (hdrchkData(c))
01892 return 0;
01893
01894 length = 0;
01895
01896 data = grabData(type, p, c, &length);
01897
01898 if (data == NULL || length <= 0)
01899 return 0;
01900
01901
01902 if (h->indexUsed == h->indexAlloced) {
01903 h->indexAlloced += INDEX_MALLOC_SIZE;
01904 h->index = xrealloc(h->index, h->indexAlloced * sizeof(*h->index));
01905 }
01906
01907
01908 entry = h->index + h->indexUsed;
01909 entry->info.tag = tag;
01910 entry->info.type = type;
01911 entry->info.count = c;
01912 entry->info.offset = 0;
01913 entry->data = data;
01914 entry->length = length;
01915
01916
01917 if (h->indexUsed > 0 && tag < h->index[h->indexUsed-1].info.tag)
01918 h->flags &= ~HEADERFLAG_SORTED;
01919
01920 h->indexUsed++;
01921
01922 return 1;
01923 }
01924
01939 static
01940 int headerAppendEntry(Header h, int_32 tag, int_32 type,
01941 const void * p, int_32 c)
01942
01943 {
01944 indexEntry entry;
01945 int length;
01946
01947 if (type == RPM_STRING_TYPE || type == RPM_I18NSTRING_TYPE) {
01948
01949 return 0;
01950 }
01951
01952
01953 entry = findEntry(h, tag, type);
01954 if (!entry)
01955 return 0;
01956
01957 length = dataLength(type, p, c, 0, NULL);
01958 if (length < 0)
01959 return 0;
01960
01961 if (ENTRY_IN_REGION(entry)) {
01962 char * t = xmalloc(entry->length + length);
01963
01964 memcpy(t, entry->data, entry->length);
01965
01966 entry->data = t;
01967 entry->info.offset = 0;
01968 } else
01969 entry->data = xrealloc(entry->data, entry->length + length);
01970
01971 copyData(type, ((char *) entry->data) + entry->length, p, c, length);
01972
01973 entry->length += length;
01974
01975 entry->info.count += c;
01976
01977 return 1;
01978 }
01979
01990 static
01991 int headerAddOrAppendEntry(Header h, int_32 tag, int_32 type,
01992 const void * p, int_32 c)
01993
01994 {
01995 return (findEntry(h, tag, type)
01996 ? headerAppendEntry(h, tag, type, p, c)
01997 : headerAddEntry(h, tag, type, p, c));
01998 }
01999
02020 static
02021 int headerAddI18NString(Header h, int_32 tag, const char * string,
02022 const char * lang)
02023
02024 {
02025 indexEntry table, entry;
02026 const char ** strArray;
02027 int length;
02028 int ghosts;
02029 int i, langNum;
02030 char * buf;
02031
02032 table = findEntry(h, HEADER_I18NTABLE, RPM_STRING_ARRAY_TYPE);
02033 entry = findEntry(h, tag, RPM_I18NSTRING_TYPE);
02034
02035 if (!table && entry)
02036 return 0;
02037
02038 if (!table && !entry) {
02039 const char * charArray[2];
02040 int count = 0;
02041 if (!lang || (lang[0] == 'C' && lang[1] == '\0')) {
02042
02043 charArray[count++] = "C";
02044
02045 } else {
02046
02047 charArray[count++] = "C";
02048
02049 charArray[count++] = lang;
02050 }
02051 if (!headerAddEntry(h, HEADER_I18NTABLE, RPM_STRING_ARRAY_TYPE,
02052 &charArray, count))
02053 return 0;
02054 table = findEntry(h, HEADER_I18NTABLE, RPM_STRING_ARRAY_TYPE);
02055 }
02056
02057 if (!table)
02058 return 0;
02059
02060 if (!lang) lang = "C";
02061
02062
02063 { const char * l = table->data;
02064 for (langNum = 0; langNum < table->info.count; langNum++) {
02065 if (!strcmp(l, lang)) break;
02066 l += strlen(l) + 1;
02067 }
02068 }
02069
02070 if (langNum >= table->info.count) {
02071 length = strlen(lang) + 1;
02072 if (ENTRY_IN_REGION(table)) {
02073 char * t = xmalloc(table->length + length);
02074 memcpy(t, table->data, table->length);
02075 table->data = t;
02076 table->info.offset = 0;
02077 } else
02078 table->data = xrealloc(table->data, table->length + length);
02079 memmove(((char *)table->data) + table->length, lang, length);
02080 table->length += length;
02081 table->info.count++;
02082 }
02083
02084 if (!entry) {
02085 strArray = alloca(sizeof(*strArray) * (langNum + 1));
02086 for (i = 0; i < langNum; i++)
02087 strArray[i] = "";
02088 strArray[langNum] = string;
02089 return headerAddEntry(h, tag, RPM_I18NSTRING_TYPE, strArray,
02090 langNum + 1);
02091 } else if (langNum >= entry->info.count) {
02092 ghosts = langNum - entry->info.count;
02093
02094 length = strlen(string) + 1 + ghosts;
02095 if (ENTRY_IN_REGION(entry)) {
02096 char * t = xmalloc(entry->length + length);
02097 memcpy(t, entry->data, entry->length);
02098 entry->data = t;
02099 entry->info.offset = 0;
02100 } else
02101 entry->data = xrealloc(entry->data, entry->length + length);
02102
02103 memset(((char *)entry->data) + entry->length, '\0', ghosts);
02104 memmove(((char *)entry->data) + entry->length + ghosts, string, strlen(string)+1);
02105
02106 entry->length += length;
02107 entry->info.count = langNum + 1;
02108 } else {
02109 char *b, *be, *e, *ee, *t;
02110 size_t bn, sn, en;
02111
02112
02113 b = be = e = ee = entry->data;
02114 for (i = 0; i < table->info.count; i++) {
02115 if (i == langNum)
02116 be = ee;
02117 ee += strlen(ee) + 1;
02118 if (i == langNum)
02119 e = ee;
02120 }
02121
02122
02123 bn = (be-b);
02124 sn = strlen(string) + 1;
02125 en = (ee-e);
02126 length = bn + sn + en;
02127 t = buf = xmalloc(length);
02128
02129
02130 memcpy(t, b, bn);
02131 t += bn;
02132
02133 memcpy(t, string, sn);
02134 t += sn;
02135 memcpy(t, e, en);
02136 t += en;
02137
02138
02139
02140 entry->length -= strlen(be) + 1;
02141 entry->length += sn;
02142
02143 if (ENTRY_IN_REGION(entry)) {
02144 entry->info.offset = 0;
02145 } else
02146 entry->data = _free(entry->data);
02147
02148 entry->data = buf;
02149
02150 }
02151
02152 return 0;
02153 }
02154
02165 static
02166 int headerModifyEntry(Header h, int_32 tag, int_32 type,
02167 const void * p, int_32 c)
02168
02169 {
02170 indexEntry entry;
02171 void * oldData;
02172 void * data;
02173 int length;
02174
02175
02176 entry = findEntry(h, tag, type);
02177 if (!entry)
02178 return 0;
02179
02180 length = 0;
02181 data = grabData(type, p, c, &length);
02182 if (data == NULL || length <= 0)
02183 return 0;
02184
02185
02186 while (entry > h->index && (entry - 1)->info.tag == tag)
02187 entry--;
02188
02189
02190
02191 oldData = entry->data;
02192
02193 entry->info.count = c;
02194 entry->info.type = type;
02195 entry->data = data;
02196 entry->length = length;
02197
02198
02199 if (ENTRY_IN_REGION(entry)) {
02200 entry->info.offset = 0;
02201 } else
02202 oldData = _free(oldData);
02203
02204
02205 return 1;
02206 }
02207
02210 static char escapedChar(const char ch)
02211 {
02212 switch (ch) {
02213 case 'a': return '\a';
02214 case 'b': return '\b';
02215 case 'f': return '\f';
02216 case 'n': return '\n';
02217 case 'r': return '\r';
02218 case 't': return '\t';
02219 case 'v': return '\v';
02220 default: return ch;
02221 }
02222 }
02223
02230 static sprintfToken
02231 freeFormat( sprintfToken format, int num)
02232
02233 {
02234 int i;
02235
02236 if (format == NULL) return NULL;
02237
02238 for (i = 0; i < num; i++) {
02239 switch (format[i].type) {
02240 case PTOK_ARRAY:
02241
02242 format[i].u.array.format =
02243 freeFormat(format[i].u.array.format,
02244 format[i].u.array.numTokens);
02245
02246 break;
02247 case PTOK_COND:
02248
02249 format[i].u.cond.ifFormat =
02250 freeFormat(format[i].u.cond.ifFormat,
02251 format[i].u.cond.numIfTokens);
02252 format[i].u.cond.elseFormat =
02253 freeFormat(format[i].u.cond.elseFormat,
02254 format[i].u.cond.numElseTokens);
02255
02256 break;
02257 case PTOK_NONE:
02258 case PTOK_TAG:
02259 case PTOK_STRING:
02260 default:
02261 break;
02262 }
02263 }
02264 format = _free(format);
02265 return NULL;
02266 }
02267
02271 struct headerIterator_s {
02272
02273 Header h;
02274
02275 int next_index;
02276 };
02277
02283 static
02284 HeaderIterator headerFreeIterator( HeaderIterator hi)
02285
02286 {
02287 if (hi != NULL) {
02288 hi->h = headerFree(hi->h);
02289 hi = _free(hi);
02290 }
02291 return hi;
02292 }
02293
02299 static
02300 HeaderIterator headerInitIterator(Header h)
02301
02302 {
02303 HeaderIterator hi = xmalloc(sizeof(*hi));
02304
02305 headerSort(h);
02306
02307 hi->h = headerLink(h);
02308 hi->next_index = 0;
02309 return hi;
02310 }
02311
02321 static
02322 int headerNextIterator(HeaderIterator hi,
02323 hTAG_t tag,
02324 hTYP_t type,
02325 hPTR_t * p,
02326 hCNT_t c)
02327
02328
02329
02330 {
02331 Header h = hi->h;
02332 int slot = hi->next_index;
02333 indexEntry entry = NULL;
02334 int rc;
02335
02336 for (slot = hi->next_index; slot < h->indexUsed; slot++) {
02337 entry = h->index + slot;
02338 if (!ENTRY_IS_REGION(entry))
02339 break;
02340 }
02341 hi->next_index = slot;
02342 if (entry == NULL || slot >= h->indexUsed)
02343 return 0;
02344
02345
02346 hi->next_index++;
02347
02348
02349 if (tag)
02350 *tag = entry->info.tag;
02351
02352 rc = copyEntry(entry, type, p, c, 0);
02353
02354
02355 return ((rc == 1) ? 1 : 0);
02356 }
02357
02363 static
02364 Header headerCopy(Header h)
02365
02366 {
02367 Header nh = headerNew();
02368 HeaderIterator hi;
02369 int_32 tag, type, count;
02370 hPTR_t ptr;
02371
02372
02373 for (hi = headerInitIterator(h);
02374 headerNextIterator(hi, &tag, &type, &ptr, &count);
02375 ptr = headerFreeData((void *)ptr, type))
02376 {
02377 if (ptr) (void) headerAddEntry(nh, tag, type, ptr, count);
02378 }
02379 hi = headerFreeIterator(hi);
02380
02381
02382 return headerReload(nh, HEADER_IMAGE);
02383 }
02384
02387 typedef struct headerSprintfArgs_s {
02388 Header h;
02389 char * fmt;
02390
02391 headerTagTableEntry tags;
02392
02393 headerSprintfExtension exts;
02394
02395 const char * errmsg;
02396 rpmec ec;
02397 sprintfToken format;
02398
02399 HeaderIterator hi;
02400
02401 char * val;
02402 size_t vallen;
02403 size_t alloced;
02404 int numTokens;
02405 int i;
02406 } * headerSprintfArgs;
02407
02413 static headerSprintfArgs hsaInit( headerSprintfArgs hsa)
02414
02415 {
02416 sprintfTag tag =
02417 (hsa->format->type == PTOK_TAG
02418 ? &hsa->format->u.tag :
02419 (hsa->format->type == PTOK_ARRAY
02420 ? &hsa->format->u.array.format->u.tag :
02421 NULL));
02422
02423 if (hsa != NULL) {
02424 hsa->i = 0;
02425 if (tag != NULL && tag->tag == -2)
02426 hsa->hi = headerInitIterator(hsa->h);
02427 }
02428
02429 return hsa;
02430
02431 }
02432
02438
02439 static sprintfToken hsaNext( headerSprintfArgs hsa)
02440
02441 {
02442 sprintfToken fmt = NULL;
02443 sprintfTag tag =
02444 (hsa->format->type == PTOK_TAG
02445 ? &hsa->format->u.tag :
02446 (hsa->format->type == PTOK_ARRAY
02447 ? &hsa->format->u.array.format->u.tag :
02448 NULL));
02449
02450 if (hsa != NULL && hsa->i >= 0 && hsa->i < hsa->numTokens) {
02451 fmt = hsa->format + hsa->i;
02452 if (hsa->hi == NULL) {
02453 hsa->i++;
02454 } else {
02455 int_32 tagno;
02456 int_32 type;
02457 int_32 count;
02458
02459
02460 if (!headerNextIterator(hsa->hi, &tagno, &type, NULL, &count))
02461 fmt = NULL;
02462 tag->tag = tagno;
02463
02464 }
02465 }
02466
02467
02468 return fmt;
02469
02470 }
02471
02477 static headerSprintfArgs hsaFini( headerSprintfArgs hsa)
02478
02479 {
02480 if (hsa != NULL) {
02481 hsa->hi = headerFreeIterator(hsa->hi);
02482 hsa->i = 0;
02483 }
02484
02485 return hsa;
02486
02487 }
02488
02495
02496 static char * hsaReserve(headerSprintfArgs hsa, size_t need)
02497
02498 {
02499 if ((hsa->vallen + need) >= hsa->alloced) {
02500 if (hsa->alloced <= need)
02501 hsa->alloced += need;
02502 hsa->alloced <<= 1;
02503 hsa->val = xrealloc(hsa->val, hsa->alloced+1);
02504 }
02505 return hsa->val + hsa->vallen;
02506 }
02507
02515
02516 static const char * myTagName(headerTagTableEntry tbl, int val)
02517
02518 {
02519 static char name[128];
02520 const char * s;
02521 char *t;
02522
02523 for (; tbl->name != NULL; tbl++) {
02524 if (tbl->val == val)
02525 break;
02526 }
02527 if ((s = tbl->name) == NULL)
02528 return NULL;
02529 s += sizeof("RPMTAG_") - 1;
02530 t = name;
02531 *t++ = *s++;
02532 while (*s != '\0')
02533 *t++ = xtolower(*s++);
02534 *t = '\0';
02535 return name;
02536 }
02537
02545 static int myTagValue(headerTagTableEntry tbl, const char * name)
02546
02547 {
02548 for (; tbl->name != NULL; tbl++) {
02549 if (!xstrcasecmp(tbl->name, name))
02550 return tbl->val;
02551 }
02552 return 0;
02553 }
02554
02561 static int findTag(headerSprintfArgs hsa, sprintfToken token, const char * name)
02562
02563 {
02564 headerSprintfExtension ext;
02565 sprintfTag stag = (token->type == PTOK_COND
02566 ? &token->u.cond.tag : &token->u.tag);
02567
02568 stag->fmt = NULL;
02569 stag->ext = NULL;
02570 stag->extNum = 0;
02571 stag->tag = -1;
02572
02573 if (!strcmp(name, "*")) {
02574 stag->tag = -2;
02575 goto bingo;
02576 }
02577
02578
02579 if (strncmp("RPMTAG_", name, sizeof("RPMTAG_")-1)) {
02580
02581 char * t = alloca(strlen(name) + sizeof("RPMTAG_"));
02582 (void) stpcpy( stpcpy(t, "RPMTAG_"), name);
02583 name = t;
02584
02585 }
02586
02587
02588
02589 for (ext = hsa->exts; ext != NULL && ext->type != HEADER_EXT_LAST;
02590 ext = (ext->type == HEADER_EXT_MORE ? ext->u.more : ext+1))
02591 {
02592 if (ext->name == NULL || ext->type != HEADER_EXT_TAG)
02593 continue;
02594 if (!xstrcasecmp(ext->name, name)) {
02595 stag->ext = ext->u.tagFunction;
02596 stag->extNum = ext - hsa->exts;
02597 goto bingo;
02598 }
02599 }
02600
02601
02602 stag->tag = myTagValue(hsa->tags, name);
02603 if (stag->tag != 0)
02604 goto bingo;
02605
02606 return 1;
02607
02608 bingo:
02609
02610 if (stag->type != NULL)
02611 for (ext = hsa->exts; ext != NULL && ext->type != HEADER_EXT_LAST;
02612 ext = (ext->type == HEADER_EXT_MORE ? ext->u.more : ext+1))
02613 {
02614 if (ext->name == NULL || ext->type != HEADER_EXT_FORMAT)
02615 continue;
02616 if (!strcmp(ext->name, stag->type)) {
02617 stag->fmt = ext->u.formatFunction;
02618 break;
02619 }
02620 }
02621 return 0;
02622 }
02623
02624
02632 static int parseExpression(headerSprintfArgs hsa, sprintfToken token,
02633 char * str, char ** endPtr)
02634
02635 ;
02636
02646 static int parseFormat(headerSprintfArgs hsa, char * str,
02647 sprintfToken * formatPtr, int * numTokensPtr,
02648 char ** endPtr, int state)
02649
02650
02651
02652 {
02653 char * chptr, * start, * next, * dst;
02654 sprintfToken format;
02655 sprintfToken token;
02656 int numTokens;
02657 int i;
02658 int done = 0;
02659
02660
02661 numTokens = 0;
02662 if (str != NULL)
02663 for (chptr = str; *chptr != '\0'; chptr++)
02664 if (*chptr == '%') numTokens++;
02665 numTokens = numTokens * 2 + 1;
02666
02667 format = xcalloc(numTokens, sizeof(*format));
02668 if (endPtr) *endPtr = NULL;
02669
02670
02671 dst = start = str;
02672 numTokens = 0;
02673 token = NULL;
02674 if (start != NULL)
02675 while (*start != '\0') {
02676 switch (*start) {
02677 case '%':
02678
02679 if (*(start + 1) == '%') {
02680 if (token == NULL || token->type != PTOK_STRING) {
02681 token = format + numTokens++;
02682 token->type = PTOK_STRING;
02683
02684 dst = token->u.string.string = start;
02685
02686 }
02687 start++;
02688
02689 *dst++ = *start++;
02690
02691 break;
02692 }
02693
02694 token = format + numTokens++;
02695
02696 *dst++ = '\0';
02697
02698 start++;
02699
02700 if (*start == '|') {
02701 char * newEnd;
02702
02703 start++;
02704
02705 if (parseExpression(hsa, token, start, &newEnd))
02706 {
02707 format = freeFormat(format, numTokens);
02708 return 1;
02709 }
02710
02711 start = newEnd;
02712 break;
02713 }
02714
02715
02716 token->u.tag.format = start;
02717
02718 token->u.tag.pad = 0;
02719 token->u.tag.justOne = 0;
02720 token->u.tag.arrayCount = 0;
02721
02722 chptr = start;
02723 while (*chptr && *chptr != '{' && *chptr != '%') chptr++;
02724 if (!*chptr || *chptr == '%') {
02725 hsa->errmsg = _("missing { after %");
02726 format = freeFormat(format, numTokens);
02727 return 1;
02728 }
02729
02730
02731 *chptr++ = '\0';
02732
02733
02734 while (start < chptr) {
02735 if (xisdigit(*start)) {
02736 i = strtoul(start, &start, 10);
02737 token->u.tag.pad += i;
02738 start = chptr;
02739 break;
02740 } else {
02741 start++;
02742 }
02743 }
02744
02745 if (*start == '=') {
02746 token->u.tag.justOne = 1;
02747 start++;
02748 } else if (*start == '#') {
02749 token->u.tag.justOne = 1;
02750 token->u.tag.arrayCount = 1;
02751 start++;
02752 }
02753
02754 dst = next = start;
02755 while (*next && *next != '}') next++;
02756 if (!*next) {
02757 hsa->errmsg = _("missing } after %{");
02758 format = freeFormat(format, numTokens);
02759 return 1;
02760 }
02761
02762 *next++ = '\0';
02763
02764
02765 chptr = start;
02766 while (*chptr && *chptr != ':') chptr++;
02767
02768 if (*chptr != '\0') {
02769
02770 *chptr++ = '\0';
02771
02772 if (!*chptr) {
02773 hsa->errmsg = _("empty tag format");
02774 format = freeFormat(format, numTokens);
02775 return 1;
02776 }
02777
02778 token->u.tag.type = chptr;
02779
02780 } else {
02781 token->u.tag.type = NULL;
02782 }
02783
02784 if (!*start) {
02785 hsa->errmsg = _("empty tag name");
02786 format = freeFormat(format, numTokens);
02787 return 1;
02788 }
02789
02790 i = 0;
02791 token->type = PTOK_TAG;
02792
02793 if (findTag(hsa, token, start)) {
02794 hsa->errmsg = _("unknown tag");
02795 format = freeFormat(format, numTokens);
02796 return 1;
02797 }
02798
02799 start = next;
02800 break;
02801
02802 case '[':
02803
02804 *dst++ = '\0';
02805 *start++ = '\0';
02806
02807 token = format + numTokens++;
02808
02809
02810 if (parseFormat(hsa, start,
02811 &token->u.array.format,
02812 &token->u.array.numTokens,
02813 &start, PARSER_IN_ARRAY))
02814 {
02815 format = freeFormat(format, numTokens);
02816 return 1;
02817 }
02818
02819
02820 if (!start) {
02821 hsa->errmsg = _("] expected at end of array");
02822 format = freeFormat(format, numTokens);
02823 return 1;
02824 }
02825
02826 dst = start;
02827
02828 token->type = PTOK_ARRAY;
02829
02830 break;
02831
02832 case ']':
02833 if (state != PARSER_IN_ARRAY) {
02834 hsa->errmsg = _("unexpected ]");
02835 format = freeFormat(format, numTokens);
02836 return 1;
02837 }
02838
02839 *start++ = '\0';
02840
02841 if (endPtr) *endPtr = start;
02842 done = 1;
02843 break;
02844
02845 case '}':
02846 if (state != PARSER_IN_EXPR) {
02847 hsa->errmsg = _("unexpected }");
02848 format = freeFormat(format, numTokens);
02849 return 1;
02850 }
02851
02852 *start++ = '\0';
02853
02854 if (endPtr) *endPtr = start;
02855 done = 1;
02856 break;
02857
02858 default:
02859 if (token == NULL || token->type != PTOK_STRING) {
02860 token = format + numTokens++;
02861 token->type = PTOK_STRING;
02862
02863 dst = token->u.string.string = start;
02864
02865 }
02866
02867
02868 if (*start == '\\') {
02869 start++;
02870 *dst++ = escapedChar(*start++);
02871 } else {
02872 *dst++ = *start++;
02873 }
02874
02875 break;
02876 }
02877 if (done)
02878 break;
02879 }
02880
02881
02882
02883 if (dst != NULL)
02884 *dst = '\0';
02885
02886
02887 for (i = 0; i < numTokens; i++) {
02888 token = format + i;
02889 if (token->type == PTOK_STRING)
02890 token->u.string.len = strlen(token->u.string.string);
02891 }
02892
02893 *numTokensPtr = numTokens;
02894 *formatPtr = format;
02895
02896 return 0;
02897 }
02898
02899
02900 static int parseExpression(headerSprintfArgs hsa, sprintfToken token,
02901 char * str, char ** endPtr)
02902 {
02903 char * chptr;
02904 char * end;
02905
02906 hsa->errmsg = NULL;
02907 chptr = str;
02908 while (*chptr && *chptr != '?') chptr++;
02909
02910 if (*chptr != '?') {
02911 hsa->errmsg = _("? expected in expression");
02912 return 1;
02913 }
02914
02915 *chptr++ = '\0';;
02916
02917 if (*chptr != '{') {
02918 hsa->errmsg = _("{ expected after ? in expression");
02919 return 1;
02920 }
02921
02922 chptr++;
02923
02924 if (parseFormat(hsa, chptr, &token->u.cond.ifFormat,
02925 &token->u.cond.numIfTokens, &end, PARSER_IN_EXPR))
02926 return 1;
02927
02928
02929 if (!(end && *end)) {
02930 hsa->errmsg = _("} expected in expression");
02931 token->u.cond.ifFormat =
02932 freeFormat(token->u.cond.ifFormat, token->u.cond.numIfTokens);
02933 return 1;
02934 }
02935
02936 chptr = end;
02937 if (*chptr != ':' && *chptr != '|') {
02938 hsa->errmsg = _(": expected following ? subexpression");
02939 token->u.cond.ifFormat =
02940 freeFormat(token->u.cond.ifFormat, token->u.cond.numIfTokens);
02941 return 1;
02942 }
02943
02944 if (*chptr == '|') {
02945 if (parseFormat(hsa, NULL, &token->u.cond.elseFormat,
02946 &token->u.cond.numElseTokens, &end, PARSER_IN_EXPR))
02947 {
02948 token->u.cond.ifFormat =
02949 freeFormat(token->u.cond.ifFormat, token->u.cond.numIfTokens);
02950 return 1;
02951 }
02952 } else {
02953 chptr++;
02954
02955 if (*chptr != '{') {
02956 hsa->errmsg = _("{ expected after : in expression");
02957 token->u.cond.ifFormat =
02958 freeFormat(token->u.cond.ifFormat, token->u.cond.numIfTokens);
02959 return 1;
02960 }
02961
02962 chptr++;
02963
02964 if (parseFormat(hsa, chptr, &token->u.cond.elseFormat,
02965 &token->u.cond.numElseTokens, &end, PARSER_IN_EXPR))
02966 return 1;
02967
02968
02969 if (!(end && *end)) {
02970 hsa->errmsg = _("} expected in expression");
02971 token->u.cond.ifFormat =
02972 freeFormat(token->u.cond.ifFormat, token->u.cond.numIfTokens);
02973 return 1;
02974 }
02975
02976 chptr = end;
02977 if (*chptr != '|') {
02978 hsa->errmsg = _("| expected at end of expression");
02979 token->u.cond.ifFormat =
02980 freeFormat(token->u.cond.ifFormat, token->u.cond.numIfTokens);
02981 token->u.cond.elseFormat =
02982 freeFormat(token->u.cond.elseFormat, token->u.cond.numElseTokens);
02983 return 1;
02984 }
02985 }
02986
02987 chptr++;
02988
02989 *endPtr = chptr;
02990
02991 token->type = PTOK_COND;
02992
02993 (void) findTag(hsa, token, str);
02994
02995 return 0;
02996 }
02997
02998
03009 static int getExtension(headerSprintfArgs hsa, headerTagTagFunction fn,
03010 hTYP_t typeptr,
03011 hPTR_t * data,
03012 hCNT_t countptr,
03013 rpmec ec)
03014
03015
03016
03017 {
03018 if (!ec->avail) {
03019 if (fn(hsa->h, &ec->type, &ec->data, &ec->count, &ec->freeit))
03020 return 1;
03021 ec->avail = 1;
03022 }
03023
03024 if (typeptr) *typeptr = ec->type;
03025 if (data) *data = ec->data;
03026 if (countptr) *countptr = ec->count;
03027
03028 return 0;
03029 }
03030
03037
03038 static char * formatValue(headerSprintfArgs hsa, sprintfTag tag, int element)
03039
03040 {
03041 char * val = NULL;
03042 size_t need = 0;
03043 char * t, * te;
03044 char buf[20];
03045 int_32 count, type;
03046 hPTR_t data;
03047 unsigned int intVal;
03048 const char ** strarray;
03049 int datafree = 0;
03050 int countBuf;
03051
03052 memset(buf, 0, sizeof(buf));
03053 if (tag->ext) {
03054
03055 if (getExtension(hsa, tag->ext, &type, &data, &count, hsa->ec + tag->extNum))
03056 {
03057 count = 1;
03058 type = RPM_STRING_TYPE;
03059 data = "(none)";
03060 }
03061
03062 } else {
03063
03064 if (!headerGetEntry(hsa->h, tag->tag, &type, (void **)&data, &count)) {
03065 count = 1;
03066 type = RPM_STRING_TYPE;
03067 data = "(none)";
03068 }
03069
03070
03071
03072 switch (type) {
03073 default:
03074 if (element >= count) {
03075
03076 data = headerFreeData(data, type);
03077
03078
03079 hsa->errmsg = _("(index out of range)");
03080 return NULL;
03081 }
03082 break;
03083 case RPM_BIN_TYPE:
03084 case RPM_STRING_TYPE:
03085 break;
03086 }
03087 datafree = 1;
03088 }
03089
03090 if (tag->arrayCount) {
03091
03092 if (datafree)
03093 data = headerFreeData(data, type);
03094
03095
03096 countBuf = count;
03097 data = &countBuf;
03098 count = 1;
03099 type = RPM_INT32_TYPE;
03100 }
03101
03102
03103 (void) stpcpy( stpcpy(buf, "%"), tag->format);
03104
03105
03106
03107 if (data)
03108 switch (type) {
03109 case RPM_STRING_ARRAY_TYPE:
03110 strarray = (const char **)data;
03111
03112 if (tag->fmt)
03113 val = tag->fmt(RPM_STRING_TYPE, strarray[element], buf, tag->pad, element);
03114
03115 if (val) {
03116 need = strlen(val);
03117 } else {
03118 need = strlen(strarray[element]) + tag->pad + 20;
03119 val = xmalloc(need+1);
03120 strcat(buf, "s");
03121
03122 sprintf(val, buf, strarray[element]);
03123
03124 }
03125
03126 break;
03127
03128 case RPM_STRING_TYPE:
03129 if (tag->fmt)
03130 val = tag->fmt(RPM_STRING_TYPE, data, buf, tag->pad, 0);
03131
03132 if (val) {
03133 need = strlen(val);
03134 } else {
03135 need = strlen(data) + tag->pad + 20;
03136 val = xmalloc(need+1);
03137 strcat(buf, "s");
03138
03139 sprintf(val, buf, data);
03140
03141 }
03142 break;
03143
03144 case RPM_CHAR_TYPE:
03145 case RPM_INT8_TYPE:
03146 case RPM_INT16_TYPE:
03147 case RPM_INT32_TYPE:
03148 switch (type) {
03149 case RPM_CHAR_TYPE:
03150 case RPM_INT8_TYPE:
03151 intVal = *(((int_8 *) data) + element);
03152 break;
03153 case RPM_INT16_TYPE:
03154 intVal = *(((uint_16 *) data) + element);
03155 break;
03156 default:
03157 case RPM_INT32_TYPE:
03158 intVal = *(((int_32 *) data) + element);
03159 break;
03160 }
03161
03162 if (tag->fmt)
03163 val = tag->fmt(RPM_INT32_TYPE, &intVal, buf, tag->pad, element);
03164
03165 if (val) {
03166 need = strlen(val);
03167 } else {
03168 need = 10 + tag->pad + 20;
03169 val = xmalloc(need+1);
03170 strcat(buf, "d");
03171
03172 sprintf(val, buf, intVal);
03173
03174 }
03175 break;
03176
03177 case RPM_BIN_TYPE:
03178
03179 if (tag->fmt)
03180 val = tag->fmt(RPM_BIN_TYPE, data, buf, tag->pad, count);
03181
03182 if (val) {
03183 need = strlen(val);
03184 } else {
03185 val = bin2hex(data, count);
03186 need = strlen(val) + tag->pad;
03187 }
03188 break;
03189
03190 default:
03191 need = sizeof("(unknown type)") - 1;
03192 val = xstrdup("(unknown type)");
03193 break;
03194 }
03195
03196
03197
03198 if (datafree)
03199 data = headerFreeData(data, type);
03200
03201
03202
03203 if (val && need > 0) {
03204 t = hsaReserve(hsa, need);
03205
03206 te = stpcpy(t, val);
03207
03208 hsa->vallen += (te - t);
03209 val = _free(val);
03210 }
03211
03212
03213 return (hsa->val + hsa->vallen);
03214 }
03215
03222
03223 static char * singleSprintf(headerSprintfArgs hsa, sprintfToken token,
03224 int element)
03225
03226 {
03227 char * t, * te;
03228 int i, j;
03229 int numElements;
03230 int_32 type;
03231 int_32 count;
03232 sprintfToken spft;
03233 int condNumFormats;
03234 size_t need;
03235
03236
03237
03238 switch (token->type) {
03239 case PTOK_NONE:
03240 break;
03241
03242 case PTOK_STRING:
03243 need = token->u.string.len;
03244 if (need == 0) break;
03245 t = hsaReserve(hsa, need);
03246
03247 te = stpcpy(t, token->u.string.string);
03248
03249 hsa->vallen += (te - t);
03250 break;
03251
03252 case PTOK_TAG:
03253 t = hsa->val + hsa->vallen;
03254 te = formatValue(hsa, &token->u.tag,
03255 (token->u.tag.justOne ? 0 : element));
03256 if (te == NULL)
03257 return NULL;
03258 break;
03259
03260 case PTOK_COND:
03261 if (token->u.cond.tag.ext || headerIsEntry(hsa->h, token->u.cond.tag.tag)) {
03262 spft = token->u.cond.ifFormat;
03263 condNumFormats = token->u.cond.numIfTokens;
03264 } else {
03265 spft = token->u.cond.elseFormat;
03266 condNumFormats = token->u.cond.numElseTokens;
03267 }
03268
03269 need = condNumFormats * 20;
03270 if (spft == NULL || need == 0) break;
03271
03272 t = hsaReserve(hsa, need);
03273 for (i = 0; i < condNumFormats; i++, spft++) {
03274 te = singleSprintf(hsa, spft, element);
03275 if (te == NULL)
03276 return NULL;
03277 }
03278 break;
03279
03280 case PTOK_ARRAY:
03281 numElements = -1;
03282 spft = token->u.array.format;
03283 for (i = 0; i < token->u.array.numTokens; i++, spft++)
03284 {
03285 if (spft->type != PTOK_TAG ||
03286 spft->u.tag.arrayCount ||
03287 spft->u.tag.justOne) continue;
03288
03289 if (spft->u.tag.ext) {
03290
03291 if (getExtension(hsa, spft->u.tag.ext, &type, NULL, &count,
03292 hsa->ec + spft->u.tag.extNum))
03293 continue;
03294
03295 } else {
03296
03297 if (!headerGetEntry(hsa->h, spft->u.tag.tag, &type, NULL, &count))
03298 continue;
03299
03300 }
03301
03302 if (type == RPM_BIN_TYPE)
03303 count = 1;
03304
03305 if (numElements > 1 && count != numElements)
03306 switch (type) {
03307 default:
03308 hsa->errmsg =
03309 _("array iterator used with different sized arrays");
03310 return NULL;
03311 break;
03312 case RPM_BIN_TYPE:
03313 case RPM_STRING_TYPE:
03314 break;
03315 }
03316 if (count > numElements)
03317 numElements = count;
03318 }
03319
03320 if (numElements == -1) {
03321 need = sizeof("(none)") - 1;
03322 t = hsaReserve(hsa, need);
03323
03324 te = stpcpy(t, "(none)");
03325
03326 hsa->vallen += (te - t);
03327 } else {
03328 int isxml;
03329
03330 need = numElements * token->u.array.numTokens * 10;
03331 if (need == 0) break;
03332
03333 spft = token->u.array.format;
03334 isxml = (spft->type == PTOK_TAG && spft->u.tag.type != NULL &&
03335 !strcmp(spft->u.tag.type, "xml"));
03336
03337 if (isxml) {
03338 const char * tagN = myTagName(hsa->tags, spft->u.tag.tag);
03339
03340 need = sizeof(" <rpmTag name=\"\">\n") - 1;
03341 if (tagN != NULL)
03342 need += strlen(tagN);
03343 t = hsaReserve(hsa, need);
03344
03345 te = stpcpy(t, " <rpmTag name=\"");
03346 if (tagN != NULL)
03347 te = stpcpy(te, tagN);
03348 te = stpcpy(te, "\">\n");
03349
03350 hsa->vallen += (te - t);
03351 }
03352
03353 t = hsaReserve(hsa, need);
03354 for (j = 0; j < numElements; j++) {
03355 spft = token->u.array.format;
03356 for (i = 0; i < token->u.array.numTokens; i++, spft++) {
03357 te = singleSprintf(hsa, spft, j);
03358 if (te == NULL)
03359 return NULL;
03360 }
03361 }
03362
03363 if (isxml) {
03364 need = sizeof(" </rpmTag>\n") - 1;
03365 t = hsaReserve(hsa, need);
03366
03367 te = stpcpy(t, " </rpmTag>\n");
03368
03369 hsa->vallen += (te - t);
03370 }
03371
03372 }
03373 break;
03374 }
03375
03376 return (hsa->val + hsa->vallen);
03377 }
03378
03384 static rpmec
03385 rpmecNew(const headerSprintfExtension exts)
03386
03387 {
03388 headerSprintfExtension ext;
03389 rpmec ec;
03390 int i = 0;
03391
03392 for (ext = exts; ext != NULL && ext->type != HEADER_EXT_LAST;
03393 ext = (ext->type == HEADER_EXT_MORE ? ext->u.more : ext+1))
03394 {
03395 i++;
03396 }
03397
03398 ec = xcalloc(i, sizeof(*ec));
03399 return ec;
03400 }
03401
03408 static rpmec
03409 rpmecFree(const headerSprintfExtension exts, rpmec ec)
03410
03411 {
03412 headerSprintfExtension ext;
03413 int i = 0;
03414
03415 for (ext = exts; ext != NULL && ext->type != HEADER_EXT_LAST;
03416 ext = (ext->type == HEADER_EXT_MORE ? ext->u.more : ext+1))
03417 {
03418
03419 if (ec[i].freeit) ec[i].data = _free(ec[i].data);
03420
03421 i++;
03422 }
03423
03424 ec = _free(ec);
03425 return NULL;
03426 }
03427
03439 static
03440 char * headerSprintf(Header h, const char * fmt,
03441 const struct headerTagTableEntry_s * tbltags,
03442 const struct headerSprintfExtension_s * extensions,
03443 errmsg_t * errmsg)
03444
03445
03446 {
03447 headerSprintfArgs hsa = memset(alloca(sizeof(*hsa)), 0, sizeof(*hsa));
03448 sprintfToken nextfmt;
03449 sprintfTag tag;
03450 char * t, * te;
03451 int isxml;
03452 int need;
03453
03454 hsa->h = headerLink(h);
03455 hsa->fmt = xstrdup(fmt);
03456
03457 hsa->exts = (headerSprintfExtension) extensions;
03458 hsa->tags = (headerTagTableEntry) tbltags;
03459
03460 hsa->errmsg = NULL;
03461
03462
03463 if (parseFormat(hsa, hsa->fmt, &hsa->format, &hsa->numTokens, NULL, PARSER_BEGIN))
03464 goto exit;
03465
03466
03467 hsa->ec = rpmecNew(hsa->exts);
03468 hsa->val = xstrdup("");
03469
03470 tag =
03471 (hsa->format->type == PTOK_TAG
03472 ? &hsa->format->u.tag :
03473 (hsa->format->type == PTOK_ARRAY
03474 ? &hsa->format->u.array.format->u.tag :
03475 NULL));
03476 isxml = (tag != NULL && tag->tag == -2 && tag->type != NULL && !strcmp(tag->type, "xml"));
03477
03478 if (isxml) {
03479 need = sizeof("<rpmHeader>\n") - 1;
03480 t = hsaReserve(hsa, need);
03481
03482 te = stpcpy(t, "<rpmHeader>\n");
03483
03484 hsa->vallen += (te - t);
03485 }
03486
03487 hsa = hsaInit(hsa);
03488 while ((nextfmt = hsaNext(hsa)) != NULL) {
03489 te = singleSprintf(hsa, nextfmt, 0);
03490 if (te == NULL) {
03491 hsa->val = _free(hsa->val);
03492 break;
03493 }
03494 }
03495 hsa = hsaFini(hsa);
03496
03497 if (isxml) {
03498 need = sizeof("</rpmHeader>\n") - 1;
03499 t = hsaReserve(hsa, need);
03500
03501 te = stpcpy(t, "</rpmHeader>\n");
03502
03503 hsa->vallen += (te - t);
03504 }
03505
03506 if (hsa->val != NULL && hsa->vallen < hsa->alloced)
03507 hsa->val = xrealloc(hsa->val, hsa->vallen+1);
03508
03509 hsa->ec = rpmecFree(hsa->exts, hsa->ec);
03510 hsa->format = freeFormat(hsa->format, hsa->numTokens);
03511
03512 exit:
03513
03514 if (errmsg)
03515 *errmsg = hsa->errmsg;
03516
03517 hsa->h = headerFree(hsa->h);
03518 hsa->fmt = _free(hsa->fmt);
03519 return hsa->val;
03520 }
03521
03530 static char * octalFormat(int_32 type, hPTR_t data,
03531 char * formatPrefix, int padding, int element)
03532
03533 {
03534 char * val;
03535
03536 if (type != RPM_INT32_TYPE) {
03537 val = xstrdup(_("(not a number)"));
03538 } else {
03539 val = xmalloc(20 + padding);
03540
03541 strcat(formatPrefix, "o");
03542
03543
03544 sprintf(val, formatPrefix, *((int_32 *) data));
03545
03546 }
03547
03548 return val;
03549 }
03550
03559 static char * hexFormat(int_32 type, hPTR_t data,
03560 char * formatPrefix, int padding, int element)
03561
03562 {
03563 char * val;
03564
03565 if (type != RPM_INT32_TYPE) {
03566 val = xstrdup(_("(not a number)"));
03567 } else {
03568 val = xmalloc(20 + padding);
03569
03570 strcat(formatPrefix, "x");
03571
03572
03573 sprintf(val, formatPrefix, *((int_32 *) data));
03574
03575 }
03576
03577 return val;
03578 }
03579
03582 static char * realDateFormat(int_32 type, hPTR_t data,
03583 char * formatPrefix, int padding, int element,
03584 const char * strftimeFormat)
03585
03586 {
03587 char * val;
03588
03589 if (type != RPM_INT32_TYPE) {
03590 val = xstrdup(_("(not a number)"));
03591 } else {
03592 struct tm * tstruct;
03593 char buf[50];
03594
03595 val = xmalloc(50 + padding);
03596
03597 strcat(formatPrefix, "s");
03598
03599
03600
03601 { time_t dateint = *((int_32 *) data);
03602 tstruct = localtime(&dateint);
03603 }
03604 buf[0] = '\0';
03605 if (tstruct)
03606 (void) strftime(buf, sizeof(buf) - 1, strftimeFormat, tstruct);
03607
03608 sprintf(val, formatPrefix, buf);
03609
03610 }
03611
03612 return val;
03613 }
03614
03623 static char * dateFormat(int_32 type, hPTR_t data,
03624 char * formatPrefix, int padding, int element)
03625
03626 {
03627 return realDateFormat(type, data, formatPrefix, padding, element,
03628 _("%c"));
03629 }
03630
03639 static char * dayFormat(int_32 type, hPTR_t data,
03640 char * formatPrefix, int padding, int element)
03641
03642 {
03643 return realDateFormat(type, data, formatPrefix, padding, element,
03644 _("%a %b %d %Y"));
03645 }
03646
03655 static char * shescapeFormat(int_32 type, hPTR_t data,
03656 char * formatPrefix, int padding, int element)
03657
03658 {
03659 char * result, * dst, * src, * buf;
03660
03661 if (type == RPM_INT32_TYPE) {
03662 result = xmalloc(padding + 20);
03663
03664 strcat(formatPrefix, "d");
03665
03666
03667 sprintf(result, formatPrefix, *((int_32 *) data));
03668
03669 } else {
03670 buf = alloca(strlen(data) + padding + 2);
03671
03672 strcat(formatPrefix, "s");
03673
03674
03675 sprintf(buf, formatPrefix, data);
03676
03677
03678
03679 result = dst = xmalloc(strlen(buf) * 4 + 3);
03680 *dst++ = '\'';
03681 for (src = buf; *src != '\0'; src++) {
03682 if (*src == '\'') {
03683 *dst++ = '\'';
03684 *dst++ = '\\';
03685 *dst++ = '\'';
03686 *dst++ = '\'';
03687 } else {
03688 *dst++ = *src;
03689 }
03690 }
03691 *dst++ = '\'';
03692 *dst = '\0';
03693
03694
03695 }
03696
03697 return result;
03698 }
03699
03700
03701 const struct headerSprintfExtension_s headerDefaultFormats[] = {
03702 { HEADER_EXT_FORMAT, "octal", { octalFormat } },
03703 { HEADER_EXT_FORMAT, "hex", { hexFormat } },
03704 { HEADER_EXT_FORMAT, "date", { dateFormat } },
03705 { HEADER_EXT_FORMAT, "day", { dayFormat } },
03706 { HEADER_EXT_FORMAT, "shescape", { shescapeFormat } },
03707 { HEADER_EXT_LAST, NULL, { NULL } }
03708 };
03709
03710
03717 static
03718 void headerCopyTags(Header headerFrom, Header headerTo, hTAG_t tagstocopy)
03719
03720 {
03721 int * p;
03722
03723 if (headerFrom == headerTo)
03724 return;
03725
03726 for (p = tagstocopy; *p != 0; p++) {
03727 char *s;
03728 int_32 type;
03729 int_32 count;
03730 if (headerIsEntry(headerTo, *p))
03731 continue;
03732
03733 if (!headerGetEntryMinMemory(headerFrom, *p, &type,
03734 (hPTR_t *) &s, &count))
03735 continue;
03736
03737 (void) headerAddEntry(headerTo, *p, type, s, count);
03738 s = headerFreeData(s, type);
03739 }
03740 }
03741
03742
03743 static struct HV_s hdrVec1 = {
03744 headerLink,
03745 headerUnlink,
03746 headerFree,
03747 headerNew,
03748 headerSort,
03749 headerUnsort,
03750 headerSizeof,
03751 headerUnload,
03752 headerReload,
03753 headerCopy,
03754 headerLoad,
03755 headerCopyLoad,
03756 headerRead,
03757 headerWrite,
03758 headerIsEntry,
03759 headerFreeTag,
03760 headerGetEntry,
03761 headerGetEntryMinMemory,
03762 headerAddEntry,
03763 headerAppendEntry,
03764 headerAddOrAppendEntry,
03765 headerAddI18NString,
03766 headerModifyEntry,
03767 headerRemoveEntry,
03768 headerSprintf,
03769 headerCopyTags,
03770 headerFreeIterator,
03771 headerInitIterator,
03772 headerNextIterator,
03773 NULL, NULL,
03774 1
03775 };
03776
03777
03778
03779 HV_t hdrVec = &hdrVec1;
03780