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 size_t headerMaxbytes = (32*1024*1024);
00050
00055 #define hdrchkTags(_ntags) ((_ntags) & 0xffff0000)
00056
00061 #define hdrchkData(_nbytes) ((_nbytes) & 0xff000000)
00062
00066
00067 static int typeSizes[] = {
00068 0,
00069 1,
00070 1,
00071 2,
00072 4,
00073 -1,
00074 -1,
00075 1,
00076 -1,
00077 -1
00078 };
00079
00080
00081 HV_t hdrVec;
00082
00088 static inline void *
00089 _free( const void * p)
00090 {
00091 if (p != NULL) free((void *)p);
00092 return NULL;
00093 }
00094
00100 static
00101 Header headerLink(Header h)
00102
00103 {
00104
00105 if (h == NULL) return NULL;
00106
00107
00108 h->nrefs++;
00109
00110 if (_hdr_debug)
00111 fprintf(stderr, "--> h %p ++ %d at %s:%u\n", h, h->nrefs, __FILE__, __LINE__);
00112
00113
00114
00115 return h;
00116
00117 }
00118
00124 static
00125 Header headerUnlink( Header h)
00126
00127 {
00128 if (h == NULL) return NULL;
00129
00130 if (_hdr_debug)
00131 fprintf(stderr, "--> h %p -- %d at %s:%u\n", h, h->nrefs, __FILE__, __LINE__);
00132
00133 h->nrefs--;
00134 return NULL;
00135 }
00136
00142 static
00143 Header headerFree( Header h)
00144
00145 {
00146 (void) headerUnlink(h);
00147
00148
00149 if (h == NULL || h->nrefs > 0)
00150 return NULL;
00151
00152 if (h->index) {
00153 indexEntry entry = h->index;
00154 int i;
00155 for (i = 0; i < h->indexUsed; i++, entry++) {
00156 if ((h->flags & HEADERFLAG_ALLOCATED) && ENTRY_IS_REGION(entry)) {
00157 if (entry->length > 0) {
00158 int_32 * ei = entry->data;
00159 if ((ei - 2) == h->blob) h->blob = _free(h->blob);
00160 entry->data = NULL;
00161 }
00162 } else if (!ENTRY_IN_REGION(entry)) {
00163 entry->data = _free(entry->data);
00164 }
00165 entry->data = NULL;
00166 }
00167 h->index = _free(h->index);
00168 }
00169
00170 h = _free(h);
00171 return h;
00172
00173 }
00174
00179 static
00180 Header headerNew(void)
00181
00182 {
00183 Header h = xcalloc(1, sizeof(*h));
00184
00185
00186
00187 h->hv = *hdrVec;
00188
00189
00190 h->blob = NULL;
00191 h->indexAlloced = INDEX_MALLOC_SIZE;
00192 h->indexUsed = 0;
00193 h->flags |= HEADERFLAG_SORTED;
00194
00195 h->index = (h->indexAlloced
00196 ? xcalloc(h->indexAlloced, sizeof(*h->index))
00197 : NULL);
00198
00199 h->nrefs = 0;
00200
00201 return headerLink(h);
00202
00203 }
00204
00207 static int indexCmp(const void * avp, const void * bvp)
00208
00209 {
00210
00211 indexEntry ap = (indexEntry) avp, bp = (indexEntry) bvp;
00212
00213 return (ap->info.tag - bp->info.tag);
00214 }
00215
00220 static
00221 void headerSort(Header h)
00222
00223 {
00224 if (!(h->flags & HEADERFLAG_SORTED)) {
00225
00226 qsort(h->index, h->indexUsed, sizeof(*h->index), indexCmp);
00227
00228 h->flags |= HEADERFLAG_SORTED;
00229 }
00230 }
00231
00234 static int offsetCmp(const void * avp, const void * bvp)
00235 {
00236
00237 indexEntry ap = (indexEntry) avp, bp = (indexEntry) bvp;
00238
00239 int rc = (ap->info.offset - bp->info.offset);
00240
00241 if (rc == 0) {
00242
00243 if (ap->info.offset < 0)
00244 rc = (((char *)ap->data) - ((char *)bp->data));
00245 else
00246 rc = (ap->info.tag - bp->info.tag);
00247 }
00248 return rc;
00249 }
00250
00255 static
00256 void headerUnsort(Header h)
00257
00258 {
00259
00260 qsort(h->index, h->indexUsed, sizeof(*h->index), offsetCmp);
00261
00262 }
00263
00270 static
00271 unsigned int headerSizeof( Header h, enum hMagic magicp)
00272
00273 {
00274 indexEntry entry;
00275 unsigned int size = 0;
00276 unsigned int pad = 0;
00277 int i;
00278
00279 if (h == NULL)
00280 return size;
00281
00282 headerSort(h);
00283
00284 switch (magicp) {
00285 case HEADER_MAGIC_YES:
00286 size += sizeof(header_magic);
00287 break;
00288 case HEADER_MAGIC_NO:
00289 break;
00290 }
00291
00292
00293 size += 2 * sizeof(int_32);
00294
00295
00296 for (i = 0, entry = h->index; i < h->indexUsed; i++, entry++) {
00297 unsigned diff;
00298 int_32 type;
00299
00300
00301 if (ENTRY_IS_REGION(entry)) {
00302 size += entry->length;
00303
00304
00305 if (i == 0 && (h->flags & HEADERFLAG_LEGACY))
00306 size += sizeof(struct entryInfo_s) + entry->info.count;
00307
00308 continue;
00309 }
00310
00311
00312 if (entry->info.offset < 0)
00313 continue;
00314
00315
00316 type = entry->info.type;
00317
00318 if (typeSizes[type] > 1) {
00319 diff = typeSizes[type] - (size % typeSizes[type]);
00320 if (diff != typeSizes[type]) {
00321 size += diff;
00322 pad += diff;
00323 }
00324 }
00325
00326
00327
00328 size += sizeof(struct entryInfo_s) + entry->length;
00329
00330 }
00331
00332 return size;
00333 }
00334
00344 static int dataLength(int_32 type, hPTR_t p, int_32 count, int onDisk,
00345 hPTR_t pend)
00346
00347 {
00348 const unsigned char * s = p;
00349 const unsigned char * se = pend;
00350 int length = 0;
00351
00352 switch (type) {
00353 case RPM_STRING_TYPE:
00354 if (count != 1)
00355 return -1;
00356 while (*s++) {
00357 if (se && s > se)
00358 return -1;
00359 length++;
00360 }
00361 length++;
00362 break;
00363
00364 case RPM_STRING_ARRAY_TYPE:
00365 case RPM_I18NSTRING_TYPE:
00366
00367
00368
00369 if (onDisk) {
00370 while (count--) {
00371 length++;
00372 while (*s++) {
00373 if (se && s > se)
00374 return -1;
00375 length++;
00376 }
00377 }
00378 } else {
00379 const char ** av = (const char **)p;
00380
00381 while (count--) {
00382
00383 length += strlen(*av++) + 1;
00384 }
00385
00386 }
00387 break;
00388
00389 default:
00390
00391 if (typeSizes[type] == -1)
00392 return -1;
00393 length = typeSizes[(type & 0xf)] * count;
00394
00395 if (length < 0 || (se && (s + length) > se))
00396 return -1;
00397 break;
00398 }
00399
00400 return length;
00401 }
00402
00429 static int regionSwab( indexEntry entry, int il, int dl,
00430 entryInfo pe,
00431 unsigned char * dataStart,
00432 const unsigned char * dataEnd,
00433 int regionid)
00434
00435 {
00436 unsigned char * tprev = NULL;
00437 unsigned char * t = NULL;
00438 int tdel, tl = dl;
00439 struct indexEntry_s ieprev;
00440
00441
00442 memset(&ieprev, 0, sizeof(ieprev));
00443
00444 for (; il > 0; il--, pe++) {
00445 struct indexEntry_s ie;
00446 int_32 type;
00447
00448 ie.info.tag = ntohl(pe->tag);
00449 ie.info.type = ntohl(pe->type);
00450 if (ie.info.type < RPM_MIN_TYPE || ie.info.type > RPM_MAX_TYPE)
00451 return -1;
00452 ie.info.count = ntohl(pe->count);
00453 ie.info.offset = ntohl(pe->offset);
00454
00455 ie.data = t = dataStart + ie.info.offset;
00456 if (dataEnd && t >= dataEnd)
00457 return -1;
00458
00459 ie.length = dataLength(ie.info.type, ie.data, ie.info.count, 1, dataEnd);
00460 if (ie.length < 0 || hdrchkData(ie.length))
00461 return -1;
00462
00463 ie.rdlen = 0;
00464
00465 if (entry) {
00466 ie.info.offset = regionid;
00467
00468 *entry = ie;
00469
00470 entry++;
00471 }
00472
00473
00474 type = ie.info.type;
00475
00476 if (typeSizes[type] > 1) {
00477 unsigned diff;
00478 diff = typeSizes[type] - (dl % typeSizes[type]);
00479 if (diff != typeSizes[type]) {
00480 dl += diff;
00481 if (ieprev.info.type == RPM_I18NSTRING_TYPE)
00482 ieprev.length += diff;
00483 }
00484 }
00485
00486 tdel = (tprev ? (t - tprev) : 0);
00487 if (ieprev.info.type == RPM_I18NSTRING_TYPE)
00488 tdel = ieprev.length;
00489
00490 if (ie.info.tag >= HEADER_I18NTABLE) {
00491 tprev = t;
00492 } else {
00493 tprev = dataStart;
00494
00495
00496 if (ie.info.tag == HEADER_IMAGE)
00497 tprev -= REGION_TAG_COUNT;
00498
00499 }
00500
00501
00502 switch (ntohl(pe->type)) {
00503
00504 case RPM_INT32_TYPE:
00505 { int_32 * it = (int_32 *)t;
00506 for (; ie.info.count > 0; ie.info.count--, it += 1) {
00507 if (dataEnd && ((unsigned char *)it) >= dataEnd)
00508 return -1;
00509 *it = htonl(*it);
00510 }
00511 t = (char *) it;
00512 } break;
00513 case RPM_INT16_TYPE:
00514 { int_16 * it = (int_16 *) t;
00515 for (; ie.info.count > 0; ie.info.count--, it += 1) {
00516 if (dataEnd && ((unsigned char *)it) >= dataEnd)
00517 return -1;
00518 *it = htons(*it);
00519 }
00520 t = (char *) it;
00521 } break;
00522
00523 default:
00524 t += ie.length;
00525 break;
00526 }
00527
00528 dl += ie.length;
00529 tl += tdel;
00530 ieprev = ie;
00531
00532 }
00533 tdel = (tprev ? (t - tprev) : 0);
00534 tl += tdel;
00535
00536
00537
00538
00539
00540
00541
00542 if (tl+REGION_TAG_COUNT == dl)
00543 tl += REGION_TAG_COUNT;
00544
00545
00546 return dl;
00547 }
00548
00551 static void * doHeaderUnload(Header h,
00552 int * lengthPtr)
00553
00554
00555
00556 {
00557 int_32 * ei = NULL;
00558 entryInfo pe;
00559 char * dataStart;
00560 char * te;
00561 unsigned pad;
00562 unsigned len;
00563 int_32 il = 0;
00564 int_32 dl = 0;
00565 indexEntry entry;
00566 int_32 type;
00567 int i;
00568 int drlen, ndribbles;
00569 int driplen, ndrips;
00570 int legacy = 0;
00571
00572
00573 headerUnsort(h);
00574
00575
00576 pad = 0;
00577 drlen = ndribbles = driplen = ndrips = 0;
00578 for (i = 0, entry = h->index; i < h->indexUsed; i++, entry++) {
00579 if (ENTRY_IS_REGION(entry)) {
00580 int_32 rdl = -entry->info.offset;
00581 int_32 ril = rdl/sizeof(*pe);
00582 int rid = entry->info.offset;
00583
00584 il += ril;
00585 dl += entry->rdlen + entry->info.count;
00586
00587 if (i == 0 && (h->flags & HEADERFLAG_LEGACY))
00588 il += 1;
00589
00590
00591 for (; i < h->indexUsed && entry->info.offset <= rid+1; i++, entry++) {
00592 if (entry->info.offset <= rid)
00593 continue;
00594
00595
00596 type = entry->info.type;
00597 if (typeSizes[type] > 1) {
00598 unsigned diff;
00599 diff = typeSizes[type] - (dl % typeSizes[type]);
00600 if (diff != typeSizes[type]) {
00601 drlen += diff;
00602 pad += diff;
00603 dl += diff;
00604 }
00605 }
00606
00607 ndribbles++;
00608 il++;
00609 drlen += entry->length;
00610 dl += entry->length;
00611 }
00612 i--;
00613 entry--;
00614 continue;
00615 }
00616
00617
00618 if (entry->data == NULL || entry->length <= 0)
00619 continue;
00620
00621
00622 type = entry->info.type;
00623 if (typeSizes[type] > 1) {
00624 unsigned diff;
00625 diff = typeSizes[type] - (dl % typeSizes[type]);
00626 if (diff != typeSizes[type]) {
00627 driplen += diff;
00628 pad += diff;
00629 dl += diff;
00630 } else
00631 diff = 0;
00632 }
00633
00634 ndrips++;
00635 il++;
00636 driplen += entry->length;
00637 dl += entry->length;
00638 }
00639
00640
00641 if (hdrchkTags(il) || hdrchkData(dl))
00642 goto errxit;
00643
00644 len = sizeof(il) + sizeof(dl) + (il * sizeof(*pe)) + dl;
00645
00646
00647 ei = xmalloc(len);
00648 ei[0] = htonl(il);
00649 ei[1] = htonl(dl);
00650
00651
00652 pe = (entryInfo) &ei[2];
00653 dataStart = te = (char *) (pe + il);
00654
00655 pad = 0;
00656 for (i = 0, entry = h->index; i < h->indexUsed; i++, entry++) {
00657 const char * src;
00658 char *t;
00659 int count;
00660 int rdlen;
00661
00662 if (entry->data == NULL || entry->length <= 0)
00663 continue;
00664
00665 t = te;
00666 pe->tag = htonl(entry->info.tag);
00667 pe->type = htonl(entry->info.type);
00668 pe->count = htonl(entry->info.count);
00669
00670 if (ENTRY_IS_REGION(entry)) {
00671 int_32 rdl = -entry->info.offset;
00672 int_32 ril = rdl/sizeof(*pe) + ndribbles;
00673 int rid = entry->info.offset;
00674
00675 src = (char *)entry->data;
00676 rdlen = entry->rdlen;
00677
00678
00679 if (i == 0 && (h->flags & HEADERFLAG_LEGACY)) {
00680 int_32 stei[4];
00681
00682 legacy = 1;
00683
00684 memcpy(pe+1, src, rdl);
00685 memcpy(te, src + rdl, rdlen);
00686
00687 te += rdlen;
00688
00689 pe->offset = htonl(te - dataStart);
00690 stei[0] = pe->tag;
00691 stei[1] = pe->type;
00692 stei[2] = htonl(-rdl-entry->info.count);
00693 stei[3] = pe->count;
00694
00695 memcpy(te, stei, entry->info.count);
00696
00697 te += entry->info.count;
00698 ril++;
00699 rdlen += entry->info.count;
00700
00701 count = regionSwab(NULL, ril, 0, pe, t, NULL, 0);
00702 if (count != rdlen)
00703 goto errxit;
00704
00705 } else {
00706
00707
00708 memcpy(pe+1, src + sizeof(*pe), ((ril-1) * sizeof(*pe)));
00709 memcpy(te, src + (ril * sizeof(*pe)), rdlen+entry->info.count+drlen);
00710
00711 te += rdlen;
00712 {
00713 entryInfo se = (entryInfo)src;
00714
00715 int off = ntohl(se->offset);
00716 pe->offset = (off) ? htonl(te - dataStart) : htonl(off);
00717 }
00718 te += entry->info.count + drlen;
00719
00720 count = regionSwab(NULL, ril, 0, pe, t, NULL, 0);
00721 if (count != (rdlen + entry->info.count + drlen))
00722 goto errxit;
00723 }
00724
00725
00726 while (i < h->indexUsed && entry->info.offset <= rid+1) {
00727 i++;
00728 entry++;
00729 }
00730 i--;
00731 entry--;
00732 pe += ril;
00733 continue;
00734 }
00735
00736
00737 if (entry->data == NULL || entry->length <= 0)
00738 continue;
00739
00740
00741 type = entry->info.type;
00742 if (typeSizes[type] > 1) {
00743 unsigned diff;
00744 diff = typeSizes[type] - ((te - dataStart) % typeSizes[type]);
00745 if (diff != typeSizes[type]) {
00746
00747 memset(te, 0, diff);
00748
00749 te += diff;
00750 pad += diff;
00751 }
00752 }
00753
00754 pe->offset = htonl(te - dataStart);
00755
00756
00757
00758 switch (entry->info.type) {
00759 case RPM_INT32_TYPE:
00760 count = entry->info.count;
00761 src = entry->data;
00762 while (count--) {
00763 *((int_32 *)te) = htonl(*((int_32 *)src));
00764
00765 te += sizeof(int_32);
00766 src += sizeof(int_32);
00767
00768 }
00769 break;
00770
00771 case RPM_INT16_TYPE:
00772 count = entry->info.count;
00773 src = entry->data;
00774 while (count--) {
00775 *((int_16 *)te) = htons(*((int_16 *)src));
00776
00777 te += sizeof(int_16);
00778 src += sizeof(int_16);
00779
00780 }
00781 break;
00782
00783 default:
00784 memcpy(te, entry->data, entry->length);
00785 te += entry->length;
00786 break;
00787 }
00788
00789 pe++;
00790 }
00791
00792
00793 if (((char *)pe) != dataStart)
00794 goto errxit;
00795 if ((((char *)ei)+len) != te)
00796 goto errxit;
00797
00798 if (lengthPtr)
00799 *lengthPtr = len;
00800
00801 h->flags &= ~HEADERFLAG_SORTED;
00802 headerSort(h);
00803
00804 return (void *) ei;
00805
00806 errxit:
00807
00808 ei = _free(ei);
00809
00810 return (void *) ei;
00811 }
00812
00818 static
00819 void * headerUnload(Header h)
00820
00821 {
00822 int length;
00823
00824 void * uh = doHeaderUnload(h, &length);
00825
00826 return uh;
00827 }
00828
00836 static
00837 indexEntry findEntry( Header h, int_32 tag, int_32 type)
00838
00839 {
00840 indexEntry entry, entry2, last;
00841 struct indexEntry_s key;
00842
00843 if (h == NULL) return NULL;
00844 if (!(h->flags & HEADERFLAG_SORTED)) headerSort(h);
00845
00846 key.info.tag = tag;
00847
00848
00849 entry2 = entry =
00850 bsearch(&key, h->index, h->indexUsed, sizeof(*h->index), indexCmp);
00851
00852 if (entry == NULL)
00853 return NULL;
00854
00855 if (type == RPM_NULL_TYPE)
00856 return entry;
00857
00858
00859 while (entry->info.tag == tag && entry->info.type != type &&
00860 entry > h->index) entry--;
00861
00862 if (entry->info.tag == tag && entry->info.type == type)
00863 return entry;
00864
00865 last = h->index + h->indexUsed;
00866
00867 while (entry2->info.tag == tag && entry2->info.type != type &&
00868 entry2 < last) entry2++;
00869
00870
00871 if (entry->info.tag == tag && entry->info.type == type)
00872 return entry;
00873
00874 return NULL;
00875 }
00876
00886 static
00887 int headerRemoveEntry(Header h, int_32 tag)
00888
00889 {
00890 indexEntry last = h->index + h->indexUsed;
00891 indexEntry entry, first;
00892 int ne;
00893
00894 entry = findEntry(h, tag, RPM_NULL_TYPE);
00895 if (!entry) return 1;
00896
00897
00898 while (entry > h->index && (entry - 1)->info.tag == tag)
00899 entry--;
00900
00901
00902 for (first = entry; first < last; first++) {
00903 void * data;
00904 if (first->info.tag != tag)
00905 break;
00906 data = first->data;
00907 first->data = NULL;
00908 first->length = 0;
00909 if (ENTRY_IN_REGION(first))
00910 continue;
00911 data = _free(data);
00912 }
00913
00914 ne = (first - entry);
00915 if (ne > 0) {
00916 h->indexUsed -= ne;
00917 ne = last - first;
00918
00919 if (ne > 0)
00920 memmove(entry, first, (ne * sizeof(*entry)));
00921
00922 }
00923
00924 return 0;
00925 }
00926
00932 static
00933 Header headerLoad( void * uh)
00934
00935 {
00936 int_32 * ei = (int_32 *) uh;
00937 int_32 il = ntohl(ei[0]);
00938 int_32 dl = ntohl(ei[1]);
00939
00940 size_t pvlen = sizeof(il) + sizeof(dl) +
00941 (il * sizeof(struct entryInfo_s)) + dl;
00942
00943 void * pv = uh;
00944 Header h = NULL;
00945 entryInfo pe;
00946 unsigned char * dataStart;
00947 unsigned char * dataEnd;
00948 indexEntry entry;
00949 int rdlen;
00950 int i;
00951
00952
00953 if (hdrchkTags(il) || hdrchkData(dl))
00954 goto errxit;
00955
00956 ei = (int_32 *) pv;
00957
00958 pe = (entryInfo) &ei[2];
00959
00960 dataStart = (unsigned char *) (pe + il);
00961 dataEnd = dataStart + dl;
00962
00963 h = xcalloc(1, sizeof(*h));
00964
00965 h->hv = *hdrVec;
00966
00967
00968 h->blob = uh;
00969
00970 h->indexAlloced = il + 1;
00971 h->indexUsed = il;
00972 h->index = xcalloc(h->indexAlloced, sizeof(*h->index));
00973 h->flags |= HEADERFLAG_SORTED;
00974 h->nrefs = 0;
00975 h = headerLink(h);
00976
00977
00978
00979
00980
00981 if (ntohl(pe->tag) == 15 &&
00982 ntohl(pe->type) == RPM_STRING_TYPE &&
00983 ntohl(pe->count) == 1)
00984 {
00985 pe->tag = htonl(1079);
00986 }
00987
00988 entry = h->index;
00989 i = 0;
00990 if (!(htonl(pe->tag) < HEADER_I18NTABLE)) {
00991 h->flags |= HEADERFLAG_LEGACY;
00992 entry->info.type = REGION_TAG_TYPE;
00993 entry->info.tag = HEADER_IMAGE;
00994
00995 entry->info.count = REGION_TAG_COUNT;
00996
00997 entry->info.offset = ((unsigned char *)pe - dataStart);
00998
00999
01000 entry->data = pe;
01001
01002 entry->length = pvlen - sizeof(il) - sizeof(dl);
01003 rdlen = regionSwab(entry+1, il, 0, pe, dataStart, dataEnd, entry->info.offset);
01004 #if 0
01005 if (rdlen != dl)
01006 goto errxit;
01007 #endif
01008 entry->rdlen = rdlen;
01009 entry++;
01010 h->indexUsed++;
01011 } else {
01012 int_32 rdl;
01013 int_32 ril;
01014
01015 h->flags &= ~HEADERFLAG_LEGACY;
01016
01017 entry->info.type = htonl(pe->type);
01018 if (entry->info.type < RPM_MIN_TYPE || entry->info.type > RPM_MAX_TYPE)
01019 goto errxit;
01020 entry->info.count = htonl(pe->count);
01021
01022 if (hdrchkTags(entry->info.count))
01023 goto errxit;
01024
01025 { int off = ntohl(pe->offset);
01026
01027 if (hdrchkData(off))
01028 goto errxit;
01029 if (off) {
01030 size_t nb = REGION_TAG_COUNT;
01031 int_32 * stei = memcpy(alloca(nb), dataStart + off, nb);
01032 rdl = -ntohl(stei[2]);
01033 ril = rdl/sizeof(*pe);
01034 if (hdrchkTags(ril) || hdrchkData(rdl))
01035 goto errxit;
01036 entry->info.tag = htonl(pe->tag);
01037 } else {
01038 ril = il;
01039
01040 rdl = (ril * sizeof(struct entryInfo_s));
01041
01042 entry->info.tag = HEADER_IMAGE;
01043 }
01044 }
01045 entry->info.offset = -rdl;
01046
01047
01048 entry->data = pe;
01049
01050 entry->length = pvlen - sizeof(il) - sizeof(dl);
01051 rdlen = regionSwab(entry+1, ril-1, 0, pe+1, dataStart, dataEnd, entry->info.offset);
01052 if (rdlen < 0)
01053 goto errxit;
01054 entry->rdlen = rdlen;
01055
01056 if (ril < h->indexUsed) {
01057 indexEntry newEntry = entry + ril;
01058 int ne = (h->indexUsed - ril);
01059 int rid = entry->info.offset+1;
01060 int rc;
01061
01062
01063 rc = regionSwab(newEntry, ne, 0, pe+ril, dataStart, dataEnd, rid);
01064 if (rc < 0)
01065 goto errxit;
01066 rdlen += rc;
01067
01068 { indexEntry firstEntry = newEntry;
01069 int save = h->indexUsed;
01070 int j;
01071
01072
01073 h->indexUsed -= ne;
01074 for (j = 0; j < ne; j++, newEntry++) {
01075 (void) headerRemoveEntry(h, newEntry->info.tag);
01076 if (newEntry->info.tag == HEADER_BASENAMES)
01077 (void) headerRemoveEntry(h, HEADER_OLDFILENAMES);
01078 }
01079
01080
01081
01082 if (h->indexUsed < (save - ne)) {
01083 memmove(h->index + h->indexUsed, firstEntry,
01084 (ne * sizeof(*entry)));
01085 }
01086
01087 h->indexUsed += ne;
01088 }
01089 }
01090 }
01091
01092 h->flags &= ~HEADERFLAG_SORTED;
01093 headerSort(h);
01094
01095
01096 return h;
01097
01098
01099 errxit:
01100
01101 if (h) {
01102 h->index = _free(h->index);
01103
01104 h = _free(h);
01105
01106 }
01107
01108
01109 return h;
01110
01111 }
01112
01120 static
01121 Header headerReload( Header h, int tag)
01122
01123 {
01124 Header nh;
01125 int length;
01126
01127
01128 void * uh = doHeaderUnload(h, &length);
01129
01130
01131 h = headerFree(h);
01132
01133 if (uh == NULL)
01134 return NULL;
01135 nh = headerLoad(uh);
01136 if (nh == NULL) {
01137 uh = _free(uh);
01138 return NULL;
01139 }
01140 if (nh->flags & HEADERFLAG_ALLOCATED)
01141 uh = _free(uh);
01142 nh->flags |= HEADERFLAG_ALLOCATED;
01143 if (ENTRY_IS_REGION(nh->index)) {
01144
01145 if (tag == HEADER_SIGNATURES || tag == HEADER_IMMUTABLE)
01146 nh->index[0].info.tag = tag;
01147
01148 }
01149 return nh;
01150 }
01151
01157 static
01158 Header headerCopyLoad(const void * uh)
01159
01160 {
01161 int_32 * ei = (int_32 *) uh;
01162
01163 int_32 il = ntohl(ei[0]);
01164 int_32 dl = ntohl(ei[1]);
01165
01166
01167 size_t pvlen = sizeof(il) + sizeof(dl) +
01168 (il * sizeof(struct entryInfo_s)) + dl;
01169
01170 void * nuh = NULL;
01171 Header h = NULL;
01172
01173
01174
01175 if (!(hdrchkTags(il) || hdrchkData(dl)) && pvlen < headerMaxbytes) {
01176
01177 nuh = memcpy(xmalloc(pvlen), uh, pvlen);
01178
01179 if ((h = headerLoad(nuh)) != NULL)
01180 h->flags |= HEADERFLAG_ALLOCATED;
01181 }
01182
01183
01184 if (h == NULL)
01185 nuh = _free(nuh);
01186
01187 return h;
01188 }
01189
01196 static
01197 Header headerRead(FD_t fd, enum hMagic magicp)
01198
01199 {
01200 int_32 block[4];
01201 int_32 reserved;
01202 int_32 * ei = NULL;
01203 int_32 il;
01204 int_32 dl;
01205 int_32 magic;
01206 Header h = NULL;
01207 size_t len;
01208 int i;
01209
01210 memset(block, 0, sizeof(block));
01211 i = 2;
01212 if (magicp == HEADER_MAGIC_YES)
01213 i += 2;
01214
01215
01216 if (timedRead(fd, (char *)block, i*sizeof(*block)) != (i * sizeof(*block)))
01217 goto exit;
01218
01219
01220 i = 0;
01221
01222
01223 if (magicp == HEADER_MAGIC_YES) {
01224 magic = block[i++];
01225 if (memcmp(&magic, header_magic, sizeof(magic)))
01226 goto exit;
01227 reserved = block[i++];
01228 }
01229
01230 il = ntohl(block[i]); i++;
01231 dl = ntohl(block[i]); i++;
01232
01233
01234
01235 len = sizeof(il) + sizeof(dl) + (il * sizeof(struct entryInfo_s)) + dl;
01236
01237
01238
01239 if (hdrchkTags(il) || hdrchkData(dl) || len > headerMaxbytes)
01240 goto exit;
01241
01242
01243 ei = xmalloc(len);
01244 ei[0] = htonl(il);
01245 ei[1] = htonl(dl);
01246 len -= sizeof(il) + sizeof(dl);
01247
01248
01249
01250
01251 if (timedRead(fd, (char *)&ei[2], len) != len)
01252 goto exit;
01253
01254
01255
01256 h = headerLoad(ei);
01257
01258 exit:
01259 if (h) {
01260 if (h->flags & HEADERFLAG_ALLOCATED)
01261 ei = _free(ei);
01262 h->flags |= HEADERFLAG_ALLOCATED;
01263 } else if (ei)
01264 ei = _free(ei);
01265
01266 return h;
01267
01268 }
01269
01277 static
01278 int headerWrite(FD_t fd, Header h, enum hMagic magicp)
01279
01280
01281 {
01282 ssize_t nb;
01283 int length;
01284 const void * uh;
01285
01286 if (h == NULL)
01287 return 1;
01288
01289 uh = doHeaderUnload(h, &length);
01290
01291 if (uh == NULL)
01292 return 1;
01293 switch (magicp) {
01294 case HEADER_MAGIC_YES:
01295
01296
01297 nb = Fwrite(header_magic, sizeof(char), sizeof(header_magic), fd);
01298
01299
01300 if (nb != sizeof(header_magic))
01301 goto exit;
01302 break;
01303 case HEADER_MAGIC_NO:
01304 break;
01305 }
01306
01307
01308 nb = Fwrite(uh, sizeof(char), length, fd);
01309
01310
01311 exit:
01312 uh = _free(uh);
01313 return (nb == length ? 0 : 1);
01314 }
01315
01322 static
01323 int headerIsEntry(Header h, int_32 tag)
01324
01325 {
01326
01327 return (findEntry(h, tag, RPM_NULL_TYPE) ? 1 : 0);
01328
01329 }
01330
01341 static int copyEntry(const indexEntry entry,
01342 hTYP_t type,
01343 hPTR_t * p,
01344 hCNT_t c,
01345 int minMem)
01346
01347
01348 {
01349 int_32 count = entry->info.count;
01350 int rc = 1;
01351
01352 if (p)
01353 switch (entry->info.type) {
01354 case RPM_BIN_TYPE:
01355
01356
01357
01358
01359
01360
01361 if (ENTRY_IS_REGION(entry)) {
01362 int_32 * ei = ((int_32 *)entry->data) - 2;
01363
01364 entryInfo pe = (entryInfo) (ei + 2);
01365
01366
01367 char * dataStart = (char *) (pe + ntohl(ei[0]));
01368
01369 int_32 rdl = -entry->info.offset;
01370 int_32 ril = rdl/sizeof(*pe);
01371
01372
01373 rdl = entry->rdlen;
01374 count = 2 * sizeof(*ei) + (ril * sizeof(*pe)) + rdl;
01375 if (entry->info.tag == HEADER_IMAGE) {
01376 ril -= 1;
01377 pe += 1;
01378 } else {
01379 count += REGION_TAG_COUNT;
01380 rdl += REGION_TAG_COUNT;
01381 }
01382
01383
01384 *p = xmalloc(count);
01385 ei = (int_32 *) *p;
01386 ei[0] = htonl(ril);
01387 ei[1] = htonl(rdl);
01388
01389
01390 pe = (entryInfo) memcpy(ei + 2, pe, (ril * sizeof(*pe)));
01391
01392
01393 dataStart = (char *) memcpy(pe + ril, dataStart, rdl);
01394
01395
01396
01397 rc = regionSwab(NULL, ril, 0, pe, dataStart, NULL, 0);
01398
01399 rc = (rc < 0) ? 0 : 1;
01400 } else {
01401 count = entry->length;
01402 *p = (!minMem
01403 ? memcpy(xmalloc(count), entry->data, count)
01404 : entry->data);
01405 }
01406 break;
01407 case RPM_STRING_TYPE:
01408 if (count == 1) {
01409 *p = entry->data;
01410 break;
01411 }
01412
01413 case RPM_STRING_ARRAY_TYPE:
01414 case RPM_I18NSTRING_TYPE:
01415 { const char ** ptrEntry;
01416
01417 int tableSize = count * sizeof(char *);
01418
01419 char * t;
01420 int i;
01421
01422
01423
01424 if (minMem) {
01425 *p = xmalloc(tableSize);
01426 ptrEntry = (const char **) *p;
01427 t = entry->data;
01428 } else {
01429 t = xmalloc(tableSize + entry->length);
01430 *p = (void *)t;
01431 ptrEntry = (const char **) *p;
01432 t += tableSize;
01433 memcpy(t, entry->data, entry->length);
01434 }
01435
01436
01437 for (i = 0; i < count; i++) {
01438
01439 *ptrEntry++ = t;
01440
01441 t = strchr(t, 0);
01442 t++;
01443 }
01444 } break;
01445
01446 default:
01447 *p = entry->data;
01448 break;
01449 }
01450 if (type) *type = entry->info.type;
01451 if (c) *c = count;
01452 return rc;
01453 }
01454
01473 static int headerMatchLocale(const char *td, const char *l, const char *le)
01474
01475 {
01476 const char *fe;
01477
01478
01479 #if 0
01480 { const char *s, *ll, *CC, *EE, *dd;
01481 char *lbuf, *t.
01482
01483
01484 lbuf = alloca(le - l + 1);
01485 for (s = l, ll = t = lbuf; *s; s++, t++) {
01486 switch (*s) {
01487 case '_':
01488 *t = '\0';
01489 CC = t + 1;
01490 break;
01491 case '.':
01492 *t = '\0';
01493 EE = t + 1;
01494 break;
01495 case '@':
01496 *t = '\0';
01497 dd = t + 1;
01498 break;
01499 default:
01500 *t = *s;
01501 break;
01502 }
01503 }
01504
01505 if (ll)
01506 for (t = ll; *t; t++) *t = tolower(*t);
01507 if (CC)
01508 for (t = CC; *t; t++) *t = toupper(*t);
01509
01510
01511 }
01512 #endif
01513
01514
01515 if (strlen(td) == (le-l) && !strncmp(td, l, (le - l)))
01516 return 1;
01517
01518
01519 for (fe = l; fe < le && *fe != '@'; fe++)
01520 {};
01521 if (fe < le && !strncmp(td, l, (fe - l)))
01522 return 1;
01523
01524
01525 for (fe = l; fe < le && *fe != '.'; fe++)
01526 {};
01527 if (fe < le && !strncmp(td, l, (fe - l)))
01528 return 1;
01529
01530
01531 for (fe = l; fe < le && *fe != '_'; fe++)
01532 {};
01533 if (fe < le && !strncmp(td, l, (fe - l)))
01534 return 1;
01535
01536 return 0;
01537 }
01538
01545 static char *
01546 headerFindI18NString(Header h, indexEntry entry)
01547
01548 {
01549 const char *lang, *l, *le;
01550 indexEntry table;
01551
01552
01553 if ((lang = getenv("LANGUAGE")) == NULL &&
01554 (lang = getenv("LC_ALL")) == NULL &&
01555 (lang = getenv("LC_MESSAGES")) == NULL &&
01556 (lang = getenv("LANG")) == NULL)
01557 return entry->data;
01558
01559
01560 if ((table = findEntry(h, HEADER_I18NTABLE, RPM_STRING_ARRAY_TYPE)) == NULL)
01561 return entry->data;
01562
01563
01564
01565 for (l = lang; *l != '\0'; l = le) {
01566 const char *td;
01567 char *ed;
01568 int langNum;
01569
01570 while (*l && *l == ':')
01571 l++;
01572 if (*l == '\0')
01573 break;
01574 for (le = l; *le && *le != ':'; le++)
01575 {};
01576
01577
01578 for (langNum = 0, td = table->data, ed = entry->data;
01579 langNum < entry->info.count;
01580 langNum++, td += strlen(td) + 1, ed += strlen(ed) + 1) {
01581
01582 if (headerMatchLocale(td, l, le))
01583 return ed;
01584
01585 }
01586 }
01587
01588
01589 return entry->data;
01590 }
01591
01602 static int intGetEntry(Header h, int_32 tag,
01603 hTAG_t type,
01604 hPTR_t * p,
01605 hCNT_t c,
01606 int minMem)
01607
01608
01609 {
01610 indexEntry entry;
01611 int rc;
01612
01613
01614
01615 entry = findEntry(h, tag, RPM_NULL_TYPE);
01616
01617 if (entry == NULL) {
01618 if (type) type = 0;
01619 if (p) *p = NULL;
01620 if (c) *c = 0;
01621 return 0;
01622 }
01623
01624 switch (entry->info.type) {
01625 case RPM_I18NSTRING_TYPE:
01626 rc = 1;
01627 if (type) *type = RPM_STRING_TYPE;
01628 if (c) *c = 1;
01629
01630 if (p) *p = headerFindI18NString(h, entry);
01631
01632 break;
01633 default:
01634 rc = copyEntry(entry, type, p, c, minMem);
01635 break;
01636 }
01637
01638
01639 return ((rc == 1) ? 1 : 0);
01640 }
01641
01649 static void * headerFreeTag( Header h,
01650 const void * data, rpmTagType type)
01651
01652 {
01653 if (data) {
01654
01655 if (type == -1 ||
01656 type == RPM_STRING_ARRAY_TYPE ||
01657 type == RPM_I18NSTRING_TYPE ||
01658 type == RPM_BIN_TYPE)
01659 data = _free(data);
01660
01661 }
01662 return NULL;
01663 }
01664
01678 static
01679 int headerGetEntry(Header h, int_32 tag,
01680 hTYP_t type,
01681 void ** p,
01682 hCNT_t c)
01683
01684
01685 {
01686 return intGetEntry(h, tag, type, (hPTR_t *)p, c, 0);
01687 }
01688
01701 static
01702 int headerGetEntryMinMemory(Header h, int_32 tag,
01703 hTYP_t type,
01704 hPTR_t * p,
01705 hCNT_t c)
01706
01707
01708 {
01709 return intGetEntry(h, tag, type, p, c, 1);
01710 }
01711
01712 int headerGetRawEntry(Header h, int_32 tag, int_32 * type, hPTR_t * p,
01713 int_32 * c)
01714 {
01715 indexEntry entry;
01716 int rc;
01717
01718 if (p == NULL) return headerIsEntry(h, tag);
01719
01720
01721
01722 entry = findEntry(h, tag, RPM_NULL_TYPE);
01723
01724 if (!entry) {
01725 if (p) *p = NULL;
01726 if (c) *c = 0;
01727 return 0;
01728 }
01729
01730 rc = copyEntry(entry, type, p, c, 0);
01731
01732
01733 return ((rc == 1) ? 1 : 0);
01734 }
01735
01738 static void copyData(int_32 type, void * dstPtr, const void * srcPtr,
01739 int_32 cnt, int dataLength)
01740
01741 {
01742 switch (type) {
01743 case RPM_STRING_ARRAY_TYPE:
01744 case RPM_I18NSTRING_TYPE:
01745 { const char ** av = (const char **) srcPtr;
01746 char * t = dstPtr;
01747
01748
01749 while (cnt-- > 0 && dataLength > 0) {
01750 const char * s;
01751 if ((s = *av++) == NULL)
01752 continue;
01753 do {
01754 *t++ = *s++;
01755 } while (s[-1] && --dataLength > 0);
01756 }
01757
01758 } break;
01759
01760 default:
01761
01762 memmove(dstPtr, srcPtr, dataLength);
01763
01764 break;
01765 }
01766 }
01767
01776
01777 static void *
01778 grabData(int_32 type, hPTR_t p, int_32 c, int * lengthPtr)
01779
01780
01781 {
01782 void * data = NULL;
01783 int length;
01784
01785 length = dataLength(type, p, c, 0, NULL);
01786 if (length > 0) {
01787 data = xmalloc(length);
01788 copyData(type, data, p, c, length);
01789 }
01790
01791 if (lengthPtr)
01792 *lengthPtr = length;
01793 return data;
01794 }
01795
01810 static
01811 int headerAddEntry(Header h, int_32 tag, int_32 type, const void * p, int_32 c)
01812
01813 {
01814 indexEntry entry;
01815 void * data;
01816 int length;
01817
01818
01819 if (c <= 0)
01820 return 0;
01821
01822 length = 0;
01823
01824 data = grabData(type, p, c, &length);
01825
01826 if (data == NULL || length <= 0)
01827 return 0;
01828
01829
01830 if (h->indexUsed == h->indexAlloced) {
01831 h->indexAlloced += INDEX_MALLOC_SIZE;
01832 h->index = xrealloc(h->index, h->indexAlloced * sizeof(*h->index));
01833 }
01834
01835
01836 entry = h->index + h->indexUsed;
01837 entry->info.tag = tag;
01838 entry->info.type = type;
01839 entry->info.count = c;
01840 entry->info.offset = 0;
01841 entry->data = data;
01842 entry->length = length;
01843
01844
01845 if (h->indexUsed > 0 && tag < h->index[h->indexUsed-1].info.tag)
01846 h->flags &= ~HEADERFLAG_SORTED;
01847
01848 h->indexUsed++;
01849
01850 return 1;
01851 }
01852
01867 static
01868 int headerAppendEntry(Header h, int_32 tag, int_32 type,
01869 const void * p, int_32 c)
01870
01871 {
01872 indexEntry entry;
01873 int length;
01874
01875 if (type == RPM_STRING_TYPE || type == RPM_I18NSTRING_TYPE) {
01876
01877 return 0;
01878 }
01879
01880
01881 entry = findEntry(h, tag, type);
01882 if (!entry)
01883 return 0;
01884
01885 length = dataLength(type, p, c, 0, NULL);
01886 if (length < 0)
01887 return 0;
01888
01889 if (ENTRY_IN_REGION(entry)) {
01890 char * t = xmalloc(entry->length + length);
01891
01892 memcpy(t, entry->data, entry->length);
01893
01894 entry->data = t;
01895 entry->info.offset = 0;
01896 } else
01897 entry->data = xrealloc(entry->data, entry->length + length);
01898
01899 copyData(type, ((char *) entry->data) + entry->length, p, c, length);
01900
01901 entry->length += length;
01902
01903 entry->info.count += c;
01904
01905 return 1;
01906 }
01907
01918 static
01919 int headerAddOrAppendEntry(Header h, int_32 tag, int_32 type,
01920 const void * p, int_32 c)
01921
01922 {
01923 return (findEntry(h, tag, type)
01924 ? headerAppendEntry(h, tag, type, p, c)
01925 : headerAddEntry(h, tag, type, p, c));
01926 }
01927
01948 static
01949 int headerAddI18NString(Header h, int_32 tag, const char * string,
01950 const char * lang)
01951
01952 {
01953 indexEntry table, entry;
01954 const char ** strArray;
01955 int length;
01956 int ghosts;
01957 int i, langNum;
01958 char * buf;
01959
01960 table = findEntry(h, HEADER_I18NTABLE, RPM_STRING_ARRAY_TYPE);
01961 entry = findEntry(h, tag, RPM_I18NSTRING_TYPE);
01962
01963 if (!table && entry)
01964 return 0;
01965
01966 if (!table && !entry) {
01967 const char * charArray[2];
01968 int count = 0;
01969 if (!lang || (lang[0] == 'C' && lang[1] == '\0')) {
01970
01971 charArray[count++] = "C";
01972
01973 } else {
01974
01975 charArray[count++] = "C";
01976
01977 charArray[count++] = lang;
01978 }
01979 if (!headerAddEntry(h, HEADER_I18NTABLE, RPM_STRING_ARRAY_TYPE,
01980 &charArray, count))
01981 return 0;
01982 table = findEntry(h, HEADER_I18NTABLE, RPM_STRING_ARRAY_TYPE);
01983 }
01984
01985 if (!table)
01986 return 0;
01987
01988 if (!lang) lang = "C";
01989
01990
01991 { const char * l = table->data;
01992 for (langNum = 0; langNum < table->info.count; langNum++) {
01993 if (!strcmp(l, lang)) break;
01994 l += strlen(l) + 1;
01995 }
01996 }
01997
01998 if (langNum >= table->info.count) {
01999 length = strlen(lang) + 1;
02000 if (ENTRY_IN_REGION(table)) {
02001 char * t = xmalloc(table->length + length);
02002 memcpy(t, table->data, table->length);
02003 table->data = t;
02004 table->info.offset = 0;
02005 } else
02006 table->data = xrealloc(table->data, table->length + length);
02007 memmove(((char *)table->data) + table->length, lang, length);
02008 table->length += length;
02009 table->info.count++;
02010 }
02011
02012 if (!entry) {
02013 strArray = alloca(sizeof(*strArray) * (langNum + 1));
02014 for (i = 0; i < langNum; i++)
02015 strArray[i] = "";
02016 strArray[langNum] = string;
02017 return headerAddEntry(h, tag, RPM_I18NSTRING_TYPE, strArray,
02018 langNum + 1);
02019 } else if (langNum >= entry->info.count) {
02020 ghosts = langNum - entry->info.count;
02021
02022 length = strlen(string) + 1 + ghosts;
02023 if (ENTRY_IN_REGION(entry)) {
02024 char * t = xmalloc(entry->length + length);
02025 memcpy(t, entry->data, entry->length);
02026 entry->data = t;
02027 entry->info.offset = 0;
02028 } else
02029 entry->data = xrealloc(entry->data, entry->length + length);
02030
02031 memset(((char *)entry->data) + entry->length, '\0', ghosts);
02032 memmove(((char *)entry->data) + entry->length + ghosts, string, strlen(string)+1);
02033
02034 entry->length += length;
02035 entry->info.count = langNum + 1;
02036 } else {
02037 char *b, *be, *e, *ee, *t;
02038 size_t bn, sn, en;
02039
02040
02041 b = be = e = ee = entry->data;
02042 for (i = 0; i < table->info.count; i++) {
02043 if (i == langNum)
02044 be = ee;
02045 ee += strlen(ee) + 1;
02046 if (i == langNum)
02047 e = ee;
02048 }
02049
02050
02051 bn = (be-b);
02052 sn = strlen(string) + 1;
02053 en = (ee-e);
02054 length = bn + sn + en;
02055 t = buf = xmalloc(length);
02056
02057
02058 memcpy(t, b, bn);
02059 t += bn;
02060
02061 memcpy(t, string, sn);
02062 t += sn;
02063 memcpy(t, e, en);
02064 t += en;
02065
02066
02067
02068 entry->length -= strlen(be) + 1;
02069 entry->length += sn;
02070
02071 if (ENTRY_IN_REGION(entry)) {
02072 entry->info.offset = 0;
02073 } else
02074 entry->data = _free(entry->data);
02075
02076 entry->data = buf;
02077
02078 }
02079
02080 return 0;
02081 }
02082
02093 static
02094 int headerModifyEntry(Header h, int_32 tag, int_32 type,
02095 const void * p, int_32 c)
02096
02097 {
02098 indexEntry entry;
02099 void * oldData;
02100 void * data;
02101 int length;
02102
02103
02104 entry = findEntry(h, tag, type);
02105 if (!entry)
02106 return 0;
02107
02108 length = 0;
02109 data = grabData(type, p, c, &length);
02110 if (data == NULL || length <= 0)
02111 return 0;
02112
02113
02114 while (entry > h->index && (entry - 1)->info.tag == tag)
02115 entry--;
02116
02117
02118
02119 oldData = entry->data;
02120
02121 entry->info.count = c;
02122 entry->info.type = type;
02123 entry->data = data;
02124 entry->length = length;
02125
02126
02127 if (ENTRY_IN_REGION(entry)) {
02128 entry->info.offset = 0;
02129 } else
02130 oldData = _free(oldData);
02131
02132
02133 return 1;
02134 }
02135
02138 static char escapedChar(const char ch)
02139 {
02140 switch (ch) {
02141 case 'a': return '\a';
02142 case 'b': return '\b';
02143 case 'f': return '\f';
02144 case 'n': return '\n';
02145 case 'r': return '\r';
02146 case 't': return '\t';
02147 case 'v': return '\v';
02148 default: return ch;
02149 }
02150 }
02151
02158 static sprintfToken
02159 freeFormat( sprintfToken format, int num)
02160
02161 {
02162 int i;
02163
02164 if (format == NULL) return NULL;
02165 for (i = 0; i < num; i++) {
02166 switch (format[i].type) {
02167 case PTOK_ARRAY:
02168
02169 format[i].u.array.format =
02170 freeFormat(format[i].u.array.format,
02171 format[i].u.array.numTokens);
02172
02173 break;
02174 case PTOK_COND:
02175
02176 format[i].u.cond.ifFormat =
02177 freeFormat(format[i].u.cond.ifFormat,
02178 format[i].u.cond.numIfTokens);
02179 format[i].u.cond.elseFormat =
02180 freeFormat(format[i].u.cond.elseFormat,
02181 format[i].u.cond.numElseTokens);
02182
02183 break;
02184 case PTOK_NONE:
02185 case PTOK_TAG:
02186 case PTOK_STRING:
02187 default:
02188 break;
02189 }
02190 }
02191 format = _free(format);
02192 return NULL;
02193 }
02194
02197 static void findTag(char * name, const headerTagTableEntry tags,
02198 const headerSprintfExtension extensions,
02199 headerTagTableEntry * tagMatch,
02200 headerSprintfExtension * extMatch)
02201
02202
02203 {
02204 headerTagTableEntry entry;
02205 headerSprintfExtension ext;
02206 const char * tagname;
02207
02208 *tagMatch = NULL;
02209 *extMatch = NULL;
02210
02211 if (strncmp("RPMTAG_", name, sizeof("RPMTAG_")-1)) {
02212
02213 char * t = alloca(strlen(name) + sizeof("RPMTAG_"));
02214 (void) stpcpy( stpcpy(t, "RPMTAG_"), name);
02215 tagname = t;
02216
02217 } else {
02218 tagname = name;
02219 }
02220
02221
02222 ext = extensions;
02223 while (ext->type != HEADER_EXT_LAST) {
02224 if (ext->name != NULL && ext->type == HEADER_EXT_TAG
02225 && !xstrcasecmp(ext->name, tagname))
02226 break;
02227
02228 if (ext->type == HEADER_EXT_MORE)
02229 ext = ext->u.more;
02230 else
02231 ext++;
02232 }
02233
02234 if (ext->type == HEADER_EXT_TAG) {
02235 *extMatch = ext;
02236 return;
02237 }
02238
02239
02240 for (entry = tags; entry->name; entry++)
02241 if (entry->name && !xstrcasecmp(entry->name, tagname))
02242 break;
02243
02244 if (entry->name) {
02245 *tagMatch = entry;
02246 return;
02247 }
02248 }
02249
02250
02251 static int parseExpression(sprintfToken token, char * str,
02252 const headerTagTableEntry tags,
02253 const headerSprintfExtension extensions,
02254 char ** endPtr, errmsg_t * errmsg)
02255
02256 ;
02257
02260
02261 static int parseFormat( char * str, const headerTagTableEntry tags,
02262 const headerSprintfExtension extensions,
02263 sprintfToken * formatPtr, int * numTokensPtr,
02264 char ** endPtr, int state,
02265 errmsg_t * errmsg)
02266
02267
02268
02269 {
02270 char * chptr, * start, * next, * dst;
02271 sprintfToken format;
02272 int numTokens;
02273 int currToken;
02274 headerTagTableEntry tag;
02275 headerSprintfExtension ext;
02276 int i;
02277 int done = 0;
02278
02279
02280 numTokens = 0;
02281 if (str != NULL)
02282 for (chptr = str; *chptr != '\0'; chptr++)
02283 if (*chptr == '%') numTokens++;
02284 numTokens = numTokens * 2 + 1;
02285
02286 format = xcalloc(numTokens, sizeof(*format));
02287 if (endPtr) *endPtr = NULL;
02288
02289
02290 dst = start = str;
02291 currToken = -1;
02292 if (start != NULL)
02293 while (*start != '\0') {
02294 switch (*start) {
02295 case '%':
02296
02297 if (*(start + 1) == '%') {
02298 if (currToken < 0 || format[currToken].type != PTOK_STRING) {
02299 currToken++;
02300 format[currToken].type = PTOK_STRING;
02301
02302 dst = format[currToken].u.string.string = start;
02303
02304 }
02305
02306 start++;
02307
02308 *dst++ = *start++;
02309
02310 break;
02311 }
02312
02313 currToken++;
02314 *dst++ = '\0';
02315 start++;
02316
02317 if (*start == '|') {
02318 char * newEnd;
02319
02320 start++;
02321 if (parseExpression(format + currToken, start, tags,
02322 extensions, &newEnd, errmsg))
02323 {
02324 format = freeFormat(format, numTokens);
02325 return 1;
02326 }
02327 start = newEnd;
02328 break;
02329 }
02330
02331
02332 format[currToken].u.tag.format = start;
02333
02334 format[currToken].u.tag.pad = 0;
02335 format[currToken].u.tag.justOne = 0;
02336 format[currToken].u.tag.arrayCount = 0;
02337
02338 chptr = start;
02339 while (*chptr && *chptr != '{' && *chptr != '%') chptr++;
02340 if (!*chptr || *chptr == '%') {
02341
02342 if (errmsg) *errmsg = _("missing { after %");
02343
02344 format = freeFormat(format, numTokens);
02345 return 1;
02346 }
02347
02348 *chptr++ = '\0';
02349
02350 while (start < chptr) {
02351 if (xisdigit(*start)) {
02352 i = strtoul(start, &start, 10);
02353 format[currToken].u.tag.pad += i;
02354 } else {
02355 start++;
02356 }
02357 }
02358
02359 if (*start == '=') {
02360 format[currToken].u.tag.justOne = 1;
02361 start++;
02362 } else if (*start == '#') {
02363 format[currToken].u.tag.justOne = 1;
02364 format[currToken].u.tag.arrayCount = 1;
02365 start++;
02366 }
02367
02368 next = start;
02369 while (*next && *next != '}') next++;
02370 if (!*next) {
02371
02372 if (errmsg) *errmsg = _("missing } after %{");
02373
02374 format = freeFormat(format, numTokens);
02375 return 1;
02376 }
02377 *next++ = '\0';
02378
02379 chptr = start;
02380 while (*chptr && *chptr != ':') chptr++;
02381
02382 if (*chptr != '\0') {
02383 *chptr++ = '\0';
02384 if (!*chptr) {
02385
02386 if (errmsg) *errmsg = _("empty tag format");
02387
02388 format = freeFormat(format, numTokens);
02389 return 1;
02390 }
02391
02392 format[currToken].u.tag.type = chptr;
02393
02394 } else {
02395 format[currToken].u.tag.type = NULL;
02396 }
02397
02398 if (!*start) {
02399
02400 if (errmsg) *errmsg = _("empty tag name");
02401
02402 format = freeFormat(format, numTokens);
02403 return 1;
02404 }
02405
02406 i = 0;
02407 findTag(start, tags, extensions, &tag, &ext);
02408
02409 if (tag) {
02410 format[currToken].u.tag.ext = NULL;
02411 format[currToken].u.tag.tag = tag->val;
02412 } else if (ext) {
02413 format[currToken].u.tag.ext = ext->u.tagFunction;
02414 format[currToken].u.tag.extNum = ext - extensions;
02415 } else {
02416
02417 if (errmsg) *errmsg = _("unknown tag");
02418
02419 format = freeFormat(format, numTokens);
02420 return 1;
02421 }
02422
02423 format[currToken].type = PTOK_TAG;
02424
02425 start = next;
02426
02427 break;
02428
02429 case '[':
02430 *dst++ = '\0';
02431 *start++ = '\0';
02432 currToken++;
02433
02434 if (parseFormat(start, tags, extensions,
02435 &format[currToken].u.array.format,
02436 &format[currToken].u.array.numTokens,
02437 &start, PARSER_IN_ARRAY, errmsg)) {
02438 format = freeFormat(format, numTokens);
02439 return 1;
02440 }
02441
02442 if (!start) {
02443
02444 if (errmsg) *errmsg = _("] expected at end of array");
02445
02446 format = freeFormat(format, numTokens);
02447 return 1;
02448 }
02449
02450 dst = start;
02451
02452 format[currToken].type = PTOK_ARRAY;
02453
02454 break;
02455
02456 case ']':
02457 case '}':
02458 if ((*start == ']' && state != PARSER_IN_ARRAY) ||
02459 (*start == '}' && state != PARSER_IN_EXPR)) {
02460 if (*start == ']') {
02461
02462 if (errmsg) *errmsg = _("unexpected ]");
02463
02464 } else {
02465
02466 if (errmsg) *errmsg = _("unexpected }");
02467
02468 }
02469 format = freeFormat(format, numTokens);
02470 return 1;
02471 }
02472 *start++ = '\0';
02473 if (endPtr) *endPtr = start;
02474 done = 1;
02475 break;
02476
02477 default:
02478 if (currToken < 0 || format[currToken].type != PTOK_STRING) {
02479 currToken++;
02480 format[currToken].type = PTOK_STRING;
02481
02482 dst = format[currToken].u.string.string = start;
02483
02484 }
02485
02486 if (*start == '\\') {
02487 start++;
02488 *dst++ = escapedChar(*start++);
02489 } else {
02490 *dst++ = *start++;
02491 }
02492 break;
02493 }
02494 if (done)
02495 break;
02496 }
02497
02498
02499 if (dst != NULL)
02500 *dst = '\0';
02501
02502 currToken++;
02503 for (i = 0; i < currToken; i++) {
02504 if (format[i].type == PTOK_STRING)
02505 format[i].u.string.len = strlen(format[i].u.string.string);
02506 }
02507
02508 *numTokensPtr = currToken;
02509 *formatPtr = format;
02510
02511 return 0;
02512 }
02513
02514
02517
02518 static int parseExpression(sprintfToken token, char * str,
02519 const headerTagTableEntry tags,
02520 const headerSprintfExtension extensions,
02521 char ** endPtr,
02522 errmsg_t * errmsg)
02523 {
02524 headerTagTableEntry tag;
02525 headerSprintfExtension ext;
02526 char * chptr;
02527 char * end;
02528
02529 if (errmsg) *errmsg = NULL;
02530 chptr = str;
02531 while (*chptr && *chptr != '?') chptr++;
02532
02533 if (*chptr != '?') {
02534
02535 if (errmsg) *errmsg = _("? expected in expression");
02536
02537 return 1;
02538 }
02539
02540 *chptr++ = '\0';;
02541
02542 if (*chptr != '{') {
02543
02544 if (errmsg) *errmsg = _("{ expected after ? in expression");
02545
02546 return 1;
02547 }
02548
02549 chptr++;
02550
02551 if (parseFormat(chptr, tags, extensions, &token->u.cond.ifFormat,
02552 &token->u.cond.numIfTokens, &end, PARSER_IN_EXPR, errmsg))
02553 return 1;
02554
02555
02556 if (!(end && *end)) {
02557
02558 if (errmsg) *errmsg = _("} expected in expression");
02559
02560 token->u.cond.ifFormat =
02561 freeFormat(token->u.cond.ifFormat, token->u.cond.numIfTokens);
02562 return 1;
02563 }
02564
02565 chptr = end;
02566 if (*chptr != ':' && *chptr != '|') {
02567
02568 if (errmsg) *errmsg = _(": expected following ? subexpression");
02569
02570 token->u.cond.ifFormat =
02571 freeFormat(token->u.cond.ifFormat, token->u.cond.numIfTokens);
02572 return 1;
02573 }
02574
02575 if (*chptr == '|') {
02576 if (parseFormat(NULL, tags, extensions, &token->u.cond.elseFormat,
02577 &token->u.cond.numElseTokens, &end, PARSER_IN_EXPR, errmsg))
02578 {
02579 token->u.cond.ifFormat =
02580 freeFormat(token->u.cond.ifFormat, token->u.cond.numIfTokens);
02581 return 1;
02582 }
02583 } else {
02584 chptr++;
02585
02586 if (*chptr != '{') {
02587
02588 if (errmsg) *errmsg = _("{ expected after : in expression");
02589
02590 token->u.cond.ifFormat =
02591 freeFormat(token->u.cond.ifFormat, token->u.cond.numIfTokens);
02592 return 1;
02593 }
02594
02595 chptr++;
02596
02597 if (parseFormat(chptr, tags, extensions, &token->u.cond.elseFormat,
02598 &token->u.cond.numElseTokens, &end, PARSER_IN_EXPR,
02599 errmsg))
02600 return 1;
02601
02602
02603 if (!(end && *end)) {
02604
02605 if (errmsg) *errmsg = _("} expected in expression");
02606
02607 token->u.cond.ifFormat =
02608 freeFormat(token->u.cond.ifFormat, token->u.cond.numIfTokens);
02609 return 1;
02610 }
02611
02612 chptr = end;
02613 if (*chptr != '|') {
02614
02615 if (errmsg) *errmsg = _("| expected at end of expression");
02616
02617 token->u.cond.ifFormat =
02618 freeFormat(token->u.cond.ifFormat, token->u.cond.numIfTokens);
02619 token->u.cond.elseFormat =
02620 freeFormat(token->u.cond.elseFormat, token->u.cond.numElseTokens);
02621 return 1;
02622 }
02623 }
02624
02625 chptr++;
02626
02627 *endPtr = chptr;
02628
02629 findTag(str, tags, extensions, &tag, &ext);
02630
02631 if (tag) {
02632 token->u.cond.tag.ext = NULL;
02633 token->u.cond.tag.tag = tag->val;
02634 } else if (ext) {
02635 token->u.cond.tag.ext = ext->u.tagFunction;
02636 token->u.cond.tag.extNum = ext - extensions;
02637 } else {
02638 token->u.cond.tag.ext = NULL;
02639 token->u.cond.tag.tag = -1;
02640 }
02641
02642 token->type = PTOK_COND;
02643
02644 return 0;
02645 }
02646
02647
02657 static int getExtension(Header h, headerTagTagFunction fn,
02658 hTYP_t typeptr,
02659 hPTR_t * data,
02660 hCNT_t countptr,
02661 extensionCache ext)
02662
02663
02664
02665 {
02666 if (!ext->avail) {
02667 if (fn(h, &ext->type, &ext->data, &ext->count, &ext->freeit))
02668 return 1;
02669 ext->avail = 1;
02670 }
02671
02672 if (typeptr) *typeptr = ext->type;
02673 if (data) *data = ext->data;
02674 if (countptr) *countptr = ext->count;
02675
02676 return 0;
02677 }
02678
02681
02682 static char * formatValue(sprintfTag tag, Header h,
02683 const headerSprintfExtension extensions,
02684 extensionCache extCache, int element,
02685 char ** valp, int * vallenp, int * allocedp)
02686
02687
02688
02689 {
02690 char * val = NULL;
02691 int need = 0;
02692 char * t, * te;
02693 char buf[20];
02694 int_32 count, type;
02695 hPTR_t data;
02696 unsigned int intVal;
02697 const char ** strarray;
02698 int datafree = 0;
02699 int countBuf;
02700 headerTagFormatFunction tagtype = NULL;
02701 headerSprintfExtension ext;
02702
02703 memset(buf, 0, sizeof(buf));
02704
02705 if (tag->ext) {
02706
02707 if (getExtension(h, tag->ext, &type, &data, &count,
02708 extCache + tag->extNum))
02709 {
02710 count = 1;
02711 type = RPM_STRING_TYPE;
02712 data = "(none)";
02713 }
02714
02715 } else {
02716
02717 if (!headerGetEntry(h, tag->tag, &type, (void **)&data, &count)) {
02718 count = 1;
02719 type = RPM_STRING_TYPE;
02720 data = "(none)";
02721 }
02722
02723
02724 datafree = 1;
02725 }
02726
02727
02728 if (tag->arrayCount) {
02729
02730 if (datafree)
02731 data = headerFreeData(data, type);
02732
02733
02734 countBuf = count;
02735 data = &countBuf;
02736 count = 1;
02737 type = RPM_INT32_TYPE;
02738 }
02739
02740
02741 (void) stpcpy( stpcpy(buf, "%"), tag->format);
02742
02743
02744 if (tag->type) {
02745 ext = extensions;
02746 while (ext->type != HEADER_EXT_LAST) {
02747 if (ext->name != NULL && ext->type == HEADER_EXT_FORMAT
02748 && !strcmp(ext->name, tag->type))
02749 {
02750 tagtype = ext->u.formatFunction;
02751 break;
02752 }
02753
02754 if (ext->type == HEADER_EXT_MORE)
02755 ext = ext->u.more;
02756 else
02757 ext++;
02758 }
02759 }
02760
02761
02762 switch (type) {
02763 case RPM_STRING_ARRAY_TYPE:
02764 strarray = (const char **)data;
02765
02766 if (tagtype)
02767 val = tagtype(RPM_STRING_TYPE, strarray[element], buf, tag->pad, 0);
02768
02769 if (val) {
02770 need = strlen(val);
02771 } else {
02772 need = strlen(strarray[element]) + tag->pad + 20;
02773 val = xmalloc(need+1);
02774 strcat(buf, "s");
02775
02776 sprintf(val, buf, strarray[element]);
02777
02778 }
02779
02780
02781 if (datafree) data = _free(data);
02782
02783
02784 break;
02785
02786 case RPM_STRING_TYPE:
02787 if (tagtype)
02788 val = tagtype(RPM_STRING_ARRAY_TYPE, data, buf, tag->pad, 0);
02789
02790 if (val) {
02791 need = strlen(val);
02792 } else {
02793 need = strlen(data) + tag->pad + 20;
02794 val = xmalloc(need+1);
02795 strcat(buf, "s");
02796
02797 sprintf(val, buf, data);
02798
02799 }
02800 break;
02801
02802 case RPM_CHAR_TYPE:
02803 case RPM_INT8_TYPE:
02804 case RPM_INT16_TYPE:
02805 case RPM_INT32_TYPE:
02806 switch (type) {
02807 case RPM_CHAR_TYPE:
02808 case RPM_INT8_TYPE:
02809 intVal = *(((int_8 *) data) + element);
02810 break;
02811 case RPM_INT16_TYPE:
02812 intVal = *(((uint_16 *) data) + element);
02813 break;
02814 default:
02815 case RPM_INT32_TYPE:
02816 intVal = *(((int_32 *) data) + element);
02817 break;
02818 }
02819
02820 if (tagtype)
02821 val = tagtype(RPM_INT32_TYPE, &intVal, buf, tag->pad, element);
02822
02823 if (val) {
02824 need = strlen(val);
02825 } else {
02826 need = 10 + tag->pad + 20;
02827 val = xmalloc(need+1);
02828 strcat(buf, "d");
02829
02830 sprintf(val, buf, intVal);
02831
02832 }
02833 break;
02834
02835 case RPM_BIN_TYPE:
02836 if (tagtype)
02837 val = tagtype(RPM_BIN_TYPE, data, buf, tag->pad, count);
02838
02839 if (val) {
02840 need = count;
02841 } else {
02842 #ifdef NOTYET
02843 val = memcpy(xmalloc(count), data, count);
02844 #else
02845
02846 static char hex[] = "0123456789abcdef";
02847 const char * s = data;
02848
02849
02850 need = 2*count + tag->pad;
02851 val = t = xmalloc(need+1);
02852 while (count-- > 0) {
02853 unsigned int i;
02854 i = *s++;
02855 *t++ = hex[ (i >> 4) & 0xf ];
02856 *t++ = hex[ (i ) & 0xf ];
02857 }
02858 *t = '\0';
02859
02860 #endif
02861 }
02862 break;
02863
02864 default:
02865 need = sizeof("(unknown type)") - 1;
02866 val = xstrdup("(unknown type)");
02867 break;
02868 }
02869
02870
02871
02872 if (val && need > 0) {
02873 if (((*vallenp) + need) >= (*allocedp)) {
02874 if ((*allocedp) <= need)
02875 (*allocedp) += need;
02876
02877 (*allocedp) <<= 1;
02878
02879
02880 (*valp) = xrealloc((*valp), (*allocedp)+1);
02881
02882 }
02883 t = (*valp) + (*vallenp);
02884
02885 te = stpcpy(t, val);
02886
02887 (*vallenp) += (te - t);
02888 val = _free(val);
02889 }
02890
02891
02892 return ((*valp) + (*vallenp));
02893 }
02894
02897
02898 static char * singleSprintf(Header h, sprintfToken token,
02899 const headerSprintfExtension extensions,
02900 extensionCache extCache, int element,
02901 char ** valp, int * vallenp, int * allocedp)
02902
02903
02904
02905 {
02906 char * t, * te;
02907 int i, j;
02908 int numElements;
02909 int type;
02910 sprintfToken condFormat;
02911 int condNumFormats;
02912 int need;
02913
02914
02915
02916 switch (token->type) {
02917 case PTOK_NONE:
02918 break;
02919
02920 case PTOK_STRING:
02921 need = token->u.string.len;
02922 if (need <= 0) break;
02923 if (((*vallenp) + need) >= (*allocedp)) {
02924 if ((*allocedp) <= need)
02925 (*allocedp) += need;
02926
02927 (*allocedp) <<= 1;
02928
02929
02930 (*valp) = xrealloc((*valp), (*allocedp)+1);
02931
02932 }
02933 t = (*valp) + (*vallenp);
02934
02935 te = stpcpy(t, token->u.string.string);
02936
02937 (*vallenp) += (te - t);
02938 break;
02939
02940 case PTOK_TAG:
02941 t = (*valp) + (*vallenp);
02942 te = formatValue(&token->u.tag, h, extensions, extCache,
02943 (token->u.tag.justOne ? 0 : element),
02944 valp, vallenp, allocedp);
02945 break;
02946
02947 case PTOK_COND:
02948 if (token->u.cond.tag.ext ||
02949 headerIsEntry(h, token->u.cond.tag.tag)) {
02950 condFormat = token->u.cond.ifFormat;
02951 condNumFormats = token->u.cond.numIfTokens;
02952 } else {
02953 condFormat = token->u.cond.elseFormat;
02954 condNumFormats = token->u.cond.numElseTokens;
02955 }
02956
02957 need = condNumFormats * 20;
02958 if (condFormat == NULL || need <= 0) break;
02959 if (((*vallenp) + need) >= (*allocedp)) {
02960 if ((*allocedp) <= need)
02961 (*allocedp) += need;
02962
02963 (*allocedp) <<= 1;
02964
02965
02966 (*valp) = xrealloc((*valp), (*allocedp)+1);
02967
02968 }
02969
02970 t = (*valp) + (*vallenp);
02971 for (i = 0; i < condNumFormats; i++)
02972 te = singleSprintf(h, condFormat + i, extensions, extCache,
02973 element, valp, vallenp, allocedp);
02974 break;
02975
02976 case PTOK_ARRAY:
02977 numElements = -1;
02978 for (i = 0; i < token->u.array.numTokens; i++) {
02979 if (token->u.array.format[i].type != PTOK_TAG ||
02980 token->u.array.format[i].u.tag.arrayCount ||
02981 token->u.array.format[i].u.tag.justOne) continue;
02982
02983 if (token->u.array.format[i].u.tag.ext) {
02984 const void * data;
02985
02986 if (getExtension(h, token->u.array.format[i].u.tag.ext,
02987 &type, &data, &numElements,
02988 extCache +
02989 token->u.array.format[i].u.tag.extNum))
02990 continue;
02991
02992 } else {
02993
02994 if (!headerGetEntry(h, token->u.array.format[i].u.tag.tag,
02995 &type, NULL, &numElements))
02996 continue;
02997
02998 }
02999 break;
03000 }
03001
03002 if (numElements == -1) {
03003 need = sizeof("(none)") - 1;
03004 if (((*vallenp) + need) >= (*allocedp)) {
03005 if ((*allocedp) <= need)
03006 (*allocedp) += need;
03007
03008 (*allocedp) <<= 1;
03009
03010
03011 (*valp) = xrealloc((*valp), (*allocedp)+1);
03012
03013 }
03014 t = (*valp) + (*vallenp);
03015
03016 te = stpcpy(t, "(none)");
03017
03018 (*vallenp) += (te - t);
03019 } else {
03020 need = numElements * token->u.array.numTokens * 10;
03021 if (need <= 0) break;
03022 if (((*vallenp) + need) >= (*allocedp)) {
03023 if ((*allocedp) <= need)
03024 (*allocedp) += need;
03025
03026 (*allocedp) <<= 1;
03027
03028
03029 (*valp) = xrealloc((*valp), (*allocedp)+1);
03030
03031 }
03032
03033 t = (*valp) + (*vallenp);
03034 for (j = 0; j < numElements; j++) {
03035 for (i = 0; i < token->u.array.numTokens; i++)
03036 te = singleSprintf(h, token->u.array.format + i,
03037 extensions, extCache, j,
03038 valp, vallenp, allocedp);
03039 }
03040 }
03041 break;
03042 }
03043
03044 return ((*valp) + (*vallenp));
03045 }
03046
03049 static extensionCache
03050 allocateExtensionCache(const headerSprintfExtension extensions)
03051
03052 {
03053 headerSprintfExtension ext = extensions;
03054 int i = 0;
03055
03056 while (ext->type != HEADER_EXT_LAST) {
03057 i++;
03058 if (ext->type == HEADER_EXT_MORE)
03059 ext = ext->u.more;
03060 else
03061 ext++;
03062 }
03063
03064
03065 return xcalloc(i, sizeof(struct extensionCache_s));
03066
03067 }
03068
03072 static extensionCache
03073 freeExtensionCache(const headerSprintfExtension extensions,
03074 extensionCache cache)
03075
03076 {
03077 headerSprintfExtension ext = extensions;
03078 int i = 0;
03079
03080 while (ext->type != HEADER_EXT_LAST) {
03081
03082 if (cache[i].freeit) cache[i].data = _free(cache[i].data);
03083
03084
03085 i++;
03086 if (ext->type == HEADER_EXT_MORE)
03087 ext = ext->u.more;
03088 else
03089 ext++;
03090 }
03091
03092 cache = _free(cache);
03093 return NULL;
03094 }
03095
03107 static
03108 char * headerSprintf(Header h, const char * fmt,
03109 const struct headerTagTableEntry_s * tbltags,
03110 const struct headerSprintfExtension_s * extensions,
03111 errmsg_t * errmsg)
03112
03113 {
03114
03115 headerSprintfExtension exts = (headerSprintfExtension) extensions;
03116 headerTagTableEntry tags = (headerTagTableEntry) tbltags;
03117
03118 char * t;
03119 char * fmtString;
03120 sprintfToken format;
03121 int numTokens;
03122 char * val = NULL;
03123 int vallen = 0;
03124 int alloced = 0;
03125 int i;
03126 extensionCache extCache;
03127
03128
03129 fmtString = xstrdup(fmt);
03130
03131
03132 if (parseFormat(fmtString, tags, exts, &format, &numTokens,
03133 NULL, PARSER_BEGIN, errmsg)) {
03134 fmtString = _free(fmtString);
03135 return NULL;
03136 }
03137
03138
03139 extCache = allocateExtensionCache(exts);
03140
03141 val = xstrdup("");
03142 for (i = 0; i < numTokens; i++) {
03143
03144
03145 t = singleSprintf(h, format + i, exts, extCache, 0,
03146 &val, &vallen, &alloced);
03147
03148
03149 }
03150
03151 if (val != NULL && vallen < alloced)
03152 val = xrealloc(val, vallen+1);
03153
03154 fmtString = _free(fmtString);
03155 extCache = freeExtensionCache(exts, extCache);
03156 format = freeFormat(format, numTokens);
03157
03158 return val;
03159 }
03160
03163 static char * octalFormat(int_32 type, hPTR_t data,
03164 char * formatPrefix, int padding, int element)
03165
03166 {
03167 char * val;
03168
03169 if (type != RPM_INT32_TYPE) {
03170 val = xstrdup(_("(not a number)"));
03171 } else {
03172 val = xmalloc(20 + padding);
03173
03174 strcat(formatPrefix, "o");
03175
03176
03177 sprintf(val, formatPrefix, *((int_32 *) data));
03178
03179 }
03180
03181 return val;
03182 }
03183
03186 static char * hexFormat(int_32 type, hPTR_t data,
03187 char * formatPrefix, int padding, int element)
03188
03189 {
03190 char * val;
03191
03192 if (type != RPM_INT32_TYPE) {
03193 val = xstrdup(_("(not a number)"));
03194 } else {
03195 val = xmalloc(20 + padding);
03196
03197 strcat(formatPrefix, "x");
03198
03199
03200 sprintf(val, formatPrefix, *((int_32 *) data));
03201
03202 }
03203
03204 return val;
03205 }
03206
03209 static char * realDateFormat(int_32 type, hPTR_t data,
03210 char * formatPrefix, int padding, int element,
03211 const char * strftimeFormat)
03212
03213 {
03214 char * val;
03215
03216 if (type != RPM_INT32_TYPE) {
03217 val = xstrdup(_("(not a number)"));
03218 } else {
03219 struct tm * tstruct;
03220 char buf[50];
03221
03222 val = xmalloc(50 + padding);
03223
03224 strcat(formatPrefix, "s");
03225
03226
03227
03228 { time_t dateint = *((int_32 *) data);
03229 tstruct = localtime(&dateint);
03230 }
03231 buf[0] = '\0';
03232 if (tstruct)
03233 (void) strftime(buf, sizeof(buf) - 1, strftimeFormat, tstruct);
03234
03235 sprintf(val, formatPrefix, buf);
03236
03237 }
03238
03239 return val;
03240 }
03241
03244 static char * dateFormat(int_32 type, hPTR_t data,
03245 char * formatPrefix, int padding, int element)
03246
03247 {
03248 return realDateFormat(type, data, formatPrefix, padding, element, "%c");
03249 }
03250
03253 static char * dayFormat(int_32 type, hPTR_t data,
03254 char * formatPrefix, int padding, int element)
03255
03256 {
03257 return realDateFormat(type, data, formatPrefix, padding, element,
03258 "%a %b %d %Y");
03259 }
03260
03263 static char * shescapeFormat(int_32 type, hPTR_t data,
03264 char * formatPrefix, int padding, int element)
03265
03266 {
03267 char * result, * dst, * src, * buf;
03268
03269 if (type == RPM_INT32_TYPE) {
03270 result = xmalloc(padding + 20);
03271
03272 strcat(formatPrefix, "d");
03273
03274
03275 sprintf(result, formatPrefix, *((int_32 *) data));
03276
03277 } else {
03278 buf = alloca(strlen(data) + padding + 2);
03279
03280 strcat(formatPrefix, "s");
03281
03282
03283 sprintf(buf, formatPrefix, data);
03284
03285
03286
03287 result = dst = xmalloc(strlen(buf) * 4 + 3);
03288 *dst++ = '\'';
03289 for (src = buf; *src != '\0'; src++) {
03290 if (*src == '\'') {
03291 *dst++ = '\'';
03292 *dst++ = '\\';
03293 *dst++ = '\'';
03294 *dst++ = '\'';
03295 } else {
03296 *dst++ = *src;
03297 }
03298 }
03299 *dst++ = '\'';
03300 *dst = '\0';
03301
03302
03303 }
03304
03305 return result;
03306 }
03307
03308
03309 const struct headerSprintfExtension_s headerDefaultFormats[] = {
03310 { HEADER_EXT_FORMAT, "octal", { octalFormat } },
03311 { HEADER_EXT_FORMAT, "hex", { hexFormat } },
03312 { HEADER_EXT_FORMAT, "date", { dateFormat } },
03313 { HEADER_EXT_FORMAT, "day", { dayFormat } },
03314 { HEADER_EXT_FORMAT, "shescape", { shescapeFormat } },
03315 { HEADER_EXT_LAST, NULL, { NULL } }
03316 };
03317
03318
03325 static
03326 void headerCopyTags(Header headerFrom, Header headerTo, hTAG_t tagstocopy)
03327
03328 {
03329 int * p;
03330
03331 if (headerFrom == headerTo)
03332 return;
03333
03334 for (p = tagstocopy; *p != 0; p++) {
03335 char *s;
03336 int_32 type;
03337 int_32 count;
03338 if (headerIsEntry(headerTo, *p))
03339 continue;
03340
03341 if (!headerGetEntryMinMemory(headerFrom, *p, &type,
03342 (hPTR_t *) &s, &count))
03343 continue;
03344
03345 (void) headerAddEntry(headerTo, *p, type, s, count);
03346 s = headerFreeData(s, type);
03347 }
03348 }
03349
03353 struct headerIteratorS {
03354 Header h;
03355 int next_index;
03356 };
03357
03363 static
03364 HeaderIterator headerFreeIterator( HeaderIterator hi)
03365
03366 {
03367 hi->h = headerFree(hi->h);
03368 hi = _free(hi);
03369 return hi;
03370 }
03371
03377 static
03378 HeaderIterator headerInitIterator(Header h)
03379
03380 {
03381 HeaderIterator hi = xmalloc(sizeof(*hi));
03382
03383 headerSort(h);
03384
03385 hi->h = headerLink(h);
03386 hi->next_index = 0;
03387 return hi;
03388 }
03389
03399 static
03400 int headerNextIterator(HeaderIterator hi,
03401 hTAG_t tag,
03402 hTYP_t type,
03403 hPTR_t * p,
03404 hCNT_t c)
03405
03406
03407
03408 {
03409 Header h = hi->h;
03410 int slot = hi->next_index;
03411 indexEntry entry = NULL;
03412 int rc;
03413
03414 for (slot = hi->next_index; slot < h->indexUsed; slot++) {
03415 entry = h->index + slot;
03416 if (!ENTRY_IS_REGION(entry))
03417 break;
03418 }
03419 hi->next_index = slot;
03420 if (entry == NULL || slot >= h->indexUsed)
03421 return 0;
03422
03423 hi->next_index++;
03424
03425
03426 if (tag)
03427 *tag = entry->info.tag;
03428
03429 rc = copyEntry(entry, type, p, c, 0);
03430
03431
03432 return ((rc == 1) ? 1 : 0);
03433 }
03434
03440 static
03441 Header headerCopy(Header h)
03442
03443 {
03444 Header nh = headerNew();
03445 HeaderIterator hi;
03446 int_32 tag, type, count;
03447 hPTR_t ptr;
03448
03449
03450 for (hi = headerInitIterator(h);
03451 headerNextIterator(hi, &tag, &type, &ptr, &count);
03452 ptr = headerFreeData((void *)ptr, type))
03453 {
03454 if (ptr) (void) headerAddEntry(nh, tag, type, ptr, count);
03455 }
03456 hi = headerFreeIterator(hi);
03457
03458
03459 return headerReload(nh, HEADER_IMAGE);
03460 }
03461
03462
03463 static struct HV_s hdrVec1 = {
03464 headerLink,
03465 headerUnlink,
03466 headerFree,
03467 headerNew,
03468 headerSort,
03469 headerUnsort,
03470 headerSizeof,
03471 headerUnload,
03472 headerReload,
03473 headerCopy,
03474 headerLoad,
03475 headerCopyLoad,
03476 headerRead,
03477 headerWrite,
03478 headerIsEntry,
03479 headerFreeTag,
03480 headerGetEntry,
03481 headerGetEntryMinMemory,
03482 headerAddEntry,
03483 headerAppendEntry,
03484 headerAddOrAppendEntry,
03485 headerAddI18NString,
03486 headerModifyEntry,
03487 headerRemoveEntry,
03488 headerSprintf,
03489 headerCopyTags,
03490 headerFreeIterator,
03491 headerInitIterator,
03492 headerNextIterator,
03493 NULL, NULL,
03494 1
03495 };
03496
03497
03498
03499 HV_t hdrVec = &hdrVec1;
03500