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