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 0
01074 if (rdlen != dl)
01075 goto errxit;
01076 #endif
01077 entry->rdlen = rdlen;
01078 entry++;
01079 h->indexUsed++;
01080 } else {
01081 int_32 rdl;
01082 int_32 ril;
01083
01084 h->flags &= ~HEADERFLAG_LEGACY;
01085
01086 entry->info.type = htonl(pe->type);
01087 entry->info.count = htonl(pe->count);
01088
01089 if (hdrchkType(entry->info.type))
01090 goto errxit;
01091 if (hdrchkTags(entry->info.count))
01092 goto errxit;
01093
01094 { int off = ntohl(pe->offset);
01095
01096 if (hdrchkData(off))
01097 goto errxit;
01098 if (off) {
01099
01100 size_t nb = REGION_TAG_COUNT;
01101
01102 int_32 * stei;
01103 if (dataStart + off + nb > dataEnd)
01104 goto errxit;
01105 stei = memcpy(alloca(nb), dataStart + off, nb);
01106 rdl = -ntohl(stei[2]);
01107 ril = rdl/sizeof(*pe);
01108 if (hdrchkTags(ril) || hdrchkData(rdl))
01109 goto errxit;
01110 entry->info.tag = htonl(pe->tag);
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 int rc;
01135
01136
01137 rc = regionSwab(newEntry, ne, 0, pe+ril, dataStart, dataEnd, rid);
01138 if (rc < 0)
01139 goto errxit;
01140 rdlen += rc;
01141
01142 { indexEntry firstEntry = newEntry;
01143 int save = h->indexUsed;
01144 int j;
01145
01146
01147 h->indexUsed -= ne;
01148 for (j = 0; j < ne; j++, newEntry++) {
01149 (void) headerRemoveEntry(h, newEntry->info.tag);
01150 if (newEntry->info.tag == HEADER_BASENAMES)
01151 (void) headerRemoveEntry(h, HEADER_OLDFILENAMES);
01152 }
01153
01154
01155
01156 if (h->indexUsed < (save - ne)) {
01157 memmove(h->index + h->indexUsed, firstEntry,
01158 (ne * sizeof(*entry)));
01159 }
01160
01161 h->indexUsed += ne;
01162 }
01163 }
01164 }
01165
01166 h->flags &= ~HEADERFLAG_SORTED;
01167 headerSort(h);
01168
01169
01170 return h;
01171
01172
01173 errxit:
01174
01175 if (h) {
01176 h->index = _free(h->index);
01177
01178 h = _free(h);
01179
01180 }
01181
01182
01183 return h;
01184
01185 }
01186
01194 static
01195 Header headerReload( Header h, int tag)
01196
01197 {
01198 Header nh;
01199 int length;
01200
01201
01202 void * uh = doHeaderUnload(h, &length);
01203
01204
01205 h = headerFree(h);
01206
01207 if (uh == NULL)
01208 return NULL;
01209 nh = headerLoad(uh);
01210 if (nh == NULL) {
01211 uh = _free(uh);
01212 return NULL;
01213 }
01214 if (nh->flags & HEADERFLAG_ALLOCATED)
01215 uh = _free(uh);
01216 nh->flags |= HEADERFLAG_ALLOCATED;
01217 if (ENTRY_IS_REGION(nh->index)) {
01218
01219 if (tag == HEADER_SIGNATURES || tag == HEADER_IMMUTABLE)
01220 nh->index[0].info.tag = tag;
01221
01222 }
01223 return nh;
01224 }
01225
01231 static
01232 Header headerCopyLoad(const void * uh)
01233
01234 {
01235 int_32 * ei = (int_32 *) uh;
01236
01237 int_32 il = ntohl(ei[0]);
01238 int_32 dl = ntohl(ei[1]);
01239
01240
01241 size_t pvlen = sizeof(il) + sizeof(dl) +
01242 (il * sizeof(struct entryInfo_s)) + dl;
01243
01244 void * nuh = NULL;
01245 Header h = NULL;
01246
01247
01248
01249 if (!(hdrchkTags(il) || hdrchkData(dl)) && pvlen < headerMaxbytes) {
01250
01251 nuh = memcpy(xmalloc(pvlen), uh, pvlen);
01252
01253 if ((h = headerLoad(nuh)) != NULL)
01254 h->flags |= HEADERFLAG_ALLOCATED;
01255 }
01256
01257
01258 if (h == NULL)
01259 nuh = _free(nuh);
01260
01261 return h;
01262 }
01263
01270 static
01271 Header headerRead(FD_t fd, enum hMagic magicp)
01272
01273 {
01274 int_32 block[4];
01275 int_32 reserved;
01276 int_32 * ei = NULL;
01277 int_32 il;
01278 int_32 dl;
01279 int_32 magic;
01280 Header h = NULL;
01281 size_t len;
01282 int i;
01283
01284 memset(block, 0, sizeof(block));
01285 i = 2;
01286 if (magicp == HEADER_MAGIC_YES)
01287 i += 2;
01288
01289
01290 if (timedRead(fd, (char *)block, i*sizeof(*block)) != (i * sizeof(*block)))
01291 goto exit;
01292
01293
01294 i = 0;
01295
01296
01297 if (magicp == HEADER_MAGIC_YES) {
01298 magic = block[i++];
01299 if (memcmp(&magic, header_magic, sizeof(magic)))
01300 goto exit;
01301 reserved = block[i++];
01302 }
01303
01304 il = ntohl(block[i]); i++;
01305 dl = ntohl(block[i]); i++;
01306
01307
01308
01309 len = sizeof(il) + sizeof(dl) + (il * sizeof(struct entryInfo_s)) + dl;
01310
01311
01312
01313 if (hdrchkTags(il) || hdrchkData(dl) || len > headerMaxbytes)
01314 goto exit;
01315
01316
01317 ei = xmalloc(len);
01318 ei[0] = htonl(il);
01319 ei[1] = htonl(dl);
01320 len -= sizeof(il) + sizeof(dl);
01321
01322
01323
01324
01325 if (timedRead(fd, (char *)&ei[2], len) != len)
01326 goto exit;
01327
01328
01329
01330 h = headerLoad(ei);
01331
01332 exit:
01333 if (h) {
01334 if (h->flags & HEADERFLAG_ALLOCATED)
01335 ei = _free(ei);
01336 h->flags |= HEADERFLAG_ALLOCATED;
01337 } else if (ei)
01338 ei = _free(ei);
01339
01340 return h;
01341
01342 }
01343
01351 static
01352 int headerWrite(FD_t fd, Header h, enum hMagic magicp)
01353
01354
01355 {
01356 ssize_t nb;
01357 int length;
01358 const void * uh;
01359
01360 if (h == NULL)
01361 return 1;
01362
01363 uh = doHeaderUnload(h, &length);
01364
01365 if (uh == NULL)
01366 return 1;
01367 switch (magicp) {
01368 case HEADER_MAGIC_YES:
01369
01370
01371 nb = Fwrite(header_magic, sizeof(char), sizeof(header_magic), fd);
01372
01373
01374 if (nb != sizeof(header_magic))
01375 goto exit;
01376 break;
01377 case HEADER_MAGIC_NO:
01378 break;
01379 }
01380
01381
01382 nb = Fwrite(uh, sizeof(char), length, fd);
01383
01384
01385 exit:
01386 uh = _free(uh);
01387 return (nb == length ? 0 : 1);
01388 }
01389
01396 static
01397 int headerIsEntry(Header h, int_32 tag)
01398
01399 {
01400
01401 return (findEntry(h, tag, RPM_NULL_TYPE) ? 1 : 0);
01402
01403 }
01404
01415 static int copyEntry(const indexEntry entry,
01416 hTYP_t type,
01417 hPTR_t * p,
01418 hCNT_t c,
01419 int minMem)
01420
01421
01422 {
01423 int_32 count = entry->info.count;
01424 int rc = 1;
01425
01426 if (p)
01427 switch (entry->info.type) {
01428 case RPM_BIN_TYPE:
01429
01430
01431
01432
01433
01434
01435 if (ENTRY_IS_REGION(entry)) {
01436 int_32 * ei = ((int_32 *)entry->data) - 2;
01437
01438 entryInfo pe = (entryInfo) (ei + 2);
01439
01440
01441 char * dataStart = (char *) (pe + ntohl(ei[0]));
01442
01443 int_32 rdl = -entry->info.offset;
01444 int_32 ril = rdl/sizeof(*pe);
01445
01446
01447 rdl = entry->rdlen;
01448 count = 2 * sizeof(*ei) + (ril * sizeof(*pe)) + rdl;
01449 if (entry->info.tag == HEADER_IMAGE) {
01450 ril -= 1;
01451 pe += 1;
01452 } else {
01453 count += REGION_TAG_COUNT;
01454 rdl += REGION_TAG_COUNT;
01455 }
01456
01457
01458 *p = xmalloc(count);
01459 ei = (int_32 *) *p;
01460 ei[0] = htonl(ril);
01461 ei[1] = htonl(rdl);
01462
01463
01464 pe = (entryInfo) memcpy(ei + 2, pe, (ril * sizeof(*pe)));
01465
01466
01467 dataStart = (char *) memcpy(pe + ril, dataStart, rdl);
01468
01469
01470
01471 rc = regionSwab(NULL, ril, 0, pe, dataStart, NULL, 0);
01472
01473 rc = (rc < 0) ? 0 : 1;
01474 } else {
01475 count = entry->length;
01476 *p = (!minMem
01477 ? memcpy(xmalloc(count), entry->data, count)
01478 : entry->data);
01479 }
01480 break;
01481 case RPM_STRING_TYPE:
01482 if (count == 1) {
01483 *p = entry->data;
01484 break;
01485 }
01486
01487 case RPM_STRING_ARRAY_TYPE:
01488 case RPM_I18NSTRING_TYPE:
01489 { const char ** ptrEntry;
01490
01491 int tableSize = count * sizeof(char *);
01492
01493 char * t;
01494 int i;
01495
01496
01497
01498 if (minMem) {
01499 *p = xmalloc(tableSize);
01500 ptrEntry = (const char **) *p;
01501 t = entry->data;
01502 } else {
01503 t = xmalloc(tableSize + entry->length);
01504 *p = (void *)t;
01505 ptrEntry = (const char **) *p;
01506 t += tableSize;
01507 memcpy(t, entry->data, entry->length);
01508 }
01509
01510
01511 for (i = 0; i < count; i++) {
01512
01513 *ptrEntry++ = t;
01514
01515 t = strchr(t, 0);
01516 t++;
01517 }
01518 } break;
01519
01520 default:
01521 *p = entry->data;
01522 break;
01523 }
01524 if (type) *type = entry->info.type;
01525 if (c) *c = count;
01526 return rc;
01527 }
01528
01547 static int headerMatchLocale(const char *td, const char *l, const char *le)
01548
01549 {
01550 const char *fe;
01551
01552
01553 #if 0
01554 { const char *s, *ll, *CC, *EE, *dd;
01555 char *lbuf, *t.
01556
01557
01558 lbuf = alloca(le - l + 1);
01559 for (s = l, ll = t = lbuf; *s; s++, t++) {
01560 switch (*s) {
01561 case '_':
01562 *t = '\0';
01563 CC = t + 1;
01564 break;
01565 case '.':
01566 *t = '\0';
01567 EE = t + 1;
01568 break;
01569 case '@':
01570 *t = '\0';
01571 dd = t + 1;
01572 break;
01573 default:
01574 *t = *s;
01575 break;
01576 }
01577 }
01578
01579 if (ll)
01580 for (t = ll; *t; t++) *t = tolower(*t);
01581 if (CC)
01582 for (t = CC; *t; t++) *t = toupper(*t);
01583
01584
01585 }
01586 #endif
01587
01588
01589 if (strlen(td) == (le-l) && !strncmp(td, l, (le - l)))
01590 return 1;
01591
01592
01593 for (fe = l; fe < le && *fe != '@'; fe++)
01594 {};
01595 if (fe < le && !strncmp(td, l, (fe - l)))
01596 return 1;
01597
01598
01599 for (fe = l; fe < le && *fe != '.'; fe++)
01600 {};
01601 if (fe < le && !strncmp(td, l, (fe - l)))
01602 return 1;
01603
01604
01605 for (fe = l; fe < le && *fe != '_'; fe++)
01606 {};
01607 if (fe < le && !strncmp(td, l, (fe - l)))
01608 return 1;
01609
01610 return 0;
01611 }
01612
01619 static char *
01620 headerFindI18NString(Header h, indexEntry entry)
01621
01622 {
01623 const char *lang, *l, *le;
01624 indexEntry table;
01625
01626
01627 if ((lang = getenv("LANGUAGE")) == NULL &&
01628 (lang = getenv("LC_ALL")) == NULL &&
01629 (lang = getenv("LC_MESSAGES")) == NULL &&
01630 (lang = getenv("LANG")) == NULL)
01631 return entry->data;
01632
01633
01634 if ((table = findEntry(h, HEADER_I18NTABLE, RPM_STRING_ARRAY_TYPE)) == NULL)
01635 return entry->data;
01636
01637
01638
01639 for (l = lang; *l != '\0'; l = le) {
01640 const char *td;
01641 char *ed;
01642 int langNum;
01643
01644 while (*l && *l == ':')
01645 l++;
01646 if (*l == '\0')
01647 break;
01648 for (le = l; *le && *le != ':'; le++)
01649 {};
01650
01651
01652 for (langNum = 0, td = table->data, ed = entry->data;
01653 langNum < entry->info.count;
01654 langNum++, td += strlen(td) + 1, ed += strlen(ed) + 1) {
01655
01656 if (headerMatchLocale(td, l, le))
01657 return ed;
01658
01659 }
01660 }
01661
01662
01663 return entry->data;
01664 }
01665
01676 static int intGetEntry(Header h, int_32 tag,
01677 hTAG_t type,
01678 hPTR_t * p,
01679 hCNT_t c,
01680 int minMem)
01681
01682
01683 {
01684 indexEntry entry;
01685 int rc;
01686
01687
01688
01689 entry = findEntry(h, tag, RPM_NULL_TYPE);
01690
01691 if (entry == NULL) {
01692 if (type) type = 0;
01693 if (p) *p = NULL;
01694 if (c) *c = 0;
01695 return 0;
01696 }
01697
01698 switch (entry->info.type) {
01699 case RPM_I18NSTRING_TYPE:
01700 rc = 1;
01701 if (type) *type = RPM_STRING_TYPE;
01702 if (c) *c = 1;
01703
01704 if (p) *p = headerFindI18NString(h, entry);
01705
01706 break;
01707 default:
01708 rc = copyEntry(entry, type, p, c, minMem);
01709 break;
01710 }
01711
01712
01713 return ((rc == 1) ? 1 : 0);
01714 }
01715
01723 static void * headerFreeTag( Header h,
01724 const void * data, rpmTagType type)
01725
01726 {
01727 if (data) {
01728
01729 if (type == -1 ||
01730 type == RPM_STRING_ARRAY_TYPE ||
01731 type == RPM_I18NSTRING_TYPE ||
01732 type == RPM_BIN_TYPE)
01733 data = _free(data);
01734
01735 }
01736 return NULL;
01737 }
01738
01752 static
01753 int headerGetEntry(Header h, int_32 tag,
01754 hTYP_t type,
01755 void ** p,
01756 hCNT_t c)
01757
01758
01759 {
01760 return intGetEntry(h, tag, type, (hPTR_t *)p, c, 0);
01761 }
01762
01775 static
01776 int headerGetEntryMinMemory(Header h, int_32 tag,
01777 hTYP_t type,
01778 hPTR_t * p,
01779 hCNT_t c)
01780
01781
01782 {
01783 return intGetEntry(h, tag, type, p, c, 1);
01784 }
01785
01786 int headerGetRawEntry(Header h, int_32 tag, int_32 * type, hPTR_t * p,
01787 int_32 * c)
01788 {
01789 indexEntry entry;
01790 int rc;
01791
01792 if (p == NULL) return headerIsEntry(h, tag);
01793
01794
01795
01796 entry = findEntry(h, tag, RPM_NULL_TYPE);
01797
01798 if (!entry) {
01799 if (p) *p = NULL;
01800 if (c) *c = 0;
01801 return 0;
01802 }
01803
01804 rc = copyEntry(entry, type, p, c, 0);
01805
01806
01807 return ((rc == 1) ? 1 : 0);
01808 }
01809
01812 static void copyData(int_32 type, void * dstPtr, const void * srcPtr,
01813 int_32 cnt, int dataLength)
01814
01815 {
01816 switch (type) {
01817 case RPM_STRING_ARRAY_TYPE:
01818 case RPM_I18NSTRING_TYPE:
01819 { const char ** av = (const char **) srcPtr;
01820 char * t = dstPtr;
01821
01822
01823 while (cnt-- > 0 && dataLength > 0) {
01824 const char * s;
01825 if ((s = *av++) == NULL)
01826 continue;
01827 do {
01828 *t++ = *s++;
01829 } while (s[-1] && --dataLength > 0);
01830 }
01831
01832 } break;
01833
01834 default:
01835
01836 memmove(dstPtr, srcPtr, dataLength);
01837
01838 break;
01839 }
01840 }
01841
01850
01851 static void *
01852 grabData(int_32 type, hPTR_t p, int_32 c, int * lengthPtr)
01853
01854
01855 {
01856 void * data = NULL;
01857 int length;
01858
01859 length = dataLength(type, p, c, 0, NULL);
01860
01861 if (length > 0) {
01862 data = xmalloc(length);
01863 copyData(type, data, p, c, length);
01864 }
01865
01866
01867 if (lengthPtr)
01868 *lengthPtr = length;
01869 return data;
01870 }
01871
01886 static
01887 int headerAddEntry(Header h, int_32 tag, int_32 type, const void * p, int_32 c)
01888
01889 {
01890 indexEntry entry;
01891 void * data;
01892 int length;
01893
01894
01895 if (c <= 0)
01896 return 0;
01897
01898 if (hdrchkType(type))
01899 return 0;
01900 if (hdrchkData(c))
01901 return 0;
01902
01903 length = 0;
01904
01905 data = grabData(type, p, c, &length);
01906
01907 if (data == NULL || length <= 0)
01908 return 0;
01909
01910
01911 if (h->indexUsed == h->indexAlloced) {
01912 h->indexAlloced += INDEX_MALLOC_SIZE;
01913 h->index = xrealloc(h->index, h->indexAlloced * sizeof(*h->index));
01914 }
01915
01916
01917 entry = h->index + h->indexUsed;
01918 entry->info.tag = tag;
01919 entry->info.type = type;
01920 entry->info.count = c;
01921 entry->info.offset = 0;
01922 entry->data = data;
01923 entry->length = length;
01924
01925
01926 if (h->indexUsed > 0 && tag < h->index[h->indexUsed-1].info.tag)
01927 h->flags &= ~HEADERFLAG_SORTED;
01928
01929 h->indexUsed++;
01930
01931 return 1;
01932 }
01933
01948 static
01949 int headerAppendEntry(Header h, int_32 tag, int_32 type,
01950 const void * p, int_32 c)
01951
01952 {
01953 indexEntry entry;
01954 int length;
01955
01956 if (type == RPM_STRING_TYPE || type == RPM_I18NSTRING_TYPE) {
01957
01958 return 0;
01959 }
01960
01961
01962 entry = findEntry(h, tag, type);
01963 if (!entry)
01964 return 0;
01965
01966 length = dataLength(type, p, c, 0, NULL);
01967 if (length < 0)
01968 return 0;
01969
01970 if (ENTRY_IN_REGION(entry)) {
01971 char * t = xmalloc(entry->length + length);
01972
01973 memcpy(t, entry->data, entry->length);
01974
01975 entry->data = t;
01976 entry->info.offset = 0;
01977 } else
01978 entry->data = xrealloc(entry->data, entry->length + length);
01979
01980 copyData(type, ((char *) entry->data) + entry->length, p, c, length);
01981
01982 entry->length += length;
01983
01984 entry->info.count += c;
01985
01986 return 1;
01987 }
01988
01999 static
02000 int headerAddOrAppendEntry(Header h, int_32 tag, int_32 type,
02001 const void * p, int_32 c)
02002
02003 {
02004 return (findEntry(h, tag, type)
02005 ? headerAppendEntry(h, tag, type, p, c)
02006 : headerAddEntry(h, tag, type, p, c));
02007 }
02008
02029 static
02030 int headerAddI18NString(Header h, int_32 tag, const char * string,
02031 const char * lang)
02032
02033 {
02034 indexEntry table, entry;
02035 const char ** strArray;
02036 int length;
02037 int ghosts;
02038 int i, langNum;
02039 char * buf;
02040
02041 table = findEntry(h, HEADER_I18NTABLE, RPM_STRING_ARRAY_TYPE);
02042 entry = findEntry(h, tag, RPM_I18NSTRING_TYPE);
02043
02044 if (!table && entry)
02045 return 0;
02046
02047 if (!table && !entry) {
02048 const char * charArray[2];
02049 int count = 0;
02050 if (!lang || (lang[0] == 'C' && lang[1] == '\0')) {
02051
02052 charArray[count++] = "C";
02053
02054 } else {
02055
02056 charArray[count++] = "C";
02057
02058 charArray[count++] = lang;
02059 }
02060 if (!headerAddEntry(h, HEADER_I18NTABLE, RPM_STRING_ARRAY_TYPE,
02061 &charArray, count))
02062 return 0;
02063 table = findEntry(h, HEADER_I18NTABLE, RPM_STRING_ARRAY_TYPE);
02064 }
02065
02066 if (!table)
02067 return 0;
02068
02069 if (!lang) lang = "C";
02070
02071
02072 { const char * l = table->data;
02073 for (langNum = 0; langNum < table->info.count; langNum++) {
02074 if (!strcmp(l, lang)) break;
02075 l += strlen(l) + 1;
02076 }
02077 }
02078
02079 if (langNum >= table->info.count) {
02080 length = strlen(lang) + 1;
02081 if (ENTRY_IN_REGION(table)) {
02082 char * t = xmalloc(table->length + length);
02083 memcpy(t, table->data, table->length);
02084 table->data = t;
02085 table->info.offset = 0;
02086 } else
02087 table->data = xrealloc(table->data, table->length + length);
02088 memmove(((char *)table->data) + table->length, lang, length);
02089 table->length += length;
02090 table->info.count++;
02091 }
02092
02093 if (!entry) {
02094 strArray = alloca(sizeof(*strArray) * (langNum + 1));
02095 for (i = 0; i < langNum; i++)
02096 strArray[i] = "";
02097 strArray[langNum] = string;
02098 return headerAddEntry(h, tag, RPM_I18NSTRING_TYPE, strArray,
02099 langNum + 1);
02100 } else if (langNum >= entry->info.count) {
02101 ghosts = langNum - entry->info.count;
02102
02103 length = strlen(string) + 1 + ghosts;
02104 if (ENTRY_IN_REGION(entry)) {
02105 char * t = xmalloc(entry->length + length);
02106 memcpy(t, entry->data, entry->length);
02107 entry->data = t;
02108 entry->info.offset = 0;
02109 } else
02110 entry->data = xrealloc(entry->data, entry->length + length);
02111
02112 memset(((char *)entry->data) + entry->length, '\0', ghosts);
02113 memmove(((char *)entry->data) + entry->length + ghosts, string, strlen(string)+1);
02114
02115 entry->length += length;
02116 entry->info.count = langNum + 1;
02117 } else {
02118 char *b, *be, *e, *ee, *t;
02119 size_t bn, sn, en;
02120
02121
02122 b = be = e = ee = entry->data;
02123 for (i = 0; i < table->info.count; i++) {
02124 if (i == langNum)
02125 be = ee;
02126 ee += strlen(ee) + 1;
02127 if (i == langNum)
02128 e = ee;
02129 }
02130
02131
02132 bn = (be-b);
02133 sn = strlen(string) + 1;
02134 en = (ee-e);
02135 length = bn + sn + en;
02136 t = buf = xmalloc(length);
02137
02138
02139 memcpy(t, b, bn);
02140 t += bn;
02141
02142 memcpy(t, string, sn);
02143 t += sn;
02144 memcpy(t, e, en);
02145 t += en;
02146
02147
02148
02149 entry->length -= strlen(be) + 1;
02150 entry->length += sn;
02151
02152 if (ENTRY_IN_REGION(entry)) {
02153 entry->info.offset = 0;
02154 } else
02155 entry->data = _free(entry->data);
02156
02157 entry->data = buf;
02158
02159 }
02160
02161 return 0;
02162 }
02163
02174 static
02175 int headerModifyEntry(Header h, int_32 tag, int_32 type,
02176 const void * p, int_32 c)
02177
02178 {
02179 indexEntry entry;
02180 void * oldData;
02181 void * data;
02182 int length;
02183
02184
02185 entry = findEntry(h, tag, type);
02186 if (!entry)
02187 return 0;
02188
02189 length = 0;
02190 data = grabData(type, p, c, &length);
02191 if (data == NULL || length <= 0)
02192 return 0;
02193
02194
02195 while (entry > h->index && (entry - 1)->info.tag == tag)
02196 entry--;
02197
02198
02199
02200 oldData = entry->data;
02201
02202 entry->info.count = c;
02203 entry->info.type = type;
02204 entry->data = data;
02205 entry->length = length;
02206
02207
02208 if (ENTRY_IN_REGION(entry)) {
02209 entry->info.offset = 0;
02210 } else
02211 oldData = _free(oldData);
02212
02213
02214 return 1;
02215 }
02216
02219 static char escapedChar(const char ch)
02220 {
02221 switch (ch) {
02222 case 'a': return '\a';
02223 case 'b': return '\b';
02224 case 'f': return '\f';
02225 case 'n': return '\n';
02226 case 'r': return '\r';
02227 case 't': return '\t';
02228 case 'v': return '\v';
02229 default: return ch;
02230 }
02231 }
02232
02239 static sprintfToken
02240 freeFormat( sprintfToken format, int num)
02241
02242 {
02243 int i;
02244
02245 if (format == NULL) return NULL;
02246
02247 for (i = 0; i < num; i++) {
02248 switch (format[i].type) {
02249 case PTOK_ARRAY:
02250
02251 format[i].u.array.format =
02252 freeFormat(format[i].u.array.format,
02253 format[i].u.array.numTokens);
02254
02255 break;
02256 case PTOK_COND:
02257
02258 format[i].u.cond.ifFormat =
02259 freeFormat(format[i].u.cond.ifFormat,
02260 format[i].u.cond.numIfTokens);
02261 format[i].u.cond.elseFormat =
02262 freeFormat(format[i].u.cond.elseFormat,
02263 format[i].u.cond.numElseTokens);
02264
02265 break;
02266 case PTOK_NONE:
02267 case PTOK_TAG:
02268 case PTOK_STRING:
02269 default:
02270 break;
02271 }
02272 }
02273 format = _free(format);
02274 return NULL;
02275 }
02276
02280 struct headerIterator_s {
02281
02282 Header h;
02283
02284 int next_index;
02285 };
02286
02292 static
02293 HeaderIterator headerFreeIterator( HeaderIterator hi)
02294
02295 {
02296 if (hi != NULL) {
02297 hi->h = headerFree(hi->h);
02298 hi = _free(hi);
02299 }
02300 return hi;
02301 }
02302
02308 static
02309 HeaderIterator headerInitIterator(Header h)
02310
02311 {
02312 HeaderIterator hi = xmalloc(sizeof(*hi));
02313
02314 headerSort(h);
02315
02316 hi->h = headerLink(h);
02317 hi->next_index = 0;
02318 return hi;
02319 }
02320
02330 static
02331 int headerNextIterator(HeaderIterator hi,
02332 hTAG_t tag,
02333 hTYP_t type,
02334 hPTR_t * p,
02335 hCNT_t c)
02336
02337
02338
02339 {
02340 Header h = hi->h;
02341 int slot = hi->next_index;
02342 indexEntry entry = NULL;
02343 int rc;
02344
02345 for (slot = hi->next_index; slot < h->indexUsed; slot++) {
02346 entry = h->index + slot;
02347 if (!ENTRY_IS_REGION(entry))
02348 break;
02349 }
02350 hi->next_index = slot;
02351 if (entry == NULL || slot >= h->indexUsed)
02352 return 0;
02353
02354
02355 hi->next_index++;
02356
02357
02358 if (tag)
02359 *tag = entry->info.tag;
02360
02361 rc = copyEntry(entry, type, p, c, 0);
02362
02363
02364 return ((rc == 1) ? 1 : 0);
02365 }
02366
02372 static
02373 Header headerCopy(Header h)
02374
02375 {
02376 Header nh = headerNew();
02377 HeaderIterator hi;
02378 int_32 tag, type, count;
02379 hPTR_t ptr;
02380
02381
02382 for (hi = headerInitIterator(h);
02383 headerNextIterator(hi, &tag, &type, &ptr, &count);
02384 ptr = headerFreeData((void *)ptr, type))
02385 {
02386 if (ptr) (void) headerAddEntry(nh, tag, type, ptr, count);
02387 }
02388 hi = headerFreeIterator(hi);
02389
02390
02391 return headerReload(nh, HEADER_IMAGE);
02392 }
02393
02396 typedef struct headerSprintfArgs_s {
02397 Header h;
02398 char * fmt;
02399
02400 headerTagTableEntry tags;
02401
02402 headerSprintfExtension exts;
02403
02404 const char * errmsg;
02405 rpmec ec;
02406 sprintfToken format;
02407
02408 HeaderIterator hi;
02409
02410 char * val;
02411 size_t vallen;
02412 size_t alloced;
02413 int numTokens;
02414 int i;
02415 } * headerSprintfArgs;
02416
02422 static headerSprintfArgs hsaInit( headerSprintfArgs hsa)
02423
02424 {
02425 sprintfTag tag =
02426 (hsa->format->type == PTOK_TAG
02427 ? &hsa->format->u.tag :
02428 (hsa->format->type == PTOK_ARRAY
02429 ? &hsa->format->u.array.format->u.tag :
02430 NULL));
02431
02432 if (hsa != NULL) {
02433 hsa->i = 0;
02434 if (tag != NULL && tag->tag == -2)
02435 hsa->hi = headerInitIterator(hsa->h);
02436 }
02437
02438 return hsa;
02439
02440 }
02441
02447
02448 static sprintfToken hsaNext( headerSprintfArgs hsa)
02449
02450 {
02451 sprintfToken fmt = NULL;
02452 sprintfTag tag =
02453 (hsa->format->type == PTOK_TAG
02454 ? &hsa->format->u.tag :
02455 (hsa->format->type == PTOK_ARRAY
02456 ? &hsa->format->u.array.format->u.tag :
02457 NULL));
02458
02459 if (hsa != NULL && hsa->i >= 0 && hsa->i < hsa->numTokens) {
02460 fmt = hsa->format + hsa->i;
02461 if (hsa->hi == NULL) {
02462 hsa->i++;
02463 } else {
02464 int_32 tagno;
02465 int_32 type;
02466 int_32 count;
02467
02468
02469 if (!headerNextIterator(hsa->hi, &tagno, &type, NULL, &count))
02470 fmt = NULL;
02471 tag->tag = tagno;
02472
02473 }
02474 }
02475
02476
02477 return fmt;
02478
02479 }
02480
02486 static headerSprintfArgs hsaFini( headerSprintfArgs hsa)
02487
02488 {
02489 if (hsa != NULL) {
02490 hsa->hi = headerFreeIterator(hsa->hi);
02491 hsa->i = 0;
02492 }
02493
02494 return hsa;
02495
02496 }
02497
02504
02505 static char * hsaReserve(headerSprintfArgs hsa, size_t need)
02506
02507 {
02508 if ((hsa->vallen + need) >= hsa->alloced) {
02509 if (hsa->alloced <= need)
02510 hsa->alloced += need;
02511 hsa->alloced <<= 1;
02512 hsa->val = xrealloc(hsa->val, hsa->alloced+1);
02513 }
02514 return hsa->val + hsa->vallen;
02515 }
02516
02523 static int findTag(headerSprintfArgs hsa, sprintfToken token, const char * name)
02524
02525 {
02526 headerTagTableEntry tag;
02527 headerSprintfExtension ext;
02528 sprintfTag stag = (token->type == PTOK_COND
02529 ? &token->u.cond.tag : &token->u.tag);
02530
02531 stag->fmt = NULL;
02532 stag->ext = NULL;
02533 stag->extNum = 0;
02534 stag->tag = -1;
02535
02536 if (!strcmp(name, "*")) {
02537 stag->tag = -2;
02538 goto bingo;
02539 }
02540
02541
02542 if (strncmp("RPMTAG_", name, sizeof("RPMTAG_")-1)) {
02543
02544 char * t = alloca(strlen(name) + sizeof("RPMTAG_"));
02545 (void) stpcpy( stpcpy(t, "RPMTAG_"), name);
02546 name = t;
02547
02548 }
02549
02550
02551
02552 for (ext = hsa->exts; ext != NULL && ext->type != HEADER_EXT_LAST;
02553 ext = (ext->type == HEADER_EXT_MORE ? ext->u.more : ext+1))
02554 {
02555 if (ext->name == NULL || ext->type != HEADER_EXT_TAG)
02556 continue;
02557 if (!xstrcasecmp(ext->name, name)) {
02558 stag->ext = ext->u.tagFunction;
02559 stag->extNum = ext - hsa->exts;
02560 goto bingo;
02561 }
02562 }
02563
02564
02565 for (tag = hsa->tags; tag->name != NULL; tag++) {
02566 if (!xstrcasecmp(tag->name, name)) {
02567 stag->tag = tag->val;
02568 goto bingo;
02569 }
02570 }
02571
02572 return 1;
02573
02574 bingo:
02575
02576 if (stag->type != NULL)
02577 for (ext = hsa->exts; ext != NULL && ext->type != HEADER_EXT_LAST;
02578 ext = (ext->type == HEADER_EXT_MORE ? ext->u.more : ext+1))
02579 {
02580 if (ext->name == NULL || ext->type != HEADER_EXT_FORMAT)
02581 continue;
02582 if (!strcmp(ext->name, stag->type)) {
02583 stag->fmt = ext->u.formatFunction;
02584 break;
02585 }
02586 }
02587 return 0;
02588 }
02589
02590
02598 static int parseExpression(headerSprintfArgs hsa, sprintfToken token,
02599 char * str, char ** endPtr)
02600
02601 ;
02602
02612 static int parseFormat(headerSprintfArgs hsa, char * str,
02613 sprintfToken * formatPtr, int * numTokensPtr,
02614 char ** endPtr, int state)
02615
02616
02617
02618 {
02619 char * chptr, * start, * next, * dst;
02620 sprintfToken format;
02621 sprintfToken token;
02622 int numTokens;
02623 int i;
02624 int done = 0;
02625
02626
02627 numTokens = 0;
02628 if (str != NULL)
02629 for (chptr = str; *chptr != '\0'; chptr++)
02630 if (*chptr == '%') numTokens++;
02631 numTokens = numTokens * 2 + 1;
02632
02633 format = xcalloc(numTokens, sizeof(*format));
02634 if (endPtr) *endPtr = NULL;
02635
02636
02637 dst = start = str;
02638 numTokens = 0;
02639 token = NULL;
02640 if (start != NULL)
02641 while (*start != '\0') {
02642 switch (*start) {
02643 case '%':
02644
02645 if (*(start + 1) == '%') {
02646 if (token == NULL || token->type != PTOK_STRING) {
02647 token = format + numTokens++;
02648 token->type = PTOK_STRING;
02649
02650 dst = token->u.string.string = start;
02651
02652 }
02653 start++;
02654
02655 *dst++ = *start++;
02656
02657 break;
02658 }
02659
02660 token = format + numTokens++;
02661
02662 *dst++ = '\0';
02663
02664 start++;
02665
02666 if (*start == '|') {
02667 char * newEnd;
02668
02669 start++;
02670
02671 if (parseExpression(hsa, token, start, &newEnd))
02672 {
02673 format = freeFormat(format, numTokens);
02674 return 1;
02675 }
02676
02677 start = newEnd;
02678 break;
02679 }
02680
02681
02682 token->u.tag.format = start;
02683
02684 token->u.tag.pad = 0;
02685 token->u.tag.justOne = 0;
02686 token->u.tag.arrayCount = 0;
02687
02688 chptr = start;
02689 while (*chptr && *chptr != '{' && *chptr != '%') chptr++;
02690 if (!*chptr || *chptr == '%') {
02691 hsa->errmsg = _("missing { after %");
02692 format = freeFormat(format, numTokens);
02693 return 1;
02694 }
02695
02696
02697 *chptr++ = '\0';
02698
02699
02700 while (start < chptr) {
02701 if (xisdigit(*start)) {
02702 i = strtoul(start, &start, 10);
02703 token->u.tag.pad += i;
02704 } else {
02705 start++;
02706 }
02707 }
02708
02709 if (*start == '=') {
02710 token->u.tag.justOne = 1;
02711 start++;
02712 } else if (*start == '#') {
02713 token->u.tag.justOne = 1;
02714 token->u.tag.arrayCount = 1;
02715 start++;
02716 }
02717
02718 next = start;
02719 while (*next && *next != '}') next++;
02720 if (!*next) {
02721 hsa->errmsg = _("missing } after %{");
02722 format = freeFormat(format, numTokens);
02723 return 1;
02724 }
02725
02726 *next++ = '\0';
02727
02728
02729 chptr = start;
02730 while (*chptr && *chptr != ':') chptr++;
02731
02732 if (*chptr != '\0') {
02733
02734 *chptr++ = '\0';
02735
02736 if (!*chptr) {
02737 hsa->errmsg = _("empty tag format");
02738 format = freeFormat(format, numTokens);
02739 return 1;
02740 }
02741
02742 token->u.tag.type = chptr;
02743
02744 } else {
02745 token->u.tag.type = NULL;
02746 }
02747
02748 if (!*start) {
02749 hsa->errmsg = _("empty tag name");
02750 format = freeFormat(format, numTokens);
02751 return 1;
02752 }
02753
02754 i = 0;
02755 token->type = PTOK_TAG;
02756
02757 if (findTag(hsa, token, start)) {
02758 hsa->errmsg = _("unknown tag");
02759 format = freeFormat(format, numTokens);
02760 return 1;
02761 }
02762
02763 start = next;
02764 break;
02765
02766 case '[':
02767
02768 *dst++ = '\0';
02769 *start++ = '\0';
02770
02771 token = format + numTokens++;
02772
02773
02774 if (parseFormat(hsa, start,
02775 &token->u.array.format,
02776 &token->u.array.numTokens,
02777 &start, PARSER_IN_ARRAY))
02778 {
02779 format = freeFormat(format, numTokens);
02780 return 1;
02781 }
02782
02783
02784 if (!start) {
02785 hsa->errmsg = _("] expected at end of array");
02786 format = freeFormat(format, numTokens);
02787 return 1;
02788 }
02789
02790 dst = start;
02791
02792 token->type = PTOK_ARRAY;
02793
02794 break;
02795
02796 case ']':
02797 if (state != PARSER_IN_ARRAY) {
02798 hsa->errmsg = _("unexpected ]");
02799 format = freeFormat(format, numTokens);
02800 return 1;
02801 }
02802
02803 *start++ = '\0';
02804
02805 if (endPtr) *endPtr = start;
02806 done = 1;
02807 break;
02808
02809 case '}':
02810 if (state != PARSER_IN_EXPR) {
02811 hsa->errmsg = _("unexpected }");
02812 format = freeFormat(format, numTokens);
02813 return 1;
02814 }
02815
02816 *start++ = '\0';
02817
02818 if (endPtr) *endPtr = start;
02819 done = 1;
02820 break;
02821
02822 default:
02823 if (token == NULL || token->type != PTOK_STRING) {
02824 token = format + numTokens++;
02825 token->type = PTOK_STRING;
02826
02827 dst = token->u.string.string = start;
02828
02829 }
02830
02831
02832 if (*start == '\\') {
02833 start++;
02834 *dst++ = escapedChar(*start++);
02835 } else {
02836 *dst++ = *start++;
02837 }
02838
02839 break;
02840 }
02841 if (done)
02842 break;
02843 }
02844
02845
02846
02847 if (dst != NULL)
02848 *dst = '\0';
02849
02850
02851 for (i = 0; i < numTokens; i++) {
02852 token = format + i;
02853 if (token->type == PTOK_STRING)
02854 token->u.string.len = strlen(token->u.string.string);
02855 }
02856
02857 *numTokensPtr = numTokens;
02858 *formatPtr = format;
02859
02860 return 0;
02861 }
02862
02863
02864 static int parseExpression(headerSprintfArgs hsa, sprintfToken token,
02865 char * str, char ** endPtr)
02866 {
02867 char * chptr;
02868 char * end;
02869
02870 hsa->errmsg = NULL;
02871 chptr = str;
02872 while (*chptr && *chptr != '?') chptr++;
02873
02874 if (*chptr != '?') {
02875 hsa->errmsg = _("? expected in expression");
02876 return 1;
02877 }
02878
02879 *chptr++ = '\0';;
02880
02881 if (*chptr != '{') {
02882 hsa->errmsg = _("{ expected after ? in expression");
02883 return 1;
02884 }
02885
02886 chptr++;
02887
02888 if (parseFormat(hsa, chptr, &token->u.cond.ifFormat,
02889 &token->u.cond.numIfTokens, &end, PARSER_IN_EXPR))
02890 return 1;
02891
02892
02893 if (!(end && *end)) {
02894 hsa->errmsg = _("} expected in expression");
02895 token->u.cond.ifFormat =
02896 freeFormat(token->u.cond.ifFormat, token->u.cond.numIfTokens);
02897 return 1;
02898 }
02899
02900 chptr = end;
02901 if (*chptr != ':' && *chptr != '|') {
02902 hsa->errmsg = _(": expected following ? subexpression");
02903 token->u.cond.ifFormat =
02904 freeFormat(token->u.cond.ifFormat, token->u.cond.numIfTokens);
02905 return 1;
02906 }
02907
02908 if (*chptr == '|') {
02909 if (parseFormat(hsa, NULL, &token->u.cond.elseFormat,
02910 &token->u.cond.numElseTokens, &end, PARSER_IN_EXPR))
02911 {
02912 token->u.cond.ifFormat =
02913 freeFormat(token->u.cond.ifFormat, token->u.cond.numIfTokens);
02914 return 1;
02915 }
02916 } else {
02917 chptr++;
02918
02919 if (*chptr != '{') {
02920 hsa->errmsg = _("{ expected after : in expression");
02921 token->u.cond.ifFormat =
02922 freeFormat(token->u.cond.ifFormat, token->u.cond.numIfTokens);
02923 return 1;
02924 }
02925
02926 chptr++;
02927
02928 if (parseFormat(hsa, chptr, &token->u.cond.elseFormat,
02929 &token->u.cond.numElseTokens, &end, PARSER_IN_EXPR))
02930 return 1;
02931
02932
02933 if (!(end && *end)) {
02934 hsa->errmsg = _("} expected in expression");
02935 token->u.cond.ifFormat =
02936 freeFormat(token->u.cond.ifFormat, token->u.cond.numIfTokens);
02937 return 1;
02938 }
02939
02940 chptr = end;
02941 if (*chptr != '|') {
02942 hsa->errmsg = _("| expected at end of expression");
02943 token->u.cond.ifFormat =
02944 freeFormat(token->u.cond.ifFormat, token->u.cond.numIfTokens);
02945 token->u.cond.elseFormat =
02946 freeFormat(token->u.cond.elseFormat, token->u.cond.numElseTokens);
02947 return 1;
02948 }
02949 }
02950
02951 chptr++;
02952
02953 *endPtr = chptr;
02954
02955 token->type = PTOK_COND;
02956
02957 (void) findTag(hsa, token, str);
02958
02959 return 0;
02960 }
02961
02962
02973 static int getExtension(headerSprintfArgs hsa, headerTagTagFunction fn,
02974 hTYP_t typeptr,
02975 hPTR_t * data,
02976 hCNT_t countptr,
02977 rpmec ec)
02978
02979
02980
02981 {
02982 if (!ec->avail) {
02983 if (fn(hsa->h, &ec->type, &ec->data, &ec->count, &ec->freeit))
02984 return 1;
02985 ec->avail = 1;
02986 }
02987
02988 if (typeptr) *typeptr = ec->type;
02989 if (data) *data = ec->data;
02990 if (countptr) *countptr = ec->count;
02991
02992 return 0;
02993 }
02994
03001
03002 static char * formatValue(headerSprintfArgs hsa, sprintfTag tag, int element)
03003
03004 {
03005 char * val = NULL;
03006 size_t need = 0;
03007 char * t, * te;
03008 char buf[20];
03009 int_32 count, type;
03010 hPTR_t data;
03011 unsigned int intVal;
03012 const char ** strarray;
03013 int datafree = 0;
03014 int countBuf;
03015
03016 memset(buf, 0, sizeof(buf));
03017 if (tag->ext) {
03018
03019 if (getExtension(hsa, tag->ext, &type, &data, &count, hsa->ec + tag->extNum))
03020 {
03021 count = 1;
03022 type = RPM_STRING_TYPE;
03023 data = "(none)";
03024 }
03025
03026 } else {
03027
03028 if (!headerGetEntry(hsa->h, tag->tag, &type, (void **)&data, &count)) {
03029 count = 1;
03030 type = RPM_STRING_TYPE;
03031 data = "(none)";
03032 }
03033
03034
03035
03036 switch (type) {
03037 default:
03038 if (element >= count) {
03039
03040 data = headerFreeData(data, type);
03041
03042
03043 hsa->errmsg = _("(index out of range)");
03044 return NULL;
03045 }
03046 break;
03047 case RPM_BIN_TYPE:
03048 case RPM_STRING_TYPE:
03049 break;
03050 }
03051 datafree = 1;
03052 }
03053
03054 if (tag->arrayCount) {
03055
03056 if (datafree)
03057 data = headerFreeData(data, type);
03058
03059
03060 countBuf = count;
03061 data = &countBuf;
03062 count = 1;
03063 type = RPM_INT32_TYPE;
03064 }
03065
03066
03067 (void) stpcpy( stpcpy(buf, "%"), tag->format);
03068
03069
03070
03071 if (data)
03072 switch (type) {
03073 case RPM_STRING_ARRAY_TYPE:
03074 strarray = (const char **)data;
03075
03076 if (tag->fmt)
03077 val = tag->fmt(RPM_STRING_TYPE, strarray[element], buf, tag->pad, element);
03078
03079 if (val) {
03080 need = strlen(val);
03081 } else {
03082 need = strlen(strarray[element]) + tag->pad + 20;
03083 val = xmalloc(need+1);
03084 strcat(buf, "s");
03085
03086 sprintf(val, buf, strarray[element]);
03087
03088 }
03089
03090 break;
03091
03092 case RPM_STRING_TYPE:
03093 if (tag->fmt)
03094 val = tag->fmt(RPM_STRING_TYPE, data, buf, tag->pad, 0);
03095
03096 if (val) {
03097 need = strlen(val);
03098 } else {
03099 need = strlen(data) + tag->pad + 20;
03100 val = xmalloc(need+1);
03101 strcat(buf, "s");
03102
03103 sprintf(val, buf, data);
03104
03105 }
03106 break;
03107
03108 case RPM_CHAR_TYPE:
03109 case RPM_INT8_TYPE:
03110 case RPM_INT16_TYPE:
03111 case RPM_INT32_TYPE:
03112 switch (type) {
03113 case RPM_CHAR_TYPE:
03114 case RPM_INT8_TYPE:
03115 intVal = *(((int_8 *) data) + element);
03116 break;
03117 case RPM_INT16_TYPE:
03118 intVal = *(((uint_16 *) data) + element);
03119 break;
03120 default:
03121 case RPM_INT32_TYPE:
03122 intVal = *(((int_32 *) data) + element);
03123 break;
03124 }
03125
03126 if (tag->fmt)
03127 val = tag->fmt(RPM_INT32_TYPE, &intVal, buf, tag->pad, element);
03128
03129 if (val) {
03130 need = strlen(val);
03131 } else {
03132 need = 10 + tag->pad + 20;
03133 val = xmalloc(need+1);
03134 strcat(buf, "d");
03135
03136 sprintf(val, buf, intVal);
03137
03138 }
03139 break;
03140
03141 case RPM_BIN_TYPE:
03142
03143 if (tag->fmt)
03144 val = tag->fmt(RPM_BIN_TYPE, data, buf, tag->pad, count);
03145
03146 if (val) {
03147 need = strlen(val);
03148 } else {
03149 #ifdef NOTYET
03150 val = memcpy(xmalloc(count), data, count);
03151 #else
03152
03153 static char hex[] = "0123456789abcdef";
03154 const char * s = data;
03155
03156
03157 need = 2*count + tag->pad;
03158 val = t = xmalloc(need+1);
03159 while (count-- > 0) {
03160 unsigned int i;
03161 i = *s++;
03162 *t++ = hex[ (i >> 4) & 0xf ];
03163 *t++ = hex[ (i ) & 0xf ];
03164 }
03165 *t = '\0';
03166
03167 #endif
03168 }
03169 break;
03170
03171 default:
03172 need = sizeof("(unknown type)") - 1;
03173 val = xstrdup("(unknown type)");
03174 break;
03175 }
03176
03177
03178
03179 if (datafree)
03180 data = headerFreeData(data, type);
03181
03182
03183
03184 if (val && need > 0) {
03185 t = hsaReserve(hsa, need);
03186
03187 te = stpcpy(t, val);
03188
03189 hsa->vallen += (te - t);
03190 val = _free(val);
03191 }
03192
03193
03194 return (hsa->val + hsa->vallen);
03195 }
03196
03203
03204 static char * singleSprintf(headerSprintfArgs hsa, sprintfToken token,
03205 int element)
03206
03207 {
03208 char * t, * te;
03209 int i, j;
03210 int numElements;
03211 int_32 type;
03212 int_32 count;
03213 sprintfToken spft;
03214 int condNumFormats;
03215 size_t need;
03216
03217
03218
03219 switch (token->type) {
03220 case PTOK_NONE:
03221 break;
03222
03223 case PTOK_STRING:
03224 need = token->u.string.len;
03225 if (need == 0) break;
03226 t = hsaReserve(hsa, need);
03227
03228 te = stpcpy(t, token->u.string.string);
03229
03230 hsa->vallen += (te - t);
03231 break;
03232
03233 case PTOK_TAG:
03234 t = hsa->val + hsa->vallen;
03235 te = formatValue(hsa, &token->u.tag,
03236 (token->u.tag.justOne ? 0 : element));
03237 if (te == NULL)
03238 return NULL;
03239 break;
03240
03241 case PTOK_COND:
03242 if (token->u.cond.tag.ext || headerIsEntry(hsa->h, token->u.cond.tag.tag)) {
03243 spft = token->u.cond.ifFormat;
03244 condNumFormats = token->u.cond.numIfTokens;
03245 } else {
03246 spft = token->u.cond.elseFormat;
03247 condNumFormats = token->u.cond.numElseTokens;
03248 }
03249
03250 need = condNumFormats * 20;
03251 if (spft == NULL || need == 0) break;
03252
03253 t = hsaReserve(hsa, need);
03254 for (i = 0; i < condNumFormats; i++, spft++) {
03255 te = singleSprintf(hsa, spft, element);
03256 if (te == NULL)
03257 return NULL;
03258 }
03259 break;
03260
03261 case PTOK_ARRAY:
03262 numElements = -1;
03263 spft = token->u.array.format;
03264 for (i = 0; i < token->u.array.numTokens; i++, spft++)
03265 {
03266 if (spft->type != PTOK_TAG ||
03267 spft->u.tag.arrayCount ||
03268 spft->u.tag.justOne) continue;
03269
03270 if (spft->u.tag.ext) {
03271
03272 if (getExtension(hsa, spft->u.tag.ext, &type, NULL, &count,
03273 hsa->ec + spft->u.tag.extNum))
03274 continue;
03275
03276 } else {
03277
03278 if (!headerGetEntry(hsa->h, spft->u.tag.tag, &type, NULL, &count))
03279 continue;
03280
03281 }
03282
03283 if (type == RPM_BIN_TYPE)
03284 count = 1;
03285
03286 if (numElements > 1 && count != numElements)
03287 switch (type) {
03288 default:
03289 hsa->errmsg =
03290 _("array iterator used with different sized arrays");
03291 return NULL;
03292 break;
03293 case RPM_BIN_TYPE:
03294 case RPM_STRING_TYPE:
03295 break;
03296 }
03297 if (count > numElements)
03298 numElements = count;
03299 }
03300
03301 if (numElements == -1) {
03302 need = sizeof("(none)") - 1;
03303 t = hsaReserve(hsa, need);
03304
03305 te = stpcpy(t, "(none)");
03306
03307 hsa->vallen += (te - t);
03308 } else {
03309 int isxml;
03310
03311 need = numElements * token->u.array.numTokens * 10;
03312 if (need == 0) break;
03313
03314 spft = token->u.array.format;
03315 isxml = (spft->type == PTOK_TAG && spft->u.tag.type != NULL &&
03316 !strcmp(spft->u.tag.type, "xml"));
03317
03318 if (isxml) {
03319 const char * tagN = tagName(spft->u.tag.tag);
03320
03321 need = strlen(tagN) + sizeof(" <rpmTag name=\"\">\n") - 1;
03322 t = hsaReserve(hsa, need);
03323
03324 te = stpcpy(t, " <rpmTag name=\"");
03325 te = stpcpy(te, tagN);
03326 te = stpcpy(te, "\">\n");
03327
03328 hsa->vallen += (te - t);
03329 }
03330
03331 t = hsaReserve(hsa, need);
03332 for (j = 0; j < numElements; j++) {
03333 spft = token->u.array.format;
03334 for (i = 0; i < token->u.array.numTokens; i++, spft++) {
03335 te = singleSprintf(hsa, spft, j);
03336 if (te == NULL)
03337 return NULL;
03338 }
03339 }
03340
03341 if (isxml) {
03342 need = sizeof(" </rpmTag>\n") - 1;
03343 t = hsaReserve(hsa, need);
03344
03345 te = stpcpy(t, " </rpmTag>\n");
03346
03347 hsa->vallen += (te - t);
03348 }
03349
03350 }
03351 break;
03352 }
03353
03354 return (hsa->val + hsa->vallen);
03355 }
03356
03362 static rpmec
03363 rpmecNew(const headerSprintfExtension exts)
03364
03365 {
03366 headerSprintfExtension ext;
03367 rpmec ec;
03368 int i = 0;
03369
03370 for (ext = exts; ext != NULL && ext->type != HEADER_EXT_LAST;
03371 ext = (ext->type == HEADER_EXT_MORE ? ext->u.more : ext+1))
03372 {
03373 i++;
03374 }
03375
03376 ec = xcalloc(i, sizeof(*ec));
03377 return ec;
03378 }
03379
03386 static rpmec
03387 rpmecFree(const headerSprintfExtension exts, rpmec ec)
03388
03389 {
03390 headerSprintfExtension ext;
03391 int i = 0;
03392
03393 for (ext = exts; ext != NULL && ext->type != HEADER_EXT_LAST;
03394 ext = (ext->type == HEADER_EXT_MORE ? ext->u.more : ext+1))
03395 {
03396
03397 if (ec[i].freeit) ec[i].data = _free(ec[i].data);
03398
03399 i++;
03400 }
03401
03402 ec = _free(ec);
03403 return NULL;
03404 }
03405
03417 static
03418 char * headerSprintf(Header h, const char * fmt,
03419 const struct headerTagTableEntry_s * tbltags,
03420 const struct headerSprintfExtension_s * extensions,
03421 errmsg_t * errmsg)
03422
03423
03424 {
03425 headerSprintfArgs hsa = memset(alloca(sizeof(*hsa)), 0, sizeof(*hsa));
03426 sprintfToken nextfmt;
03427 sprintfTag tag;
03428 char * t, * te;
03429 int isxml;
03430 int need;
03431
03432 hsa->h = headerLink(h);
03433 hsa->fmt = xstrdup(fmt);
03434
03435 hsa->exts = (headerSprintfExtension) extensions;
03436 hsa->tags = (headerTagTableEntry) tbltags;
03437
03438 hsa->errmsg = NULL;
03439
03440
03441 if (parseFormat(hsa, hsa->fmt, &hsa->format, &hsa->numTokens, NULL, PARSER_BEGIN))
03442 goto exit;
03443
03444
03445 hsa->ec = rpmecNew(hsa->exts);
03446 hsa->val = xstrdup("");
03447
03448 tag =
03449 (hsa->format->type == PTOK_TAG
03450 ? &hsa->format->u.tag :
03451 (hsa->format->type == PTOK_ARRAY
03452 ? &hsa->format->u.array.format->u.tag :
03453 NULL));
03454 isxml = (tag != NULL && tag->tag == -2 && tag->type != NULL && !strcmp(tag->type, "xml"));
03455
03456 if (isxml) {
03457 need = sizeof("<rpmHeader>\n") - 1;
03458 t = hsaReserve(hsa, need);
03459
03460 te = stpcpy(t, "<rpmHeader>\n");
03461
03462 hsa->vallen += (te - t);
03463 }
03464
03465 hsa = hsaInit(hsa);
03466 while ((nextfmt = hsaNext(hsa)) != NULL) {
03467 te = singleSprintf(hsa, nextfmt, 0);
03468 if (te == NULL) {
03469 hsa->val = _free(hsa->val);
03470 break;
03471 }
03472 }
03473 hsa = hsaFini(hsa);
03474
03475 if (isxml) {
03476 need = sizeof("</rpmHeader>\n") - 1;
03477 t = hsaReserve(hsa, need);
03478
03479 te = stpcpy(t, "</rpmHeader>\n");
03480
03481 hsa->vallen += (te - t);
03482 }
03483
03484 if (hsa->val != NULL && hsa->vallen < hsa->alloced)
03485 hsa->val = xrealloc(hsa->val, hsa->vallen+1);
03486
03487 hsa->ec = rpmecFree(hsa->exts, hsa->ec);
03488 hsa->format = freeFormat(hsa->format, hsa->numTokens);
03489
03490 exit:
03491
03492 if (errmsg)
03493 *errmsg = hsa->errmsg;
03494
03495 hsa->h = headerFree(hsa->h);
03496 hsa->fmt = _free(hsa->fmt);
03497 return hsa->val;
03498 }
03499
03508 static char * octalFormat(int_32 type, hPTR_t data,
03509 char * formatPrefix, int padding, int element)
03510
03511 {
03512 char * val;
03513
03514 if (type != RPM_INT32_TYPE) {
03515 val = xstrdup(_("(not a number)"));
03516 } else {
03517 val = xmalloc(20 + padding);
03518
03519 strcat(formatPrefix, "o");
03520
03521
03522 sprintf(val, formatPrefix, *((int_32 *) data));
03523
03524 }
03525
03526 return val;
03527 }
03528
03537 static char * hexFormat(int_32 type, hPTR_t data,
03538 char * formatPrefix, int padding, int element)
03539
03540 {
03541 char * val;
03542
03543 if (type != RPM_INT32_TYPE) {
03544 val = xstrdup(_("(not a number)"));
03545 } else {
03546 val = xmalloc(20 + padding);
03547
03548 strcat(formatPrefix, "x");
03549
03550
03551 sprintf(val, formatPrefix, *((int_32 *) data));
03552
03553 }
03554
03555 return val;
03556 }
03557
03560 static char * realDateFormat(int_32 type, hPTR_t data,
03561 char * formatPrefix, int padding, int element,
03562 const char * strftimeFormat)
03563
03564 {
03565 char * val;
03566
03567 if (type != RPM_INT32_TYPE) {
03568 val = xstrdup(_("(not a number)"));
03569 } else {
03570 struct tm * tstruct;
03571 char buf[50];
03572
03573 val = xmalloc(50 + padding);
03574
03575 strcat(formatPrefix, "s");
03576
03577
03578
03579 { time_t dateint = *((int_32 *) data);
03580 tstruct = localtime(&dateint);
03581 }
03582 buf[0] = '\0';
03583 if (tstruct)
03584 (void) strftime(buf, sizeof(buf) - 1, strftimeFormat, tstruct);
03585
03586 sprintf(val, formatPrefix, buf);
03587
03588 }
03589
03590 return val;
03591 }
03592
03601 static char * dateFormat(int_32 type, hPTR_t data,
03602 char * formatPrefix, int padding, int element)
03603
03604 {
03605 return realDateFormat(type, data, formatPrefix, padding, element,
03606 _("%c"));
03607 }
03608
03617 static char * dayFormat(int_32 type, hPTR_t data,
03618 char * formatPrefix, int padding, int element)
03619
03620 {
03621 return realDateFormat(type, data, formatPrefix, padding, element,
03622 _("%a %b %d %Y"));
03623 }
03624
03633 static char * shescapeFormat(int_32 type, hPTR_t data,
03634 char * formatPrefix, int padding, int element)
03635
03636 {
03637 char * result, * dst, * src, * buf;
03638
03639 if (type == RPM_INT32_TYPE) {
03640 result = xmalloc(padding + 20);
03641
03642 strcat(formatPrefix, "d");
03643
03644
03645 sprintf(result, formatPrefix, *((int_32 *) data));
03646
03647 } else {
03648 buf = alloca(strlen(data) + padding + 2);
03649
03650 strcat(formatPrefix, "s");
03651
03652
03653 sprintf(buf, formatPrefix, data);
03654
03655
03656
03657 result = dst = xmalloc(strlen(buf) * 4 + 3);
03658 *dst++ = '\'';
03659 for (src = buf; *src != '\0'; src++) {
03660 if (*src == '\'') {
03661 *dst++ = '\'';
03662 *dst++ = '\\';
03663 *dst++ = '\'';
03664 *dst++ = '\'';
03665 } else {
03666 *dst++ = *src;
03667 }
03668 }
03669 *dst++ = '\'';
03670 *dst = '\0';
03671
03672
03673 }
03674
03675 return result;
03676 }
03677
03678
03679 const struct headerSprintfExtension_s headerDefaultFormats[] = {
03680 { HEADER_EXT_FORMAT, "octal", { octalFormat } },
03681 { HEADER_EXT_FORMAT, "hex", { hexFormat } },
03682 { HEADER_EXT_FORMAT, "date", { dateFormat } },
03683 { HEADER_EXT_FORMAT, "day", { dayFormat } },
03684 { HEADER_EXT_FORMAT, "shescape", { shescapeFormat } },
03685 { HEADER_EXT_LAST, NULL, { NULL } }
03686 };
03687
03688
03695 static
03696 void headerCopyTags(Header headerFrom, Header headerTo, hTAG_t tagstocopy)
03697
03698 {
03699 int * p;
03700
03701 if (headerFrom == headerTo)
03702 return;
03703
03704 for (p = tagstocopy; *p != 0; p++) {
03705 char *s;
03706 int_32 type;
03707 int_32 count;
03708 if (headerIsEntry(headerTo, *p))
03709 continue;
03710
03711 if (!headerGetEntryMinMemory(headerFrom, *p, &type,
03712 (hPTR_t *) &s, &count))
03713 continue;
03714
03715 (void) headerAddEntry(headerTo, *p, type, s, count);
03716 s = headerFreeData(s, type);
03717 }
03718 }
03719
03720
03721 static struct HV_s hdrVec1 = {
03722 headerLink,
03723 headerUnlink,
03724 headerFree,
03725 headerNew,
03726 headerSort,
03727 headerUnsort,
03728 headerSizeof,
03729 headerUnload,
03730 headerReload,
03731 headerCopy,
03732 headerLoad,
03733 headerCopyLoad,
03734 headerRead,
03735 headerWrite,
03736 headerIsEntry,
03737 headerFreeTag,
03738 headerGetEntry,
03739 headerGetEntryMinMemory,
03740 headerAddEntry,
03741 headerAppendEntry,
03742 headerAddOrAppendEntry,
03743 headerAddI18NString,
03744 headerModifyEntry,
03745 headerRemoveEntry,
03746 headerSprintf,
03747 headerCopyTags,
03748 headerFreeIterator,
03749 headerInitIterator,
03750 headerNextIterator,
03751 NULL, NULL,
03752 1
03753 };
03754
03755
03756
03757 HV_t hdrVec = &hdrVec1;
03758