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 const char *const tagName(int tag) ;
00024
00025
00026
00027
00028
00029
00030
00031
00032
00033
00034 #define PARSER_BEGIN 0
00035 #define PARSER_IN_ARRAY 1
00036 #define PARSER_IN_EXPR 2
00037
00038
00039
00040 extern const char *const tagName(int tag)
00041 ;
00042
00043
00046
00047 static unsigned char header_magic[8] = {
00048 0x8e, 0xad, 0xe8, 0x01, 0x00, 0x00, 0x00, 0x00
00049 };
00050
00054
00055 static int typeAlign[16] = {
00056 1,
00057 1,
00058 1,
00059 2,
00060 4,
00061 8,
00062 1,
00063 1,
00064 1,
00065 1,
00066 0,
00067 0,
00068 0,
00069 0,
00070 0,
00071 0
00072 };
00073
00077
00078 static int typeSizes[16] = {
00079 0,
00080 1,
00081 1,
00082 2,
00083 4,
00084 -1,
00085 -1,
00086 1,
00087 -1,
00088 -1,
00089 0,
00090 0,
00091 0,
00092 0,
00093 0,
00094 0
00095 };
00096
00100
00101 static size_t headerMaxbytes = (32*1024*1024);
00102
00107 #define hdrchkTags(_ntags) ((_ntags) & 0xffff0000)
00108
00112 #define hdrchkType(_type) ((_type) < RPM_MIN_TYPE || (_type) > RPM_MAX_TYPE)
00113
00118 #define hdrchkData(_nbytes) ((_nbytes) & 0xff000000)
00119
00123 #define hdrchkAlign(_type, _off) ((_off) & (typeAlign[_type]-1))
00124
00128 #define hdrchkRange(_dl, _off) ((_off) < 0 || (_off) > (_dl))
00129
00130
00131 HV_t hdrVec;
00132
00138 static inline void *
00139 _free( const void * p)
00140 {
00141 if (p != NULL) free((void *)p);
00142 return NULL;
00143 }
00144
00150 static
00151 Header headerLink(Header h)
00152
00153 {
00154
00155 if (h == NULL) return NULL;
00156
00157
00158 h->nrefs++;
00159
00160 if (_hdr_debug)
00161 fprintf(stderr, "--> h %p ++ %d at %s:%u\n", h, h->nrefs, __FILE__, __LINE__);
00162
00163
00164
00165 return h;
00166
00167 }
00168
00174 static
00175 Header headerUnlink( Header h)
00176
00177 {
00178 if (h == NULL) return NULL;
00179
00180 if (_hdr_debug)
00181 fprintf(stderr, "--> h %p -- %d at %s:%u\n", h, h->nrefs, __FILE__, __LINE__);
00182
00183 h->nrefs--;
00184 return NULL;
00185 }
00186
00192 static
00193 Header headerFree( Header h)
00194
00195 {
00196 (void) headerUnlink(h);
00197
00198
00199 if (h == NULL || h->nrefs > 0)
00200 return NULL;
00201
00202 if (h->index) {
00203 indexEntry entry = h->index;
00204 int i;
00205 for (i = 0; i < h->indexUsed; i++, entry++) {
00206 if ((h->flags & HEADERFLAG_ALLOCATED) && ENTRY_IS_REGION(entry)) {
00207 if (entry->length > 0) {
00208 int_32 * ei = entry->data;
00209 if ((ei - 2) == h->blob) h->blob = _free(h->blob);
00210 entry->data = NULL;
00211 }
00212 } else if (!ENTRY_IN_REGION(entry)) {
00213 entry->data = _free(entry->data);
00214 }
00215 entry->data = NULL;
00216 }
00217 h->index = _free(h->index);
00218 }
00219
00220 h = _free(h);
00221 return h;
00222
00223 }
00224
00229 static
00230 Header headerNew(void)
00231
00232 {
00233 Header h = xcalloc(1, sizeof(*h));
00234
00235
00236
00237 h->hv = *hdrVec;
00238
00239
00240 h->blob = NULL;
00241 h->indexAlloced = INDEX_MALLOC_SIZE;
00242 h->indexUsed = 0;
00243 h->flags |= HEADERFLAG_SORTED;
00244
00245 h->index = (h->indexAlloced
00246 ? xcalloc(h->indexAlloced, sizeof(*h->index))
00247 : NULL);
00248
00249 h->nrefs = 0;
00250
00251 return headerLink(h);
00252
00253 }
00254
00257 static int indexCmp(const void * avp, const void * bvp)
00258
00259 {
00260
00261 indexEntry ap = (indexEntry) avp, bp = (indexEntry) bvp;
00262
00263 return (ap->info.tag - bp->info.tag);
00264 }
00265
00270 static
00271 void headerSort(Header h)
00272
00273 {
00274 if (!(h->flags & HEADERFLAG_SORTED)) {
00275
00276 qsort(h->index, h->indexUsed, sizeof(*h->index), indexCmp);
00277
00278 h->flags |= HEADERFLAG_SORTED;
00279 }
00280 }
00281
00284 static int offsetCmp(const void * avp, const void * bvp)
00285 {
00286
00287 indexEntry ap = (indexEntry) avp, bp = (indexEntry) bvp;
00288
00289 int rc = (ap->info.offset - bp->info.offset);
00290
00291 if (rc == 0) {
00292
00293 if (ap->info.offset < 0)
00294 rc = (((char *)ap->data) - ((char *)bp->data));
00295 else
00296 rc = (ap->info.tag - bp->info.tag);
00297 }
00298 return rc;
00299 }
00300
00305 static
00306 void headerUnsort(Header h)
00307
00308 {
00309
00310 qsort(h->index, h->indexUsed, sizeof(*h->index), offsetCmp);
00311
00312 }
00313
00320 static
00321 unsigned int headerSizeof( Header h, enum hMagic magicp)
00322
00323 {
00324 indexEntry entry;
00325 unsigned int size = 0;
00326 unsigned int pad = 0;
00327 int i;
00328
00329 if (h == NULL)
00330 return size;
00331
00332 headerSort(h);
00333
00334 switch (magicp) {
00335 case HEADER_MAGIC_YES:
00336 size += sizeof(header_magic);
00337 break;
00338 case HEADER_MAGIC_NO:
00339 break;
00340 }
00341
00342
00343 size += 2 * sizeof(int_32);
00344
00345
00346 for (i = 0, entry = h->index; i < h->indexUsed; i++, entry++) {
00347 unsigned diff;
00348 int_32 type;
00349
00350
00351 if (ENTRY_IS_REGION(entry)) {
00352 size += entry->length;
00353
00354
00355 if (i == 0 && (h->flags & HEADERFLAG_LEGACY))
00356 size += sizeof(struct entryInfo_s) + entry->info.count;
00357
00358 continue;
00359 }
00360
00361
00362 if (entry->info.offset < 0)
00363 continue;
00364
00365
00366 type = entry->info.type;
00367
00368 if (typeSizes[type] > 1) {
00369 diff = typeSizes[type] - (size % typeSizes[type]);
00370 if (diff != typeSizes[type]) {
00371 size += diff;
00372 pad += diff;
00373 }
00374 }
00375
00376
00377
00378 size += sizeof(struct entryInfo_s) + entry->length;
00379
00380 }
00381
00382 return size;
00383 }
00384
00394 static int dataLength(int_32 type, hPTR_t p, int_32 count, int onDisk,
00395 hPTR_t pend)
00396
00397 {
00398 const unsigned char * s = p;
00399 const unsigned char * se = pend;
00400 int length = 0;
00401
00402 switch (type) {
00403 case RPM_STRING_TYPE:
00404 if (count != 1)
00405 return -1;
00406
00407 while (*s++) {
00408 if (se && s > se)
00409 return -1;
00410 length++;
00411 }
00412
00413 length++;
00414 break;
00415
00416 case RPM_STRING_ARRAY_TYPE:
00417 case RPM_I18NSTRING_TYPE:
00418
00419
00420
00421 if (onDisk) {
00422 while (count--) {
00423 length++;
00424
00425 while (*s++) {
00426 if (se && s > se)
00427 return -1;
00428 length++;
00429 }
00430
00431 }
00432 } else {
00433 const char ** av = (const char **)p;
00434
00435 while (count--) {
00436
00437 length += strlen(*av++) + 1;
00438 }
00439
00440 }
00441 break;
00442
00443 default:
00444
00445 if (typeSizes[type] == -1)
00446 return -1;
00447 length = typeSizes[(type & 0xf)] * count;
00448
00449 if (length < 0 || (se && (s + length) > se))
00450 return -1;
00451 break;
00452 }
00453
00454 return length;
00455 }
00456
00483 static int regionSwab( indexEntry entry, int il, int dl,
00484 entryInfo pe,
00485 unsigned char * dataStart,
00486 const unsigned char * dataEnd,
00487 int regionid)
00488
00489 {
00490 unsigned char * tprev = NULL;
00491 unsigned char * t = NULL;
00492 int tdel = 0;
00493 int tl = dl;
00494 struct indexEntry_s ieprev;
00495
00496 if (regionid > 0)
00497 return -1;
00498
00499 memset(&ieprev, 0, sizeof(ieprev));
00500
00501 for (; il > 0; il--, pe++) {
00502 struct indexEntry_s ie;
00503 int_32 type;
00504
00505 ie.info.tag = ntohl(pe->tag);
00506 ie.info.type = ntohl(pe->type);
00507 ie.info.count = ntohl(pe->count);
00508 ie.info.offset = ntohl(pe->offset);
00509
00510 if (hdrchkType(ie.info.type))
00511 return -1;
00512 if (hdrchkData(ie.info.count))
00513 return -1;
00514 if (hdrchkData(ie.info.offset))
00515 return -1;
00516
00517 if (hdrchkAlign(ie.info.type, ie.info.offset))
00518 return -1;
00519
00520
00521 ie.data = t = dataStart + ie.info.offset;
00522 if (dataEnd && t >= dataEnd)
00523 return -1;
00524
00525 ie.length = dataLength(ie.info.type, ie.data, ie.info.count, 1, dataEnd);
00526 if (ie.length < 0 || hdrchkData(ie.length))
00527 return -1;
00528
00529 ie.rdlen = 0;
00530
00531 if (entry) {
00532 ie.info.offset = regionid;
00533
00534 *entry = ie;
00535
00536 entry++;
00537 }
00538
00539
00540 type = ie.info.type;
00541
00542 if (typeSizes[type] > 1) {
00543 unsigned diff;
00544 diff = typeSizes[type] - (dl % typeSizes[type]);
00545 if (diff != typeSizes[type]) {
00546 dl += diff;
00547 if (ieprev.info.type == RPM_I18NSTRING_TYPE)
00548 ieprev.length += diff;
00549 }
00550 }
00551
00552 tdel = (tprev ? (t - tprev) : 0);
00553 if (ieprev.info.type == RPM_I18NSTRING_TYPE)
00554 tdel = ieprev.length;
00555
00556 if (ie.info.tag >= HEADER_I18NTABLE) {
00557 tprev = t;
00558 } else {
00559 tprev = dataStart;
00560
00561
00562 if (ie.info.tag == HEADER_IMAGE)
00563 tprev -= REGION_TAG_COUNT;
00564
00565 }
00566
00567
00568 switch (ntohl(pe->type)) {
00569
00570 case RPM_INT32_TYPE:
00571 { int_32 * it = (int_32 *)t;
00572 for (; ie.info.count > 0; ie.info.count--, it += 1) {
00573 if (dataEnd && ((unsigned char *)it) >= dataEnd)
00574 return -1;
00575 *it = htonl(*it);
00576 }
00577 t = (char *) it;
00578 } break;
00579 case RPM_INT16_TYPE:
00580 { int_16 * it = (int_16 *) t;
00581 for (; ie.info.count > 0; ie.info.count--, it += 1) {
00582 if (dataEnd && ((unsigned char *)it) >= dataEnd)
00583 return -1;
00584 *it = htons(*it);
00585 }
00586 t = (char *) it;
00587 } break;
00588
00589 default:
00590 t += ie.length;
00591 break;
00592 }
00593
00594 dl += ie.length;
00595 tl += tdel;
00596 ieprev = ie;
00597
00598 }
00599 tdel = (tprev ? (t - tprev) : 0);
00600 tl += tdel;
00601
00602
00603
00604
00605
00606
00607
00608 if (tl+REGION_TAG_COUNT == dl)
00609 tl += REGION_TAG_COUNT;
00610
00611
00612 return dl;
00613 }
00614
00620 static void * doHeaderUnload(Header h,
00621 int * lengthPtr)
00622
00623
00624
00625 {
00626 int_32 * ei = NULL;
00627 entryInfo pe;
00628 char * dataStart;
00629 char * te;
00630 unsigned pad;
00631 unsigned len;
00632 int_32 il = 0;
00633 int_32 dl = 0;
00634 indexEntry entry;
00635 int_32 type;
00636 int i;
00637 int drlen, ndribbles;
00638 int driplen, ndrips;
00639 int legacy = 0;
00640
00641
00642 headerUnsort(h);
00643
00644
00645 pad = 0;
00646 drlen = ndribbles = driplen = ndrips = 0;
00647 for (i = 0, entry = h->index; i < h->indexUsed; i++, entry++) {
00648 if (ENTRY_IS_REGION(entry)) {
00649 int_32 rdl = -entry->info.offset;
00650 int_32 ril = rdl/sizeof(*pe);
00651 int rid = entry->info.offset;
00652
00653 il += ril;
00654 dl += entry->rdlen + entry->info.count;
00655
00656 if (i == 0 && (h->flags & HEADERFLAG_LEGACY))
00657 il += 1;
00658
00659
00660 for (; i < h->indexUsed && entry->info.offset <= rid+1; i++, entry++) {
00661 if (entry->info.offset <= rid)
00662 continue;
00663
00664
00665 type = entry->info.type;
00666 if (typeSizes[type] > 1) {
00667 unsigned diff;
00668 diff = typeSizes[type] - (dl % typeSizes[type]);
00669 if (diff != typeSizes[type]) {
00670 drlen += diff;
00671 pad += diff;
00672 dl += diff;
00673 }
00674 }
00675
00676 ndribbles++;
00677 il++;
00678 drlen += entry->length;
00679 dl += entry->length;
00680 }
00681 i--;
00682 entry--;
00683 continue;
00684 }
00685
00686
00687 if (entry->data == NULL || entry->length <= 0)
00688 continue;
00689
00690
00691 type = entry->info.type;
00692 if (typeSizes[type] > 1) {
00693 unsigned diff;
00694 diff = typeSizes[type] - (dl % typeSizes[type]);
00695 if (diff != typeSizes[type]) {
00696 driplen += diff;
00697 pad += diff;
00698 dl += diff;
00699 } else
00700 diff = 0;
00701 }
00702
00703 ndrips++;
00704 il++;
00705 driplen += entry->length;
00706 dl += entry->length;
00707 }
00708
00709
00710 if (hdrchkTags(il) || hdrchkData(dl))
00711 goto errxit;
00712
00713 len = sizeof(il) + sizeof(dl) + (il * sizeof(*pe)) + dl;
00714
00715
00716 ei = xmalloc(len);
00717 ei[0] = htonl(il);
00718 ei[1] = htonl(dl);
00719
00720
00721 pe = (entryInfo) &ei[2];
00722 dataStart = te = (char *) (pe + il);
00723
00724 pad = 0;
00725 for (i = 0, entry = h->index; i < h->indexUsed; i++, entry++) {
00726 const char * src;
00727 char *t;
00728 int count;
00729 int rdlen;
00730
00731 if (entry->data == NULL || entry->length <= 0)
00732 continue;
00733
00734 t = te;
00735 pe->tag = htonl(entry->info.tag);
00736 pe->type = htonl(entry->info.type);
00737 pe->count = htonl(entry->info.count);
00738
00739 if (ENTRY_IS_REGION(entry)) {
00740 int_32 rdl = -entry->info.offset;
00741 int_32 ril = rdl/sizeof(*pe) + ndribbles;
00742 int rid = entry->info.offset;
00743
00744 src = (char *)entry->data;
00745 rdlen = entry->rdlen;
00746
00747
00748 if (i == 0 && (h->flags & HEADERFLAG_LEGACY)) {
00749 int_32 stei[4];
00750
00751 legacy = 1;
00752
00753 memcpy(pe+1, src, rdl);
00754 memcpy(te, src + rdl, rdlen);
00755
00756 te += rdlen;
00757
00758 pe->offset = htonl(te - dataStart);
00759 stei[0] = pe->tag;
00760 stei[1] = pe->type;
00761 stei[2] = htonl(-rdl-entry->info.count);
00762 stei[3] = pe->count;
00763
00764 memcpy(te, stei, entry->info.count);
00765
00766 te += entry->info.count;
00767 ril++;
00768 rdlen += entry->info.count;
00769
00770 count = regionSwab(NULL, ril, 0, pe, t, NULL, 0);
00771 if (count != rdlen)
00772 goto errxit;
00773
00774 } else {
00775
00776
00777 memcpy(pe+1, src + sizeof(*pe), ((ril-1) * sizeof(*pe)));
00778 memcpy(te, src + (ril * sizeof(*pe)), rdlen+entry->info.count+drlen);
00779
00780 te += rdlen;
00781 {
00782 entryInfo se = (entryInfo)src;
00783
00784 int off = ntohl(se->offset);
00785 pe->offset = (off) ? htonl(te - dataStart) : htonl(off);
00786 }
00787 te += entry->info.count + drlen;
00788
00789 count = regionSwab(NULL, ril, 0, pe, t, NULL, 0);
00790 if (count != (rdlen + entry->info.count + drlen))
00791 goto errxit;
00792 }
00793
00794
00795 while (i < h->indexUsed && entry->info.offset <= rid+1) {
00796 i++;
00797 entry++;
00798 }
00799 i--;
00800 entry--;
00801 pe += ril;
00802 continue;
00803 }
00804
00805
00806 if (entry->data == NULL || entry->length <= 0)
00807 continue;
00808
00809
00810 type = entry->info.type;
00811 if (typeSizes[type] > 1) {
00812 unsigned diff;
00813 diff = typeSizes[type] - ((te - dataStart) % typeSizes[type]);
00814 if (diff != typeSizes[type]) {
00815
00816 memset(te, 0, diff);
00817
00818 te += diff;
00819 pad += diff;
00820 }
00821 }
00822
00823 pe->offset = htonl(te - dataStart);
00824
00825
00826
00827 switch (entry->info.type) {
00828 case RPM_INT32_TYPE:
00829 count = entry->info.count;
00830 src = entry->data;
00831 while (count--) {
00832 *((int_32 *)te) = htonl(*((int_32 *)src));
00833
00834 te += sizeof(int_32);
00835 src += sizeof(int_32);
00836
00837 }
00838 break;
00839
00840 case RPM_INT16_TYPE:
00841 count = entry->info.count;
00842 src = entry->data;
00843 while (count--) {
00844 *((int_16 *)te) = htons(*((int_16 *)src));
00845
00846 te += sizeof(int_16);
00847 src += sizeof(int_16);
00848
00849 }
00850 break;
00851
00852 default:
00853 memcpy(te, entry->data, entry->length);
00854 te += entry->length;
00855 break;
00856 }
00857
00858 pe++;
00859 }
00860
00861
00862 if (((char *)pe) != dataStart)
00863 goto errxit;
00864 if ((((char *)ei)+len) != te)
00865 goto errxit;
00866
00867 if (lengthPtr)
00868 *lengthPtr = len;
00869
00870 h->flags &= ~HEADERFLAG_SORTED;
00871 headerSort(h);
00872
00873 return (void *) ei;
00874
00875 errxit:
00876
00877 ei = _free(ei);
00878
00879 return (void *) ei;
00880 }
00881
00887 static
00888 void * headerUnload(Header h)
00889
00890 {
00891 int length;
00892
00893 void * uh = doHeaderUnload(h, &length);
00894
00895 return uh;
00896 }
00897
00905 static
00906 indexEntry findEntry( Header h, int_32 tag, int_32 type)
00907
00908 {
00909 indexEntry entry, entry2, last;
00910 struct indexEntry_s key;
00911
00912 if (h == NULL) return NULL;
00913 if (!(h->flags & HEADERFLAG_SORTED)) headerSort(h);
00914
00915 key.info.tag = tag;
00916
00917
00918 entry2 = entry =
00919 bsearch(&key, h->index, h->indexUsed, sizeof(*h->index), indexCmp);
00920
00921 if (entry == NULL)
00922 return NULL;
00923
00924 if (type == RPM_NULL_TYPE)
00925 return entry;
00926
00927
00928 while (entry->info.tag == tag && entry->info.type != type &&
00929 entry > h->index) entry--;
00930
00931 if (entry->info.tag == tag && entry->info.type == type)
00932 return entry;
00933
00934 last = h->index + h->indexUsed;
00935
00936 while (entry2->info.tag == tag && entry2->info.type != type &&
00937 entry2 < last) entry2++;
00938
00939
00940 if (entry->info.tag == tag && entry->info.type == type)
00941 return entry;
00942
00943 return NULL;
00944 }
00945
00955 static
00956 int headerRemoveEntry(Header h, int_32 tag)
00957
00958 {
00959 indexEntry last = h->index + h->indexUsed;
00960 indexEntry entry, first;
00961 int ne;
00962
00963 entry = findEntry(h, tag, RPM_NULL_TYPE);
00964 if (!entry) return 1;
00965
00966
00967 while (entry > h->index && (entry - 1)->info.tag == tag)
00968 entry--;
00969
00970
00971 for (first = entry; first < last; first++) {
00972 void * data;
00973 if (first->info.tag != tag)
00974 break;
00975 data = first->data;
00976 first->data = NULL;
00977 first->length = 0;
00978 if (ENTRY_IN_REGION(first))
00979 continue;
00980 data = _free(data);
00981 }
00982
00983 ne = (first - entry);
00984 if (ne > 0) {
00985 h->indexUsed -= ne;
00986 ne = last - first;
00987
00988 if (ne > 0)
00989 memmove(entry, first, (ne * sizeof(*entry)));
00990
00991 }
00992
00993 return 0;
00994 }
00995
01001 static
01002 Header headerLoad( void * uh)
01003
01004 {
01005 int_32 * ei = (int_32 *) uh;
01006 int_32 il = ntohl(ei[0]);
01007 int_32 dl = ntohl(ei[1]);
01008
01009 size_t pvlen = sizeof(il) + sizeof(dl) +
01010 (il * sizeof(struct entryInfo_s)) + dl;
01011
01012 void * pv = uh;
01013 Header h = NULL;
01014 entryInfo pe;
01015 unsigned char * dataStart;
01016 unsigned char * dataEnd;
01017 indexEntry entry;
01018 int rdlen;
01019 int i;
01020
01021
01022 if (hdrchkTags(il) || hdrchkData(dl))
01023 goto errxit;
01024
01025 ei = (int_32 *) pv;
01026
01027 pe = (entryInfo) &ei[2];
01028
01029 dataStart = (unsigned char *) (pe + il);
01030 dataEnd = dataStart + dl;
01031
01032 h = xcalloc(1, sizeof(*h));
01033
01034 h->hv = *hdrVec;
01035
01036
01037 h->blob = uh;
01038
01039 h->indexAlloced = il + 1;
01040 h->indexUsed = il;
01041 h->index = xcalloc(h->indexAlloced, sizeof(*h->index));
01042 h->flags |= HEADERFLAG_SORTED;
01043 h->nrefs = 0;
01044 h = headerLink(h);
01045
01046
01047
01048
01049
01050 if (ntohl(pe->tag) == 15 &&
01051 ntohl(pe->type) == RPM_STRING_TYPE &&
01052 ntohl(pe->count) == 1)
01053 {
01054 pe->tag = htonl(1079);
01055 }
01056
01057 entry = h->index;
01058 i = 0;
01059 if (!(htonl(pe->tag) < HEADER_I18NTABLE)) {
01060 h->flags |= HEADERFLAG_LEGACY;
01061 entry->info.type = REGION_TAG_TYPE;
01062 entry->info.tag = HEADER_IMAGE;
01063
01064 entry->info.count = REGION_TAG_COUNT;
01065
01066 entry->info.offset = ((unsigned char *)pe - dataStart);
01067
01068
01069 entry->data = pe;
01070
01071 entry->length = pvlen - sizeof(il) - sizeof(dl);
01072 rdlen = regionSwab(entry+1, il, 0, pe, dataStart, dataEnd, entry->info.offset);
01073 if (rdlen != dl)
01074 goto errxit;
01075 entry->rdlen = rdlen;
01076 entry++;
01077 h->indexUsed++;
01078 } else {
01079 int_32 rdl;
01080 int_32 ril;
01081
01082 h->flags &= ~HEADERFLAG_LEGACY;
01083
01084 entry->info.type = htonl(pe->type);
01085 entry->info.count = htonl(pe->count);
01086 entry->info.tag = htonl(pe->tag);
01087
01088 if (!ENTRY_IS_REGION(entry))
01089 goto errxit;
01090 if (entry->info.type != REGION_TAG_TYPE)
01091 goto errxit;
01092 if (entry->info.count != REGION_TAG_COUNT)
01093 goto errxit;
01094
01095 { int off = ntohl(pe->offset);
01096
01097 if (hdrchkData(off))
01098 goto errxit;
01099 if (off) {
01100
01101 size_t nb = REGION_TAG_COUNT;
01102
01103 int_32 * stei;
01104 if (dataStart + off + nb > dataEnd)
01105 goto errxit;
01106 stei = memcpy(alloca(nb), dataStart + off, nb);
01107 rdl = -ntohl(stei[2]);
01108 ril = rdl/sizeof(*pe);
01109 if (hdrchkTags(ril) || hdrchkData(rdl))
01110 goto errxit;
01111 } else {
01112 ril = il;
01113
01114 rdl = (ril * sizeof(struct entryInfo_s));
01115
01116 entry->info.tag = HEADER_IMAGE;
01117 }
01118 }
01119 entry->info.offset = -rdl;
01120
01121
01122 entry->data = pe;
01123
01124 entry->length = pvlen - sizeof(il) - sizeof(dl);
01125 rdlen = regionSwab(entry+1, ril-1, 0, pe+1, dataStart, dataEnd, entry->info.offset);
01126 if (rdlen < 0)
01127 goto errxit;
01128 entry->rdlen = rdlen;
01129
01130 if (ril < h->indexUsed) {
01131 indexEntry newEntry = entry + ril;
01132 int ne = (h->indexUsed - ril);
01133 int rid = entry->info.offset+1;
01134
01135
01136 rdlen = regionSwab(newEntry, ne, rdlen, pe+ril,
01137 dataStart, dataEnd, rid);
01138 if (rdlen < 0)
01139 goto errxit;
01140
01141 { indexEntry firstEntry = newEntry;
01142 int save = h->indexUsed;
01143 int j;
01144
01145
01146 h->indexUsed -= ne;
01147 for (j = 0; j < ne; j++, newEntry++) {
01148 (void) headerRemoveEntry(h, newEntry->info.tag);
01149 if (newEntry->info.tag == HEADER_BASENAMES)
01150 (void) headerRemoveEntry(h, HEADER_OLDFILENAMES);
01151 }
01152
01153
01154
01155 if (h->indexUsed < (save - ne)) {
01156 memmove(h->index + h->indexUsed, firstEntry,
01157 (ne * sizeof(*entry)));
01158 }
01159
01160 h->indexUsed += ne;
01161 }
01162 }
01163
01164 rdlen += REGION_TAG_COUNT;
01165
01166 if (rdlen != dl)
01167 goto errxit;
01168 }
01169
01170 h->flags &= ~HEADERFLAG_SORTED;
01171 headerSort(h);
01172
01173
01174 return h;
01175
01176
01177 errxit:
01178
01179 if (h) {
01180 h->index = _free(h->index);
01181
01182 h = _free(h);
01183
01184 }
01185
01186
01187 return h;
01188
01189 }
01190
01198 static
01199 Header headerReload( Header h, int tag)
01200
01201 {
01202 Header nh;
01203 int length;
01204
01205
01206 void * uh = doHeaderUnload(h, &length);
01207
01208
01209 h = headerFree(h);
01210
01211 if (uh == NULL)
01212 return NULL;
01213 nh = headerLoad(uh);
01214 if (nh == NULL) {
01215 uh = _free(uh);
01216 return NULL;
01217 }
01218 if (nh->flags & HEADERFLAG_ALLOCATED)
01219 uh = _free(uh);
01220 nh->flags |= HEADERFLAG_ALLOCATED;
01221 if (ENTRY_IS_REGION(nh->index)) {
01222
01223 if (tag == HEADER_SIGNATURES || tag == HEADER_IMMUTABLE)
01224 nh->index[0].info.tag = tag;
01225
01226 }
01227 return nh;
01228 }
01229
01235 static
01236 Header headerCopyLoad(const void * uh)
01237
01238 {
01239 int_32 * ei = (int_32 *) uh;
01240
01241 int_32 il = ntohl(ei[0]);
01242 int_32 dl = ntohl(ei[1]);
01243
01244
01245 size_t pvlen = sizeof(il) + sizeof(dl) +
01246 (il * sizeof(struct entryInfo_s)) + dl;
01247
01248 void * nuh = NULL;
01249 Header h = NULL;
01250
01251
01252
01253 if (!(hdrchkTags(il) || hdrchkData(dl)) && pvlen < headerMaxbytes) {
01254
01255 nuh = memcpy(xmalloc(pvlen), uh, pvlen);
01256
01257 if ((h = headerLoad(nuh)) != NULL)
01258 h->flags |= HEADERFLAG_ALLOCATED;
01259 }
01260
01261
01262 if (h == NULL)
01263 nuh = _free(nuh);
01264
01265 return h;
01266 }
01267
01274 static
01275 Header headerRead(FD_t fd, enum hMagic magicp)
01276
01277 {
01278 int_32 block[4];
01279 int_32 reserved;
01280 int_32 * ei = NULL;
01281 int_32 il;
01282 int_32 dl;
01283 int_32 magic;
01284 Header h = NULL;
01285 size_t len;
01286 int i;
01287
01288 memset(block, 0, sizeof(block));
01289 i = 2;
01290 if (magicp == HEADER_MAGIC_YES)
01291 i += 2;
01292
01293
01294 if (timedRead(fd, (char *)block, i*sizeof(*block)) != (i * sizeof(*block)))
01295 goto exit;
01296
01297
01298 i = 0;
01299
01300
01301 if (magicp == HEADER_MAGIC_YES) {
01302 magic = block[i++];
01303 if (memcmp(&magic, header_magic, sizeof(magic)))
01304 goto exit;
01305 reserved = block[i++];
01306 }
01307
01308 il = ntohl(block[i]); i++;
01309 dl = ntohl(block[i]); i++;
01310
01311
01312
01313 len = sizeof(il) + sizeof(dl) + (il * sizeof(struct entryInfo_s)) + dl;
01314
01315
01316
01317 if (hdrchkTags(il) || hdrchkData(dl) || len > headerMaxbytes)
01318 goto exit;
01319
01320
01321 ei = xmalloc(len);
01322 ei[0] = htonl(il);
01323 ei[1] = htonl(dl);
01324 len -= sizeof(il) + sizeof(dl);
01325
01326
01327
01328
01329 if (timedRead(fd, (char *)&ei[2], len) != len)
01330 goto exit;
01331
01332
01333
01334 h = headerLoad(ei);
01335
01336 exit:
01337 if (h) {
01338 if (h->flags & HEADERFLAG_ALLOCATED)
01339 ei = _free(ei);
01340 h->flags |= HEADERFLAG_ALLOCATED;
01341 } else if (ei)
01342 ei = _free(ei);
01343
01344 return h;
01345
01346 }
01347
01355 static
01356 int headerWrite(FD_t fd, Header h, enum hMagic magicp)
01357
01358
01359 {
01360 ssize_t nb;
01361 int length;
01362 const void * uh;
01363
01364 if (h == NULL)
01365 return 1;
01366
01367 uh = doHeaderUnload(h, &length);
01368
01369 if (uh == NULL)
01370 return 1;
01371 switch (magicp) {
01372 case HEADER_MAGIC_YES:
01373
01374
01375 nb = Fwrite(header_magic, sizeof(char), sizeof(header_magic), fd);
01376
01377
01378 if (nb != sizeof(header_magic))
01379 goto exit;
01380 break;
01381 case HEADER_MAGIC_NO:
01382 break;
01383 }
01384
01385
01386 nb = Fwrite(uh, sizeof(char), length, fd);
01387
01388
01389 exit:
01390 uh = _free(uh);
01391 return (nb == length ? 0 : 1);
01392 }
01393
01400 static
01401 int headerIsEntry(Header h, int_32 tag)
01402
01403 {
01404
01405 return (findEntry(h, tag, RPM_NULL_TYPE) ? 1 : 0);
01406
01407 }
01408
01419 static int copyEntry(const indexEntry entry,
01420 hTYP_t type,
01421 hPTR_t * p,
01422 hCNT_t c,
01423 int minMem)
01424
01425
01426 {
01427 int_32 count = entry->info.count;
01428 int rc = 1;
01429
01430 if (p)
01431 switch (entry->info.type) {
01432 case RPM_BIN_TYPE:
01433
01434
01435
01436
01437
01438
01439 if (ENTRY_IS_REGION(entry)) {
01440 int_32 * ei = ((int_32 *)entry->data) - 2;
01441
01442 entryInfo pe = (entryInfo) (ei + 2);
01443
01444
01445 char * dataStart = (char *) (pe + ntohl(ei[0]));
01446
01447 int_32 rdl = -entry->info.offset;
01448 int_32 ril = rdl/sizeof(*pe);
01449
01450
01451 rdl = entry->rdlen;
01452 count = 2 * sizeof(*ei) + (ril * sizeof(*pe)) + rdl;
01453 if (entry->info.tag == HEADER_IMAGE) {
01454 ril -= 1;
01455 pe += 1;
01456 } else {
01457 count += REGION_TAG_COUNT;
01458 rdl += REGION_TAG_COUNT;
01459 }
01460
01461
01462 *p = xmalloc(count);
01463 ei = (int_32 *) *p;
01464 ei[0] = htonl(ril);
01465 ei[1] = htonl(rdl);
01466
01467
01468 pe = (entryInfo) memcpy(ei + 2, pe, (ril * sizeof(*pe)));
01469
01470
01471 dataStart = (char *) memcpy(pe + ril, dataStart, rdl);
01472
01473
01474
01475 rc = regionSwab(NULL, ril, 0, pe, dataStart, NULL, 0);
01476
01477 rc = (rc < 0) ? 0 : 1;
01478 } else {
01479 count = entry->length;
01480 *p = (!minMem
01481 ? memcpy(xmalloc(count), entry->data, count)
01482 : entry->data);
01483 }
01484 break;
01485 case RPM_STRING_TYPE:
01486 if (count == 1) {
01487 *p = entry->data;
01488 break;
01489 }
01490
01491 case RPM_STRING_ARRAY_TYPE:
01492 case RPM_I18NSTRING_TYPE:
01493 { const char ** ptrEntry;
01494
01495 int tableSize = count * sizeof(char *);
01496
01497 char * t;
01498 int i;
01499
01500
01501
01502 if (minMem) {
01503 *p = xmalloc(tableSize);
01504 ptrEntry = (const char **) *p;
01505 t = entry->data;
01506 } else {
01507 t = xmalloc(tableSize + entry->length);
01508 *p = (void *)t;
01509 ptrEntry = (const char **) *p;
01510 t += tableSize;
01511 memcpy(t, entry->data, entry->length);
01512 }
01513
01514
01515 for (i = 0; i < count; i++) {
01516
01517 *ptrEntry++ = t;
01518
01519 t = strchr(t, 0);
01520 t++;
01521 }
01522 } break;
01523
01524 default:
01525 *p = entry->data;
01526 break;
01527 }
01528 if (type) *type = entry->info.type;
01529 if (c) *c = count;
01530 return rc;
01531 }
01532
01551 static int headerMatchLocale(const char *td, const char *l, const char *le)
01552
01553 {
01554 const char *fe;
01555
01556
01557 #if 0
01558 { const char *s, *ll, *CC, *EE, *dd;
01559 char *lbuf, *t.
01560
01561
01562 lbuf = alloca(le - l + 1);
01563 for (s = l, ll = t = lbuf; *s; s++, t++) {
01564 switch (*s) {
01565 case '_':
01566 *t = '\0';
01567 CC = t + 1;
01568 break;
01569 case '.':
01570 *t = '\0';
01571 EE = t + 1;
01572 break;
01573 case '@':
01574 *t = '\0';
01575 dd = t + 1;
01576 break;
01577 default:
01578 *t = *s;
01579 break;
01580 }
01581 }
01582
01583 if (ll)
01584 for (t = ll; *t; t++) *t = tolower(*t);
01585 if (CC)
01586 for (t = CC; *t; t++) *t = toupper(*t);
01587
01588
01589 }
01590 #endif
01591
01592
01593 if (strlen(td) == (le-l) && !strncmp(td, l, (le - l)))
01594 return 1;
01595
01596
01597 for (fe = l; fe < le && *fe != '@'; fe++)
01598 {};
01599 if (fe < le && !strncmp(td, l, (fe - l)))
01600 return 1;
01601
01602
01603 for (fe = l; fe < le && *fe != '.'; fe++)
01604 {};
01605 if (fe < le && !strncmp(td, l, (fe - l)))
01606 return 1;
01607
01608
01609 for (fe = l; fe < le && *fe != '_'; fe++)
01610 {};
01611 if (fe < le && !strncmp(td, l, (fe - l)))
01612 return 1;
01613
01614 return 0;
01615 }
01616
01623 static char *
01624 headerFindI18NString(Header h, indexEntry entry)
01625
01626 {
01627 const char *lang, *l, *le;
01628 indexEntry table;
01629
01630
01631 if ((lang = getenv("LANGUAGE")) == NULL &&
01632 (lang = getenv("LC_ALL")) == NULL &&
01633 (lang = getenv("LC_MESSAGES")) == NULL &&
01634 (lang = getenv("LANG")) == NULL)
01635 return entry->data;
01636
01637
01638 if ((table = findEntry(h, HEADER_I18NTABLE, RPM_STRING_ARRAY_TYPE)) == NULL)
01639 return entry->data;
01640
01641
01642
01643 for (l = lang; *l != '\0'; l = le) {
01644 const char *td;
01645 char *ed;
01646 int langNum;
01647
01648 while (*l && *l == ':')
01649 l++;
01650 if (*l == '\0')
01651 break;
01652 for (le = l; *le && *le != ':'; le++)
01653 {};
01654
01655
01656 for (langNum = 0, td = table->data, ed = entry->data;
01657 langNum < entry->info.count;
01658 langNum++, td += strlen(td) + 1, ed += strlen(ed) + 1) {
01659
01660 if (headerMatchLocale(td, l, le))
01661 return ed;
01662
01663 }
01664 }
01665
01666
01667 return entry->data;
01668 }
01669
01680 static int intGetEntry(Header h, int_32 tag,
01681 hTAG_t type,
01682 hPTR_t * p,
01683 hCNT_t c,
01684 int minMem)
01685
01686
01687 {
01688 indexEntry entry;
01689 int rc;
01690
01691
01692
01693 entry = findEntry(h, tag, RPM_NULL_TYPE);
01694
01695 if (entry == NULL) {
01696 if (type) type = 0;
01697 if (p) *p = NULL;
01698 if (c) *c = 0;
01699 return 0;
01700 }
01701
01702 switch (entry->info.type) {
01703 case RPM_I18NSTRING_TYPE:
01704 rc = 1;
01705 if (type) *type = RPM_STRING_TYPE;
01706 if (c) *c = 1;
01707
01708 if (p) *p = headerFindI18NString(h, entry);
01709
01710 break;
01711 default:
01712 rc = copyEntry(entry, type, p, c, minMem);
01713 break;
01714 }
01715
01716
01717 return ((rc == 1) ? 1 : 0);
01718 }
01719
01727 static void * headerFreeTag( Header h,
01728 const void * data, rpmTagType type)
01729
01730 {
01731 if (data) {
01732
01733 if (type == -1 ||
01734 type == RPM_STRING_ARRAY_TYPE ||
01735 type == RPM_I18NSTRING_TYPE ||
01736 type == RPM_BIN_TYPE)
01737 data = _free(data);
01738
01739 }
01740 return NULL;
01741 }
01742
01756 static
01757 int headerGetEntry(Header h, int_32 tag,
01758 hTYP_t type,
01759 void ** p,
01760 hCNT_t c)
01761
01762
01763 {
01764 return intGetEntry(h, tag, type, (hPTR_t *)p, c, 0);
01765 }
01766
01779 static
01780 int headerGetEntryMinMemory(Header h, int_32 tag,
01781 hTYP_t type,
01782 hPTR_t * p,
01783 hCNT_t c)
01784
01785
01786 {
01787 return intGetEntry(h, tag, type, p, c, 1);
01788 }
01789
01790 int headerGetRawEntry(Header h, int_32 tag, int_32 * type, hPTR_t * p,
01791 int_32 * c)
01792 {
01793 indexEntry entry;
01794 int rc;
01795
01796 if (p == NULL) return headerIsEntry(h, tag);
01797
01798
01799
01800 entry = findEntry(h, tag, RPM_NULL_TYPE);
01801
01802 if (!entry) {
01803 if (p) *p = NULL;
01804 if (c) *c = 0;
01805 return 0;
01806 }
01807
01808 rc = copyEntry(entry, type, p, c, 0);
01809
01810
01811 return ((rc == 1) ? 1 : 0);
01812 }
01813
01816 static void copyData(int_32 type, void * dstPtr, const void * srcPtr,
01817 int_32 cnt, int dataLength)
01818
01819 {
01820 switch (type) {
01821 case RPM_STRING_ARRAY_TYPE:
01822 case RPM_I18NSTRING_TYPE:
01823 { const char ** av = (const char **) srcPtr;
01824 char * t = dstPtr;
01825
01826
01827 while (cnt-- > 0 && dataLength > 0) {
01828 const char * s;
01829 if ((s = *av++) == NULL)
01830 continue;
01831 do {
01832 *t++ = *s++;
01833 } while (s[-1] && --dataLength > 0);
01834 }
01835
01836 } break;
01837
01838 default:
01839
01840 memmove(dstPtr, srcPtr, dataLength);
01841
01842 break;
01843 }
01844 }
01845
01854
01855 static void *
01856 grabData(int_32 type, hPTR_t p, int_32 c, int * lengthPtr)
01857
01858
01859 {
01860 void * data = NULL;
01861 int length;
01862
01863 length = dataLength(type, p, c, 0, NULL);
01864
01865 if (length > 0) {
01866 data = xmalloc(length);
01867 copyData(type, data, p, c, length);
01868 }
01869
01870
01871 if (lengthPtr)
01872 *lengthPtr = length;
01873 return data;
01874 }
01875
01890 static
01891 int headerAddEntry(Header h, int_32 tag, int_32 type, const void * p, int_32 c)
01892
01893 {
01894 indexEntry entry;
01895 void * data;
01896 int length;
01897
01898
01899 if (c <= 0)
01900 return 0;
01901
01902 if (hdrchkType(type))
01903 return 0;
01904 if (hdrchkData(c))
01905 return 0;
01906
01907 length = 0;
01908
01909 data = grabData(type, p, c, &length);
01910
01911 if (data == NULL || length <= 0)
01912 return 0;
01913
01914
01915 if (h->indexUsed == h->indexAlloced) {
01916 h->indexAlloced += INDEX_MALLOC_SIZE;
01917 h->index = xrealloc(h->index, h->indexAlloced * sizeof(*h->index));
01918 }
01919
01920
01921 entry = h->index + h->indexUsed;
01922 entry->info.tag = tag;
01923 entry->info.type = type;
01924 entry->info.count = c;
01925 entry->info.offset = 0;
01926 entry->data = data;
01927 entry->length = length;
01928
01929
01930 if (h->indexUsed > 0 && tag < h->index[h->indexUsed-1].info.tag)
01931 h->flags &= ~HEADERFLAG_SORTED;
01932
01933 h->indexUsed++;
01934
01935 return 1;
01936 }
01937
01952 static
01953 int headerAppendEntry(Header h, int_32 tag, int_32 type,
01954 const void * p, int_32 c)
01955
01956 {
01957 indexEntry entry;
01958 int length;
01959
01960 if (type == RPM_STRING_TYPE || type == RPM_I18NSTRING_TYPE) {
01961
01962 return 0;
01963 }
01964
01965
01966 entry = findEntry(h, tag, type);
01967 if (!entry)
01968 return 0;
01969
01970 length = dataLength(type, p, c, 0, NULL);
01971 if (length < 0)
01972 return 0;
01973
01974 if (ENTRY_IN_REGION(entry)) {
01975 char * t = xmalloc(entry->length + length);
01976
01977 memcpy(t, entry->data, entry->length);
01978
01979 entry->data = t;
01980 entry->info.offset = 0;
01981 } else
01982 entry->data = xrealloc(entry->data, entry->length + length);
01983
01984 copyData(type, ((char *) entry->data) + entry->length, p, c, length);
01985
01986 entry->length += length;
01987
01988 entry->info.count += c;
01989
01990 return 1;
01991 }
01992
02003 static
02004 int headerAddOrAppendEntry(Header h, int_32 tag, int_32 type,
02005 const void * p, int_32 c)
02006
02007 {
02008 return (findEntry(h, tag, type)
02009 ? headerAppendEntry(h, tag, type, p, c)
02010 : headerAddEntry(h, tag, type, p, c));
02011 }
02012
02033 static
02034 int headerAddI18NString(Header h, int_32 tag, const char * string,
02035 const char * lang)
02036
02037 {
02038 indexEntry table, entry;
02039 const char ** strArray;
02040 int length;
02041 int ghosts;
02042 int i, langNum;
02043 char * buf;
02044
02045 table = findEntry(h, HEADER_I18NTABLE, RPM_STRING_ARRAY_TYPE);
02046 entry = findEntry(h, tag, RPM_I18NSTRING_TYPE);
02047
02048 if (!table && entry)
02049 return 0;
02050
02051 if (!table && !entry) {
02052 const char * charArray[2];
02053 int count = 0;
02054 if (!lang || (lang[0] == 'C' && lang[1] == '\0')) {
02055
02056 charArray[count++] = "C";
02057
02058 } else {
02059
02060 charArray[count++] = "C";
02061
02062 charArray[count++] = lang;
02063 }
02064 if (!headerAddEntry(h, HEADER_I18NTABLE, RPM_STRING_ARRAY_TYPE,
02065 &charArray, count))
02066 return 0;
02067 table = findEntry(h, HEADER_I18NTABLE, RPM_STRING_ARRAY_TYPE);
02068 }
02069
02070 if (!table)
02071 return 0;
02072
02073 if (!lang) lang = "C";
02074
02075
02076 { const char * l = table->data;
02077 for (langNum = 0; langNum < table->info.count; langNum++) {
02078 if (!strcmp(l, lang)) break;
02079 l += strlen(l) + 1;
02080 }
02081 }
02082
02083 if (langNum >= table->info.count) {
02084 length = strlen(lang) + 1;
02085 if (ENTRY_IN_REGION(table)) {
02086 char * t = xmalloc(table->length + length);
02087 memcpy(t, table->data, table->length);
02088 table->data = t;
02089 table->info.offset = 0;
02090 } else
02091 table->data = xrealloc(table->data, table->length + length);
02092 memmove(((char *)table->data) + table->length, lang, length);
02093 table->length += length;
02094 table->info.count++;
02095 }
02096
02097 if (!entry) {
02098 strArray = alloca(sizeof(*strArray) * (langNum + 1));
02099 for (i = 0; i < langNum; i++)
02100 strArray[i] = "";
02101 strArray[langNum] = string;
02102 return headerAddEntry(h, tag, RPM_I18NSTRING_TYPE, strArray,
02103 langNum + 1);
02104 } else if (langNum >= entry->info.count) {
02105 ghosts = langNum - entry->info.count;
02106
02107 length = strlen(string) + 1 + ghosts;
02108 if (ENTRY_IN_REGION(entry)) {
02109 char * t = xmalloc(entry->length + length);
02110 memcpy(t, entry->data, entry->length);
02111 entry->data = t;
02112 entry->info.offset = 0;
02113 } else
02114 entry->data = xrealloc(entry->data, entry->length + length);
02115
02116 memset(((char *)entry->data) + entry->length, '\0', ghosts);
02117 memmove(((char *)entry->data) + entry->length + ghosts, string, strlen(string)+1);
02118
02119 entry->length += length;
02120 entry->info.count = langNum + 1;
02121 } else {
02122 char *b, *be, *e, *ee, *t;
02123 size_t bn, sn, en;
02124
02125
02126 b = be = e = ee = entry->data;
02127 for (i = 0; i < table->info.count; i++) {
02128 if (i == langNum)
02129 be = ee;
02130 ee += strlen(ee) + 1;
02131 if (i == langNum)
02132 e = ee;
02133 }
02134
02135
02136 bn = (be-b);
02137 sn = strlen(string) + 1;
02138 en = (ee-e);
02139 length = bn + sn + en;
02140 t = buf = xmalloc(length);
02141
02142
02143 memcpy(t, b, bn);
02144 t += bn;
02145
02146 memcpy(t, string, sn);
02147 t += sn;
02148 memcpy(t, e, en);
02149 t += en;
02150
02151
02152
02153 entry->length -= strlen(be) + 1;
02154 entry->length += sn;
02155
02156 if (ENTRY_IN_REGION(entry)) {
02157 entry->info.offset = 0;
02158 } else
02159 entry->data = _free(entry->data);
02160
02161 entry->data = buf;
02162
02163 }
02164
02165 return 0;
02166 }
02167
02178 static
02179 int headerModifyEntry(Header h, int_32 tag, int_32 type,
02180 const void * p, int_32 c)
02181
02182 {
02183 indexEntry entry;
02184 void * oldData;
02185 void * data;
02186 int length;
02187
02188
02189 entry = findEntry(h, tag, type);
02190 if (!entry)
02191 return 0;
02192
02193 length = 0;
02194 data = grabData(type, p, c, &length);
02195 if (data == NULL || length <= 0)
02196 return 0;
02197
02198
02199 while (entry > h->index && (entry - 1)->info.tag == tag)
02200 entry--;
02201
02202
02203
02204 oldData = entry->data;
02205
02206 entry->info.count = c;
02207 entry->info.type = type;
02208 entry->data = data;
02209 entry->length = length;
02210
02211
02212 if (ENTRY_IN_REGION(entry)) {
02213 entry->info.offset = 0;
02214 } else
02215 oldData = _free(oldData);
02216
02217
02218 return 1;
02219 }
02220
02223 static char escapedChar(const char ch)
02224 {
02225 switch (ch) {
02226 case 'a': return '\a';
02227 case 'b': return '\b';
02228 case 'f': return '\f';
02229 case 'n': return '\n';
02230 case 'r': return '\r';
02231 case 't': return '\t';
02232 case 'v': return '\v';
02233 default: return ch;
02234 }
02235 }
02236
02243 static sprintfToken
02244 freeFormat( sprintfToken format, int num)
02245
02246 {
02247 int i;
02248
02249 if (format == NULL) return NULL;
02250
02251 for (i = 0; i < num; i++) {
02252 switch (format[i].type) {
02253 case PTOK_ARRAY:
02254
02255 format[i].u.array.format =
02256 freeFormat(format[i].u.array.format,
02257 format[i].u.array.numTokens);
02258
02259 break;
02260 case PTOK_COND:
02261
02262 format[i].u.cond.ifFormat =
02263 freeFormat(format[i].u.cond.ifFormat,
02264 format[i].u.cond.numIfTokens);
02265 format[i].u.cond.elseFormat =
02266 freeFormat(format[i].u.cond.elseFormat,
02267 format[i].u.cond.numElseTokens);
02268
02269 break;
02270 case PTOK_NONE:
02271 case PTOK_TAG:
02272 case PTOK_STRING:
02273 default:
02274 break;
02275 }
02276 }
02277 format = _free(format);
02278 return NULL;
02279 }
02280
02284 struct headerIterator_s {
02285
02286 Header h;
02287
02288 int next_index;
02289 };
02290
02296 static
02297 HeaderIterator headerFreeIterator( HeaderIterator hi)
02298
02299 {
02300 if (hi != NULL) {
02301 hi->h = headerFree(hi->h);
02302 hi = _free(hi);
02303 }
02304 return hi;
02305 }
02306
02312 static
02313 HeaderIterator headerInitIterator(Header h)
02314
02315 {
02316 HeaderIterator hi = xmalloc(sizeof(*hi));
02317
02318 headerSort(h);
02319
02320 hi->h = headerLink(h);
02321 hi->next_index = 0;
02322 return hi;
02323 }
02324
02334 static
02335 int headerNextIterator(HeaderIterator hi,
02336 hTAG_t tag,
02337 hTYP_t type,
02338 hPTR_t * p,
02339 hCNT_t c)
02340
02341
02342
02343 {
02344 Header h = hi->h;
02345 int slot = hi->next_index;
02346 indexEntry entry = NULL;
02347 int rc;
02348
02349 for (slot = hi->next_index; slot < h->indexUsed; slot++) {
02350 entry = h->index + slot;
02351 if (!ENTRY_IS_REGION(entry))
02352 break;
02353 }
02354 hi->next_index = slot;
02355 if (entry == NULL || slot >= h->indexUsed)
02356 return 0;
02357
02358
02359 hi->next_index++;
02360
02361
02362 if (tag)
02363 *tag = entry->info.tag;
02364
02365 rc = copyEntry(entry, type, p, c, 0);
02366
02367
02368 return ((rc == 1) ? 1 : 0);
02369 }
02370
02376 static
02377 Header headerCopy(Header h)
02378
02379 {
02380 Header nh = headerNew();
02381 HeaderIterator hi;
02382 int_32 tag, type, count;
02383 hPTR_t ptr;
02384
02385
02386 for (hi = headerInitIterator(h);
02387 headerNextIterator(hi, &tag, &type, &ptr, &count);
02388 ptr = headerFreeData((void *)ptr, type))
02389 {
02390 if (ptr) (void) headerAddEntry(nh, tag, type, ptr, count);
02391 }
02392 hi = headerFreeIterator(hi);
02393
02394
02395 return headerReload(nh, HEADER_IMAGE);
02396 }
02397
02400 typedef struct headerSprintfArgs_s {
02401 Header h;
02402 char * fmt;
02403
02404 headerTagTableEntry tags;
02405
02406 headerSprintfExtension exts;
02407
02408 const char * errmsg;
02409 rpmec ec;
02410 sprintfToken format;
02411
02412 HeaderIterator hi;
02413
02414 char * val;
02415 size_t vallen;
02416 size_t alloced;
02417 int numTokens;
02418 int i;
02419 } * headerSprintfArgs;
02420
02426 static headerSprintfArgs hsaInit( headerSprintfArgs hsa)
02427
02428 {
02429 sprintfTag tag =
02430 (hsa->format->type == PTOK_TAG
02431 ? &hsa->format->u.tag :
02432 (hsa->format->type == PTOK_ARRAY
02433 ? &hsa->format->u.array.format->u.tag :
02434 NULL));
02435
02436 if (hsa != NULL) {
02437 hsa->i = 0;
02438 if (tag != NULL && tag->tag == -2)
02439 hsa->hi = headerInitIterator(hsa->h);
02440 }
02441
02442 return hsa;
02443
02444 }
02445
02451
02452 static sprintfToken hsaNext( headerSprintfArgs hsa)
02453
02454 {
02455 sprintfToken fmt = NULL;
02456 sprintfTag tag =
02457 (hsa->format->type == PTOK_TAG
02458 ? &hsa->format->u.tag :
02459 (hsa->format->type == PTOK_ARRAY
02460 ? &hsa->format->u.array.format->u.tag :
02461 NULL));
02462
02463 if (hsa != NULL && hsa->i >= 0 && hsa->i < hsa->numTokens) {
02464 fmt = hsa->format + hsa->i;
02465 if (hsa->hi == NULL) {
02466 hsa->i++;
02467 } else {
02468 int_32 tagno;
02469 int_32 type;
02470 int_32 count;
02471
02472
02473 if (!headerNextIterator(hsa->hi, &tagno, &type, NULL, &count))
02474 fmt = NULL;
02475 tag->tag = tagno;
02476
02477 }
02478 }
02479
02480
02481 return fmt;
02482
02483 }
02484
02490 static headerSprintfArgs hsaFini( headerSprintfArgs hsa)
02491
02492 {
02493 if (hsa != NULL) {
02494 hsa->hi = headerFreeIterator(hsa->hi);
02495 hsa->i = 0;
02496 }
02497
02498 return hsa;
02499
02500 }
02501
02508
02509 static char * hsaReserve(headerSprintfArgs hsa, size_t need)
02510
02511 {
02512 if ((hsa->vallen + need) >= hsa->alloced) {
02513 if (hsa->alloced <= need)
02514 hsa->alloced += need;
02515 hsa->alloced <<= 1;
02516 hsa->val = xrealloc(hsa->val, hsa->alloced+1);
02517 }
02518 return hsa->val + hsa->vallen;
02519 }
02520
02527 static int findTag(headerSprintfArgs hsa, sprintfToken token, const char * name)
02528
02529 {
02530 headerTagTableEntry tag;
02531 headerSprintfExtension ext;
02532 sprintfTag stag = (token->type == PTOK_COND
02533 ? &token->u.cond.tag : &token->u.tag);
02534
02535 stag->fmt = NULL;
02536 stag->ext = NULL;
02537 stag->extNum = 0;
02538 stag->tag = -1;
02539
02540 if (!strcmp(name, "*")) {
02541 stag->tag = -2;
02542 goto bingo;
02543 }
02544
02545
02546 if (strncmp("RPMTAG_", name, sizeof("RPMTAG_")-1)) {
02547
02548 char * t = alloca(strlen(name) + sizeof("RPMTAG_"));
02549 (void) stpcpy( stpcpy(t, "RPMTAG_"), name);
02550 name = t;
02551
02552 }
02553
02554
02555
02556 for (ext = hsa->exts; ext != NULL && ext->type != HEADER_EXT_LAST;
02557 ext = (ext->type == HEADER_EXT_MORE ? ext->u.more : ext+1))
02558 {
02559 if (ext->name == NULL || ext->type != HEADER_EXT_TAG)
02560 continue;
02561 if (!xstrcasecmp(ext->name, name)) {
02562 stag->ext = ext->u.tagFunction;
02563 stag->extNum = ext - hsa->exts;
02564 goto bingo;
02565 }
02566 }
02567
02568
02569 for (tag = hsa->tags; tag->name != NULL; tag++) {
02570 if (!xstrcasecmp(tag->name, name)) {
02571 stag->tag = tag->val;
02572 goto bingo;
02573 }
02574 }
02575
02576 return 1;
02577
02578 bingo:
02579
02580 if (stag->type != NULL)
02581 for (ext = hsa->exts; ext != NULL && ext->type != HEADER_EXT_LAST;
02582 ext = (ext->type == HEADER_EXT_MORE ? ext->u.more : ext+1))
02583 {
02584 if (ext->name == NULL || ext->type != HEADER_EXT_FORMAT)
02585 continue;
02586 if (!strcmp(ext->name, stag->type)) {
02587 stag->fmt = ext->u.formatFunction;
02588 break;
02589 }
02590 }
02591 return 0;
02592 }
02593
02594
02602 static int parseExpression(headerSprintfArgs hsa, sprintfToken token,
02603 char * str, char ** endPtr)
02604
02605 ;
02606
02616 static int parseFormat(headerSprintfArgs hsa, char * str,
02617 sprintfToken * formatPtr, int * numTokensPtr,
02618 char ** endPtr, int state)
02619
02620
02621
02622 {
02623 char * chptr, * start, * next, * dst;
02624 sprintfToken format;
02625 sprintfToken token;
02626 int numTokens;
02627 int i;
02628 int done = 0;
02629
02630
02631 numTokens = 0;
02632 if (str != NULL)
02633 for (chptr = str; *chptr != '\0'; chptr++)
02634 if (*chptr == '%') numTokens++;
02635 numTokens = numTokens * 2 + 1;
02636
02637 format = xcalloc(numTokens, sizeof(*format));
02638 if (endPtr) *endPtr = NULL;
02639
02640
02641 dst = start = str;
02642 numTokens = 0;
02643 token = NULL;
02644 if (start != NULL)
02645 while (*start != '\0') {
02646 switch (*start) {
02647 case '%':
02648
02649 if (*(start + 1) == '%') {
02650 if (token == NULL || token->type != PTOK_STRING) {
02651 token = format + numTokens++;
02652 token->type = PTOK_STRING;
02653
02654 dst = token->u.string.string = start;
02655
02656 }
02657 start++;
02658
02659 *dst++ = *start++;
02660
02661 break;
02662 }
02663
02664 token = format + numTokens++;
02665
02666 *dst++ = '\0';
02667
02668 start++;
02669
02670 if (*start == '|') {
02671 char * newEnd;
02672
02673 start++;
02674
02675 if (parseExpression(hsa, token, start, &newEnd))
02676 {
02677 format = freeFormat(format, numTokens);
02678 return 1;
02679 }
02680
02681 start = newEnd;
02682 break;
02683 }
02684
02685
02686 token->u.tag.format = start;
02687
02688 token->u.tag.pad = 0;
02689 token->u.tag.justOne = 0;
02690 token->u.tag.arrayCount = 0;
02691
02692 chptr = start;
02693 while (*chptr && *chptr != '{' && *chptr != '%') chptr++;
02694 if (!*chptr || *chptr == '%') {
02695 hsa->errmsg = _("missing { after %");
02696 format = freeFormat(format, numTokens);
02697 return 1;
02698 }
02699
02700
02701 *chptr++ = '\0';
02702
02703
02704 while (start < chptr) {
02705 if (xisdigit(*start)) {
02706 i = strtoul(start, &start, 10);
02707 token->u.tag.pad += i;
02708 } else {
02709 start++;
02710 }
02711 }
02712
02713 if (*start == '=') {
02714 token->u.tag.justOne = 1;
02715 start++;
02716 } else if (*start == '#') {
02717 token->u.tag.justOne = 1;
02718 token->u.tag.arrayCount = 1;
02719 start++;
02720 }
02721
02722 next = start;
02723 while (*next && *next != '}') next++;
02724 if (!*next) {
02725 hsa->errmsg = _("missing } after %{");
02726 format = freeFormat(format, numTokens);
02727 return 1;
02728 }
02729
02730 *next++ = '\0';
02731
02732
02733 chptr = start;
02734 while (*chptr && *chptr != ':') chptr++;
02735
02736 if (*chptr != '\0') {
02737
02738 *chptr++ = '\0';
02739
02740 if (!*chptr) {
02741 hsa->errmsg = _("empty tag format");
02742 format = freeFormat(format, numTokens);
02743 return 1;
02744 }
02745
02746 token->u.tag.type = chptr;
02747
02748 } else {
02749 token->u.tag.type = NULL;
02750 }
02751
02752 if (!*start) {
02753 hsa->errmsg = _("empty tag name");
02754 format = freeFormat(format, numTokens);
02755 return 1;
02756 }
02757
02758 i = 0;
02759 token->type = PTOK_TAG;
02760
02761 if (findTag(hsa, token, start)) {
02762 hsa->errmsg = _("unknown tag");
02763 format = freeFormat(format, numTokens);
02764 return 1;
02765 }
02766
02767 start = next;
02768 break;
02769
02770 case '[':
02771
02772 *dst++ = '\0';
02773 *start++ = '\0';
02774
02775 token = format + numTokens++;
02776
02777
02778 if (parseFormat(hsa, start,
02779 &token->u.array.format,
02780 &token->u.array.numTokens,
02781 &start, PARSER_IN_ARRAY))
02782 {
02783 format = freeFormat(format, numTokens);
02784 return 1;
02785 }
02786
02787
02788 if (!start) {
02789 hsa->errmsg = _("] expected at end of array");
02790 format = freeFormat(format, numTokens);
02791 return 1;
02792 }
02793
02794 dst = start;
02795
02796 token->type = PTOK_ARRAY;
02797
02798 break;
02799
02800 case ']':
02801 if (state != PARSER_IN_ARRAY) {
02802 hsa->errmsg = _("unexpected ]");
02803 format = freeFormat(format, numTokens);
02804 return 1;
02805 }
02806
02807 *start++ = '\0';
02808
02809 if (endPtr) *endPtr = start;
02810 done = 1;
02811 break;
02812
02813 case '}':
02814 if (state != PARSER_IN_EXPR) {
02815 hsa->errmsg = _("unexpected }");
02816 format = freeFormat(format, numTokens);
02817 return 1;
02818 }
02819
02820 *start++ = '\0';
02821
02822 if (endPtr) *endPtr = start;
02823 done = 1;
02824 break;
02825
02826 default:
02827 if (token == NULL || token->type != PTOK_STRING) {
02828 token = format + numTokens++;
02829 token->type = PTOK_STRING;
02830
02831 dst = token->u.string.string = start;
02832
02833 }
02834
02835
02836 if (*start == '\\') {
02837 start++;
02838 *dst++ = escapedChar(*start++);
02839 } else {
02840 *dst++ = *start++;
02841 }
02842
02843 break;
02844 }
02845 if (done)
02846 break;
02847 }
02848
02849
02850
02851 if (dst != NULL)
02852 *dst = '\0';
02853
02854
02855 for (i = 0; i < numTokens; i++) {
02856 token = format + i;
02857 if (token->type == PTOK_STRING)
02858 token->u.string.len = strlen(token->u.string.string);
02859 }
02860
02861 *numTokensPtr = numTokens;
02862 *formatPtr = format;
02863
02864 return 0;
02865 }
02866
02867
02868 static int parseExpression(headerSprintfArgs hsa, sprintfToken token,
02869 char * str, char ** endPtr)
02870 {
02871 char * chptr;
02872 char * end;
02873
02874 hsa->errmsg = NULL;
02875 chptr = str;
02876 while (*chptr && *chptr != '?') chptr++;
02877
02878 if (*chptr != '?') {
02879 hsa->errmsg = _("? expected in expression");
02880 return 1;
02881 }
02882
02883 *chptr++ = '\0';;
02884
02885 if (*chptr != '{') {
02886 hsa->errmsg = _("{ expected after ? in expression");
02887 return 1;
02888 }
02889
02890 chptr++;
02891
02892 if (parseFormat(hsa, chptr, &token->u.cond.ifFormat,
02893 &token->u.cond.numIfTokens, &end, PARSER_IN_EXPR))
02894 return 1;
02895
02896
02897 if (!(end && *end)) {
02898 hsa->errmsg = _("} expected in expression");
02899 token->u.cond.ifFormat =
02900 freeFormat(token->u.cond.ifFormat, token->u.cond.numIfTokens);
02901 return 1;
02902 }
02903
02904 chptr = end;
02905 if (*chptr != ':' && *chptr != '|') {
02906 hsa->errmsg = _(": expected following ? subexpression");
02907 token->u.cond.ifFormat =
02908 freeFormat(token->u.cond.ifFormat, token->u.cond.numIfTokens);
02909 return 1;
02910 }
02911
02912 if (*chptr == '|') {
02913 if (parseFormat(hsa, NULL, &token->u.cond.elseFormat,
02914 &token->u.cond.numElseTokens, &end, PARSER_IN_EXPR))
02915 {
02916 token->u.cond.ifFormat =
02917 freeFormat(token->u.cond.ifFormat, token->u.cond.numIfTokens);
02918 return 1;
02919 }
02920 } else {
02921 chptr++;
02922
02923 if (*chptr != '{') {
02924 hsa->errmsg = _("{ expected after : in expression");
02925 token->u.cond.ifFormat =
02926 freeFormat(token->u.cond.ifFormat, token->u.cond.numIfTokens);
02927 return 1;
02928 }
02929
02930 chptr++;
02931
02932 if (parseFormat(hsa, chptr, &token->u.cond.elseFormat,
02933 &token->u.cond.numElseTokens, &end, PARSER_IN_EXPR))
02934 return 1;
02935
02936
02937 if (!(end && *end)) {
02938 hsa->errmsg = _("} expected in expression");
02939 token->u.cond.ifFormat =
02940 freeFormat(token->u.cond.ifFormat, token->u.cond.numIfTokens);
02941 return 1;
02942 }
02943
02944 chptr = end;
02945 if (*chptr != '|') {
02946 hsa->errmsg = _("| expected at end of expression");
02947 token->u.cond.ifFormat =
02948 freeFormat(token->u.cond.ifFormat, token->u.cond.numIfTokens);
02949 token->u.cond.elseFormat =
02950 freeFormat(token->u.cond.elseFormat, token->u.cond.numElseTokens);
02951 return 1;
02952 }
02953 }
02954
02955 chptr++;
02956
02957 *endPtr = chptr;
02958
02959 token->type = PTOK_COND;
02960
02961 (void) findTag(hsa, token, str);
02962
02963 return 0;
02964 }
02965
02966
02977 static int getExtension(headerSprintfArgs hsa, headerTagTagFunction fn,
02978 hTYP_t typeptr,
02979 hPTR_t * data,
02980 hCNT_t countptr,
02981 rpmec ec)
02982
02983
02984
02985 {
02986 if (!ec->avail) {
02987 if (fn(hsa->h, &ec->type, &ec->data, &ec->count, &ec->freeit))
02988 return 1;
02989 ec->avail = 1;
02990 }
02991
02992 if (typeptr) *typeptr = ec->type;
02993 if (data) *data = ec->data;
02994 if (countptr) *countptr = ec->count;
02995
02996 return 0;
02997 }
02998
03005
03006 static char * formatValue(headerSprintfArgs hsa, sprintfTag tag, int element)
03007
03008 {
03009 char * val = NULL;
03010 size_t need = 0;
03011 char * t, * te;
03012 char buf[20];
03013 int_32 count, type;
03014 hPTR_t data;
03015 unsigned int intVal;
03016 const char ** strarray;
03017 int datafree = 0;
03018 int countBuf;
03019
03020 memset(buf, 0, sizeof(buf));
03021 if (tag->ext) {
03022
03023 if (getExtension(hsa, tag->ext, &type, &data, &count, hsa->ec + tag->extNum))
03024 {
03025 count = 1;
03026 type = RPM_STRING_TYPE;
03027 data = "(none)";
03028 }
03029
03030 } else {
03031
03032 if (!headerGetEntry(hsa->h, tag->tag, &type, (void **)&data, &count)) {
03033 count = 1;
03034 type = RPM_STRING_TYPE;
03035 data = "(none)";
03036 }
03037
03038
03039
03040 switch (type) {
03041 default:
03042 if (element >= count) {
03043
03044 data = headerFreeData(data, type);
03045
03046
03047 hsa->errmsg = _("(index out of range)");
03048 return NULL;
03049 }
03050 break;
03051 case RPM_BIN_TYPE:
03052 case RPM_STRING_TYPE:
03053 break;
03054 }
03055 datafree = 1;
03056 }
03057
03058 if (tag->arrayCount) {
03059
03060 if (datafree)
03061 data = headerFreeData(data, type);
03062
03063
03064 countBuf = count;
03065 data = &countBuf;
03066 count = 1;
03067 type = RPM_INT32_TYPE;
03068 }
03069
03070
03071 (void) stpcpy( stpcpy(buf, "%"), tag->format);
03072
03073
03074
03075 if (data)
03076 switch (type) {
03077 case RPM_STRING_ARRAY_TYPE:
03078 strarray = (const char **)data;
03079
03080 if (tag->fmt)
03081 val = tag->fmt(RPM_STRING_TYPE, strarray[element], buf, tag->pad, element);
03082
03083 if (val) {
03084 need = strlen(val);
03085 } else {
03086 need = strlen(strarray[element]) + tag->pad + 20;
03087 val = xmalloc(need+1);
03088 strcat(buf, "s");
03089
03090 sprintf(val, buf, strarray[element]);
03091
03092 }
03093
03094 break;
03095
03096 case RPM_STRING_TYPE:
03097 if (tag->fmt)
03098 val = tag->fmt(RPM_STRING_TYPE, data, buf, tag->pad, 0);
03099
03100 if (val) {
03101 need = strlen(val);
03102 } else {
03103 need = strlen(data) + tag->pad + 20;
03104 val = xmalloc(need+1);
03105 strcat(buf, "s");
03106
03107 sprintf(val, buf, data);
03108
03109 }
03110 break;
03111
03112 case RPM_CHAR_TYPE:
03113 case RPM_INT8_TYPE:
03114 case RPM_INT16_TYPE:
03115 case RPM_INT32_TYPE:
03116 switch (type) {
03117 case RPM_CHAR_TYPE:
03118 case RPM_INT8_TYPE:
03119 intVal = *(((int_8 *) data) + element);
03120 break;
03121 case RPM_INT16_TYPE:
03122 intVal = *(((uint_16 *) data) + element);
03123 break;
03124 default:
03125 case RPM_INT32_TYPE:
03126 intVal = *(((int_32 *) data) + element);
03127 break;
03128 }
03129
03130 if (tag->fmt)
03131 val = tag->fmt(RPM_INT32_TYPE, &intVal, buf, tag->pad, element);
03132
03133 if (val) {
03134 need = strlen(val);
03135 } else {
03136 need = 10 + tag->pad + 20;
03137 val = xmalloc(need+1);
03138 strcat(buf, "d");
03139
03140 sprintf(val, buf, intVal);
03141
03142 }
03143 break;
03144
03145 case RPM_BIN_TYPE:
03146
03147 if (tag->fmt)
03148 val = tag->fmt(RPM_BIN_TYPE, data, buf, tag->pad, count);
03149
03150 if (val) {
03151 need = strlen(val);
03152 } else {
03153 #ifdef NOTYET
03154 val = memcpy(xmalloc(count), data, count);
03155 #else
03156
03157 static char hex[] = "0123456789abcdef";
03158 const char * s = data;
03159
03160
03161 need = 2*count + tag->pad;
03162 val = t = xmalloc(need+1);
03163 while (count-- > 0) {
03164 unsigned int i;
03165 i = *s++;
03166 *t++ = hex[ (i >> 4) & 0xf ];
03167 *t++ = hex[ (i ) & 0xf ];
03168 }
03169 *t = '\0';
03170
03171 #endif
03172 }
03173 break;
03174
03175 default:
03176 need = sizeof("(unknown type)") - 1;
03177 val = xstrdup("(unknown type)");
03178 break;
03179 }
03180
03181
03182
03183 if (datafree)
03184 data = headerFreeData(data, type);
03185
03186
03187
03188 if (val && need > 0) {
03189 t = hsaReserve(hsa, need);
03190
03191 te = stpcpy(t, val);
03192
03193 hsa->vallen += (te - t);
03194 val = _free(val);
03195 }
03196
03197
03198 return (hsa->val + hsa->vallen);
03199 }
03200
03207
03208 static char * singleSprintf(headerSprintfArgs hsa, sprintfToken token,
03209 int element)
03210
03211 {
03212 char * t, * te;
03213 int i, j;
03214 int numElements;
03215 int_32 type;
03216 int_32 count;
03217 sprintfToken spft;
03218 int condNumFormats;
03219 size_t need;
03220
03221
03222
03223 switch (token->type) {
03224 case PTOK_NONE:
03225 break;
03226
03227 case PTOK_STRING:
03228 need = token->u.string.len;
03229 if (need == 0) break;
03230 t = hsaReserve(hsa, need);
03231
03232 te = stpcpy(t, token->u.string.string);
03233
03234 hsa->vallen += (te - t);
03235 break;
03236
03237 case PTOK_TAG:
03238 t = hsa->val + hsa->vallen;
03239 te = formatValue(hsa, &token->u.tag,
03240 (token->u.tag.justOne ? 0 : element));
03241 if (te == NULL)
03242 return NULL;
03243 break;
03244
03245 case PTOK_COND:
03246 if (token->u.cond.tag.ext || headerIsEntry(hsa->h, token->u.cond.tag.tag)) {
03247 spft = token->u.cond.ifFormat;
03248 condNumFormats = token->u.cond.numIfTokens;
03249 } else {
03250 spft = token->u.cond.elseFormat;
03251 condNumFormats = token->u.cond.numElseTokens;
03252 }
03253
03254 need = condNumFormats * 20;
03255 if (spft == NULL || need == 0) break;
03256
03257 t = hsaReserve(hsa, need);
03258 for (i = 0; i < condNumFormats; i++, spft++) {
03259 te = singleSprintf(hsa, spft, element);
03260 if (te == NULL)
03261 return NULL;
03262 }
03263 break;
03264
03265 case PTOK_ARRAY:
03266 numElements = -1;
03267 spft = token->u.array.format;
03268 for (i = 0; i < token->u.array.numTokens; i++, spft++)
03269 {
03270 if (spft->type != PTOK_TAG ||
03271 spft->u.tag.arrayCount ||
03272 spft->u.tag.justOne) continue;
03273
03274 if (spft->u.tag.ext) {
03275
03276 if (getExtension(hsa, spft->u.tag.ext, &type, NULL, &count,
03277 hsa->ec + spft->u.tag.extNum))
03278 continue;
03279
03280 } else {
03281
03282 if (!headerGetEntry(hsa->h, spft->u.tag.tag, &type, NULL, &count))
03283 continue;
03284
03285 }
03286
03287 if (type == RPM_BIN_TYPE)
03288 count = 1;
03289
03290 if (numElements > 1 && count != numElements)
03291 switch (type) {
03292 default:
03293 hsa->errmsg =
03294 _("array iterator used with different sized arrays");
03295 return NULL;
03296 break;
03297 case RPM_BIN_TYPE:
03298 case RPM_STRING_TYPE:
03299 break;
03300 }
03301 if (count > numElements)
03302 numElements = count;
03303 }
03304
03305 if (numElements == -1) {
03306 need = sizeof("(none)") - 1;
03307 t = hsaReserve(hsa, need);
03308
03309 te = stpcpy(t, "(none)");
03310
03311 hsa->vallen += (te - t);
03312 } else {
03313 int isxml;
03314
03315 need = numElements * token->u.array.numTokens * 10;
03316 if (need == 0) break;
03317
03318 spft = token->u.array.format;
03319 isxml = (spft->type == PTOK_TAG && spft->u.tag.type != NULL &&
03320 !strcmp(spft->u.tag.type, "xml"));
03321
03322 if (isxml) {
03323 const char * tagN = tagName(spft->u.tag.tag);
03324
03325 need = strlen(tagN) + sizeof(" <rpmTag name=\"\">\n") - 1;
03326 t = hsaReserve(hsa, need);
03327
03328 te = stpcpy(t, " <rpmTag name=\"");
03329 te = stpcpy(te, tagN);
03330 te = stpcpy(te, "\">\n");
03331
03332 hsa->vallen += (te - t);
03333 }
03334
03335 t = hsaReserve(hsa, need);
03336 for (j = 0; j < numElements; j++) {
03337 spft = token->u.array.format;
03338 for (i = 0; i < token->u.array.numTokens; i++, spft++) {
03339 te = singleSprintf(hsa, spft, j);
03340 if (te == NULL)
03341 return NULL;
03342 }
03343 }
03344
03345 if (isxml) {
03346 need = sizeof(" </rpmTag>\n") - 1;
03347 t = hsaReserve(hsa, need);
03348
03349 te = stpcpy(t, " </rpmTag>\n");
03350
03351 hsa->vallen += (te - t);
03352 }
03353
03354 }
03355 break;
03356 }
03357
03358 return (hsa->val + hsa->vallen);
03359 }
03360
03366 static rpmec
03367 rpmecNew(const headerSprintfExtension exts)
03368
03369 {
03370 headerSprintfExtension ext;
03371 rpmec ec;
03372 int i = 0;
03373
03374 for (ext = exts; ext != NULL && ext->type != HEADER_EXT_LAST;
03375 ext = (ext->type == HEADER_EXT_MORE ? ext->u.more : ext+1))
03376 {
03377 i++;
03378 }
03379
03380 ec = xcalloc(i, sizeof(*ec));
03381 return ec;
03382 }
03383
03390 static rpmec
03391 rpmecFree(const headerSprintfExtension exts, rpmec ec)
03392
03393 {
03394 headerSprintfExtension ext;
03395 int i = 0;
03396
03397 for (ext = exts; ext != NULL && ext->type != HEADER_EXT_LAST;
03398 ext = (ext->type == HEADER_EXT_MORE ? ext->u.more : ext+1))
03399 {
03400
03401 if (ec[i].freeit) ec[i].data = _free(ec[i].data);
03402
03403 i++;
03404 }
03405
03406 ec = _free(ec);
03407 return NULL;
03408 }
03409
03421 static
03422 char * headerSprintf(Header h, const char * fmt,
03423 const struct headerTagTableEntry_s * tbltags,
03424 const struct headerSprintfExtension_s * extensions,
03425 errmsg_t * errmsg)
03426
03427
03428 {
03429 headerSprintfArgs hsa = memset(alloca(sizeof(*hsa)), 0, sizeof(*hsa));
03430 sprintfToken nextfmt;
03431 sprintfTag tag;
03432 char * t, * te;
03433 int isxml;
03434 int need;
03435
03436 hsa->h = headerLink(h);
03437 hsa->fmt = xstrdup(fmt);
03438
03439 hsa->exts = (headerSprintfExtension) extensions;
03440 hsa->tags = (headerTagTableEntry) tbltags;
03441
03442 hsa->errmsg = NULL;
03443
03444
03445 if (parseFormat(hsa, hsa->fmt, &hsa->format, &hsa->numTokens, NULL, PARSER_BEGIN))
03446 goto exit;
03447
03448
03449 hsa->ec = rpmecNew(hsa->exts);
03450 hsa->val = xstrdup("");
03451
03452 tag =
03453 (hsa->format->type == PTOK_TAG
03454 ? &hsa->format->u.tag :
03455 (hsa->format->type == PTOK_ARRAY
03456 ? &hsa->format->u.array.format->u.tag :
03457 NULL));
03458 isxml = (tag != NULL && tag->tag == -2 && tag->type != NULL && !strcmp(tag->type, "xml"));
03459
03460 if (isxml) {
03461 need = sizeof("<rpmHeader>\n") - 1;
03462 t = hsaReserve(hsa, need);
03463
03464 te = stpcpy(t, "<rpmHeader>\n");
03465
03466 hsa->vallen += (te - t);
03467 }
03468
03469 hsa = hsaInit(hsa);
03470 while ((nextfmt = hsaNext(hsa)) != NULL) {
03471 te = singleSprintf(hsa, nextfmt, 0);
03472 if (te == NULL) {
03473 hsa->val = _free(hsa->val);
03474 break;
03475 }
03476 }
03477 hsa = hsaFini(hsa);
03478
03479 if (isxml) {
03480 need = sizeof("</rpmHeader>\n") - 1;
03481 t = hsaReserve(hsa, need);
03482
03483 te = stpcpy(t, "</rpmHeader>\n");
03484
03485 hsa->vallen += (te - t);
03486 }
03487
03488 if (hsa->val != NULL && hsa->vallen < hsa->alloced)
03489 hsa->val = xrealloc(hsa->val, hsa->vallen+1);
03490
03491 hsa->ec = rpmecFree(hsa->exts, hsa->ec);
03492 hsa->format = freeFormat(hsa->format, hsa->numTokens);
03493
03494 exit:
03495
03496 if (errmsg)
03497 *errmsg = hsa->errmsg;
03498
03499 hsa->h = headerFree(hsa->h);
03500 hsa->fmt = _free(hsa->fmt);
03501 return hsa->val;
03502 }
03503
03512 static char * octalFormat(int_32 type, hPTR_t data,
03513 char * formatPrefix, int padding, int element)
03514
03515 {
03516 char * val;
03517
03518 if (type != RPM_INT32_TYPE) {
03519 val = xstrdup(_("(not a number)"));
03520 } else {
03521 val = xmalloc(20 + padding);
03522
03523 strcat(formatPrefix, "o");
03524
03525
03526 sprintf(val, formatPrefix, *((int_32 *) data));
03527
03528 }
03529
03530 return val;
03531 }
03532
03541 static char * hexFormat(int_32 type, hPTR_t data,
03542 char * formatPrefix, int padding, int element)
03543
03544 {
03545 char * val;
03546
03547 if (type != RPM_INT32_TYPE) {
03548 val = xstrdup(_("(not a number)"));
03549 } else {
03550 val = xmalloc(20 + padding);
03551
03552 strcat(formatPrefix, "x");
03553
03554
03555 sprintf(val, formatPrefix, *((int_32 *) data));
03556
03557 }
03558
03559 return val;
03560 }
03561
03564 static char * realDateFormat(int_32 type, hPTR_t data,
03565 char * formatPrefix, int padding, int element,
03566 const char * strftimeFormat)
03567
03568 {
03569 char * val;
03570
03571 if (type != RPM_INT32_TYPE) {
03572 val = xstrdup(_("(not a number)"));
03573 } else {
03574 struct tm * tstruct;
03575 char buf[50];
03576
03577 val = xmalloc(50 + padding);
03578
03579 strcat(formatPrefix, "s");
03580
03581
03582
03583 { time_t dateint = *((int_32 *) data);
03584 tstruct = localtime(&dateint);
03585 }
03586 buf[0] = '\0';
03587 if (tstruct)
03588 (void) strftime(buf, sizeof(buf) - 1, strftimeFormat, tstruct);
03589
03590 sprintf(val, formatPrefix, buf);
03591
03592 }
03593
03594 return val;
03595 }
03596
03605 static char * dateFormat(int_32 type, hPTR_t data,
03606 char * formatPrefix, int padding, int element)
03607
03608 {
03609 return realDateFormat(type, data, formatPrefix, padding, element,
03610 _("%c"));
03611 }
03612
03621 static char * dayFormat(int_32 type, hPTR_t data,
03622 char * formatPrefix, int padding, int element)
03623
03624 {
03625 return realDateFormat(type, data, formatPrefix, padding, element,
03626 _("%a %b %d %Y"));
03627 }
03628
03637 static char * shescapeFormat(int_32 type, hPTR_t data,
03638 char * formatPrefix, int padding, int element)
03639
03640 {
03641 char * result, * dst, * src, * buf;
03642
03643 if (type == RPM_INT32_TYPE) {
03644 result = xmalloc(padding + 20);
03645
03646 strcat(formatPrefix, "d");
03647
03648
03649 sprintf(result, formatPrefix, *((int_32 *) data));
03650
03651 } else {
03652 buf = alloca(strlen(data) + padding + 2);
03653
03654 strcat(formatPrefix, "s");
03655
03656
03657 sprintf(buf, formatPrefix, data);
03658
03659
03660
03661 result = dst = xmalloc(strlen(buf) * 4 + 3);
03662 *dst++ = '\'';
03663 for (src = buf; *src != '\0'; src++) {
03664 if (*src == '\'') {
03665 *dst++ = '\'';
03666 *dst++ = '\\';
03667 *dst++ = '\'';
03668 *dst++ = '\'';
03669 } else {
03670 *dst++ = *src;
03671 }
03672 }
03673 *dst++ = '\'';
03674 *dst = '\0';
03675
03676
03677 }
03678
03679 return result;
03680 }
03681
03682
03683 const struct headerSprintfExtension_s headerDefaultFormats[] = {
03684 { HEADER_EXT_FORMAT, "octal", { octalFormat } },
03685 { HEADER_EXT_FORMAT, "hex", { hexFormat } },
03686 { HEADER_EXT_FORMAT, "date", { dateFormat } },
03687 { HEADER_EXT_FORMAT, "day", { dayFormat } },
03688 { HEADER_EXT_FORMAT, "shescape", { shescapeFormat } },
03689 { HEADER_EXT_LAST, NULL, { NULL } }
03690 };
03691
03692
03699 static
03700 void headerCopyTags(Header headerFrom, Header headerTo, hTAG_t tagstocopy)
03701
03702 {
03703 int * p;
03704
03705 if (headerFrom == headerTo)
03706 return;
03707
03708 for (p = tagstocopy; *p != 0; p++) {
03709 char *s;
03710 int_32 type;
03711 int_32 count;
03712 if (headerIsEntry(headerTo, *p))
03713 continue;
03714
03715 if (!headerGetEntryMinMemory(headerFrom, *p, &type,
03716 (hPTR_t *) &s, &count))
03717 continue;
03718
03719 (void) headerAddEntry(headerTo, *p, type, s, count);
03720 s = headerFreeData(s, type);
03721 }
03722 }
03723
03724
03725 static struct HV_s hdrVec1 = {
03726 headerLink,
03727 headerUnlink,
03728 headerFree,
03729 headerNew,
03730 headerSort,
03731 headerUnsort,
03732 headerSizeof,
03733 headerUnload,
03734 headerReload,
03735 headerCopy,
03736 headerLoad,
03737 headerCopyLoad,
03738 headerRead,
03739 headerWrite,
03740 headerIsEntry,
03741 headerFreeTag,
03742 headerGetEntry,
03743 headerGetEntryMinMemory,
03744 headerAddEntry,
03745 headerAppendEntry,
03746 headerAddOrAppendEntry,
03747 headerAddI18NString,
03748 headerModifyEntry,
03749 headerRemoveEntry,
03750 headerSprintf,
03751 headerCopyTags,
03752 headerFreeIterator,
03753 headerInitIterator,
03754 headerNextIterator,
03755 NULL, NULL,
03756 1
03757 };
03758
03759
03760
03761 HV_t hdrVec = &hdrVec1;
03762