00001
00005
00006
00007
00008
00009
00010
00011 #include "system.h"
00012
00013 #define __HEADER_PROTOTYPES__
00014
00015 #include <rpmio_internal.h>
00016 #include <header_internal.h>
00017
00018 #include "debug.h"
00019
00020
00021 int _hdr_debug = 0;
00022
00023
00024
00025
00026
00027
00028
00029
00030
00031 #define PARSER_BEGIN 0
00032 #define PARSER_IN_ARRAY 1
00033 #define PARSER_IN_EXPR 2
00034
00037
00038 static unsigned char header_magic[8] = {
00039 0x8e, 0xad, 0xe8, 0x01, 0x00, 0x00, 0x00, 0x00
00040 };
00041
00045
00046 static int typeAlign[16] = {
00047 1,
00048 1,
00049 1,
00050 2,
00051 4,
00052 8,
00053 1,
00054 1,
00055 1,
00056 1,
00057 1,
00058 1,
00059 0,
00060 0,
00061 0,
00062 0
00063 };
00064
00068
00069 static int typeSizes[16] = {
00070 0,
00071 1,
00072 1,
00073 2,
00074 4,
00075 8,
00076 -1,
00077 1,
00078 -1,
00079 -1,
00080 1,
00081 1,
00082 0,
00083 0,
00084 0,
00085 0
00086 };
00087
00091
00092 static size_t headerMaxbytes = (32*1024*1024);
00093
00098 #define hdrchkTags(_ntags) ((_ntags) & 0xffff0000)
00099
00103 #define hdrchkType(_type) ((_type) < RPM_MIN_TYPE || (_type) > RPM_MAX_TYPE)
00104
00109 #define hdrchkData(_nbytes) ((_nbytes) & 0xff000000)
00110
00114 #define hdrchkAlign(_type, _off) ((_off) & (typeAlign[_type]-1))
00115
00119 #define hdrchkRange(_dl, _off) ((_off) < 0 || (_off) > (_dl))
00120
00121
00122 HV_t hdrVec;
00123
00129 static
00130 Header headerLink(Header h)
00131
00132 {
00133
00134 if (h == NULL) return NULL;
00135
00136
00137 h->nrefs++;
00138
00139 if (_hdr_debug)
00140 fprintf(stderr, "--> h %p ++ %d at %s:%u\n", h, h->nrefs, __FILE__, __LINE__);
00141
00142
00143
00144 return h;
00145
00146 }
00147
00153 static
00154 Header headerUnlink( Header h)
00155
00156 {
00157 if (h == NULL) return NULL;
00158
00159 if (_hdr_debug)
00160 fprintf(stderr, "--> h %p -- %d at %s:%u\n", h, h->nrefs, __FILE__, __LINE__);
00161
00162 h->nrefs--;
00163 return NULL;
00164 }
00165
00171 static
00172 Header headerFree( Header h)
00173
00174 {
00175 (void) headerUnlink(h);
00176
00177
00178 if (h == NULL || h->nrefs > 0)
00179 return NULL;
00180
00181 if (h->index) {
00182 indexEntry entry = h->index;
00183 int i;
00184 for (i = 0; i < h->indexUsed; i++, entry++) {
00185 if ((h->flags & HEADERFLAG_ALLOCATED) && ENTRY_IS_REGION(entry)) {
00186 if (entry->length > 0) {
00187 int_32 * ei = entry->data;
00188 if ((ei - 2) == h->blob) h->blob = _free(h->blob);
00189 entry->data = NULL;
00190 }
00191 } else if (!ENTRY_IN_REGION(entry)) {
00192 entry->data = _free(entry->data);
00193 }
00194 entry->data = NULL;
00195 }
00196 h->index = _free(h->index);
00197 }
00198 h->origin = _free(h->origin);
00199
00200 h = _free(h);
00201 return h;
00202
00203 }
00204
00209 static
00210 Header headerNew(void)
00211
00212 {
00213 Header h = xcalloc(1, sizeof(*h));
00214
00215
00216
00217 h->hv = *hdrVec;
00218
00219
00220 h->blob = NULL;
00221 h->origin = NULL;
00222 h->instance = 0;
00223 h->indexAlloced = INDEX_MALLOC_SIZE;
00224 h->indexUsed = 0;
00225 h->flags |= HEADERFLAG_SORTED;
00226
00227 h->index = (h->indexAlloced
00228 ? xcalloc(h->indexAlloced, sizeof(*h->index))
00229 : NULL);
00230
00231 h->nrefs = 0;
00232
00233 return headerLink(h);
00234
00235 }
00236
00239 static int indexCmp(const void * avp, const void * bvp)
00240
00241 {
00242
00243 indexEntry ap = (indexEntry) avp, bp = (indexEntry) bvp;
00244
00245 return (ap->info.tag - bp->info.tag);
00246 }
00247
00252 static
00253 void headerSort(Header h)
00254
00255 {
00256 if (!(h->flags & HEADERFLAG_SORTED)) {
00257
00258 qsort(h->index, h->indexUsed, sizeof(*h->index), indexCmp);
00259
00260 h->flags |= HEADERFLAG_SORTED;
00261 }
00262 }
00263
00266 static int offsetCmp(const void * avp, const void * bvp)
00267 {
00268
00269 indexEntry ap = (indexEntry) avp, bp = (indexEntry) bvp;
00270
00271 int rc = (ap->info.offset - bp->info.offset);
00272
00273 if (rc == 0) {
00274
00275 if (ap->info.offset < 0)
00276 rc = (((char *)ap->data) - ((char *)bp->data));
00277 else
00278 rc = (ap->info.tag - bp->info.tag);
00279 }
00280 return rc;
00281 }
00282
00287 static
00288 void headerUnsort(Header h)
00289
00290 {
00291
00292 qsort(h->index, h->indexUsed, sizeof(*h->index), offsetCmp);
00293
00294 }
00295
00302 static
00303 unsigned int headerSizeof( Header h, enum hMagic magicp)
00304
00305 {
00306 indexEntry entry;
00307 unsigned int size = 0;
00308 unsigned int pad = 0;
00309 int i;
00310
00311 if (h == NULL)
00312 return size;
00313
00314 headerSort(h);
00315
00316 switch (magicp) {
00317 case HEADER_MAGIC_YES:
00318 size += sizeof(header_magic);
00319 break;
00320 case HEADER_MAGIC_NO:
00321 break;
00322 }
00323
00324
00325 size += 2 * sizeof(int_32);
00326
00327
00328 for (i = 0, entry = h->index; i < h->indexUsed; i++, entry++) {
00329 unsigned diff;
00330 int_32 type;
00331
00332
00333 if (ENTRY_IS_REGION(entry)) {
00334 size += entry->length;
00335
00336
00337 if (i == 0 && (h->flags & HEADERFLAG_LEGACY))
00338 size += sizeof(struct entryInfo_s) + entry->info.count;
00339
00340 continue;
00341 }
00342
00343
00344 if (entry->info.offset < 0)
00345 continue;
00346
00347
00348 type = entry->info.type;
00349
00350 if (typeSizes[type] > 1) {
00351 diff = typeSizes[type] - (size % typeSizes[type]);
00352 if (diff != typeSizes[type]) {
00353 size += diff;
00354 pad += diff;
00355 }
00356 }
00357
00358
00359
00360 size += sizeof(struct entryInfo_s) + entry->length;
00361
00362 }
00363
00364 return size;
00365 }
00366
00376 static int dataLength(int_32 type, hPTR_t p, int_32 count, int onDisk,
00377 hPTR_t pend)
00378
00379 {
00380 const unsigned char * s = p;
00381 const unsigned char * se = pend;
00382 int length = 0;
00383
00384 switch (type) {
00385 case RPM_STRING_TYPE:
00386 if (count != 1)
00387 return -1;
00388
00389 while (*s++) {
00390 if (se && s > se)
00391 return -1;
00392 length++;
00393 }
00394
00395 length++;
00396 break;
00397
00398 case RPM_STRING_ARRAY_TYPE:
00399 case RPM_I18NSTRING_TYPE:
00400
00401
00402
00403 if (onDisk) {
00404 while (count--) {
00405 length++;
00406
00407 while (*s++) {
00408 if (se && s > se)
00409 return -1;
00410 length++;
00411 }
00412
00413 }
00414 } else {
00415 const char ** av = (const char **)p;
00416
00417 while (count--) {
00418
00419 length += strlen(*av++) + 1;
00420 }
00421
00422 }
00423 break;
00424
00425 default:
00426
00427 if (typeSizes[type] == -1)
00428 return -1;
00429 length = typeSizes[(type & 0xf)] * count;
00430
00431 if (length < 0 || (se && (s + length) > se))
00432 return -1;
00433 break;
00434 }
00435
00436 return length;
00437 }
00438
00465 static int regionSwab( indexEntry entry, int il, int dl,
00466 entryInfo pe,
00467 unsigned char * dataStart,
00468 const unsigned char * dataEnd,
00469 int regionid)
00470
00471 {
00472 unsigned char * tprev = NULL;
00473 unsigned char * t = NULL;
00474 int tdel = 0;
00475 int tl = dl;
00476 struct indexEntry_s ieprev;
00477
00478
00479 memset(&ieprev, 0, sizeof(ieprev));
00480
00481 for (; il > 0; il--, pe++) {
00482 struct indexEntry_s ie;
00483 int_32 type;
00484
00485 ie.info.tag = ntohl(pe->tag);
00486 ie.info.type = ntohl(pe->type);
00487 ie.info.count = ntohl(pe->count);
00488 ie.info.offset = ntohl(pe->offset);
00489
00490 if (hdrchkType(ie.info.type))
00491 return -1;
00492 if (hdrchkData(ie.info.count))
00493 return -1;
00494 if (hdrchkData(ie.info.offset))
00495 return -1;
00496
00497 if (hdrchkAlign(ie.info.type, ie.info.offset))
00498 return -1;
00499
00500
00501 ie.data = t = dataStart + ie.info.offset;
00502 if (dataEnd && t >= dataEnd)
00503 return -1;
00504
00505 ie.length = dataLength(ie.info.type, ie.data, ie.info.count, 1, dataEnd);
00506 if (ie.length < 0 || hdrchkData(ie.length))
00507 return -1;
00508
00509 ie.rdlen = 0;
00510
00511 if (entry) {
00512 ie.info.offset = regionid;
00513
00514 *entry = ie;
00515
00516 entry++;
00517 }
00518
00519
00520 type = ie.info.type;
00521
00522 if (typeSizes[type] > 1) {
00523 unsigned diff;
00524 diff = typeSizes[type] - (dl % typeSizes[type]);
00525 if (diff != typeSizes[type]) {
00526 dl += diff;
00527 if (ieprev.info.type == RPM_I18NSTRING_TYPE)
00528 ieprev.length += diff;
00529 }
00530 }
00531
00532 tdel = (tprev ? (t - tprev) : 0);
00533 if (ieprev.info.type == RPM_I18NSTRING_TYPE)
00534 tdel = ieprev.length;
00535
00536 if (ie.info.tag >= HEADER_I18NTABLE) {
00537 tprev = t;
00538 } else {
00539 tprev = dataStart;
00540
00541
00542 if (ie.info.tag == HEADER_IMAGE)
00543 tprev -= REGION_TAG_COUNT;
00544
00545 }
00546
00547
00548 switch (ntohl(pe->type)) {
00549
00550 case RPM_INT64_TYPE:
00551 { int_64 * it = (int_64 *)t;
00552 int_32 b[2];
00553 for (; ie.info.count > 0; ie.info.count--, it += 1) {
00554 if (dataEnd && ((unsigned char *)it) >= dataEnd)
00555 return -1;
00556 b[1] = htonl(((int_32 *)it)[0]);
00557 b[0] = htonl(((int_32 *)it)[1]);
00558 if (b[1] != ((int_32 *)it)[0])
00559 memcpy(it, b, sizeof(b));
00560 }
00561 t = (char *) it;
00562 } break;
00563 case RPM_INT32_TYPE:
00564 { int_32 * it = (int_32 *)t;
00565 for (; ie.info.count > 0; ie.info.count--, it += 1) {
00566 if (dataEnd && ((unsigned char *)it) >= dataEnd)
00567 return -1;
00568 *it = htonl(*it);
00569 }
00570 t = (char *) it;
00571 } break;
00572 case RPM_INT16_TYPE:
00573 { int_16 * it = (int_16 *) t;
00574 for (; ie.info.count > 0; ie.info.count--, it += 1) {
00575 if (dataEnd && ((unsigned char *)it) >= dataEnd)
00576 return -1;
00577 *it = htons(*it);
00578 }
00579 t = (char *) it;
00580 } break;
00581
00582 default:
00583 t += ie.length;
00584 break;
00585 }
00586
00587 dl += ie.length;
00588 if (dataEnd && dataStart + dl > dataEnd) return -1;
00589 tl += tdel;
00590 ieprev = ie;
00591
00592 }
00593 tdel = (tprev ? (t - tprev) : 0);
00594 tl += tdel;
00595
00596
00597
00598
00599
00600
00601
00602 if (tl+REGION_TAG_COUNT == dl)
00603 tl += REGION_TAG_COUNT;
00604
00605
00606 return dl;
00607 }
00608
00614 static void * doHeaderUnload(Header h,
00615 int * lengthPtr)
00616
00617
00618
00619 {
00620 int_32 * ei = NULL;
00621 entryInfo pe;
00622 char * dataStart;
00623 char * te;
00624 unsigned pad;
00625 unsigned len;
00626 int_32 il = 0;
00627 int_32 dl = 0;
00628 indexEntry entry;
00629 int_32 type;
00630 int i;
00631 int drlen, ndribbles;
00632 int driplen, ndrips;
00633 int legacy = 0;
00634
00635
00636 headerUnsort(h);
00637
00638
00639 pad = 0;
00640 drlen = ndribbles = driplen = ndrips = 0;
00641 for (i = 0, entry = h->index; i < h->indexUsed; i++, entry++) {
00642 if (ENTRY_IS_REGION(entry)) {
00643 int_32 rdl = -entry->info.offset;
00644 int_32 ril = rdl/sizeof(*pe);
00645 int rid = entry->info.offset;
00646
00647 il += ril;
00648 dl += entry->rdlen + entry->info.count;
00649
00650 if (i == 0 && (h->flags & HEADERFLAG_LEGACY))
00651 il += 1;
00652
00653
00654 for (; i < h->indexUsed && entry->info.offset <= rid+1; i++, entry++) {
00655 if (entry->info.offset <= rid)
00656 continue;
00657
00658
00659 type = entry->info.type;
00660 if (typeSizes[type] > 1) {
00661 unsigned diff;
00662 diff = typeSizes[type] - (dl % typeSizes[type]);
00663 if (diff != typeSizes[type]) {
00664 drlen += diff;
00665 pad += diff;
00666 dl += diff;
00667 }
00668 }
00669
00670 ndribbles++;
00671 il++;
00672 drlen += entry->length;
00673 dl += entry->length;
00674 }
00675 i--;
00676 entry--;
00677 continue;
00678 }
00679
00680
00681 if (entry->data == NULL || entry->length <= 0)
00682 continue;
00683
00684
00685 type = entry->info.type;
00686 if (typeSizes[type] > 1) {
00687 unsigned diff;
00688 diff = typeSizes[type] - (dl % typeSizes[type]);
00689 if (diff != typeSizes[type]) {
00690 driplen += diff;
00691 pad += diff;
00692 dl += diff;
00693 } else
00694 diff = 0;
00695 }
00696
00697 ndrips++;
00698 il++;
00699 driplen += entry->length;
00700 dl += entry->length;
00701 }
00702
00703
00704 if (hdrchkTags(il) || hdrchkData(dl))
00705 goto errxit;
00706
00707 len = sizeof(il) + sizeof(dl) + (il * sizeof(*pe)) + dl;
00708
00709
00710 ei = xmalloc(len);
00711 ei[0] = htonl(il);
00712 ei[1] = htonl(dl);
00713
00714
00715 pe = (entryInfo) &ei[2];
00716 dataStart = te = (char *) (pe + il);
00717
00718 pad = 0;
00719 for (i = 0, entry = h->index; i < h->indexUsed; i++, entry++) {
00720 const char * src;
00721 char *t;
00722 int count;
00723 int rdlen;
00724
00725 if (entry->data == NULL || entry->length <= 0)
00726 continue;
00727
00728 t = te;
00729 pe->tag = htonl(entry->info.tag);
00730 pe->type = htonl(entry->info.type);
00731 pe->count = htonl(entry->info.count);
00732
00733 if (ENTRY_IS_REGION(entry)) {
00734 int_32 rdl = -entry->info.offset;
00735 int_32 ril = rdl/sizeof(*pe) + ndribbles;
00736 int rid = entry->info.offset;
00737
00738 src = (char *)entry->data;
00739 rdlen = entry->rdlen;
00740
00741
00742 if (i == 0 && (h->flags & HEADERFLAG_LEGACY)) {
00743 int_32 stei[4];
00744
00745 legacy = 1;
00746
00747 memcpy(pe+1, src, rdl);
00748 memcpy(te, src + rdl, rdlen);
00749
00750 te += rdlen;
00751
00752 pe->offset = htonl(te - dataStart);
00753 stei[0] = pe->tag;
00754 stei[1] = pe->type;
00755 stei[2] = htonl(-rdl-entry->info.count);
00756 stei[3] = pe->count;
00757
00758 memcpy(te, stei, entry->info.count);
00759
00760 te += entry->info.count;
00761 ril++;
00762 rdlen += entry->info.count;
00763
00764 count = regionSwab(NULL, ril, 0, pe, t, NULL, 0);
00765 if (count != rdlen)
00766 goto errxit;
00767
00768 } else {
00769
00770
00771 memcpy(pe+1, src + sizeof(*pe), ((ril-1) * sizeof(*pe)));
00772 memcpy(te, src + (ril * sizeof(*pe)), rdlen+entry->info.count+drlen);
00773
00774 te += rdlen;
00775 {
00776 entryInfo se = (entryInfo)src;
00777
00778 int off = ntohl(se->offset);
00779 pe->offset = (off) ? htonl(te - dataStart) : htonl(off);
00780 }
00781 te += entry->info.count + drlen;
00782
00783 count = regionSwab(NULL, ril, 0, pe, t, NULL, 0);
00784 if (count != (rdlen + entry->info.count + drlen))
00785 goto errxit;
00786 }
00787
00788
00789 while (i < h->indexUsed && entry->info.offset <= rid+1) {
00790 i++;
00791 entry++;
00792 }
00793 i--;
00794 entry--;
00795 pe += ril;
00796 continue;
00797 }
00798
00799
00800 if (entry->data == NULL || entry->length <= 0)
00801 continue;
00802
00803
00804 type = entry->info.type;
00805 if (typeSizes[type] > 1) {
00806 unsigned diff;
00807 diff = typeSizes[type] - ((te - dataStart) % typeSizes[type]);
00808 if (diff != typeSizes[type]) {
00809
00810 memset(te, 0, diff);
00811
00812 te += diff;
00813 pad += diff;
00814 }
00815 }
00816
00817 pe->offset = htonl(te - dataStart);
00818
00819
00820
00821 switch (entry->info.type) {
00822 case RPM_INT64_TYPE:
00823 { int_32 b[2];
00824 count = entry->info.count;
00825 src = entry->data;
00826 while (count--) {
00827 b[1] = htonl(((int_32 *)src)[0]);
00828 b[0] = htonl(((int_32 *)src)[1]);
00829 if (b[1] == ((int_32 *)src)[0])
00830 memcpy(te, src, sizeof(b));
00831 else
00832 memcpy(te, b, sizeof(b));
00833 te += sizeof(b);
00834 src += sizeof(b);
00835 }
00836 } break;
00837
00838 case RPM_INT32_TYPE:
00839 count = entry->info.count;
00840 src = entry->data;
00841 while (count--) {
00842 *((int_32 *)te) = htonl(*((int_32 *)src));
00843
00844 te += sizeof(int_32);
00845 src += sizeof(int_32);
00846
00847 }
00848 break;
00849
00850 case RPM_INT16_TYPE:
00851 count = entry->info.count;
00852 src = entry->data;
00853 while (count--) {
00854 *((int_16 *)te) = htons(*((int_16 *)src));
00855
00856 te += sizeof(int_16);
00857 src += sizeof(int_16);
00858
00859 }
00860 break;
00861
00862 default:
00863 memcpy(te, entry->data, entry->length);
00864 te += entry->length;
00865 break;
00866 }
00867
00868 pe++;
00869 }
00870
00871
00872 if (((char *)pe) != dataStart)
00873 goto errxit;
00874 if ((((char *)ei)+len) != te)
00875 goto errxit;
00876
00877 if (lengthPtr)
00878 *lengthPtr = len;
00879
00880 h->flags &= ~HEADERFLAG_SORTED;
00881 headerSort(h);
00882
00883 return (void *) ei;
00884
00885 errxit:
00886
00887 ei = _free(ei);
00888
00889 return (void *) ei;
00890 }
00891
00897 static
00898 void * headerUnload(Header h)
00899
00900 {
00901 int length;
00902
00903 void * uh = doHeaderUnload(h, &length);
00904
00905 return uh;
00906 }
00907
00915 static
00916 indexEntry findEntry( Header h, int_32 tag, int_32 type)
00917
00918 {
00919 indexEntry entry, entry2, last;
00920 struct indexEntry_s key;
00921
00922 if (h == NULL) return NULL;
00923 if (!(h->flags & HEADERFLAG_SORTED)) headerSort(h);
00924
00925 key.info.tag = tag;
00926
00927
00928 entry2 = entry =
00929 bsearch(&key, h->index, h->indexUsed, sizeof(*h->index), indexCmp);
00930
00931 if (entry == NULL)
00932 return NULL;
00933
00934 if (type == RPM_NULL_TYPE)
00935 return entry;
00936
00937
00938 while (entry->info.tag == tag && entry->info.type != type &&
00939 entry > h->index) entry--;
00940
00941 if (entry->info.tag == tag && entry->info.type == type)
00942 return entry;
00943
00944 last = h->index + h->indexUsed;
00945
00946 while (entry2->info.tag == tag && entry2->info.type != type &&
00947 entry2 < last) entry2++;
00948
00949
00950 if (entry->info.tag == tag && entry->info.type == type)
00951 return entry;
00952
00953 return NULL;
00954 }
00955
00965 static
00966 int headerRemoveEntry(Header h, int_32 tag)
00967
00968 {
00969 indexEntry last = h->index + h->indexUsed;
00970 indexEntry entry, first;
00971 int ne;
00972
00973 entry = findEntry(h, tag, RPM_NULL_TYPE);
00974 if (!entry) return 1;
00975
00976
00977 while (entry > h->index && (entry - 1)->info.tag == tag)
00978 entry--;
00979
00980
00981 for (first = entry; first < last; first++) {
00982 void * data;
00983 if (first->info.tag != tag)
00984 break;
00985 data = first->data;
00986 first->data = NULL;
00987 first->length = 0;
00988 if (ENTRY_IN_REGION(first))
00989 continue;
00990 data = _free(data);
00991 }
00992
00993 ne = (first - entry);
00994 if (ne > 0) {
00995 h->indexUsed -= ne;
00996 ne = last - first;
00997
00998 if (ne > 0)
00999 memmove(entry, first, (ne * sizeof(*entry)));
01000
01001 }
01002
01003 return 0;
01004 }
01005
01011 static
01012 Header headerLoad( void * uh)
01013
01014 {
01015 int_32 * ei = (int_32 *) uh;
01016 int_32 il = ntohl(ei[0]);
01017 int_32 dl = ntohl(ei[1]);
01018
01019 size_t pvlen = sizeof(il) + sizeof(dl) +
01020 (il * sizeof(struct entryInfo_s)) + dl;
01021
01022 void * pv = uh;
01023 Header h = NULL;
01024 entryInfo pe;
01025 unsigned char * dataStart;
01026 unsigned char * dataEnd;
01027 indexEntry entry;
01028 int rdlen;
01029 int i;
01030
01031
01032 if (hdrchkTags(il) || hdrchkData(dl))
01033 goto errxit;
01034
01035 ei = (int_32 *) pv;
01036
01037 pe = (entryInfo) &ei[2];
01038
01039 dataStart = (unsigned char *) (pe + il);
01040 dataEnd = dataStart + dl;
01041
01042 h = xcalloc(1, sizeof(*h));
01043
01044 h->hv = *hdrVec;
01045
01046
01047 h->blob = uh;
01048
01049 h->indexAlloced = il + 1;
01050 h->indexUsed = il;
01051 h->index = xcalloc(h->indexAlloced, sizeof(*h->index));
01052 h->flags |= HEADERFLAG_SORTED;
01053 h->nrefs = 0;
01054 h = headerLink(h);
01055
01056
01057
01058
01059
01060 if (ntohl(pe->tag) == 15 &&
01061 ntohl(pe->type) == RPM_STRING_TYPE &&
01062 ntohl(pe->count) == 1)
01063 {
01064 pe->tag = htonl(1079);
01065 }
01066
01067 entry = h->index;
01068 i = 0;
01069 if (!(htonl(pe->tag) < HEADER_I18NTABLE)) {
01070 h->flags |= HEADERFLAG_LEGACY;
01071 entry->info.type = REGION_TAG_TYPE;
01072 entry->info.tag = HEADER_IMAGE;
01073
01074 entry->info.count = REGION_TAG_COUNT;
01075
01076 entry->info.offset = ((unsigned char *)pe - dataStart);
01077
01078
01079 entry->data = pe;
01080
01081 entry->length = pvlen - sizeof(il) - sizeof(dl);
01082 rdlen = regionSwab(entry+1, il, 0, pe, dataStart, dataEnd, entry->info.offset);
01083 #if 0
01084 if (rdlen != dl)
01085 goto errxit;
01086 #endif
01087 entry->rdlen = rdlen;
01088 entry++;
01089 h->indexUsed++;
01090 } else {
01091 int_32 rdl;
01092 int_32 ril;
01093
01094 h->flags &= ~HEADERFLAG_LEGACY;
01095
01096 entry->info.type = htonl(pe->type);
01097 entry->info.count = htonl(pe->count);
01098
01099 if (hdrchkType(entry->info.type))
01100 goto errxit;
01101 if (hdrchkTags(entry->info.count))
01102 goto errxit;
01103
01104 { int off = ntohl(pe->offset);
01105
01106 if (hdrchkData(off))
01107 goto errxit;
01108 if (off) {
01109
01110 size_t nb = REGION_TAG_COUNT;
01111
01112 int_32 * stei = memcpy(alloca(nb), dataStart + off, nb);
01113 rdl = -ntohl(stei[2]);
01114 ril = rdl/sizeof(*pe);
01115 if (hdrchkTags(ril) || hdrchkData(rdl))
01116 goto errxit;
01117 entry->info.tag = htonl(pe->tag);
01118 } else {
01119 ril = il;
01120
01121 rdl = (ril * sizeof(struct entryInfo_s));
01122
01123 entry->info.tag = HEADER_IMAGE;
01124 }
01125 }
01126 entry->info.offset = -rdl;
01127
01128
01129 entry->data = pe;
01130
01131 entry->length = pvlen - sizeof(il) - sizeof(dl);
01132 rdlen = regionSwab(entry+1, ril-1, 0, pe+1, dataStart, dataEnd, entry->info.offset);
01133 if (rdlen < 0)
01134 goto errxit;
01135 entry->rdlen = rdlen;
01136
01137 if (ril < h->indexUsed) {
01138 indexEntry newEntry = entry + ril;
01139 int ne = (h->indexUsed - ril);
01140 int rid = entry->info.offset+1;
01141 int rc;
01142
01143
01144 rc = regionSwab(newEntry, ne, 0, pe+ril, dataStart, dataEnd, rid);
01145 if (rc < 0)
01146 goto errxit;
01147 rdlen += rc;
01148
01149 { indexEntry firstEntry = newEntry;
01150 int save = h->indexUsed;
01151 int j;
01152
01153
01154 h->indexUsed -= ne;
01155 for (j = 0; j < ne; j++, newEntry++) {
01156 (void) headerRemoveEntry(h, newEntry->info.tag);
01157 if (newEntry->info.tag == HEADER_BASENAMES)
01158 (void) headerRemoveEntry(h, HEADER_OLDFILENAMES);
01159 }
01160
01161
01162
01163 if (h->indexUsed < (save - ne)) {
01164 memmove(h->index + h->indexUsed, firstEntry,
01165 (ne * sizeof(*entry)));
01166 }
01167
01168 h->indexUsed += ne;
01169 }
01170 }
01171 }
01172
01173 h->flags &= ~HEADERFLAG_SORTED;
01174 headerSort(h);
01175
01176
01177 return h;
01178
01179
01180 errxit:
01181
01182 if (h) {
01183 h->index = _free(h->index);
01184
01185 h = _free(h);
01186
01187 }
01188
01189
01190 return h;
01191
01192 }
01193
01199 static
01200 const char * headerGetOrigin( Header h)
01201
01202 {
01203 return (h != NULL ? h->origin : NULL);
01204 }
01205
01212 static
01213 int headerSetOrigin( Header h, const char * origin)
01214
01215 {
01216 if (h != NULL) {
01217 h->origin = _free(h->origin);
01218 h->origin = xstrdup(origin);
01219 }
01220 return 0;
01221 }
01222
01228 static
01229 int headerGetInstance( Header h)
01230
01231 {
01232 return (h != NULL ? h->instance : 0);
01233 }
01234
01241 static
01242 int headerSetInstance( Header h, int instance)
01243
01244 {
01245 if (h != NULL)
01246 h->instance = instance;
01247 return 0;
01248 }
01249
01257 static
01258 Header headerReload( Header h, int tag)
01259
01260 {
01261 Header nh;
01262 int length;
01263
01264
01265 void * uh = doHeaderUnload(h, &length);
01266
01267 const char * origin;
01268 int_32 instance = h->instance;
01269 int xx;
01270
01271 origin = (h->origin != NULL ? xstrdup(h->origin) : NULL);
01272 h = headerFree(h);
01273
01274 if (uh == NULL)
01275 return NULL;
01276 nh = headerLoad(uh);
01277 if (nh == NULL) {
01278 uh = _free(uh);
01279 return NULL;
01280 }
01281 if (nh->flags & HEADERFLAG_ALLOCATED)
01282 uh = _free(uh);
01283 nh->flags |= HEADERFLAG_ALLOCATED;
01284 if (ENTRY_IS_REGION(nh->index)) {
01285
01286 if (tag == HEADER_SIGNATURES || tag == HEADER_IMMUTABLE)
01287 nh->index[0].info.tag = tag;
01288
01289 }
01290 if (origin != NULL) {
01291 xx = headerSetOrigin(nh, origin);
01292 origin = _free(origin);
01293 }
01294 xx = headerSetInstance(nh, instance);
01295 return nh;
01296 }
01297
01303 static
01304 Header headerCopyLoad(const void * uh)
01305
01306 {
01307 int_32 * ei = (int_32 *) uh;
01308
01309 int_32 il = ntohl(ei[0]);
01310 int_32 dl = ntohl(ei[1]);
01311
01312
01313 size_t pvlen = sizeof(il) + sizeof(dl) +
01314 (il * sizeof(struct entryInfo_s)) + dl;
01315
01316 void * nuh = NULL;
01317 Header h = NULL;
01318
01319
01320
01321 if (!(hdrchkTags(il) || hdrchkData(dl)) && pvlen < headerMaxbytes) {
01322
01323 nuh = memcpy(xmalloc(pvlen), uh, pvlen);
01324
01325 if ((h = headerLoad(nuh)) != NULL)
01326 h->flags |= HEADERFLAG_ALLOCATED;
01327 }
01328
01329
01330 if (h == NULL)
01331 nuh = _free(nuh);
01332
01333 return h;
01334 }
01335
01342 static
01343 Header headerRead(FD_t fd, enum hMagic magicp)
01344
01345 {
01346 int_32 block[4];
01347 int_32 reserved;
01348 int_32 * ei = NULL;
01349 int_32 il;
01350 int_32 dl;
01351 int_32 magic;
01352 Header h = NULL;
01353 size_t len;
01354 int i;
01355
01356 memset(block, 0, sizeof(block));
01357 i = 2;
01358 if (magicp == HEADER_MAGIC_YES)
01359 i += 2;
01360
01361
01362 if (timedRead(fd, (char *)block, i*sizeof(*block)) != (i * sizeof(*block)))
01363 goto exit;
01364
01365
01366 i = 0;
01367
01368
01369 if (magicp == HEADER_MAGIC_YES) {
01370 magic = block[i++];
01371 if (memcmp(&magic, header_magic, sizeof(magic)))
01372 goto exit;
01373 reserved = block[i++];
01374 }
01375
01376 il = ntohl(block[i]); i++;
01377 dl = ntohl(block[i]); i++;
01378
01379
01380
01381 len = sizeof(il) + sizeof(dl) + (il * sizeof(struct entryInfo_s)) + dl;
01382
01383
01384
01385 if (hdrchkTags(il) || hdrchkData(dl) || len > headerMaxbytes)
01386 goto exit;
01387
01388
01389 ei = xmalloc(len);
01390 ei[0] = htonl(il);
01391 ei[1] = htonl(dl);
01392 len -= sizeof(il) + sizeof(dl);
01393
01394
01395
01396
01397 if (timedRead(fd, (char *)&ei[2], len) != len)
01398 goto exit;
01399
01400
01401
01402 h = headerLoad(ei);
01403
01404 { const char * origin = fdGetOPath(fd);
01405 if (origin != NULL)
01406 (void) headerSetOrigin(h, origin);
01407 }
01408
01409 exit:
01410 if (h) {
01411 if (h->flags & HEADERFLAG_ALLOCATED)
01412 ei = _free(ei);
01413 h->flags |= HEADERFLAG_ALLOCATED;
01414 } else if (ei)
01415 ei = _free(ei);
01416
01417 return h;
01418
01419 }
01420
01428 static
01429 int headerWrite(FD_t fd, Header h, enum hMagic magicp)
01430
01431
01432 {
01433 ssize_t nb;
01434 int length;
01435 const void * uh;
01436
01437 if (h == NULL)
01438 return 1;
01439
01440 uh = doHeaderUnload(h, &length);
01441
01442 if (uh == NULL)
01443 return 1;
01444 switch (magicp) {
01445 case HEADER_MAGIC_YES:
01446
01447
01448 nb = Fwrite(header_magic, sizeof(char), sizeof(header_magic), fd);
01449
01450
01451 if (nb != sizeof(header_magic))
01452 goto exit;
01453 break;
01454 case HEADER_MAGIC_NO:
01455 break;
01456 }
01457
01458
01459 nb = Fwrite(uh, sizeof(char), length, fd);
01460
01461
01462 exit:
01463 uh = _free(uh);
01464 return (nb == length ? 0 : 1);
01465 }
01466
01473 static
01474 int headerIsEntry(Header h, int_32 tag)
01475
01476 {
01477
01478 return (findEntry(h, tag, RPM_NULL_TYPE) ? 1 : 0);
01479
01480 }
01481
01492 static int copyEntry(const indexEntry entry,
01493 hTYP_t type,
01494 hPTR_t * p,
01495 hCNT_t c,
01496 int minMem)
01497
01498
01499 {
01500 int_32 count = entry->info.count;
01501 int rc = 1;
01502
01503 if (p)
01504 switch (entry->info.type) {
01505 case RPM_BIN_TYPE:
01506
01507
01508
01509
01510
01511
01512 if (ENTRY_IS_REGION(entry)) {
01513 int_32 * ei = ((int_32 *)entry->data) - 2;
01514
01515 entryInfo pe = (entryInfo) (ei + 2);
01516
01517
01518 char * dataStart = (char *) (pe + ntohl(ei[0]));
01519
01520 int_32 rdl = -entry->info.offset;
01521 int_32 ril = rdl/sizeof(*pe);
01522
01523
01524 rdl = entry->rdlen;
01525 count = 2 * sizeof(*ei) + (ril * sizeof(*pe)) + rdl;
01526 if (entry->info.tag == HEADER_IMAGE) {
01527 ril -= 1;
01528 pe += 1;
01529 } else {
01530 count += REGION_TAG_COUNT;
01531 rdl += REGION_TAG_COUNT;
01532 }
01533
01534
01535 *p = xmalloc(count);
01536 ei = (int_32 *) *p;
01537 ei[0] = htonl(ril);
01538 ei[1] = htonl(rdl);
01539
01540
01541 pe = (entryInfo) memcpy(ei + 2, pe, (ril * sizeof(*pe)));
01542
01543
01544 dataStart = (char *) memcpy(pe + ril, dataStart, rdl);
01545
01546
01547
01548 rc = regionSwab(NULL, ril, 0, pe, dataStart, NULL, 0);
01549
01550 rc = (rc < 0) ? 0 : 1;
01551 } else {
01552 count = entry->length;
01553 *p = (!minMem
01554 ? memcpy(xmalloc(count), entry->data, count)
01555 : entry->data);
01556 }
01557 break;
01558 case RPM_STRING_TYPE:
01559 if (count == 1) {
01560 *p = entry->data;
01561 break;
01562 }
01563
01564 case RPM_STRING_ARRAY_TYPE:
01565 case RPM_I18NSTRING_TYPE:
01566 { const char ** ptrEntry;
01567
01568 int tableSize = count * sizeof(char *);
01569
01570 char * t;
01571 int i;
01572
01573
01574
01575 if (minMem) {
01576 *p = xmalloc(tableSize);
01577 ptrEntry = (const char **) *p;
01578 t = entry->data;
01579 } else {
01580 t = xmalloc(tableSize + entry->length);
01581 *p = (void *)t;
01582 ptrEntry = (const char **) *p;
01583 t += tableSize;
01584 memcpy(t, entry->data, entry->length);
01585 }
01586
01587
01588 for (i = 0; i < count; i++) {
01589
01590 *ptrEntry++ = t;
01591
01592 t = strchr(t, 0);
01593 t++;
01594 }
01595 } break;
01596
01597 case RPM_OPENPGP_TYPE:
01598 case RPM_ASN1_TYPE:
01599 default:
01600 *p = entry->data;
01601 break;
01602 }
01603 if (type) *type = entry->info.type;
01604 if (c) *c = count;
01605 return rc;
01606 }
01607
01626 static int headerMatchLocale(const char *td, const char *l, const char *le)
01627
01628 {
01629 const char *fe;
01630
01631
01632 #if 0
01633 { const char *s, *ll, *CC, *EE, *dd;
01634 char *lbuf, *t.
01635
01636
01637 lbuf = alloca(le - l + 1);
01638 for (s = l, ll = t = lbuf; *s; s++, t++) {
01639 switch (*s) {
01640 case '_':
01641 *t = '\0';
01642 CC = t + 1;
01643 break;
01644 case '.':
01645 *t = '\0';
01646 EE = t + 1;
01647 break;
01648 case '@':
01649 *t = '\0';
01650 dd = t + 1;
01651 break;
01652 default:
01653 *t = *s;
01654 break;
01655 }
01656 }
01657
01658 if (ll)
01659 for (t = ll; *t; t++) *t = tolower(*t);
01660 if (CC)
01661 for (t = CC; *t; t++) *t = toupper(*t);
01662
01663
01664 }
01665 #endif
01666
01667
01668 if (strlen(td) == (le-l) && !strncmp(td, l, (le - l)))
01669 return 1;
01670
01671
01672 for (fe = l; fe < le && *fe != '@'; fe++)
01673 {};
01674 if (fe < le && !strncmp(td, l, (fe - l)))
01675 return 1;
01676
01677
01678 for (fe = l; fe < le && *fe != '.'; fe++)
01679 {};
01680 if (fe < le && !strncmp(td, l, (fe - l)))
01681 return 1;
01682
01683
01684 for (fe = l; fe < le && *fe != '_'; fe++)
01685 {};
01686 if (fe < le && !strncmp(td, l, (fe - l)))
01687 return 1;
01688
01689 return 0;
01690 }
01691
01698 static char *
01699 headerFindI18NString(Header h, indexEntry entry)
01700
01701 {
01702 const char *lang, *l, *le;
01703 indexEntry table;
01704
01705
01706 if ((lang = getenv("LANGUAGE")) == NULL &&
01707 (lang = getenv("LC_ALL")) == NULL &&
01708 (lang = getenv("LC_MESSAGES")) == NULL &&
01709 (lang = getenv("LANG")) == NULL)
01710 return entry->data;
01711
01712
01713 if ((table = findEntry(h, HEADER_I18NTABLE, RPM_STRING_ARRAY_TYPE)) == NULL)
01714 return entry->data;
01715
01716
01717
01718 for (l = lang; *l != '\0'; l = le) {
01719 const char *td;
01720 char *ed;
01721 int langNum;
01722
01723 while (*l && *l == ':')
01724 l++;
01725 if (*l == '\0')
01726 break;
01727 for (le = l; *le && *le != ':'; le++)
01728 {};
01729
01730
01731 for (langNum = 0, td = table->data, ed = entry->data;
01732 langNum < entry->info.count;
01733 langNum++, td += strlen(td) + 1, ed += strlen(ed) + 1) {
01734
01735 if (headerMatchLocale(td, l, le))
01736 return ed;
01737
01738 }
01739 }
01740
01741
01742 return entry->data;
01743 }
01744
01755 static int intGetEntry(Header h, int_32 tag,
01756 hTAG_t type,
01757 hPTR_t * p,
01758 hCNT_t c,
01759 int minMem)
01760
01761
01762 {
01763 indexEntry entry;
01764 int rc;
01765
01766
01767
01768 entry = findEntry(h, tag, RPM_NULL_TYPE);
01769
01770 if (entry == NULL) {
01771 if (type) type = 0;
01772 if (p) *p = NULL;
01773 if (c) *c = 0;
01774 return 0;
01775 }
01776
01777 switch (entry->info.type) {
01778 case RPM_I18NSTRING_TYPE:
01779 rc = 1;
01780 if (type) *type = RPM_STRING_TYPE;
01781 if (c) *c = 1;
01782
01783 if (p) *p = headerFindI18NString(h, entry);
01784
01785 break;
01786 default:
01787 rc = copyEntry(entry, type, p, c, minMem);
01788 break;
01789 }
01790
01791
01792 return ((rc == 1) ? 1 : 0);
01793 }
01794
01802 static void * headerFreeTag( Header h,
01803 const void * data, rpmTagType type)
01804
01805 {
01806 if (data) {
01807
01808 if (type == -1 ||
01809 type == RPM_STRING_ARRAY_TYPE ||
01810 type == RPM_I18NSTRING_TYPE ||
01811 type == RPM_BIN_TYPE ||
01812 type == RPM_ASN1_TYPE ||
01813 type == RPM_OPENPGP_TYPE)
01814 data = _free(data);
01815
01816 }
01817 return NULL;
01818 }
01819
01833 static
01834 int headerGetEntry(Header h, int_32 tag,
01835 hTYP_t type,
01836 void * p,
01837 hCNT_t c)
01838
01839
01840 {
01841 return intGetEntry(h, tag, type, (hPTR_t *)p, c, 0);
01842 }
01843
01856 static
01857 int headerGetEntryMinMemory(Header h, int_32 tag,
01858 hTYP_t type,
01859 void * p,
01860 hCNT_t c)
01861
01862
01863 {
01864 return intGetEntry(h, tag, type, p, c, 1);
01865 }
01866
01867 int headerGetRawEntry(Header h, int_32 tag, int_32 * type, void * p, int_32 * c)
01868 {
01869 indexEntry entry;
01870 int rc;
01871
01872 if (p == NULL) return headerIsEntry(h, tag);
01873
01874
01875
01876 entry = findEntry(h, tag, RPM_NULL_TYPE);
01877
01878 if (!entry) {
01879 if (p) *(void **)p = NULL;
01880 if (c) *c = 0;
01881 return 0;
01882 }
01883
01884 rc = copyEntry(entry, type, p, c, 0);
01885
01886
01887 return ((rc == 1) ? 1 : 0);
01888 }
01889
01892 static void copyData(int_32 type, void * dstPtr, const void * srcPtr,
01893 int_32 cnt, int dataLength)
01894
01895 {
01896 switch (type) {
01897 case RPM_STRING_ARRAY_TYPE:
01898 case RPM_I18NSTRING_TYPE:
01899 { const char ** av = (const char **) srcPtr;
01900 char * t = dstPtr;
01901
01902
01903 while (cnt-- > 0 && dataLength > 0) {
01904 const char * s;
01905 if ((s = *av++) == NULL)
01906 continue;
01907 do {
01908 *t++ = *s++;
01909 } while (s[-1] && --dataLength > 0);
01910 }
01911
01912 } break;
01913
01914 default:
01915
01916 memmove(dstPtr, srcPtr, dataLength);
01917
01918 break;
01919 }
01920 }
01921
01930
01931 static void *
01932 grabData(int_32 type, hPTR_t p, int_32 c, int * lengthPtr)
01933
01934
01935 {
01936 void * data = NULL;
01937 int length;
01938
01939 length = dataLength(type, p, c, 0, NULL);
01940
01941 if (length > 0) {
01942 data = xmalloc(length);
01943 copyData(type, data, p, c, length);
01944 }
01945
01946
01947 if (lengthPtr)
01948 *lengthPtr = length;
01949 return data;
01950 }
01951
01966 static
01967 int headerAddEntry(Header h, int_32 tag, int_32 type, const void * p, int_32 c)
01968
01969 {
01970 indexEntry entry;
01971 void * data;
01972 int length;
01973
01974
01975 if (c <= 0)
01976 return 0;
01977
01978 if (hdrchkType(type))
01979 return 0;
01980 if (hdrchkData(c))
01981 return 0;
01982
01983 length = 0;
01984
01985 data = grabData(type, p, c, &length);
01986
01987 if (data == NULL || length <= 0)
01988 return 0;
01989
01990
01991 if (h->indexUsed == h->indexAlloced) {
01992 h->indexAlloced += INDEX_MALLOC_SIZE;
01993 h->index = xrealloc(h->index, h->indexAlloced * sizeof(*h->index));
01994 }
01995
01996
01997 entry = h->index + h->indexUsed;
01998 entry->info.tag = tag;
01999 entry->info.type = type;
02000 entry->info.count = c;
02001 entry->info.offset = 0;
02002 entry->data = data;
02003 entry->length = length;
02004
02005
02006 if (h->indexUsed > 0 && tag < h->index[h->indexUsed-1].info.tag)
02007 h->flags &= ~HEADERFLAG_SORTED;
02008
02009 h->indexUsed++;
02010
02011 return 1;
02012 }
02013
02028 static
02029 int headerAppendEntry(Header h, int_32 tag, int_32 type,
02030 const void * p, int_32 c)
02031
02032 {
02033 indexEntry entry;
02034 int length;
02035
02036 if (type == RPM_STRING_TYPE || type == RPM_I18NSTRING_TYPE) {
02037
02038 return 0;
02039 }
02040
02041
02042 entry = findEntry(h, tag, type);
02043 if (!entry)
02044 return 0;
02045
02046 length = dataLength(type, p, c, 0, NULL);
02047 if (length < 0)
02048 return 0;
02049
02050 if (ENTRY_IN_REGION(entry)) {
02051 char * t = xmalloc(entry->length + length);
02052
02053 memcpy(t, entry->data, entry->length);
02054
02055 entry->data = t;
02056 entry->info.offset = 0;
02057 } else
02058 entry->data = xrealloc(entry->data, entry->length + length);
02059
02060 copyData(type, ((char *) entry->data) + entry->length, p, c, length);
02061
02062 entry->length += length;
02063
02064 entry->info.count += c;
02065
02066 return 1;
02067 }
02068
02078 static
02079 int headerAddOrAppendEntry(Header h, int_32 tag, int_32 type,
02080 const void * p, int_32 c)
02081
02082 {
02083 return (findEntry(h, tag, type)
02084 ? headerAppendEntry(h, tag, type, p, c)
02085 : headerAddEntry(h, tag, type, p, c));
02086 }
02087
02108 static
02109 int headerAddI18NString(Header h, int_32 tag, const char * string,
02110 const char * lang)
02111
02112 {
02113 indexEntry table, entry;
02114 const char ** strArray;
02115 int length;
02116 int ghosts;
02117 int i, langNum;
02118 char * buf;
02119
02120 table = findEntry(h, HEADER_I18NTABLE, RPM_STRING_ARRAY_TYPE);
02121 entry = findEntry(h, tag, RPM_I18NSTRING_TYPE);
02122
02123 if (!table && entry)
02124 return 0;
02125
02126 if (!table && !entry) {
02127 const char * charArray[2];
02128 int count = 0;
02129 if (!lang || (lang[0] == 'C' && lang[1] == '\0')) {
02130
02131 charArray[count++] = "C";
02132
02133 } else {
02134
02135 charArray[count++] = "C";
02136
02137 charArray[count++] = lang;
02138 }
02139 if (!headerAddEntry(h, HEADER_I18NTABLE, RPM_STRING_ARRAY_TYPE,
02140 &charArray, count))
02141 return 0;
02142 table = findEntry(h, HEADER_I18NTABLE, RPM_STRING_ARRAY_TYPE);
02143 }
02144
02145 if (!table)
02146 return 0;
02147
02148 if (!lang) lang = "C";
02149
02150
02151 { const char * l = table->data;
02152 for (langNum = 0; langNum < table->info.count; langNum++) {
02153 if (!strcmp(l, lang)) break;
02154 l += strlen(l) + 1;
02155 }
02156 }
02157
02158 if (langNum >= table->info.count) {
02159 length = strlen(lang) + 1;
02160 if (ENTRY_IN_REGION(table)) {
02161 char * t = xmalloc(table->length + length);
02162 memcpy(t, table->data, table->length);
02163 table->data = t;
02164 table->info.offset = 0;
02165 } else
02166 table->data = xrealloc(table->data, table->length + length);
02167 memmove(((char *)table->data) + table->length, lang, length);
02168 table->length += length;
02169 table->info.count++;
02170 }
02171
02172 if (!entry) {
02173 strArray = alloca(sizeof(*strArray) * (langNum + 1));
02174 for (i = 0; i < langNum; i++)
02175 strArray[i] = "";
02176 strArray[langNum] = string;
02177 return headerAddEntry(h, tag, RPM_I18NSTRING_TYPE, strArray,
02178 langNum + 1);
02179 } else if (langNum >= entry->info.count) {
02180 ghosts = langNum - entry->info.count;
02181
02182 length = strlen(string) + 1 + ghosts;
02183 if (ENTRY_IN_REGION(entry)) {
02184 char * t = xmalloc(entry->length + length);
02185 memcpy(t, entry->data, entry->length);
02186 entry->data = t;
02187 entry->info.offset = 0;
02188 } else
02189 entry->data = xrealloc(entry->data, entry->length + length);
02190
02191 memset(((char *)entry->data) + entry->length, '\0', ghosts);
02192 memmove(((char *)entry->data) + entry->length + ghosts, string, strlen(string)+1);
02193
02194 entry->length += length;
02195 entry->info.count = langNum + 1;
02196 } else {
02197 char *b, *be, *e, *ee, *t;
02198 size_t bn, sn, en;
02199
02200
02201 b = be = e = ee = entry->data;
02202 for (i = 0; i < table->info.count; i++) {
02203 if (i == langNum)
02204 be = ee;
02205 ee += strlen(ee) + 1;
02206 if (i == langNum)
02207 e = ee;
02208 }
02209
02210
02211 bn = (be-b);
02212 sn = strlen(string) + 1;
02213 en = (ee-e);
02214 length = bn + sn + en;
02215 t = buf = xmalloc(length);
02216
02217
02218 memcpy(t, b, bn);
02219 t += bn;
02220
02221 memcpy(t, string, sn);
02222 t += sn;
02223 memcpy(t, e, en);
02224 t += en;
02225
02226
02227
02228 entry->length -= strlen(be) + 1;
02229 entry->length += sn;
02230
02231 if (ENTRY_IN_REGION(entry)) {
02232 entry->info.offset = 0;
02233 } else
02234 entry->data = _free(entry->data);
02235
02236 entry->data = buf;
02237
02238 }
02239
02240 return 0;
02241 }
02242
02253 static
02254 int headerModifyEntry(Header h, int_32 tag, int_32 type,
02255 const void * p, int_32 c)
02256
02257 {
02258 indexEntry entry;
02259 void * oldData;
02260 void * data;
02261 int length;
02262
02263
02264 entry = findEntry(h, tag, type);
02265 if (!entry)
02266 return 0;
02267
02268 length = 0;
02269 data = grabData(type, p, c, &length);
02270 if (data == NULL || length <= 0)
02271 return 0;
02272
02273
02274 while (entry > h->index && (entry - 1)->info.tag == tag)
02275 entry--;
02276
02277
02278
02279 oldData = entry->data;
02280
02281 entry->info.count = c;
02282 entry->info.type = type;
02283 entry->data = data;
02284 entry->length = length;
02285
02286
02287 if (ENTRY_IN_REGION(entry)) {
02288 entry->info.offset = 0;
02289 } else
02290 oldData = _free(oldData);
02291
02292
02293 return 1;
02294 }
02295
02298 static char escapedChar(const char ch)
02299 {
02300 switch (ch) {
02301 case 'a': return '\a';
02302 case 'b': return '\b';
02303 case 'f': return '\f';
02304 case 'n': return '\n';
02305 case 'r': return '\r';
02306 case 't': return '\t';
02307 case 'v': return '\v';
02308 default: return ch;
02309 }
02310 }
02311
02318 static sprintfToken
02319 freeFormat( sprintfToken format, int num)
02320
02321 {
02322 int i;
02323
02324 if (format == NULL) return NULL;
02325
02326 for (i = 0; i < num; i++) {
02327 switch (format[i].type) {
02328 case PTOK_ARRAY:
02329
02330 format[i].u.array.format =
02331 freeFormat(format[i].u.array.format,
02332 format[i].u.array.numTokens);
02333
02334 break;
02335 case PTOK_COND:
02336
02337 format[i].u.cond.ifFormat =
02338 freeFormat(format[i].u.cond.ifFormat,
02339 format[i].u.cond.numIfTokens);
02340 format[i].u.cond.elseFormat =
02341 freeFormat(format[i].u.cond.elseFormat,
02342 format[i].u.cond.numElseTokens);
02343
02344 break;
02345 case PTOK_NONE:
02346 case PTOK_TAG:
02347 case PTOK_STRING:
02348 default:
02349 break;
02350 }
02351 }
02352 format = _free(format);
02353 return NULL;
02354 }
02355
02359 struct headerIterator_s {
02360
02361 Header h;
02362
02363 int next_index;
02364 };
02365
02371 static
02372 HeaderIterator headerFreeIterator( HeaderIterator hi)
02373
02374 {
02375 if (hi != NULL) {
02376 hi->h = headerFree(hi->h);
02377 hi = _free(hi);
02378 }
02379 return hi;
02380 }
02381
02387 static
02388 HeaderIterator headerInitIterator(Header h)
02389
02390 {
02391 HeaderIterator hi = xmalloc(sizeof(*hi));
02392
02393 headerSort(h);
02394
02395 hi->h = headerLink(h);
02396 hi->next_index = 0;
02397 return hi;
02398 }
02399
02409 static
02410 int headerNextIterator(HeaderIterator hi,
02411 hTAG_t tag,
02412 hTYP_t type,
02413 hPTR_t * p,
02414 hCNT_t c)
02415
02416
02417
02418 {
02419 Header h = hi->h;
02420 int slot = hi->next_index;
02421 indexEntry entry = NULL;
02422 int rc;
02423
02424 for (slot = hi->next_index; slot < h->indexUsed; slot++) {
02425 entry = h->index + slot;
02426 if (!ENTRY_IS_REGION(entry))
02427 break;
02428 }
02429 hi->next_index = slot;
02430 if (entry == NULL || slot >= h->indexUsed)
02431 return 0;
02432
02433
02434 hi->next_index++;
02435
02436
02437 if (tag)
02438 *tag = entry->info.tag;
02439
02440 rc = copyEntry(entry, type, p, c, 0);
02441
02442
02443 return ((rc == 1) ? 1 : 0);
02444 }
02445
02451 static
02452 Header headerCopy(Header h)
02453
02454 {
02455 Header nh = headerNew();
02456 HeaderIterator hi;
02457 int_32 tag, type, count;
02458 hPTR_t ptr;
02459
02460
02461 for (hi = headerInitIterator(h);
02462 headerNextIterator(hi, &tag, &type, &ptr, &count);
02463 ptr = headerFreeData((void *)ptr, type))
02464 {
02465 if (ptr) (void) headerAddEntry(nh, tag, type, ptr, count);
02466 }
02467 hi = headerFreeIterator(hi);
02468
02469
02470 return headerReload(nh, HEADER_IMAGE);
02471 }
02472
02475 typedef struct headerSprintfArgs_s {
02476 Header h;
02477 char * fmt;
02478
02479 headerTagTableEntry tags;
02480
02481 headerSprintfExtension exts;
02482
02483 const char * errmsg;
02484 rpmec ec;
02485 sprintfToken format;
02486
02487 HeaderIterator hi;
02488
02489 char * val;
02490 size_t vallen;
02491 size_t alloced;
02492 int numTokens;
02493 int i;
02494 } * headerSprintfArgs;
02495
02501 static headerSprintfArgs hsaInit( headerSprintfArgs hsa)
02502
02503 {
02504 sprintfTag tag =
02505 (hsa->format->type == PTOK_TAG
02506 ? &hsa->format->u.tag :
02507 (hsa->format->type == PTOK_ARRAY
02508 ? &hsa->format->u.array.format->u.tag :
02509 NULL));
02510
02511 if (hsa != NULL) {
02512 hsa->i = 0;
02513 if (tag != NULL && tag->tag == -2)
02514 hsa->hi = headerInitIterator(hsa->h);
02515 }
02516
02517 return hsa;
02518
02519 }
02520
02526
02527 static sprintfToken hsaNext( headerSprintfArgs hsa)
02528
02529 {
02530 sprintfToken fmt = NULL;
02531 sprintfTag tag =
02532 (hsa->format->type == PTOK_TAG
02533 ? &hsa->format->u.tag :
02534 (hsa->format->type == PTOK_ARRAY
02535 ? &hsa->format->u.array.format->u.tag :
02536 NULL));
02537
02538 if (hsa != NULL && hsa->i >= 0 && hsa->i < hsa->numTokens) {
02539 fmt = hsa->format + hsa->i;
02540 if (hsa->hi == NULL) {
02541 hsa->i++;
02542 } else {
02543 int_32 tagno;
02544 int_32 type;
02545 int_32 count;
02546
02547
02548 if (!headerNextIterator(hsa->hi, &tagno, &type, NULL, &count))
02549 fmt = NULL;
02550 tag->tag = tagno;
02551
02552 }
02553 }
02554
02555
02556 return fmt;
02557
02558 }
02559
02565 static headerSprintfArgs hsaFini( headerSprintfArgs hsa)
02566
02567 {
02568 if (hsa != NULL) {
02569 hsa->hi = headerFreeIterator(hsa->hi);
02570 hsa->i = 0;
02571 }
02572
02573 return hsa;
02574
02575 }
02576
02583
02584 static char * hsaReserve(headerSprintfArgs hsa, size_t need)
02585
02586 {
02587 if ((hsa->vallen + need) >= hsa->alloced) {
02588 if (hsa->alloced <= need)
02589 hsa->alloced += need;
02590 hsa->alloced <<= 1;
02591 hsa->val = xrealloc(hsa->val, hsa->alloced+1);
02592 }
02593 return hsa->val + hsa->vallen;
02594 }
02595
02604
02605 static const char * myTagName(headerTagTableEntry tbl, int val,
02606 int *typep)
02607
02608 {
02609 static char name[128];
02610 const char * s;
02611 char *t;
02612
02613 for (; tbl->name != NULL; tbl++) {
02614 if (tbl->val == val)
02615 break;
02616 }
02617 if ((s = tbl->name) == NULL)
02618 return NULL;
02619 s += sizeof("RPMTAG_") - 1;
02620 t = name;
02621 *t++ = *s++;
02622 while (*s != '\0')
02623 *t++ = xtolower(*s++);
02624 *t = '\0';
02625 if (typep)
02626 *typep = tbl->type;
02627 return name;
02628 }
02629
02637 static int myTagValue(headerTagTableEntry tbl, const char * name)
02638
02639 {
02640 for (; tbl->name != NULL; tbl++) {
02641 if (!xstrcasecmp(tbl->name, name))
02642 return tbl->val;
02643 }
02644 return 0;
02645 }
02646
02654 static int findTag(headerSprintfArgs hsa, sprintfToken token, const char * name)
02655
02656 {
02657 headerSprintfExtension ext;
02658 sprintfTag stag = (token->type == PTOK_COND
02659 ? &token->u.cond.tag : &token->u.tag);
02660
02661 stag->fmt = NULL;
02662 stag->ext = NULL;
02663 stag->extNum = 0;
02664 stag->tag = -1;
02665
02666 if (!strcmp(name, "*")) {
02667 stag->tag = -2;
02668 goto bingo;
02669 }
02670
02671
02672 if (strncmp("RPMTAG_", name, sizeof("RPMTAG_")-1)) {
02673
02674 char * t = alloca(strlen(name) + sizeof("RPMTAG_"));
02675 (void) stpcpy( stpcpy(t, "RPMTAG_"), name);
02676 name = t;
02677
02678 }
02679
02680
02681
02682 for (ext = hsa->exts; ext != NULL && ext->type != HEADER_EXT_LAST;
02683 ext = (ext->type == HEADER_EXT_MORE ? ext->u.more : ext+1))
02684 {
02685 if (ext->name == NULL || ext->type != HEADER_EXT_TAG)
02686 continue;
02687 if (!xstrcasecmp(ext->name, name)) {
02688 stag->ext = ext->u.tagFunction;
02689 stag->extNum = ext - hsa->exts;
02690 goto bingo;
02691 }
02692 }
02693
02694
02695 stag->tag = myTagValue(hsa->tags, name);
02696 if (stag->tag != 0)
02697 goto bingo;
02698
02699 return 1;
02700
02701 bingo:
02702
02703 if (stag->type != NULL)
02704 for (ext = hsa->exts; ext != NULL && ext->type != HEADER_EXT_LAST;
02705 ext = (ext->type == HEADER_EXT_MORE ? ext->u.more : ext+1))
02706 {
02707 if (ext->name == NULL || ext->type != HEADER_EXT_FORMAT)
02708 continue;
02709 if (!strcmp(ext->name, stag->type)) {
02710 stag->fmt = ext->u.formatFunction;
02711 break;
02712 }
02713 }
02714 return 0;
02715 }
02716
02717
02726 static int parseExpression(headerSprintfArgs hsa, sprintfToken token,
02727 char * str, char ** endPtr)
02728
02729 ;
02730
02741 static int parseFormat(headerSprintfArgs hsa, char * str,
02742 sprintfToken * formatPtr, int * numTokensPtr,
02743 char ** endPtr, int state)
02744
02745
02746
02747 {
02748 char * chptr, * start, * next, * dst;
02749 sprintfToken format;
02750 sprintfToken token;
02751 int numTokens;
02752 int i;
02753 int done = 0;
02754
02755
02756 numTokens = 0;
02757 if (str != NULL)
02758 for (chptr = str; *chptr != '\0'; chptr++)
02759 if (*chptr == '%') numTokens++;
02760 numTokens = numTokens * 2 + 1;
02761
02762 format = xcalloc(numTokens, sizeof(*format));
02763 if (endPtr) *endPtr = NULL;
02764
02765
02766 dst = start = str;
02767 numTokens = 0;
02768 token = NULL;
02769 if (start != NULL)
02770 while (*start != '\0') {
02771 switch (*start) {
02772 case '%':
02773
02774 if (*(start + 1) == '%') {
02775 if (token == NULL || token->type != PTOK_STRING) {
02776 token = format + numTokens++;
02777 token->type = PTOK_STRING;
02778
02779 dst = token->u.string.string = start;
02780
02781 }
02782 start++;
02783
02784 *dst++ = *start++;
02785
02786 break;
02787 }
02788
02789 token = format + numTokens++;
02790
02791 *dst++ = '\0';
02792
02793 start++;
02794
02795 if (*start == '|') {
02796 char * newEnd;
02797
02798 start++;
02799
02800 if (parseExpression(hsa, token, start, &newEnd))
02801 {
02802 format = freeFormat(format, numTokens);
02803 return 1;
02804 }
02805
02806 start = newEnd;
02807 break;
02808 }
02809
02810
02811 token->u.tag.format = start;
02812
02813 token->u.tag.pad = 0;
02814 token->u.tag.justOne = 0;
02815 token->u.tag.arrayCount = 0;
02816
02817 chptr = start;
02818 while (*chptr && *chptr != '{' && *chptr != '%') chptr++;
02819 if (!*chptr || *chptr == '%') {
02820 hsa->errmsg = _("missing { after %");
02821 format = freeFormat(format, numTokens);
02822 return 1;
02823 }
02824
02825
02826 *chptr++ = '\0';
02827
02828
02829 while (start < chptr) {
02830 if (xisdigit(*start)) {
02831 i = strtoul(start, &start, 10);
02832 token->u.tag.pad += i;
02833 } else {
02834 start++;
02835 }
02836 }
02837
02838 if (*start == '=') {
02839 token->u.tag.justOne = 1;
02840 start++;
02841 } else if (*start == '#') {
02842 token->u.tag.justOne = 1;
02843 token->u.tag.arrayCount = 1;
02844 start++;
02845 }
02846
02847 next = start;
02848 while (*next && *next != '}') next++;
02849 if (!*next) {
02850 hsa->errmsg = _("missing } after %{");
02851 format = freeFormat(format, numTokens);
02852 return 1;
02853 }
02854
02855 *next++ = '\0';
02856
02857
02858 chptr = start;
02859 while (*chptr && *chptr != ':') chptr++;
02860
02861 if (*chptr != '\0') {
02862
02863 *chptr++ = '\0';
02864
02865 if (!*chptr) {
02866 hsa->errmsg = _("empty tag format");
02867 format = freeFormat(format, numTokens);
02868 return 1;
02869 }
02870
02871 token->u.tag.type = chptr;
02872
02873 } else {
02874 token->u.tag.type = NULL;
02875 }
02876
02877 if (!*start) {
02878 hsa->errmsg = _("empty tag name");
02879 format = freeFormat(format, numTokens);
02880 return 1;
02881 }
02882
02883 i = 0;
02884 token->type = PTOK_TAG;
02885
02886 if (findTag(hsa, token, start)) {
02887 hsa->errmsg = _("unknown tag");
02888 format = freeFormat(format, numTokens);
02889 return 1;
02890 }
02891
02892 start = next;
02893 break;
02894
02895 case '[':
02896
02897 *dst++ = '\0';
02898 *start++ = '\0';
02899
02900 token = format + numTokens++;
02901
02902
02903 if (parseFormat(hsa, start,
02904 &token->u.array.format,
02905 &token->u.array.numTokens,
02906 &start, PARSER_IN_ARRAY))
02907 {
02908 format = freeFormat(format, numTokens);
02909 return 1;
02910 }
02911
02912
02913 if (!start) {
02914 hsa->errmsg = _("] expected at end of array");
02915 format = freeFormat(format, numTokens);
02916 return 1;
02917 }
02918
02919 dst = start;
02920
02921 token->type = PTOK_ARRAY;
02922
02923 break;
02924
02925 case ']':
02926 if (state != PARSER_IN_ARRAY) {
02927 hsa->errmsg = _("unexpected ]");
02928 format = freeFormat(format, numTokens);
02929 return 1;
02930 }
02931
02932 *start++ = '\0';
02933
02934 if (endPtr) *endPtr = start;
02935 done = 1;
02936 break;
02937
02938 case '}':
02939 if (state != PARSER_IN_EXPR) {
02940 hsa->errmsg = _("unexpected }");
02941 format = freeFormat(format, numTokens);
02942 return 1;
02943 }
02944
02945 *start++ = '\0';
02946
02947 if (endPtr) *endPtr = start;
02948 done = 1;
02949 break;
02950
02951 default:
02952 if (token == NULL || token->type != PTOK_STRING) {
02953 token = format + numTokens++;
02954 token->type = PTOK_STRING;
02955
02956 dst = token->u.string.string = start;
02957
02958 }
02959
02960
02961 if (*start == '\\') {
02962 start++;
02963 *dst++ = escapedChar(*start++);
02964 } else {
02965 *dst++ = *start++;
02966 }
02967
02968 break;
02969 }
02970 if (done)
02971 break;
02972 }
02973
02974
02975
02976 if (dst != NULL)
02977 *dst = '\0';
02978
02979
02980 for (i = 0; i < numTokens; i++) {
02981 token = format + i;
02982 if (token->type == PTOK_STRING)
02983 token->u.string.len = strlen(token->u.string.string);
02984 }
02985
02986 *numTokensPtr = numTokens;
02987 *formatPtr = format;
02988
02989 return 0;
02990 }
02991
02992
02993 static int parseExpression(headerSprintfArgs hsa, sprintfToken token,
02994 char * str, char ** endPtr)
02995 {
02996 char * chptr;
02997 char * end;
02998
02999 hsa->errmsg = NULL;
03000 chptr = str;
03001 while (*chptr && *chptr != '?') chptr++;
03002
03003 if (*chptr != '?') {
03004 hsa->errmsg = _("? expected in expression");
03005 return 1;
03006 }
03007
03008 *chptr++ = '\0';;
03009
03010 if (*chptr != '{') {
03011 hsa->errmsg = _("{ expected after ? in expression");
03012 return 1;
03013 }
03014
03015 chptr++;
03016
03017 if (parseFormat(hsa, chptr, &token->u.cond.ifFormat,
03018 &token->u.cond.numIfTokens, &end, PARSER_IN_EXPR))
03019 return 1;
03020
03021
03022 if (!(end && *end)) {
03023 hsa->errmsg = _("} expected in expression");
03024 token->u.cond.ifFormat =
03025 freeFormat(token->u.cond.ifFormat, token->u.cond.numIfTokens);
03026 return 1;
03027 }
03028
03029 chptr = end;
03030 if (*chptr != ':' && *chptr != '|') {
03031 hsa->errmsg = _(": expected following ? subexpression");
03032 token->u.cond.ifFormat =
03033 freeFormat(token->u.cond.ifFormat, token->u.cond.numIfTokens);
03034 return 1;
03035 }
03036
03037 if (*chptr == '|') {
03038 if (parseFormat(hsa, NULL, &token->u.cond.elseFormat,
03039 &token->u.cond.numElseTokens, &end, PARSER_IN_EXPR))
03040 {
03041 token->u.cond.ifFormat =
03042 freeFormat(token->u.cond.ifFormat, token->u.cond.numIfTokens);
03043 return 1;
03044 }
03045 } else {
03046 chptr++;
03047
03048 if (*chptr != '{') {
03049 hsa->errmsg = _("{ expected after : in expression");
03050 token->u.cond.ifFormat =
03051 freeFormat(token->u.cond.ifFormat, token->u.cond.numIfTokens);
03052 return 1;
03053 }
03054
03055 chptr++;
03056
03057 if (parseFormat(hsa, chptr, &token->u.cond.elseFormat,
03058 &token->u.cond.numElseTokens, &end, PARSER_IN_EXPR))
03059 return 1;
03060
03061
03062 if (!(end && *end)) {
03063 hsa->errmsg = _("} expected in expression");
03064 token->u.cond.ifFormat =
03065 freeFormat(token->u.cond.ifFormat, token->u.cond.numIfTokens);
03066 return 1;
03067 }
03068
03069 chptr = end;
03070 if (*chptr != '|') {
03071 hsa->errmsg = _("| expected at end of expression");
03072 token->u.cond.ifFormat =
03073 freeFormat(token->u.cond.ifFormat, token->u.cond.numIfTokens);
03074 token->u.cond.elseFormat =
03075 freeFormat(token->u.cond.elseFormat, token->u.cond.numElseTokens);
03076 return 1;
03077 }
03078 }
03079
03080 chptr++;
03081
03082 *endPtr = chptr;
03083
03084 token->type = PTOK_COND;
03085
03086 (void) findTag(hsa, token, str);
03087
03088 return 0;
03089 }
03090
03091
03102 static int getExtension(headerSprintfArgs hsa, headerTagTagFunction fn,
03103 hTYP_t typeptr,
03104 hPTR_t * data,
03105 hCNT_t countptr,
03106 rpmec ec)
03107
03108
03109
03110 {
03111 if (!ec->avail) {
03112 if (fn(hsa->h, &ec->type, &ec->data, &ec->count, &ec->freeit))
03113 return 1;
03114 ec->avail = 1;
03115 }
03116
03117 if (typeptr) *typeptr = ec->type;
03118 if (data) *data = ec->data;
03119 if (countptr) *countptr = ec->count;
03120
03121 return 0;
03122 }
03123
03131
03132 static char * formatValue(headerSprintfArgs hsa, sprintfTag tag, int element)
03133
03134 {
03135 char * val = NULL;
03136 size_t need = 0;
03137 char * t, * te;
03138 char buf[20];
03139 int_32 count, type;
03140 hPTR_t data;
03141 unsigned int intVal;
03142 uint_64 llVal;
03143 const char ** strarray;
03144 int datafree = 0;
03145 int countBuf;
03146
03147 memset(buf, 0, sizeof(buf));
03148 if (tag->ext) {
03149
03150 if (getExtension(hsa, tag->ext, &type, &data, &count, hsa->ec + tag->extNum))
03151 {
03152 count = 1;
03153 type = RPM_STRING_TYPE;
03154 data = "(none)";
03155 }
03156
03157 } else {
03158
03159 if (!headerGetEntry(hsa->h, tag->tag, &type, &data, &count)) {
03160 count = 1;
03161 type = RPM_STRING_TYPE;
03162 data = "(none)";
03163 }
03164
03165
03166
03167 switch (type) {
03168 default:
03169 if (element >= count) {
03170
03171 data = headerFreeData(data, type);
03172
03173
03174 hsa->errmsg = _("(index out of range)");
03175 return NULL;
03176 }
03177 break;
03178 case RPM_OPENPGP_TYPE:
03179 case RPM_ASN1_TYPE:
03180 case RPM_BIN_TYPE:
03181 case RPM_STRING_TYPE:
03182 break;
03183 }
03184 datafree = 1;
03185 }
03186
03187 if (tag->arrayCount) {
03188
03189 if (datafree)
03190 data = headerFreeData(data, type);
03191
03192
03193 countBuf = count;
03194 data = &countBuf;
03195 count = 1;
03196 type = RPM_INT32_TYPE;
03197 }
03198
03199
03200 (void) stpcpy( stpcpy(buf, "%"), tag->format);
03201
03202
03203
03204 if (data)
03205 switch (type) {
03206 case RPM_STRING_ARRAY_TYPE:
03207 strarray = (const char **)data;
03208
03209 if (tag->fmt)
03210 val = tag->fmt(RPM_STRING_TYPE, strarray[element], buf, tag->pad, (count > 1 ? element : -1));
03211
03212 if (val) {
03213 need = strlen(val);
03214 } else {
03215 need = strlen(strarray[element]) + tag->pad + 20;
03216 val = xmalloc(need+1);
03217 strcat(buf, "s");
03218
03219 sprintf(val, buf, strarray[element]);
03220
03221 }
03222
03223 break;
03224
03225 case RPM_STRING_TYPE:
03226 if (tag->fmt)
03227 val = tag->fmt(RPM_STRING_TYPE, data, buf, tag->pad, -1);
03228
03229 if (val) {
03230 need = strlen(val);
03231 } else {
03232 need = strlen(data) + tag->pad + 20;
03233 val = xmalloc(need+1);
03234 strcat(buf, "s");
03235
03236 sprintf(val, buf, data);
03237
03238 }
03239 break;
03240
03241 case RPM_INT64_TYPE:
03242 llVal = *(((int_64 *) data) + element);
03243 if (tag->fmt)
03244 val = tag->fmt(RPM_INT64_TYPE, &llVal, buf, tag->pad, (count > 1 ? element : -1));
03245 if (val) {
03246 need = strlen(val);
03247 } else {
03248 need = 10 + tag->pad + 40;
03249 val = xmalloc(need+1);
03250 strcat(buf, "lld");
03251
03252 sprintf(val, buf, llVal);
03253
03254 }
03255 break;
03256
03257 case RPM_CHAR_TYPE:
03258 case RPM_INT8_TYPE:
03259 case RPM_INT16_TYPE:
03260 case RPM_INT32_TYPE:
03261 switch (type) {
03262 case RPM_CHAR_TYPE:
03263 case RPM_INT8_TYPE:
03264 intVal = *(((int_8 *) data) + element);
03265 break;
03266 case RPM_INT16_TYPE:
03267 intVal = *(((uint_16 *) data) + element);
03268 break;
03269 default:
03270 case RPM_INT32_TYPE:
03271 intVal = *(((int_32 *) data) + element);
03272 break;
03273 }
03274
03275 if (tag->fmt)
03276 val = tag->fmt(RPM_INT32_TYPE, &intVal, buf, tag->pad, (count > 1 ? element : -1));
03277
03278 if (val) {
03279 need = strlen(val);
03280 } else {
03281 need = 10 + tag->pad + 20;
03282 val = xmalloc(need+1);
03283 strcat(buf, "d");
03284
03285 sprintf(val, buf, intVal);
03286
03287 }
03288 break;
03289
03290 case RPM_OPENPGP_TYPE:
03291 case RPM_ASN1_TYPE:
03292 case RPM_BIN_TYPE:
03293
03294 if (tag->fmt)
03295 val = tag->fmt(RPM_BIN_TYPE, data, buf, tag->pad, count);
03296
03297 if (val) {
03298 need = strlen(val);
03299 } else {
03300 #ifdef NOTYET
03301 val = memcpy(xmalloc(count), data, count);
03302 #else
03303
03304 static char hex[] = "0123456789abcdef";
03305 const char * s = data;
03306
03307
03308 need = 2*count + tag->pad;
03309 val = t = xmalloc(need+1);
03310 while (count-- > 0) {
03311 unsigned int i;
03312 i = *s++;
03313 *t++ = hex[ (i >> 4) & 0xf ];
03314 *t++ = hex[ (i ) & 0xf ];
03315 }
03316 *t = '\0';
03317
03318 #endif
03319 }
03320 break;
03321
03322 default:
03323 need = sizeof("(unknown type)") - 1;
03324 val = xstrdup("(unknown type)");
03325 break;
03326 }
03327
03328
03329
03330 if (datafree)
03331 data = headerFreeData(data, type);
03332
03333
03334
03335 if (val && need > 0) {
03336 t = hsaReserve(hsa, need);
03337
03338 te = stpcpy(t, val);
03339
03340 hsa->vallen += (te - t);
03341 val = _free(val);
03342 }
03343
03344
03345 return (hsa->val + hsa->vallen);
03346 }
03347
03355
03356 static char * singleSprintf(headerSprintfArgs hsa, sprintfToken token,
03357 int element)
03358
03359 {
03360 char numbuf[64];
03361 char * t, * te;
03362 int i, j;
03363 int numElements;
03364 int_32 type;
03365 int_32 count;
03366 sprintfToken spft;
03367 int condNumFormats;
03368 size_t need;
03369
03370
03371
03372 switch (token->type) {
03373 case PTOK_NONE:
03374 break;
03375
03376 case PTOK_STRING:
03377 need = token->u.string.len;
03378 if (need == 0) break;
03379 t = hsaReserve(hsa, need);
03380
03381 te = stpcpy(t, token->u.string.string);
03382
03383 hsa->vallen += (te - t);
03384 break;
03385
03386 case PTOK_TAG:
03387 t = hsa->val + hsa->vallen;
03388 te = formatValue(hsa, &token->u.tag,
03389 (token->u.tag.justOne ? 0 : element));
03390 if (te == NULL)
03391 return NULL;
03392 break;
03393
03394 case PTOK_COND:
03395 if (token->u.cond.tag.ext || headerIsEntry(hsa->h, token->u.cond.tag.tag)) {
03396 spft = token->u.cond.ifFormat;
03397 condNumFormats = token->u.cond.numIfTokens;
03398 } else {
03399 spft = token->u.cond.elseFormat;
03400 condNumFormats = token->u.cond.numElseTokens;
03401 }
03402
03403 need = condNumFormats * 20;
03404 if (spft == NULL || need == 0) break;
03405
03406 t = hsaReserve(hsa, need);
03407 for (i = 0; i < condNumFormats; i++, spft++) {
03408 te = singleSprintf(hsa, spft, element);
03409 if (te == NULL)
03410 return NULL;
03411 }
03412 break;
03413
03414 case PTOK_ARRAY:
03415 numElements = -1;
03416 spft = token->u.array.format;
03417 for (i = 0; i < token->u.array.numTokens; i++, spft++)
03418 {
03419 if (spft->type != PTOK_TAG ||
03420 spft->u.tag.arrayCount ||
03421 spft->u.tag.justOne) continue;
03422
03423 if (spft->u.tag.ext) {
03424
03425 if (getExtension(hsa, spft->u.tag.ext, &type, NULL, &count,
03426 hsa->ec + spft->u.tag.extNum))
03427 continue;
03428
03429 } else {
03430
03431 if (!headerGetEntry(hsa->h, spft->u.tag.tag, &type, NULL, &count))
03432 continue;
03433
03434 }
03435
03436 if (type == RPM_BIN_TYPE || type == RPM_ASN1_TYPE || type == RPM_OPENPGP_TYPE)
03437 count = 1;
03438
03439 if (numElements > 1 && count != numElements)
03440 switch (type) {
03441 default:
03442 hsa->errmsg =
03443 _("array iterator used with different sized arrays");
03444 return NULL;
03445 break;
03446 case RPM_OPENPGP_TYPE:
03447 case RPM_ASN1_TYPE:
03448 case RPM_BIN_TYPE:
03449 case RPM_STRING_TYPE:
03450 break;
03451 }
03452 if (count > numElements)
03453 numElements = count;
03454 }
03455
03456 if (numElements == -1) {
03457 #ifdef DYING
03458 need = sizeof("(none)\n") - 1;
03459 t = hsaReserve(hsa, need);
03460
03461 te = stpcpy(t, "(none)\n");
03462
03463 hsa->vallen += (te - t);
03464 #endif
03465 } else {
03466 int isxml;
03467 int isyaml;
03468
03469 need = numElements * token->u.array.numTokens;
03470 if (need == 0) break;
03471
03472 spft = token->u.array.format;
03473 isxml = (spft->type == PTOK_TAG && spft->u.tag.type != NULL &&
03474 !strcmp(spft->u.tag.type, "xml"));
03475 isyaml = (spft->type == PTOK_TAG && spft->u.tag.type != NULL &&
03476 !strcmp(spft->u.tag.type, "yaml"));
03477
03478 if (isxml) {
03479 const char * tagN = myTagName(hsa->tags, spft->u.tag.tag, NULL);
03480
03481 if (tagN == NULL) {
03482 (void) snprintf(numbuf, sizeof(numbuf), "Tag_0x%08x",
03483 spft->u.tag.tag);
03484 numbuf[sizeof(numbuf)-1] = '\0';
03485 tagN = numbuf;
03486 }
03487 need = sizeof(" <rpmTag name=\"\">\n") + strlen(tagN);
03488 te = t = hsaReserve(hsa, need);
03489
03490 te = stpcpy( stpcpy( stpcpy(te, " <rpmTag name=\""), tagN), "\">\n");
03491
03492 hsa->vallen += (te - t);
03493 }
03494 if (isyaml) {
03495 int tagT = -1;
03496 const char * tagN = myTagName(hsa->tags, spft->u.tag.tag, &tagT);
03497
03498 if (tagN == NULL) {
03499 (void) snprintf(numbuf, sizeof(numbuf), "Tag_0x%08x",
03500 spft->u.tag.tag);
03501 numbuf[sizeof(numbuf)-1] = '\0';
03502 tagN = numbuf;
03503 tagT = numElements > 1
03504 ? RPM_ARRAY_RETURN_TYPE : RPM_SCALAR_RETURN_TYPE;
03505 }
03506 need = sizeof(" : - ") + strlen(tagN);
03507 te = t = hsaReserve(hsa, need);
03508
03509 *te++ = ' ';
03510 *te++ = ' ';
03511 te = stpcpy(te, tagN);
03512 *te++ = ':';
03513 *te++ = (((tagT & RPM_MASK_RETURN_TYPE) == RPM_ARRAY_RETURN_TYPE)
03514 ? '\n' : ' ');
03515
03516 if (((tagT & RPM_MASK_RETURN_TYPE) == RPM_ARRAY_RETURN_TYPE)
03517 && numElements == 1) {
03518 te = stpcpy(te, " ");
03519 if (spft->u.tag.tag != 1118)
03520 te = stpcpy(te, "- ");
03521 }
03522 *te = '\0';
03523
03524 hsa->vallen += (te - t);
03525 }
03526
03527 need = numElements * token->u.array.numTokens * 10;
03528 t = hsaReserve(hsa, need);
03529 for (j = 0; j < numElements; j++) {
03530 spft = token->u.array.format;
03531 for (i = 0; i < token->u.array.numTokens; i++, spft++) {
03532 te = singleSprintf(hsa, spft, j);
03533 if (te == NULL)
03534 return NULL;
03535 }
03536 }
03537
03538 if (isxml) {
03539 need = sizeof(" </rpmTag>\n") - 1;
03540 te = t = hsaReserve(hsa, need);
03541
03542 te = stpcpy(te, " </rpmTag>\n");
03543
03544 hsa->vallen += (te - t);
03545 }
03546 if (isyaml) {
03547 #if 0
03548 need = sizeof("\n") - 1;
03549 te = t = hsaReserve(hsa, need);
03550
03551 te = stpcpy(te, "\n");
03552
03553 hsa->vallen += (te - t);
03554 #endif
03555 }
03556
03557 }
03558 break;
03559 }
03560
03561 return (hsa->val + hsa->vallen);
03562 }
03563
03569 static rpmec
03570 rpmecNew(const headerSprintfExtension exts)
03571
03572 {
03573 headerSprintfExtension ext;
03574 rpmec ec;
03575 int i = 0;
03576
03577 for (ext = exts; ext != NULL && ext->type != HEADER_EXT_LAST;
03578 ext = (ext->type == HEADER_EXT_MORE ? ext->u.more : ext+1))
03579 {
03580 i++;
03581 }
03582
03583 ec = xcalloc(i, sizeof(*ec));
03584 return ec;
03585 }
03586
03593 static rpmec
03594 rpmecFree(const headerSprintfExtension exts, rpmec ec)
03595
03596 {
03597 headerSprintfExtension ext;
03598 int i = 0;
03599
03600 for (ext = exts; ext != NULL && ext->type != HEADER_EXT_LAST;
03601 ext = (ext->type == HEADER_EXT_MORE ? ext->u.more : ext+1))
03602 {
03603
03604 if (ec[i].freeit) ec[i].data = _free(ec[i].data);
03605
03606 i++;
03607 }
03608
03609 ec = _free(ec);
03610 return NULL;
03611 }
03612
03624 static
03625 char * headerSprintf(Header h, const char * fmt,
03626 const struct headerTagTableEntry_s * tbltags,
03627 const struct headerSprintfExtension_s * extensions,
03628 errmsg_t * errmsg)
03629
03630
03631 {
03632 headerSprintfArgs hsa = memset(alloca(sizeof(*hsa)), 0, sizeof(*hsa));
03633 sprintfToken nextfmt;
03634 sprintfTag tag;
03635 char * t, * te;
03636 int isxml;
03637 int isyaml;
03638 int need;
03639
03640 hsa->h = headerLink(h);
03641 hsa->fmt = xstrdup(fmt);
03642
03643 hsa->exts = (headerSprintfExtension) extensions;
03644 hsa->tags = (headerTagTableEntry) tbltags;
03645
03646 hsa->errmsg = NULL;
03647
03648
03649 if (parseFormat(hsa, hsa->fmt, &hsa->format, &hsa->numTokens, NULL, PARSER_BEGIN))
03650 goto exit;
03651
03652
03653 hsa->ec = rpmecNew(hsa->exts);
03654 hsa->val = xstrdup("");
03655
03656 tag =
03657 (hsa->format->type == PTOK_TAG
03658 ? &hsa->format->u.tag :
03659 (hsa->format->type == PTOK_ARRAY
03660 ? &hsa->format->u.array.format->u.tag :
03661 NULL));
03662 isxml = (tag != NULL && tag->tag == -2 && tag->type != NULL && !strcmp(tag->type, "xml"));
03663 isyaml = (tag != NULL && tag->tag == -2 && tag->type != NULL && !strcmp(tag->type, "yaml"));
03664
03665 if (isxml) {
03666 need = sizeof("<rpmHeader>\n") - 1;
03667 t = hsaReserve(hsa, need);
03668
03669 te = stpcpy(t, "<rpmHeader>\n");
03670
03671 hsa->vallen += (te - t);
03672 }
03673 if (isyaml) {
03674 need = sizeof("- !!omap\n") - 1;
03675 t = hsaReserve(hsa, need);
03676
03677 te = stpcpy(t, "- !!omap\n");
03678
03679 hsa->vallen += (te - t);
03680 }
03681
03682 hsa = hsaInit(hsa);
03683 while ((nextfmt = hsaNext(hsa)) != NULL) {
03684 te = singleSprintf(hsa, nextfmt, 0);
03685 if (te == NULL) {
03686 hsa->val = _free(hsa->val);
03687 break;
03688 }
03689 }
03690 hsa = hsaFini(hsa);
03691
03692 if (isxml) {
03693 need = sizeof("</rpmHeader>\n") - 1;
03694 t = hsaReserve(hsa, need);
03695
03696 te = stpcpy(t, "</rpmHeader>\n");
03697
03698 hsa->vallen += (te - t);
03699 }
03700 if (isyaml) {
03701 need = sizeof("\n") - 1;
03702 t = hsaReserve(hsa, need);
03703
03704 te = stpcpy(t, "\n");
03705
03706 hsa->vallen += (te - t);
03707 }
03708
03709 if (hsa->val != NULL && hsa->vallen < hsa->alloced)
03710 hsa->val = xrealloc(hsa->val, hsa->vallen+1);
03711
03712 hsa->ec = rpmecFree(hsa->exts, hsa->ec);
03713 hsa->format = freeFormat(hsa->format, hsa->numTokens);
03714
03715 exit:
03716
03717 if (errmsg)
03718 *errmsg = hsa->errmsg;
03719
03720 hsa->h = headerFree(hsa->h);
03721 hsa->fmt = _free(hsa->fmt);
03722 return hsa->val;
03723 }
03724
03734 static char * octalFormat(int_32 type, hPTR_t data,
03735 char * formatPrefix, int padding, int element)
03736
03737 {
03738 char * val;
03739
03740 if (type == RPM_INT32_TYPE) {
03741 val = xmalloc(20 + padding);
03742
03743 strcat(formatPrefix, "o");
03744
03745
03746 sprintf(val, formatPrefix, *((int_32 *) data));
03747
03748 } else if (type == RPM_INT64_TYPE) {
03749 val = xmalloc(40 + padding);
03750
03751 strcat(formatPrefix, "llo");
03752
03753
03754 sprintf(val, formatPrefix, *((int_64 *) data));
03755
03756 } else
03757 val = xstrdup(_("(not a number)"));
03758
03759 return val;
03760 }
03761
03771 static char * hexFormat(int_32 type, hPTR_t data,
03772 char * formatPrefix, int padding, int element)
03773
03774 {
03775 char * val;
03776
03777 if (type == RPM_INT32_TYPE) {
03778 val = xmalloc(20 + padding);
03779
03780 strcat(formatPrefix, "x");
03781
03782
03783 sprintf(val, formatPrefix, *((int_32 *) data));
03784
03785 } else if (type == RPM_INT64_TYPE) {
03786 val = xmalloc(40 + padding);
03787
03788 strcat(formatPrefix, "llx");
03789
03790
03791 sprintf(val, formatPrefix, *((int_64 *) data));
03792
03793 } else
03794 val = xstrdup(_("(not a number)"));
03795
03796 return val;
03797 }
03798
03809 static char * realDateFormat(int_32 type, hPTR_t data,
03810 char * formatPrefix, int padding, int element,
03811 const char * strftimeFormat)
03812
03813 {
03814 char * val;
03815
03816 if (type != RPM_INT32_TYPE) {
03817 val = xstrdup(_("(not a number)"));
03818 } else {
03819 struct tm * tstruct;
03820 char buf[50];
03821
03822 val = xmalloc(50 + padding);
03823
03824 strcat(formatPrefix, "s");
03825
03826
03827
03828 { time_t dateint = *((int_32 *) data);
03829 tstruct = localtime(&dateint);
03830 }
03831 buf[0] = '\0';
03832 if (tstruct)
03833 (void) strftime(buf, sizeof(buf) - 1, strftimeFormat, tstruct);
03834
03835 sprintf(val, formatPrefix, buf);
03836
03837 }
03838
03839 return val;
03840 }
03841
03851 static char * dateFormat(int_32 type, hPTR_t data,
03852 char * formatPrefix, int padding, int element)
03853
03854 {
03855 return realDateFormat(type, data, formatPrefix, padding, element,
03856 _("%c"));
03857 }
03858
03868 static char * dayFormat(int_32 type, hPTR_t data,
03869 char * formatPrefix, int padding, int element)
03870
03871 {
03872 return realDateFormat(type, data, formatPrefix, padding, element,
03873 _("%a %b %d %Y"));
03874 }
03875
03885 static char * shescapeFormat(int_32 type, hPTR_t data,
03886 char * formatPrefix, int padding, int element)
03887
03888 {
03889 char * result, * dst, * src, * buf;
03890
03891 if (type == RPM_INT32_TYPE) {
03892 result = xmalloc(padding + 20);
03893
03894 strcat(formatPrefix, "d");
03895
03896
03897 sprintf(result, formatPrefix, *((int_32 *) data));
03898
03899 } else if (type == RPM_INT64_TYPE) {
03900 result = xmalloc(padding + 40);
03901
03902 strcat(formatPrefix, "lld");
03903
03904
03905 sprintf(result, formatPrefix, *((int_64 *) data));
03906
03907 } else {
03908 buf = alloca(strlen(data) + padding + 2);
03909
03910 strcat(formatPrefix, "s");
03911
03912
03913 sprintf(buf, formatPrefix, data);
03914
03915
03916
03917 result = dst = xmalloc(strlen(buf) * 4 + 3);
03918 *dst++ = '\'';
03919 for (src = buf; *src != '\0'; src++) {
03920 if (*src == '\'') {
03921 *dst++ = '\'';
03922 *dst++ = '\\';
03923 *dst++ = '\'';
03924 *dst++ = '\'';
03925 } else {
03926 *dst++ = *src;
03927 }
03928 }
03929 *dst++ = '\'';
03930 *dst = '\0';
03931
03932
03933 }
03934
03935 return result;
03936 }
03937
03938
03939 const struct headerSprintfExtension_s headerDefaultFormats[] = {
03940 { HEADER_EXT_FORMAT, "octal", { octalFormat } },
03941 { HEADER_EXT_FORMAT, "hex", { hexFormat } },
03942 { HEADER_EXT_FORMAT, "date", { dateFormat } },
03943 { HEADER_EXT_FORMAT, "day", { dayFormat } },
03944 { HEADER_EXT_FORMAT, "shescape", { shescapeFormat } },
03945 { HEADER_EXT_LAST, NULL, { NULL } }
03946 };
03947
03948
03955 static
03956 void headerCopyTags(Header headerFrom, Header headerTo, hTAG_t tagstocopy)
03957
03958 {
03959 int * p;
03960
03961 if (headerFrom == headerTo)
03962 return;
03963
03964 for (p = tagstocopy; *p != 0; p++) {
03965 char *s;
03966 int_32 type;
03967 int_32 count;
03968 if (headerIsEntry(headerTo, *p))
03969 continue;
03970
03971 if (!headerGetEntryMinMemory(headerFrom, *p, &type, &s, &count))
03972 continue;
03973
03974 (void) headerAddEntry(headerTo, *p, type, s, count);
03975 s = headerFreeData(s, type);
03976 }
03977 }
03978
03979
03980 static struct HV_s hdrVec1 = {
03981 headerLink,
03982 headerUnlink,
03983 headerFree,
03984 headerNew,
03985 headerSort,
03986 headerUnsort,
03987 headerSizeof,
03988 headerUnload,
03989 headerReload,
03990 headerCopy,
03991 headerLoad,
03992 headerCopyLoad,
03993 headerRead,
03994 headerWrite,
03995 headerIsEntry,
03996 headerFreeTag,
03997 headerGetEntry,
03998 headerGetEntryMinMemory,
03999 headerAddEntry,
04000 headerAppendEntry,
04001 headerAddOrAppendEntry,
04002 headerAddI18NString,
04003 headerModifyEntry,
04004 headerRemoveEntry,
04005 headerSprintf,
04006 headerCopyTags,
04007 headerFreeIterator,
04008 headerInitIterator,
04009 headerNextIterator,
04010 headerGetOrigin,
04011 headerSetOrigin,
04012 headerGetInstance,
04013 headerSetInstance,
04014 NULL, NULL,
04015 1
04016 };
04017
04018
04019
04020 HV_t hdrVec = &hdrVec1;
04021