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