00001
00005
00006
00007
00008
00009
00010
00011 #include "system.h"
00012
00013 #define __HEADER_PROTOTYPES__
00014
00015 #include <header_internal.h>
00016
00017 #include "debug.h"
00018
00019
00020 int _hdr_debug = 0;
00021
00022
00023
00024
00025
00026
00027
00028
00029
00030 #define PARSER_BEGIN 0
00031 #define PARSER_IN_ARRAY 1
00032 #define PARSER_IN_EXPR 2
00033
00036
00037 static unsigned char header_magic[8] = {
00038 0x8e, 0xad, 0xe8, 0x01, 0x00, 0x00, 0x00, 0x00
00039 };
00040
00044
00045 static int typeAlign[16] = {
00046 1,
00047 1,
00048 1,
00049 2,
00050 4,
00051 8,
00052 1,
00053 1,
00054 1,
00055 1,
00056 0,
00057 0,
00058 0,
00059 0,
00060 0,
00061 0
00062 };
00063
00067
00068 static int typeSizes[16] = {
00069 0,
00070 1,
00071 1,
00072 2,
00073 4,
00074 -1,
00075 -1,
00076 1,
00077 -1,
00078 -1,
00079 0,
00080 0,
00081 0,
00082 0,
00083 0,
00084 0
00085 };
00086
00090
00091 static size_t headerMaxbytes = (32*1024*1024);
00092
00097 #define hdrchkTags(_ntags) ((_ntags) & 0xffff0000)
00098
00102 #define hdrchkType(_type) ((_type) < RPM_MIN_TYPE || (_type) > RPM_MAX_TYPE)
00103
00108 #define hdrchkData(_nbytes) ((_nbytes) & 0xff000000)
00109
00113 #define hdrchkAlign(_type, _off) ((_off) & (typeAlign[_type]-1))
00114
00118 #define hdrchkRange(_dl, _off) ((_off) < 0 || (_off) > (_dl))
00119
00120
00121 HV_t hdrVec;
00122
00128 static inline void *
00129 _free( const void * p)
00130 {
00131 if (p != NULL) free((void *)p);
00132 return NULL;
00133 }
00134
00140 static
00141 Header headerLink(Header h)
00142
00143 {
00144
00145 if (h == NULL) return NULL;
00146
00147
00148 h->nrefs++;
00149
00150 if (_hdr_debug)
00151 fprintf(stderr, "--> h %p ++ %d at %s:%u\n", h, h->nrefs, __FILE__, __LINE__);
00152
00153
00154
00155 return h;
00156
00157 }
00158
00164 static
00165 Header headerUnlink( Header h)
00166
00167 {
00168 if (h == NULL) return NULL;
00169
00170 if (_hdr_debug)
00171 fprintf(stderr, "--> h %p -- %d at %s:%u\n", h, h->nrefs, __FILE__, __LINE__);
00172
00173 h->nrefs--;
00174 return NULL;
00175 }
00176
00182 static
00183 Header headerFree( Header h)
00184
00185 {
00186 (void) headerUnlink(h);
00187
00188
00189 if (h == NULL || h->nrefs > 0)
00190 return NULL;
00191
00192 if (h->index) {
00193 indexEntry entry = h->index;
00194 int i;
00195 for (i = 0; i < h->indexUsed; i++, entry++) {
00196 if ((h->flags & HEADERFLAG_ALLOCATED) && ENTRY_IS_REGION(entry)) {
00197 if (entry->length > 0) {
00198 int_32 * ei = entry->data;
00199 if ((ei - 2) == h->blob) h->blob = _free(h->blob);
00200 entry->data = NULL;
00201 }
00202 } else if (!ENTRY_IN_REGION(entry)) {
00203 entry->data = _free(entry->data);
00204 }
00205 entry->data = NULL;
00206 }
00207 h->index = _free(h->index);
00208 }
00209
00210 h = _free(h);
00211 return h;
00212
00213 }
00214
00219 static
00220 Header headerNew(void)
00221
00222 {
00223 Header h = xcalloc(1, sizeof(*h));
00224
00225
00226
00227 h->hv = *hdrVec;
00228
00229
00230 h->blob = NULL;
00231 h->indexAlloced = INDEX_MALLOC_SIZE;
00232 h->indexUsed = 0;
00233 h->flags |= HEADERFLAG_SORTED;
00234
00235 h->index = (h->indexAlloced
00236 ? xcalloc(h->indexAlloced, sizeof(*h->index))
00237 : NULL);
00238
00239 h->nrefs = 0;
00240
00241 return headerLink(h);
00242
00243 }
00244
00247 static int indexCmp(const void * avp, const void * bvp)
00248
00249 {
00250
00251 indexEntry ap = (indexEntry) avp, bp = (indexEntry) bvp;
00252
00253 return (ap->info.tag - bp->info.tag);
00254 }
00255
00260 static
00261 void headerSort(Header h)
00262
00263 {
00264 if (!(h->flags & HEADERFLAG_SORTED)) {
00265
00266 qsort(h->index, h->indexUsed, sizeof(*h->index), indexCmp);
00267
00268 h->flags |= HEADERFLAG_SORTED;
00269 }
00270 }
00271
00274 static int offsetCmp(const void * avp, const void * bvp)
00275 {
00276
00277 indexEntry ap = (indexEntry) avp, bp = (indexEntry) bvp;
00278
00279 int rc = (ap->info.offset - bp->info.offset);
00280
00281 if (rc == 0) {
00282
00283 if (ap->info.offset < 0)
00284 rc = (((char *)ap->data) - ((char *)bp->data));
00285 else
00286 rc = (ap->info.tag - bp->info.tag);
00287 }
00288 return rc;
00289 }
00290
00295 static
00296 void headerUnsort(Header h)
00297
00298 {
00299
00300 qsort(h->index, h->indexUsed, sizeof(*h->index), offsetCmp);
00301
00302 }
00303
00310 static
00311 unsigned int headerSizeof( Header h, enum hMagic magicp)
00312
00313 {
00314 indexEntry entry;
00315 unsigned int size = 0;
00316 unsigned int pad = 0;
00317 int i;
00318
00319 if (h == NULL)
00320 return size;
00321
00322 headerSort(h);
00323
00324 switch (magicp) {
00325 case HEADER_MAGIC_YES:
00326 size += sizeof(header_magic);
00327 break;
00328 case HEADER_MAGIC_NO:
00329 break;
00330 }
00331
00332
00333 size += 2 * sizeof(int_32);
00334
00335
00336 for (i = 0, entry = h->index; i < h->indexUsed; i++, entry++) {
00337 unsigned diff;
00338 int_32 type;
00339
00340
00341 if (ENTRY_IS_REGION(entry)) {
00342 size += entry->length;
00343
00344
00345 if (i == 0 && (h->flags & HEADERFLAG_LEGACY))
00346 size += sizeof(struct entryInfo_s) + entry->info.count;
00347
00348 continue;
00349 }
00350
00351
00352 if (entry->info.offset < 0)
00353 continue;
00354
00355
00356 type = entry->info.type;
00357
00358 if (typeSizes[type] > 1) {
00359 diff = typeSizes[type] - (size % typeSizes[type]);
00360 if (diff != typeSizes[type]) {
00361 size += diff;
00362 pad += diff;
00363 }
00364 }
00365
00366
00367
00368 size += sizeof(struct entryInfo_s) + entry->length;
00369
00370 }
00371
00372 return size;
00373 }
00374
00384 static int dataLength(int_32 type, hPTR_t p, int_32 count, int onDisk,
00385 hPTR_t pend)
00386
00387 {
00388 const unsigned char * s = p;
00389 const unsigned char * se = pend;
00390 int length = 0;
00391
00392 switch (type) {
00393 case RPM_STRING_TYPE:
00394 if (count != 1)
00395 return -1;
00396
00397 while (*s++) {
00398 if (se && s > se)
00399 return -1;
00400 length++;
00401 }
00402
00403 length++;
00404 break;
00405
00406 case RPM_STRING_ARRAY_TYPE:
00407 case RPM_I18NSTRING_TYPE:
00408
00409
00410
00411 if (onDisk) {
00412 while (count--) {
00413 length++;
00414
00415 while (*s++) {
00416 if (se && s > se)
00417 return -1;
00418 length++;
00419 }
00420
00421 }
00422 } else {
00423 const char ** av = (const char **)p;
00424
00425 while (count--) {
00426
00427 length += strlen(*av++) + 1;
00428 }
00429
00430 }
00431 break;
00432
00433 default:
00434
00435 if (typeSizes[type] == -1)
00436 return -1;
00437 length = typeSizes[(type & 0xf)] * count;
00438
00439 if (length < 0 || (se && (s + length) > se))
00440 return -1;
00441 break;
00442 }
00443
00444 return length;
00445 }
00446
00473 static int regionSwab( indexEntry entry, int il, int dl,
00474 entryInfo pe,
00475 unsigned char * dataStart,
00476 const unsigned char * dataEnd,
00477 int regionid)
00478
00479 {
00480 unsigned char * tprev = NULL;
00481 unsigned char * t = NULL;
00482 int tdel = 0;
00483 int tl = dl;
00484 struct indexEntry_s ieprev;
00485
00486 if (regionid > 0)
00487 return -1;
00488
00489 memset(&ieprev, 0, sizeof(ieprev));
00490
00491 for (; il > 0; il--, pe++) {
00492 struct indexEntry_s ie;
00493 int_32 type;
00494
00495 ie.info.tag = ntohl(pe->tag);
00496 ie.info.type = ntohl(pe->type);
00497 ie.info.count = ntohl(pe->count);
00498 ie.info.offset = ntohl(pe->offset);
00499
00500 if (hdrchkType(ie.info.type))
00501 return -1;
00502 if (hdrchkData(ie.info.count))
00503 return -1;
00504 if (hdrchkData(ie.info.offset))
00505 return -1;
00506
00507 if (hdrchkAlign(ie.info.type, ie.info.offset))
00508 return -1;
00509
00510
00511 ie.data = t = dataStart + ie.info.offset;
00512 if (dataEnd && t >= dataEnd)
00513 return -1;
00514
00515 ie.length = dataLength(ie.info.type, ie.data, ie.info.count, 1, dataEnd);
00516 if (ie.length < 0 || hdrchkData(ie.length))
00517 return -1;
00518
00519 ie.rdlen = 0;
00520
00521 if (entry) {
00522 ie.info.offset = regionid;
00523
00524 *entry = ie;
00525
00526 entry++;
00527 }
00528
00529
00530 type = ie.info.type;
00531
00532 if (typeSizes[type] > 1) {
00533 unsigned diff;
00534 diff = typeSizes[type] - (dl % typeSizes[type]);
00535 if (diff != typeSizes[type]) {
00536 dl += diff;
00537 if (ieprev.info.type == RPM_I18NSTRING_TYPE)
00538 ieprev.length += diff;
00539 }
00540 }
00541
00542 tdel = (tprev ? (t - tprev) : 0);
00543 if (ieprev.info.type == RPM_I18NSTRING_TYPE)
00544 tdel = ieprev.length;
00545
00546 if (ie.info.tag >= HEADER_I18NTABLE) {
00547 tprev = t;
00548 } else {
00549 tprev = dataStart;
00550
00551
00552 if (ie.info.tag == HEADER_IMAGE)
00553 tprev -= REGION_TAG_COUNT;
00554
00555 }
00556
00557
00558 switch (ntohl(pe->type)) {
00559
00560 case RPM_INT32_TYPE:
00561 { int_32 * it = (int_32 *)t;
00562 for (; ie.info.count > 0; ie.info.count--, it += 1) {
00563 if (dataEnd && ((unsigned char *)it) >= dataEnd)
00564 return -1;
00565 *it = htonl(*it);
00566 }
00567 t = (char *) it;
00568 } break;
00569 case RPM_INT16_TYPE:
00570 { int_16 * it = (int_16 *) t;
00571 for (; ie.info.count > 0; ie.info.count--, it += 1) {
00572 if (dataEnd && ((unsigned char *)it) >= dataEnd)
00573 return -1;
00574 *it = htons(*it);
00575 }
00576 t = (char *) it;
00577 } break;
00578
00579 default:
00580 t += ie.length;
00581 break;
00582 }
00583
00584 dl += ie.length;
00585 tl += tdel;
00586 ieprev = ie;
00587
00588 }
00589 tdel = (tprev ? (t - tprev) : 0);
00590 tl += tdel;
00591
00592
00593
00594
00595
00596
00597
00598 if (tl+REGION_TAG_COUNT == dl)
00599 tl += REGION_TAG_COUNT;
00600
00601
00602 return dl;
00603 }
00604
00610 static void * doHeaderUnload(Header h,
00611 int * lengthPtr)
00612
00613
00614
00615 {
00616 int_32 * ei = NULL;
00617 entryInfo pe;
00618 char * dataStart;
00619 char * te;
00620 unsigned pad;
00621 unsigned len;
00622 int_32 il = 0;
00623 int_32 dl = 0;
00624 indexEntry entry;
00625 int_32 type;
00626 int i;
00627 int drlen, ndribbles;
00628 int driplen, ndrips;
00629 int legacy = 0;
00630
00631
00632 headerUnsort(h);
00633
00634
00635 pad = 0;
00636 drlen = ndribbles = driplen = ndrips = 0;
00637 for (i = 0, entry = h->index; i < h->indexUsed; i++, entry++) {
00638 if (ENTRY_IS_REGION(entry)) {
00639 int_32 rdl = -entry->info.offset;
00640 int_32 ril = rdl/sizeof(*pe);
00641 int rid = entry->info.offset;
00642
00643 il += ril;
00644 dl += entry->rdlen + entry->info.count;
00645
00646 if (i == 0 && (h->flags & HEADERFLAG_LEGACY))
00647 il += 1;
00648
00649
00650 for (; i < h->indexUsed && entry->info.offset <= rid+1; i++, entry++) {
00651 if (entry->info.offset <= rid)
00652 continue;
00653
00654
00655 type = entry->info.type;
00656 if (typeSizes[type] > 1) {
00657 unsigned diff;
00658 diff = typeSizes[type] - (dl % typeSizes[type]);
00659 if (diff != typeSizes[type]) {
00660 drlen += diff;
00661 pad += diff;
00662 dl += diff;
00663 }
00664 }
00665
00666 ndribbles++;
00667 il++;
00668 drlen += entry->length;
00669 dl += entry->length;
00670 }
00671 i--;
00672 entry--;
00673 continue;
00674 }
00675
00676
00677 if (entry->data == NULL || entry->length <= 0)
00678 continue;
00679
00680
00681 type = entry->info.type;
00682 if (typeSizes[type] > 1) {
00683 unsigned diff;
00684 diff = typeSizes[type] - (dl % typeSizes[type]);
00685 if (diff != typeSizes[type]) {
00686 driplen += diff;
00687 pad += diff;
00688 dl += diff;
00689 } else
00690 diff = 0;
00691 }
00692
00693 ndrips++;
00694 il++;
00695 driplen += entry->length;
00696 dl += entry->length;
00697 }
00698
00699
00700 if (hdrchkTags(il) || hdrchkData(dl))
00701 goto errxit;
00702
00703 len = sizeof(il) + sizeof(dl) + (il * sizeof(*pe)) + dl;
00704
00705
00706 ei = xmalloc(len);
00707 ei[0] = htonl(il);
00708 ei[1] = htonl(dl);
00709
00710
00711 pe = (entryInfo) &ei[2];
00712 dataStart = te = (char *) (pe + il);
00713
00714 pad = 0;
00715 for (i = 0, entry = h->index; i < h->indexUsed; i++, entry++) {
00716 const char * src;
00717 char *t;
00718 int count;
00719 int rdlen;
00720
00721 if (entry->data == NULL || entry->length <= 0)
00722 continue;
00723
00724 t = te;
00725 pe->tag = htonl(entry->info.tag);
00726 pe->type = htonl(entry->info.type);
00727 pe->count = htonl(entry->info.count);
00728
00729 if (ENTRY_IS_REGION(entry)) {
00730 int_32 rdl = -entry->info.offset;
00731 int_32 ril = rdl/sizeof(*pe) + ndribbles;
00732 int rid = entry->info.offset;
00733
00734 src = (char *)entry->data;
00735 rdlen = entry->rdlen;
00736
00737
00738 if (i == 0 && (h->flags & HEADERFLAG_LEGACY)) {
00739 int_32 stei[4];
00740
00741 legacy = 1;
00742
00743 memcpy(pe+1, src, rdl);
00744 memcpy(te, src + rdl, rdlen);
00745
00746 te += rdlen;
00747
00748 pe->offset = htonl(te - dataStart);
00749 stei[0] = pe->tag;
00750 stei[1] = pe->type;
00751 stei[2] = htonl(-rdl-entry->info.count);
00752 stei[3] = pe->count;
00753
00754 memcpy(te, stei, entry->info.count);
00755
00756 te += entry->info.count;
00757 ril++;
00758 rdlen += entry->info.count;
00759
00760 count = regionSwab(NULL, ril, 0, pe, t, NULL, 0);
00761 if (count != rdlen)
00762 goto errxit;
00763
00764 } else {
00765
00766
00767 memcpy(pe+1, src + sizeof(*pe), ((ril-1) * sizeof(*pe)));
00768 memcpy(te, src + (ril * sizeof(*pe)), rdlen+entry->info.count+drlen);
00769
00770 te += rdlen;
00771 {
00772 entryInfo se = (entryInfo)src;
00773
00774 int off = ntohl(se->offset);
00775 pe->offset = (off) ? htonl(te - dataStart) : htonl(off);
00776 }
00777 te += entry->info.count + drlen;
00778
00779 count = regionSwab(NULL, ril, 0, pe, t, NULL, 0);
00780 if (count != (rdlen + entry->info.count + drlen))
00781 goto errxit;
00782 }
00783
00784
00785 while (i < h->indexUsed && entry->info.offset <= rid+1) {
00786 i++;
00787 entry++;
00788 }
00789 i--;
00790 entry--;
00791 pe += ril;
00792 continue;
00793 }
00794
00795
00796 if (entry->data == NULL || entry->length <= 0)
00797 continue;
00798
00799
00800 type = entry->info.type;
00801 if (typeSizes[type] > 1) {
00802 unsigned diff;
00803 diff = typeSizes[type] - ((te - dataStart) % typeSizes[type]);
00804 if (diff != typeSizes[type]) {
00805
00806 memset(te, 0, diff);
00807
00808 te += diff;
00809 pad += diff;
00810 }
00811 }
00812
00813 pe->offset = htonl(te - dataStart);
00814
00815
00816
00817 switch (entry->info.type) {
00818 case RPM_INT32_TYPE:
00819 count = entry->info.count;
00820 src = entry->data;
00821 while (count--) {
00822 *((int_32 *)te) = htonl(*((int_32 *)src));
00823
00824 te += sizeof(int_32);
00825 src += sizeof(int_32);
00826
00827 }
00828 break;
00829
00830 case RPM_INT16_TYPE:
00831 count = entry->info.count;
00832 src = entry->data;
00833 while (count--) {
00834 *((int_16 *)te) = htons(*((int_16 *)src));
00835
00836 te += sizeof(int_16);
00837 src += sizeof(int_16);
00838
00839 }
00840 break;
00841
00842 default:
00843 memcpy(te, entry->data, entry->length);
00844 te += entry->length;
00845 break;
00846 }
00847
00848 pe++;
00849 }
00850
00851
00852 if (((char *)pe) != dataStart)
00853 goto errxit;
00854 if ((((char *)ei)+len) != te)
00855 goto errxit;
00856
00857 if (lengthPtr)
00858 *lengthPtr = len;
00859
00860 h->flags &= ~HEADERFLAG_SORTED;
00861 headerSort(h);
00862
00863 return (void *) ei;
00864
00865 errxit:
00866
00867 ei = _free(ei);
00868
00869 return (void *) ei;
00870 }
00871
00877 static
00878 void * headerUnload(Header h)
00879
00880 {
00881 int length;
00882
00883 void * uh = doHeaderUnload(h, &length);
00884
00885 return uh;
00886 }
00887
00895 static
00896 indexEntry findEntry( Header h, int_32 tag, int_32 type)
00897
00898 {
00899 indexEntry entry, entry2, last;
00900 struct indexEntry_s key;
00901
00902 if (h == NULL) return NULL;
00903 if (!(h->flags & HEADERFLAG_SORTED)) headerSort(h);
00904
00905 key.info.tag = tag;
00906
00907
00908 entry2 = entry =
00909 bsearch(&key, h->index, h->indexUsed, sizeof(*h->index), indexCmp);
00910
00911 if (entry == NULL)
00912 return NULL;
00913
00914 if (type == RPM_NULL_TYPE)
00915 return entry;
00916
00917
00918 while (entry->info.tag == tag && entry->info.type != type &&
00919 entry > h->index) entry--;
00920
00921 if (entry->info.tag == tag && entry->info.type == type)
00922 return entry;
00923
00924 last = h->index + h->indexUsed;
00925
00926 while (entry2->info.tag == tag && entry2->info.type != type &&
00927 entry2 < last) entry2++;
00928
00929
00930 if (entry->info.tag == tag && entry->info.type == type)
00931 return entry;
00932
00933 return NULL;
00934 }
00935
00945 static
00946 int headerRemoveEntry(Header h, int_32 tag)
00947
00948 {
00949 indexEntry last = h->index + h->indexUsed;
00950 indexEntry entry, first;
00951 int ne;
00952
00953 entry = findEntry(h, tag, RPM_NULL_TYPE);
00954 if (!entry) return 1;
00955
00956
00957 while (entry > h->index && (entry - 1)->info.tag == tag)
00958 entry--;
00959
00960
00961 for (first = entry; first < last; first++) {
00962 void * data;
00963 if (first->info.tag != tag)
00964 break;
00965 data = first->data;
00966 first->data = NULL;
00967 first->length = 0;
00968 if (ENTRY_IN_REGION(first))
00969 continue;
00970 data = _free(data);
00971 }
00972
00973 ne = (first - entry);
00974 if (ne > 0) {
00975 h->indexUsed -= ne;
00976 ne = last - first;
00977
00978 if (ne > 0)
00979 memmove(entry, first, (ne * sizeof(*entry)));
00980
00981 }
00982
00983 return 0;
00984 }
00985
00991 static
00992 Header headerLoad( void * uh)
00993
00994 {
00995 int_32 * ei = (int_32 *) uh;
00996 int_32 il = ntohl(ei[0]);
00997 int_32 dl = ntohl(ei[1]);
00998
00999 size_t pvlen = sizeof(il) + sizeof(dl) +
01000 (il * sizeof(struct entryInfo_s)) + dl;
01001
01002 void * pv = uh;
01003 Header h = NULL;
01004 entryInfo pe;
01005 unsigned char * dataStart;
01006 unsigned char * dataEnd;
01007 indexEntry entry;
01008 int rdlen;
01009 int i;
01010
01011
01012 if (hdrchkTags(il) || hdrchkData(dl))
01013 goto errxit;
01014
01015 ei = (int_32 *) pv;
01016
01017 pe = (entryInfo) &ei[2];
01018
01019 dataStart = (unsigned char *) (pe + il);
01020 dataEnd = dataStart + dl;
01021
01022 h = xcalloc(1, sizeof(*h));
01023
01024 h->hv = *hdrVec;
01025
01026
01027 h->blob = uh;
01028
01029 h->indexAlloced = il + 1;
01030 h->indexUsed = il;
01031 h->index = xcalloc(h->indexAlloced, sizeof(*h->index));
01032 h->flags |= HEADERFLAG_SORTED;
01033 h->nrefs = 0;
01034 h = headerLink(h);
01035
01036
01037
01038
01039
01040 if (ntohl(pe->tag) == 15 &&
01041 ntohl(pe->type) == RPM_STRING_TYPE &&
01042 ntohl(pe->count) == 1)
01043 {
01044 pe->tag = htonl(1079);
01045 }
01046
01047 entry = h->index;
01048 i = 0;
01049 if (!(htonl(pe->tag) < HEADER_I18NTABLE)) {
01050 h->flags |= HEADERFLAG_LEGACY;
01051 entry->info.type = REGION_TAG_TYPE;
01052 entry->info.tag = HEADER_IMAGE;
01053
01054 entry->info.count = REGION_TAG_COUNT;
01055
01056 entry->info.offset = ((unsigned char *)pe - dataStart);
01057
01058
01059 entry->data = pe;
01060
01061 entry->length = pvlen - sizeof(il) - sizeof(dl);
01062 rdlen = regionSwab(entry+1, il, 0, pe, dataStart, dataEnd, entry->info.offset);
01063 #if 0
01064 if (rdlen != dl)
01065 goto errxit;
01066 #endif
01067 entry->rdlen = rdlen;
01068 entry++;
01069 h->indexUsed++;
01070 } else {
01071 int_32 rdl;
01072 int_32 ril;
01073
01074 h->flags &= ~HEADERFLAG_LEGACY;
01075
01076 entry->info.type = htonl(pe->type);
01077 entry->info.count = htonl(pe->count);
01078
01079 if (hdrchkType(entry->info.type))
01080 goto errxit;
01081 if (hdrchkTags(entry->info.count))
01082 goto errxit;
01083
01084 { int off = ntohl(pe->offset);
01085
01086 if (hdrchkData(off))
01087 goto errxit;
01088 if (off) {
01089
01090 size_t nb = REGION_TAG_COUNT;
01091
01092 int_32 * stei;
01093 if (dataStart + off + nb > dataEnd)
01094 goto errxit;
01095 stei = memcpy(alloca(nb), dataStart + off, nb);
01096 rdl = -ntohl(stei[2]);
01097 ril = rdl/sizeof(*pe);
01098 if (hdrchkTags(ril) || hdrchkData(rdl))
01099 goto errxit;
01100 entry->info.tag = htonl(pe->tag);
01101 } else {
01102 ril = il;
01103
01104 rdl = (ril * sizeof(struct entryInfo_s));
01105
01106 entry->info.tag = HEADER_IMAGE;
01107 }
01108 }
01109 entry->info.offset = -rdl;
01110
01111
01112 entry->data = pe;
01113
01114 entry->length = pvlen - sizeof(il) - sizeof(dl);
01115 rdlen = regionSwab(entry+1, ril-1, 0, pe+1, dataStart, dataEnd, entry->info.offset);
01116 if (rdlen < 0)
01117 goto errxit;
01118 entry->rdlen = rdlen;
01119
01120 if (ril < h->indexUsed) {
01121 indexEntry newEntry = entry + ril;
01122 int ne = (h->indexUsed - ril);
01123 int rid = entry->info.offset+1;
01124 int rc;
01125
01126
01127 rc = regionSwab(newEntry, ne, 0, pe+ril, dataStart, dataEnd, rid);
01128 if (rc < 0)
01129 goto errxit;
01130 rdlen += rc;
01131
01132 { indexEntry firstEntry = newEntry;
01133 int save = h->indexUsed;
01134 int j;
01135
01136
01137 h->indexUsed -= ne;
01138 for (j = 0; j < ne; j++, newEntry++) {
01139 (void) headerRemoveEntry(h, newEntry->info.tag);
01140 if (newEntry->info.tag == HEADER_BASENAMES)
01141 (void) headerRemoveEntry(h, HEADER_OLDFILENAMES);
01142 }
01143
01144
01145
01146 if (h->indexUsed < (save - ne)) {
01147 memmove(h->index + h->indexUsed, firstEntry,
01148 (ne * sizeof(*entry)));
01149 }
01150
01151 h->indexUsed += ne;
01152 }
01153 }
01154 }
01155
01156 h->flags &= ~HEADERFLAG_SORTED;
01157 headerSort(h);
01158
01159
01160 return h;
01161
01162
01163 errxit:
01164
01165 if (h) {
01166 h->index = _free(h->index);
01167
01168 h = _free(h);
01169
01170 }
01171
01172
01173 return h;
01174
01175 }
01176
01184 static
01185 Header headerReload( Header h, int tag)
01186
01187 {
01188 Header nh;
01189 int length;
01190
01191
01192 void * uh = doHeaderUnload(h, &length);
01193
01194
01195 h = headerFree(h);
01196
01197 if (uh == NULL)
01198 return NULL;
01199 nh = headerLoad(uh);
01200 if (nh == NULL) {
01201 uh = _free(uh);
01202 return NULL;
01203 }
01204 if (nh->flags & HEADERFLAG_ALLOCATED)
01205 uh = _free(uh);
01206 nh->flags |= HEADERFLAG_ALLOCATED;
01207 if (ENTRY_IS_REGION(nh->index)) {
01208
01209 if (tag == HEADER_SIGNATURES || tag == HEADER_IMMUTABLE)
01210 nh->index[0].info.tag = tag;
01211
01212 }
01213 return nh;
01214 }
01215
01221 static
01222 Header headerCopyLoad(const void * uh)
01223
01224 {
01225 int_32 * ei = (int_32 *) uh;
01226
01227 int_32 il = ntohl(ei[0]);
01228 int_32 dl = ntohl(ei[1]);
01229
01230
01231 size_t pvlen = sizeof(il) + sizeof(dl) +
01232 (il * sizeof(struct entryInfo_s)) + dl;
01233
01234 void * nuh = NULL;
01235 Header h = NULL;
01236
01237
01238
01239 if (!(hdrchkTags(il) || hdrchkData(dl)) && pvlen < headerMaxbytes) {
01240
01241 nuh = memcpy(xmalloc(pvlen), uh, pvlen);
01242
01243 if ((h = headerLoad(nuh)) != NULL)
01244 h->flags |= HEADERFLAG_ALLOCATED;
01245 }
01246
01247
01248 if (h == NULL)
01249 nuh = _free(nuh);
01250
01251 return h;
01252 }
01253
01260 static
01261 Header headerRead(FD_t fd, enum hMagic magicp)
01262
01263 {
01264 int_32 block[4];
01265 int_32 reserved;
01266 int_32 * ei = NULL;
01267 int_32 il;
01268 int_32 dl;
01269 int_32 magic;
01270 Header h = NULL;
01271 size_t len;
01272 int i;
01273
01274 memset(block, 0, sizeof(block));
01275 i = 2;
01276 if (magicp == HEADER_MAGIC_YES)
01277 i += 2;
01278
01279
01280 if (timedRead(fd, (char *)block, i*sizeof(*block)) != (i * sizeof(*block)))
01281 goto exit;
01282
01283
01284 i = 0;
01285
01286
01287 if (magicp == HEADER_MAGIC_YES) {
01288 magic = block[i++];
01289 if (memcmp(&magic, header_magic, sizeof(magic)))
01290 goto exit;
01291 reserved = block[i++];
01292 }
01293
01294 il = ntohl(block[i]); i++;
01295 dl = ntohl(block[i]); i++;
01296
01297
01298
01299 len = sizeof(il) + sizeof(dl) + (il * sizeof(struct entryInfo_s)) + dl;
01300
01301
01302
01303 if (hdrchkTags(il) || hdrchkData(dl) || len > headerMaxbytes)
01304 goto exit;
01305
01306
01307 ei = xmalloc(len);
01308 ei[0] = htonl(il);
01309 ei[1] = htonl(dl);
01310 len -= sizeof(il) + sizeof(dl);
01311
01312
01313
01314
01315 if (timedRead(fd, (char *)&ei[2], len) != len)
01316 goto exit;
01317
01318
01319
01320 h = headerLoad(ei);
01321
01322 exit:
01323 if (h) {
01324 if (h->flags & HEADERFLAG_ALLOCATED)
01325 ei = _free(ei);
01326 h->flags |= HEADERFLAG_ALLOCATED;
01327 } else if (ei)
01328 ei = _free(ei);
01329
01330 return h;
01331
01332 }
01333
01341 static
01342 int headerWrite(FD_t fd, Header h, enum hMagic magicp)
01343
01344
01345 {
01346 ssize_t nb;
01347 int length;
01348 const void * uh;
01349
01350 if (h == NULL)
01351 return 1;
01352
01353 uh = doHeaderUnload(h, &length);
01354
01355 if (uh == NULL)
01356 return 1;
01357 switch (magicp) {
01358 case HEADER_MAGIC_YES:
01359
01360
01361 nb = Fwrite(header_magic, sizeof(char), sizeof(header_magic), fd);
01362
01363
01364 if (nb != sizeof(header_magic))
01365 goto exit;
01366 break;
01367 case HEADER_MAGIC_NO:
01368 break;
01369 }
01370
01371
01372 nb = Fwrite(uh, sizeof(char), length, fd);
01373
01374
01375 exit:
01376 uh = _free(uh);
01377 return (nb == length ? 0 : 1);
01378 }
01379
01386 static
01387 int headerIsEntry(Header h, int_32 tag)
01388
01389 {
01390
01391 return (findEntry(h, tag, RPM_NULL_TYPE) ? 1 : 0);
01392
01393 }
01394
01405 static int copyEntry(const indexEntry entry,
01406 hTYP_t type,
01407 hPTR_t * p,
01408 hCNT_t c,
01409 int minMem)
01410
01411
01412 {
01413 int_32 count = entry->info.count;
01414 int rc = 1;
01415
01416 if (p)
01417 switch (entry->info.type) {
01418 case RPM_BIN_TYPE:
01419
01420
01421
01422
01423
01424
01425 if (ENTRY_IS_REGION(entry)) {
01426 int_32 * ei = ((int_32 *)entry->data) - 2;
01427
01428 entryInfo pe = (entryInfo) (ei + 2);
01429
01430
01431 char * dataStart = (char *) (pe + ntohl(ei[0]));
01432
01433 int_32 rdl = -entry->info.offset;
01434 int_32 ril = rdl/sizeof(*pe);
01435
01436
01437 rdl = entry->rdlen;
01438 count = 2 * sizeof(*ei) + (ril * sizeof(*pe)) + rdl;
01439 if (entry->info.tag == HEADER_IMAGE) {
01440 ril -= 1;
01441 pe += 1;
01442 } else {
01443 count += REGION_TAG_COUNT;
01444 rdl += REGION_TAG_COUNT;
01445 }
01446
01447
01448 *p = xmalloc(count);
01449 ei = (int_32 *) *p;
01450 ei[0] = htonl(ril);
01451 ei[1] = htonl(rdl);
01452
01453
01454 pe = (entryInfo) memcpy(ei + 2, pe, (ril * sizeof(*pe)));
01455
01456
01457 dataStart = (char *) memcpy(pe + ril, dataStart, rdl);
01458
01459
01460
01461 rc = regionSwab(NULL, ril, 0, pe, dataStart, dataStart + rdl, 0);
01462
01463 rc = (rc < 0) ? 0 : 1;
01464 } else {
01465 count = entry->length;
01466 *p = (!minMem
01467 ? memcpy(xmalloc(count), entry->data, count)
01468 : entry->data);
01469 }
01470 break;
01471 case RPM_STRING_TYPE:
01472 if (count == 1) {
01473 *p = entry->data;
01474 break;
01475 }
01476
01477 case RPM_STRING_ARRAY_TYPE:
01478 case RPM_I18NSTRING_TYPE:
01479 { const char ** ptrEntry;
01480
01481 int tableSize = count * sizeof(char *);
01482
01483 char * t;
01484 int i;
01485
01486
01487
01488 if (minMem) {
01489 *p = xmalloc(tableSize);
01490 ptrEntry = (const char **) *p;
01491 t = entry->data;
01492 } else {
01493 t = xmalloc(tableSize + entry->length);
01494 *p = (void *)t;
01495 ptrEntry = (const char **) *p;
01496 t += tableSize;
01497 memcpy(t, entry->data, entry->length);
01498 }
01499
01500
01501 for (i = 0; i < count; i++) {
01502
01503 *ptrEntry++ = t;
01504
01505 t = strchr(t, 0);
01506 t++;
01507 }
01508 } break;
01509
01510 default:
01511 *p = entry->data;
01512 break;
01513 }
01514 if (type) *type = entry->info.type;
01515 if (c) *c = count;
01516 return rc;
01517 }
01518
01537 static int headerMatchLocale(const char *td, const char *l, const char *le)
01538
01539 {
01540 const char *fe;
01541
01542
01543 #if 0
01544 { const char *s, *ll, *CC, *EE, *dd;
01545 char *lbuf, *t.
01546
01547
01548 lbuf = alloca(le - l + 1);
01549 for (s = l, ll = t = lbuf; *s; s++, t++) {
01550 switch (*s) {
01551 case '_':
01552 *t = '\0';
01553 CC = t + 1;
01554 break;
01555 case '.':
01556 *t = '\0';
01557 EE = t + 1;
01558 break;
01559 case '@':
01560 *t = '\0';
01561 dd = t + 1;
01562 break;
01563 default:
01564 *t = *s;
01565 break;
01566 }
01567 }
01568
01569 if (ll)
01570 for (t = ll; *t; t++) *t = tolower(*t);
01571 if (CC)
01572 for (t = CC; *t; t++) *t = toupper(*t);
01573
01574
01575 }
01576 #endif
01577
01578
01579 if (strlen(td) == (le-l) && !strncmp(td, l, (le - l)))
01580 return 1;
01581
01582
01583 for (fe = l; fe < le && *fe != '@'; fe++)
01584 {};
01585 if (fe < le && !strncmp(td, l, (fe - l)))
01586 return 1;
01587
01588
01589 for (fe = l; fe < le && *fe != '.'; fe++)
01590 {};
01591 if (fe < le && !strncmp(td, l, (fe - l)))
01592 return 1;
01593
01594
01595 for (fe = l; fe < le && *fe != '_'; fe++)
01596 {};
01597 if (fe < le && !strncmp(td, l, (fe - l)))
01598 return 2;
01599
01600 return 0;
01601 }
01602
01609 static char *
01610 headerFindI18NString(Header h, indexEntry entry)
01611
01612 {
01613 const char *lang, *l, *le;
01614 indexEntry table;
01615
01616
01617 if ((lang = getenv("LANGUAGE")) == NULL &&
01618 (lang = getenv("LC_ALL")) == NULL &&
01619 (lang = getenv("LC_MESSAGES")) == NULL &&
01620 (lang = getenv("LANG")) == NULL)
01621 return entry->data;
01622
01623
01624 if ((table = findEntry(h, HEADER_I18NTABLE, RPM_STRING_ARRAY_TYPE)) == NULL)
01625 return entry->data;
01626
01627
01628
01629 for (l = lang; *l != '\0'; l = le) {
01630 const char *td;
01631 char *ed, *ed_weak = NULL;
01632 int langNum;
01633
01634 while (*l && *l == ':')
01635 l++;
01636 if (*l == '\0')
01637 break;
01638 for (le = l; *le && *le != ':'; le++)
01639 {};
01640
01641
01642 for (langNum = 0, td = table->data, ed = entry->data;
01643 langNum < entry->info.count;
01644 langNum++, td += strlen(td) + 1, ed += strlen(ed) + 1) {
01645
01646 int match = headerMatchLocale(td, l, le);
01647 if (match == 1) return ed;
01648 else if (match == 2) ed_weak = ed;
01649
01650 }
01651 if (ed_weak) return ed_weak;
01652 }
01653
01654
01655 return entry->data;
01656 }
01657
01668 static int intGetEntry(Header h, int_32 tag,
01669 hTAG_t type,
01670 hPTR_t * p,
01671 hCNT_t c,
01672 int minMem)
01673
01674
01675 {
01676 indexEntry entry;
01677 int rc;
01678
01679
01680
01681 entry = findEntry(h, tag, RPM_NULL_TYPE);
01682
01683 if (entry == NULL) {
01684 if (type) type = 0;
01685 if (p) *p = NULL;
01686 if (c) *c = 0;
01687 return 0;
01688 }
01689
01690 switch (entry->info.type) {
01691 case RPM_I18NSTRING_TYPE:
01692 rc = 1;
01693 if (type) *type = RPM_STRING_TYPE;
01694 if (c) *c = 1;
01695
01696 if (p) *p = headerFindI18NString(h, entry);
01697
01698 break;
01699 default:
01700 rc = copyEntry(entry, type, p, c, minMem);
01701 break;
01702 }
01703
01704
01705 return ((rc == 1) ? 1 : 0);
01706 }
01707
01715 static void * headerFreeTag( Header h,
01716 const void * data, rpmTagType type)
01717
01718 {
01719 if (data) {
01720
01721 if (type == -1 ||
01722 type == RPM_STRING_ARRAY_TYPE ||
01723 type == RPM_I18NSTRING_TYPE ||
01724 type == RPM_BIN_TYPE)
01725 data = _free(data);
01726
01727 }
01728 return NULL;
01729 }
01730
01744 static
01745 int headerGetEntry(Header h, int_32 tag,
01746 hTYP_t type,
01747 void ** p,
01748 hCNT_t c)
01749
01750
01751 {
01752 return intGetEntry(h, tag, type, (hPTR_t *)p, c, 0);
01753 }
01754
01767 static
01768 int headerGetEntryMinMemory(Header h, int_32 tag,
01769 hTYP_t type,
01770 hPTR_t * p,
01771 hCNT_t c)
01772
01773
01774 {
01775 return intGetEntry(h, tag, type, p, c, 1);
01776 }
01777
01778 int headerGetRawEntry(Header h, int_32 tag, int_32 * type, hPTR_t * p,
01779 int_32 * c)
01780 {
01781 indexEntry entry;
01782 int rc;
01783
01784 if (p == NULL) return headerIsEntry(h, tag);
01785
01786
01787
01788 entry = findEntry(h, tag, RPM_NULL_TYPE);
01789
01790 if (!entry) {
01791 if (p) *p = NULL;
01792 if (c) *c = 0;
01793 return 0;
01794 }
01795
01796 rc = copyEntry(entry, type, p, c, 0);
01797
01798
01799 return ((rc == 1) ? 1 : 0);
01800 }
01801
01804 static void copyData(int_32 type, void * dstPtr, const void * srcPtr,
01805 int_32 cnt, int dataLength)
01806
01807 {
01808 switch (type) {
01809 case RPM_STRING_ARRAY_TYPE:
01810 case RPM_I18NSTRING_TYPE:
01811 { const char ** av = (const char **) srcPtr;
01812 char * t = dstPtr;
01813
01814
01815 while (cnt-- > 0 && dataLength > 0) {
01816 const char * s;
01817 if ((s = *av++) == NULL)
01818 continue;
01819 do {
01820 *t++ = *s++;
01821 } while (s[-1] && --dataLength > 0);
01822 }
01823
01824 } break;
01825
01826 default:
01827
01828 memmove(dstPtr, srcPtr, dataLength);
01829
01830 break;
01831 }
01832 }
01833
01842
01843 static void *
01844 grabData(int_32 type, hPTR_t p, int_32 c, int * lengthPtr)
01845
01846
01847 {
01848 void * data = NULL;
01849 int length;
01850
01851 length = dataLength(type, p, c, 0, NULL);
01852
01853 if (length > 0) {
01854 data = xmalloc(length);
01855 copyData(type, data, p, c, length);
01856 }
01857
01858
01859 if (lengthPtr)
01860 *lengthPtr = length;
01861 return data;
01862 }
01863
01878 static
01879 int headerAddEntry(Header h, int_32 tag, int_32 type, const void * p, int_32 c)
01880
01881 {
01882 indexEntry entry;
01883 void * data;
01884 int length;
01885
01886
01887 if (c <= 0)
01888 return 0;
01889
01890 if (hdrchkType(type))
01891 return 0;
01892 if (hdrchkData(c))
01893 return 0;
01894
01895 length = 0;
01896
01897 data = grabData(type, p, c, &length);
01898
01899 if (data == NULL || length <= 0)
01900 return 0;
01901
01902
01903 if (h->indexUsed == h->indexAlloced) {
01904 h->indexAlloced += INDEX_MALLOC_SIZE;
01905 h->index = xrealloc(h->index, h->indexAlloced * sizeof(*h->index));
01906 }
01907
01908
01909 entry = h->index + h->indexUsed;
01910 entry->info.tag = tag;
01911 entry->info.type = type;
01912 entry->info.count = c;
01913 entry->info.offset = 0;
01914 entry->data = data;
01915 entry->length = length;
01916
01917
01918 if (h->indexUsed > 0 && tag < h->index[h->indexUsed-1].info.tag)
01919 h->flags &= ~HEADERFLAG_SORTED;
01920
01921 h->indexUsed++;
01922
01923 return 1;
01924 }
01925
01940 static
01941 int headerAppendEntry(Header h, int_32 tag, int_32 type,
01942 const void * p, int_32 c)
01943
01944 {
01945 indexEntry entry;
01946 int length;
01947
01948 if (type == RPM_STRING_TYPE || type == RPM_I18NSTRING_TYPE) {
01949
01950 return 0;
01951 }
01952
01953
01954 entry = findEntry(h, tag, type);
01955 if (!entry)
01956 return 0;
01957
01958 length = dataLength(type, p, c, 0, NULL);
01959 if (length < 0)
01960 return 0;
01961
01962 if (ENTRY_IN_REGION(entry)) {
01963 char * t = xmalloc(entry->length + length);
01964
01965 memcpy(t, entry->data, entry->length);
01966
01967 entry->data = t;
01968 entry->info.offset = 0;
01969 } else
01970 entry->data = xrealloc(entry->data, entry->length + length);
01971
01972 copyData(type, ((char *) entry->data) + entry->length, p, c, length);
01973
01974 entry->length += length;
01975
01976 entry->info.count += c;
01977
01978 return 1;
01979 }
01980
01991 static
01992 int headerAddOrAppendEntry(Header h, int_32 tag, int_32 type,
01993 const void * p, int_32 c)
01994
01995 {
01996 return (findEntry(h, tag, type)
01997 ? headerAppendEntry(h, tag, type, p, c)
01998 : headerAddEntry(h, tag, type, p, c));
01999 }
02000
02021 static
02022 int headerAddI18NString(Header h, int_32 tag, const char * string,
02023 const char * lang)
02024
02025 {
02026 indexEntry table, entry;
02027 const char ** strArray;
02028 int length;
02029 int ghosts;
02030 int i, langNum;
02031 char * buf;
02032
02033 table = findEntry(h, HEADER_I18NTABLE, RPM_STRING_ARRAY_TYPE);
02034 entry = findEntry(h, tag, RPM_I18NSTRING_TYPE);
02035
02036 if (!table && entry)
02037 return 0;
02038
02039 if (!table && !entry) {
02040 const char * charArray[2];
02041 int count = 0;
02042 if (!lang || (lang[0] == 'C' && lang[1] == '\0')) {
02043
02044 charArray[count++] = "C";
02045
02046 } else {
02047
02048 charArray[count++] = "C";
02049
02050 charArray[count++] = lang;
02051 }
02052 if (!headerAddEntry(h, HEADER_I18NTABLE, RPM_STRING_ARRAY_TYPE,
02053 &charArray, count))
02054 return 0;
02055 table = findEntry(h, HEADER_I18NTABLE, RPM_STRING_ARRAY_TYPE);
02056 }
02057
02058 if (!table)
02059 return 0;
02060
02061 if (!lang) lang = "C";
02062
02063
02064 { const char * l = table->data;
02065 for (langNum = 0; langNum < table->info.count; langNum++) {
02066 if (!strcmp(l, lang)) break;
02067 l += strlen(l) + 1;
02068 }
02069 }
02070
02071 if (langNum >= table->info.count) {
02072 length = strlen(lang) + 1;
02073 if (ENTRY_IN_REGION(table)) {
02074 char * t = xmalloc(table->length + length);
02075 memcpy(t, table->data, table->length);
02076 table->data = t;
02077 table->info.offset = 0;
02078 } else
02079 table->data = xrealloc(table->data, table->length + length);
02080 memmove(((char *)table->data) + table->length, lang, length);
02081 table->length += length;
02082 table->info.count++;
02083 }
02084
02085 if (!entry) {
02086 strArray = alloca(sizeof(*strArray) * (langNum + 1));
02087 for (i = 0; i < langNum; i++)
02088 strArray[i] = "";
02089 strArray[langNum] = string;
02090 return headerAddEntry(h, tag, RPM_I18NSTRING_TYPE, strArray,
02091 langNum + 1);
02092 } else if (langNum >= entry->info.count) {
02093 ghosts = langNum - entry->info.count;
02094
02095 length = strlen(string) + 1 + ghosts;
02096 if (ENTRY_IN_REGION(entry)) {
02097 char * t = xmalloc(entry->length + length);
02098 memcpy(t, entry->data, entry->length);
02099 entry->data = t;
02100 entry->info.offset = 0;
02101 } else
02102 entry->data = xrealloc(entry->data, entry->length + length);
02103
02104 memset(((char *)entry->data) + entry->length, '\0', ghosts);
02105 memmove(((char *)entry->data) + entry->length + ghosts, string, strlen(string)+1);
02106
02107 entry->length += length;
02108 entry->info.count = langNum + 1;
02109 } else {
02110 char *b, *be, *e, *ee, *t;
02111 size_t bn, sn, en;
02112
02113
02114 b = be = e = ee = entry->data;
02115 for (i = 0; i < table->info.count; i++) {
02116 if (i == langNum)
02117 be = ee;
02118 ee += strlen(ee) + 1;
02119 if (i == langNum)
02120 e = ee;
02121 }
02122
02123
02124 bn = (be-b);
02125 sn = strlen(string) + 1;
02126 en = (ee-e);
02127 length = bn + sn + en;
02128 t = buf = xmalloc(length);
02129
02130
02131 memcpy(t, b, bn);
02132 t += bn;
02133
02134 memcpy(t, string, sn);
02135 t += sn;
02136 memcpy(t, e, en);
02137 t += en;
02138
02139
02140
02141 entry->length -= strlen(be) + 1;
02142 entry->length += sn;
02143
02144 if (ENTRY_IN_REGION(entry)) {
02145 entry->info.offset = 0;
02146 } else
02147 entry->data = _free(entry->data);
02148
02149 entry->data = buf;
02150
02151 }
02152
02153 return 0;
02154 }
02155
02166 static
02167 int headerModifyEntry(Header h, int_32 tag, int_32 type,
02168 const void * p, int_32 c)
02169
02170 {
02171 indexEntry entry;
02172 void * oldData;
02173 void * data;
02174 int length;
02175
02176
02177 entry = findEntry(h, tag, type);
02178 if (!entry)
02179 return 0;
02180
02181 length = 0;
02182 data = grabData(type, p, c, &length);
02183 if (data == NULL || length <= 0)
02184 return 0;
02185
02186
02187 while (entry > h->index && (entry - 1)->info.tag == tag)
02188 entry--;
02189
02190
02191
02192 oldData = entry->data;
02193
02194 entry->info.count = c;
02195 entry->info.type = type;
02196 entry->data = data;
02197 entry->length = length;
02198
02199
02200 if (ENTRY_IN_REGION(entry)) {
02201 entry->info.offset = 0;
02202 } else
02203 oldData = _free(oldData);
02204
02205
02206 return 1;
02207 }
02208
02211 static char escapedChar(const char ch)
02212 {
02213 switch (ch) {
02214 case 'a': return '\a';
02215 case 'b': return '\b';
02216 case 'f': return '\f';
02217 case 'n': return '\n';
02218 case 'r': return '\r';
02219 case 't': return '\t';
02220 case 'v': return '\v';
02221 default: return ch;
02222 }
02223 }
02224
02231 static sprintfToken
02232 freeFormat( sprintfToken format, int num)
02233
02234 {
02235 int i;
02236
02237 if (format == NULL) return NULL;
02238
02239 for (i = 0; i < num; i++) {
02240 switch (format[i].type) {
02241 case PTOK_ARRAY:
02242
02243 format[i].u.array.format =
02244 freeFormat(format[i].u.array.format,
02245 format[i].u.array.numTokens);
02246
02247 break;
02248 case PTOK_COND:
02249
02250 format[i].u.cond.ifFormat =
02251 freeFormat(format[i].u.cond.ifFormat,
02252 format[i].u.cond.numIfTokens);
02253 format[i].u.cond.elseFormat =
02254 freeFormat(format[i].u.cond.elseFormat,
02255 format[i].u.cond.numElseTokens);
02256
02257 break;
02258 case PTOK_NONE:
02259 case PTOK_TAG:
02260 case PTOK_STRING:
02261 default:
02262 break;
02263 }
02264 }
02265 format = _free(format);
02266 return NULL;
02267 }
02268
02272 struct headerIterator_s {
02273
02274 Header h;
02275
02276 int next_index;
02277 };
02278
02284 static
02285 HeaderIterator headerFreeIterator( HeaderIterator hi)
02286
02287 {
02288 if (hi != NULL) {
02289 hi->h = headerFree(hi->h);
02290 hi = _free(hi);
02291 }
02292 return hi;
02293 }
02294
02300 static
02301 HeaderIterator headerInitIterator(Header h)
02302
02303 {
02304 HeaderIterator hi = xmalloc(sizeof(*hi));
02305
02306 headerSort(h);
02307
02308 hi->h = headerLink(h);
02309 hi->next_index = 0;
02310 return hi;
02311 }
02312
02322 static
02323 int headerNextIterator(HeaderIterator hi,
02324 hTAG_t tag,
02325 hTYP_t type,
02326 hPTR_t * p,
02327 hCNT_t c)
02328
02329
02330
02331 {
02332 Header h = hi->h;
02333 int slot = hi->next_index;
02334 indexEntry entry = NULL;
02335 int rc;
02336
02337 for (slot = hi->next_index; slot < h->indexUsed; slot++) {
02338 entry = h->index + slot;
02339 if (!ENTRY_IS_REGION(entry))
02340 break;
02341 }
02342 hi->next_index = slot;
02343 if (entry == NULL || slot >= h->indexUsed)
02344 return 0;
02345
02346
02347 hi->next_index++;
02348
02349
02350 if (tag)
02351 *tag = entry->info.tag;
02352
02353 rc = copyEntry(entry, type, p, c, 0);
02354
02355
02356 return ((rc == 1) ? 1 : 0);
02357 }
02358
02364 static
02365 Header headerCopy(Header h)
02366
02367 {
02368 Header nh = headerNew();
02369 HeaderIterator hi;
02370 int_32 tag, type, count;
02371 hPTR_t ptr;
02372
02373
02374 for (hi = headerInitIterator(h);
02375 headerNextIterator(hi, &tag, &type, &ptr, &count);
02376 ptr = headerFreeData((void *)ptr, type))
02377 {
02378 if (ptr) (void) headerAddEntry(nh, tag, type, ptr, count);
02379 }
02380 hi = headerFreeIterator(hi);
02381
02382
02383 return headerReload(nh, HEADER_IMAGE);
02384 }
02385
02388 typedef struct headerSprintfArgs_s {
02389 Header h;
02390 char * fmt;
02391
02392 headerTagTableEntry tags;
02393
02394 headerSprintfExtension exts;
02395
02396 const char * errmsg;
02397 rpmec ec;
02398 sprintfToken format;
02399
02400 HeaderIterator hi;
02401
02402 char * val;
02403 size_t vallen;
02404 size_t alloced;
02405 int numTokens;
02406 int i;
02407 } * headerSprintfArgs;
02408
02414 static headerSprintfArgs hsaInit( headerSprintfArgs hsa)
02415
02416 {
02417 sprintfTag tag =
02418 (hsa->format->type == PTOK_TAG
02419 ? &hsa->format->u.tag :
02420 (hsa->format->type == PTOK_ARRAY
02421 ? &hsa->format->u.array.format->u.tag :
02422 NULL));
02423
02424 if (hsa != NULL) {
02425 hsa->i = 0;
02426 if (tag != NULL && tag->tag == -2)
02427 hsa->hi = headerInitIterator(hsa->h);
02428 }
02429
02430 return hsa;
02431
02432 }
02433
02439
02440 static sprintfToken hsaNext( headerSprintfArgs hsa)
02441
02442 {
02443 sprintfToken fmt = NULL;
02444 sprintfTag tag =
02445 (hsa->format->type == PTOK_TAG
02446 ? &hsa->format->u.tag :
02447 (hsa->format->type == PTOK_ARRAY
02448 ? &hsa->format->u.array.format->u.tag :
02449 NULL));
02450
02451 if (hsa != NULL && hsa->i >= 0 && hsa->i < hsa->numTokens) {
02452 fmt = hsa->format + hsa->i;
02453 if (hsa->hi == NULL) {
02454 hsa->i++;
02455 } else {
02456 int_32 tagno;
02457 int_32 type;
02458 int_32 count;
02459
02460
02461 if (!headerNextIterator(hsa->hi, &tagno, &type, NULL, &count))
02462 fmt = NULL;
02463 tag->tag = tagno;
02464
02465 }
02466 }
02467
02468
02469 return fmt;
02470
02471 }
02472
02478 static headerSprintfArgs hsaFini( headerSprintfArgs hsa)
02479
02480 {
02481 if (hsa != NULL) {
02482 hsa->hi = headerFreeIterator(hsa->hi);
02483 hsa->i = 0;
02484 }
02485
02486 return hsa;
02487
02488 }
02489
02496
02497 static char * hsaReserve(headerSprintfArgs hsa, size_t need)
02498
02499 {
02500 if ((hsa->vallen + need) >= hsa->alloced) {
02501 if (hsa->alloced <= need)
02502 hsa->alloced += need;
02503 hsa->alloced <<= 1;
02504 hsa->val = xrealloc(hsa->val, hsa->alloced+1);
02505 }
02506 return hsa->val + hsa->vallen;
02507 }
02508
02516
02517 static const char * myTagName(headerTagTableEntry tbl, int val)
02518
02519 {
02520 static char name[128];
02521 const char * s;
02522 char *t;
02523
02524 for (; tbl->name != NULL; tbl++) {
02525 if (tbl->val == val)
02526 break;
02527 }
02528 if ((s = tbl->name) == NULL)
02529 return NULL;
02530 s += sizeof("RPMTAG_") - 1;
02531 t = name;
02532 *t++ = *s++;
02533 while (*s != '\0')
02534 *t++ = xtolower(*s++);
02535 *t = '\0';
02536 return name;
02537 }
02538
02546 static int myTagValue(headerTagTableEntry tbl, const char * name)
02547
02548 {
02549 for (; tbl->name != NULL; tbl++) {
02550 if (!xstrcasecmp(tbl->name, name))
02551 return tbl->val;
02552 }
02553 return 0;
02554 }
02555
02562 static int findTag(headerSprintfArgs hsa, sprintfToken token, const char * name)
02563
02564 {
02565 headerSprintfExtension ext;
02566 sprintfTag stag = (token->type == PTOK_COND
02567 ? &token->u.cond.tag : &token->u.tag);
02568
02569 stag->fmt = NULL;
02570 stag->ext = NULL;
02571 stag->extNum = 0;
02572 stag->tag = -1;
02573
02574 if (!strcmp(name, "*")) {
02575 stag->tag = -2;
02576 goto bingo;
02577 }
02578
02579
02580 if (strncmp("RPMTAG_", name, sizeof("RPMTAG_")-1)) {
02581
02582 char * t = alloca(strlen(name) + sizeof("RPMTAG_"));
02583 (void) stpcpy( stpcpy(t, "RPMTAG_"), name);
02584 name = t;
02585
02586 }
02587
02588
02589
02590 for (ext = hsa->exts; ext != NULL && ext->type != HEADER_EXT_LAST;
02591 ext = (ext->type == HEADER_EXT_MORE ? ext->u.more : ext+1))
02592 {
02593 if (ext->name == NULL || ext->type != HEADER_EXT_TAG)
02594 continue;
02595 if (!xstrcasecmp(ext->name, name)) {
02596 stag->ext = ext->u.tagFunction;
02597 stag->extNum = ext - hsa->exts;
02598 goto bingo;
02599 }
02600 }
02601
02602
02603 stag->tag = myTagValue(hsa->tags, name);
02604 if (stag->tag != 0)
02605 goto bingo;
02606
02607 return 1;
02608
02609 bingo:
02610
02611 if (stag->type != NULL)
02612 for (ext = hsa->exts; ext != NULL && ext->type != HEADER_EXT_LAST;
02613 ext = (ext->type == HEADER_EXT_MORE ? ext->u.more : ext+1))
02614 {
02615 if (ext->name == NULL || ext->type != HEADER_EXT_FORMAT)
02616 continue;
02617 if (!strcmp(ext->name, stag->type)) {
02618 stag->fmt = ext->u.formatFunction;
02619 break;
02620 }
02621 }
02622 return 0;
02623 }
02624
02625
02633 static int parseExpression(headerSprintfArgs hsa, sprintfToken token,
02634 char * str, char ** endPtr)
02635
02636 ;
02637
02647 static int parseFormat(headerSprintfArgs hsa, char * str,
02648 sprintfToken * formatPtr, int * numTokensPtr,
02649 char ** endPtr, int state)
02650
02651
02652
02653 {
02654 char * chptr, * start, * next, * dst;
02655 sprintfToken format;
02656 sprintfToken token;
02657 int numTokens;
02658 int i;
02659 int done = 0;
02660
02661
02662 numTokens = 0;
02663 if (str != NULL)
02664 for (chptr = str; *chptr != '\0'; chptr++)
02665 if (*chptr == '%') numTokens++;
02666 numTokens = numTokens * 2 + 1;
02667
02668 format = xcalloc(numTokens, sizeof(*format));
02669 if (endPtr) *endPtr = NULL;
02670
02671
02672 dst = start = str;
02673 numTokens = 0;
02674 token = NULL;
02675 if (start != NULL)
02676 while (*start != '\0') {
02677 switch (*start) {
02678 case '%':
02679
02680 if (*(start + 1) == '%') {
02681 if (token == NULL || token->type != PTOK_STRING) {
02682 token = format + numTokens++;
02683 token->type = PTOK_STRING;
02684
02685 dst = token->u.string.string = start;
02686
02687 }
02688 start++;
02689
02690 *dst++ = *start++;
02691
02692 break;
02693 }
02694
02695 token = format + numTokens++;
02696
02697 *dst++ = '\0';
02698
02699 start++;
02700
02701 if (*start == '|') {
02702 char * newEnd;
02703
02704 start++;
02705
02706 if (parseExpression(hsa, token, start, &newEnd))
02707 {
02708 format = freeFormat(format, numTokens);
02709 return 1;
02710 }
02711
02712 start = newEnd;
02713 break;
02714 }
02715
02716
02717 token->u.tag.format = start;
02718
02719 token->u.tag.pad = 0;
02720 token->u.tag.justOne = 0;
02721 token->u.tag.arrayCount = 0;
02722
02723 chptr = start;
02724 while (*chptr && *chptr != '{' && *chptr != '%') chptr++;
02725 if (!*chptr || *chptr == '%') {
02726 hsa->errmsg = _("missing { after %");
02727 format = freeFormat(format, numTokens);
02728 return 1;
02729 }
02730
02731
02732 *chptr++ = '\0';
02733
02734
02735 while (start < chptr) {
02736 if (xisdigit(*start)) {
02737 i = strtoul(start, &start, 10);
02738 token->u.tag.pad += i;
02739 start = chptr;
02740 break;
02741 } else {
02742 start++;
02743 }
02744 }
02745
02746 if (*start == '=') {
02747 token->u.tag.justOne = 1;
02748 start++;
02749 } else if (*start == '#') {
02750 token->u.tag.justOne = 1;
02751 token->u.tag.arrayCount = 1;
02752 start++;
02753 }
02754
02755 dst = next = start;
02756 while (*next && *next != '}') next++;
02757 if (!*next) {
02758 hsa->errmsg = _("missing } after %{");
02759 format = freeFormat(format, numTokens);
02760 return 1;
02761 }
02762
02763 *next++ = '\0';
02764
02765
02766 chptr = start;
02767 while (*chptr && *chptr != ':') chptr++;
02768
02769 if (*chptr != '\0') {
02770
02771 *chptr++ = '\0';
02772
02773 if (!*chptr) {
02774 hsa->errmsg = _("empty tag format");
02775 format = freeFormat(format, numTokens);
02776 return 1;
02777 }
02778
02779 token->u.tag.type = chptr;
02780
02781 } else {
02782 token->u.tag.type = NULL;
02783 }
02784
02785 if (!*start) {
02786 hsa->errmsg = _("empty tag name");
02787 format = freeFormat(format, numTokens);
02788 return 1;
02789 }
02790
02791 i = 0;
02792 token->type = PTOK_TAG;
02793
02794 if (findTag(hsa, token, start)) {
02795 hsa->errmsg = _("unknown tag");
02796 format = freeFormat(format, numTokens);
02797 return 1;
02798 }
02799
02800 start = next;
02801 break;
02802
02803 case '[':
02804
02805 *dst++ = '\0';
02806 *start++ = '\0';
02807
02808 token = format + numTokens++;
02809
02810
02811 if (parseFormat(hsa, start,
02812 &token->u.array.format,
02813 &token->u.array.numTokens,
02814 &start, PARSER_IN_ARRAY))
02815 {
02816 format = freeFormat(format, numTokens);
02817 return 1;
02818 }
02819
02820
02821 if (!start) {
02822 hsa->errmsg = _("] expected at end of array");
02823 format = freeFormat(format, numTokens);
02824 return 1;
02825 }
02826
02827 dst = start;
02828
02829 token->type = PTOK_ARRAY;
02830
02831 break;
02832
02833 case ']':
02834 if (state != PARSER_IN_ARRAY) {
02835 hsa->errmsg = _("unexpected ]");
02836 format = freeFormat(format, numTokens);
02837 return 1;
02838 }
02839
02840 *start++ = '\0';
02841
02842 if (endPtr) *endPtr = start;
02843 done = 1;
02844 break;
02845
02846 case '}':
02847 if (state != PARSER_IN_EXPR) {
02848 hsa->errmsg = _("unexpected }");
02849 format = freeFormat(format, numTokens);
02850 return 1;
02851 }
02852
02853 *start++ = '\0';
02854
02855 if (endPtr) *endPtr = start;
02856 done = 1;
02857 break;
02858
02859 default:
02860 if (token == NULL || token->type != PTOK_STRING) {
02861 token = format + numTokens++;
02862 token->type = PTOK_STRING;
02863
02864 dst = token->u.string.string = start;
02865
02866 }
02867
02868
02869 if (*start == '\\') {
02870 start++;
02871 *dst++ = escapedChar(*start++);
02872 } else {
02873 *dst++ = *start++;
02874 }
02875
02876 break;
02877 }
02878 if (done)
02879 break;
02880 }
02881
02882
02883
02884 if (dst != NULL)
02885 *dst = '\0';
02886
02887
02888 for (i = 0; i < numTokens; i++) {
02889 token = format + i;
02890 if (token->type == PTOK_STRING)
02891 token->u.string.len = strlen(token->u.string.string);
02892 }
02893
02894 *numTokensPtr = numTokens;
02895 *formatPtr = format;
02896
02897 return 0;
02898 }
02899
02900
02901 static int parseExpression(headerSprintfArgs hsa, sprintfToken token,
02902 char * str, char ** endPtr)
02903 {
02904 char * chptr;
02905 char * end;
02906
02907 hsa->errmsg = NULL;
02908 chptr = str;
02909 while (*chptr && *chptr != '?') chptr++;
02910
02911 if (*chptr != '?') {
02912 hsa->errmsg = _("? expected in expression");
02913 return 1;
02914 }
02915
02916 *chptr++ = '\0';;
02917
02918 if (*chptr != '{') {
02919 hsa->errmsg = _("{ expected after ? in expression");
02920 return 1;
02921 }
02922
02923 chptr++;
02924
02925 if (parseFormat(hsa, chptr, &token->u.cond.ifFormat,
02926 &token->u.cond.numIfTokens, &end, PARSER_IN_EXPR))
02927 return 1;
02928
02929
02930 if (!(end && *end)) {
02931 hsa->errmsg = _("} expected in expression");
02932 token->u.cond.ifFormat =
02933 freeFormat(token->u.cond.ifFormat, token->u.cond.numIfTokens);
02934 return 1;
02935 }
02936
02937 chptr = end;
02938 if (*chptr != ':' && *chptr != '|') {
02939 hsa->errmsg = _(": expected following ? subexpression");
02940 token->u.cond.ifFormat =
02941 freeFormat(token->u.cond.ifFormat, token->u.cond.numIfTokens);
02942 return 1;
02943 }
02944
02945 if (*chptr == '|') {
02946 if (parseFormat(hsa, NULL, &token->u.cond.elseFormat,
02947 &token->u.cond.numElseTokens, &end, PARSER_IN_EXPR))
02948 {
02949 token->u.cond.ifFormat =
02950 freeFormat(token->u.cond.ifFormat, token->u.cond.numIfTokens);
02951 return 1;
02952 }
02953 } else {
02954 chptr++;
02955
02956 if (*chptr != '{') {
02957 hsa->errmsg = _("{ expected after : in expression");
02958 token->u.cond.ifFormat =
02959 freeFormat(token->u.cond.ifFormat, token->u.cond.numIfTokens);
02960 return 1;
02961 }
02962
02963 chptr++;
02964
02965 if (parseFormat(hsa, chptr, &token->u.cond.elseFormat,
02966 &token->u.cond.numElseTokens, &end, PARSER_IN_EXPR))
02967 return 1;
02968
02969
02970 if (!(end && *end)) {
02971 hsa->errmsg = _("} expected in expression");
02972 token->u.cond.ifFormat =
02973 freeFormat(token->u.cond.ifFormat, token->u.cond.numIfTokens);
02974 return 1;
02975 }
02976
02977 chptr = end;
02978 if (*chptr != '|') {
02979 hsa->errmsg = _("| expected at end of expression");
02980 token->u.cond.ifFormat =
02981 freeFormat(token->u.cond.ifFormat, token->u.cond.numIfTokens);
02982 token->u.cond.elseFormat =
02983 freeFormat(token->u.cond.elseFormat, token->u.cond.numElseTokens);
02984 return 1;
02985 }
02986 }
02987
02988 chptr++;
02989
02990 *endPtr = chptr;
02991
02992 token->type = PTOK_COND;
02993
02994 (void) findTag(hsa, token, str);
02995
02996 return 0;
02997 }
02998
02999
03010 static int getExtension(headerSprintfArgs hsa, headerTagTagFunction fn,
03011 hTYP_t typeptr,
03012 hPTR_t * data,
03013 hCNT_t countptr,
03014 rpmec ec)
03015
03016
03017
03018 {
03019 if (!ec->avail) {
03020 if (fn(hsa->h, &ec->type, &ec->data, &ec->count, &ec->freeit))
03021 return 1;
03022 ec->avail = 1;
03023 }
03024
03025 if (typeptr) *typeptr = ec->type;
03026 if (data) *data = ec->data;
03027 if (countptr) *countptr = ec->count;
03028
03029 return 0;
03030 }
03031
03038
03039 static char * formatValue(headerSprintfArgs hsa, sprintfTag tag, int element)
03040
03041 {
03042 char * val = NULL;
03043 size_t need = 0;
03044 char * t, * te;
03045 char buf[20];
03046 int_32 count, type;
03047 hPTR_t data;
03048 unsigned int intVal;
03049 const char ** strarray;
03050 int datafree = 0;
03051 int countBuf;
03052
03053 memset(buf, 0, sizeof(buf));
03054 if (tag->ext) {
03055
03056 if (getExtension(hsa, tag->ext, &type, &data, &count, hsa->ec + tag->extNum))
03057 {
03058 count = 1;
03059 type = RPM_STRING_TYPE;
03060 data = "(none)";
03061 }
03062
03063 } else {
03064
03065 if (!headerGetEntry(hsa->h, tag->tag, &type, (void **)&data, &count)) {
03066 count = 1;
03067 type = RPM_STRING_TYPE;
03068 data = "(none)";
03069 }
03070
03071
03072
03073 switch (type) {
03074 default:
03075 if (element >= count) {
03076
03077 data = headerFreeData(data, type);
03078
03079
03080 hsa->errmsg = _("(index out of range)");
03081 return NULL;
03082 }
03083 break;
03084 case RPM_BIN_TYPE:
03085 case RPM_STRING_TYPE:
03086 break;
03087 }
03088 datafree = 1;
03089 }
03090
03091 if (tag->arrayCount) {
03092
03093 if (datafree)
03094 data = headerFreeData(data, type);
03095
03096
03097 countBuf = count;
03098 data = &countBuf;
03099 count = 1;
03100 type = RPM_INT32_TYPE;
03101 }
03102
03103
03104 (void) stpcpy( stpcpy(buf, "%"), tag->format);
03105
03106
03107
03108 if (data)
03109 switch (type) {
03110 case RPM_STRING_ARRAY_TYPE:
03111 strarray = (const char **)data;
03112
03113 if (tag->fmt)
03114 val = tag->fmt(RPM_STRING_TYPE, strarray[element], buf, tag->pad, element);
03115
03116 if (val) {
03117 need = strlen(val);
03118 } else {
03119 need = strlen(strarray[element]) + tag->pad + 20;
03120 val = xmalloc(need+1);
03121 strcat(buf, "s");
03122
03123 sprintf(val, buf, strarray[element]);
03124
03125 }
03126
03127 break;
03128
03129 case RPM_STRING_TYPE:
03130 if (tag->fmt)
03131 val = tag->fmt(RPM_STRING_TYPE, data, buf, tag->pad, 0);
03132
03133 if (val) {
03134 need = strlen(val);
03135 } else {
03136 need = strlen(data) + tag->pad + 20;
03137 val = xmalloc(need+1);
03138 strcat(buf, "s");
03139
03140 sprintf(val, buf, data);
03141
03142 }
03143 break;
03144
03145 case RPM_CHAR_TYPE:
03146 case RPM_INT8_TYPE:
03147 case RPM_INT16_TYPE:
03148 case RPM_INT32_TYPE:
03149 switch (type) {
03150 case RPM_CHAR_TYPE:
03151 case RPM_INT8_TYPE:
03152 intVal = *(((int_8 *) data) + element);
03153 break;
03154 case RPM_INT16_TYPE:
03155 intVal = *(((uint_16 *) data) + element);
03156 break;
03157 default:
03158 case RPM_INT32_TYPE:
03159 intVal = *(((int_32 *) data) + element);
03160 break;
03161 }
03162
03163 if (tag->fmt)
03164 val = tag->fmt(RPM_INT32_TYPE, &intVal, buf, tag->pad, element);
03165
03166 if (val) {
03167 need = strlen(val);
03168 } else {
03169 need = 10 + tag->pad + 20;
03170 val = xmalloc(need+1);
03171 strcat(buf, "d");
03172
03173 sprintf(val, buf, intVal);
03174
03175 }
03176 break;
03177
03178 case RPM_BIN_TYPE:
03179
03180 if (tag->fmt)
03181 val = tag->fmt(RPM_BIN_TYPE, data, buf, tag->pad, count);
03182
03183 if (val) {
03184 need = strlen(val);
03185 } else {
03186 val = bin2hex(data, count);
03187 need = strlen(val) + tag->pad;
03188 }
03189 break;
03190
03191 default:
03192 need = sizeof("(unknown type)") - 1;
03193 val = xstrdup("(unknown type)");
03194 break;
03195 }
03196
03197
03198
03199 if (datafree)
03200 data = headerFreeData(data, type);
03201
03202
03203
03204 if (val && need > 0) {
03205 t = hsaReserve(hsa, need);
03206
03207 te = stpcpy(t, val);
03208
03209 hsa->vallen += (te - t);
03210 val = _free(val);
03211 }
03212
03213
03214 return (hsa->val + hsa->vallen);
03215 }
03216
03223
03224 static char * singleSprintf(headerSprintfArgs hsa, sprintfToken token,
03225 int element)
03226
03227 {
03228 char * t, * te;
03229 int i, j;
03230 int numElements;
03231 int_32 type;
03232 int_32 count;
03233 sprintfToken spft;
03234 int condNumFormats;
03235 size_t need;
03236
03237
03238
03239 switch (token->type) {
03240 case PTOK_NONE:
03241 break;
03242
03243 case PTOK_STRING:
03244 need = token->u.string.len;
03245 if (need == 0) break;
03246 t = hsaReserve(hsa, need);
03247
03248 te = stpcpy(t, token->u.string.string);
03249
03250 hsa->vallen += (te - t);
03251 break;
03252
03253 case PTOK_TAG:
03254 t = hsa->val + hsa->vallen;
03255 te = formatValue(hsa, &token->u.tag,
03256 (token->u.tag.justOne ? 0 : element));
03257 if (te == NULL)
03258 return NULL;
03259 break;
03260
03261 case PTOK_COND:
03262 if (token->u.cond.tag.ext || headerIsEntry(hsa->h, token->u.cond.tag.tag)) {
03263 spft = token->u.cond.ifFormat;
03264 condNumFormats = token->u.cond.numIfTokens;
03265 } else {
03266 spft = token->u.cond.elseFormat;
03267 condNumFormats = token->u.cond.numElseTokens;
03268 }
03269
03270 need = condNumFormats * 20;
03271 if (spft == NULL || need == 0) break;
03272
03273 t = hsaReserve(hsa, need);
03274 for (i = 0; i < condNumFormats; i++, spft++) {
03275 te = singleSprintf(hsa, spft, element);
03276 if (te == NULL)
03277 return NULL;
03278 }
03279 break;
03280
03281 case PTOK_ARRAY:
03282 numElements = -1;
03283 spft = token->u.array.format;
03284 for (i = 0; i < token->u.array.numTokens; i++, spft++)
03285 {
03286 if (spft->type != PTOK_TAG ||
03287 spft->u.tag.arrayCount ||
03288 spft->u.tag.justOne) continue;
03289
03290 if (spft->u.tag.ext) {
03291
03292 if (getExtension(hsa, spft->u.tag.ext, &type, NULL, &count,
03293 hsa->ec + spft->u.tag.extNum))
03294 continue;
03295
03296 } else {
03297
03298 if (!headerGetEntry(hsa->h, spft->u.tag.tag, &type, NULL, &count))
03299 continue;
03300
03301 }
03302
03303 if (type == RPM_BIN_TYPE)
03304 count = 1;
03305
03306 if (numElements > 1 && count != numElements)
03307 switch (type) {
03308 default:
03309 hsa->errmsg =
03310 _("array iterator used with different sized arrays");
03311 return NULL;
03312 break;
03313 case RPM_BIN_TYPE:
03314 case RPM_STRING_TYPE:
03315 break;
03316 }
03317 if (count > numElements)
03318 numElements = count;
03319 }
03320
03321 if (numElements == -1) {
03322 need = sizeof("(none)") - 1;
03323 t = hsaReserve(hsa, need);
03324
03325 te = stpcpy(t, "(none)");
03326
03327 hsa->vallen += (te - t);
03328 } else {
03329 int isxml;
03330
03331 need = numElements * token->u.array.numTokens * 10;
03332 if (need == 0) break;
03333
03334 spft = token->u.array.format;
03335 isxml = (spft->type == PTOK_TAG && spft->u.tag.type != NULL &&
03336 !strcmp(spft->u.tag.type, "xml"));
03337
03338 if (isxml) {
03339 const char * tagN = myTagName(hsa->tags, spft->u.tag.tag);
03340
03341 need = sizeof(" <rpmTag name=\"\">\n") - 1;
03342 if (tagN != NULL)
03343 need += strlen(tagN);
03344 t = hsaReserve(hsa, need);
03345
03346 te = stpcpy(t, " <rpmTag name=\"");
03347 if (tagN != NULL)
03348 te = stpcpy(te, tagN);
03349 te = stpcpy(te, "\">\n");
03350
03351 hsa->vallen += (te - t);
03352 }
03353
03354 t = hsaReserve(hsa, need);
03355 for (j = 0; j < numElements; j++) {
03356 spft = token->u.array.format;
03357 for (i = 0; i < token->u.array.numTokens; i++, spft++) {
03358 te = singleSprintf(hsa, spft, j);
03359 if (te == NULL)
03360 return NULL;
03361 }
03362 }
03363
03364 if (isxml) {
03365 need = sizeof(" </rpmTag>\n") - 1;
03366 t = hsaReserve(hsa, need);
03367
03368 te = stpcpy(t, " </rpmTag>\n");
03369
03370 hsa->vallen += (te - t);
03371 }
03372
03373 }
03374 break;
03375 }
03376
03377 return (hsa->val + hsa->vallen);
03378 }
03379
03385 static rpmec
03386 rpmecNew(const headerSprintfExtension exts)
03387
03388 {
03389 headerSprintfExtension ext;
03390 rpmec ec;
03391 int i = 0;
03392
03393 for (ext = exts; ext != NULL && ext->type != HEADER_EXT_LAST;
03394 ext = (ext->type == HEADER_EXT_MORE ? ext->u.more : ext+1))
03395 {
03396 i++;
03397 }
03398
03399 ec = xcalloc(i, sizeof(*ec));
03400 return ec;
03401 }
03402
03409 static rpmec
03410 rpmecFree(const headerSprintfExtension exts, rpmec ec)
03411
03412 {
03413 headerSprintfExtension ext;
03414 int i = 0;
03415
03416 for (ext = exts; ext != NULL && ext->type != HEADER_EXT_LAST;
03417 ext = (ext->type == HEADER_EXT_MORE ? ext->u.more : ext+1))
03418 {
03419
03420 if (ec[i].freeit) ec[i].data = _free(ec[i].data);
03421
03422 i++;
03423 }
03424
03425 ec = _free(ec);
03426 return NULL;
03427 }
03428
03440 static
03441 char * headerSprintf(Header h, const char * fmt,
03442 const struct headerTagTableEntry_s * tbltags,
03443 const struct headerSprintfExtension_s * extensions,
03444 errmsg_t * errmsg)
03445
03446
03447 {
03448 headerSprintfArgs hsa = memset(alloca(sizeof(*hsa)), 0, sizeof(*hsa));
03449 sprintfToken nextfmt;
03450 sprintfTag tag;
03451 char * t, * te;
03452 int isxml;
03453 int need;
03454
03455 hsa->h = headerLink(h);
03456 hsa->fmt = xstrdup(fmt);
03457
03458 hsa->exts = (headerSprintfExtension) extensions;
03459 hsa->tags = (headerTagTableEntry) tbltags;
03460
03461 hsa->errmsg = NULL;
03462
03463
03464 if (parseFormat(hsa, hsa->fmt, &hsa->format, &hsa->numTokens, NULL, PARSER_BEGIN))
03465 goto exit;
03466
03467
03468 hsa->ec = rpmecNew(hsa->exts);
03469 hsa->val = xstrdup("");
03470
03471 tag =
03472 (hsa->format->type == PTOK_TAG
03473 ? &hsa->format->u.tag :
03474 (hsa->format->type == PTOK_ARRAY
03475 ? &hsa->format->u.array.format->u.tag :
03476 NULL));
03477 isxml = (tag != NULL && tag->tag == -2 && tag->type != NULL && !strcmp(tag->type, "xml"));
03478
03479 if (isxml) {
03480 need = sizeof("<rpmHeader>\n") - 1;
03481 t = hsaReserve(hsa, need);
03482
03483 te = stpcpy(t, "<rpmHeader>\n");
03484
03485 hsa->vallen += (te - t);
03486 }
03487
03488 hsa = hsaInit(hsa);
03489 while ((nextfmt = hsaNext(hsa)) != NULL) {
03490 te = singleSprintf(hsa, nextfmt, 0);
03491 if (te == NULL) {
03492 hsa->val = _free(hsa->val);
03493 break;
03494 }
03495 }
03496 hsa = hsaFini(hsa);
03497
03498 if (isxml) {
03499 need = sizeof("</rpmHeader>\n") - 1;
03500 t = hsaReserve(hsa, need);
03501
03502 te = stpcpy(t, "</rpmHeader>\n");
03503
03504 hsa->vallen += (te - t);
03505 }
03506
03507 if (hsa->val != NULL && hsa->vallen < hsa->alloced)
03508 hsa->val = xrealloc(hsa->val, hsa->vallen+1);
03509
03510 hsa->ec = rpmecFree(hsa->exts, hsa->ec);
03511 hsa->format = freeFormat(hsa->format, hsa->numTokens);
03512
03513 exit:
03514
03515 if (errmsg)
03516 *errmsg = hsa->errmsg;
03517
03518 hsa->h = headerFree(hsa->h);
03519 hsa->fmt = _free(hsa->fmt);
03520 return hsa->val;
03521 }
03522
03531 static char * octalFormat(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, "o");
03543
03544
03545 sprintf(val, formatPrefix, *((int_32 *) data));
03546
03547 }
03548
03549 return val;
03550 }
03551
03560 static char * hexFormat(int_32 type, hPTR_t data,
03561 char * formatPrefix, int padding, int element)
03562
03563 {
03564 char * val;
03565
03566 if (type != RPM_INT32_TYPE) {
03567 val = xstrdup(_("(not a number)"));
03568 } else {
03569 val = xmalloc(20 + padding);
03570
03571 strcat(formatPrefix, "x");
03572
03573
03574 sprintf(val, formatPrefix, *((int_32 *) data));
03575
03576 }
03577
03578 return val;
03579 }
03580
03583 static char * realDateFormat(int_32 type, hPTR_t data,
03584 char * formatPrefix, int padding, int element,
03585 const char * strftimeFormat)
03586
03587 {
03588 char * val;
03589
03590 if (type != RPM_INT32_TYPE) {
03591 val = xstrdup(_("(not a number)"));
03592 } else {
03593 struct tm * tstruct;
03594 char buf[50];
03595
03596 val = xmalloc(50 + padding);
03597
03598 strcat(formatPrefix, "s");
03599
03600
03601
03602 { time_t dateint = *((int_32 *) data);
03603 tstruct = localtime(&dateint);
03604 }
03605 buf[0] = '\0';
03606 if (tstruct)
03607 (void) strftime(buf, sizeof(buf) - 1, strftimeFormat, tstruct);
03608
03609 sprintf(val, formatPrefix, buf);
03610
03611 }
03612
03613 return val;
03614 }
03615
03624 static char * dateFormat(int_32 type, hPTR_t data,
03625 char * formatPrefix, int padding, int element)
03626
03627 {
03628 return realDateFormat(type, data, formatPrefix, padding, element,
03629 _("%c"));
03630 }
03631
03640 static char * dayFormat(int_32 type, hPTR_t data,
03641 char * formatPrefix, int padding, int element)
03642
03643 {
03644 return realDateFormat(type, data, formatPrefix, padding, element,
03645 _("%a %b %d %Y"));
03646 }
03647
03656 static char * shescapeFormat(int_32 type, hPTR_t data,
03657 char * formatPrefix, int padding, int element)
03658
03659 {
03660 char * result, * dst, * src, * buf;
03661
03662 if (type == RPM_INT32_TYPE) {
03663 result = xmalloc(padding + 20);
03664
03665 strcat(formatPrefix, "d");
03666
03667
03668 sprintf(result, formatPrefix, *((int_32 *) data));
03669
03670 } else {
03671 buf = alloca(strlen(data) + padding + 2);
03672
03673 strcat(formatPrefix, "s");
03674
03675
03676 sprintf(buf, formatPrefix, data);
03677
03678
03679
03680 result = dst = xmalloc(strlen(buf) * 4 + 3);
03681 *dst++ = '\'';
03682 for (src = buf; *src != '\0'; src++) {
03683 if (*src == '\'') {
03684 *dst++ = '\'';
03685 *dst++ = '\\';
03686 *dst++ = '\'';
03687 *dst++ = '\'';
03688 } else {
03689 *dst++ = *src;
03690 }
03691 }
03692 *dst++ = '\'';
03693 *dst = '\0';
03694
03695
03696 }
03697
03698 return result;
03699 }
03700
03701
03702 const struct headerSprintfExtension_s headerDefaultFormats[] = {
03703 { HEADER_EXT_FORMAT, "octal", { octalFormat } },
03704 { HEADER_EXT_FORMAT, "hex", { hexFormat } },
03705 { HEADER_EXT_FORMAT, "date", { dateFormat } },
03706 { HEADER_EXT_FORMAT, "day", { dayFormat } },
03707 { HEADER_EXT_FORMAT, "shescape", { shescapeFormat } },
03708 { HEADER_EXT_LAST, NULL, { NULL } }
03709 };
03710
03711
03718 static
03719 void headerCopyTags(Header headerFrom, Header headerTo, hTAG_t tagstocopy)
03720
03721 {
03722 int * p;
03723
03724 if (headerFrom == headerTo)
03725 return;
03726
03727 for (p = tagstocopy; *p != 0; p++) {
03728 char *s;
03729 int_32 type;
03730 int_32 count;
03731 if (headerIsEntry(headerTo, *p))
03732 continue;
03733
03734 if (!headerGetEntryMinMemory(headerFrom, *p, &type,
03735 (hPTR_t *) &s, &count))
03736 continue;
03737
03738 (void) headerAddEntry(headerTo, *p, type, s, count);
03739 s = headerFreeData(s, type);
03740 }
03741 }
03742
03743
03744 static struct HV_s hdrVec1 = {
03745 headerLink,
03746 headerUnlink,
03747 headerFree,
03748 headerNew,
03749 headerSort,
03750 headerUnsort,
03751 headerSizeof,
03752 headerUnload,
03753 headerReload,
03754 headerCopy,
03755 headerLoad,
03756 headerCopyLoad,
03757 headerRead,
03758 headerWrite,
03759 headerIsEntry,
03760 headerFreeTag,
03761 headerGetEntry,
03762 headerGetEntryMinMemory,
03763 headerAddEntry,
03764 headerAppendEntry,
03765 headerAddOrAppendEntry,
03766 headerAddI18NString,
03767 headerModifyEntry,
03768 headerRemoveEntry,
03769 headerSprintf,
03770 headerCopyTags,
03771 headerFreeIterator,
03772 headerInitIterator,
03773 headerNextIterator,
03774 NULL, NULL,
03775 1
03776 };
03777
03778
03779
03780 HV_t hdrVec = &hdrVec1;
03781