00001
00005
00006
00007
00008
00009
00010
00011 #include "system.h"
00012
00013 #define __HEADER_PROTOTYPES__
00014
00015 #include <header_internal.h>
00016
00017 #include "debug.h"
00018
00019
00020 int _hdr_debug = 0;
00021
00022
00023 const char *const tagName(int tag) ;
00024
00025
00026
00027
00028
00029
00030
00031
00032
00033
00034 #define PARSER_BEGIN 0
00035 #define PARSER_IN_ARRAY 1
00036 #define PARSER_IN_EXPR 2
00037
00040
00041 static unsigned char header_magic[8] = {
00042 0x8e, 0xad, 0xe8, 0x01, 0x00, 0x00, 0x00, 0x00
00043 };
00044
00048
00049 static int typeAlign[16] = {
00050 1,
00051 1,
00052 1,
00053 2,
00054 4,
00055 8,
00056 1,
00057 1,
00058 1,
00059 1,
00060 0,
00061 0,
00062 0,
00063 0,
00064 0,
00065 0
00066 };
00067
00071
00072 static int typeSizes[16] = {
00073 0,
00074 1,
00075 1,
00076 2,
00077 4,
00078 -1,
00079 -1,
00080 1,
00081 -1,
00082 -1,
00083 0,
00084 0,
00085 0,
00086 0,
00087 0,
00088 0
00089 };
00090
00094
00095 static size_t headerMaxbytes = (32*1024*1024);
00096
00101 #define hdrchkTags(_ntags) ((_ntags) & 0xffff0000)
00102
00106 #define hdrchkType(_type) ((_type) < RPM_MIN_TYPE || (_type) > RPM_MAX_TYPE)
00107
00112 #define hdrchkData(_nbytes) ((_nbytes) & 0xff000000)
00113
00117 #define hdrchkAlign(_type, _off) ((_off) & (typeAlign[_type]-1))
00118
00122 #define hdrchkRange(_dl, _off) ((_off) < 0 || (_off) > (_dl))
00123
00124
00125 HV_t hdrVec;
00126
00132 static inline void *
00133 _free( const void * p)
00134 {
00135 if (p != NULL) free((void *)p);
00136 return NULL;
00137 }
00138
00144 static
00145 Header headerLink(Header h)
00146
00147 {
00148
00149 if (h == NULL) return NULL;
00150
00151
00152 h->nrefs++;
00153
00154 if (_hdr_debug)
00155 fprintf(stderr, "--> h %p ++ %d at %s:%u\n", h, h->nrefs, __FILE__, __LINE__);
00156
00157
00158
00159 return h;
00160
00161 }
00162
00168 static
00169 Header headerUnlink( Header h)
00170
00171 {
00172 if (h == NULL) return NULL;
00173
00174 if (_hdr_debug)
00175 fprintf(stderr, "--> h %p -- %d at %s:%u\n", h, h->nrefs, __FILE__, __LINE__);
00176
00177 h->nrefs--;
00178 return NULL;
00179 }
00180
00186 static
00187 Header headerFree( Header h)
00188
00189 {
00190 (void) headerUnlink(h);
00191
00192
00193 if (h == NULL || h->nrefs > 0)
00194 return NULL;
00195
00196 if (h->index) {
00197 indexEntry entry = h->index;
00198 int i;
00199 for (i = 0; i < h->indexUsed; i++, entry++) {
00200 if ((h->flags & HEADERFLAG_ALLOCATED) && ENTRY_IS_REGION(entry)) {
00201 if (entry->length > 0) {
00202 int_32 * ei = entry->data;
00203 if ((ei - 2) == h->blob) h->blob = _free(h->blob);
00204 entry->data = NULL;
00205 }
00206 } else if (!ENTRY_IN_REGION(entry)) {
00207 entry->data = _free(entry->data);
00208 }
00209 entry->data = NULL;
00210 }
00211 h->index = _free(h->index);
00212 }
00213
00214 h = _free(h);
00215 return h;
00216
00217 }
00218
00223 static
00224 Header headerNew(void)
00225
00226 {
00227 Header h = xcalloc(1, sizeof(*h));
00228
00229
00230
00231 h->hv = *hdrVec;
00232
00233
00234 h->blob = NULL;
00235 h->indexAlloced = INDEX_MALLOC_SIZE;
00236 h->indexUsed = 0;
00237 h->flags |= HEADERFLAG_SORTED;
00238
00239 h->index = (h->indexAlloced
00240 ? xcalloc(h->indexAlloced, sizeof(*h->index))
00241 : NULL);
00242
00243 h->nrefs = 0;
00244
00245 return headerLink(h);
00246
00247 }
00248
00251 static int indexCmp(const void * avp, const void * bvp)
00252
00253 {
00254
00255 indexEntry ap = (indexEntry) avp, bp = (indexEntry) bvp;
00256
00257 return (ap->info.tag - bp->info.tag);
00258 }
00259
00264 static
00265 void headerSort(Header h)
00266
00267 {
00268 if (!(h->flags & HEADERFLAG_SORTED)) {
00269
00270 qsort(h->index, h->indexUsed, sizeof(*h->index), indexCmp);
00271
00272 h->flags |= HEADERFLAG_SORTED;
00273 }
00274 }
00275
00278 static int offsetCmp(const void * avp, const void * bvp)
00279 {
00280
00281 indexEntry ap = (indexEntry) avp, bp = (indexEntry) bvp;
00282
00283 int rc = (ap->info.offset - bp->info.offset);
00284
00285 if (rc == 0) {
00286
00287 if (ap->info.offset < 0)
00288 rc = (((char *)ap->data) - ((char *)bp->data));
00289 else
00290 rc = (ap->info.tag - bp->info.tag);
00291 }
00292 return rc;
00293 }
00294
00299 static
00300 void headerUnsort(Header h)
00301
00302 {
00303
00304 qsort(h->index, h->indexUsed, sizeof(*h->index), offsetCmp);
00305
00306 }
00307
00314 static
00315 unsigned int headerSizeof( Header h, enum hMagic magicp)
00316
00317 {
00318 indexEntry entry;
00319 unsigned int size = 0;
00320 unsigned int pad = 0;
00321 int i;
00322
00323 if (h == NULL)
00324 return size;
00325
00326 headerSort(h);
00327
00328 switch (magicp) {
00329 case HEADER_MAGIC_YES:
00330 size += sizeof(header_magic);
00331 break;
00332 case HEADER_MAGIC_NO:
00333 break;
00334 }
00335
00336
00337 size += 2 * sizeof(int_32);
00338
00339
00340 for (i = 0, entry = h->index; i < h->indexUsed; i++, entry++) {
00341 unsigned diff;
00342 int_32 type;
00343
00344
00345 if (ENTRY_IS_REGION(entry)) {
00346 size += entry->length;
00347
00348
00349 if (i == 0 && (h->flags & HEADERFLAG_LEGACY))
00350 size += sizeof(struct entryInfo_s) + entry->info.count;
00351
00352 continue;
00353 }
00354
00355
00356 if (entry->info.offset < 0)
00357 continue;
00358
00359
00360 type = entry->info.type;
00361
00362 if (typeSizes[type] > 1) {
00363 diff = typeSizes[type] - (size % typeSizes[type]);
00364 if (diff != typeSizes[type]) {
00365 size += diff;
00366 pad += diff;
00367 }
00368 }
00369
00370
00371
00372 size += sizeof(struct entryInfo_s) + entry->length;
00373
00374 }
00375
00376 return size;
00377 }
00378
00388 static int dataLength(int_32 type, hPTR_t p, int_32 count, int onDisk,
00389 hPTR_t pend)
00390
00391 {
00392 const unsigned char * s = p;
00393 const unsigned char * se = pend;
00394 int length = 0;
00395
00396 switch (type) {
00397 case RPM_STRING_TYPE:
00398 if (count != 1)
00399 return -1;
00400
00401 while (*s++) {
00402 if (se && s > se)
00403 return -1;
00404 length++;
00405 }
00406
00407 length++;
00408 break;
00409
00410 case RPM_STRING_ARRAY_TYPE:
00411 case RPM_I18NSTRING_TYPE:
00412
00413
00414
00415 if (onDisk) {
00416 while (count--) {
00417 length++;
00418
00419 while (*s++) {
00420 if (se && s > se)
00421 return -1;
00422 length++;
00423 }
00424
00425 }
00426 } else {
00427 const char ** av = (const char **)p;
00428
00429 while (count--) {
00430
00431 length += strlen(*av++) + 1;
00432 }
00433
00434 }
00435 break;
00436
00437 default:
00438
00439 if (typeSizes[type] == -1)
00440 return -1;
00441 length = typeSizes[(type & 0xf)] * count;
00442
00443 if (length < 0 || (se && (s + length) > se))
00444 return -1;
00445 break;
00446 }
00447
00448 return length;
00449 }
00450
00477 static int regionSwab( indexEntry entry, int il, int dl,
00478 entryInfo pe,
00479 unsigned char * dataStart,
00480 const unsigned char * dataEnd,
00481 int regionid)
00482
00483 {
00484 unsigned char * tprev = NULL;
00485 unsigned char * t = NULL;
00486 int tdel, tl = dl;
00487 struct indexEntry_s ieprev;
00488
00489
00490 memset(&ieprev, 0, sizeof(ieprev));
00491
00492 for (; il > 0; il--, pe++) {
00493 struct indexEntry_s ie;
00494 int_32 type;
00495
00496 ie.info.tag = ntohl(pe->tag);
00497 ie.info.type = ntohl(pe->type);
00498 ie.info.count = ntohl(pe->count);
00499 ie.info.offset = ntohl(pe->offset);
00500
00501 if (hdrchkType(ie.info.type))
00502 return -1;
00503 if (hdrchkData(ie.info.count))
00504 return -1;
00505 if (hdrchkData(ie.info.offset))
00506 return -1;
00507
00508 if (hdrchkAlign(ie.info.type, ie.info.offset))
00509 return -1;
00510
00511
00512 ie.data = t = dataStart + ie.info.offset;
00513 if (dataEnd && t >= dataEnd)
00514 return -1;
00515
00516 ie.length = dataLength(ie.info.type, ie.data, ie.info.count, 1, dataEnd);
00517 if (ie.length < 0 || hdrchkData(ie.length))
00518 return -1;
00519
00520 ie.rdlen = 0;
00521
00522 if (entry) {
00523 ie.info.offset = regionid;
00524
00525 *entry = ie;
00526
00527 entry++;
00528 }
00529
00530
00531 type = ie.info.type;
00532
00533 if (typeSizes[type] > 1) {
00534 unsigned diff;
00535 diff = typeSizes[type] - (dl % typeSizes[type]);
00536 if (diff != typeSizes[type]) {
00537 dl += diff;
00538 if (ieprev.info.type == RPM_I18NSTRING_TYPE)
00539 ieprev.length += diff;
00540 }
00541 }
00542
00543 tdel = (tprev ? (t - tprev) : 0);
00544 if (ieprev.info.type == RPM_I18NSTRING_TYPE)
00545 tdel = ieprev.length;
00546
00547 if (ie.info.tag >= HEADER_I18NTABLE) {
00548 tprev = t;
00549 } else {
00550 tprev = dataStart;
00551
00552
00553 if (ie.info.tag == HEADER_IMAGE)
00554 tprev -= REGION_TAG_COUNT;
00555
00556 }
00557
00558
00559 switch (ntohl(pe->type)) {
00560
00561 case RPM_INT32_TYPE:
00562 { int_32 * it = (int_32 *)t;
00563 for (; ie.info.count > 0; ie.info.count--, it += 1) {
00564 if (dataEnd && ((unsigned char *)it) >= dataEnd)
00565 return -1;
00566 *it = htonl(*it);
00567 }
00568 t = (char *) it;
00569 } break;
00570 case RPM_INT16_TYPE:
00571 { int_16 * it = (int_16 *) t;
00572 for (; ie.info.count > 0; ie.info.count--, it += 1) {
00573 if (dataEnd && ((unsigned char *)it) >= dataEnd)
00574 return -1;
00575 *it = htons(*it);
00576 }
00577 t = (char *) it;
00578 } break;
00579
00580 default:
00581 t += ie.length;
00582 break;
00583 }
00584
00585 dl += ie.length;
00586 tl += tdel;
00587 ieprev = ie;
00588
00589 }
00590 tdel = (tprev ? (t - tprev) : 0);
00591 tl += tdel;
00592
00593
00594
00595
00596
00597
00598
00599 if (tl+REGION_TAG_COUNT == dl)
00600 tl += REGION_TAG_COUNT;
00601
00602
00603 return dl;
00604 }
00605
00608 static void * doHeaderUnload(Header h,
00609 int * lengthPtr)
00610
00611
00612
00613 {
00614 int_32 * ei = NULL;
00615 entryInfo pe;
00616 char * dataStart;
00617 char * te;
00618 unsigned pad;
00619 unsigned len;
00620 int_32 il = 0;
00621 int_32 dl = 0;
00622 indexEntry entry;
00623 int_32 type;
00624 int i;
00625 int drlen, ndribbles;
00626 int driplen, ndrips;
00627 int legacy = 0;
00628
00629
00630 headerUnsort(h);
00631
00632
00633 pad = 0;
00634 drlen = ndribbles = driplen = ndrips = 0;
00635 for (i = 0, entry = h->index; i < h->indexUsed; i++, entry++) {
00636 if (ENTRY_IS_REGION(entry)) {
00637 int_32 rdl = -entry->info.offset;
00638 int_32 ril = rdl/sizeof(*pe);
00639 int rid = entry->info.offset;
00640
00641 il += ril;
00642 dl += entry->rdlen + entry->info.count;
00643
00644 if (i == 0 && (h->flags & HEADERFLAG_LEGACY))
00645 il += 1;
00646
00647
00648 for (; i < h->indexUsed && entry->info.offset <= rid+1; i++, entry++) {
00649 if (entry->info.offset <= rid)
00650 continue;
00651
00652
00653 type = entry->info.type;
00654 if (typeSizes[type] > 1) {
00655 unsigned diff;
00656 diff = typeSizes[type] - (dl % typeSizes[type]);
00657 if (diff != typeSizes[type]) {
00658 drlen += diff;
00659 pad += diff;
00660 dl += diff;
00661 }
00662 }
00663
00664 ndribbles++;
00665 il++;
00666 drlen += entry->length;
00667 dl += entry->length;
00668 }
00669 i--;
00670 entry--;
00671 continue;
00672 }
00673
00674
00675 if (entry->data == NULL || entry->length <= 0)
00676 continue;
00677
00678
00679 type = entry->info.type;
00680 if (typeSizes[type] > 1) {
00681 unsigned diff;
00682 diff = typeSizes[type] - (dl % typeSizes[type]);
00683 if (diff != typeSizes[type]) {
00684 driplen += diff;
00685 pad += diff;
00686 dl += diff;
00687 } else
00688 diff = 0;
00689 }
00690
00691 ndrips++;
00692 il++;
00693 driplen += entry->length;
00694 dl += entry->length;
00695 }
00696
00697
00698 if (hdrchkTags(il) || hdrchkData(dl))
00699 goto errxit;
00700
00701 len = sizeof(il) + sizeof(dl) + (il * sizeof(*pe)) + dl;
00702
00703
00704 ei = xmalloc(len);
00705 ei[0] = htonl(il);
00706 ei[1] = htonl(dl);
00707
00708
00709 pe = (entryInfo) &ei[2];
00710 dataStart = te = (char *) (pe + il);
00711
00712 pad = 0;
00713 for (i = 0, entry = h->index; i < h->indexUsed; i++, entry++) {
00714 const char * src;
00715 char *t;
00716 int count;
00717 int rdlen;
00718
00719 if (entry->data == NULL || entry->length <= 0)
00720 continue;
00721
00722 t = te;
00723 pe->tag = htonl(entry->info.tag);
00724 pe->type = htonl(entry->info.type);
00725 pe->count = htonl(entry->info.count);
00726
00727 if (ENTRY_IS_REGION(entry)) {
00728 int_32 rdl = -entry->info.offset;
00729 int_32 ril = rdl/sizeof(*pe) + ndribbles;
00730 int rid = entry->info.offset;
00731
00732 src = (char *)entry->data;
00733 rdlen = entry->rdlen;
00734
00735
00736 if (i == 0 && (h->flags & HEADERFLAG_LEGACY)) {
00737 int_32 stei[4];
00738
00739 legacy = 1;
00740
00741 memcpy(pe+1, src, rdl);
00742 memcpy(te, src + rdl, rdlen);
00743
00744 te += rdlen;
00745
00746 pe->offset = htonl(te - dataStart);
00747 stei[0] = pe->tag;
00748 stei[1] = pe->type;
00749 stei[2] = htonl(-rdl-entry->info.count);
00750 stei[3] = pe->count;
00751
00752 memcpy(te, stei, entry->info.count);
00753
00754 te += entry->info.count;
00755 ril++;
00756 rdlen += entry->info.count;
00757
00758 count = regionSwab(NULL, ril, 0, pe, t, NULL, 0);
00759 if (count != rdlen)
00760 goto errxit;
00761
00762 } else {
00763
00764
00765 memcpy(pe+1, src + sizeof(*pe), ((ril-1) * sizeof(*pe)));
00766 memcpy(te, src + (ril * sizeof(*pe)), rdlen+entry->info.count+drlen);
00767
00768 te += rdlen;
00769 {
00770 entryInfo se = (entryInfo)src;
00771
00772 int off = ntohl(se->offset);
00773 pe->offset = (off) ? htonl(te - dataStart) : htonl(off);
00774 }
00775 te += entry->info.count + drlen;
00776
00777 count = regionSwab(NULL, ril, 0, pe, t, NULL, 0);
00778 if (count != (rdlen + entry->info.count + drlen))
00779 goto errxit;
00780 }
00781
00782
00783 while (i < h->indexUsed && entry->info.offset <= rid+1) {
00784 i++;
00785 entry++;
00786 }
00787 i--;
00788 entry--;
00789 pe += ril;
00790 continue;
00791 }
00792
00793
00794 if (entry->data == NULL || entry->length <= 0)
00795 continue;
00796
00797
00798 type = entry->info.type;
00799 if (typeSizes[type] > 1) {
00800 unsigned diff;
00801 diff = typeSizes[type] - ((te - dataStart) % typeSizes[type]);
00802 if (diff != typeSizes[type]) {
00803
00804 memset(te, 0, diff);
00805
00806 te += diff;
00807 pad += diff;
00808 }
00809 }
00810
00811 pe->offset = htonl(te - dataStart);
00812
00813
00814
00815 switch (entry->info.type) {
00816 case RPM_INT32_TYPE:
00817 count = entry->info.count;
00818 src = entry->data;
00819 while (count--) {
00820 *((int_32 *)te) = htonl(*((int_32 *)src));
00821
00822 te += sizeof(int_32);
00823 src += sizeof(int_32);
00824
00825 }
00826 break;
00827
00828 case RPM_INT16_TYPE:
00829 count = entry->info.count;
00830 src = entry->data;
00831 while (count--) {
00832 *((int_16 *)te) = htons(*((int_16 *)src));
00833
00834 te += sizeof(int_16);
00835 src += sizeof(int_16);
00836
00837 }
00838 break;
00839
00840 default:
00841 memcpy(te, entry->data, entry->length);
00842 te += entry->length;
00843 break;
00844 }
00845
00846 pe++;
00847 }
00848
00849
00850 if (((char *)pe) != dataStart)
00851 goto errxit;
00852 if ((((char *)ei)+len) != te)
00853 goto errxit;
00854
00855 if (lengthPtr)
00856 *lengthPtr = len;
00857
00858 h->flags &= ~HEADERFLAG_SORTED;
00859 headerSort(h);
00860
00861 return (void *) ei;
00862
00863 errxit:
00864
00865 ei = _free(ei);
00866
00867 return (void *) ei;
00868 }
00869
00875 static
00876 void * headerUnload(Header h)
00877
00878 {
00879 int length;
00880
00881 void * uh = doHeaderUnload(h, &length);
00882
00883 return uh;
00884 }
00885
00893 static
00894 indexEntry findEntry( Header h, int_32 tag, int_32 type)
00895
00896 {
00897 indexEntry entry, entry2, last;
00898 struct indexEntry_s key;
00899
00900 if (h == NULL) return NULL;
00901 if (!(h->flags & HEADERFLAG_SORTED)) headerSort(h);
00902
00903 key.info.tag = tag;
00904
00905
00906 entry2 = entry =
00907 bsearch(&key, h->index, h->indexUsed, sizeof(*h->index), indexCmp);
00908
00909 if (entry == NULL)
00910 return NULL;
00911
00912 if (type == RPM_NULL_TYPE)
00913 return entry;
00914
00915
00916 while (entry->info.tag == tag && entry->info.type != type &&
00917 entry > h->index) entry--;
00918
00919 if (entry->info.tag == tag && entry->info.type == type)
00920 return entry;
00921
00922 last = h->index + h->indexUsed;
00923
00924 while (entry2->info.tag == tag && entry2->info.type != type &&
00925 entry2 < last) entry2++;
00926
00927
00928 if (entry->info.tag == tag && entry->info.type == type)
00929 return entry;
00930
00931 return NULL;
00932 }
00933
00943 static
00944 int headerRemoveEntry(Header h, int_32 tag)
00945
00946 {
00947 indexEntry last = h->index + h->indexUsed;
00948 indexEntry entry, first;
00949 int ne;
00950
00951 entry = findEntry(h, tag, RPM_NULL_TYPE);
00952 if (!entry) return 1;
00953
00954
00955 while (entry > h->index && (entry - 1)->info.tag == tag)
00956 entry--;
00957
00958
00959 for (first = entry; first < last; first++) {
00960 void * data;
00961 if (first->info.tag != tag)
00962 break;
00963 data = first->data;
00964 first->data = NULL;
00965 first->length = 0;
00966 if (ENTRY_IN_REGION(first))
00967 continue;
00968 data = _free(data);
00969 }
00970
00971 ne = (first - entry);
00972 if (ne > 0) {
00973 h->indexUsed -= ne;
00974 ne = last - first;
00975
00976 if (ne > 0)
00977 memmove(entry, first, (ne * sizeof(*entry)));
00978
00979 }
00980
00981 return 0;
00982 }
00983
00989 static
00990 Header headerLoad( void * uh)
00991
00992 {
00993 int_32 * ei = (int_32 *) uh;
00994 int_32 il = ntohl(ei[0]);
00995 int_32 dl = ntohl(ei[1]);
00996
00997 size_t pvlen = sizeof(il) + sizeof(dl) +
00998 (il * sizeof(struct entryInfo_s)) + dl;
00999
01000 void * pv = uh;
01001 Header h = NULL;
01002 entryInfo pe;
01003 unsigned char * dataStart;
01004 unsigned char * dataEnd;
01005 indexEntry entry;
01006 int rdlen;
01007 int i;
01008
01009
01010 if (hdrchkTags(il) || hdrchkData(dl))
01011 goto errxit;
01012
01013 ei = (int_32 *) pv;
01014
01015 pe = (entryInfo) &ei[2];
01016
01017 dataStart = (unsigned char *) (pe + il);
01018 dataEnd = dataStart + dl;
01019
01020 h = xcalloc(1, sizeof(*h));
01021
01022 h->hv = *hdrVec;
01023
01024
01025 h->blob = uh;
01026
01027 h->indexAlloced = il + 1;
01028 h->indexUsed = il;
01029 h->index = xcalloc(h->indexAlloced, sizeof(*h->index));
01030 h->flags |= HEADERFLAG_SORTED;
01031 h->nrefs = 0;
01032 h = headerLink(h);
01033
01034
01035
01036
01037
01038 if (ntohl(pe->tag) == 15 &&
01039 ntohl(pe->type) == RPM_STRING_TYPE &&
01040 ntohl(pe->count) == 1)
01041 {
01042 pe->tag = htonl(1079);
01043 }
01044
01045 entry = h->index;
01046 i = 0;
01047 if (!(htonl(pe->tag) < HEADER_I18NTABLE)) {
01048 h->flags |= HEADERFLAG_LEGACY;
01049 entry->info.type = REGION_TAG_TYPE;
01050 entry->info.tag = HEADER_IMAGE;
01051
01052 entry->info.count = REGION_TAG_COUNT;
01053
01054 entry->info.offset = ((unsigned char *)pe - dataStart);
01055
01056
01057 entry->data = pe;
01058
01059 entry->length = pvlen - sizeof(il) - sizeof(dl);
01060 rdlen = regionSwab(entry+1, il, 0, pe, dataStart, dataEnd, entry->info.offset);
01061 #if 0
01062 if (rdlen != dl)
01063 goto errxit;
01064 #endif
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
01077 if (hdrchkType(entry->info.type))
01078 goto errxit;
01079 if (hdrchkTags(entry->info.count))
01080 goto errxit;
01081
01082 { int off = ntohl(pe->offset);
01083
01084 if (hdrchkData(off))
01085 goto errxit;
01086 if (off) {
01087
01088 size_t nb = REGION_TAG_COUNT;
01089
01090 int_32 * stei = memcpy(alloca(nb), dataStart + off, nb);
01091 rdl = -ntohl(stei[2]);
01092 ril = rdl/sizeof(*pe);
01093 if (hdrchkTags(ril) || hdrchkData(rdl))
01094 goto errxit;
01095 entry->info.tag = htonl(pe->tag);
01096 } else {
01097 ril = il;
01098
01099 rdl = (ril * sizeof(struct entryInfo_s));
01100
01101 entry->info.tag = HEADER_IMAGE;
01102 }
01103 }
01104 entry->info.offset = -rdl;
01105
01106
01107 entry->data = pe;
01108
01109 entry->length = pvlen - sizeof(il) - sizeof(dl);
01110 rdlen = regionSwab(entry+1, ril-1, 0, pe+1, dataStart, dataEnd, entry->info.offset);
01111 if (rdlen < 0)
01112 goto errxit;
01113 entry->rdlen = rdlen;
01114
01115 if (ril < h->indexUsed) {
01116 indexEntry newEntry = entry + ril;
01117 int ne = (h->indexUsed - ril);
01118 int rid = entry->info.offset+1;
01119 int rc;
01120
01121
01122 rc = regionSwab(newEntry, ne, 0, pe+ril, dataStart, dataEnd, rid);
01123 if (rc < 0)
01124 goto errxit;
01125 rdlen += rc;
01126
01127 { indexEntry firstEntry = newEntry;
01128 int save = h->indexUsed;
01129 int j;
01130
01131
01132 h->indexUsed -= ne;
01133 for (j = 0; j < ne; j++, newEntry++) {
01134 (void) headerRemoveEntry(h, newEntry->info.tag);
01135 if (newEntry->info.tag == HEADER_BASENAMES)
01136 (void) headerRemoveEntry(h, HEADER_OLDFILENAMES);
01137 }
01138
01139
01140
01141 if (h->indexUsed < (save - ne)) {
01142 memmove(h->index + h->indexUsed, firstEntry,
01143 (ne * sizeof(*entry)));
01144 }
01145
01146 h->indexUsed += ne;
01147 }
01148 }
01149 }
01150
01151 h->flags &= ~HEADERFLAG_SORTED;
01152 headerSort(h);
01153
01154
01155 return h;
01156
01157
01158 errxit:
01159
01160 if (h) {
01161 h->index = _free(h->index);
01162
01163 h = _free(h);
01164
01165 }
01166
01167
01168 return h;
01169
01170 }
01171
01179 static
01180 Header headerReload( Header h, int tag)
01181
01182 {
01183 Header nh;
01184 int length;
01185
01186
01187 void * uh = doHeaderUnload(h, &length);
01188
01189
01190 h = headerFree(h);
01191
01192 if (uh == NULL)
01193 return NULL;
01194 nh = headerLoad(uh);
01195 if (nh == NULL) {
01196 uh = _free(uh);
01197 return NULL;
01198 }
01199 if (nh->flags & HEADERFLAG_ALLOCATED)
01200 uh = _free(uh);
01201 nh->flags |= HEADERFLAG_ALLOCATED;
01202 if (ENTRY_IS_REGION(nh->index)) {
01203
01204 if (tag == HEADER_SIGNATURES || tag == HEADER_IMMUTABLE)
01205 nh->index[0].info.tag = tag;
01206
01207 }
01208 return nh;
01209 }
01210
01216 static
01217 Header headerCopyLoad(const void * uh)
01218
01219 {
01220 int_32 * ei = (int_32 *) uh;
01221
01222 int_32 il = ntohl(ei[0]);
01223 int_32 dl = ntohl(ei[1]);
01224
01225
01226 size_t pvlen = sizeof(il) + sizeof(dl) +
01227 (il * sizeof(struct entryInfo_s)) + dl;
01228
01229 void * nuh = NULL;
01230 Header h = NULL;
01231
01232
01233
01234 if (!(hdrchkTags(il) || hdrchkData(dl)) && pvlen < headerMaxbytes) {
01235
01236 nuh = memcpy(xmalloc(pvlen), uh, pvlen);
01237
01238 if ((h = headerLoad(nuh)) != NULL)
01239 h->flags |= HEADERFLAG_ALLOCATED;
01240 }
01241
01242
01243 if (h == NULL)
01244 nuh = _free(nuh);
01245
01246 return h;
01247 }
01248
01255 static
01256 Header headerRead(FD_t fd, enum hMagic magicp)
01257
01258 {
01259 int_32 block[4];
01260 int_32 reserved;
01261 int_32 * ei = NULL;
01262 int_32 il;
01263 int_32 dl;
01264 int_32 magic;
01265 Header h = NULL;
01266 size_t len;
01267 int i;
01268
01269 memset(block, 0, sizeof(block));
01270 i = 2;
01271 if (magicp == HEADER_MAGIC_YES)
01272 i += 2;
01273
01274
01275 if (timedRead(fd, (char *)block, i*sizeof(*block)) != (i * sizeof(*block)))
01276 goto exit;
01277
01278
01279 i = 0;
01280
01281
01282 if (magicp == HEADER_MAGIC_YES) {
01283 magic = block[i++];
01284 if (memcmp(&magic, header_magic, sizeof(magic)))
01285 goto exit;
01286 reserved = block[i++];
01287 }
01288
01289 il = ntohl(block[i]); i++;
01290 dl = ntohl(block[i]); i++;
01291
01292
01293
01294 len = sizeof(il) + sizeof(dl) + (il * sizeof(struct entryInfo_s)) + dl;
01295
01296
01297
01298 if (hdrchkTags(il) || hdrchkData(dl) || len > headerMaxbytes)
01299 goto exit;
01300
01301
01302 ei = xmalloc(len);
01303 ei[0] = htonl(il);
01304 ei[1] = htonl(dl);
01305 len -= sizeof(il) + sizeof(dl);
01306
01307
01308
01309
01310 if (timedRead(fd, (char *)&ei[2], len) != len)
01311 goto exit;
01312
01313
01314
01315 h = headerLoad(ei);
01316
01317 exit:
01318 if (h) {
01319 if (h->flags & HEADERFLAG_ALLOCATED)
01320 ei = _free(ei);
01321 h->flags |= HEADERFLAG_ALLOCATED;
01322 } else if (ei)
01323 ei = _free(ei);
01324
01325 return h;
01326
01327 }
01328
01336 static
01337 int headerWrite(FD_t fd, Header h, enum hMagic magicp)
01338
01339
01340 {
01341 ssize_t nb;
01342 int length;
01343 const void * uh;
01344
01345 if (h == NULL)
01346 return 1;
01347
01348 uh = doHeaderUnload(h, &length);
01349
01350 if (uh == NULL)
01351 return 1;
01352 switch (magicp) {
01353 case HEADER_MAGIC_YES:
01354
01355
01356 nb = Fwrite(header_magic, sizeof(char), sizeof(header_magic), fd);
01357
01358
01359 if (nb != sizeof(header_magic))
01360 goto exit;
01361 break;
01362 case HEADER_MAGIC_NO:
01363 break;
01364 }
01365
01366
01367 nb = Fwrite(uh, sizeof(char), length, fd);
01368
01369
01370 exit:
01371 uh = _free(uh);
01372 return (nb == length ? 0 : 1);
01373 }
01374
01381 static
01382 int headerIsEntry(Header h, int_32 tag)
01383
01384 {
01385
01386 return (findEntry(h, tag, RPM_NULL_TYPE) ? 1 : 0);
01387
01388 }
01389
01400 static int copyEntry(const indexEntry entry,
01401 hTYP_t type,
01402 hPTR_t * p,
01403 hCNT_t c,
01404 int minMem)
01405
01406
01407 {
01408 int_32 count = entry->info.count;
01409 int rc = 1;
01410
01411 if (p)
01412 switch (entry->info.type) {
01413 case RPM_BIN_TYPE:
01414
01415
01416
01417
01418
01419
01420 if (ENTRY_IS_REGION(entry)) {
01421 int_32 * ei = ((int_32 *)entry->data) - 2;
01422
01423 entryInfo pe = (entryInfo) (ei + 2);
01424
01425
01426 char * dataStart = (char *) (pe + ntohl(ei[0]));
01427
01428 int_32 rdl = -entry->info.offset;
01429 int_32 ril = rdl/sizeof(*pe);
01430
01431
01432 rdl = entry->rdlen;
01433 count = 2 * sizeof(*ei) + (ril * sizeof(*pe)) + rdl;
01434 if (entry->info.tag == HEADER_IMAGE) {
01435 ril -= 1;
01436 pe += 1;
01437 } else {
01438 count += REGION_TAG_COUNT;
01439 rdl += REGION_TAG_COUNT;
01440 }
01441
01442
01443 *p = xmalloc(count);
01444 ei = (int_32 *) *p;
01445 ei[0] = htonl(ril);
01446 ei[1] = htonl(rdl);
01447
01448
01449 pe = (entryInfo) memcpy(ei + 2, pe, (ril * sizeof(*pe)));
01450
01451
01452 dataStart = (char *) memcpy(pe + ril, dataStart, rdl);
01453
01454
01455
01456 rc = regionSwab(NULL, ril, 0, pe, dataStart, NULL, 0);
01457
01458 rc = (rc < 0) ? 0 : 1;
01459 } else {
01460 count = entry->length;
01461 *p = (!minMem
01462 ? memcpy(xmalloc(count), entry->data, count)
01463 : entry->data);
01464 }
01465 break;
01466 case RPM_STRING_TYPE:
01467 if (count == 1) {
01468 *p = entry->data;
01469 break;
01470 }
01471
01472 case RPM_STRING_ARRAY_TYPE:
01473 case RPM_I18NSTRING_TYPE:
01474 { const char ** ptrEntry;
01475
01476 int tableSize = count * sizeof(char *);
01477
01478 char * t;
01479 int i;
01480
01481
01482
01483 if (minMem) {
01484 *p = xmalloc(tableSize);
01485 ptrEntry = (const char **) *p;
01486 t = entry->data;
01487 } else {
01488 t = xmalloc(tableSize + entry->length);
01489 *p = (void *)t;
01490 ptrEntry = (const char **) *p;
01491 t += tableSize;
01492 memcpy(t, entry->data, entry->length);
01493 }
01494
01495
01496 for (i = 0; i < count; i++) {
01497
01498 *ptrEntry++ = t;
01499
01500 t = strchr(t, 0);
01501 t++;
01502 }
01503 } break;
01504
01505 default:
01506 *p = entry->data;
01507 break;
01508 }
01509 if (type) *type = entry->info.type;
01510 if (c) *c = count;
01511 return rc;
01512 }
01513
01532 static int headerMatchLocale(const char *td, const char *l, const char *le)
01533
01534 {
01535 const char *fe;
01536
01537
01538 #if 0
01539 { const char *s, *ll, *CC, *EE, *dd;
01540 char *lbuf, *t.
01541
01542
01543 lbuf = alloca(le - l + 1);
01544 for (s = l, ll = t = lbuf; *s; s++, t++) {
01545 switch (*s) {
01546 case '_':
01547 *t = '\0';
01548 CC = t + 1;
01549 break;
01550 case '.':
01551 *t = '\0';
01552 EE = t + 1;
01553 break;
01554 case '@':
01555 *t = '\0';
01556 dd = t + 1;
01557 break;
01558 default:
01559 *t = *s;
01560 break;
01561 }
01562 }
01563
01564 if (ll)
01565 for (t = ll; *t; t++) *t = tolower(*t);
01566 if (CC)
01567 for (t = CC; *t; t++) *t = toupper(*t);
01568
01569
01570 }
01571 #endif
01572
01573
01574 if (strlen(td) == (le-l) && !strncmp(td, l, (le - l)))
01575 return 1;
01576
01577
01578 for (fe = l; fe < le && *fe != '@'; fe++)
01579 {};
01580 if (fe < le && !strncmp(td, l, (fe - l)))
01581 return 1;
01582
01583
01584 for (fe = l; fe < le && *fe != '.'; fe++)
01585 {};
01586 if (fe < le && !strncmp(td, l, (fe - l)))
01587 return 1;
01588
01589
01590 for (fe = l; fe < le && *fe != '_'; fe++)
01591 {};
01592 if (fe < le && !strncmp(td, l, (fe - l)))
01593 return 1;
01594
01595 return 0;
01596 }
01597
01604 static char *
01605 headerFindI18NString(Header h, indexEntry entry)
01606
01607 {
01608 const char *lang, *l, *le;
01609 indexEntry table;
01610
01611
01612 if ((lang = getenv("LANGUAGE")) == NULL &&
01613 (lang = getenv("LC_ALL")) == NULL &&
01614 (lang = getenv("LC_MESSAGES")) == NULL &&
01615 (lang = getenv("LANG")) == NULL)
01616 return entry->data;
01617
01618
01619 if ((table = findEntry(h, HEADER_I18NTABLE, RPM_STRING_ARRAY_TYPE)) == NULL)
01620 return entry->data;
01621
01622
01623
01624 for (l = lang; *l != '\0'; l = le) {
01625 const char *td;
01626 char *ed;
01627 int langNum;
01628
01629 while (*l && *l == ':')
01630 l++;
01631 if (*l == '\0')
01632 break;
01633 for (le = l; *le && *le != ':'; le++)
01634 {};
01635
01636
01637 for (langNum = 0, td = table->data, ed = entry->data;
01638 langNum < entry->info.count;
01639 langNum++, td += strlen(td) + 1, ed += strlen(ed) + 1) {
01640
01641 if (headerMatchLocale(td, l, le))
01642 return ed;
01643
01644 }
01645 }
01646
01647
01648 return entry->data;
01649 }
01650
01661 static int intGetEntry(Header h, int_32 tag,
01662 hTAG_t type,
01663 hPTR_t * p,
01664 hCNT_t c,
01665 int minMem)
01666
01667
01668 {
01669 indexEntry entry;
01670 int rc;
01671
01672
01673
01674 entry = findEntry(h, tag, RPM_NULL_TYPE);
01675
01676 if (entry == NULL) {
01677 if (type) type = 0;
01678 if (p) *p = NULL;
01679 if (c) *c = 0;
01680 return 0;
01681 }
01682
01683 switch (entry->info.type) {
01684 case RPM_I18NSTRING_TYPE:
01685 rc = 1;
01686 if (type) *type = RPM_STRING_TYPE;
01687 if (c) *c = 1;
01688
01689 if (p) *p = headerFindI18NString(h, entry);
01690
01691 break;
01692 default:
01693 rc = copyEntry(entry, type, p, c, minMem);
01694 break;
01695 }
01696
01697
01698 return ((rc == 1) ? 1 : 0);
01699 }
01700
01708 static void * headerFreeTag( Header h,
01709 const void * data, rpmTagType type)
01710
01711 {
01712 if (data) {
01713
01714 if (type == -1 ||
01715 type == RPM_STRING_ARRAY_TYPE ||
01716 type == RPM_I18NSTRING_TYPE ||
01717 type == RPM_BIN_TYPE)
01718 data = _free(data);
01719
01720 }
01721 return NULL;
01722 }
01723
01737 static
01738 int headerGetEntry(Header h, int_32 tag,
01739 hTYP_t type,
01740 void ** p,
01741 hCNT_t c)
01742
01743
01744 {
01745 return intGetEntry(h, tag, type, (hPTR_t *)p, c, 0);
01746 }
01747
01760 static
01761 int headerGetEntryMinMemory(Header h, int_32 tag,
01762 hTYP_t type,
01763 hPTR_t * p,
01764 hCNT_t c)
01765
01766
01767 {
01768 return intGetEntry(h, tag, type, p, c, 1);
01769 }
01770
01771 int headerGetRawEntry(Header h, int_32 tag, int_32 * type, hPTR_t * p,
01772 int_32 * c)
01773 {
01774 indexEntry entry;
01775 int rc;
01776
01777 if (p == NULL) return headerIsEntry(h, tag);
01778
01779
01780
01781 entry = findEntry(h, tag, RPM_NULL_TYPE);
01782
01783 if (!entry) {
01784 if (p) *p = NULL;
01785 if (c) *c = 0;
01786 return 0;
01787 }
01788
01789 rc = copyEntry(entry, type, p, c, 0);
01790
01791
01792 return ((rc == 1) ? 1 : 0);
01793 }
01794
01797 static void copyData(int_32 type, void * dstPtr, const void * srcPtr,
01798 int_32 cnt, int dataLength)
01799
01800 {
01801 switch (type) {
01802 case RPM_STRING_ARRAY_TYPE:
01803 case RPM_I18NSTRING_TYPE:
01804 { const char ** av = (const char **) srcPtr;
01805 char * t = dstPtr;
01806
01807
01808 while (cnt-- > 0 && dataLength > 0) {
01809 const char * s;
01810 if ((s = *av++) == NULL)
01811 continue;
01812 do {
01813 *t++ = *s++;
01814 } while (s[-1] && --dataLength > 0);
01815 }
01816
01817 } break;
01818
01819 default:
01820
01821 memmove(dstPtr, srcPtr, dataLength);
01822
01823 break;
01824 }
01825 }
01826
01835
01836 static void *
01837 grabData(int_32 type, hPTR_t p, int_32 c, int * lengthPtr)
01838
01839
01840 {
01841 void * data = NULL;
01842 int length;
01843
01844 length = dataLength(type, p, c, 0, NULL);
01845
01846 if (length > 0) {
01847 data = xmalloc(length);
01848 copyData(type, data, p, c, length);
01849 }
01850
01851
01852 if (lengthPtr)
01853 *lengthPtr = length;
01854 return data;
01855 }
01856
01871 static
01872 int headerAddEntry(Header h, int_32 tag, int_32 type, const void * p, int_32 c)
01873
01874 {
01875 indexEntry entry;
01876 void * data;
01877 int length;
01878
01879
01880 if (c <= 0)
01881 return 0;
01882
01883 if (hdrchkType(type))
01884 return 0;
01885 if (hdrchkData(c))
01886 return 0;
01887
01888 length = 0;
01889
01890 data = grabData(type, p, c, &length);
01891
01892 if (data == NULL || length <= 0)
01893 return 0;
01894
01895
01896 if (h->indexUsed == h->indexAlloced) {
01897 h->indexAlloced += INDEX_MALLOC_SIZE;
01898 h->index = xrealloc(h->index, h->indexAlloced * sizeof(*h->index));
01899 }
01900
01901
01902 entry = h->index + h->indexUsed;
01903 entry->info.tag = tag;
01904 entry->info.type = type;
01905 entry->info.count = c;
01906 entry->info.offset = 0;
01907 entry->data = data;
01908 entry->length = length;
01909
01910
01911 if (h->indexUsed > 0 && tag < h->index[h->indexUsed-1].info.tag)
01912 h->flags &= ~HEADERFLAG_SORTED;
01913
01914 h->indexUsed++;
01915
01916 return 1;
01917 }
01918
01933 static
01934 int headerAppendEntry(Header h, int_32 tag, int_32 type,
01935 const void * p, int_32 c)
01936
01937 {
01938 indexEntry entry;
01939 int length;
01940
01941 if (type == RPM_STRING_TYPE || type == RPM_I18NSTRING_TYPE) {
01942
01943 return 0;
01944 }
01945
01946
01947 entry = findEntry(h, tag, type);
01948 if (!entry)
01949 return 0;
01950
01951 length = dataLength(type, p, c, 0, NULL);
01952 if (length < 0)
01953 return 0;
01954
01955 if (ENTRY_IN_REGION(entry)) {
01956 char * t = xmalloc(entry->length + length);
01957
01958 memcpy(t, entry->data, entry->length);
01959
01960 entry->data = t;
01961 entry->info.offset = 0;
01962 } else
01963 entry->data = xrealloc(entry->data, entry->length + length);
01964
01965 copyData(type, ((char *) entry->data) + entry->length, p, c, length);
01966
01967 entry->length += length;
01968
01969 entry->info.count += c;
01970
01971 return 1;
01972 }
01973
01984 static
01985 int headerAddOrAppendEntry(Header h, int_32 tag, int_32 type,
01986 const void * p, int_32 c)
01987
01988 {
01989 return (findEntry(h, tag, type)
01990 ? headerAppendEntry(h, tag, type, p, c)
01991 : headerAddEntry(h, tag, type, p, c));
01992 }
01993
02014 static
02015 int headerAddI18NString(Header h, int_32 tag, const char * string,
02016 const char * lang)
02017
02018 {
02019 indexEntry table, entry;
02020 const char ** strArray;
02021 int length;
02022 int ghosts;
02023 int i, langNum;
02024 char * buf;
02025
02026 table = findEntry(h, HEADER_I18NTABLE, RPM_STRING_ARRAY_TYPE);
02027 entry = findEntry(h, tag, RPM_I18NSTRING_TYPE);
02028
02029 if (!table && entry)
02030 return 0;
02031
02032 if (!table && !entry) {
02033 const char * charArray[2];
02034 int count = 0;
02035 if (!lang || (lang[0] == 'C' && lang[1] == '\0')) {
02036
02037 charArray[count++] = "C";
02038
02039 } else {
02040
02041 charArray[count++] = "C";
02042
02043 charArray[count++] = lang;
02044 }
02045 if (!headerAddEntry(h, HEADER_I18NTABLE, RPM_STRING_ARRAY_TYPE,
02046 &charArray, count))
02047 return 0;
02048 table = findEntry(h, HEADER_I18NTABLE, RPM_STRING_ARRAY_TYPE);
02049 }
02050
02051 if (!table)
02052 return 0;
02053
02054 if (!lang) lang = "C";
02055
02056
02057 { const char * l = table->data;
02058 for (langNum = 0; langNum < table->info.count; langNum++) {
02059 if (!strcmp(l, lang)) break;
02060 l += strlen(l) + 1;
02061 }
02062 }
02063
02064 if (langNum >= table->info.count) {
02065 length = strlen(lang) + 1;
02066 if (ENTRY_IN_REGION(table)) {
02067 char * t = xmalloc(table->length + length);
02068 memcpy(t, table->data, table->length);
02069 table->data = t;
02070 table->info.offset = 0;
02071 } else
02072 table->data = xrealloc(table->data, table->length + length);
02073 memmove(((char *)table->data) + table->length, lang, length);
02074 table->length += length;
02075 table->info.count++;
02076 }
02077
02078 if (!entry) {
02079 strArray = alloca(sizeof(*strArray) * (langNum + 1));
02080 for (i = 0; i < langNum; i++)
02081 strArray[i] = "";
02082 strArray[langNum] = string;
02083 return headerAddEntry(h, tag, RPM_I18NSTRING_TYPE, strArray,
02084 langNum + 1);
02085 } else if (langNum >= entry->info.count) {
02086 ghosts = langNum - entry->info.count;
02087
02088 length = strlen(string) + 1 + ghosts;
02089 if (ENTRY_IN_REGION(entry)) {
02090 char * t = xmalloc(entry->length + length);
02091 memcpy(t, entry->data, entry->length);
02092 entry->data = t;
02093 entry->info.offset = 0;
02094 } else
02095 entry->data = xrealloc(entry->data, entry->length + length);
02096
02097 memset(((char *)entry->data) + entry->length, '\0', ghosts);
02098 memmove(((char *)entry->data) + entry->length + ghosts, string, strlen(string)+1);
02099
02100 entry->length += length;
02101 entry->info.count = langNum + 1;
02102 } else {
02103 char *b, *be, *e, *ee, *t;
02104 size_t bn, sn, en;
02105
02106
02107 b = be = e = ee = entry->data;
02108 for (i = 0; i < table->info.count; i++) {
02109 if (i == langNum)
02110 be = ee;
02111 ee += strlen(ee) + 1;
02112 if (i == langNum)
02113 e = ee;
02114 }
02115
02116
02117 bn = (be-b);
02118 sn = strlen(string) + 1;
02119 en = (ee-e);
02120 length = bn + sn + en;
02121 t = buf = xmalloc(length);
02122
02123
02124 memcpy(t, b, bn);
02125 t += bn;
02126
02127 memcpy(t, string, sn);
02128 t += sn;
02129 memcpy(t, e, en);
02130 t += en;
02131
02132
02133
02134 entry->length -= strlen(be) + 1;
02135 entry->length += sn;
02136
02137 if (ENTRY_IN_REGION(entry)) {
02138 entry->info.offset = 0;
02139 } else
02140 entry->data = _free(entry->data);
02141
02142 entry->data = buf;
02143
02144 }
02145
02146 return 0;
02147 }
02148
02159 static
02160 int headerModifyEntry(Header h, int_32 tag, int_32 type,
02161 const void * p, int_32 c)
02162
02163 {
02164 indexEntry entry;
02165 void * oldData;
02166 void * data;
02167 int length;
02168
02169
02170 entry = findEntry(h, tag, type);
02171 if (!entry)
02172 return 0;
02173
02174 length = 0;
02175 data = grabData(type, p, c, &length);
02176 if (data == NULL || length <= 0)
02177 return 0;
02178
02179
02180 while (entry > h->index && (entry - 1)->info.tag == tag)
02181 entry--;
02182
02183
02184
02185 oldData = entry->data;
02186
02187 entry->info.count = c;
02188 entry->info.type = type;
02189 entry->data = data;
02190 entry->length = length;
02191
02192
02193 if (ENTRY_IN_REGION(entry)) {
02194 entry->info.offset = 0;
02195 } else
02196 oldData = _free(oldData);
02197
02198
02199 return 1;
02200 }
02201
02204 static char escapedChar(const char ch)
02205 {
02206 switch (ch) {
02207 case 'a': return '\a';
02208 case 'b': return '\b';
02209 case 'f': return '\f';
02210 case 'n': return '\n';
02211 case 'r': return '\r';
02212 case 't': return '\t';
02213 case 'v': return '\v';
02214 default: return ch;
02215 }
02216 }
02217
02224 static sprintfToken
02225 freeFormat( sprintfToken format, int num)
02226
02227 {
02228 int i;
02229
02230 if (format == NULL) return NULL;
02231 for (i = 0; i < num; i++) {
02232 switch (format[i].type) {
02233 case PTOK_ARRAY:
02234
02235 format[i].u.array.format =
02236 freeFormat(format[i].u.array.format,
02237 format[i].u.array.numTokens);
02238
02239 break;
02240 case PTOK_COND:
02241
02242 format[i].u.cond.ifFormat =
02243 freeFormat(format[i].u.cond.ifFormat,
02244 format[i].u.cond.numIfTokens);
02245 format[i].u.cond.elseFormat =
02246 freeFormat(format[i].u.cond.elseFormat,
02247 format[i].u.cond.numElseTokens);
02248
02249 break;
02250 case PTOK_NONE:
02251 case PTOK_TAG:
02252 case PTOK_STRING:
02253 default:
02254 break;
02255 }
02256 }
02257 format = _free(format);
02258 return NULL;
02259 }
02260
02263 static void findTag(char * name, const headerTagTableEntry tags,
02264 const headerSprintfExtension extensions,
02265 headerTagTableEntry * tagMatch,
02266 headerSprintfExtension * extMatch)
02267
02268
02269 {
02270 headerTagTableEntry entry;
02271 headerSprintfExtension ext;
02272 const char * tagname;
02273
02274 *tagMatch = NULL;
02275 *extMatch = NULL;
02276
02277 if (strncmp("RPMTAG_", name, sizeof("RPMTAG_")-1)) {
02278
02279 char * t = alloca(strlen(name) + sizeof("RPMTAG_"));
02280 (void) stpcpy( stpcpy(t, "RPMTAG_"), name);
02281 tagname = t;
02282
02283 } else {
02284 tagname = name;
02285 }
02286
02287
02288 ext = extensions;
02289 while (ext->type != HEADER_EXT_LAST) {
02290 if (ext->name != NULL && ext->type == HEADER_EXT_TAG
02291 && !xstrcasecmp(ext->name, tagname))
02292 break;
02293
02294 if (ext->type == HEADER_EXT_MORE)
02295 ext = ext->u.more;
02296 else
02297 ext++;
02298 }
02299
02300 if (ext->type == HEADER_EXT_TAG) {
02301 *extMatch = ext;
02302 return;
02303 }
02304
02305
02306 for (entry = tags; entry->name; entry++)
02307 if (entry->name && !xstrcasecmp(entry->name, tagname))
02308 break;
02309
02310 if (entry->name) {
02311 *tagMatch = entry;
02312 return;
02313 }
02314 }
02315
02316
02317 static int parseExpression(sprintfToken token, char * str,
02318 const headerTagTableEntry tags,
02319 const headerSprintfExtension extensions,
02320 char ** endPtr, errmsg_t * errmsg)
02321
02322 ;
02323
02326
02327 static int parseFormat( char * str, const headerTagTableEntry tags,
02328 const headerSprintfExtension extensions,
02329 sprintfToken * formatPtr, int * numTokensPtr,
02330 char ** endPtr, int state,
02331 errmsg_t * errmsg)
02332
02333
02334
02335 {
02336 char * chptr, * start, * next, * dst;
02337 sprintfToken format;
02338 int numTokens;
02339 int currToken;
02340 headerTagTableEntry tag;
02341 headerSprintfExtension ext;
02342 int i;
02343 int done = 0;
02344
02345
02346 numTokens = 0;
02347 if (str != NULL)
02348 for (chptr = str; *chptr != '\0'; chptr++)
02349 if (*chptr == '%') numTokens++;
02350 numTokens = numTokens * 2 + 1;
02351
02352 format = xcalloc(numTokens, sizeof(*format));
02353 if (endPtr) *endPtr = NULL;
02354
02355
02356 dst = start = str;
02357 currToken = -1;
02358 if (start != NULL)
02359 while (*start != '\0') {
02360 switch (*start) {
02361 case '%':
02362
02363 if (*(start + 1) == '%') {
02364 if (currToken < 0 || format[currToken].type != PTOK_STRING) {
02365 currToken++;
02366 format[currToken].type = PTOK_STRING;
02367
02368 dst = format[currToken].u.string.string = start;
02369
02370 }
02371
02372 start++;
02373
02374 *dst++ = *start++;
02375
02376 break;
02377 }
02378
02379 currToken++;
02380 *dst++ = '\0';
02381 start++;
02382
02383 if (*start == '|') {
02384 char * newEnd;
02385
02386 start++;
02387 if (parseExpression(format + currToken, start, tags,
02388 extensions, &newEnd, errmsg))
02389 {
02390 format = freeFormat(format, numTokens);
02391 return 1;
02392 }
02393 start = newEnd;
02394 break;
02395 }
02396
02397
02398 format[currToken].u.tag.format = start;
02399
02400 format[currToken].u.tag.pad = 0;
02401 format[currToken].u.tag.justOne = 0;
02402 format[currToken].u.tag.arrayCount = 0;
02403
02404 chptr = start;
02405 while (*chptr && *chptr != '{' && *chptr != '%') chptr++;
02406 if (!*chptr || *chptr == '%') {
02407
02408 if (errmsg) *errmsg = _("missing { after %");
02409
02410 format = freeFormat(format, numTokens);
02411 return 1;
02412 }
02413
02414 *chptr++ = '\0';
02415
02416 while (start < chptr) {
02417 if (xisdigit(*start)) {
02418 i = strtoul(start, &start, 10);
02419 format[currToken].u.tag.pad += i;
02420 } else {
02421 start++;
02422 }
02423 }
02424
02425 if (*start == '=') {
02426 format[currToken].u.tag.justOne = 1;
02427 start++;
02428 } else if (*start == '#') {
02429 format[currToken].u.tag.justOne = 1;
02430 format[currToken].u.tag.arrayCount = 1;
02431 start++;
02432 }
02433
02434 next = start;
02435 while (*next && *next != '}') next++;
02436 if (!*next) {
02437
02438 if (errmsg) *errmsg = _("missing } after %{");
02439
02440 format = freeFormat(format, numTokens);
02441 return 1;
02442 }
02443 *next++ = '\0';
02444
02445 chptr = start;
02446 while (*chptr && *chptr != ':') chptr++;
02447
02448 if (*chptr != '\0') {
02449 *chptr++ = '\0';
02450 if (!*chptr) {
02451
02452 if (errmsg) *errmsg = _("empty tag format");
02453
02454 format = freeFormat(format, numTokens);
02455 return 1;
02456 }
02457
02458 format[currToken].u.tag.type = chptr;
02459
02460 } else {
02461 format[currToken].u.tag.type = NULL;
02462 }
02463
02464 if (!*start) {
02465
02466 if (errmsg) *errmsg = _("empty tag name");
02467
02468 format = freeFormat(format, numTokens);
02469 return 1;
02470 }
02471
02472 i = 0;
02473 findTag(start, tags, extensions, &tag, &ext);
02474
02475 if (tag) {
02476 format[currToken].u.tag.ext = NULL;
02477 format[currToken].u.tag.tag = tag->val;
02478 } else if (ext) {
02479 format[currToken].u.tag.ext = ext->u.tagFunction;
02480 format[currToken].u.tag.extNum = ext - extensions;
02481 } else {
02482
02483 if (errmsg) *errmsg = _("unknown tag");
02484
02485 format = freeFormat(format, numTokens);
02486 return 1;
02487 }
02488
02489 format[currToken].type = PTOK_TAG;
02490
02491 start = next;
02492
02493 break;
02494
02495 case '[':
02496 *dst++ = '\0';
02497 *start++ = '\0';
02498 currToken++;
02499
02500 if (parseFormat(start, tags, extensions,
02501 &format[currToken].u.array.format,
02502 &format[currToken].u.array.numTokens,
02503 &start, PARSER_IN_ARRAY, errmsg)) {
02504 format = freeFormat(format, numTokens);
02505 return 1;
02506 }
02507
02508 if (!start) {
02509
02510 if (errmsg) *errmsg = _("] expected at end of array");
02511
02512 format = freeFormat(format, numTokens);
02513 return 1;
02514 }
02515
02516 dst = start;
02517
02518 format[currToken].type = PTOK_ARRAY;
02519
02520 break;
02521
02522 case ']':
02523 case '}':
02524 if ((*start == ']' && state != PARSER_IN_ARRAY) ||
02525 (*start == '}' && state != PARSER_IN_EXPR)) {
02526 if (*start == ']') {
02527
02528 if (errmsg) *errmsg = _("unexpected ]");
02529
02530 } else {
02531
02532 if (errmsg) *errmsg = _("unexpected }");
02533
02534 }
02535 format = freeFormat(format, numTokens);
02536 return 1;
02537 }
02538 *start++ = '\0';
02539 if (endPtr) *endPtr = start;
02540 done = 1;
02541 break;
02542
02543 default:
02544 if (currToken < 0 || format[currToken].type != PTOK_STRING) {
02545 currToken++;
02546 format[currToken].type = PTOK_STRING;
02547
02548 dst = format[currToken].u.string.string = start;
02549
02550 }
02551
02552 if (*start == '\\') {
02553 start++;
02554 *dst++ = escapedChar(*start++);
02555 } else {
02556 *dst++ = *start++;
02557 }
02558 break;
02559 }
02560 if (done)
02561 break;
02562 }
02563
02564
02565 if (dst != NULL)
02566 *dst = '\0';
02567
02568 currToken++;
02569 for (i = 0; i < currToken; i++) {
02570 if (format[i].type == PTOK_STRING)
02571 format[i].u.string.len = strlen(format[i].u.string.string);
02572 }
02573
02574 *numTokensPtr = currToken;
02575 *formatPtr = format;
02576
02577 return 0;
02578 }
02579
02580
02583
02584 static int parseExpression(sprintfToken token, char * str,
02585 const headerTagTableEntry tags,
02586 const headerSprintfExtension extensions,
02587 char ** endPtr,
02588 errmsg_t * errmsg)
02589 {
02590 headerTagTableEntry tag;
02591 headerSprintfExtension ext;
02592 char * chptr;
02593 char * end;
02594
02595 if (errmsg) *errmsg = NULL;
02596 chptr = str;
02597 while (*chptr && *chptr != '?') chptr++;
02598
02599 if (*chptr != '?') {
02600
02601 if (errmsg) *errmsg = _("? expected in expression");
02602
02603 return 1;
02604 }
02605
02606 *chptr++ = '\0';;
02607
02608 if (*chptr != '{') {
02609
02610 if (errmsg) *errmsg = _("{ expected after ? in expression");
02611
02612 return 1;
02613 }
02614
02615 chptr++;
02616
02617 if (parseFormat(chptr, tags, extensions, &token->u.cond.ifFormat,
02618 &token->u.cond.numIfTokens, &end, PARSER_IN_EXPR, errmsg))
02619 return 1;
02620
02621
02622 if (!(end && *end)) {
02623
02624 if (errmsg) *errmsg = _("} expected in expression");
02625
02626 token->u.cond.ifFormat =
02627 freeFormat(token->u.cond.ifFormat, token->u.cond.numIfTokens);
02628 return 1;
02629 }
02630
02631 chptr = end;
02632 if (*chptr != ':' && *chptr != '|') {
02633
02634 if (errmsg) *errmsg = _(": expected following ? subexpression");
02635
02636 token->u.cond.ifFormat =
02637 freeFormat(token->u.cond.ifFormat, token->u.cond.numIfTokens);
02638 return 1;
02639 }
02640
02641 if (*chptr == '|') {
02642 if (parseFormat(NULL, tags, extensions, &token->u.cond.elseFormat,
02643 &token->u.cond.numElseTokens, &end, PARSER_IN_EXPR, errmsg))
02644 {
02645 token->u.cond.ifFormat =
02646 freeFormat(token->u.cond.ifFormat, token->u.cond.numIfTokens);
02647 return 1;
02648 }
02649 } else {
02650 chptr++;
02651
02652 if (*chptr != '{') {
02653
02654 if (errmsg) *errmsg = _("{ expected after : in expression");
02655
02656 token->u.cond.ifFormat =
02657 freeFormat(token->u.cond.ifFormat, token->u.cond.numIfTokens);
02658 return 1;
02659 }
02660
02661 chptr++;
02662
02663 if (parseFormat(chptr, tags, extensions, &token->u.cond.elseFormat,
02664 &token->u.cond.numElseTokens, &end, PARSER_IN_EXPR,
02665 errmsg))
02666 return 1;
02667
02668
02669 if (!(end && *end)) {
02670
02671 if (errmsg) *errmsg = _("} expected in expression");
02672
02673 token->u.cond.ifFormat =
02674 freeFormat(token->u.cond.ifFormat, token->u.cond.numIfTokens);
02675 return 1;
02676 }
02677
02678 chptr = end;
02679 if (*chptr != '|') {
02680
02681 if (errmsg) *errmsg = _("| expected at end of expression");
02682
02683 token->u.cond.ifFormat =
02684 freeFormat(token->u.cond.ifFormat, token->u.cond.numIfTokens);
02685 token->u.cond.elseFormat =
02686 freeFormat(token->u.cond.elseFormat, token->u.cond.numElseTokens);
02687 return 1;
02688 }
02689 }
02690
02691 chptr++;
02692
02693 *endPtr = chptr;
02694
02695 findTag(str, tags, extensions, &tag, &ext);
02696
02697 if (tag) {
02698 token->u.cond.tag.ext = NULL;
02699 token->u.cond.tag.tag = tag->val;
02700 } else if (ext) {
02701 token->u.cond.tag.ext = ext->u.tagFunction;
02702 token->u.cond.tag.extNum = ext - extensions;
02703 } else {
02704 token->u.cond.tag.ext = NULL;
02705 token->u.cond.tag.tag = -1;
02706 }
02707
02708 token->type = PTOK_COND;
02709
02710 return 0;
02711 }
02712
02713
02723 static int getExtension(Header h, headerTagTagFunction fn,
02724 hTYP_t typeptr,
02725 hPTR_t * data,
02726 hCNT_t countptr,
02727 extensionCache ext)
02728
02729
02730
02731 {
02732 if (!ext->avail) {
02733 if (fn(h, &ext->type, &ext->data, &ext->count, &ext->freeit))
02734 return 1;
02735 ext->avail = 1;
02736 }
02737
02738 if (typeptr) *typeptr = ext->type;
02739 if (data) *data = ext->data;
02740 if (countptr) *countptr = ext->count;
02741
02742 return 0;
02743 }
02744
02747
02748 static char * formatValue(sprintfTag tag, Header h,
02749 const headerSprintfExtension extensions,
02750 extensionCache extCache, int element,
02751 char ** valp, int * vallenp, int * allocedp)
02752
02753
02754
02755 {
02756 char * val = NULL;
02757 int need = 0;
02758 char * t, * te;
02759 char buf[20];
02760 int_32 count, type;
02761 hPTR_t data;
02762 unsigned int intVal;
02763 const char ** strarray;
02764 int datafree = 0;
02765 int countBuf;
02766 headerTagFormatFunction tagtype = NULL;
02767 headerSprintfExtension ext;
02768
02769 memset(buf, 0, sizeof(buf));
02770
02771 if (tag->ext) {
02772
02773 if (getExtension(h, tag->ext, &type, &data, &count,
02774 extCache + tag->extNum))
02775 {
02776 count = 1;
02777 type = RPM_STRING_TYPE;
02778 data = "(none)";
02779 }
02780
02781 } else {
02782
02783 if (!headerGetEntry(h, tag->tag, &type, (void **)&data, &count)) {
02784 count = 1;
02785 type = RPM_STRING_TYPE;
02786 data = "(none)";
02787 }
02788
02789
02790 datafree = 1;
02791 }
02792
02793
02794 if (tag->arrayCount) {
02795
02796 if (datafree)
02797 data = headerFreeData(data, type);
02798
02799
02800 countBuf = count;
02801 data = &countBuf;
02802 count = 1;
02803 type = RPM_INT32_TYPE;
02804 }
02805
02806
02807 (void) stpcpy( stpcpy(buf, "%"), tag->format);
02808
02809
02810 if (tag->type) {
02811 ext = extensions;
02812 while (ext->type != HEADER_EXT_LAST) {
02813 if (ext->name != NULL && ext->type == HEADER_EXT_FORMAT
02814 && !strcmp(ext->name, tag->type))
02815 {
02816 tagtype = ext->u.formatFunction;
02817 break;
02818 }
02819
02820 if (ext->type == HEADER_EXT_MORE)
02821 ext = ext->u.more;
02822 else
02823 ext++;
02824 }
02825 }
02826
02827
02828 switch (type) {
02829 case RPM_STRING_ARRAY_TYPE:
02830 strarray = (const char **)data;
02831
02832 if (tagtype)
02833 val = tagtype(RPM_STRING_TYPE, strarray[element], buf, tag->pad, 0);
02834
02835 if (val) {
02836 need = strlen(val);
02837 } else {
02838 need = strlen(strarray[element]) + tag->pad + 20;
02839 val = xmalloc(need+1);
02840 strcat(buf, "s");
02841
02842 sprintf(val, buf, strarray[element]);
02843
02844 }
02845
02846
02847 if (datafree) data = _free(data);
02848
02849
02850 break;
02851
02852 case RPM_STRING_TYPE:
02853 if (tagtype)
02854 val = tagtype(RPM_STRING_ARRAY_TYPE, data, buf, tag->pad, 0);
02855
02856 if (val) {
02857 need = strlen(val);
02858 } else {
02859 need = strlen(data) + tag->pad + 20;
02860 val = xmalloc(need+1);
02861 strcat(buf, "s");
02862
02863 sprintf(val, buf, data);
02864
02865 }
02866 break;
02867
02868 case RPM_CHAR_TYPE:
02869 case RPM_INT8_TYPE:
02870 case RPM_INT16_TYPE:
02871 case RPM_INT32_TYPE:
02872 switch (type) {
02873 case RPM_CHAR_TYPE:
02874 case RPM_INT8_TYPE:
02875 intVal = *(((int_8 *) data) + element);
02876 break;
02877 case RPM_INT16_TYPE:
02878 intVal = *(((uint_16 *) data) + element);
02879 break;
02880 default:
02881 case RPM_INT32_TYPE:
02882 intVal = *(((int_32 *) data) + element);
02883 break;
02884 }
02885
02886 if (tagtype)
02887 val = tagtype(RPM_INT32_TYPE, &intVal, buf, tag->pad, element);
02888
02889 if (val) {
02890 need = strlen(val);
02891 } else {
02892 need = 10 + tag->pad + 20;
02893 val = xmalloc(need+1);
02894 strcat(buf, "d");
02895
02896 sprintf(val, buf, intVal);
02897
02898 }
02899 break;
02900
02901 case RPM_BIN_TYPE:
02902 if (tagtype)
02903 val = tagtype(RPM_BIN_TYPE, data, buf, tag->pad, count);
02904
02905 if (val) {
02906 need = count;
02907 } else {
02908 #ifdef NOTYET
02909 val = memcpy(xmalloc(count), data, count);
02910 #else
02911
02912 static char hex[] = "0123456789abcdef";
02913 const char * s = data;
02914
02915
02916 need = 2*count + tag->pad;
02917 val = t = xmalloc(need+1);
02918 while (count-- > 0) {
02919 unsigned int i;
02920 i = *s++;
02921 *t++ = hex[ (i >> 4) & 0xf ];
02922 *t++ = hex[ (i ) & 0xf ];
02923 }
02924 *t = '\0';
02925
02926 #endif
02927 }
02928 break;
02929
02930 default:
02931 need = sizeof("(unknown type)") - 1;
02932 val = xstrdup("(unknown type)");
02933 break;
02934 }
02935
02936
02937
02938 if (val && need > 0) {
02939 if (((*vallenp) + need) >= (*allocedp)) {
02940 if ((*allocedp) <= need)
02941 (*allocedp) += need;
02942
02943 (*allocedp) <<= 1;
02944
02945
02946 (*valp) = xrealloc((*valp), (*allocedp)+1);
02947
02948 }
02949 t = (*valp) + (*vallenp);
02950
02951 te = stpcpy(t, val);
02952
02953 (*vallenp) += (te - t);
02954 val = _free(val);
02955 }
02956
02957
02958 return ((*valp) + (*vallenp));
02959 }
02960
02963
02964 static char * singleSprintf(Header h, sprintfToken token,
02965 const headerSprintfExtension extensions,
02966 extensionCache extCache, int element,
02967 char ** valp, int * vallenp, int * allocedp)
02968
02969
02970
02971 {
02972 char * t, * te;
02973 int i, j;
02974 int numElements;
02975 int type;
02976 sprintfToken condFormat;
02977 int condNumFormats;
02978 int need;
02979
02980
02981
02982 switch (token->type) {
02983 case PTOK_NONE:
02984 break;
02985
02986 case PTOK_STRING:
02987 need = token->u.string.len;
02988 if (need <= 0) break;
02989 if (((*vallenp) + need) >= (*allocedp)) {
02990 if ((*allocedp) <= need)
02991 (*allocedp) += need;
02992
02993 (*allocedp) <<= 1;
02994
02995
02996 (*valp) = xrealloc((*valp), (*allocedp)+1);
02997
02998 }
02999 t = (*valp) + (*vallenp);
03000
03001 te = stpcpy(t, token->u.string.string);
03002
03003 (*vallenp) += (te - t);
03004 break;
03005
03006 case PTOK_TAG:
03007 t = (*valp) + (*vallenp);
03008 te = formatValue(&token->u.tag, h, extensions, extCache,
03009 (token->u.tag.justOne ? 0 : element),
03010 valp, vallenp, allocedp);
03011 break;
03012
03013 case PTOK_COND:
03014 if (token->u.cond.tag.ext ||
03015 headerIsEntry(h, token->u.cond.tag.tag)) {
03016 condFormat = token->u.cond.ifFormat;
03017 condNumFormats = token->u.cond.numIfTokens;
03018 } else {
03019 condFormat = token->u.cond.elseFormat;
03020 condNumFormats = token->u.cond.numElseTokens;
03021 }
03022
03023 need = condNumFormats * 20;
03024 if (condFormat == NULL || need <= 0) break;
03025 if (((*vallenp) + need) >= (*allocedp)) {
03026 if ((*allocedp) <= need)
03027 (*allocedp) += need;
03028
03029 (*allocedp) <<= 1;
03030
03031
03032 (*valp) = xrealloc((*valp), (*allocedp)+1);
03033
03034 }
03035
03036 t = (*valp) + (*vallenp);
03037 for (i = 0; i < condNumFormats; i++)
03038 te = singleSprintf(h, condFormat + i, extensions, extCache,
03039 element, valp, vallenp, allocedp);
03040 break;
03041
03042 case PTOK_ARRAY:
03043 numElements = -1;
03044 for (i = 0; i < token->u.array.numTokens; i++) {
03045 if (token->u.array.format[i].type != PTOK_TAG ||
03046 token->u.array.format[i].u.tag.arrayCount ||
03047 token->u.array.format[i].u.tag.justOne) continue;
03048
03049 if (token->u.array.format[i].u.tag.ext) {
03050 const void * data;
03051
03052 if (getExtension(h, token->u.array.format[i].u.tag.ext,
03053 &type, &data, &numElements,
03054 extCache +
03055 token->u.array.format[i].u.tag.extNum))
03056 continue;
03057
03058 } else {
03059
03060 if (!headerGetEntry(h, token->u.array.format[i].u.tag.tag,
03061 &type, NULL, &numElements))
03062 continue;
03063
03064 }
03065 break;
03066 }
03067
03068 if (numElements == -1) {
03069 need = sizeof("(none)") - 1;
03070 if (((*vallenp) + need) >= (*allocedp)) {
03071 if ((*allocedp) <= need)
03072 (*allocedp) += need;
03073
03074 (*allocedp) <<= 1;
03075
03076
03077 (*valp) = xrealloc((*valp), (*allocedp)+1);
03078
03079 }
03080 t = (*valp) + (*vallenp);
03081
03082 te = stpcpy(t, "(none)");
03083
03084 (*vallenp) += (te - t);
03085 } else {
03086 need = numElements * token->u.array.numTokens * 10;
03087 if (need <= 0) break;
03088 if (((*vallenp) + need) >= (*allocedp)) {
03089 if ((*allocedp) <= need)
03090 (*allocedp) += need;
03091
03092 (*allocedp) <<= 1;
03093
03094
03095 (*valp) = xrealloc((*valp), (*allocedp)+1);
03096
03097 }
03098
03099 t = (*valp) + (*vallenp);
03100 for (j = 0; j < numElements; j++) {
03101 for (i = 0; i < token->u.array.numTokens; i++)
03102 te = singleSprintf(h, token->u.array.format + i,
03103 extensions, extCache, j,
03104 valp, vallenp, allocedp);
03105 }
03106 }
03107 break;
03108 }
03109
03110 return ((*valp) + (*vallenp));
03111 }
03112
03115 static extensionCache
03116 allocateExtensionCache(const headerSprintfExtension extensions)
03117
03118 {
03119 headerSprintfExtension ext = extensions;
03120 int i = 0;
03121
03122 while (ext->type != HEADER_EXT_LAST) {
03123 i++;
03124 if (ext->type == HEADER_EXT_MORE)
03125 ext = ext->u.more;
03126 else
03127 ext++;
03128 }
03129
03130
03131 return xcalloc(i, sizeof(struct extensionCache_s));
03132
03133 }
03134
03138 static extensionCache
03139 freeExtensionCache(const headerSprintfExtension extensions,
03140 extensionCache cache)
03141
03142 {
03143 headerSprintfExtension ext = extensions;
03144 int i = 0;
03145
03146 while (ext->type != HEADER_EXT_LAST) {
03147
03148 if (cache[i].freeit) cache[i].data = _free(cache[i].data);
03149
03150
03151 i++;
03152 if (ext->type == HEADER_EXT_MORE)
03153 ext = ext->u.more;
03154 else
03155 ext++;
03156 }
03157
03158 cache = _free(cache);
03159 return NULL;
03160 }
03161
03173 static
03174 char * headerSprintf(Header h, const char * fmt,
03175 const struct headerTagTableEntry_s * tbltags,
03176 const struct headerSprintfExtension_s * extensions,
03177 errmsg_t * errmsg)
03178
03179 {
03180
03181 headerSprintfExtension exts = (headerSprintfExtension) extensions;
03182 headerTagTableEntry tags = (headerTagTableEntry) tbltags;
03183
03184 char * t;
03185 char * fmtString;
03186 sprintfToken format;
03187 int numTokens;
03188 char * val = NULL;
03189 int vallen = 0;
03190 int alloced = 0;
03191 int i;
03192 extensionCache extCache;
03193
03194
03195 fmtString = xstrdup(fmt);
03196
03197
03198 if (parseFormat(fmtString, tags, exts, &format, &numTokens,
03199 NULL, PARSER_BEGIN, errmsg)) {
03200 fmtString = _free(fmtString);
03201 return NULL;
03202 }
03203
03204
03205 extCache = allocateExtensionCache(exts);
03206
03207 val = xstrdup("");
03208 for (i = 0; i < numTokens; i++) {
03209
03210
03211 t = singleSprintf(h, format + i, exts, extCache, 0,
03212 &val, &vallen, &alloced);
03213
03214
03215 }
03216
03217 if (val != NULL && vallen < alloced)
03218 val = xrealloc(val, vallen+1);
03219
03220 fmtString = _free(fmtString);
03221 extCache = freeExtensionCache(exts, extCache);
03222 format = freeFormat(format, numTokens);
03223
03224 return val;
03225 }
03226
03229 static char * octalFormat(int_32 type, hPTR_t data,
03230 char * formatPrefix, int padding, int element)
03231
03232 {
03233 char * val;
03234
03235 if (type != RPM_INT32_TYPE) {
03236 val = xstrdup(_("(not a number)"));
03237 } else {
03238 val = xmalloc(20 + padding);
03239
03240 strcat(formatPrefix, "o");
03241
03242
03243 sprintf(val, formatPrefix, *((int_32 *) data));
03244
03245 }
03246
03247 return val;
03248 }
03249
03252 static char * hexFormat(int_32 type, hPTR_t data,
03253 char * formatPrefix, int padding, int element)
03254
03255 {
03256 char * val;
03257
03258 if (type != RPM_INT32_TYPE) {
03259 val = xstrdup(_("(not a number)"));
03260 } else {
03261 val = xmalloc(20 + padding);
03262
03263 strcat(formatPrefix, "x");
03264
03265
03266 sprintf(val, formatPrefix, *((int_32 *) data));
03267
03268 }
03269
03270 return val;
03271 }
03272
03275 static char * realDateFormat(int_32 type, hPTR_t data,
03276 char * formatPrefix, int padding, int element,
03277 const char * strftimeFormat)
03278
03279 {
03280 char * val;
03281
03282 if (type != RPM_INT32_TYPE) {
03283 val = xstrdup(_("(not a number)"));
03284 } else {
03285 struct tm * tstruct;
03286 char buf[50];
03287
03288 val = xmalloc(50 + padding);
03289
03290 strcat(formatPrefix, "s");
03291
03292
03293
03294 { time_t dateint = *((int_32 *) data);
03295 tstruct = localtime(&dateint);
03296 }
03297 buf[0] = '\0';
03298 if (tstruct)
03299 (void) strftime(buf, sizeof(buf) - 1, strftimeFormat, tstruct);
03300
03301 sprintf(val, formatPrefix, buf);
03302
03303 }
03304
03305 return val;
03306 }
03307
03310 static char * dateFormat(int_32 type, hPTR_t data,
03311 char * formatPrefix, int padding, int element)
03312
03313 {
03314 return realDateFormat(type, data, formatPrefix, padding, element, "%c");
03315 }
03316
03319 static char * dayFormat(int_32 type, hPTR_t data,
03320 char * formatPrefix, int padding, int element)
03321
03322 {
03323 return realDateFormat(type, data, formatPrefix, padding, element,
03324 "%a %b %d %Y");
03325 }
03326
03329 static char * shescapeFormat(int_32 type, hPTR_t data,
03330 char * formatPrefix, int padding, int element)
03331
03332 {
03333 char * result, * dst, * src, * buf;
03334
03335 if (type == RPM_INT32_TYPE) {
03336 result = xmalloc(padding + 20);
03337
03338 strcat(formatPrefix, "d");
03339
03340
03341 sprintf(result, formatPrefix, *((int_32 *) data));
03342
03343 } else {
03344 buf = alloca(strlen(data) + padding + 2);
03345
03346 strcat(formatPrefix, "s");
03347
03348
03349 sprintf(buf, formatPrefix, data);
03350
03351
03352
03353 result = dst = xmalloc(strlen(buf) * 4 + 3);
03354 *dst++ = '\'';
03355 for (src = buf; *src != '\0'; src++) {
03356 if (*src == '\'') {
03357 *dst++ = '\'';
03358 *dst++ = '\\';
03359 *dst++ = '\'';
03360 *dst++ = '\'';
03361 } else {
03362 *dst++ = *src;
03363 }
03364 }
03365 *dst++ = '\'';
03366 *dst = '\0';
03367
03368
03369 }
03370
03371 return result;
03372 }
03373
03374
03375 const struct headerSprintfExtension_s headerDefaultFormats[] = {
03376 { HEADER_EXT_FORMAT, "octal", { octalFormat } },
03377 { HEADER_EXT_FORMAT, "hex", { hexFormat } },
03378 { HEADER_EXT_FORMAT, "date", { dateFormat } },
03379 { HEADER_EXT_FORMAT, "day", { dayFormat } },
03380 { HEADER_EXT_FORMAT, "shescape", { shescapeFormat } },
03381 { HEADER_EXT_LAST, NULL, { NULL } }
03382 };
03383
03384
03391 static
03392 void headerCopyTags(Header headerFrom, Header headerTo, hTAG_t tagstocopy)
03393
03394 {
03395 int * p;
03396
03397 if (headerFrom == headerTo)
03398 return;
03399
03400 for (p = tagstocopy; *p != 0; p++) {
03401 char *s;
03402 int_32 type;
03403 int_32 count;
03404 if (headerIsEntry(headerTo, *p))
03405 continue;
03406
03407 if (!headerGetEntryMinMemory(headerFrom, *p, &type,
03408 (hPTR_t *) &s, &count))
03409 continue;
03410
03411 (void) headerAddEntry(headerTo, *p, type, s, count);
03412 s = headerFreeData(s, type);
03413 }
03414 }
03415
03419 struct headerIteratorS {
03420 Header h;
03421 int next_index;
03422 };
03423
03429 static
03430 HeaderIterator headerFreeIterator( HeaderIterator hi)
03431
03432 {
03433 hi->h = headerFree(hi->h);
03434 hi = _free(hi);
03435 return hi;
03436 }
03437
03443 static
03444 HeaderIterator headerInitIterator(Header h)
03445
03446 {
03447 HeaderIterator hi = xmalloc(sizeof(*hi));
03448
03449 headerSort(h);
03450
03451 hi->h = headerLink(h);
03452 hi->next_index = 0;
03453 return hi;
03454 }
03455
03465 static
03466 int headerNextIterator(HeaderIterator hi,
03467 hTAG_t tag,
03468 hTYP_t type,
03469 hPTR_t * p,
03470 hCNT_t c)
03471
03472
03473
03474 {
03475 Header h = hi->h;
03476 int slot = hi->next_index;
03477 indexEntry entry = NULL;
03478 int rc;
03479
03480 for (slot = hi->next_index; slot < h->indexUsed; slot++) {
03481 entry = h->index + slot;
03482 if (!ENTRY_IS_REGION(entry))
03483 break;
03484 }
03485 hi->next_index = slot;
03486 if (entry == NULL || slot >= h->indexUsed)
03487 return 0;
03488
03489
03490 hi->next_index++;
03491
03492
03493 if (tag)
03494 *tag = entry->info.tag;
03495
03496 rc = copyEntry(entry, type, p, c, 0);
03497
03498
03499 return ((rc == 1) ? 1 : 0);
03500 }
03501
03507 static
03508 Header headerCopy(Header h)
03509
03510 {
03511 Header nh = headerNew();
03512 HeaderIterator hi;
03513 int_32 tag, type, count;
03514 hPTR_t ptr;
03515
03516
03517 for (hi = headerInitIterator(h);
03518 headerNextIterator(hi, &tag, &type, &ptr, &count);
03519 ptr = headerFreeData((void *)ptr, type))
03520 {
03521 if (ptr) (void) headerAddEntry(nh, tag, type, ptr, count);
03522 }
03523 hi = headerFreeIterator(hi);
03524
03525
03526 return headerReload(nh, HEADER_IMAGE);
03527 }
03528
03529
03530 static struct HV_s hdrVec1 = {
03531 headerLink,
03532 headerUnlink,
03533 headerFree,
03534 headerNew,
03535 headerSort,
03536 headerUnsort,
03537 headerSizeof,
03538 headerUnload,
03539 headerReload,
03540 headerCopy,
03541 headerLoad,
03542 headerCopyLoad,
03543 headerRead,
03544 headerWrite,
03545 headerIsEntry,
03546 headerFreeTag,
03547 headerGetEntry,
03548 headerGetEntryMinMemory,
03549 headerAddEntry,
03550 headerAppendEntry,
03551 headerAddOrAppendEntry,
03552 headerAddI18NString,
03553 headerModifyEntry,
03554 headerRemoveEntry,
03555 headerSprintf,
03556 headerCopyTags,
03557 headerFreeIterator,
03558 headerInitIterator,
03559 headerNextIterator,
03560 NULL, NULL,
03561 1
03562 };
03563
03564
03565
03566 HV_t hdrVec = &hdrVec1;
03567