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