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
01649 return ((entry->data != NULL) && *(char*)(entry->data)) ? _(entry->data) : entry->data;
01650 }
01651
01662 static int intGetEntry(Header h, int_32 tag,
01663 hTAG_t type,
01664 hPTR_t * p,
01665 hCNT_t c,
01666 int minMem)
01667
01668
01669 {
01670 indexEntry entry;
01671 int rc;
01672
01673
01674
01675 entry = findEntry(h, tag, RPM_NULL_TYPE);
01676
01677 if (entry == NULL) {
01678 if (type) type = 0;
01679 if (p) *p = NULL;
01680 if (c) *c = 0;
01681 return 0;
01682 }
01683
01684 switch (entry->info.type) {
01685 case RPM_I18NSTRING_TYPE:
01686 rc = 1;
01687 if (type) *type = RPM_STRING_TYPE;
01688 if (c) *c = 1;
01689
01690 if (p) *p = headerFindI18NString(h, entry);
01691
01692 break;
01693 default:
01694 rc = copyEntry(entry, type, p, c, minMem);
01695 break;
01696 }
01697
01698
01699 return ((rc == 1) ? 1 : 0);
01700 }
01701
01709 static void * headerFreeTag( Header h,
01710 const void * data, rpmTagType type)
01711
01712 {
01713 if (data) {
01714
01715 if (type == -1 ||
01716 type == RPM_STRING_ARRAY_TYPE ||
01717 type == RPM_I18NSTRING_TYPE ||
01718 type == RPM_BIN_TYPE)
01719 data = _free(data);
01720
01721 }
01722 return NULL;
01723 }
01724
01738 static
01739 int headerGetEntry(Header h, int_32 tag,
01740 hTYP_t type,
01741 void ** p,
01742 hCNT_t c)
01743
01744
01745 {
01746 return intGetEntry(h, tag, type, (hPTR_t *)p, c, 0);
01747 }
01748
01761 static
01762 int headerGetEntryMinMemory(Header h, int_32 tag,
01763 hTYP_t type,
01764 hPTR_t * p,
01765 hCNT_t c)
01766
01767
01768 {
01769 return intGetEntry(h, tag, type, p, c, 1);
01770 }
01771
01772 int headerGetRawEntry(Header h, int_32 tag, int_32 * type, hPTR_t * p,
01773 int_32 * c)
01774 {
01775 indexEntry entry;
01776 int rc;
01777
01778 if (p == NULL) return headerIsEntry(h, tag);
01779
01780
01781
01782 entry = findEntry(h, tag, RPM_NULL_TYPE);
01783
01784 if (!entry) {
01785 if (p) *p = NULL;
01786 if (c) *c = 0;
01787 return 0;
01788 }
01789
01790 rc = copyEntry(entry, type, p, c, 0);
01791
01792
01793 return ((rc == 1) ? 1 : 0);
01794 }
01795
01798 static void copyData(int_32 type, void * dstPtr, const void * srcPtr,
01799 int_32 cnt, int dataLength)
01800
01801 {
01802 switch (type) {
01803 case RPM_STRING_ARRAY_TYPE:
01804 case RPM_I18NSTRING_TYPE:
01805 { const char ** av = (const char **) srcPtr;
01806 char * t = dstPtr;
01807
01808
01809 while (cnt-- > 0 && dataLength > 0) {
01810 const char * s;
01811 if ((s = *av++) == NULL)
01812 continue;
01813 do {
01814 *t++ = *s++;
01815 } while (s[-1] && --dataLength > 0);
01816 }
01817
01818 } break;
01819
01820 default:
01821
01822 memmove(dstPtr, srcPtr, dataLength);
01823
01824 break;
01825 }
01826 }
01827
01836
01837 static void *
01838 grabData(int_32 type, hPTR_t p, int_32 c, int * lengthPtr)
01839
01840
01841 {
01842 void * data = NULL;
01843 int length;
01844
01845 length = dataLength(type, p, c, 0, NULL);
01846
01847 if (length > 0) {
01848 data = xmalloc(length);
01849 copyData(type, data, p, c, length);
01850 }
01851
01852
01853 if (lengthPtr)
01854 *lengthPtr = length;
01855 return data;
01856 }
01857
01872 static
01873 int headerAddEntry(Header h, int_32 tag, int_32 type, const void * p, int_32 c)
01874
01875 {
01876 indexEntry entry;
01877 void * data;
01878 int length;
01879
01880
01881 if (c <= 0)
01882 return 0;
01883
01884 if (hdrchkType(type))
01885 return 0;
01886 if (hdrchkData(c))
01887 return 0;
01888
01889 length = 0;
01890
01891 data = grabData(type, p, c, &length);
01892
01893 if (data == NULL || length <= 0)
01894 return 0;
01895
01896
01897 if (h->indexUsed == h->indexAlloced) {
01898 h->indexAlloced += INDEX_MALLOC_SIZE;
01899 h->index = xrealloc(h->index, h->indexAlloced * sizeof(*h->index));
01900 }
01901
01902
01903 entry = h->index + h->indexUsed;
01904 entry->info.tag = tag;
01905 entry->info.type = type;
01906 entry->info.count = c;
01907 entry->info.offset = 0;
01908 entry->data = data;
01909 entry->length = length;
01910
01911
01912 if (h->indexUsed > 0 && tag < h->index[h->indexUsed-1].info.tag)
01913 h->flags &= ~HEADERFLAG_SORTED;
01914
01915 h->indexUsed++;
01916
01917 return 1;
01918 }
01919
01934 static
01935 int headerAppendEntry(Header h, int_32 tag, int_32 type,
01936 const void * p, int_32 c)
01937
01938 {
01939 indexEntry entry;
01940 int length;
01941
01942 if (type == RPM_STRING_TYPE || type == RPM_I18NSTRING_TYPE) {
01943
01944 return 0;
01945 }
01946
01947
01948 entry = findEntry(h, tag, type);
01949 if (!entry)
01950 return 0;
01951
01952 length = dataLength(type, p, c, 0, NULL);
01953 if (length < 0)
01954 return 0;
01955
01956 if (ENTRY_IN_REGION(entry)) {
01957 char * t = xmalloc(entry->length + length);
01958
01959 memcpy(t, entry->data, entry->length);
01960
01961 entry->data = t;
01962 entry->info.offset = 0;
01963 } else
01964 entry->data = xrealloc(entry->data, entry->length + length);
01965
01966 copyData(type, ((char *) entry->data) + entry->length, p, c, length);
01967
01968 entry->length += length;
01969
01970 entry->info.count += c;
01971
01972 return 1;
01973 }
01974
01985 static
01986 int headerAddOrAppendEntry(Header h, int_32 tag, int_32 type,
01987 const void * p, int_32 c)
01988
01989 {
01990 return (findEntry(h, tag, type)
01991 ? headerAppendEntry(h, tag, type, p, c)
01992 : headerAddEntry(h, tag, type, p, c));
01993 }
01994
02015 static
02016 int headerAddI18NString(Header h, int_32 tag, const char * string,
02017 const char * lang)
02018
02019 {
02020 indexEntry table, entry;
02021 const char ** strArray;
02022 int length;
02023 int ghosts;
02024 int i, langNum;
02025 char * buf;
02026
02027 table = findEntry(h, HEADER_I18NTABLE, RPM_STRING_ARRAY_TYPE);
02028 entry = findEntry(h, tag, RPM_I18NSTRING_TYPE);
02029
02030 if (!table && entry)
02031 return 0;
02032
02033 if (!table && !entry) {
02034 const char * charArray[2];
02035 int count = 0;
02036 if (!lang || (lang[0] == 'C' && lang[1] == '\0')) {
02037
02038 charArray[count++] = "C";
02039
02040 } else {
02041
02042 charArray[count++] = "C";
02043
02044 charArray[count++] = lang;
02045 }
02046 if (!headerAddEntry(h, HEADER_I18NTABLE, RPM_STRING_ARRAY_TYPE,
02047 &charArray, count))
02048 return 0;
02049 table = findEntry(h, HEADER_I18NTABLE, RPM_STRING_ARRAY_TYPE);
02050 }
02051
02052 if (!table)
02053 return 0;
02054
02055 if (!lang) lang = "C";
02056
02057
02058 { const char * l = table->data;
02059 for (langNum = 0; langNum < table->info.count; langNum++) {
02060 if (!strcmp(l, lang)) break;
02061 l += strlen(l) + 1;
02062 }
02063 }
02064
02065 if (langNum >= table->info.count) {
02066 length = strlen(lang) + 1;
02067 if (ENTRY_IN_REGION(table)) {
02068 char * t = xmalloc(table->length + length);
02069 memcpy(t, table->data, table->length);
02070 table->data = t;
02071 table->info.offset = 0;
02072 } else
02073 table->data = xrealloc(table->data, table->length + length);
02074 memmove(((char *)table->data) + table->length, lang, length);
02075 table->length += length;
02076 table->info.count++;
02077 }
02078
02079 if (!entry) {
02080 strArray = alloca(sizeof(*strArray) * (langNum + 1));
02081 for (i = 0; i < langNum; i++)
02082 strArray[i] = "";
02083 strArray[langNum] = string;
02084 return headerAddEntry(h, tag, RPM_I18NSTRING_TYPE, strArray,
02085 langNum + 1);
02086 } else if (langNum >= entry->info.count) {
02087 ghosts = langNum - entry->info.count;
02088
02089 length = strlen(string) + 1 + ghosts;
02090 if (ENTRY_IN_REGION(entry)) {
02091 char * t = xmalloc(entry->length + length);
02092 memcpy(t, entry->data, entry->length);
02093 entry->data = t;
02094 entry->info.offset = 0;
02095 } else
02096 entry->data = xrealloc(entry->data, entry->length + length);
02097
02098 memset(((char *)entry->data) + entry->length, '\0', ghosts);
02099 memmove(((char *)entry->data) + entry->length + ghosts, string, strlen(string)+1);
02100
02101 entry->length += length;
02102 entry->info.count = langNum + 1;
02103 } else {
02104 char *b, *be, *e, *ee, *t;
02105 size_t bn, sn, en;
02106
02107
02108 b = be = e = ee = entry->data;
02109 for (i = 0; i < table->info.count; i++) {
02110 if (i == langNum)
02111 be = ee;
02112 ee += strlen(ee) + 1;
02113 if (i == langNum)
02114 e = ee;
02115 }
02116
02117
02118 bn = (be-b);
02119 sn = strlen(string) + 1;
02120 en = (ee-e);
02121 length = bn + sn + en;
02122 t = buf = xmalloc(length);
02123
02124
02125 memcpy(t, b, bn);
02126 t += bn;
02127
02128 memcpy(t, string, sn);
02129 t += sn;
02130 memcpy(t, e, en);
02131 t += en;
02132
02133
02134
02135 entry->length -= strlen(be) + 1;
02136 entry->length += sn;
02137
02138 if (ENTRY_IN_REGION(entry)) {
02139 entry->info.offset = 0;
02140 } else
02141 entry->data = _free(entry->data);
02142
02143 entry->data = buf;
02144
02145 }
02146
02147 return 0;
02148 }
02149
02160 static
02161 int headerModifyEntry(Header h, int_32 tag, int_32 type,
02162 const void * p, int_32 c)
02163
02164 {
02165 indexEntry entry;
02166 void * oldData;
02167 void * data;
02168 int length;
02169
02170
02171 entry = findEntry(h, tag, type);
02172 if (!entry)
02173 return 0;
02174
02175 length = 0;
02176 data = grabData(type, p, c, &length);
02177 if (data == NULL || length <= 0)
02178 return 0;
02179
02180
02181 while (entry > h->index && (entry - 1)->info.tag == tag)
02182 entry--;
02183
02184
02185
02186 oldData = entry->data;
02187
02188 entry->info.count = c;
02189 entry->info.type = type;
02190 entry->data = data;
02191 entry->length = length;
02192
02193
02194 if (ENTRY_IN_REGION(entry)) {
02195 entry->info.offset = 0;
02196 } else
02197 oldData = _free(oldData);
02198
02199
02200 return 1;
02201 }
02202
02205 static char escapedChar(const char ch)
02206 {
02207 switch (ch) {
02208 case 'a': return '\a';
02209 case 'b': return '\b';
02210 case 'f': return '\f';
02211 case 'n': return '\n';
02212 case 'r': return '\r';
02213 case 't': return '\t';
02214 case 'v': return '\v';
02215 default: return ch;
02216 }
02217 }
02218
02225 static sprintfToken
02226 freeFormat( sprintfToken format, int num)
02227
02228 {
02229 int i;
02230
02231 if (format == NULL) return NULL;
02232
02233 for (i = 0; i < num; i++) {
02234 switch (format[i].type) {
02235 case PTOK_ARRAY:
02236
02237 format[i].u.array.format =
02238 freeFormat(format[i].u.array.format,
02239 format[i].u.array.numTokens);
02240
02241 break;
02242 case PTOK_COND:
02243
02244 format[i].u.cond.ifFormat =
02245 freeFormat(format[i].u.cond.ifFormat,
02246 format[i].u.cond.numIfTokens);
02247 format[i].u.cond.elseFormat =
02248 freeFormat(format[i].u.cond.elseFormat,
02249 format[i].u.cond.numElseTokens);
02250
02251 break;
02252 case PTOK_NONE:
02253 case PTOK_TAG:
02254 case PTOK_STRING:
02255 default:
02256 break;
02257 }
02258 }
02259 format = _free(format);
02260 return NULL;
02261 }
02262
02266 struct headerIterator_s {
02267
02268 Header h;
02269
02270 int next_index;
02271 };
02272
02278 static
02279 HeaderIterator headerFreeIterator( HeaderIterator hi)
02280
02281 {
02282 if (hi != NULL) {
02283 hi->h = headerFree(hi->h);
02284 hi = _free(hi);
02285 }
02286 return hi;
02287 }
02288
02294 static
02295 HeaderIterator headerInitIterator(Header h)
02296
02297 {
02298 HeaderIterator hi = xmalloc(sizeof(*hi));
02299
02300 headerSort(h);
02301
02302 hi->h = headerLink(h);
02303 hi->next_index = 0;
02304 return hi;
02305 }
02306
02316 static
02317 int headerNextIterator(HeaderIterator hi,
02318 hTAG_t tag,
02319 hTYP_t type,
02320 hPTR_t * p,
02321 hCNT_t c)
02322
02323
02324
02325 {
02326 Header h = hi->h;
02327 int slot = hi->next_index;
02328 indexEntry entry = NULL;
02329 int rc;
02330
02331 for (slot = hi->next_index; slot < h->indexUsed; slot++) {
02332 entry = h->index + slot;
02333 if (!ENTRY_IS_REGION(entry))
02334 break;
02335 }
02336 hi->next_index = slot;
02337 if (entry == NULL || slot >= h->indexUsed)
02338 return 0;
02339
02340
02341 hi->next_index++;
02342
02343
02344 if (tag)
02345 *tag = entry->info.tag;
02346
02347 rc = copyEntry(entry, type, p, c, 0);
02348
02349
02350 return ((rc == 1) ? 1 : 0);
02351 }
02352
02358 static
02359 Header headerCopy(Header h)
02360
02361 {
02362 Header nh = headerNew();
02363 HeaderIterator hi;
02364 int_32 tag, type, count;
02365 hPTR_t ptr;
02366
02367
02368 for (hi = headerInitIterator(h);
02369 headerNextIterator(hi, &tag, &type, &ptr, &count);
02370 ptr = headerFreeData((void *)ptr, type))
02371 {
02372 if (ptr) (void) headerAddEntry(nh, tag, type, ptr, count);
02373 }
02374 hi = headerFreeIterator(hi);
02375
02376
02377 return headerReload(nh, HEADER_IMAGE);
02378 }
02379
02382 typedef struct headerSprintfArgs_s {
02383 Header h;
02384 char * fmt;
02385
02386 headerTagTableEntry tags;
02387
02388 headerSprintfExtension exts;
02389
02390 const char * errmsg;
02391 rpmec ec;
02392 sprintfToken format;
02393
02394 HeaderIterator hi;
02395
02396 char * val;
02397 size_t vallen;
02398 size_t alloced;
02399 int numTokens;
02400 int i;
02401 } * headerSprintfArgs;
02402
02408 static headerSprintfArgs hsaInit( headerSprintfArgs hsa)
02409
02410 {
02411 sprintfTag tag =
02412 (hsa->format->type == PTOK_TAG
02413 ? &hsa->format->u.tag :
02414 (hsa->format->type == PTOK_ARRAY
02415 ? &hsa->format->u.array.format->u.tag :
02416 NULL));
02417
02418 if (hsa != NULL) {
02419 hsa->i = 0;
02420 if (tag != NULL && tag->tag == -2)
02421 hsa->hi = headerInitIterator(hsa->h);
02422 }
02423
02424 return hsa;
02425
02426 }
02427
02433
02434 static sprintfToken hsaNext( headerSprintfArgs hsa)
02435
02436 {
02437 sprintfToken fmt = NULL;
02438 sprintfTag tag =
02439 (hsa->format->type == PTOK_TAG
02440 ? &hsa->format->u.tag :
02441 (hsa->format->type == PTOK_ARRAY
02442 ? &hsa->format->u.array.format->u.tag :
02443 NULL));
02444
02445 if (hsa != NULL && hsa->i >= 0 && hsa->i < hsa->numTokens) {
02446 fmt = hsa->format + hsa->i;
02447 if (hsa->hi == NULL) {
02448 hsa->i++;
02449 } else {
02450 int_32 tagno;
02451 int_32 type;
02452 int_32 count;
02453
02454
02455 if (!headerNextIterator(hsa->hi, &tagno, &type, NULL, &count))
02456 fmt = NULL;
02457 tag->tag = tagno;
02458
02459 }
02460 }
02461
02462
02463 return fmt;
02464
02465 }
02466
02472 static headerSprintfArgs hsaFini( headerSprintfArgs hsa)
02473
02474 {
02475 if (hsa != NULL) {
02476 hsa->hi = headerFreeIterator(hsa->hi);
02477 hsa->i = 0;
02478 }
02479
02480 return hsa;
02481
02482 }
02483
02490
02491 static char * hsaReserve(headerSprintfArgs hsa, size_t need)
02492
02493 {
02494 if ((hsa->vallen + need) >= hsa->alloced) {
02495 if (hsa->alloced <= need)
02496 hsa->alloced += need;
02497 hsa->alloced <<= 1;
02498 hsa->val = xrealloc(hsa->val, hsa->alloced+1);
02499 }
02500 return hsa->val + hsa->vallen;
02501 }
02502
02510
02511 static const char * myTagName(headerTagTableEntry tbl, int val)
02512
02513 {
02514 static char name[128];
02515 const char * s;
02516 char *t;
02517
02518 for (; tbl->name != NULL; tbl++) {
02519 if (tbl->val == val)
02520 break;
02521 }
02522 if ((s = tbl->name) == NULL)
02523 return NULL;
02524 s += sizeof("RPMTAG_") - 1;
02525 t = name;
02526 *t++ = *s++;
02527 while (*s != '\0')
02528 *t++ = xtolower(*s++);
02529 *t = '\0';
02530 return name;
02531 }
02532
02540 static int myTagValue(headerTagTableEntry tbl, const char * name)
02541
02542 {
02543 for (; tbl->name != NULL; tbl++) {
02544 if (!xstrcasecmp(tbl->name, name))
02545 return tbl->val;
02546 }
02547 return 0;
02548 }
02549
02556 static int findTag(headerSprintfArgs hsa, sprintfToken token, const char * name)
02557
02558 {
02559 headerSprintfExtension ext;
02560 sprintfTag stag = (token->type == PTOK_COND
02561 ? &token->u.cond.tag : &token->u.tag);
02562
02563 stag->fmt = NULL;
02564 stag->ext = NULL;
02565 stag->extNum = 0;
02566 stag->tag = -1;
02567
02568 if (!strcmp(name, "*")) {
02569 stag->tag = -2;
02570 goto bingo;
02571 }
02572
02573
02574 if (strncmp("RPMTAG_", name, sizeof("RPMTAG_")-1)) {
02575
02576 char * t = alloca(strlen(name) + sizeof("RPMTAG_"));
02577 (void) stpcpy( stpcpy(t, "RPMTAG_"), name);
02578 name = t;
02579
02580 }
02581
02582
02583
02584 for (ext = hsa->exts; ext != NULL && ext->type != HEADER_EXT_LAST;
02585 ext = (ext->type == HEADER_EXT_MORE ? ext->u.more : ext+1))
02586 {
02587 if (ext->name == NULL || ext->type != HEADER_EXT_TAG)
02588 continue;
02589 if (!xstrcasecmp(ext->name, name)) {
02590 stag->ext = ext->u.tagFunction;
02591 stag->extNum = ext - hsa->exts;
02592 goto bingo;
02593 }
02594 }
02595
02596
02597 stag->tag = myTagValue(hsa->tags, name);
02598 if (stag->tag != 0)
02599 goto bingo;
02600
02601 return 1;
02602
02603 bingo:
02604
02605 if (stag->type != NULL)
02606 for (ext = hsa->exts; ext != NULL && ext->type != HEADER_EXT_LAST;
02607 ext = (ext->type == HEADER_EXT_MORE ? ext->u.more : ext+1))
02608 {
02609 if (ext->name == NULL || ext->type != HEADER_EXT_FORMAT)
02610 continue;
02611 if (!strcmp(ext->name, stag->type)) {
02612 stag->fmt = ext->u.formatFunction;
02613 break;
02614 }
02615 }
02616 return 0;
02617 }
02618
02619
02627 static int parseExpression(headerSprintfArgs hsa, sprintfToken token,
02628 char * str, char ** endPtr)
02629
02630 ;
02631
02641 static int parseFormat(headerSprintfArgs hsa, char * str,
02642 sprintfToken * formatPtr, int * numTokensPtr,
02643 char ** endPtr, int state)
02644
02645
02646
02647 {
02648 char * chptr, * start, * next, * dst;
02649 sprintfToken format;
02650 sprintfToken token;
02651 int numTokens;
02652 int i;
02653 int done = 0;
02654
02655
02656 numTokens = 0;
02657 if (str != NULL)
02658 for (chptr = str; *chptr != '\0'; chptr++)
02659 if (*chptr == '%') numTokens++;
02660 numTokens = numTokens * 2 + 1;
02661
02662 format = xcalloc(numTokens, sizeof(*format));
02663 if (endPtr) *endPtr = NULL;
02664
02665
02666 dst = start = str;
02667 numTokens = 0;
02668 token = NULL;
02669 if (start != NULL)
02670 while (*start != '\0') {
02671 switch (*start) {
02672 case '%':
02673
02674 if (*(start + 1) == '%') {
02675 if (token == NULL || token->type != PTOK_STRING) {
02676 token = format + numTokens++;
02677 token->type = PTOK_STRING;
02678
02679 dst = token->u.string.string = start;
02680
02681 }
02682 start++;
02683
02684 *dst++ = *start++;
02685
02686 break;
02687 }
02688
02689 token = format + numTokens++;
02690
02691 *dst++ = '\0';
02692
02693 start++;
02694
02695 if (*start == '|') {
02696 char * newEnd;
02697
02698 start++;
02699
02700 if (parseExpression(hsa, token, start, &newEnd))
02701 {
02702 format = freeFormat(format, numTokens);
02703 return 1;
02704 }
02705
02706 start = newEnd;
02707 break;
02708 }
02709
02710
02711 token->u.tag.format = start;
02712
02713 token->u.tag.pad = 0;
02714 token->u.tag.justOne = 0;
02715 token->u.tag.arrayCount = 0;
02716
02717 chptr = start;
02718 while (*chptr && *chptr != '{' && *chptr != '%') chptr++;
02719 if (!*chptr || *chptr == '%') {
02720 hsa->errmsg = _("missing { after %");
02721 format = freeFormat(format, numTokens);
02722 return 1;
02723 }
02724
02725
02726 *chptr++ = '\0';
02727
02728
02729 while (start < chptr) {
02730 if (xisdigit(*start)) {
02731 i = strtoul(start, &start, 10);
02732 token->u.tag.pad += i;
02733 } else {
02734 start++;
02735 }
02736 }
02737
02738 if (*start == '=') {
02739 token->u.tag.justOne = 1;
02740 start++;
02741 } else if (*start == '#') {
02742 token->u.tag.justOne = 1;
02743 token->u.tag.arrayCount = 1;
02744 start++;
02745 }
02746
02747 next = start;
02748 while (*next && *next != '}') next++;
02749 if (!*next) {
02750 hsa->errmsg = _("missing } after %{");
02751 format = freeFormat(format, numTokens);
02752 return 1;
02753 }
02754
02755 *next++ = '\0';
02756
02757
02758 chptr = start;
02759 while (*chptr && *chptr != ':') chptr++;
02760
02761 if (*chptr != '\0') {
02762
02763 *chptr++ = '\0';
02764
02765 if (!*chptr) {
02766 hsa->errmsg = _("empty tag format");
02767 format = freeFormat(format, numTokens);
02768 return 1;
02769 }
02770
02771 token->u.tag.type = chptr;
02772
02773 } else {
02774 token->u.tag.type = NULL;
02775 }
02776
02777 if (!*start) {
02778 hsa->errmsg = _("empty tag name");
02779 format = freeFormat(format, numTokens);
02780 return 1;
02781 }
02782
02783 i = 0;
02784 token->type = PTOK_TAG;
02785
02786 if (findTag(hsa, token, start)) {
02787 hsa->errmsg = _("unknown tag");
02788 format = freeFormat(format, numTokens);
02789 return 1;
02790 }
02791
02792 start = next;
02793 break;
02794
02795 case '[':
02796
02797 *dst++ = '\0';
02798 *start++ = '\0';
02799
02800 token = format + numTokens++;
02801
02802
02803 if (parseFormat(hsa, start,
02804 &token->u.array.format,
02805 &token->u.array.numTokens,
02806 &start, PARSER_IN_ARRAY))
02807 {
02808 format = freeFormat(format, numTokens);
02809 return 1;
02810 }
02811
02812
02813 if (!start) {
02814 hsa->errmsg = _("] expected at end of array");
02815 format = freeFormat(format, numTokens);
02816 return 1;
02817 }
02818
02819 dst = start;
02820
02821 token->type = PTOK_ARRAY;
02822
02823 break;
02824
02825 case ']':
02826 if (state != PARSER_IN_ARRAY) {
02827 hsa->errmsg = _("unexpected ]");
02828 format = freeFormat(format, numTokens);
02829 return 1;
02830 }
02831
02832 *start++ = '\0';
02833
02834 if (endPtr) *endPtr = start;
02835 done = 1;
02836 break;
02837
02838 case '}':
02839 if (state != PARSER_IN_EXPR) {
02840 hsa->errmsg = _("unexpected }");
02841 format = freeFormat(format, numTokens);
02842 return 1;
02843 }
02844
02845 *start++ = '\0';
02846
02847 if (endPtr) *endPtr = start;
02848 done = 1;
02849 break;
02850
02851 default:
02852 if (token == NULL || token->type != PTOK_STRING) {
02853 token = format + numTokens++;
02854 token->type = PTOK_STRING;
02855
02856 dst = token->u.string.string = start;
02857
02858 }
02859
02860
02861 if (*start == '\\') {
02862 start++;
02863 *dst++ = escapedChar(*start++);
02864 } else {
02865 *dst++ = *start++;
02866 }
02867
02868 break;
02869 }
02870 if (done)
02871 break;
02872 }
02873
02874
02875
02876 if (dst != NULL)
02877 *dst = '\0';
02878
02879
02880 for (i = 0; i < numTokens; i++) {
02881 token = format + i;
02882 if (token->type == PTOK_STRING)
02883 token->u.string.len = strlen(token->u.string.string);
02884 }
02885
02886 *numTokensPtr = numTokens;
02887 *formatPtr = format;
02888
02889 return 0;
02890 }
02891
02892
02893 static int parseExpression(headerSprintfArgs hsa, sprintfToken token,
02894 char * str, char ** endPtr)
02895 {
02896 char * chptr;
02897 char * end;
02898
02899 hsa->errmsg = NULL;
02900 chptr = str;
02901 while (*chptr && *chptr != '?') chptr++;
02902
02903 if (*chptr != '?') {
02904 hsa->errmsg = _("? expected in expression");
02905 return 1;
02906 }
02907
02908 *chptr++ = '\0';;
02909
02910 if (*chptr != '{') {
02911 hsa->errmsg = _("{ expected after ? in expression");
02912 return 1;
02913 }
02914
02915 chptr++;
02916
02917 if (parseFormat(hsa, chptr, &token->u.cond.ifFormat,
02918 &token->u.cond.numIfTokens, &end, PARSER_IN_EXPR))
02919 return 1;
02920
02921
02922 if (!(end && *end)) {
02923 hsa->errmsg = _("} expected in expression");
02924 token->u.cond.ifFormat =
02925 freeFormat(token->u.cond.ifFormat, token->u.cond.numIfTokens);
02926 return 1;
02927 }
02928
02929 chptr = end;
02930 if (*chptr != ':' && *chptr != '|') {
02931 hsa->errmsg = _(": expected following ? subexpression");
02932 token->u.cond.ifFormat =
02933 freeFormat(token->u.cond.ifFormat, token->u.cond.numIfTokens);
02934 return 1;
02935 }
02936
02937 if (*chptr == '|') {
02938 if (parseFormat(hsa, NULL, &token->u.cond.elseFormat,
02939 &token->u.cond.numElseTokens, &end, PARSER_IN_EXPR))
02940 {
02941 token->u.cond.ifFormat =
02942 freeFormat(token->u.cond.ifFormat, token->u.cond.numIfTokens);
02943 return 1;
02944 }
02945 } else {
02946 chptr++;
02947
02948 if (*chptr != '{') {
02949 hsa->errmsg = _("{ expected after : in expression");
02950 token->u.cond.ifFormat =
02951 freeFormat(token->u.cond.ifFormat, token->u.cond.numIfTokens);
02952 return 1;
02953 }
02954
02955 chptr++;
02956
02957 if (parseFormat(hsa, chptr, &token->u.cond.elseFormat,
02958 &token->u.cond.numElseTokens, &end, PARSER_IN_EXPR))
02959 return 1;
02960
02961
02962 if (!(end && *end)) {
02963 hsa->errmsg = _("} expected in expression");
02964 token->u.cond.ifFormat =
02965 freeFormat(token->u.cond.ifFormat, token->u.cond.numIfTokens);
02966 return 1;
02967 }
02968
02969 chptr = end;
02970 if (*chptr != '|') {
02971 hsa->errmsg = _("| expected at end of expression");
02972 token->u.cond.ifFormat =
02973 freeFormat(token->u.cond.ifFormat, token->u.cond.numIfTokens);
02974 token->u.cond.elseFormat =
02975 freeFormat(token->u.cond.elseFormat, token->u.cond.numElseTokens);
02976 return 1;
02977 }
02978 }
02979
02980 chptr++;
02981
02982 *endPtr = chptr;
02983
02984 token->type = PTOK_COND;
02985
02986 (void) findTag(hsa, token, str);
02987
02988 return 0;
02989 }
02990
02991
03002 static int getExtension(headerSprintfArgs hsa, headerTagTagFunction fn,
03003 hTYP_t typeptr,
03004 hPTR_t * data,
03005 hCNT_t countptr,
03006 rpmec ec)
03007
03008
03009
03010 {
03011 if (!ec->avail) {
03012 if (fn(hsa->h, &ec->type, &ec->data, &ec->count, &ec->freeit))
03013 return 1;
03014 ec->avail = 1;
03015 }
03016
03017 if (typeptr) *typeptr = ec->type;
03018 if (data) *data = ec->data;
03019 if (countptr) *countptr = ec->count;
03020
03021 return 0;
03022 }
03023
03030
03031 static char * formatValue(headerSprintfArgs hsa, sprintfTag tag, int element)
03032
03033 {
03034 char * val = NULL;
03035 size_t need = 0;
03036 char * t, * te;
03037 char buf[20];
03038 int_32 count, type;
03039 hPTR_t data;
03040 unsigned int intVal;
03041 const char ** strarray;
03042 int datafree = 0;
03043 int countBuf;
03044
03045 memset(buf, 0, sizeof(buf));
03046 if (tag->ext) {
03047
03048 if (getExtension(hsa, tag->ext, &type, &data, &count, hsa->ec + tag->extNum))
03049 {
03050 count = 1;
03051 type = RPM_STRING_TYPE;
03052 data = "(none)";
03053 }
03054
03055 } else {
03056
03057 if (!headerGetEntry(hsa->h, tag->tag, &type, (void **)&data, &count)) {
03058 count = 1;
03059 type = RPM_STRING_TYPE;
03060 data = "(none)";
03061 }
03062
03063
03064
03065 switch (type) {
03066 default:
03067 if (element >= count) {
03068
03069 data = headerFreeData(data, type);
03070
03071
03072 hsa->errmsg = _("(index out of range)");
03073 return NULL;
03074 }
03075 break;
03076 case RPM_BIN_TYPE:
03077 case RPM_STRING_TYPE:
03078 break;
03079 }
03080 datafree = 1;
03081 }
03082
03083 if (tag->arrayCount) {
03084
03085 if (datafree)
03086 data = headerFreeData(data, type);
03087
03088
03089 countBuf = count;
03090 data = &countBuf;
03091 count = 1;
03092 type = RPM_INT32_TYPE;
03093 }
03094
03095
03096 (void) stpcpy( stpcpy(buf, "%"), tag->format);
03097
03098
03099
03100 if (data)
03101 switch (type) {
03102 case RPM_STRING_ARRAY_TYPE:
03103 strarray = (const char **)data;
03104
03105 if (tag->fmt)
03106 val = tag->fmt(RPM_STRING_TYPE, strarray[element], buf, tag->pad, element);
03107
03108 if (val) {
03109 need = strlen(val);
03110 } else {
03111 need = strlen(strarray[element]) + tag->pad + 20;
03112 val = xmalloc(need+1);
03113 strcat(buf, "s");
03114
03115 sprintf(val, buf, strarray[element]);
03116
03117 }
03118
03119 break;
03120
03121 case RPM_STRING_TYPE:
03122 if (tag->fmt)
03123 val = tag->fmt(RPM_STRING_TYPE, data, buf, tag->pad, 0);
03124
03125 if (val) {
03126 need = strlen(val);
03127 } else {
03128 need = strlen(data) + tag->pad + 20;
03129 val = xmalloc(need+1);
03130 strcat(buf, "s");
03131
03132 sprintf(val, buf, data);
03133
03134 }
03135 break;
03136
03137 case RPM_CHAR_TYPE:
03138 case RPM_INT8_TYPE:
03139 case RPM_INT16_TYPE:
03140 case RPM_INT32_TYPE:
03141 switch (type) {
03142 case RPM_CHAR_TYPE:
03143 case RPM_INT8_TYPE:
03144 intVal = *(((int_8 *) data) + element);
03145 break;
03146 case RPM_INT16_TYPE:
03147 intVal = *(((uint_16 *) data) + element);
03148 break;
03149 default:
03150 case RPM_INT32_TYPE:
03151 intVal = *(((int_32 *) data) + element);
03152 break;
03153 }
03154
03155 if (tag->fmt)
03156 val = tag->fmt(RPM_INT32_TYPE, &intVal, buf, tag->pad, element);
03157
03158 if (val) {
03159 need = strlen(val);
03160 } else {
03161 need = 10 + tag->pad + 20;
03162 val = xmalloc(need+1);
03163 strcat(buf, "d");
03164
03165 sprintf(val, buf, intVal);
03166
03167 }
03168 break;
03169
03170 case RPM_BIN_TYPE:
03171
03172 if (tag->fmt)
03173 val = tag->fmt(RPM_BIN_TYPE, data, buf, tag->pad, count);
03174
03175 if (val) {
03176 need = strlen(val);
03177 } else {
03178 #ifdef NOTYET
03179 val = memcpy(xmalloc(count), data, count);
03180 #else
03181
03182 static char hex[] = "0123456789abcdef";
03183 const char * s = data;
03184
03185
03186 need = 2*count + tag->pad;
03187 val = t = xmalloc(need+1);
03188 while (count-- > 0) {
03189 unsigned int i;
03190 i = *s++;
03191 *t++ = hex[ (i >> 4) & 0xf ];
03192 *t++ = hex[ (i ) & 0xf ];
03193 }
03194 *t = '\0';
03195
03196 #endif
03197 }
03198 break;
03199
03200 default:
03201 need = sizeof("(unknown type)") - 1;
03202 val = xstrdup("(unknown type)");
03203 break;
03204 }
03205
03206
03207
03208 if (datafree)
03209 data = headerFreeData(data, type);
03210
03211
03212
03213 if (val && need > 0) {
03214 t = hsaReserve(hsa, need);
03215
03216 te = stpcpy(t, val);
03217
03218 hsa->vallen += (te - t);
03219 val = _free(val);
03220 }
03221
03222
03223 return (hsa->val + hsa->vallen);
03224 }
03225
03232
03233 static char * singleSprintf(headerSprintfArgs hsa, sprintfToken token,
03234 int element)
03235
03236 {
03237 char * t, * te;
03238 int i, j;
03239 int numElements;
03240 int_32 type;
03241 int_32 count;
03242 sprintfToken spft;
03243 int condNumFormats;
03244 size_t need;
03245
03246
03247
03248 switch (token->type) {
03249 case PTOK_NONE:
03250 break;
03251
03252 case PTOK_STRING:
03253 need = token->u.string.len;
03254 if (need == 0) break;
03255 t = hsaReserve(hsa, need);
03256
03257 te = stpcpy(t, token->u.string.string);
03258
03259 hsa->vallen += (te - t);
03260 break;
03261
03262 case PTOK_TAG:
03263 t = hsa->val + hsa->vallen;
03264 te = formatValue(hsa, &token->u.tag,
03265 (token->u.tag.justOne ? 0 : element));
03266 if (te == NULL)
03267 return NULL;
03268 break;
03269
03270 case PTOK_COND:
03271 if (token->u.cond.tag.ext || headerIsEntry(hsa->h, token->u.cond.tag.tag)) {
03272 spft = token->u.cond.ifFormat;
03273 condNumFormats = token->u.cond.numIfTokens;
03274 } else {
03275 spft = token->u.cond.elseFormat;
03276 condNumFormats = token->u.cond.numElseTokens;
03277 }
03278
03279 need = condNumFormats * 20;
03280 if (spft == NULL || need == 0) break;
03281
03282 t = hsaReserve(hsa, need);
03283 for (i = 0; i < condNumFormats; i++, spft++) {
03284 te = singleSprintf(hsa, spft, element);
03285 if (te == NULL)
03286 return NULL;
03287 }
03288 break;
03289
03290 case PTOK_ARRAY:
03291 numElements = -1;
03292 spft = token->u.array.format;
03293 for (i = 0; i < token->u.array.numTokens; i++, spft++)
03294 {
03295 if (spft->type != PTOK_TAG ||
03296 spft->u.tag.arrayCount ||
03297 spft->u.tag.justOne) continue;
03298
03299 if (spft->u.tag.ext) {
03300
03301 if (getExtension(hsa, spft->u.tag.ext, &type, NULL, &count,
03302 hsa->ec + spft->u.tag.extNum))
03303 continue;
03304
03305 } else {
03306
03307 if (!headerGetEntry(hsa->h, spft->u.tag.tag, &type, NULL, &count))
03308 continue;
03309
03310 }
03311
03312 if (type == RPM_BIN_TYPE)
03313 count = 1;
03314
03315 if (numElements > 1 && count != numElements)
03316 switch (type) {
03317 default:
03318 hsa->errmsg =
03319 _("array iterator used with different sized arrays");
03320 return NULL;
03321 break;
03322 case RPM_BIN_TYPE:
03323 case RPM_STRING_TYPE:
03324 break;
03325 }
03326 if (count > numElements)
03327 numElements = count;
03328 }
03329
03330 if (numElements == -1) {
03331 need = sizeof("(none)") - 1;
03332 t = hsaReserve(hsa, need);
03333
03334 te = stpcpy(t, "(none)");
03335
03336 hsa->vallen += (te - t);
03337 } else {
03338 int isxml;
03339
03340 need = numElements * token->u.array.numTokens * 10;
03341 if (need == 0) break;
03342
03343 spft = token->u.array.format;
03344 isxml = (spft->type == PTOK_TAG && spft->u.tag.type != NULL &&
03345 !strcmp(spft->u.tag.type, "xml"));
03346
03347 if (isxml) {
03348 const char * tagN = myTagName(hsa->tags, spft->u.tag.tag);
03349
03350 need = sizeof(" <rpmTag name=\"\">\n") - 1;
03351 if (tagN != NULL)
03352 need += strlen(tagN);
03353 t = hsaReserve(hsa, need);
03354
03355 te = stpcpy(t, " <rpmTag name=\"");
03356 if (tagN != NULL)
03357 te = stpcpy(te, tagN);
03358 te = stpcpy(te, "\">\n");
03359
03360 hsa->vallen += (te - t);
03361 }
03362
03363 t = hsaReserve(hsa, need);
03364 for (j = 0; j < numElements; j++) {
03365 spft = token->u.array.format;
03366 for (i = 0; i < token->u.array.numTokens; i++, spft++) {
03367 te = singleSprintf(hsa, spft, j);
03368 if (te == NULL)
03369 return NULL;
03370 }
03371 }
03372
03373 if (isxml) {
03374 need = sizeof(" </rpmTag>\n") - 1;
03375 t = hsaReserve(hsa, need);
03376
03377 te = stpcpy(t, " </rpmTag>\n");
03378
03379 hsa->vallen += (te - t);
03380 }
03381
03382 }
03383 break;
03384 }
03385
03386 return (hsa->val + hsa->vallen);
03387 }
03388
03394 static rpmec
03395 rpmecNew(const headerSprintfExtension exts)
03396
03397 {
03398 headerSprintfExtension ext;
03399 rpmec ec;
03400 int i = 0;
03401
03402 for (ext = exts; ext != NULL && ext->type != HEADER_EXT_LAST;
03403 ext = (ext->type == HEADER_EXT_MORE ? ext->u.more : ext+1))
03404 {
03405 i++;
03406 }
03407
03408 ec = xcalloc(i, sizeof(*ec));
03409 return ec;
03410 }
03411
03418 static rpmec
03419 rpmecFree(const headerSprintfExtension exts, rpmec ec)
03420
03421 {
03422 headerSprintfExtension ext;
03423 int i = 0;
03424
03425 for (ext = exts; ext != NULL && ext->type != HEADER_EXT_LAST;
03426 ext = (ext->type == HEADER_EXT_MORE ? ext->u.more : ext+1))
03427 {
03428
03429 if (ec[i].freeit) ec[i].data = _free(ec[i].data);
03430
03431 i++;
03432 }
03433
03434 ec = _free(ec);
03435 return NULL;
03436 }
03437
03449 static
03450 char * headerSprintf(Header h, const char * fmt,
03451 const struct headerTagTableEntry_s * tbltags,
03452 const struct headerSprintfExtension_s * extensions,
03453 errmsg_t * errmsg)
03454
03455
03456 {
03457 headerSprintfArgs hsa = memset(alloca(sizeof(*hsa)), 0, sizeof(*hsa));
03458 sprintfToken nextfmt;
03459 sprintfTag tag;
03460 char * t, * te;
03461 int isxml;
03462 int need;
03463
03464 hsa->h = headerLink(h);
03465 hsa->fmt = xstrdup(fmt);
03466
03467 hsa->exts = (headerSprintfExtension) extensions;
03468 hsa->tags = (headerTagTableEntry) tbltags;
03469
03470 hsa->errmsg = NULL;
03471
03472
03473 if (parseFormat(hsa, hsa->fmt, &hsa->format, &hsa->numTokens, NULL, PARSER_BEGIN))
03474 goto exit;
03475
03476
03477 hsa->ec = rpmecNew(hsa->exts);
03478 hsa->val = xstrdup("");
03479
03480 tag =
03481 (hsa->format->type == PTOK_TAG
03482 ? &hsa->format->u.tag :
03483 (hsa->format->type == PTOK_ARRAY
03484 ? &hsa->format->u.array.format->u.tag :
03485 NULL));
03486 isxml = (tag != NULL && tag->tag == -2 && tag->type != NULL && !strcmp(tag->type, "xml"));
03487
03488 if (isxml) {
03489 need = sizeof("<rpmHeader>\n") - 1;
03490 t = hsaReserve(hsa, need);
03491
03492 te = stpcpy(t, "<rpmHeader>\n");
03493
03494 hsa->vallen += (te - t);
03495 }
03496
03497 hsa = hsaInit(hsa);
03498 while ((nextfmt = hsaNext(hsa)) != NULL) {
03499 te = singleSprintf(hsa, nextfmt, 0);
03500 if (te == NULL) {
03501 hsa->val = _free(hsa->val);
03502 break;
03503 }
03504 }
03505 hsa = hsaFini(hsa);
03506
03507 if (isxml) {
03508 need = sizeof("</rpmHeader>\n") - 1;
03509 t = hsaReserve(hsa, need);
03510
03511 te = stpcpy(t, "</rpmHeader>\n");
03512
03513 hsa->vallen += (te - t);
03514 }
03515
03516 if (hsa->val != NULL && hsa->vallen < hsa->alloced)
03517 hsa->val = xrealloc(hsa->val, hsa->vallen+1);
03518
03519 hsa->ec = rpmecFree(hsa->exts, hsa->ec);
03520 hsa->format = freeFormat(hsa->format, hsa->numTokens);
03521
03522 exit:
03523
03524 if (errmsg)
03525 *errmsg = hsa->errmsg;
03526
03527 hsa->h = headerFree(hsa->h);
03528 hsa->fmt = _free(hsa->fmt);
03529 return hsa->val;
03530 }
03531
03540 static char * octalFormat(int_32 type, hPTR_t data,
03541 char * formatPrefix, int padding, int element)
03542
03543 {
03544 char * val;
03545
03546 if (type != RPM_INT32_TYPE) {
03547 val = xstrdup(_("(not a number)"));
03548 } else {
03549 val = xmalloc(20 + padding);
03550
03551 strcat(formatPrefix, "o");
03552
03553
03554 sprintf(val, formatPrefix, *((int_32 *) data));
03555
03556 }
03557
03558 return val;
03559 }
03560
03569 static char * hexFormat(int_32 type, hPTR_t data,
03570 char * formatPrefix, int padding, int element)
03571
03572 {
03573 char * val;
03574
03575 if (type != RPM_INT32_TYPE) {
03576 val = xstrdup(_("(not a number)"));
03577 } else {
03578 val = xmalloc(20 + padding);
03579
03580 strcat(formatPrefix, "x");
03581
03582
03583 sprintf(val, formatPrefix, *((int_32 *) data));
03584
03585 }
03586
03587 return val;
03588 }
03589
03592 static char * realDateFormat(int_32 type, hPTR_t data,
03593 char * formatPrefix, int padding, int element,
03594 const char * strftimeFormat)
03595
03596 {
03597 char * val;
03598
03599 if (type != RPM_INT32_TYPE) {
03600 val = xstrdup(_("(not a number)"));
03601 } else {
03602 struct tm * tstruct;
03603 char buf[50];
03604
03605 val = xmalloc(50 + padding);
03606
03607 strcat(formatPrefix, "s");
03608
03609
03610
03611 { time_t dateint = *((int_32 *) data);
03612 tstruct = localtime(&dateint);
03613 }
03614 buf[0] = '\0';
03615 if (tstruct)
03616 (void) strftime(buf, sizeof(buf) - 1, strftimeFormat, tstruct);
03617
03618 sprintf(val, formatPrefix, buf);
03619
03620 }
03621
03622 return val;
03623 }
03624
03633 static char * dateFormat(int_32 type, hPTR_t data,
03634 char * formatPrefix, int padding, int element)
03635
03636 {
03637 return realDateFormat(type, data, formatPrefix, padding, element,
03638 _("%c"));
03639 }
03640
03649 static char * dayFormat(int_32 type, hPTR_t data,
03650 char * formatPrefix, int padding, int element)
03651
03652 {
03653 return realDateFormat(type, data, formatPrefix, padding, element,
03654 _("%a %b %d %Y"));
03655 }
03656
03665 static char * shescapeFormat(int_32 type, hPTR_t data,
03666 char * formatPrefix, int padding, int element)
03667
03668 {
03669 char * result, * dst, * src, * buf;
03670
03671 if (type == RPM_INT32_TYPE) {
03672 result = xmalloc(padding + 20);
03673
03674 strcat(formatPrefix, "d");
03675
03676
03677 sprintf(result, formatPrefix, *((int_32 *) data));
03678
03679 } else {
03680 buf = alloca(strlen(data) + padding + 2);
03681
03682 strcat(formatPrefix, "s");
03683
03684
03685 sprintf(buf, formatPrefix, data);
03686
03687
03688
03689 result = dst = xmalloc(strlen(buf) * 4 + 3);
03690 *dst++ = '\'';
03691 for (src = buf; *src != '\0'; src++) {
03692 if (*src == '\'') {
03693 *dst++ = '\'';
03694 *dst++ = '\\';
03695 *dst++ = '\'';
03696 *dst++ = '\'';
03697 } else {
03698 *dst++ = *src;
03699 }
03700 }
03701 *dst++ = '\'';
03702 *dst = '\0';
03703
03704
03705 }
03706
03707 return result;
03708 }
03709
03710
03711 const struct headerSprintfExtension_s headerDefaultFormats[] = {
03712 { HEADER_EXT_FORMAT, "octal", { octalFormat } },
03713 { HEADER_EXT_FORMAT, "hex", { hexFormat } },
03714 { HEADER_EXT_FORMAT, "date", { dateFormat } },
03715 { HEADER_EXT_FORMAT, "day", { dayFormat } },
03716 { HEADER_EXT_FORMAT, "shescape", { shescapeFormat } },
03717 { HEADER_EXT_LAST, NULL, { NULL } }
03718 };
03719
03720
03727 static
03728 void headerCopyTags(Header headerFrom, Header headerTo, hTAG_t tagstocopy)
03729
03730 {
03731 int * p;
03732
03733 if (headerFrom == headerTo)
03734 return;
03735
03736 for (p = tagstocopy; *p != 0; p++) {
03737 char *s;
03738 int_32 type;
03739 int_32 count;
03740 if (headerIsEntry(headerTo, *p))
03741 continue;
03742
03743 if (!headerGetEntryMinMemory(headerFrom, *p, &type,
03744 (hPTR_t *) &s, &count))
03745 continue;
03746
03747 (void) headerAddEntry(headerTo, *p, type, s, count);
03748 s = headerFreeData(s, type);
03749 }
03750 }
03751
03752
03753 static struct HV_s hdrVec1 = {
03754 headerLink,
03755 headerUnlink,
03756 headerFree,
03757 headerNew,
03758 headerSort,
03759 headerUnsort,
03760 headerSizeof,
03761 headerUnload,
03762 headerReload,
03763 headerCopy,
03764 headerLoad,
03765 headerCopyLoad,
03766 headerRead,
03767 headerWrite,
03768 headerIsEntry,
03769 headerFreeTag,
03770 headerGetEntry,
03771 headerGetEntryMinMemory,
03772 headerAddEntry,
03773 headerAppendEntry,
03774 headerAddOrAppendEntry,
03775 headerAddI18NString,
03776 headerModifyEntry,
03777 headerRemoveEntry,
03778 headerSprintf,
03779 headerCopyTags,
03780 headerFreeIterator,
03781 headerInitIterator,
03782 headerNextIterator,
03783 NULL, NULL,
03784 1
03785 };
03786
03787
03788
03789 HV_t hdrVec = &hdrVec1;
03790