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, tl = dl;
00493 struct indexEntry_s ieprev;
00494
00495
00496 memset(&ieprev, 0, sizeof(ieprev));
00497
00498 for (; il > 0; il--, pe++) {
00499 struct indexEntry_s ie;
00500 int_32 type;
00501
00502 ie.info.tag = ntohl(pe->tag);
00503 ie.info.type = ntohl(pe->type);
00504 ie.info.count = ntohl(pe->count);
00505 ie.info.offset = ntohl(pe->offset);
00506
00507 if (hdrchkType(ie.info.type))
00508 return -1;
00509 if (hdrchkData(ie.info.count))
00510 return -1;
00511 if (hdrchkData(ie.info.offset))
00512 return -1;
00513
00514 if (hdrchkAlign(ie.info.type, ie.info.offset))
00515 return -1;
00516
00517
00518 ie.data = t = dataStart + ie.info.offset;
00519 if (dataEnd && t >= dataEnd)
00520 return -1;
00521
00522 ie.length = dataLength(ie.info.type, ie.data, ie.info.count, 1, dataEnd);
00523 if (ie.length < 0 || hdrchkData(ie.length))
00524 return -1;
00525
00526 ie.rdlen = 0;
00527
00528 if (entry) {
00529 ie.info.offset = regionid;
00530
00531 *entry = ie;
00532
00533 entry++;
00534 }
00535
00536
00537 type = ie.info.type;
00538
00539 if (typeSizes[type] > 1) {
00540 unsigned diff;
00541 diff = typeSizes[type] - (dl % typeSizes[type]);
00542 if (diff != typeSizes[type]) {
00543 dl += diff;
00544 if (ieprev.info.type == RPM_I18NSTRING_TYPE)
00545 ieprev.length += diff;
00546 }
00547 }
00548
00549 tdel = (tprev ? (t - tprev) : 0);
00550 if (ieprev.info.type == RPM_I18NSTRING_TYPE)
00551 tdel = ieprev.length;
00552
00553 if (ie.info.tag >= HEADER_I18NTABLE) {
00554 tprev = t;
00555 } else {
00556 tprev = dataStart;
00557
00558
00559 if (ie.info.tag == HEADER_IMAGE)
00560 tprev -= REGION_TAG_COUNT;
00561
00562 }
00563
00564
00565 switch (ntohl(pe->type)) {
00566
00567 case RPM_INT32_TYPE:
00568 { int_32 * it = (int_32 *)t;
00569 for (; ie.info.count > 0; ie.info.count--, it += 1) {
00570 if (dataEnd && ((unsigned char *)it) >= dataEnd)
00571 return -1;
00572 *it = htonl(*it);
00573 }
00574 t = (char *) it;
00575 } break;
00576 case RPM_INT16_TYPE:
00577 { int_16 * it = (int_16 *) t;
00578 for (; ie.info.count > 0; ie.info.count--, it += 1) {
00579 if (dataEnd && ((unsigned char *)it) >= dataEnd)
00580 return -1;
00581 *it = htons(*it);
00582 }
00583 t = (char *) it;
00584 } break;
00585
00586 default:
00587 t += ie.length;
00588 break;
00589 }
00590
00591 dl += ie.length;
00592 tl += tdel;
00593 ieprev = ie;
00594
00595 }
00596 tdel = (tprev ? (t - tprev) : 0);
00597 tl += tdel;
00598
00599
00600
00601
00602
00603
00604
00605 if (tl+REGION_TAG_COUNT == dl)
00606 tl += REGION_TAG_COUNT;
00607
00608
00609 return dl;
00610 }
00611
00617 static void * doHeaderUnload(Header h,
00618 int * lengthPtr)
00619
00620
00621
00622 {
00623 int_32 * ei = NULL;
00624 entryInfo pe;
00625 char * dataStart;
00626 char * te;
00627 unsigned pad;
00628 unsigned len;
00629 int_32 il = 0;
00630 int_32 dl = 0;
00631 indexEntry entry;
00632 int_32 type;
00633 int i;
00634 int drlen, ndribbles;
00635 int driplen, ndrips;
00636 int legacy = 0;
00637
00638
00639 headerUnsort(h);
00640
00641
00642 pad = 0;
00643 drlen = ndribbles = driplen = ndrips = 0;
00644 for (i = 0, entry = h->index; i < h->indexUsed; i++, entry++) {
00645 if (ENTRY_IS_REGION(entry)) {
00646 int_32 rdl = -entry->info.offset;
00647 int_32 ril = rdl/sizeof(*pe);
00648 int rid = entry->info.offset;
00649
00650 il += ril;
00651 dl += entry->rdlen + entry->info.count;
00652
00653 if (i == 0 && (h->flags & HEADERFLAG_LEGACY))
00654 il += 1;
00655
00656
00657 for (; i < h->indexUsed && entry->info.offset <= rid+1; i++, entry++) {
00658 if (entry->info.offset <= rid)
00659 continue;
00660
00661
00662 type = entry->info.type;
00663 if (typeSizes[type] > 1) {
00664 unsigned diff;
00665 diff = typeSizes[type] - (dl % typeSizes[type]);
00666 if (diff != typeSizes[type]) {
00667 drlen += diff;
00668 pad += diff;
00669 dl += diff;
00670 }
00671 }
00672
00673 ndribbles++;
00674 il++;
00675 drlen += entry->length;
00676 dl += entry->length;
00677 }
00678 i--;
00679 entry--;
00680 continue;
00681 }
00682
00683
00684 if (entry->data == NULL || entry->length <= 0)
00685 continue;
00686
00687
00688 type = entry->info.type;
00689 if (typeSizes[type] > 1) {
00690 unsigned diff;
00691 diff = typeSizes[type] - (dl % typeSizes[type]);
00692 if (diff != typeSizes[type]) {
00693 driplen += diff;
00694 pad += diff;
00695 dl += diff;
00696 } else
00697 diff = 0;
00698 }
00699
00700 ndrips++;
00701 il++;
00702 driplen += entry->length;
00703 dl += entry->length;
00704 }
00705
00706
00707 if (hdrchkTags(il) || hdrchkData(dl))
00708 goto errxit;
00709
00710 len = sizeof(il) + sizeof(dl) + (il * sizeof(*pe)) + dl;
00711
00712
00713 ei = xmalloc(len);
00714 ei[0] = htonl(il);
00715 ei[1] = htonl(dl);
00716
00717
00718 pe = (entryInfo) &ei[2];
00719 dataStart = te = (char *) (pe + il);
00720
00721 pad = 0;
00722 for (i = 0, entry = h->index; i < h->indexUsed; i++, entry++) {
00723 const char * src;
00724 char *t;
00725 int count;
00726 int rdlen;
00727
00728 if (entry->data == NULL || entry->length <= 0)
00729 continue;
00730
00731 t = te;
00732 pe->tag = htonl(entry->info.tag);
00733 pe->type = htonl(entry->info.type);
00734 pe->count = htonl(entry->info.count);
00735
00736 if (ENTRY_IS_REGION(entry)) {
00737 int_32 rdl = -entry->info.offset;
00738 int_32 ril = rdl/sizeof(*pe) + ndribbles;
00739 int rid = entry->info.offset;
00740
00741 src = (char *)entry->data;
00742 rdlen = entry->rdlen;
00743
00744
00745 if (i == 0 && (h->flags & HEADERFLAG_LEGACY)) {
00746 int_32 stei[4];
00747
00748 legacy = 1;
00749
00750 memcpy(pe+1, src, rdl);
00751 memcpy(te, src + rdl, rdlen);
00752
00753 te += rdlen;
00754
00755 pe->offset = htonl(te - dataStart);
00756 stei[0] = pe->tag;
00757 stei[1] = pe->type;
00758 stei[2] = htonl(-rdl-entry->info.count);
00759 stei[3] = pe->count;
00760
00761 memcpy(te, stei, entry->info.count);
00762
00763 te += entry->info.count;
00764 ril++;
00765 rdlen += entry->info.count;
00766
00767 count = regionSwab(NULL, ril, 0, pe, t, NULL, 0);
00768 if (count != rdlen)
00769 goto errxit;
00770
00771 } else {
00772
00773
00774 memcpy(pe+1, src + sizeof(*pe), ((ril-1) * sizeof(*pe)));
00775 memcpy(te, src + (ril * sizeof(*pe)), rdlen+entry->info.count+drlen);
00776
00777 te += rdlen;
00778 {
00779 entryInfo se = (entryInfo)src;
00780
00781 int off = ntohl(se->offset);
00782 pe->offset = (off) ? htonl(te - dataStart) : htonl(off);
00783 }
00784 te += entry->info.count + drlen;
00785
00786 count = regionSwab(NULL, ril, 0, pe, t, NULL, 0);
00787 if (count != (rdlen + entry->info.count + drlen))
00788 goto errxit;
00789 }
00790
00791
00792 while (i < h->indexUsed && entry->info.offset <= rid+1) {
00793 i++;
00794 entry++;
00795 }
00796 i--;
00797 entry--;
00798 pe += ril;
00799 continue;
00800 }
00801
00802
00803 if (entry->data == NULL || entry->length <= 0)
00804 continue;
00805
00806
00807 type = entry->info.type;
00808 if (typeSizes[type] > 1) {
00809 unsigned diff;
00810 diff = typeSizes[type] - ((te - dataStart) % typeSizes[type]);
00811 if (diff != typeSizes[type]) {
00812
00813 memset(te, 0, diff);
00814
00815 te += diff;
00816 pad += diff;
00817 }
00818 }
00819
00820 pe->offset = htonl(te - dataStart);
00821
00822
00823
00824 switch (entry->info.type) {
00825 case RPM_INT32_TYPE:
00826 count = entry->info.count;
00827 src = entry->data;
00828 while (count--) {
00829 *((int_32 *)te) = htonl(*((int_32 *)src));
00830
00831 te += sizeof(int_32);
00832 src += sizeof(int_32);
00833
00834 }
00835 break;
00836
00837 case RPM_INT16_TYPE:
00838 count = entry->info.count;
00839 src = entry->data;
00840 while (count--) {
00841 *((int_16 *)te) = htons(*((int_16 *)src));
00842
00843 te += sizeof(int_16);
00844 src += sizeof(int_16);
00845
00846 }
00847 break;
00848
00849 default:
00850 memcpy(te, entry->data, entry->length);
00851 te += entry->length;
00852 break;
00853 }
00854
00855 pe++;
00856 }
00857
00858
00859 if (((char *)pe) != dataStart)
00860 goto errxit;
00861 if ((((char *)ei)+len) != te)
00862 goto errxit;
00863
00864 if (lengthPtr)
00865 *lengthPtr = len;
00866
00867 h->flags &= ~HEADERFLAG_SORTED;
00868 headerSort(h);
00869
00870 return (void *) ei;
00871
00872 errxit:
00873
00874 ei = _free(ei);
00875
00876 return (void *) ei;
00877 }
00878
00884 static
00885 void * headerUnload(Header h)
00886
00887 {
00888 int length;
00889
00890 void * uh = doHeaderUnload(h, &length);
00891
00892 return uh;
00893 }
00894
00902 static
00903 indexEntry findEntry( Header h, int_32 tag, int_32 type)
00904
00905 {
00906 indexEntry entry, entry2, last;
00907 struct indexEntry_s key;
00908
00909 if (h == NULL) return NULL;
00910 if (!(h->flags & HEADERFLAG_SORTED)) headerSort(h);
00911
00912 key.info.tag = tag;
00913
00914
00915 entry2 = entry =
00916 bsearch(&key, h->index, h->indexUsed, sizeof(*h->index), indexCmp);
00917
00918 if (entry == NULL)
00919 return NULL;
00920
00921 if (type == RPM_NULL_TYPE)
00922 return entry;
00923
00924
00925 while (entry->info.tag == tag && entry->info.type != type &&
00926 entry > h->index) entry--;
00927
00928 if (entry->info.tag == tag && entry->info.type == type)
00929 return entry;
00930
00931 last = h->index + h->indexUsed;
00932
00933 while (entry2->info.tag == tag && entry2->info.type != type &&
00934 entry2 < last) entry2++;
00935
00936
00937 if (entry->info.tag == tag && entry->info.type == type)
00938 return entry;
00939
00940 return NULL;
00941 }
00942
00952 static
00953 int headerRemoveEntry(Header h, int_32 tag)
00954
00955 {
00956 indexEntry last = h->index + h->indexUsed;
00957 indexEntry entry, first;
00958 int ne;
00959
00960 entry = findEntry(h, tag, RPM_NULL_TYPE);
00961 if (!entry) return 1;
00962
00963
00964 while (entry > h->index && (entry - 1)->info.tag == tag)
00965 entry--;
00966
00967
00968 for (first = entry; first < last; first++) {
00969 void * data;
00970 if (first->info.tag != tag)
00971 break;
00972 data = first->data;
00973 first->data = NULL;
00974 first->length = 0;
00975 if (ENTRY_IN_REGION(first))
00976 continue;
00977 data = _free(data);
00978 }
00979
00980 ne = (first - entry);
00981 if (ne > 0) {
00982 h->indexUsed -= ne;
00983 ne = last - first;
00984
00985 if (ne > 0)
00986 memmove(entry, first, (ne * sizeof(*entry)));
00987
00988 }
00989
00990 return 0;
00991 }
00992
00998 static
00999 Header headerLoad( void * uh)
01000
01001 {
01002 int_32 * ei = (int_32 *) uh;
01003 int_32 il = ntohl(ei[0]);
01004 int_32 dl = ntohl(ei[1]);
01005
01006 size_t pvlen = sizeof(il) + sizeof(dl) +
01007 (il * sizeof(struct entryInfo_s)) + dl;
01008
01009 void * pv = uh;
01010 Header h = NULL;
01011 entryInfo pe;
01012 unsigned char * dataStart;
01013 unsigned char * dataEnd;
01014 indexEntry entry;
01015 int rdlen;
01016 int i;
01017
01018
01019 if (hdrchkTags(il) || hdrchkData(dl))
01020 goto errxit;
01021
01022 ei = (int_32 *) pv;
01023
01024 pe = (entryInfo) &ei[2];
01025
01026 dataStart = (unsigned char *) (pe + il);
01027 dataEnd = dataStart + dl;
01028
01029 h = xcalloc(1, sizeof(*h));
01030
01031 h->hv = *hdrVec;
01032
01033
01034 h->blob = uh;
01035
01036 h->indexAlloced = il + 1;
01037 h->indexUsed = il;
01038 h->index = xcalloc(h->indexAlloced, sizeof(*h->index));
01039 h->flags |= HEADERFLAG_SORTED;
01040 h->nrefs = 0;
01041 h = headerLink(h);
01042
01043
01044
01045
01046
01047 if (ntohl(pe->tag) == 15 &&
01048 ntohl(pe->type) == RPM_STRING_TYPE &&
01049 ntohl(pe->count) == 1)
01050 {
01051 pe->tag = htonl(1079);
01052 }
01053
01054 entry = h->index;
01055 i = 0;
01056 if (!(htonl(pe->tag) < HEADER_I18NTABLE)) {
01057 h->flags |= HEADERFLAG_LEGACY;
01058 entry->info.type = REGION_TAG_TYPE;
01059 entry->info.tag = HEADER_IMAGE;
01060
01061 entry->info.count = REGION_TAG_COUNT;
01062
01063 entry->info.offset = ((unsigned char *)pe - dataStart);
01064
01065
01066 entry->data = pe;
01067
01068 entry->length = pvlen - sizeof(il) - sizeof(dl);
01069 rdlen = regionSwab(entry+1, il, 0, pe, dataStart, dataEnd, entry->info.offset);
01070 #if 0
01071 if (rdlen != dl)
01072 goto errxit;
01073 #endif
01074 entry->rdlen = rdlen;
01075 entry++;
01076 h->indexUsed++;
01077 } else {
01078 int_32 rdl;
01079 int_32 ril;
01080
01081 h->flags &= ~HEADERFLAG_LEGACY;
01082
01083 entry->info.type = htonl(pe->type);
01084 entry->info.count = htonl(pe->count);
01085
01086 if (hdrchkType(entry->info.type))
01087 goto errxit;
01088 if (hdrchkTags(entry->info.count))
01089 goto errxit;
01090
01091 { int off = ntohl(pe->offset);
01092
01093 if (hdrchkData(off))
01094 goto errxit;
01095 if (off) {
01096
01097 size_t nb = REGION_TAG_COUNT;
01098
01099 int_32 * stei = memcpy(alloca(nb), dataStart + off, nb);
01100 rdl = -ntohl(stei[2]);
01101 ril = rdl/sizeof(*pe);
01102 if (hdrchkTags(ril) || hdrchkData(rdl))
01103 goto errxit;
01104 entry->info.tag = htonl(pe->tag);
01105 } else {
01106 ril = il;
01107
01108 rdl = (ril * sizeof(struct entryInfo_s));
01109
01110 entry->info.tag = HEADER_IMAGE;
01111 }
01112 }
01113 entry->info.offset = -rdl;
01114
01115
01116 entry->data = pe;
01117
01118 entry->length = pvlen - sizeof(il) - sizeof(dl);
01119 rdlen = regionSwab(entry+1, ril-1, 0, pe+1, dataStart, dataEnd, entry->info.offset);
01120 if (rdlen < 0)
01121 goto errxit;
01122 entry->rdlen = rdlen;
01123
01124 if (ril < h->indexUsed) {
01125 indexEntry newEntry = entry + ril;
01126 int ne = (h->indexUsed - ril);
01127 int rid = entry->info.offset+1;
01128 int rc;
01129
01130
01131 rc = regionSwab(newEntry, ne, 0, pe+ril, dataStart, dataEnd, rid);
01132 if (rc < 0)
01133 goto errxit;
01134 rdlen += rc;
01135
01136 { indexEntry firstEntry = newEntry;
01137 int save = h->indexUsed;
01138 int j;
01139
01140
01141 h->indexUsed -= ne;
01142 for (j = 0; j < ne; j++, newEntry++) {
01143 (void) headerRemoveEntry(h, newEntry->info.tag);
01144 if (newEntry->info.tag == HEADER_BASENAMES)
01145 (void) headerRemoveEntry(h, HEADER_OLDFILENAMES);
01146 }
01147
01148
01149
01150 if (h->indexUsed < (save - ne)) {
01151 memmove(h->index + h->indexUsed, firstEntry,
01152 (ne * sizeof(*entry)));
01153 }
01154
01155 h->indexUsed += ne;
01156 }
01157 }
01158 }
01159
01160 h->flags &= ~HEADERFLAG_SORTED;
01161 headerSort(h);
01162
01163
01164 return h;
01165
01166
01167 errxit:
01168
01169 if (h) {
01170 h->index = _free(h->index);
01171
01172 h = _free(h);
01173
01174 }
01175
01176
01177 return h;
01178
01179 }
01180
01188 static
01189 Header headerReload( Header h, int tag)
01190
01191 {
01192 Header nh;
01193 int length;
01194
01195
01196 void * uh = doHeaderUnload(h, &length);
01197
01198
01199 h = headerFree(h);
01200
01201 if (uh == NULL)
01202 return NULL;
01203 nh = headerLoad(uh);
01204 if (nh == NULL) {
01205 uh = _free(uh);
01206 return NULL;
01207 }
01208 if (nh->flags & HEADERFLAG_ALLOCATED)
01209 uh = _free(uh);
01210 nh->flags |= HEADERFLAG_ALLOCATED;
01211 if (ENTRY_IS_REGION(nh->index)) {
01212
01213 if (tag == HEADER_SIGNATURES || tag == HEADER_IMMUTABLE)
01214 nh->index[0].info.tag = tag;
01215
01216 }
01217 return nh;
01218 }
01219
01225 static
01226 Header headerCopyLoad(const void * uh)
01227
01228 {
01229 int_32 * ei = (int_32 *) uh;
01230
01231 int_32 il = ntohl(ei[0]);
01232 int_32 dl = ntohl(ei[1]);
01233
01234
01235 size_t pvlen = sizeof(il) + sizeof(dl) +
01236 (il * sizeof(struct entryInfo_s)) + dl;
01237
01238 void * nuh = NULL;
01239 Header h = NULL;
01240
01241
01242
01243 if (!(hdrchkTags(il) || hdrchkData(dl)) && pvlen < headerMaxbytes) {
01244
01245 nuh = memcpy(xmalloc(pvlen), uh, pvlen);
01246
01247 if ((h = headerLoad(nuh)) != NULL)
01248 h->flags |= HEADERFLAG_ALLOCATED;
01249 }
01250
01251
01252 if (h == NULL)
01253 nuh = _free(nuh);
01254
01255 return h;
01256 }
01257
01264 static
01265 Header headerRead(FD_t fd, enum hMagic magicp)
01266
01267 {
01268 int_32 block[4];
01269 int_32 reserved;
01270 int_32 * ei = NULL;
01271 int_32 il;
01272 int_32 dl;
01273 int_32 magic;
01274 Header h = NULL;
01275 size_t len;
01276 int i;
01277
01278 memset(block, 0, sizeof(block));
01279 i = 2;
01280 if (magicp == HEADER_MAGIC_YES)
01281 i += 2;
01282
01283
01284 if (timedRead(fd, (char *)block, i*sizeof(*block)) != (i * sizeof(*block)))
01285 goto exit;
01286
01287
01288 i = 0;
01289
01290
01291 if (magicp == HEADER_MAGIC_YES) {
01292 magic = block[i++];
01293 if (memcmp(&magic, header_magic, sizeof(magic)))
01294 goto exit;
01295 reserved = block[i++];
01296 }
01297
01298 il = ntohl(block[i]); i++;
01299 dl = ntohl(block[i]); i++;
01300
01301
01302
01303 len = sizeof(il) + sizeof(dl) + (il * sizeof(struct entryInfo_s)) + dl;
01304
01305
01306
01307 if (hdrchkTags(il) || hdrchkData(dl) || len > headerMaxbytes)
01308 goto exit;
01309
01310
01311 ei = xmalloc(len);
01312 ei[0] = htonl(il);
01313 ei[1] = htonl(dl);
01314 len -= sizeof(il) + sizeof(dl);
01315
01316
01317
01318
01319 if (timedRead(fd, (char *)&ei[2], len) != len)
01320 goto exit;
01321
01322
01323
01324 h = headerLoad(ei);
01325
01326 exit:
01327 if (h) {
01328 if (h->flags & HEADERFLAG_ALLOCATED)
01329 ei = _free(ei);
01330 h->flags |= HEADERFLAG_ALLOCATED;
01331 } else if (ei)
01332 ei = _free(ei);
01333
01334 return h;
01335
01336 }
01337
01345 static
01346 int headerWrite(FD_t fd, Header h, enum hMagic magicp)
01347
01348
01349 {
01350 ssize_t nb;
01351 int length;
01352 const void * uh;
01353
01354 if (h == NULL)
01355 return 1;
01356
01357 uh = doHeaderUnload(h, &length);
01358
01359 if (uh == NULL)
01360 return 1;
01361 switch (magicp) {
01362 case HEADER_MAGIC_YES:
01363
01364
01365 nb = Fwrite(header_magic, sizeof(char), sizeof(header_magic), fd);
01366
01367
01368 if (nb != sizeof(header_magic))
01369 goto exit;
01370 break;
01371 case HEADER_MAGIC_NO:
01372 break;
01373 }
01374
01375
01376 nb = Fwrite(uh, sizeof(char), length, fd);
01377
01378
01379 exit:
01380 uh = _free(uh);
01381 return (nb == length ? 0 : 1);
01382 }
01383
01390 static
01391 int headerIsEntry(Header h, int_32 tag)
01392
01393 {
01394
01395 return (findEntry(h, tag, RPM_NULL_TYPE) ? 1 : 0);
01396
01397 }
01398
01409 static int copyEntry(const indexEntry entry,
01410 hTYP_t type,
01411 hPTR_t * p,
01412 hCNT_t c,
01413 int minMem)
01414
01415
01416 {
01417 int_32 count = entry->info.count;
01418 int rc = 1;
01419
01420 if (p)
01421 switch (entry->info.type) {
01422 case RPM_BIN_TYPE:
01423
01424
01425
01426
01427
01428
01429 if (ENTRY_IS_REGION(entry)) {
01430 int_32 * ei = ((int_32 *)entry->data) - 2;
01431
01432 entryInfo pe = (entryInfo) (ei + 2);
01433
01434
01435 char * dataStart = (char *) (pe + ntohl(ei[0]));
01436
01437 int_32 rdl = -entry->info.offset;
01438 int_32 ril = rdl/sizeof(*pe);
01439
01440
01441 rdl = entry->rdlen;
01442 count = 2 * sizeof(*ei) + (ril * sizeof(*pe)) + rdl;
01443 if (entry->info.tag == HEADER_IMAGE) {
01444 ril -= 1;
01445 pe += 1;
01446 } else {
01447 count += REGION_TAG_COUNT;
01448 rdl += REGION_TAG_COUNT;
01449 }
01450
01451
01452 *p = xmalloc(count);
01453 ei = (int_32 *) *p;
01454 ei[0] = htonl(ril);
01455 ei[1] = htonl(rdl);
01456
01457
01458 pe = (entryInfo) memcpy(ei + 2, pe, (ril * sizeof(*pe)));
01459
01460
01461 dataStart = (char *) memcpy(pe + ril, dataStart, rdl);
01462
01463
01464
01465 rc = regionSwab(NULL, ril, 0, pe, dataStart, NULL, 0);
01466
01467 rc = (rc < 0) ? 0 : 1;
01468 } else {
01469 count = entry->length;
01470 *p = (!minMem
01471 ? memcpy(xmalloc(count), entry->data, count)
01472 : entry->data);
01473 }
01474 break;
01475 case RPM_STRING_TYPE:
01476 if (count == 1) {
01477 *p = entry->data;
01478 break;
01479 }
01480
01481 case RPM_STRING_ARRAY_TYPE:
01482 case RPM_I18NSTRING_TYPE:
01483 { const char ** ptrEntry;
01484
01485 int tableSize = count * sizeof(char *);
01486
01487 char * t;
01488 int i;
01489
01490
01491
01492 if (minMem) {
01493 *p = xmalloc(tableSize);
01494 ptrEntry = (const char **) *p;
01495 t = entry->data;
01496 } else {
01497 t = xmalloc(tableSize + entry->length);
01498 *p = (void *)t;
01499 ptrEntry = (const char **) *p;
01500 t += tableSize;
01501 memcpy(t, entry->data, entry->length);
01502 }
01503
01504
01505 for (i = 0; i < count; i++) {
01506
01507 *ptrEntry++ = t;
01508
01509 t = strchr(t, 0);
01510 t++;
01511 }
01512 } break;
01513
01514 default:
01515 *p = entry->data;
01516 break;
01517 }
01518 if (type) *type = entry->info.type;
01519 if (c) *c = count;
01520 return rc;
01521 }
01522
01541 static int headerMatchLocale(const char *td, const char *l, const char *le)
01542
01543 {
01544 const char *fe;
01545
01546
01547 #if 0
01548 { const char *s, *ll, *CC, *EE, *dd;
01549 char *lbuf, *t.
01550
01551
01552 lbuf = alloca(le - l + 1);
01553 for (s = l, ll = t = lbuf; *s; s++, t++) {
01554 switch (*s) {
01555 case '_':
01556 *t = '\0';
01557 CC = t + 1;
01558 break;
01559 case '.':
01560 *t = '\0';
01561 EE = t + 1;
01562 break;
01563 case '@':
01564 *t = '\0';
01565 dd = t + 1;
01566 break;
01567 default:
01568 *t = *s;
01569 break;
01570 }
01571 }
01572
01573 if (ll)
01574 for (t = ll; *t; t++) *t = tolower(*t);
01575 if (CC)
01576 for (t = CC; *t; t++) *t = toupper(*t);
01577
01578
01579 }
01580 #endif
01581
01582
01583 if (strlen(td) == (le-l) && !strncmp(td, l, (le - l)))
01584 return 1;
01585
01586
01587 for (fe = l; fe < le && *fe != '@'; fe++)
01588 {};
01589 if (fe < le && !strncmp(td, l, (fe - 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 return 0;
01605 }
01606
01613 static char *
01614 headerFindI18NString(Header h, indexEntry entry)
01615
01616 {
01617 const char *lang, *l, *le;
01618 indexEntry table;
01619
01620
01621 if ((lang = getenv("LANGUAGE")) == NULL &&
01622 (lang = getenv("LC_ALL")) == NULL &&
01623 (lang = getenv("LC_MESSAGES")) == NULL &&
01624 (lang = getenv("LANG")) == NULL)
01625 return entry->data;
01626
01627
01628 if ((table = findEntry(h, HEADER_I18NTABLE, RPM_STRING_ARRAY_TYPE)) == NULL)
01629 return entry->data;
01630
01631
01632
01633 for (l = lang; *l != '\0'; l = le) {
01634 const char *td;
01635 char *ed;
01636 int langNum;
01637
01638 while (*l && *l == ':')
01639 l++;
01640 if (*l == '\0')
01641 break;
01642 for (le = l; *le && *le != ':'; le++)
01643 {};
01644
01645
01646 for (langNum = 0, td = table->data, ed = entry->data;
01647 langNum < entry->info.count;
01648 langNum++, td += strlen(td) + 1, ed += strlen(ed) + 1) {
01649
01650 if (headerMatchLocale(td, l, le))
01651 return ed;
01652
01653 }
01654 }
01655
01656
01657 return entry->data;
01658 }
01659
01670 static int intGetEntry(Header h, int_32 tag,
01671 hTAG_t type,
01672 hPTR_t * p,
01673 hCNT_t c,
01674 int minMem)
01675
01676
01677 {
01678 indexEntry entry;
01679 int rc;
01680
01681
01682
01683 entry = findEntry(h, tag, RPM_NULL_TYPE);
01684
01685 if (entry == NULL) {
01686 if (type) type = 0;
01687 if (p) *p = NULL;
01688 if (c) *c = 0;
01689 return 0;
01690 }
01691
01692 switch (entry->info.type) {
01693 case RPM_I18NSTRING_TYPE:
01694 rc = 1;
01695 if (type) *type = RPM_STRING_TYPE;
01696 if (c) *c = 1;
01697
01698 if (p) *p = headerFindI18NString(h, entry);
01699
01700 break;
01701 default:
01702 rc = copyEntry(entry, type, p, c, minMem);
01703 break;
01704 }
01705
01706
01707 return ((rc == 1) ? 1 : 0);
01708 }
01709
01717 static void * headerFreeTag( Header h,
01718 const void * data, rpmTagType type)
01719
01720 {
01721 if (data) {
01722
01723 if (type == -1 ||
01724 type == RPM_STRING_ARRAY_TYPE ||
01725 type == RPM_I18NSTRING_TYPE ||
01726 type == RPM_BIN_TYPE)
01727 data = _free(data);
01728
01729 }
01730 return NULL;
01731 }
01732
01746 static
01747 int headerGetEntry(Header h, int_32 tag,
01748 hTYP_t type,
01749 void ** p,
01750 hCNT_t c)
01751
01752
01753 {
01754 return intGetEntry(h, tag, type, (hPTR_t *)p, c, 0);
01755 }
01756
01769 static
01770 int headerGetEntryMinMemory(Header h, int_32 tag,
01771 hTYP_t type,
01772 hPTR_t * p,
01773 hCNT_t c)
01774
01775
01776 {
01777 return intGetEntry(h, tag, type, p, c, 1);
01778 }
01779
01780 int headerGetRawEntry(Header h, int_32 tag, int_32 * type, hPTR_t * p,
01781 int_32 * c)
01782 {
01783 indexEntry entry;
01784 int rc;
01785
01786 if (p == NULL) return headerIsEntry(h, tag);
01787
01788
01789
01790 entry = findEntry(h, tag, RPM_NULL_TYPE);
01791
01792 if (!entry) {
01793 if (p) *p = NULL;
01794 if (c) *c = 0;
01795 return 0;
01796 }
01797
01798 rc = copyEntry(entry, type, p, c, 0);
01799
01800
01801 return ((rc == 1) ? 1 : 0);
01802 }
01803
01806 static void copyData(int_32 type, void * dstPtr, const void * srcPtr,
01807 int_32 cnt, int dataLength)
01808
01809 {
01810 switch (type) {
01811 case RPM_STRING_ARRAY_TYPE:
01812 case RPM_I18NSTRING_TYPE:
01813 { const char ** av = (const char **) srcPtr;
01814 char * t = dstPtr;
01815
01816
01817 while (cnt-- > 0 && dataLength > 0) {
01818 const char * s;
01819 if ((s = *av++) == NULL)
01820 continue;
01821 do {
01822 *t++ = *s++;
01823 } while (s[-1] && --dataLength > 0);
01824 }
01825
01826 } break;
01827
01828 default:
01829
01830 memmove(dstPtr, srcPtr, dataLength);
01831
01832 break;
01833 }
01834 }
01835
01844
01845 static void *
01846 grabData(int_32 type, hPTR_t p, int_32 c, int * lengthPtr)
01847
01848
01849 {
01850 void * data = NULL;
01851 int length;
01852
01853 length = dataLength(type, p, c, 0, NULL);
01854
01855 if (length > 0) {
01856 data = xmalloc(length);
01857 copyData(type, data, p, c, length);
01858 }
01859
01860
01861 if (lengthPtr)
01862 *lengthPtr = length;
01863 return data;
01864 }
01865
01880 static
01881 int headerAddEntry(Header h, int_32 tag, int_32 type, const void * p, int_32 c)
01882
01883 {
01884 indexEntry entry;
01885 void * data;
01886 int length;
01887
01888
01889 if (c <= 0)
01890 return 0;
01891
01892 if (hdrchkType(type))
01893 return 0;
01894 if (hdrchkData(c))
01895 return 0;
01896
01897 length = 0;
01898
01899 data = grabData(type, p, c, &length);
01900
01901 if (data == NULL || length <= 0)
01902 return 0;
01903
01904
01905 if (h->indexUsed == h->indexAlloced) {
01906 h->indexAlloced += INDEX_MALLOC_SIZE;
01907 h->index = xrealloc(h->index, h->indexAlloced * sizeof(*h->index));
01908 }
01909
01910
01911 entry = h->index + h->indexUsed;
01912 entry->info.tag = tag;
01913 entry->info.type = type;
01914 entry->info.count = c;
01915 entry->info.offset = 0;
01916 entry->data = data;
01917 entry->length = length;
01918
01919
01920 if (h->indexUsed > 0 && tag < h->index[h->indexUsed-1].info.tag)
01921 h->flags &= ~HEADERFLAG_SORTED;
01922
01923 h->indexUsed++;
01924
01925 return 1;
01926 }
01927
01942 static
01943 int headerAppendEntry(Header h, int_32 tag, int_32 type,
01944 const void * p, int_32 c)
01945
01946 {
01947 indexEntry entry;
01948 int length;
01949
01950 if (type == RPM_STRING_TYPE || type == RPM_I18NSTRING_TYPE) {
01951
01952 return 0;
01953 }
01954
01955
01956 entry = findEntry(h, tag, type);
01957 if (!entry)
01958 return 0;
01959
01960 length = dataLength(type, p, c, 0, NULL);
01961 if (length < 0)
01962 return 0;
01963
01964 if (ENTRY_IN_REGION(entry)) {
01965 char * t = xmalloc(entry->length + length);
01966
01967 memcpy(t, entry->data, entry->length);
01968
01969 entry->data = t;
01970 entry->info.offset = 0;
01971 } else
01972 entry->data = xrealloc(entry->data, entry->length + length);
01973
01974 copyData(type, ((char *) entry->data) + entry->length, p, c, length);
01975
01976 entry->length += length;
01977
01978 entry->info.count += c;
01979
01980 return 1;
01981 }
01982
01993 static
01994 int headerAddOrAppendEntry(Header h, int_32 tag, int_32 type,
01995 const void * p, int_32 c)
01996
01997 {
01998 return (findEntry(h, tag, type)
01999 ? headerAppendEntry(h, tag, type, p, c)
02000 : headerAddEntry(h, tag, type, p, c));
02001 }
02002
02023 static
02024 int headerAddI18NString(Header h, int_32 tag, const char * string,
02025 const char * lang)
02026
02027 {
02028 indexEntry table, entry;
02029 const char ** strArray;
02030 int length;
02031 int ghosts;
02032 int i, langNum;
02033 char * buf;
02034
02035 table = findEntry(h, HEADER_I18NTABLE, RPM_STRING_ARRAY_TYPE);
02036 entry = findEntry(h, tag, RPM_I18NSTRING_TYPE);
02037
02038 if (!table && entry)
02039 return 0;
02040
02041 if (!table && !entry) {
02042 const char * charArray[2];
02043 int count = 0;
02044 if (!lang || (lang[0] == 'C' && lang[1] == '\0')) {
02045
02046 charArray[count++] = "C";
02047
02048 } else {
02049
02050 charArray[count++] = "C";
02051
02052 charArray[count++] = lang;
02053 }
02054 if (!headerAddEntry(h, HEADER_I18NTABLE, RPM_STRING_ARRAY_TYPE,
02055 &charArray, count))
02056 return 0;
02057 table = findEntry(h, HEADER_I18NTABLE, RPM_STRING_ARRAY_TYPE);
02058 }
02059
02060 if (!table)
02061 return 0;
02062
02063 if (!lang) lang = "C";
02064
02065
02066 { const char * l = table->data;
02067 for (langNum = 0; langNum < table->info.count; langNum++) {
02068 if (!strcmp(l, lang)) break;
02069 l += strlen(l) + 1;
02070 }
02071 }
02072
02073 if (langNum >= table->info.count) {
02074 length = strlen(lang) + 1;
02075 if (ENTRY_IN_REGION(table)) {
02076 char * t = xmalloc(table->length + length);
02077 memcpy(t, table->data, table->length);
02078 table->data = t;
02079 table->info.offset = 0;
02080 } else
02081 table->data = xrealloc(table->data, table->length + length);
02082 memmove(((char *)table->data) + table->length, lang, length);
02083 table->length += length;
02084 table->info.count++;
02085 }
02086
02087 if (!entry) {
02088 strArray = alloca(sizeof(*strArray) * (langNum + 1));
02089 for (i = 0; i < langNum; i++)
02090 strArray[i] = "";
02091 strArray[langNum] = string;
02092 return headerAddEntry(h, tag, RPM_I18NSTRING_TYPE, strArray,
02093 langNum + 1);
02094 } else if (langNum >= entry->info.count) {
02095 ghosts = langNum - entry->info.count;
02096
02097 length = strlen(string) + 1 + ghosts;
02098 if (ENTRY_IN_REGION(entry)) {
02099 char * t = xmalloc(entry->length + length);
02100 memcpy(t, entry->data, entry->length);
02101 entry->data = t;
02102 entry->info.offset = 0;
02103 } else
02104 entry->data = xrealloc(entry->data, entry->length + length);
02105
02106 memset(((char *)entry->data) + entry->length, '\0', ghosts);
02107 memmove(((char *)entry->data) + entry->length + ghosts, string, strlen(string)+1);
02108
02109 entry->length += length;
02110 entry->info.count = langNum + 1;
02111 } else {
02112 char *b, *be, *e, *ee, *t;
02113 size_t bn, sn, en;
02114
02115
02116 b = be = e = ee = entry->data;
02117 for (i = 0; i < table->info.count; i++) {
02118 if (i == langNum)
02119 be = ee;
02120 ee += strlen(ee) + 1;
02121 if (i == langNum)
02122 e = ee;
02123 }
02124
02125
02126 bn = (be-b);
02127 sn = strlen(string) + 1;
02128 en = (ee-e);
02129 length = bn + sn + en;
02130 t = buf = xmalloc(length);
02131
02132
02133 memcpy(t, b, bn);
02134 t += bn;
02135
02136 memcpy(t, string, sn);
02137 t += sn;
02138 memcpy(t, e, en);
02139 t += en;
02140
02141
02142
02143 entry->length -= strlen(be) + 1;
02144 entry->length += sn;
02145
02146 if (ENTRY_IN_REGION(entry)) {
02147 entry->info.offset = 0;
02148 } else
02149 entry->data = _free(entry->data);
02150
02151 entry->data = buf;
02152
02153 }
02154
02155 return 0;
02156 }
02157
02168 static
02169 int headerModifyEntry(Header h, int_32 tag, int_32 type,
02170 const void * p, int_32 c)
02171
02172 {
02173 indexEntry entry;
02174 void * oldData;
02175 void * data;
02176 int length;
02177
02178
02179 entry = findEntry(h, tag, type);
02180 if (!entry)
02181 return 0;
02182
02183 length = 0;
02184 data = grabData(type, p, c, &length);
02185 if (data == NULL || length <= 0)
02186 return 0;
02187
02188
02189 while (entry > h->index && (entry - 1)->info.tag == tag)
02190 entry--;
02191
02192
02193
02194 oldData = entry->data;
02195
02196 entry->info.count = c;
02197 entry->info.type = type;
02198 entry->data = data;
02199 entry->length = length;
02200
02201
02202 if (ENTRY_IN_REGION(entry)) {
02203 entry->info.offset = 0;
02204 } else
02205 oldData = _free(oldData);
02206
02207
02208 return 1;
02209 }
02210
02213 static char escapedChar(const char ch)
02214 {
02215 switch (ch) {
02216 case 'a': return '\a';
02217 case 'b': return '\b';
02218 case 'f': return '\f';
02219 case 'n': return '\n';
02220 case 'r': return '\r';
02221 case 't': return '\t';
02222 case 'v': return '\v';
02223 default: return ch;
02224 }
02225 }
02226
02233 static sprintfToken
02234 freeFormat( sprintfToken format, int num)
02235
02236 {
02237 int i;
02238
02239 if (format == NULL) return NULL;
02240
02241 for (i = 0; i < num; i++) {
02242 switch (format[i].type) {
02243 case PTOK_ARRAY:
02244
02245 format[i].u.array.format =
02246 freeFormat(format[i].u.array.format,
02247 format[i].u.array.numTokens);
02248
02249 break;
02250 case PTOK_COND:
02251
02252 format[i].u.cond.ifFormat =
02253 freeFormat(format[i].u.cond.ifFormat,
02254 format[i].u.cond.numIfTokens);
02255 format[i].u.cond.elseFormat =
02256 freeFormat(format[i].u.cond.elseFormat,
02257 format[i].u.cond.numElseTokens);
02258
02259 break;
02260 case PTOK_NONE:
02261 case PTOK_TAG:
02262 case PTOK_STRING:
02263 default:
02264 break;
02265 }
02266 }
02267 format = _free(format);
02268 return NULL;
02269 }
02270
02274 struct headerIterator_s {
02275
02276 Header h;
02277
02278 int next_index;
02279 };
02280
02286 static
02287 HeaderIterator headerFreeIterator( HeaderIterator hi)
02288
02289 {
02290 if (hi != NULL) {
02291 hi->h = headerFree(hi->h);
02292 hi = _free(hi);
02293 }
02294 return hi;
02295 }
02296
02302 static
02303 HeaderIterator headerInitIterator(Header h)
02304
02305 {
02306 HeaderIterator hi = xmalloc(sizeof(*hi));
02307
02308 headerSort(h);
02309
02310 hi->h = headerLink(h);
02311 hi->next_index = 0;
02312 return hi;
02313 }
02314
02324 static
02325 int headerNextIterator(HeaderIterator hi,
02326 hTAG_t tag,
02327 hTYP_t type,
02328 hPTR_t * p,
02329 hCNT_t c)
02330
02331
02332
02333 {
02334 Header h = hi->h;
02335 int slot = hi->next_index;
02336 indexEntry entry = NULL;
02337 int rc;
02338
02339 for (slot = hi->next_index; slot < h->indexUsed; slot++) {
02340 entry = h->index + slot;
02341 if (!ENTRY_IS_REGION(entry))
02342 break;
02343 }
02344 hi->next_index = slot;
02345 if (entry == NULL || slot >= h->indexUsed)
02346 return 0;
02347
02348
02349 hi->next_index++;
02350
02351
02352 if (tag)
02353 *tag = entry->info.tag;
02354
02355 rc = copyEntry(entry, type, p, c, 0);
02356
02357
02358 return ((rc == 1) ? 1 : 0);
02359 }
02360
02366 static
02367 Header headerCopy(Header h)
02368
02369 {
02370 Header nh = headerNew();
02371 HeaderIterator hi;
02372 int_32 tag, type, count;
02373 hPTR_t ptr;
02374
02375
02376 for (hi = headerInitIterator(h);
02377 headerNextIterator(hi, &tag, &type, &ptr, &count);
02378 ptr = headerFreeData((void *)ptr, type))
02379 {
02380 if (ptr) (void) headerAddEntry(nh, tag, type, ptr, count);
02381 }
02382 hi = headerFreeIterator(hi);
02383
02384
02385 return headerReload(nh, HEADER_IMAGE);
02386 }
02387
02390 typedef struct headerSprintfArgs_s {
02391 Header h;
02392 char * fmt;
02393
02394 headerTagTableEntry tags;
02395
02396 headerSprintfExtension exts;
02397
02398 const char * errmsg;
02399 rpmec ec;
02400 sprintfToken format;
02401
02402 HeaderIterator hi;
02403
02404 char * val;
02405 size_t vallen;
02406 size_t alloced;
02407 int numTokens;
02408 int i;
02409 } * headerSprintfArgs;
02410
02416 static headerSprintfArgs hsaInit( headerSprintfArgs hsa)
02417
02418 {
02419 sprintfTag tag =
02420 (hsa->format->type == PTOK_TAG
02421 ? &hsa->format->u.tag :
02422 (hsa->format->type == PTOK_ARRAY
02423 ? &hsa->format->u.array.format->u.tag :
02424 NULL));
02425
02426 if (hsa != NULL) {
02427 hsa->i = 0;
02428 if (tag != NULL && tag->tag == -2)
02429 hsa->hi = headerInitIterator(hsa->h);
02430 }
02431
02432 return hsa;
02433
02434 }
02435
02441
02442 static sprintfToken hsaNext( headerSprintfArgs hsa)
02443
02444 {
02445 sprintfToken fmt = NULL;
02446 sprintfTag tag =
02447 (hsa->format->type == PTOK_TAG
02448 ? &hsa->format->u.tag :
02449 (hsa->format->type == PTOK_ARRAY
02450 ? &hsa->format->u.array.format->u.tag :
02451 NULL));
02452
02453 if (hsa != NULL && hsa->i >= 0 && hsa->i < hsa->numTokens) {
02454 fmt = hsa->format + hsa->i;
02455 if (hsa->hi == NULL) {
02456 hsa->i++;
02457 } else {
02458 int_32 tagno;
02459 int_32 type;
02460 int_32 count;
02461
02462
02463 if (!headerNextIterator(hsa->hi, &tagno, &type, NULL, &count))
02464 fmt = NULL;
02465 tag->tag = tagno;
02466
02467 }
02468 }
02469
02470
02471 return fmt;
02472
02473 }
02474
02480 static headerSprintfArgs hsaFini( headerSprintfArgs hsa)
02481
02482 {
02483 if (hsa != NULL) {
02484 hsa->hi = headerFreeIterator(hsa->hi);
02485 hsa->i = 0;
02486 }
02487
02488 return hsa;
02489
02490 }
02491
02498
02499 static char * hsaReserve(headerSprintfArgs hsa, size_t need)
02500
02501 {
02502 if ((hsa->vallen + need) >= hsa->alloced) {
02503 if (hsa->alloced <= need)
02504 hsa->alloced += need;
02505 hsa->alloced <<= 1;
02506 hsa->val = xrealloc(hsa->val, hsa->alloced+1);
02507 }
02508 return hsa->val + hsa->vallen;
02509 }
02510
02517 static int findTag(headerSprintfArgs hsa, sprintfToken token, const char * name)
02518
02519 {
02520 headerTagTableEntry tag;
02521 headerSprintfExtension ext;
02522 sprintfTag stag = (token->type == PTOK_COND
02523 ? &token->u.cond.tag : &token->u.tag);
02524
02525 stag->fmt = NULL;
02526 stag->ext = NULL;
02527 stag->extNum = 0;
02528 stag->tag = -1;
02529
02530 if (!strcmp(name, "*")) {
02531 stag->tag = -2;
02532 goto bingo;
02533 }
02534
02535
02536 if (strncmp("RPMTAG_", name, sizeof("RPMTAG_")-1)) {
02537
02538 char * t = alloca(strlen(name) + sizeof("RPMTAG_"));
02539 (void) stpcpy( stpcpy(t, "RPMTAG_"), name);
02540 name = t;
02541
02542 }
02543
02544
02545
02546 for (ext = hsa->exts; ext != NULL && ext->type != HEADER_EXT_LAST;
02547 ext = (ext->type == HEADER_EXT_MORE ? ext->u.more : ext+1))
02548 {
02549 if (ext->name == NULL || ext->type != HEADER_EXT_TAG)
02550 continue;
02551 if (!xstrcasecmp(ext->name, name)) {
02552 stag->ext = ext->u.tagFunction;
02553 stag->extNum = ext - hsa->exts;
02554 goto bingo;
02555 }
02556 }
02557
02558
02559 for (tag = hsa->tags; tag->name != NULL; tag++) {
02560 if (!xstrcasecmp(tag->name, name)) {
02561 stag->tag = tag->val;
02562 goto bingo;
02563 }
02564 }
02565
02566 return 1;
02567
02568 bingo:
02569
02570 if (stag->type != NULL)
02571 for (ext = hsa->exts; ext != NULL && ext->type != HEADER_EXT_LAST;
02572 ext = (ext->type == HEADER_EXT_MORE ? ext->u.more : ext+1))
02573 {
02574 if (ext->name == NULL || ext->type != HEADER_EXT_FORMAT)
02575 continue;
02576 if (!strcmp(ext->name, stag->type)) {
02577 stag->fmt = ext->u.formatFunction;
02578 break;
02579 }
02580 }
02581 return 0;
02582 }
02583
02584
02592 static int parseExpression(headerSprintfArgs hsa, sprintfToken token,
02593 char * str, char ** endPtr)
02594
02595 ;
02596
02606 static int parseFormat(headerSprintfArgs hsa, char * str,
02607 sprintfToken * formatPtr, int * numTokensPtr,
02608 char ** endPtr, int state)
02609
02610
02611
02612 {
02613 char * chptr, * start, * next, * dst;
02614 sprintfToken format;
02615 sprintfToken token;
02616 int numTokens;
02617 int i;
02618 int done = 0;
02619
02620
02621 numTokens = 0;
02622 if (str != NULL)
02623 for (chptr = str; *chptr != '\0'; chptr++)
02624 if (*chptr == '%') numTokens++;
02625 numTokens = numTokens * 2 + 1;
02626
02627 format = xcalloc(numTokens, sizeof(*format));
02628 if (endPtr) *endPtr = NULL;
02629
02630
02631 dst = start = str;
02632 numTokens = 0;
02633 token = NULL;
02634 if (start != NULL)
02635 while (*start != '\0') {
02636 switch (*start) {
02637 case '%':
02638
02639 if (*(start + 1) == '%') {
02640 if (token == NULL || token->type != PTOK_STRING) {
02641 token = format + numTokens++;
02642 token->type = PTOK_STRING;
02643
02644 dst = token->u.string.string = start;
02645
02646 }
02647 start++;
02648
02649 *dst++ = *start++;
02650
02651 break;
02652 }
02653
02654 token = format + numTokens++;
02655
02656 *dst++ = '\0';
02657
02658 start++;
02659
02660 if (*start == '|') {
02661 char * newEnd;
02662
02663 start++;
02664
02665 if (parseExpression(hsa, token, start, &newEnd))
02666 {
02667 format = freeFormat(format, numTokens);
02668 return 1;
02669 }
02670
02671 start = newEnd;
02672 break;
02673 }
02674
02675
02676 token->u.tag.format = start;
02677
02678 token->u.tag.pad = 0;
02679 token->u.tag.justOne = 0;
02680 token->u.tag.arrayCount = 0;
02681
02682 chptr = start;
02683 while (*chptr && *chptr != '{' && *chptr != '%') chptr++;
02684 if (!*chptr || *chptr == '%') {
02685 hsa->errmsg = _("missing { after %");
02686 format = freeFormat(format, numTokens);
02687 return 1;
02688 }
02689
02690
02691 *chptr++ = '\0';
02692
02693
02694 while (start < chptr) {
02695 if (xisdigit(*start)) {
02696 i = strtoul(start, &start, 10);
02697 token->u.tag.pad += i;
02698 } else {
02699 start++;
02700 }
02701 }
02702
02703 if (*start == '=') {
02704 token->u.tag.justOne = 1;
02705 start++;
02706 } else if (*start == '#') {
02707 token->u.tag.justOne = 1;
02708 token->u.tag.arrayCount = 1;
02709 start++;
02710 }
02711
02712 next = start;
02713 while (*next && *next != '}') next++;
02714 if (!*next) {
02715 hsa->errmsg = _("missing } after %{");
02716 format = freeFormat(format, numTokens);
02717 return 1;
02718 }
02719
02720 *next++ = '\0';
02721
02722
02723 chptr = start;
02724 while (*chptr && *chptr != ':') chptr++;
02725
02726 if (*chptr != '\0') {
02727
02728 *chptr++ = '\0';
02729
02730 if (!*chptr) {
02731 hsa->errmsg = _("empty tag format");
02732 format = freeFormat(format, numTokens);
02733 return 1;
02734 }
02735
02736 token->u.tag.type = chptr;
02737
02738 } else {
02739 token->u.tag.type = NULL;
02740 }
02741
02742 if (!*start) {
02743 hsa->errmsg = _("empty tag name");
02744 format = freeFormat(format, numTokens);
02745 return 1;
02746 }
02747
02748 i = 0;
02749 token->type = PTOK_TAG;
02750
02751 if (findTag(hsa, token, start)) {
02752 hsa->errmsg = _("unknown tag");
02753 format = freeFormat(format, numTokens);
02754 return 1;
02755 }
02756
02757 start = next;
02758 break;
02759
02760 case '[':
02761
02762 *dst++ = '\0';
02763 *start++ = '\0';
02764
02765 token = format + numTokens++;
02766
02767
02768 if (parseFormat(hsa, start,
02769 &token->u.array.format,
02770 &token->u.array.numTokens,
02771 &start, PARSER_IN_ARRAY))
02772 {
02773 format = freeFormat(format, numTokens);
02774 return 1;
02775 }
02776
02777
02778 if (!start) {
02779 hsa->errmsg = _("] expected at end of array");
02780 format = freeFormat(format, numTokens);
02781 return 1;
02782 }
02783
02784 dst = start;
02785
02786 token->type = PTOK_ARRAY;
02787
02788 break;
02789
02790 case ']':
02791 if (state != PARSER_IN_ARRAY) {
02792 hsa->errmsg = _("unexpected ]");
02793 format = freeFormat(format, numTokens);
02794 return 1;
02795 }
02796
02797 *start++ = '\0';
02798
02799 if (endPtr) *endPtr = start;
02800 done = 1;
02801 break;
02802
02803 case '}':
02804 if (state != PARSER_IN_EXPR) {
02805 hsa->errmsg = _("unexpected }");
02806 format = freeFormat(format, numTokens);
02807 return 1;
02808 }
02809
02810 *start++ = '\0';
02811
02812 if (endPtr) *endPtr = start;
02813 done = 1;
02814 break;
02815
02816 default:
02817 if (token == NULL || token->type != PTOK_STRING) {
02818 token = format + numTokens++;
02819 token->type = PTOK_STRING;
02820
02821 dst = token->u.string.string = start;
02822
02823 }
02824
02825
02826 if (*start == '\\') {
02827 start++;
02828 *dst++ = escapedChar(*start++);
02829 } else {
02830 *dst++ = *start++;
02831 }
02832
02833 break;
02834 }
02835 if (done)
02836 break;
02837 }
02838
02839
02840
02841 if (dst != NULL)
02842 *dst = '\0';
02843
02844
02845 for (i = 0; i < numTokens; i++) {
02846 token = format + i;
02847 if (token->type == PTOK_STRING)
02848 token->u.string.len = strlen(token->u.string.string);
02849 }
02850
02851 *numTokensPtr = numTokens;
02852 *formatPtr = format;
02853
02854 return 0;
02855 }
02856
02857
02858 static int parseExpression(headerSprintfArgs hsa, sprintfToken token,
02859 char * str, char ** endPtr)
02860 {
02861 char * chptr;
02862 char * end;
02863
02864 hsa->errmsg = NULL;
02865 chptr = str;
02866 while (*chptr && *chptr != '?') chptr++;
02867
02868 if (*chptr != '?') {
02869 hsa->errmsg = _("? expected in expression");
02870 return 1;
02871 }
02872
02873 *chptr++ = '\0';;
02874
02875 if (*chptr != '{') {
02876 hsa->errmsg = _("{ expected after ? in expression");
02877 return 1;
02878 }
02879
02880 chptr++;
02881
02882 if (parseFormat(hsa, chptr, &token->u.cond.ifFormat,
02883 &token->u.cond.numIfTokens, &end, PARSER_IN_EXPR))
02884 return 1;
02885
02886
02887 if (!(end && *end)) {
02888 hsa->errmsg = _("} expected in expression");
02889 token->u.cond.ifFormat =
02890 freeFormat(token->u.cond.ifFormat, token->u.cond.numIfTokens);
02891 return 1;
02892 }
02893
02894 chptr = end;
02895 if (*chptr != ':' && *chptr != '|') {
02896 hsa->errmsg = _(": expected following ? subexpression");
02897 token->u.cond.ifFormat =
02898 freeFormat(token->u.cond.ifFormat, token->u.cond.numIfTokens);
02899 return 1;
02900 }
02901
02902 if (*chptr == '|') {
02903 if (parseFormat(hsa, NULL, &token->u.cond.elseFormat,
02904 &token->u.cond.numElseTokens, &end, PARSER_IN_EXPR))
02905 {
02906 token->u.cond.ifFormat =
02907 freeFormat(token->u.cond.ifFormat, token->u.cond.numIfTokens);
02908 return 1;
02909 }
02910 } else {
02911 chptr++;
02912
02913 if (*chptr != '{') {
02914 hsa->errmsg = _("{ expected after : in expression");
02915 token->u.cond.ifFormat =
02916 freeFormat(token->u.cond.ifFormat, token->u.cond.numIfTokens);
02917 return 1;
02918 }
02919
02920 chptr++;
02921
02922 if (parseFormat(hsa, chptr, &token->u.cond.elseFormat,
02923 &token->u.cond.numElseTokens, &end, PARSER_IN_EXPR))
02924 return 1;
02925
02926
02927 if (!(end && *end)) {
02928 hsa->errmsg = _("} expected in expression");
02929 token->u.cond.ifFormat =
02930 freeFormat(token->u.cond.ifFormat, token->u.cond.numIfTokens);
02931 return 1;
02932 }
02933
02934 chptr = end;
02935 if (*chptr != '|') {
02936 hsa->errmsg = _("| expected at end of expression");
02937 token->u.cond.ifFormat =
02938 freeFormat(token->u.cond.ifFormat, token->u.cond.numIfTokens);
02939 token->u.cond.elseFormat =
02940 freeFormat(token->u.cond.elseFormat, token->u.cond.numElseTokens);
02941 return 1;
02942 }
02943 }
02944
02945 chptr++;
02946
02947 *endPtr = chptr;
02948
02949 token->type = PTOK_COND;
02950
02951 (void) findTag(hsa, token, str);
02952
02953 return 0;
02954 }
02955
02956
02967 static int getExtension(headerSprintfArgs hsa, headerTagTagFunction fn,
02968 hTYP_t typeptr,
02969 hPTR_t * data,
02970 hCNT_t countptr,
02971 rpmec ec)
02972
02973
02974
02975 {
02976 if (!ec->avail) {
02977 if (fn(hsa->h, &ec->type, &ec->data, &ec->count, &ec->freeit))
02978 return 1;
02979 ec->avail = 1;
02980 }
02981
02982 if (typeptr) *typeptr = ec->type;
02983 if (data) *data = ec->data;
02984 if (countptr) *countptr = ec->count;
02985
02986 return 0;
02987 }
02988
02995
02996 static char * formatValue(headerSprintfArgs hsa, sprintfTag tag, int element)
02997
02998 {
02999 char * val = NULL;
03000 size_t need = 0;
03001 char * t, * te;
03002 char buf[20];
03003 int_32 count, type;
03004 hPTR_t data;
03005 unsigned int intVal;
03006 const char ** strarray;
03007 int datafree = 0;
03008 int countBuf;
03009
03010 memset(buf, 0, sizeof(buf));
03011 if (tag->ext) {
03012
03013 if (getExtension(hsa, tag->ext, &type, &data, &count, hsa->ec + tag->extNum))
03014 {
03015 count = 1;
03016 type = RPM_STRING_TYPE;
03017 data = "(none)";
03018 }
03019
03020 } else {
03021
03022 if (!headerGetEntry(hsa->h, tag->tag, &type, (void **)&data, &count)) {
03023 count = 1;
03024 type = RPM_STRING_TYPE;
03025 data = "(none)";
03026 }
03027
03028
03029
03030 switch (type) {
03031 default:
03032 if (element >= count) {
03033
03034 data = headerFreeData(data, type);
03035
03036
03037 hsa->errmsg = _("(index out of range)");
03038 return NULL;
03039 }
03040 break;
03041 case RPM_BIN_TYPE:
03042 case RPM_STRING_TYPE:
03043 break;
03044 }
03045 datafree = 1;
03046 }
03047
03048 if (tag->arrayCount) {
03049
03050 if (datafree)
03051 data = headerFreeData(data, type);
03052
03053
03054 countBuf = count;
03055 data = &countBuf;
03056 count = 1;
03057 type = RPM_INT32_TYPE;
03058 }
03059
03060
03061 (void) stpcpy( stpcpy(buf, "%"), tag->format);
03062
03063
03064
03065 if (data)
03066 switch (type) {
03067 case RPM_STRING_ARRAY_TYPE:
03068 strarray = (const char **)data;
03069
03070 if (tag->fmt)
03071 val = tag->fmt(RPM_STRING_TYPE, strarray[element], buf, tag->pad, element);
03072
03073 if (val) {
03074 need = strlen(val);
03075 } else {
03076 need = strlen(strarray[element]) + tag->pad + 20;
03077 val = xmalloc(need+1);
03078 strcat(buf, "s");
03079
03080 sprintf(val, buf, strarray[element]);
03081
03082 }
03083
03084 break;
03085
03086 case RPM_STRING_TYPE:
03087 if (tag->fmt)
03088 val = tag->fmt(RPM_STRING_TYPE, data, buf, tag->pad, 0);
03089
03090 if (val) {
03091 need = strlen(val);
03092 } else {
03093 need = strlen(data) + tag->pad + 20;
03094 val = xmalloc(need+1);
03095 strcat(buf, "s");
03096
03097 sprintf(val, buf, data);
03098
03099 }
03100 break;
03101
03102 case RPM_CHAR_TYPE:
03103 case RPM_INT8_TYPE:
03104 case RPM_INT16_TYPE:
03105 case RPM_INT32_TYPE:
03106 switch (type) {
03107 case RPM_CHAR_TYPE:
03108 case RPM_INT8_TYPE:
03109 intVal = *(((int_8 *) data) + element);
03110 break;
03111 case RPM_INT16_TYPE:
03112 intVal = *(((uint_16 *) data) + element);
03113 break;
03114 default:
03115 case RPM_INT32_TYPE:
03116 intVal = *(((int_32 *) data) + element);
03117 break;
03118 }
03119
03120 if (tag->fmt)
03121 val = tag->fmt(RPM_INT32_TYPE, &intVal, buf, tag->pad, element);
03122
03123 if (val) {
03124 need = strlen(val);
03125 } else {
03126 need = 10 + tag->pad + 20;
03127 val = xmalloc(need+1);
03128 strcat(buf, "d");
03129
03130 sprintf(val, buf, intVal);
03131
03132 }
03133 break;
03134
03135 case RPM_BIN_TYPE:
03136
03137 if (tag->fmt)
03138 val = tag->fmt(RPM_BIN_TYPE, data, buf, tag->pad, count);
03139
03140 if (val) {
03141 need = strlen(val);
03142 } else {
03143 #ifdef NOTYET
03144 val = memcpy(xmalloc(count), data, count);
03145 #else
03146
03147 static char hex[] = "0123456789abcdef";
03148 const char * s = data;
03149
03150
03151 need = 2*count + tag->pad;
03152 val = t = xmalloc(need+1);
03153 while (count-- > 0) {
03154 unsigned int i;
03155 i = *s++;
03156 *t++ = hex[ (i >> 4) & 0xf ];
03157 *t++ = hex[ (i ) & 0xf ];
03158 }
03159 *t = '\0';
03160
03161 #endif
03162 }
03163 break;
03164
03165 default:
03166 need = sizeof("(unknown type)") - 1;
03167 val = xstrdup("(unknown type)");
03168 break;
03169 }
03170
03171
03172
03173 if (datafree)
03174 data = headerFreeData(data, type);
03175
03176
03177
03178 if (val && need > 0) {
03179 t = hsaReserve(hsa, need);
03180
03181 te = stpcpy(t, val);
03182
03183 hsa->vallen += (te - t);
03184 val = _free(val);
03185 }
03186
03187
03188 return (hsa->val + hsa->vallen);
03189 }
03190
03197
03198 static char * singleSprintf(headerSprintfArgs hsa, sprintfToken token,
03199 int element)
03200
03201 {
03202 char * t, * te;
03203 int i, j;
03204 int numElements;
03205 int_32 type;
03206 int_32 count;
03207 sprintfToken spft;
03208 int condNumFormats;
03209 size_t need;
03210
03211
03212
03213 switch (token->type) {
03214 case PTOK_NONE:
03215 break;
03216
03217 case PTOK_STRING:
03218 need = token->u.string.len;
03219 if (need == 0) break;
03220 t = hsaReserve(hsa, need);
03221
03222 te = stpcpy(t, token->u.string.string);
03223
03224 hsa->vallen += (te - t);
03225 break;
03226
03227 case PTOK_TAG:
03228 t = hsa->val + hsa->vallen;
03229 te = formatValue(hsa, &token->u.tag,
03230 (token->u.tag.justOne ? 0 : element));
03231 if (te == NULL)
03232 return NULL;
03233 break;
03234
03235 case PTOK_COND:
03236 if (token->u.cond.tag.ext || headerIsEntry(hsa->h, token->u.cond.tag.tag)) {
03237 spft = token->u.cond.ifFormat;
03238 condNumFormats = token->u.cond.numIfTokens;
03239 } else {
03240 spft = token->u.cond.elseFormat;
03241 condNumFormats = token->u.cond.numElseTokens;
03242 }
03243
03244 need = condNumFormats * 20;
03245 if (spft == NULL || need == 0) break;
03246
03247 t = hsaReserve(hsa, need);
03248 for (i = 0; i < condNumFormats; i++, spft++) {
03249 te = singleSprintf(hsa, spft, element);
03250 if (te == NULL)
03251 return NULL;
03252 }
03253 break;
03254
03255 case PTOK_ARRAY:
03256 numElements = -1;
03257 spft = token->u.array.format;
03258 for (i = 0; i < token->u.array.numTokens; i++, spft++)
03259 {
03260 if (spft->type != PTOK_TAG ||
03261 spft->u.tag.arrayCount ||
03262 spft->u.tag.justOne) continue;
03263
03264 if (spft->u.tag.ext) {
03265
03266 if (getExtension(hsa, spft->u.tag.ext, &type, NULL, &count,
03267 hsa->ec + spft->u.tag.extNum))
03268 continue;
03269
03270 } else {
03271
03272 if (!headerGetEntry(hsa->h, spft->u.tag.tag, &type, NULL, &count))
03273 continue;
03274
03275 }
03276
03277 if (type == RPM_BIN_TYPE)
03278 count = 1;
03279
03280 if (numElements > 1 && count != numElements)
03281 switch (type) {
03282 default:
03283 hsa->errmsg =
03284 _("array iterator used with different sized arrays");
03285 return NULL;
03286 break;
03287 case RPM_BIN_TYPE:
03288 case RPM_STRING_TYPE:
03289 break;
03290 }
03291 if (count > numElements)
03292 numElements = count;
03293 }
03294
03295 if (numElements == -1) {
03296 need = sizeof("(none)") - 1;
03297 t = hsaReserve(hsa, need);
03298
03299 te = stpcpy(t, "(none)");
03300
03301 hsa->vallen += (te - t);
03302 } else {
03303 int isxml;
03304
03305 need = numElements * token->u.array.numTokens * 10;
03306 if (need == 0) break;
03307
03308 spft = token->u.array.format;
03309 isxml = (spft->type == PTOK_TAG && spft->u.tag.type != NULL &&
03310 !strcmp(spft->u.tag.type, "xml"));
03311
03312 if (isxml) {
03313 const char * tagN = tagName(spft->u.tag.tag);
03314
03315 need = strlen(tagN) + sizeof(" <rpmTag name=\"\">\n") - 1;
03316 t = hsaReserve(hsa, need);
03317
03318 te = stpcpy(t, " <rpmTag name=\"");
03319 te = stpcpy(te, tagN);
03320 te = stpcpy(te, "\">\n");
03321
03322 hsa->vallen += (te - t);
03323 }
03324
03325 t = hsaReserve(hsa, need);
03326 for (j = 0; j < numElements; j++) {
03327 spft = token->u.array.format;
03328 for (i = 0; i < token->u.array.numTokens; i++, spft++) {
03329 te = singleSprintf(hsa, spft, j);
03330 if (te == NULL)
03331 return NULL;
03332 }
03333 }
03334
03335 if (isxml) {
03336 need = sizeof(" </rpmTag>\n") - 1;
03337 t = hsaReserve(hsa, need);
03338
03339 te = stpcpy(t, " </rpmTag>\n");
03340
03341 hsa->vallen += (te - t);
03342 }
03343
03344 }
03345 break;
03346 }
03347
03348 return (hsa->val + hsa->vallen);
03349 }
03350
03356 static rpmec
03357 rpmecNew(const headerSprintfExtension exts)
03358
03359 {
03360 headerSprintfExtension ext;
03361 rpmec ec;
03362 int i = 0;
03363
03364 for (ext = exts; ext != NULL && ext->type != HEADER_EXT_LAST;
03365 ext = (ext->type == HEADER_EXT_MORE ? ext->u.more : ext+1))
03366 {
03367 i++;
03368 }
03369
03370 ec = xcalloc(i, sizeof(*ec));
03371 return ec;
03372 }
03373
03380 static rpmec
03381 rpmecFree(const headerSprintfExtension exts, rpmec ec)
03382
03383 {
03384 headerSprintfExtension ext;
03385 int i = 0;
03386
03387 for (ext = exts; ext != NULL && ext->type != HEADER_EXT_LAST;
03388 ext = (ext->type == HEADER_EXT_MORE ? ext->u.more : ext+1))
03389 {
03390
03391 if (ec[i].freeit) ec[i].data = _free(ec[i].data);
03392
03393 i++;
03394 }
03395
03396 ec = _free(ec);
03397 return NULL;
03398 }
03399
03411 static
03412 char * headerSprintf(Header h, const char * fmt,
03413 const struct headerTagTableEntry_s * tbltags,
03414 const struct headerSprintfExtension_s * extensions,
03415 errmsg_t * errmsg)
03416
03417
03418 {
03419 headerSprintfArgs hsa = memset(alloca(sizeof(*hsa)), 0, sizeof(*hsa));
03420 sprintfToken nextfmt;
03421 sprintfTag tag;
03422 char * t, * te;
03423 int isxml;
03424 int need;
03425
03426 hsa->h = headerLink(h);
03427 hsa->fmt = xstrdup(fmt);
03428
03429 hsa->exts = (headerSprintfExtension) extensions;
03430 hsa->tags = (headerTagTableEntry) tbltags;
03431
03432 hsa->errmsg = NULL;
03433
03434
03435 if (parseFormat(hsa, hsa->fmt, &hsa->format, &hsa->numTokens, NULL, PARSER_BEGIN))
03436 goto exit;
03437
03438
03439 hsa->ec = rpmecNew(hsa->exts);
03440 hsa->val = xstrdup("");
03441
03442 tag =
03443 (hsa->format->type == PTOK_TAG
03444 ? &hsa->format->u.tag :
03445 (hsa->format->type == PTOK_ARRAY
03446 ? &hsa->format->u.array.format->u.tag :
03447 NULL));
03448 isxml = (tag != NULL && tag->tag == -2 && tag->type != NULL && !strcmp(tag->type, "xml"));
03449
03450 if (isxml) {
03451 need = sizeof("<rpmHeader>\n") - 1;
03452 t = hsaReserve(hsa, need);
03453
03454 te = stpcpy(t, "<rpmHeader>\n");
03455
03456 hsa->vallen += (te - t);
03457 }
03458
03459 hsa = hsaInit(hsa);
03460 while ((nextfmt = hsaNext(hsa)) != NULL) {
03461 te = singleSprintf(hsa, nextfmt, 0);
03462 if (te == NULL) {
03463 hsa->val = _free(hsa->val);
03464 break;
03465 }
03466 }
03467 hsa = hsaFini(hsa);
03468
03469 if (isxml) {
03470 need = sizeof("</rpmHeader>\n") - 1;
03471 t = hsaReserve(hsa, need);
03472
03473 te = stpcpy(t, "</rpmHeader>\n");
03474
03475 hsa->vallen += (te - t);
03476 }
03477
03478 if (hsa->val != NULL && hsa->vallen < hsa->alloced)
03479 hsa->val = xrealloc(hsa->val, hsa->vallen+1);
03480
03481 hsa->ec = rpmecFree(hsa->exts, hsa->ec);
03482 hsa->format = freeFormat(hsa->format, hsa->numTokens);
03483
03484 exit:
03485
03486 if (errmsg)
03487 *errmsg = hsa->errmsg;
03488
03489 hsa->h = headerFree(hsa->h);
03490 hsa->fmt = _free(hsa->fmt);
03491 return hsa->val;
03492 }
03493
03502 static char * octalFormat(int_32 type, hPTR_t data,
03503 char * formatPrefix, int padding, int element)
03504
03505 {
03506 char * val;
03507
03508 if (type != RPM_INT32_TYPE) {
03509 val = xstrdup(_("(not a number)"));
03510 } else {
03511 val = xmalloc(20 + padding);
03512
03513 strcat(formatPrefix, "o");
03514
03515
03516 sprintf(val, formatPrefix, *((int_32 *) data));
03517
03518 }
03519
03520 return val;
03521 }
03522
03531 static char * hexFormat(int_32 type, hPTR_t data,
03532 char * formatPrefix, int padding, int element)
03533
03534 {
03535 char * val;
03536
03537 if (type != RPM_INT32_TYPE) {
03538 val = xstrdup(_("(not a number)"));
03539 } else {
03540 val = xmalloc(20 + padding);
03541
03542 strcat(formatPrefix, "x");
03543
03544
03545 sprintf(val, formatPrefix, *((int_32 *) data));
03546
03547 }
03548
03549 return val;
03550 }
03551
03554 static char * realDateFormat(int_32 type, hPTR_t data,
03555 char * formatPrefix, int padding, int element,
03556 const char * strftimeFormat)
03557
03558 {
03559 char * val;
03560
03561 if (type != RPM_INT32_TYPE) {
03562 val = xstrdup(_("(not a number)"));
03563 } else {
03564 struct tm * tstruct;
03565 char buf[50];
03566
03567 val = xmalloc(50 + padding);
03568
03569 strcat(formatPrefix, "s");
03570
03571
03572
03573 { time_t dateint = *((int_32 *) data);
03574 tstruct = localtime(&dateint);
03575 }
03576 buf[0] = '\0';
03577 if (tstruct)
03578 (void) strftime(buf, sizeof(buf) - 1, strftimeFormat, tstruct);
03579
03580 sprintf(val, formatPrefix, buf);
03581
03582 }
03583
03584 return val;
03585 }
03586
03595 static char * dateFormat(int_32 type, hPTR_t data,
03596 char * formatPrefix, int padding, int element)
03597
03598 {
03599 return realDateFormat(type, data, formatPrefix, padding, element,
03600 _("%c"));
03601 }
03602
03611 static char * dayFormat(int_32 type, hPTR_t data,
03612 char * formatPrefix, int padding, int element)
03613
03614 {
03615 return realDateFormat(type, data, formatPrefix, padding, element,
03616 _("%a %b %d %Y"));
03617 }
03618
03627 static char * shescapeFormat(int_32 type, hPTR_t data,
03628 char * formatPrefix, int padding, int element)
03629
03630 {
03631 char * result, * dst, * src, * buf;
03632
03633 if (type == RPM_INT32_TYPE) {
03634 result = xmalloc(padding + 20);
03635
03636 strcat(formatPrefix, "d");
03637
03638
03639 sprintf(result, formatPrefix, *((int_32 *) data));
03640
03641 } else {
03642 buf = alloca(strlen(data) + padding + 2);
03643
03644 strcat(formatPrefix, "s");
03645
03646
03647 sprintf(buf, formatPrefix, data);
03648
03649
03650
03651 result = dst = xmalloc(strlen(buf) * 4 + 3);
03652 *dst++ = '\'';
03653 for (src = buf; *src != '\0'; src++) {
03654 if (*src == '\'') {
03655 *dst++ = '\'';
03656 *dst++ = '\\';
03657 *dst++ = '\'';
03658 *dst++ = '\'';
03659 } else {
03660 *dst++ = *src;
03661 }
03662 }
03663 *dst++ = '\'';
03664 *dst = '\0';
03665
03666
03667 }
03668
03669 return result;
03670 }
03671
03672
03673 const struct headerSprintfExtension_s headerDefaultFormats[] = {
03674 { HEADER_EXT_FORMAT, "octal", { octalFormat } },
03675 { HEADER_EXT_FORMAT, "hex", { hexFormat } },
03676 { HEADER_EXT_FORMAT, "date", { dateFormat } },
03677 { HEADER_EXT_FORMAT, "day", { dayFormat } },
03678 { HEADER_EXT_FORMAT, "shescape", { shescapeFormat } },
03679 { HEADER_EXT_LAST, NULL, { NULL } }
03680 };
03681
03682
03689 static
03690 void headerCopyTags(Header headerFrom, Header headerTo, hTAG_t tagstocopy)
03691
03692 {
03693 int * p;
03694
03695 if (headerFrom == headerTo)
03696 return;
03697
03698 for (p = tagstocopy; *p != 0; p++) {
03699 char *s;
03700 int_32 type;
03701 int_32 count;
03702 if (headerIsEntry(headerTo, *p))
03703 continue;
03704
03705 if (!headerGetEntryMinMemory(headerFrom, *p, &type,
03706 (hPTR_t *) &s, &count))
03707 continue;
03708
03709 (void) headerAddEntry(headerTo, *p, type, s, count);
03710 s = headerFreeData(s, type);
03711 }
03712 }
03713
03714
03715 static struct HV_s hdrVec1 = {
03716 headerLink,
03717 headerUnlink,
03718 headerFree,
03719 headerNew,
03720 headerSort,
03721 headerUnsort,
03722 headerSizeof,
03723 headerUnload,
03724 headerReload,
03725 headerCopy,
03726 headerLoad,
03727 headerCopyLoad,
03728 headerRead,
03729 headerWrite,
03730 headerIsEntry,
03731 headerFreeTag,
03732 headerGetEntry,
03733 headerGetEntryMinMemory,
03734 headerAddEntry,
03735 headerAppendEntry,
03736 headerAddOrAppendEntry,
03737 headerAddI18NString,
03738 headerModifyEntry,
03739 headerRemoveEntry,
03740 headerSprintf,
03741 headerCopyTags,
03742 headerFreeIterator,
03743 headerInitIterator,
03744 headerNextIterator,
03745 NULL, NULL,
03746 1
03747 };
03748
03749
03750
03751 HV_t hdrVec = &hdrVec1;
03752