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 inline void *
00130 _free( const void * p)
00131 {
00132 if (p != NULL) free((void *)p);
00133 return NULL;
00134 }
00135
00141 static
00142 Header headerLink(Header h)
00143
00144 {
00145
00146 if (h == NULL) return NULL;
00147
00148
00149 h->nrefs++;
00150
00151 if (_hdr_debug)
00152 fprintf(stderr, "--> h %p ++ %d at %s:%u\n", h, h->nrefs, __FILE__, __LINE__);
00153
00154
00155
00156 return h;
00157
00158 }
00159
00165 static
00166 Header headerUnlink( Header h)
00167
00168 {
00169 if (h == NULL) return NULL;
00170
00171 if (_hdr_debug)
00172 fprintf(stderr, "--> h %p -- %d at %s:%u\n", h, h->nrefs, __FILE__, __LINE__);
00173
00174 h->nrefs--;
00175 return NULL;
00176 }
00177
00183 static
00184 Header headerFree( Header h)
00185
00186 {
00187 (void) headerUnlink(h);
00188
00189
00190 if (h == NULL || h->nrefs > 0)
00191 return NULL;
00192
00193 if (h->index) {
00194 indexEntry entry = h->index;
00195 int i;
00196 for (i = 0; i < h->indexUsed; i++, entry++) {
00197 if ((h->flags & HEADERFLAG_ALLOCATED) && ENTRY_IS_REGION(entry)) {
00198 if (entry->length > 0) {
00199 int_32 * ei = entry->data;
00200 if ((ei - 2) == h->blob) h->blob = _free(h->blob);
00201 entry->data = NULL;
00202 }
00203 } else if (!ENTRY_IN_REGION(entry)) {
00204 entry->data = _free(entry->data);
00205 }
00206 entry->data = NULL;
00207 }
00208 h->index = _free(h->index);
00209 }
00210 h->origin = _free(h->origin);
00211
00212 h = _free(h);
00213 return h;
00214
00215 }
00216
00221 static
00222 Header headerNew(void)
00223
00224 {
00225 Header h = xcalloc(1, sizeof(*h));
00226
00227
00228
00229 h->hv = *hdrVec;
00230
00231
00232 h->blob = NULL;
00233 h->origin = NULL;
00234 h->instance = 0;
00235 h->indexAlloced = INDEX_MALLOC_SIZE;
00236 h->indexUsed = 0;
00237 h->flags |= HEADERFLAG_SORTED;
00238
00239 h->index = (h->indexAlloced
00240 ? xcalloc(h->indexAlloced, sizeof(*h->index))
00241 : NULL);
00242
00243 h->nrefs = 0;
00244
00245 return headerLink(h);
00246
00247 }
00248
00251 static int indexCmp(const void * avp, const void * bvp)
00252
00253 {
00254
00255 indexEntry ap = (indexEntry) avp, bp = (indexEntry) bvp;
00256
00257 return (ap->info.tag - bp->info.tag);
00258 }
00259
00264 static
00265 void headerSort(Header h)
00266
00267 {
00268 if (!(h->flags & HEADERFLAG_SORTED)) {
00269
00270 qsort(h->index, h->indexUsed, sizeof(*h->index), indexCmp);
00271
00272 h->flags |= HEADERFLAG_SORTED;
00273 }
00274 }
00275
00278 static int offsetCmp(const void * avp, const void * bvp)
00279 {
00280
00281 indexEntry ap = (indexEntry) avp, bp = (indexEntry) bvp;
00282
00283 int rc = (ap->info.offset - bp->info.offset);
00284
00285 if (rc == 0) {
00286
00287 if (ap->info.offset < 0)
00288 rc = (((char *)ap->data) - ((char *)bp->data));
00289 else
00290 rc = (ap->info.tag - bp->info.tag);
00291 }
00292 return rc;
00293 }
00294
00299 static
00300 void headerUnsort(Header h)
00301
00302 {
00303
00304 qsort(h->index, h->indexUsed, sizeof(*h->index), offsetCmp);
00305
00306 }
00307
00314 static
00315 unsigned int headerSizeof( Header h, enum hMagic magicp)
00316
00317 {
00318 indexEntry entry;
00319 unsigned int size = 0;
00320 unsigned int pad = 0;
00321 int i;
00322
00323 if (h == NULL)
00324 return size;
00325
00326 headerSort(h);
00327
00328 switch (magicp) {
00329 case HEADER_MAGIC_YES:
00330 size += sizeof(header_magic);
00331 break;
00332 case HEADER_MAGIC_NO:
00333 break;
00334 }
00335
00336
00337 size += 2 * sizeof(int_32);
00338
00339
00340 for (i = 0, entry = h->index; i < h->indexUsed; i++, entry++) {
00341 unsigned diff;
00342 int_32 type;
00343
00344
00345 if (ENTRY_IS_REGION(entry)) {
00346 size += entry->length;
00347
00348
00349 if (i == 0 && (h->flags & HEADERFLAG_LEGACY))
00350 size += sizeof(struct entryInfo_s) + entry->info.count;
00351
00352 continue;
00353 }
00354
00355
00356 if (entry->info.offset < 0)
00357 continue;
00358
00359
00360 type = entry->info.type;
00361
00362 if (typeSizes[type] > 1) {
00363 diff = typeSizes[type] - (size % typeSizes[type]);
00364 if (diff != typeSizes[type]) {
00365 size += diff;
00366 pad += diff;
00367 }
00368 }
00369
00370
00371
00372 size += sizeof(struct entryInfo_s) + entry->length;
00373
00374 }
00375
00376 return size;
00377 }
00378
00388 static int dataLength(int_32 type, hPTR_t p, int_32 count, int onDisk,
00389 hPTR_t pend)
00390
00391 {
00392 const unsigned char * s = p;
00393 const unsigned char * se = pend;
00394 int length = 0;
00395
00396 switch (type) {
00397 case RPM_STRING_TYPE:
00398 if (count != 1)
00399 return -1;
00400
00401 while (*s++) {
00402 if (se && s > se)
00403 return -1;
00404 length++;
00405 }
00406
00407 length++;
00408 break;
00409
00410 case RPM_STRING_ARRAY_TYPE:
00411 case RPM_I18NSTRING_TYPE:
00412
00413
00414
00415 if (onDisk) {
00416 while (count--) {
00417 length++;
00418
00419 while (*s++) {
00420 if (se && s > se)
00421 return -1;
00422 length++;
00423 }
00424
00425 }
00426 } else {
00427 const char ** av = (const char **)p;
00428
00429 while (count--) {
00430
00431 length += strlen(*av++) + 1;
00432 }
00433
00434 }
00435 break;
00436
00437 default:
00438
00439 if (typeSizes[type] == -1)
00440 return -1;
00441 length = typeSizes[(type & 0xf)] * count;
00442
00443 if (length < 0 || (se && (s + length) > se))
00444 return -1;
00445 break;
00446 }
00447
00448 return length;
00449 }
00450
00477 static int regionSwab( indexEntry entry, int il, int dl,
00478 entryInfo pe,
00479 unsigned char * dataStart,
00480 const unsigned char * dataEnd,
00481 int regionid)
00482
00483 {
00484 unsigned char * tprev = NULL;
00485 unsigned char * t = NULL;
00486 int tdel = 0;
00487 int tl = dl;
00488 struct indexEntry_s ieprev;
00489
00490
00491 memset(&ieprev, 0, sizeof(ieprev));
00492
00493 for (; il > 0; il--, pe++) {
00494 struct indexEntry_s ie;
00495 int_32 type;
00496
00497 ie.info.tag = ntohl(pe->tag);
00498 ie.info.type = ntohl(pe->type);
00499 ie.info.count = ntohl(pe->count);
00500 ie.info.offset = ntohl(pe->offset);
00501
00502 if (hdrchkType(ie.info.type))
00503 return -1;
00504 if (hdrchkData(ie.info.count))
00505 return -1;
00506 if (hdrchkData(ie.info.offset))
00507 return -1;
00508
00509 if (hdrchkAlign(ie.info.type, ie.info.offset))
00510 return -1;
00511
00512
00513 ie.data = t = dataStart + ie.info.offset;
00514 if (dataEnd && t >= dataEnd)
00515 return -1;
00516
00517 ie.length = dataLength(ie.info.type, ie.data, ie.info.count, 1, dataEnd);
00518 if (ie.length < 0 || hdrchkData(ie.length))
00519 return -1;
00520
00521 ie.rdlen = 0;
00522
00523 if (entry) {
00524 ie.info.offset = regionid;
00525
00526 *entry = ie;
00527
00528 entry++;
00529 }
00530
00531
00532 type = ie.info.type;
00533
00534 if (typeSizes[type] > 1) {
00535 unsigned diff;
00536 diff = typeSizes[type] - (dl % typeSizes[type]);
00537 if (diff != typeSizes[type]) {
00538 dl += diff;
00539 if (ieprev.info.type == RPM_I18NSTRING_TYPE)
00540 ieprev.length += diff;
00541 }
00542 }
00543
00544 tdel = (tprev ? (t - tprev) : 0);
00545 if (ieprev.info.type == RPM_I18NSTRING_TYPE)
00546 tdel = ieprev.length;
00547
00548 if (ie.info.tag >= HEADER_I18NTABLE) {
00549 tprev = t;
00550 } else {
00551 tprev = dataStart;
00552
00553
00554 if (ie.info.tag == HEADER_IMAGE)
00555 tprev -= REGION_TAG_COUNT;
00556
00557 }
00558
00559
00560 switch (ntohl(pe->type)) {
00561
00562 case RPM_INT64_TYPE:
00563 { int_64 * it = (int_64 *)t;
00564 int_32 b[2];
00565 for (; ie.info.count > 0; ie.info.count--, it += 1) {
00566 if (dataEnd && ((unsigned char *)it) >= dataEnd)
00567 return -1;
00568 b[1] = htonl(((int_32 *)it)[0]);
00569 b[0] = htonl(((int_32 *)it)[1]);
00570 if (b[1] != ((int_32 *)it)[0])
00571 memcpy(it, b, sizeof(b));
00572 }
00573 t = (char *) it;
00574 } break;
00575 case RPM_INT32_TYPE:
00576 { int_32 * it = (int_32 *)t;
00577 for (; ie.info.count > 0; ie.info.count--, it += 1) {
00578 if (dataEnd && ((unsigned char *)it) >= dataEnd)
00579 return -1;
00580 *it = htonl(*it);
00581 }
00582 t = (char *) it;
00583 } break;
00584 case RPM_INT16_TYPE:
00585 { int_16 * it = (int_16 *) t;
00586 for (; ie.info.count > 0; ie.info.count--, it += 1) {
00587 if (dataEnd && ((unsigned char *)it) >= dataEnd)
00588 return -1;
00589 *it = htons(*it);
00590 }
00591 t = (char *) it;
00592 } break;
00593
00594 default:
00595 t += ie.length;
00596 break;
00597 }
00598
00599 dl += ie.length;
00600 if (dataEnd && dataStart + dl > dataEnd) return -1;
00601 tl += tdel;
00602 ieprev = ie;
00603
00604 }
00605 tdel = (tprev ? (t - tprev) : 0);
00606 tl += tdel;
00607
00608
00609
00610
00611
00612
00613
00614 if (tl+REGION_TAG_COUNT == dl)
00615 tl += REGION_TAG_COUNT;
00616
00617
00618 return dl;
00619 }
00620
00626 static void * doHeaderUnload(Header h,
00627 int * lengthPtr)
00628
00629
00630
00631 {
00632 int_32 * ei = NULL;
00633 entryInfo pe;
00634 char * dataStart;
00635 char * te;
00636 unsigned pad;
00637 unsigned len;
00638 int_32 il = 0;
00639 int_32 dl = 0;
00640 indexEntry entry;
00641 int_32 type;
00642 int i;
00643 int drlen, ndribbles;
00644 int driplen, ndrips;
00645 int legacy = 0;
00646
00647
00648 headerUnsort(h);
00649
00650
00651 pad = 0;
00652 drlen = ndribbles = driplen = ndrips = 0;
00653 for (i = 0, entry = h->index; i < h->indexUsed; i++, entry++) {
00654 if (ENTRY_IS_REGION(entry)) {
00655 int_32 rdl = -entry->info.offset;
00656 int_32 ril = rdl/sizeof(*pe);
00657 int rid = entry->info.offset;
00658
00659 il += ril;
00660 dl += entry->rdlen + entry->info.count;
00661
00662 if (i == 0 && (h->flags & HEADERFLAG_LEGACY))
00663 il += 1;
00664
00665
00666 for (; i < h->indexUsed && entry->info.offset <= rid+1; i++, entry++) {
00667 if (entry->info.offset <= rid)
00668 continue;
00669
00670
00671 type = entry->info.type;
00672 if (typeSizes[type] > 1) {
00673 unsigned diff;
00674 diff = typeSizes[type] - (dl % typeSizes[type]);
00675 if (diff != typeSizes[type]) {
00676 drlen += diff;
00677 pad += diff;
00678 dl += diff;
00679 }
00680 }
00681
00682 ndribbles++;
00683 il++;
00684 drlen += entry->length;
00685 dl += entry->length;
00686 }
00687 i--;
00688 entry--;
00689 continue;
00690 }
00691
00692
00693 if (entry->data == NULL || entry->length <= 0)
00694 continue;
00695
00696
00697 type = entry->info.type;
00698 if (typeSizes[type] > 1) {
00699 unsigned diff;
00700 diff = typeSizes[type] - (dl % typeSizes[type]);
00701 if (diff != typeSizes[type]) {
00702 driplen += diff;
00703 pad += diff;
00704 dl += diff;
00705 } else
00706 diff = 0;
00707 }
00708
00709 ndrips++;
00710 il++;
00711 driplen += entry->length;
00712 dl += entry->length;
00713 }
00714
00715
00716 if (hdrchkTags(il) || hdrchkData(dl))
00717 goto errxit;
00718
00719 len = sizeof(il) + sizeof(dl) + (il * sizeof(*pe)) + dl;
00720
00721
00722 ei = xmalloc(len);
00723 ei[0] = htonl(il);
00724 ei[1] = htonl(dl);
00725
00726
00727 pe = (entryInfo) &ei[2];
00728 dataStart = te = (char *) (pe + il);
00729
00730 pad = 0;
00731 for (i = 0, entry = h->index; i < h->indexUsed; i++, entry++) {
00732 const char * src;
00733 char *t;
00734 int count;
00735 int rdlen;
00736
00737 if (entry->data == NULL || entry->length <= 0)
00738 continue;
00739
00740 t = te;
00741 pe->tag = htonl(entry->info.tag);
00742 pe->type = htonl(entry->info.type);
00743 pe->count = htonl(entry->info.count);
00744
00745 if (ENTRY_IS_REGION(entry)) {
00746 int_32 rdl = -entry->info.offset;
00747 int_32 ril = rdl/sizeof(*pe) + ndribbles;
00748 int rid = entry->info.offset;
00749
00750 src = (char *)entry->data;
00751 rdlen = entry->rdlen;
00752
00753
00754 if (i == 0 && (h->flags & HEADERFLAG_LEGACY)) {
00755 int_32 stei[4];
00756
00757 legacy = 1;
00758
00759 memcpy(pe+1, src, rdl);
00760 memcpy(te, src + rdl, rdlen);
00761
00762 te += rdlen;
00763
00764 pe->offset = htonl(te - dataStart);
00765 stei[0] = pe->tag;
00766 stei[1] = pe->type;
00767 stei[2] = htonl(-rdl-entry->info.count);
00768 stei[3] = pe->count;
00769
00770 memcpy(te, stei, entry->info.count);
00771
00772 te += entry->info.count;
00773 ril++;
00774 rdlen += entry->info.count;
00775
00776 count = regionSwab(NULL, ril, 0, pe, t, NULL, 0);
00777 if (count != rdlen)
00778 goto errxit;
00779
00780 } else {
00781
00782
00783 memcpy(pe+1, src + sizeof(*pe), ((ril-1) * sizeof(*pe)));
00784 memcpy(te, src + (ril * sizeof(*pe)), rdlen+entry->info.count+drlen);
00785
00786 te += rdlen;
00787 {
00788 entryInfo se = (entryInfo)src;
00789
00790 int off = ntohl(se->offset);
00791 pe->offset = (off) ? htonl(te - dataStart) : htonl(off);
00792 }
00793 te += entry->info.count + drlen;
00794
00795 count = regionSwab(NULL, ril, 0, pe, t, NULL, 0);
00796 if (count != (rdlen + entry->info.count + drlen))
00797 goto errxit;
00798 }
00799
00800
00801 while (i < h->indexUsed && entry->info.offset <= rid+1) {
00802 i++;
00803 entry++;
00804 }
00805 i--;
00806 entry--;
00807 pe += ril;
00808 continue;
00809 }
00810
00811
00812 if (entry->data == NULL || entry->length <= 0)
00813 continue;
00814
00815
00816 type = entry->info.type;
00817 if (typeSizes[type] > 1) {
00818 unsigned diff;
00819 diff = typeSizes[type] - ((te - dataStart) % typeSizes[type]);
00820 if (diff != typeSizes[type]) {
00821
00822 memset(te, 0, diff);
00823
00824 te += diff;
00825 pad += diff;
00826 }
00827 }
00828
00829 pe->offset = htonl(te - dataStart);
00830
00831
00832
00833 switch (entry->info.type) {
00834 case RPM_INT64_TYPE:
00835 { int_32 b[2];
00836 count = entry->info.count;
00837 src = entry->data;
00838 while (count--) {
00839 b[1] = htonl(((int_32 *)src)[0]);
00840 b[0] = htonl(((int_32 *)src)[1]);
00841 if (b[1] == ((int_32 *)src)[0])
00842 memcpy(te, src, sizeof(b));
00843 else
00844 memcpy(te, b, sizeof(b));
00845 te += sizeof(b);
00846 src += sizeof(b);
00847 }
00848 } break;
00849
00850 case RPM_INT32_TYPE:
00851 count = entry->info.count;
00852 src = entry->data;
00853 while (count--) {
00854 *((int_32 *)te) = htonl(*((int_32 *)src));
00855
00856 te += sizeof(int_32);
00857 src += sizeof(int_32);
00858
00859 }
00860 break;
00861
00862 case RPM_INT16_TYPE:
00863 count = entry->info.count;
00864 src = entry->data;
00865 while (count--) {
00866 *((int_16 *)te) = htons(*((int_16 *)src));
00867
00868 te += sizeof(int_16);
00869 src += sizeof(int_16);
00870
00871 }
00872 break;
00873
00874 default:
00875 memcpy(te, entry->data, entry->length);
00876 te += entry->length;
00877 break;
00878 }
00879
00880 pe++;
00881 }
00882
00883
00884 if (((char *)pe) != dataStart)
00885 goto errxit;
00886 if ((((char *)ei)+len) != te)
00887 goto errxit;
00888
00889 if (lengthPtr)
00890 *lengthPtr = len;
00891
00892 h->flags &= ~HEADERFLAG_SORTED;
00893 headerSort(h);
00894
00895 return (void *) ei;
00896
00897 errxit:
00898
00899 ei = _free(ei);
00900
00901 return (void *) ei;
00902 }
00903
00909 static
00910 void * headerUnload(Header h)
00911
00912 {
00913 int length;
00914
00915 void * uh = doHeaderUnload(h, &length);
00916
00917 return uh;
00918 }
00919
00927 static
00928 indexEntry findEntry( Header h, int_32 tag, int_32 type)
00929
00930 {
00931 indexEntry entry, entry2, last;
00932 struct indexEntry_s key;
00933
00934 if (h == NULL) return NULL;
00935 if (!(h->flags & HEADERFLAG_SORTED)) headerSort(h);
00936
00937 key.info.tag = tag;
00938
00939
00940 entry2 = entry =
00941 bsearch(&key, h->index, h->indexUsed, sizeof(*h->index), indexCmp);
00942
00943 if (entry == NULL)
00944 return NULL;
00945
00946 if (type == RPM_NULL_TYPE)
00947 return entry;
00948
00949
00950 while (entry->info.tag == tag && entry->info.type != type &&
00951 entry > h->index) entry--;
00952
00953 if (entry->info.tag == tag && entry->info.type == type)
00954 return entry;
00955
00956 last = h->index + h->indexUsed;
00957
00958 while (entry2->info.tag == tag && entry2->info.type != type &&
00959 entry2 < last) entry2++;
00960
00961
00962 if (entry->info.tag == tag && entry->info.type == type)
00963 return entry;
00964
00965 return NULL;
00966 }
00967
00977 static
00978 int headerRemoveEntry(Header h, int_32 tag)
00979
00980 {
00981 indexEntry last = h->index + h->indexUsed;
00982 indexEntry entry, first;
00983 int ne;
00984
00985 entry = findEntry(h, tag, RPM_NULL_TYPE);
00986 if (!entry) return 1;
00987
00988
00989 while (entry > h->index && (entry - 1)->info.tag == tag)
00990 entry--;
00991
00992
00993 for (first = entry; first < last; first++) {
00994 void * data;
00995 if (first->info.tag != tag)
00996 break;
00997 data = first->data;
00998 first->data = NULL;
00999 first->length = 0;
01000 if (ENTRY_IN_REGION(first))
01001 continue;
01002 data = _free(data);
01003 }
01004
01005 ne = (first - entry);
01006 if (ne > 0) {
01007 h->indexUsed -= ne;
01008 ne = last - first;
01009
01010 if (ne > 0)
01011 memmove(entry, first, (ne * sizeof(*entry)));
01012
01013 }
01014
01015 return 0;
01016 }
01017
01023 static
01024 Header headerLoad( void * uh)
01025
01026 {
01027 int_32 * ei = (int_32 *) uh;
01028 int_32 il = ntohl(ei[0]);
01029 int_32 dl = ntohl(ei[1]);
01030
01031 size_t pvlen = sizeof(il) + sizeof(dl) +
01032 (il * sizeof(struct entryInfo_s)) + dl;
01033
01034 void * pv = uh;
01035 Header h = NULL;
01036 entryInfo pe;
01037 unsigned char * dataStart;
01038 unsigned char * dataEnd;
01039 indexEntry entry;
01040 int rdlen;
01041 int i;
01042
01043
01044 if (hdrchkTags(il) || hdrchkData(dl))
01045 goto errxit;
01046
01047 ei = (int_32 *) pv;
01048
01049 pe = (entryInfo) &ei[2];
01050
01051 dataStart = (unsigned char *) (pe + il);
01052 dataEnd = dataStart + dl;
01053
01054 h = xcalloc(1, sizeof(*h));
01055
01056 h->hv = *hdrVec;
01057
01058
01059 h->blob = uh;
01060
01061 h->indexAlloced = il + 1;
01062 h->indexUsed = il;
01063 h->index = xcalloc(h->indexAlloced, sizeof(*h->index));
01064 h->flags |= HEADERFLAG_SORTED;
01065 h->nrefs = 0;
01066 h = headerLink(h);
01067
01068
01069
01070
01071
01072 if (ntohl(pe->tag) == 15 &&
01073 ntohl(pe->type) == RPM_STRING_TYPE &&
01074 ntohl(pe->count) == 1)
01075 {
01076 pe->tag = htonl(1079);
01077 }
01078
01079 entry = h->index;
01080 i = 0;
01081 if (!(htonl(pe->tag) < HEADER_I18NTABLE)) {
01082 h->flags |= HEADERFLAG_LEGACY;
01083 entry->info.type = REGION_TAG_TYPE;
01084 entry->info.tag = HEADER_IMAGE;
01085
01086 entry->info.count = REGION_TAG_COUNT;
01087
01088 entry->info.offset = ((unsigned char *)pe - dataStart);
01089
01090
01091 entry->data = pe;
01092
01093 entry->length = pvlen - sizeof(il) - sizeof(dl);
01094 rdlen = regionSwab(entry+1, il, 0, pe, dataStart, dataEnd, entry->info.offset);
01095 #if 0
01096 if (rdlen != dl)
01097 goto errxit;
01098 #endif
01099 entry->rdlen = rdlen;
01100 entry++;
01101 h->indexUsed++;
01102 } else {
01103 int_32 rdl;
01104 int_32 ril;
01105
01106 h->flags &= ~HEADERFLAG_LEGACY;
01107
01108 entry->info.type = htonl(pe->type);
01109 entry->info.count = htonl(pe->count);
01110
01111 if (hdrchkType(entry->info.type))
01112 goto errxit;
01113 if (hdrchkTags(entry->info.count))
01114 goto errxit;
01115
01116 { int off = ntohl(pe->offset);
01117
01118 if (hdrchkData(off))
01119 goto errxit;
01120 if (off) {
01121
01122 size_t nb = REGION_TAG_COUNT;
01123
01124 int_32 * stei = memcpy(alloca(nb), dataStart + off, nb);
01125 rdl = -ntohl(stei[2]);
01126 ril = rdl/sizeof(*pe);
01127 if (hdrchkTags(ril) || hdrchkData(rdl))
01128 goto errxit;
01129 entry->info.tag = htonl(pe->tag);
01130 } else {
01131 ril = il;
01132
01133 rdl = (ril * sizeof(struct entryInfo_s));
01134
01135 entry->info.tag = HEADER_IMAGE;
01136 }
01137 }
01138 entry->info.offset = -rdl;
01139
01140
01141 entry->data = pe;
01142
01143 entry->length = pvlen - sizeof(il) - sizeof(dl);
01144 rdlen = regionSwab(entry+1, ril-1, 0, pe+1, dataStart, dataEnd, entry->info.offset);
01145 if (rdlen < 0)
01146 goto errxit;
01147 entry->rdlen = rdlen;
01148
01149 if (ril < h->indexUsed) {
01150 indexEntry newEntry = entry + ril;
01151 int ne = (h->indexUsed - ril);
01152 int rid = entry->info.offset+1;
01153 int rc;
01154
01155
01156 rc = regionSwab(newEntry, ne, 0, pe+ril, dataStart, dataEnd, rid);
01157 if (rc < 0)
01158 goto errxit;
01159 rdlen += rc;
01160
01161 { indexEntry firstEntry = newEntry;
01162 int save = h->indexUsed;
01163 int j;
01164
01165
01166 h->indexUsed -= ne;
01167 for (j = 0; j < ne; j++, newEntry++) {
01168 (void) headerRemoveEntry(h, newEntry->info.tag);
01169 if (newEntry->info.tag == HEADER_BASENAMES)
01170 (void) headerRemoveEntry(h, HEADER_OLDFILENAMES);
01171 }
01172
01173
01174
01175 if (h->indexUsed < (save - ne)) {
01176 memmove(h->index + h->indexUsed, firstEntry,
01177 (ne * sizeof(*entry)));
01178 }
01179
01180 h->indexUsed += ne;
01181 }
01182 }
01183 }
01184
01185 h->flags &= ~HEADERFLAG_SORTED;
01186 headerSort(h);
01187
01188
01189 return h;
01190
01191
01192 errxit:
01193
01194 if (h) {
01195 h->index = _free(h->index);
01196
01197 h = _free(h);
01198
01199 }
01200
01201
01202 return h;
01203
01204 }
01205
01211 static
01212 const char * headerGetOrigin( Header h)
01213
01214 {
01215 return (h != NULL ? h->origin : NULL);
01216 }
01217
01224 static
01225 int headerSetOrigin( Header h, const char * origin)
01226
01227 {
01228 if (h != NULL) {
01229 h->origin = _free(h->origin);
01230 h->origin = xstrdup(origin);
01231 }
01232 return 0;
01233 }
01234
01240 static
01241 int headerGetInstance( Header h)
01242
01243 {
01244 return (h != NULL ? h->instance : 0);
01245 }
01246
01253 static
01254 int headerSetInstance( Header h, int instance)
01255
01256 {
01257 if (h != NULL)
01258 h->instance = instance;
01259 return 0;
01260 }
01261
01269 static
01270 Header headerReload( Header h, int tag)
01271
01272 {
01273 Header nh;
01274 int length;
01275
01276
01277 void * uh = doHeaderUnload(h, &length);
01278
01279 const char * origin;
01280 int_32 instance = h->instance;
01281 int xx;
01282
01283 origin = (h->origin != NULL ? xstrdup(h->origin) : NULL);
01284 h = headerFree(h);
01285
01286 if (uh == NULL)
01287 return NULL;
01288 nh = headerLoad(uh);
01289 if (nh == NULL) {
01290 uh = _free(uh);
01291 return NULL;
01292 }
01293 if (nh->flags & HEADERFLAG_ALLOCATED)
01294 uh = _free(uh);
01295 nh->flags |= HEADERFLAG_ALLOCATED;
01296 if (ENTRY_IS_REGION(nh->index)) {
01297
01298 if (tag == HEADER_SIGNATURES || tag == HEADER_IMMUTABLE)
01299 nh->index[0].info.tag = tag;
01300
01301 }
01302 if (origin != NULL) {
01303 xx = headerSetOrigin(nh, origin);
01304 origin = _free(origin);
01305 }
01306 xx = headerSetInstance(nh, instance);
01307 return nh;
01308 }
01309
01315 static
01316 Header headerCopyLoad(const void * uh)
01317
01318 {
01319 int_32 * ei = (int_32 *) uh;
01320
01321 int_32 il = ntohl(ei[0]);
01322 int_32 dl = ntohl(ei[1]);
01323
01324
01325 size_t pvlen = sizeof(il) + sizeof(dl) +
01326 (il * sizeof(struct entryInfo_s)) + dl;
01327
01328 void * nuh = NULL;
01329 Header h = NULL;
01330
01331
01332
01333 if (!(hdrchkTags(il) || hdrchkData(dl)) && pvlen < headerMaxbytes) {
01334
01335 nuh = memcpy(xmalloc(pvlen), uh, pvlen);
01336
01337 if ((h = headerLoad(nuh)) != NULL)
01338 h->flags |= HEADERFLAG_ALLOCATED;
01339 }
01340
01341
01342 if (h == NULL)
01343 nuh = _free(nuh);
01344
01345 return h;
01346 }
01347
01354 static
01355 Header headerRead(FD_t fd, enum hMagic magicp)
01356
01357 {
01358 int_32 block[4];
01359 int_32 reserved;
01360 int_32 * ei = NULL;
01361 int_32 il;
01362 int_32 dl;
01363 int_32 magic;
01364 Header h = NULL;
01365 size_t len;
01366 int i;
01367
01368 memset(block, 0, sizeof(block));
01369 i = 2;
01370 if (magicp == HEADER_MAGIC_YES)
01371 i += 2;
01372
01373
01374 if (timedRead(fd, (char *)block, i*sizeof(*block)) != (i * sizeof(*block)))
01375 goto exit;
01376
01377
01378 i = 0;
01379
01380
01381 if (magicp == HEADER_MAGIC_YES) {
01382 magic = block[i++];
01383 if (memcmp(&magic, header_magic, sizeof(magic)))
01384 goto exit;
01385 reserved = block[i++];
01386 }
01387
01388 il = ntohl(block[i]); i++;
01389 dl = ntohl(block[i]); i++;
01390
01391
01392
01393 len = sizeof(il) + sizeof(dl) + (il * sizeof(struct entryInfo_s)) + dl;
01394
01395
01396
01397 if (hdrchkTags(il) || hdrchkData(dl) || len > headerMaxbytes)
01398 goto exit;
01399
01400
01401 ei = xmalloc(len);
01402 ei[0] = htonl(il);
01403 ei[1] = htonl(dl);
01404 len -= sizeof(il) + sizeof(dl);
01405
01406
01407
01408
01409 if (timedRead(fd, (char *)&ei[2], len) != len)
01410 goto exit;
01411
01412
01413
01414 h = headerLoad(ei);
01415
01416 { const char * origin = fdGetOPath(fd);
01417 if (origin != NULL)
01418 (void) headerSetOrigin(h, origin);
01419 }
01420
01421 exit:
01422 if (h) {
01423 if (h->flags & HEADERFLAG_ALLOCATED)
01424 ei = _free(ei);
01425 h->flags |= HEADERFLAG_ALLOCATED;
01426 } else if (ei)
01427 ei = _free(ei);
01428
01429 return h;
01430
01431 }
01432
01440 static
01441 int headerWrite(FD_t fd, Header h, enum hMagic magicp)
01442
01443
01444 {
01445 ssize_t nb;
01446 int length;
01447 const void * uh;
01448
01449 if (h == NULL)
01450 return 1;
01451
01452 uh = doHeaderUnload(h, &length);
01453
01454 if (uh == NULL)
01455 return 1;
01456 switch (magicp) {
01457 case HEADER_MAGIC_YES:
01458
01459
01460 nb = Fwrite(header_magic, sizeof(char), sizeof(header_magic), fd);
01461
01462
01463 if (nb != sizeof(header_magic))
01464 goto exit;
01465 break;
01466 case HEADER_MAGIC_NO:
01467 break;
01468 }
01469
01470
01471 nb = Fwrite(uh, sizeof(char), length, fd);
01472
01473
01474 exit:
01475 uh = _free(uh);
01476 return (nb == length ? 0 : 1);
01477 }
01478
01485 static
01486 int headerIsEntry(Header h, int_32 tag)
01487
01488 {
01489
01490 return (findEntry(h, tag, RPM_NULL_TYPE) ? 1 : 0);
01491
01492 }
01493
01504 static int copyEntry(const indexEntry entry,
01505 hTYP_t type,
01506 hPTR_t * p,
01507 hCNT_t c,
01508 int minMem)
01509
01510
01511 {
01512 int_32 count = entry->info.count;
01513 int rc = 1;
01514
01515 if (p)
01516 switch (entry->info.type) {
01517 case RPM_BIN_TYPE:
01518
01519
01520
01521
01522
01523
01524 if (ENTRY_IS_REGION(entry)) {
01525 int_32 * ei = ((int_32 *)entry->data) - 2;
01526
01527 entryInfo pe = (entryInfo) (ei + 2);
01528
01529
01530 char * dataStart = (char *) (pe + ntohl(ei[0]));
01531
01532 int_32 rdl = -entry->info.offset;
01533 int_32 ril = rdl/sizeof(*pe);
01534
01535
01536 rdl = entry->rdlen;
01537 count = 2 * sizeof(*ei) + (ril * sizeof(*pe)) + rdl;
01538 if (entry->info.tag == HEADER_IMAGE) {
01539 ril -= 1;
01540 pe += 1;
01541 } else {
01542 count += REGION_TAG_COUNT;
01543 rdl += REGION_TAG_COUNT;
01544 }
01545
01546
01547 *p = xmalloc(count);
01548 ei = (int_32 *) *p;
01549 ei[0] = htonl(ril);
01550 ei[1] = htonl(rdl);
01551
01552
01553 pe = (entryInfo) memcpy(ei + 2, pe, (ril * sizeof(*pe)));
01554
01555
01556 dataStart = (char *) memcpy(pe + ril, dataStart, rdl);
01557
01558
01559
01560 rc = regionSwab(NULL, ril, 0, pe, dataStart, NULL, 0);
01561
01562 rc = (rc < 0) ? 0 : 1;
01563 } else {
01564 count = entry->length;
01565 *p = (!minMem
01566 ? memcpy(xmalloc(count), entry->data, count)
01567 : entry->data);
01568 }
01569 break;
01570 case RPM_STRING_TYPE:
01571 if (count == 1) {
01572 *p = entry->data;
01573 break;
01574 }
01575
01576 case RPM_STRING_ARRAY_TYPE:
01577 case RPM_I18NSTRING_TYPE:
01578 { const char ** ptrEntry;
01579
01580 int tableSize = count * sizeof(char *);
01581
01582 char * t;
01583 int i;
01584
01585
01586
01587 if (minMem) {
01588 *p = xmalloc(tableSize);
01589 ptrEntry = (const char **) *p;
01590 t = entry->data;
01591 } else {
01592 t = xmalloc(tableSize + entry->length);
01593 *p = (void *)t;
01594 ptrEntry = (const char **) *p;
01595 t += tableSize;
01596 memcpy(t, entry->data, entry->length);
01597 }
01598
01599
01600 for (i = 0; i < count; i++) {
01601
01602 *ptrEntry++ = t;
01603
01604 t = strchr(t, 0);
01605 t++;
01606 }
01607 } break;
01608
01609 case RPM_OPENPGP_TYPE:
01610 case RPM_ASN1_TYPE:
01611 default:
01612 *p = entry->data;
01613 break;
01614 }
01615 if (type) *type = entry->info.type;
01616 if (c) *c = count;
01617 return rc;
01618 }
01619
01638 static int headerMatchLocale(const char *td, const char *l, const char *le)
01639
01640 {
01641 const char *fe;
01642
01643
01644 #if 0
01645 { const char *s, *ll, *CC, *EE, *dd;
01646 char *lbuf, *t.
01647
01648
01649 lbuf = alloca(le - l + 1);
01650 for (s = l, ll = t = lbuf; *s; s++, t++) {
01651 switch (*s) {
01652 case '_':
01653 *t = '\0';
01654 CC = t + 1;
01655 break;
01656 case '.':
01657 *t = '\0';
01658 EE = t + 1;
01659 break;
01660 case '@':
01661 *t = '\0';
01662 dd = t + 1;
01663 break;
01664 default:
01665 *t = *s;
01666 break;
01667 }
01668 }
01669
01670 if (ll)
01671 for (t = ll; *t; t++) *t = tolower(*t);
01672 if (CC)
01673 for (t = CC; *t; t++) *t = toupper(*t);
01674
01675
01676 }
01677 #endif
01678
01679
01680 if (strlen(td) == (le-l) && !strncmp(td, l, (le - 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
01690 for (fe = l; fe < le && *fe != '.'; fe++)
01691 {};
01692 if (fe < le && !strncmp(td, l, (fe - l)))
01693 return 1;
01694
01695
01696 for (fe = l; fe < le && *fe != '_'; fe++)
01697 {};
01698 if (fe < le && !strncmp(td, l, (fe - l)))
01699 return 1;
01700
01701 return 0;
01702 }
01703
01710 static char *
01711 headerFindI18NString(Header h, indexEntry entry)
01712
01713 {
01714 const char *lang, *l, *le;
01715 indexEntry table;
01716
01717
01718 if ((lang = getenv("LANGUAGE")) == NULL &&
01719 (lang = getenv("LC_ALL")) == NULL &&
01720 (lang = getenv("LC_MESSAGES")) == NULL &&
01721 (lang = getenv("LANG")) == NULL)
01722 return entry->data;
01723
01724
01725 if ((table = findEntry(h, HEADER_I18NTABLE, RPM_STRING_ARRAY_TYPE)) == NULL)
01726 return entry->data;
01727
01728
01729
01730 for (l = lang; *l != '\0'; l = le) {
01731 const char *td;
01732 char *ed;
01733 int langNum;
01734
01735 while (*l && *l == ':')
01736 l++;
01737 if (*l == '\0')
01738 break;
01739 for (le = l; *le && *le != ':'; le++)
01740 {};
01741
01742
01743 for (langNum = 0, td = table->data, ed = entry->data;
01744 langNum < entry->info.count;
01745 langNum++, td += strlen(td) + 1, ed += strlen(ed) + 1) {
01746
01747 if (headerMatchLocale(td, l, le))
01748 return ed;
01749
01750 }
01751 }
01752
01753
01754 return entry->data;
01755 }
01756
01767 static int intGetEntry(Header h, int_32 tag,
01768 hTAG_t type,
01769 hPTR_t * p,
01770 hCNT_t c,
01771 int minMem)
01772
01773
01774 {
01775 indexEntry entry;
01776 int rc;
01777
01778
01779
01780 entry = findEntry(h, tag, RPM_NULL_TYPE);
01781
01782 if (entry == NULL) {
01783 if (type) type = 0;
01784 if (p) *p = NULL;
01785 if (c) *c = 0;
01786 return 0;
01787 }
01788
01789 switch (entry->info.type) {
01790 case RPM_I18NSTRING_TYPE:
01791 rc = 1;
01792 if (type) *type = RPM_STRING_TYPE;
01793 if (c) *c = 1;
01794
01795 if (p) *p = headerFindI18NString(h, entry);
01796
01797 break;
01798 default:
01799 rc = copyEntry(entry, type, p, c, minMem);
01800 break;
01801 }
01802
01803
01804 return ((rc == 1) ? 1 : 0);
01805 }
01806
01814 static void * headerFreeTag( Header h,
01815 const void * data, rpmTagType type)
01816
01817 {
01818 if (data) {
01819
01820 if (type == -1 ||
01821 type == RPM_STRING_ARRAY_TYPE ||
01822 type == RPM_I18NSTRING_TYPE ||
01823 type == RPM_BIN_TYPE ||
01824 type == RPM_ASN1_TYPE ||
01825 type == RPM_OPENPGP_TYPE)
01826 data = _free(data);
01827
01828 }
01829 return NULL;
01830 }
01831
01845 static
01846 int headerGetEntry(Header h, int_32 tag,
01847 hTYP_t type,
01848 void * p,
01849 hCNT_t c)
01850
01851
01852 {
01853 return intGetEntry(h, tag, type, (hPTR_t *)p, c, 0);
01854 }
01855
01868 static
01869 int headerGetEntryMinMemory(Header h, int_32 tag,
01870 hTYP_t type,
01871 void * p,
01872 hCNT_t c)
01873
01874
01875 {
01876 return intGetEntry(h, tag, type, p, c, 1);
01877 }
01878
01879 int headerGetRawEntry(Header h, int_32 tag, int_32 * type, void * p, int_32 * c)
01880 {
01881 indexEntry entry;
01882 int rc;
01883
01884 if (p == NULL) return headerIsEntry(h, tag);
01885
01886
01887
01888 entry = findEntry(h, tag, RPM_NULL_TYPE);
01889
01890 if (!entry) {
01891 if (p) *(void **)p = NULL;
01892 if (c) *c = 0;
01893 return 0;
01894 }
01895
01896 rc = copyEntry(entry, type, p, c, 0);
01897
01898
01899 return ((rc == 1) ? 1 : 0);
01900 }
01901
01904 static void copyData(int_32 type, void * dstPtr, const void * srcPtr,
01905 int_32 cnt, int dataLength)
01906
01907 {
01908 switch (type) {
01909 case RPM_STRING_ARRAY_TYPE:
01910 case RPM_I18NSTRING_TYPE:
01911 { const char ** av = (const char **) srcPtr;
01912 char * t = dstPtr;
01913
01914
01915 while (cnt-- > 0 && dataLength > 0) {
01916 const char * s;
01917 if ((s = *av++) == NULL)
01918 continue;
01919 do {
01920 *t++ = *s++;
01921 } while (s[-1] && --dataLength > 0);
01922 }
01923
01924 } break;
01925
01926 default:
01927
01928 memmove(dstPtr, srcPtr, dataLength);
01929
01930 break;
01931 }
01932 }
01933
01942
01943 static void *
01944 grabData(int_32 type, hPTR_t p, int_32 c, int * lengthPtr)
01945
01946
01947 {
01948 void * data = NULL;
01949 int length;
01950
01951 length = dataLength(type, p, c, 0, NULL);
01952
01953 if (length > 0) {
01954 data = xmalloc(length);
01955 copyData(type, data, p, c, length);
01956 }
01957
01958
01959 if (lengthPtr)
01960 *lengthPtr = length;
01961 return data;
01962 }
01963
01978 static
01979 int headerAddEntry(Header h, int_32 tag, int_32 type, const void * p, int_32 c)
01980
01981 {
01982 indexEntry entry;
01983 void * data;
01984 int length;
01985
01986
01987 if (c <= 0)
01988 return 0;
01989
01990 if (hdrchkType(type))
01991 return 0;
01992 if (hdrchkData(c))
01993 return 0;
01994
01995 length = 0;
01996
01997 data = grabData(type, p, c, &length);
01998
01999 if (data == NULL || length <= 0)
02000 return 0;
02001
02002
02003 if (h->indexUsed == h->indexAlloced) {
02004 h->indexAlloced += INDEX_MALLOC_SIZE;
02005 h->index = xrealloc(h->index, h->indexAlloced * sizeof(*h->index));
02006 }
02007
02008
02009 entry = h->index + h->indexUsed;
02010 entry->info.tag = tag;
02011 entry->info.type = type;
02012 entry->info.count = c;
02013 entry->info.offset = 0;
02014 entry->data = data;
02015 entry->length = length;
02016
02017
02018 if (h->indexUsed > 0 && tag < h->index[h->indexUsed-1].info.tag)
02019 h->flags &= ~HEADERFLAG_SORTED;
02020
02021 h->indexUsed++;
02022
02023 return 1;
02024 }
02025
02040 static
02041 int headerAppendEntry(Header h, int_32 tag, int_32 type,
02042 const void * p, int_32 c)
02043
02044 {
02045 indexEntry entry;
02046 int length;
02047
02048 if (type == RPM_STRING_TYPE || type == RPM_I18NSTRING_TYPE) {
02049
02050 return 0;
02051 }
02052
02053
02054 entry = findEntry(h, tag, type);
02055 if (!entry)
02056 return 0;
02057
02058 length = dataLength(type, p, c, 0, NULL);
02059 if (length < 0)
02060 return 0;
02061
02062 if (ENTRY_IN_REGION(entry)) {
02063 char * t = xmalloc(entry->length + length);
02064
02065 memcpy(t, entry->data, entry->length);
02066
02067 entry->data = t;
02068 entry->info.offset = 0;
02069 } else
02070 entry->data = xrealloc(entry->data, entry->length + length);
02071
02072 copyData(type, ((char *) entry->data) + entry->length, p, c, length);
02073
02074 entry->length += length;
02075
02076 entry->info.count += c;
02077
02078 return 1;
02079 }
02080
02090 static
02091 int headerAddOrAppendEntry(Header h, int_32 tag, int_32 type,
02092 const void * p, int_32 c)
02093
02094 {
02095 return (findEntry(h, tag, type)
02096 ? headerAppendEntry(h, tag, type, p, c)
02097 : headerAddEntry(h, tag, type, p, c));
02098 }
02099
02120 static
02121 int headerAddI18NString(Header h, int_32 tag, const char * string,
02122 const char * lang)
02123
02124 {
02125 indexEntry table, entry;
02126 const char ** strArray;
02127 int length;
02128 int ghosts;
02129 int i, langNum;
02130 char * buf;
02131
02132 table = findEntry(h, HEADER_I18NTABLE, RPM_STRING_ARRAY_TYPE);
02133 entry = findEntry(h, tag, RPM_I18NSTRING_TYPE);
02134
02135 if (!table && entry)
02136 return 0;
02137
02138 if (!table && !entry) {
02139 const char * charArray[2];
02140 int count = 0;
02141 if (!lang || (lang[0] == 'C' && lang[1] == '\0')) {
02142
02143 charArray[count++] = "C";
02144
02145 } else {
02146
02147 charArray[count++] = "C";
02148
02149 charArray[count++] = lang;
02150 }
02151 if (!headerAddEntry(h, HEADER_I18NTABLE, RPM_STRING_ARRAY_TYPE,
02152 &charArray, count))
02153 return 0;
02154 table = findEntry(h, HEADER_I18NTABLE, RPM_STRING_ARRAY_TYPE);
02155 }
02156
02157 if (!table)
02158 return 0;
02159
02160 if (!lang) lang = "C";
02161
02162
02163 { const char * l = table->data;
02164 for (langNum = 0; langNum < table->info.count; langNum++) {
02165 if (!strcmp(l, lang)) break;
02166 l += strlen(l) + 1;
02167 }
02168 }
02169
02170 if (langNum >= table->info.count) {
02171 length = strlen(lang) + 1;
02172 if (ENTRY_IN_REGION(table)) {
02173 char * t = xmalloc(table->length + length);
02174 memcpy(t, table->data, table->length);
02175 table->data = t;
02176 table->info.offset = 0;
02177 } else
02178 table->data = xrealloc(table->data, table->length + length);
02179 memmove(((char *)table->data) + table->length, lang, length);
02180 table->length += length;
02181 table->info.count++;
02182 }
02183
02184 if (!entry) {
02185 strArray = alloca(sizeof(*strArray) * (langNum + 1));
02186 for (i = 0; i < langNum; i++)
02187 strArray[i] = "";
02188 strArray[langNum] = string;
02189 return headerAddEntry(h, tag, RPM_I18NSTRING_TYPE, strArray,
02190 langNum + 1);
02191 } else if (langNum >= entry->info.count) {
02192 ghosts = langNum - entry->info.count;
02193
02194 length = strlen(string) + 1 + ghosts;
02195 if (ENTRY_IN_REGION(entry)) {
02196 char * t = xmalloc(entry->length + length);
02197 memcpy(t, entry->data, entry->length);
02198 entry->data = t;
02199 entry->info.offset = 0;
02200 } else
02201 entry->data = xrealloc(entry->data, entry->length + length);
02202
02203 memset(((char *)entry->data) + entry->length, '\0', ghosts);
02204 memmove(((char *)entry->data) + entry->length + ghosts, string, strlen(string)+1);
02205
02206 entry->length += length;
02207 entry->info.count = langNum + 1;
02208 } else {
02209 char *b, *be, *e, *ee, *t;
02210 size_t bn, sn, en;
02211
02212
02213 b = be = e = ee = entry->data;
02214 for (i = 0; i < table->info.count; i++) {
02215 if (i == langNum)
02216 be = ee;
02217 ee += strlen(ee) + 1;
02218 if (i == langNum)
02219 e = ee;
02220 }
02221
02222
02223 bn = (be-b);
02224 sn = strlen(string) + 1;
02225 en = (ee-e);
02226 length = bn + sn + en;
02227 t = buf = xmalloc(length);
02228
02229
02230 memcpy(t, b, bn);
02231 t += bn;
02232
02233 memcpy(t, string, sn);
02234 t += sn;
02235 memcpy(t, e, en);
02236 t += en;
02237
02238
02239
02240 entry->length -= strlen(be) + 1;
02241 entry->length += sn;
02242
02243 if (ENTRY_IN_REGION(entry)) {
02244 entry->info.offset = 0;
02245 } else
02246 entry->data = _free(entry->data);
02247
02248 entry->data = buf;
02249
02250 }
02251
02252 return 0;
02253 }
02254
02265 static
02266 int headerModifyEntry(Header h, int_32 tag, int_32 type,
02267 const void * p, int_32 c)
02268
02269 {
02270 indexEntry entry;
02271 void * oldData;
02272 void * data;
02273 int length;
02274
02275
02276 entry = findEntry(h, tag, type);
02277 if (!entry)
02278 return 0;
02279
02280 length = 0;
02281 data = grabData(type, p, c, &length);
02282 if (data == NULL || length <= 0)
02283 return 0;
02284
02285
02286 while (entry > h->index && (entry - 1)->info.tag == tag)
02287 entry--;
02288
02289
02290
02291 oldData = entry->data;
02292
02293 entry->info.count = c;
02294 entry->info.type = type;
02295 entry->data = data;
02296 entry->length = length;
02297
02298
02299 if (ENTRY_IN_REGION(entry)) {
02300 entry->info.offset = 0;
02301 } else
02302 oldData = _free(oldData);
02303
02304
02305 return 1;
02306 }
02307
02310 static char escapedChar(const char ch)
02311 {
02312 switch (ch) {
02313 case 'a': return '\a';
02314 case 'b': return '\b';
02315 case 'f': return '\f';
02316 case 'n': return '\n';
02317 case 'r': return '\r';
02318 case 't': return '\t';
02319 case 'v': return '\v';
02320 default: return ch;
02321 }
02322 }
02323
02330 static sprintfToken
02331 freeFormat( sprintfToken format, int num)
02332
02333 {
02334 int i;
02335
02336 if (format == NULL) return NULL;
02337
02338 for (i = 0; i < num; i++) {
02339 switch (format[i].type) {
02340 case PTOK_ARRAY:
02341
02342 format[i].u.array.format =
02343 freeFormat(format[i].u.array.format,
02344 format[i].u.array.numTokens);
02345
02346 break;
02347 case PTOK_COND:
02348
02349 format[i].u.cond.ifFormat =
02350 freeFormat(format[i].u.cond.ifFormat,
02351 format[i].u.cond.numIfTokens);
02352 format[i].u.cond.elseFormat =
02353 freeFormat(format[i].u.cond.elseFormat,
02354 format[i].u.cond.numElseTokens);
02355
02356 break;
02357 case PTOK_NONE:
02358 case PTOK_TAG:
02359 case PTOK_STRING:
02360 default:
02361 break;
02362 }
02363 }
02364 format = _free(format);
02365 return NULL;
02366 }
02367
02371 struct headerIterator_s {
02372
02373 Header h;
02374
02375 int next_index;
02376 };
02377
02383 static
02384 HeaderIterator headerFreeIterator( HeaderIterator hi)
02385
02386 {
02387 if (hi != NULL) {
02388 hi->h = headerFree(hi->h);
02389 hi = _free(hi);
02390 }
02391 return hi;
02392 }
02393
02399 static
02400 HeaderIterator headerInitIterator(Header h)
02401
02402 {
02403 HeaderIterator hi = xmalloc(sizeof(*hi));
02404
02405 headerSort(h);
02406
02407 hi->h = headerLink(h);
02408 hi->next_index = 0;
02409 return hi;
02410 }
02411
02421 static
02422 int headerNextIterator(HeaderIterator hi,
02423 hTAG_t tag,
02424 hTYP_t type,
02425 hPTR_t * p,
02426 hCNT_t c)
02427
02428
02429
02430 {
02431 Header h = hi->h;
02432 int slot = hi->next_index;
02433 indexEntry entry = NULL;
02434 int rc;
02435
02436 for (slot = hi->next_index; slot < h->indexUsed; slot++) {
02437 entry = h->index + slot;
02438 if (!ENTRY_IS_REGION(entry))
02439 break;
02440 }
02441 hi->next_index = slot;
02442 if (entry == NULL || slot >= h->indexUsed)
02443 return 0;
02444
02445
02446 hi->next_index++;
02447
02448
02449 if (tag)
02450 *tag = entry->info.tag;
02451
02452 rc = copyEntry(entry, type, p, c, 0);
02453
02454
02455 return ((rc == 1) ? 1 : 0);
02456 }
02457
02463 static
02464 Header headerCopy(Header h)
02465
02466 {
02467 Header nh = headerNew();
02468 HeaderIterator hi;
02469 int_32 tag, type, count;
02470 hPTR_t ptr;
02471
02472
02473 for (hi = headerInitIterator(h);
02474 headerNextIterator(hi, &tag, &type, &ptr, &count);
02475 ptr = headerFreeData((void *)ptr, type))
02476 {
02477 if (ptr) (void) headerAddEntry(nh, tag, type, ptr, count);
02478 }
02479 hi = headerFreeIterator(hi);
02480
02481
02482 return headerReload(nh, HEADER_IMAGE);
02483 }
02484
02487 typedef struct headerSprintfArgs_s {
02488 Header h;
02489 char * fmt;
02490
02491 headerTagTableEntry tags;
02492
02493 headerSprintfExtension exts;
02494
02495 const char * errmsg;
02496 rpmec ec;
02497 sprintfToken format;
02498
02499 HeaderIterator hi;
02500
02501 char * val;
02502 size_t vallen;
02503 size_t alloced;
02504 int numTokens;
02505 int i;
02506 } * headerSprintfArgs;
02507
02513 static headerSprintfArgs hsaInit( headerSprintfArgs hsa)
02514
02515 {
02516 sprintfTag tag =
02517 (hsa->format->type == PTOK_TAG
02518 ? &hsa->format->u.tag :
02519 (hsa->format->type == PTOK_ARRAY
02520 ? &hsa->format->u.array.format->u.tag :
02521 NULL));
02522
02523 if (hsa != NULL) {
02524 hsa->i = 0;
02525 if (tag != NULL && tag->tag == -2)
02526 hsa->hi = headerInitIterator(hsa->h);
02527 }
02528
02529 return hsa;
02530
02531 }
02532
02538
02539 static sprintfToken hsaNext( headerSprintfArgs hsa)
02540
02541 {
02542 sprintfToken fmt = NULL;
02543 sprintfTag tag =
02544 (hsa->format->type == PTOK_TAG
02545 ? &hsa->format->u.tag :
02546 (hsa->format->type == PTOK_ARRAY
02547 ? &hsa->format->u.array.format->u.tag :
02548 NULL));
02549
02550 if (hsa != NULL && hsa->i >= 0 && hsa->i < hsa->numTokens) {
02551 fmt = hsa->format + hsa->i;
02552 if (hsa->hi == NULL) {
02553 hsa->i++;
02554 } else {
02555 int_32 tagno;
02556 int_32 type;
02557 int_32 count;
02558
02559
02560 if (!headerNextIterator(hsa->hi, &tagno, &type, NULL, &count))
02561 fmt = NULL;
02562 tag->tag = tagno;
02563
02564 }
02565 }
02566
02567
02568 return fmt;
02569
02570 }
02571
02577 static headerSprintfArgs hsaFini( headerSprintfArgs hsa)
02578
02579 {
02580 if (hsa != NULL) {
02581 hsa->hi = headerFreeIterator(hsa->hi);
02582 hsa->i = 0;
02583 }
02584
02585 return hsa;
02586
02587 }
02588
02595
02596 static char * hsaReserve(headerSprintfArgs hsa, size_t need)
02597
02598 {
02599 if ((hsa->vallen + need) >= hsa->alloced) {
02600 if (hsa->alloced <= need)
02601 hsa->alloced += need;
02602 hsa->alloced <<= 1;
02603 hsa->val = xrealloc(hsa->val, hsa->alloced+1);
02604 }
02605 return hsa->val + hsa->vallen;
02606 }
02607
02616
02617 static const char * myTagName(headerTagTableEntry tbl, int val,
02618 int *typep)
02619
02620 {
02621 static char name[128];
02622 const char * s;
02623 char *t;
02624
02625 for (; tbl->name != NULL; tbl++) {
02626 if (tbl->val == val)
02627 break;
02628 }
02629 if ((s = tbl->name) == NULL)
02630 return NULL;
02631 s += sizeof("RPMTAG_") - 1;
02632 t = name;
02633 *t++ = *s++;
02634 while (*s != '\0')
02635 *t++ = xtolower(*s++);
02636 *t = '\0';
02637 if (typep)
02638 *typep = tbl->type;
02639 return name;
02640 }
02641
02649 static int myTagValue(headerTagTableEntry tbl, const char * name)
02650
02651 {
02652 for (; tbl->name != NULL; tbl++) {
02653 if (!xstrcasecmp(tbl->name, name))
02654 return tbl->val;
02655 }
02656 return 0;
02657 }
02658
02666 static int findTag(headerSprintfArgs hsa, sprintfToken token, const char * name)
02667
02668 {
02669 headerSprintfExtension ext;
02670 sprintfTag stag = (token->type == PTOK_COND
02671 ? &token->u.cond.tag : &token->u.tag);
02672
02673 stag->fmt = NULL;
02674 stag->ext = NULL;
02675 stag->extNum = 0;
02676 stag->tag = -1;
02677
02678 if (!strcmp(name, "*")) {
02679 stag->tag = -2;
02680 goto bingo;
02681 }
02682
02683
02684 if (strncmp("RPMTAG_", name, sizeof("RPMTAG_")-1)) {
02685
02686 char * t = alloca(strlen(name) + sizeof("RPMTAG_"));
02687 (void) stpcpy( stpcpy(t, "RPMTAG_"), name);
02688 name = t;
02689
02690 }
02691
02692
02693
02694 for (ext = hsa->exts; ext != NULL && ext->type != HEADER_EXT_LAST;
02695 ext = (ext->type == HEADER_EXT_MORE ? ext->u.more : ext+1))
02696 {
02697 if (ext->name == NULL || ext->type != HEADER_EXT_TAG)
02698 continue;
02699 if (!xstrcasecmp(ext->name, name)) {
02700 stag->ext = ext->u.tagFunction;
02701 stag->extNum = ext - hsa->exts;
02702 goto bingo;
02703 }
02704 }
02705
02706
02707 stag->tag = myTagValue(hsa->tags, name);
02708 if (stag->tag != 0)
02709 goto bingo;
02710
02711 return 1;
02712
02713 bingo:
02714
02715 if (stag->type != NULL)
02716 for (ext = hsa->exts; ext != NULL && ext->type != HEADER_EXT_LAST;
02717 ext = (ext->type == HEADER_EXT_MORE ? ext->u.more : ext+1))
02718 {
02719 if (ext->name == NULL || ext->type != HEADER_EXT_FORMAT)
02720 continue;
02721 if (!strcmp(ext->name, stag->type)) {
02722 stag->fmt = ext->u.formatFunction;
02723 break;
02724 }
02725 }
02726 return 0;
02727 }
02728
02729
02738 static int parseExpression(headerSprintfArgs hsa, sprintfToken token,
02739 char * str, char ** endPtr)
02740
02741 ;
02742
02753 static int parseFormat(headerSprintfArgs hsa, char * str,
02754 sprintfToken * formatPtr, int * numTokensPtr,
02755 char ** endPtr, int state)
02756
02757
02758
02759 {
02760 char * chptr, * start, * next, * dst;
02761 sprintfToken format;
02762 sprintfToken token;
02763 int numTokens;
02764 int i;
02765 int done = 0;
02766
02767
02768 numTokens = 0;
02769 if (str != NULL)
02770 for (chptr = str; *chptr != '\0'; chptr++)
02771 if (*chptr == '%') numTokens++;
02772 numTokens = numTokens * 2 + 1;
02773
02774 format = xcalloc(numTokens, sizeof(*format));
02775 if (endPtr) *endPtr = NULL;
02776
02777
02778 dst = start = str;
02779 numTokens = 0;
02780 token = NULL;
02781 if (start != NULL)
02782 while (*start != '\0') {
02783 switch (*start) {
02784 case '%':
02785
02786 if (*(start + 1) == '%') {
02787 if (token == NULL || token->type != PTOK_STRING) {
02788 token = format + numTokens++;
02789 token->type = PTOK_STRING;
02790
02791 dst = token->u.string.string = start;
02792
02793 }
02794 start++;
02795
02796 *dst++ = *start++;
02797
02798 break;
02799 }
02800
02801 token = format + numTokens++;
02802
02803 *dst++ = '\0';
02804
02805 start++;
02806
02807 if (*start == '|') {
02808 char * newEnd;
02809
02810 start++;
02811
02812 if (parseExpression(hsa, token, start, &newEnd))
02813 {
02814 format = freeFormat(format, numTokens);
02815 return 1;
02816 }
02817
02818 start = newEnd;
02819 break;
02820 }
02821
02822
02823 token->u.tag.format = start;
02824
02825 token->u.tag.pad = 0;
02826 token->u.tag.justOne = 0;
02827 token->u.tag.arrayCount = 0;
02828
02829 chptr = start;
02830 while (*chptr && *chptr != '{' && *chptr != '%') chptr++;
02831 if (!*chptr || *chptr == '%') {
02832 hsa->errmsg = _("missing { after %");
02833 format = freeFormat(format, numTokens);
02834 return 1;
02835 }
02836
02837
02838 *chptr++ = '\0';
02839
02840
02841 while (start < chptr) {
02842 if (xisdigit(*start)) {
02843 i = strtoul(start, &start, 10);
02844 token->u.tag.pad += i;
02845 } else {
02846 start++;
02847 }
02848 }
02849
02850 if (*start == '=') {
02851 token->u.tag.justOne = 1;
02852 start++;
02853 } else if (*start == '#') {
02854 token->u.tag.justOne = 1;
02855 token->u.tag.arrayCount = 1;
02856 start++;
02857 }
02858
02859 next = start;
02860 while (*next && *next != '}') next++;
02861 if (!*next) {
02862 hsa->errmsg = _("missing } after %{");
02863 format = freeFormat(format, numTokens);
02864 return 1;
02865 }
02866
02867 *next++ = '\0';
02868
02869
02870 chptr = start;
02871 while (*chptr && *chptr != ':') chptr++;
02872
02873 if (*chptr != '\0') {
02874
02875 *chptr++ = '\0';
02876
02877 if (!*chptr) {
02878 hsa->errmsg = _("empty tag format");
02879 format = freeFormat(format, numTokens);
02880 return 1;
02881 }
02882
02883 token->u.tag.type = chptr;
02884
02885 } else {
02886 token->u.tag.type = NULL;
02887 }
02888
02889 if (!*start) {
02890 hsa->errmsg = _("empty tag name");
02891 format = freeFormat(format, numTokens);
02892 return 1;
02893 }
02894
02895 i = 0;
02896 token->type = PTOK_TAG;
02897
02898 if (findTag(hsa, token, start)) {
02899 hsa->errmsg = _("unknown tag");
02900 format = freeFormat(format, numTokens);
02901 return 1;
02902 }
02903
02904 start = next;
02905 break;
02906
02907 case '[':
02908
02909 *dst++ = '\0';
02910 *start++ = '\0';
02911
02912 token = format + numTokens++;
02913
02914
02915 if (parseFormat(hsa, start,
02916 &token->u.array.format,
02917 &token->u.array.numTokens,
02918 &start, PARSER_IN_ARRAY))
02919 {
02920 format = freeFormat(format, numTokens);
02921 return 1;
02922 }
02923
02924
02925 if (!start) {
02926 hsa->errmsg = _("] expected at end of array");
02927 format = freeFormat(format, numTokens);
02928 return 1;
02929 }
02930
02931 dst = start;
02932
02933 token->type = PTOK_ARRAY;
02934
02935 break;
02936
02937 case ']':
02938 if (state != PARSER_IN_ARRAY) {
02939 hsa->errmsg = _("unexpected ]");
02940 format = freeFormat(format, numTokens);
02941 return 1;
02942 }
02943
02944 *start++ = '\0';
02945
02946 if (endPtr) *endPtr = start;
02947 done = 1;
02948 break;
02949
02950 case '}':
02951 if (state != PARSER_IN_EXPR) {
02952 hsa->errmsg = _("unexpected }");
02953 format = freeFormat(format, numTokens);
02954 return 1;
02955 }
02956
02957 *start++ = '\0';
02958
02959 if (endPtr) *endPtr = start;
02960 done = 1;
02961 break;
02962
02963 default:
02964 if (token == NULL || token->type != PTOK_STRING) {
02965 token = format + numTokens++;
02966 token->type = PTOK_STRING;
02967
02968 dst = token->u.string.string = start;
02969
02970 }
02971
02972
02973 if (*start == '\\') {
02974 start++;
02975 *dst++ = escapedChar(*start++);
02976 } else {
02977 *dst++ = *start++;
02978 }
02979
02980 break;
02981 }
02982 if (done)
02983 break;
02984 }
02985
02986
02987
02988 if (dst != NULL)
02989 *dst = '\0';
02990
02991
02992 for (i = 0; i < numTokens; i++) {
02993 token = format + i;
02994 if (token->type == PTOK_STRING)
02995 token->u.string.len = strlen(token->u.string.string);
02996 }
02997
02998 *numTokensPtr = numTokens;
02999 *formatPtr = format;
03000
03001 return 0;
03002 }
03003
03004
03005 static int parseExpression(headerSprintfArgs hsa, sprintfToken token,
03006 char * str, char ** endPtr)
03007 {
03008 char * chptr;
03009 char * end;
03010
03011 hsa->errmsg = NULL;
03012 chptr = str;
03013 while (*chptr && *chptr != '?') chptr++;
03014
03015 if (*chptr != '?') {
03016 hsa->errmsg = _("? expected in expression");
03017 return 1;
03018 }
03019
03020 *chptr++ = '\0';;
03021
03022 if (*chptr != '{') {
03023 hsa->errmsg = _("{ expected after ? in expression");
03024 return 1;
03025 }
03026
03027 chptr++;
03028
03029 if (parseFormat(hsa, chptr, &token->u.cond.ifFormat,
03030 &token->u.cond.numIfTokens, &end, PARSER_IN_EXPR))
03031 return 1;
03032
03033
03034 if (!(end && *end)) {
03035 hsa->errmsg = _("} expected in expression");
03036 token->u.cond.ifFormat =
03037 freeFormat(token->u.cond.ifFormat, token->u.cond.numIfTokens);
03038 return 1;
03039 }
03040
03041 chptr = end;
03042 if (*chptr != ':' && *chptr != '|') {
03043 hsa->errmsg = _(": expected following ? subexpression");
03044 token->u.cond.ifFormat =
03045 freeFormat(token->u.cond.ifFormat, token->u.cond.numIfTokens);
03046 return 1;
03047 }
03048
03049 if (*chptr == '|') {
03050 if (parseFormat(hsa, NULL, &token->u.cond.elseFormat,
03051 &token->u.cond.numElseTokens, &end, PARSER_IN_EXPR))
03052 {
03053 token->u.cond.ifFormat =
03054 freeFormat(token->u.cond.ifFormat, token->u.cond.numIfTokens);
03055 return 1;
03056 }
03057 } else {
03058 chptr++;
03059
03060 if (*chptr != '{') {
03061 hsa->errmsg = _("{ expected after : in expression");
03062 token->u.cond.ifFormat =
03063 freeFormat(token->u.cond.ifFormat, token->u.cond.numIfTokens);
03064 return 1;
03065 }
03066
03067 chptr++;
03068
03069 if (parseFormat(hsa, chptr, &token->u.cond.elseFormat,
03070 &token->u.cond.numElseTokens, &end, PARSER_IN_EXPR))
03071 return 1;
03072
03073
03074 if (!(end && *end)) {
03075 hsa->errmsg = _("} expected in expression");
03076 token->u.cond.ifFormat =
03077 freeFormat(token->u.cond.ifFormat, token->u.cond.numIfTokens);
03078 return 1;
03079 }
03080
03081 chptr = end;
03082 if (*chptr != '|') {
03083 hsa->errmsg = _("| expected at end of expression");
03084 token->u.cond.ifFormat =
03085 freeFormat(token->u.cond.ifFormat, token->u.cond.numIfTokens);
03086 token->u.cond.elseFormat =
03087 freeFormat(token->u.cond.elseFormat, token->u.cond.numElseTokens);
03088 return 1;
03089 }
03090 }
03091
03092 chptr++;
03093
03094 *endPtr = chptr;
03095
03096 token->type = PTOK_COND;
03097
03098 (void) findTag(hsa, token, str);
03099
03100 return 0;
03101 }
03102
03103
03114 static int getExtension(headerSprintfArgs hsa, headerTagTagFunction fn,
03115 hTYP_t typeptr,
03116 hPTR_t * data,
03117 hCNT_t countptr,
03118 rpmec ec)
03119
03120
03121
03122 {
03123 if (!ec->avail) {
03124 if (fn(hsa->h, &ec->type, &ec->data, &ec->count, &ec->freeit))
03125 return 1;
03126 ec->avail = 1;
03127 }
03128
03129 if (typeptr) *typeptr = ec->type;
03130 if (data) *data = ec->data;
03131 if (countptr) *countptr = ec->count;
03132
03133 return 0;
03134 }
03135
03143
03144 static char * formatValue(headerSprintfArgs hsa, sprintfTag tag, int element)
03145
03146 {
03147 char * val = NULL;
03148 size_t need = 0;
03149 char * t, * te;
03150 char buf[20];
03151 int_32 count, type;
03152 hPTR_t data;
03153 unsigned int intVal;
03154 uint_64 llVal;
03155 const char ** strarray;
03156 int datafree = 0;
03157 int countBuf;
03158
03159 memset(buf, 0, sizeof(buf));
03160 if (tag->ext) {
03161
03162 if (getExtension(hsa, tag->ext, &type, &data, &count, hsa->ec + tag->extNum))
03163 {
03164 count = 1;
03165 type = RPM_STRING_TYPE;
03166 data = "(none)";
03167 }
03168
03169 } else {
03170
03171 if (!headerGetEntry(hsa->h, tag->tag, &type, &data, &count)) {
03172 count = 1;
03173 type = RPM_STRING_TYPE;
03174 data = "(none)";
03175 }
03176
03177
03178
03179 switch (type) {
03180 default:
03181 if (element >= count) {
03182
03183 data = headerFreeData(data, type);
03184
03185
03186 hsa->errmsg = _("(index out of range)");
03187 return NULL;
03188 }
03189 break;
03190 case RPM_OPENPGP_TYPE:
03191 case RPM_ASN1_TYPE:
03192 case RPM_BIN_TYPE:
03193 case RPM_STRING_TYPE:
03194 break;
03195 }
03196 datafree = 1;
03197 }
03198
03199 if (tag->arrayCount) {
03200
03201 if (datafree)
03202 data = headerFreeData(data, type);
03203
03204
03205 countBuf = count;
03206 data = &countBuf;
03207 count = 1;
03208 type = RPM_INT32_TYPE;
03209 }
03210
03211
03212 (void) stpcpy( stpcpy(buf, "%"), tag->format);
03213
03214
03215
03216 if (data)
03217 switch (type) {
03218 case RPM_STRING_ARRAY_TYPE:
03219 strarray = (const char **)data;
03220
03221 if (tag->fmt)
03222 val = tag->fmt(RPM_STRING_TYPE, strarray[element], buf, tag->pad, (count > 1 ? element : -1));
03223
03224 if (val) {
03225 need = strlen(val);
03226 } else {
03227 need = strlen(strarray[element]) + tag->pad + 20;
03228 val = xmalloc(need+1);
03229 strcat(buf, "s");
03230
03231 sprintf(val, buf, strarray[element]);
03232
03233 }
03234
03235 break;
03236
03237 case RPM_STRING_TYPE:
03238 if (tag->fmt)
03239 val = tag->fmt(RPM_STRING_TYPE, data, buf, tag->pad, -1);
03240
03241 if (val) {
03242 need = strlen(val);
03243 } else {
03244 need = strlen(data) + tag->pad + 20;
03245 val = xmalloc(need+1);
03246 strcat(buf, "s");
03247
03248 sprintf(val, buf, data);
03249
03250 }
03251 break;
03252
03253 case RPM_INT64_TYPE:
03254 llVal = *(((int_64 *) data) + element);
03255 if (tag->fmt)
03256 val = tag->fmt(RPM_INT64_TYPE, &llVal, buf, tag->pad, (count > 1 ? element : -1));
03257 if (val) {
03258 need = strlen(val);
03259 } else {
03260 need = 10 + tag->pad + 40;
03261 val = xmalloc(need+1);
03262 strcat(buf, "lld");
03263
03264 sprintf(val, buf, llVal);
03265
03266 }
03267 break;
03268
03269 case RPM_CHAR_TYPE:
03270 case RPM_INT8_TYPE:
03271 case RPM_INT16_TYPE:
03272 case RPM_INT32_TYPE:
03273 switch (type) {
03274 case RPM_CHAR_TYPE:
03275 case RPM_INT8_TYPE:
03276 intVal = *(((int_8 *) data) + element);
03277 break;
03278 case RPM_INT16_TYPE:
03279 intVal = *(((uint_16 *) data) + element);
03280 break;
03281 default:
03282 case RPM_INT32_TYPE:
03283 intVal = *(((int_32 *) data) + element);
03284 break;
03285 }
03286
03287 if (tag->fmt)
03288 val = tag->fmt(RPM_INT32_TYPE, &intVal, buf, tag->pad, (count > 1 ? element : -1));
03289
03290 if (val) {
03291 need = strlen(val);
03292 } else {
03293 need = 10 + tag->pad + 20;
03294 val = xmalloc(need+1);
03295 strcat(buf, "d");
03296
03297 sprintf(val, buf, intVal);
03298
03299 }
03300 break;
03301
03302 case RPM_OPENPGP_TYPE:
03303 case RPM_ASN1_TYPE:
03304 case RPM_BIN_TYPE:
03305
03306 if (tag->fmt)
03307 val = tag->fmt(RPM_BIN_TYPE, data, buf, tag->pad, count);
03308
03309 if (val) {
03310 need = strlen(val);
03311 } else {
03312 #ifdef NOTYET
03313 val = memcpy(xmalloc(count), data, count);
03314 #else
03315
03316 static char hex[] = "0123456789abcdef";
03317 const char * s = data;
03318
03319
03320 need = 2*count + tag->pad;
03321 val = t = xmalloc(need+1);
03322 while (count-- > 0) {
03323 unsigned int i;
03324 i = *s++;
03325 *t++ = hex[ (i >> 4) & 0xf ];
03326 *t++ = hex[ (i ) & 0xf ];
03327 }
03328 *t = '\0';
03329
03330 #endif
03331 }
03332 break;
03333
03334 default:
03335 need = sizeof("(unknown type)") - 1;
03336 val = xstrdup("(unknown type)");
03337 break;
03338 }
03339
03340
03341
03342 if (datafree)
03343 data = headerFreeData(data, type);
03344
03345
03346
03347 if (val && need > 0) {
03348 t = hsaReserve(hsa, need);
03349
03350 te = stpcpy(t, val);
03351
03352 hsa->vallen += (te - t);
03353 val = _free(val);
03354 }
03355
03356
03357 return (hsa->val + hsa->vallen);
03358 }
03359
03367
03368 static char * singleSprintf(headerSprintfArgs hsa, sprintfToken token,
03369 int element)
03370
03371 {
03372 char numbuf[64];
03373 char * t, * te;
03374 int i, j;
03375 int numElements;
03376 int_32 type;
03377 int_32 count;
03378 sprintfToken spft;
03379 int condNumFormats;
03380 size_t need;
03381
03382
03383
03384 switch (token->type) {
03385 case PTOK_NONE:
03386 break;
03387
03388 case PTOK_STRING:
03389 need = token->u.string.len;
03390 if (need == 0) break;
03391 t = hsaReserve(hsa, need);
03392
03393 te = stpcpy(t, token->u.string.string);
03394
03395 hsa->vallen += (te - t);
03396 break;
03397
03398 case PTOK_TAG:
03399 t = hsa->val + hsa->vallen;
03400 te = formatValue(hsa, &token->u.tag,
03401 (token->u.tag.justOne ? 0 : element));
03402 if (te == NULL)
03403 return NULL;
03404 break;
03405
03406 case PTOK_COND:
03407 if (token->u.cond.tag.ext || headerIsEntry(hsa->h, token->u.cond.tag.tag)) {
03408 spft = token->u.cond.ifFormat;
03409 condNumFormats = token->u.cond.numIfTokens;
03410 } else {
03411 spft = token->u.cond.elseFormat;
03412 condNumFormats = token->u.cond.numElseTokens;
03413 }
03414
03415 need = condNumFormats * 20;
03416 if (spft == NULL || need == 0) break;
03417
03418 t = hsaReserve(hsa, need);
03419 for (i = 0; i < condNumFormats; i++, spft++) {
03420 te = singleSprintf(hsa, spft, element);
03421 if (te == NULL)
03422 return NULL;
03423 }
03424 break;
03425
03426 case PTOK_ARRAY:
03427 numElements = -1;
03428 spft = token->u.array.format;
03429 for (i = 0; i < token->u.array.numTokens; i++, spft++)
03430 {
03431 if (spft->type != PTOK_TAG ||
03432 spft->u.tag.arrayCount ||
03433 spft->u.tag.justOne) continue;
03434
03435 if (spft->u.tag.ext) {
03436
03437 if (getExtension(hsa, spft->u.tag.ext, &type, NULL, &count,
03438 hsa->ec + spft->u.tag.extNum))
03439 continue;
03440
03441 } else {
03442
03443 if (!headerGetEntry(hsa->h, spft->u.tag.tag, &type, NULL, &count))
03444 continue;
03445
03446 }
03447
03448 if (type == RPM_BIN_TYPE || type == RPM_ASN1_TYPE || type == RPM_OPENPGP_TYPE)
03449 count = 1;
03450
03451 if (numElements > 1 && count != numElements)
03452 switch (type) {
03453 default:
03454 hsa->errmsg =
03455 _("array iterator used with different sized arrays");
03456 return NULL;
03457 break;
03458 case RPM_OPENPGP_TYPE:
03459 case RPM_ASN1_TYPE:
03460 case RPM_BIN_TYPE:
03461 case RPM_STRING_TYPE:
03462 break;
03463 }
03464 if (count > numElements)
03465 numElements = count;
03466 }
03467
03468 if (numElements == -1) {
03469 #ifdef DYING
03470 need = sizeof("(none)\n") - 1;
03471 t = hsaReserve(hsa, need);
03472
03473 te = stpcpy(t, "(none)\n");
03474
03475 hsa->vallen += (te - t);
03476 #endif
03477 } else {
03478 int isxml;
03479 int isyaml;
03480
03481 need = numElements * token->u.array.numTokens;
03482 if (need == 0) break;
03483
03484 spft = token->u.array.format;
03485 isxml = (spft->type == PTOK_TAG && spft->u.tag.type != NULL &&
03486 !strcmp(spft->u.tag.type, "xml"));
03487 isyaml = (spft->type == PTOK_TAG && spft->u.tag.type != NULL &&
03488 !strcmp(spft->u.tag.type, "yaml"));
03489
03490 if (isxml) {
03491 const char * tagN = myTagName(hsa->tags, spft->u.tag.tag, NULL);
03492
03493 if (tagN == NULL) {
03494 (void) snprintf(numbuf, sizeof(numbuf), "Tag_0x%08x",
03495 spft->u.tag.tag);
03496 numbuf[sizeof(numbuf)-1] = '\0';
03497 tagN = numbuf;
03498 }
03499 need = sizeof(" <rpmTag name=\"\">\n") + strlen(tagN);
03500 te = t = hsaReserve(hsa, need);
03501
03502 te = stpcpy( stpcpy( stpcpy(te, " <rpmTag name=\""), tagN), "\">\n");
03503
03504 hsa->vallen += (te - t);
03505 }
03506 if (isyaml) {
03507 int tagT = -1;
03508 const char * tagN = myTagName(hsa->tags, spft->u.tag.tag, &tagT);
03509
03510 if (tagN == NULL) {
03511 (void) snprintf(numbuf, sizeof(numbuf), "Tag_0x%08x",
03512 spft->u.tag.tag);
03513 numbuf[sizeof(numbuf)-1] = '\0';
03514 tagN = numbuf;
03515 tagT = numElements > 1
03516 ? RPM_ARRAY_RETURN_TYPE : RPM_SCALAR_RETURN_TYPE;
03517 }
03518 need = sizeof(" : - ") + strlen(tagN);
03519 te = t = hsaReserve(hsa, need);
03520
03521 *te++ = ' ';
03522 *te++ = ' ';
03523 te = stpcpy(te, tagN);
03524 *te++ = ':';
03525 *te++ = (((tagT & RPM_MASK_RETURN_TYPE) == RPM_ARRAY_RETURN_TYPE)
03526 ? '\n' : ' ');
03527
03528 if (((tagT & RPM_MASK_RETURN_TYPE) == RPM_ARRAY_RETURN_TYPE)
03529 && numElements == 1) {
03530 te = stpcpy(te, " ");
03531 if (spft->u.tag.tag != 1118)
03532 te = stpcpy(te, "- ");
03533 }
03534 *te = '\0';
03535
03536 hsa->vallen += (te - t);
03537 }
03538
03539 need = numElements * token->u.array.numTokens * 10;
03540 t = hsaReserve(hsa, need);
03541 for (j = 0; j < numElements; j++) {
03542 spft = token->u.array.format;
03543 for (i = 0; i < token->u.array.numTokens; i++, spft++) {
03544 te = singleSprintf(hsa, spft, j);
03545 if (te == NULL)
03546 return NULL;
03547 }
03548 }
03549
03550 if (isxml) {
03551 need = sizeof(" </rpmTag>\n") - 1;
03552 te = t = hsaReserve(hsa, need);
03553
03554 te = stpcpy(te, " </rpmTag>\n");
03555
03556 hsa->vallen += (te - t);
03557 }
03558 if (isyaml) {
03559 #if 0
03560 need = sizeof("\n") - 1;
03561 te = t = hsaReserve(hsa, need);
03562
03563 te = stpcpy(te, "\n");
03564
03565 hsa->vallen += (te - t);
03566 #endif
03567 }
03568
03569 }
03570 break;
03571 }
03572
03573 return (hsa->val + hsa->vallen);
03574 }
03575
03581 static rpmec
03582 rpmecNew(const headerSprintfExtension exts)
03583
03584 {
03585 headerSprintfExtension ext;
03586 rpmec ec;
03587 int i = 0;
03588
03589 for (ext = exts; ext != NULL && ext->type != HEADER_EXT_LAST;
03590 ext = (ext->type == HEADER_EXT_MORE ? ext->u.more : ext+1))
03591 {
03592 i++;
03593 }
03594
03595 ec = xcalloc(i, sizeof(*ec));
03596 return ec;
03597 }
03598
03605 static rpmec
03606 rpmecFree(const headerSprintfExtension exts, rpmec ec)
03607
03608 {
03609 headerSprintfExtension ext;
03610 int i = 0;
03611
03612 for (ext = exts; ext != NULL && ext->type != HEADER_EXT_LAST;
03613 ext = (ext->type == HEADER_EXT_MORE ? ext->u.more : ext+1))
03614 {
03615
03616 if (ec[i].freeit) ec[i].data = _free(ec[i].data);
03617
03618 i++;
03619 }
03620
03621 ec = _free(ec);
03622 return NULL;
03623 }
03624
03636 static
03637 char * headerSprintf(Header h, const char * fmt,
03638 const struct headerTagTableEntry_s * tbltags,
03639 const struct headerSprintfExtension_s * extensions,
03640 errmsg_t * errmsg)
03641
03642
03643 {
03644 headerSprintfArgs hsa = memset(alloca(sizeof(*hsa)), 0, sizeof(*hsa));
03645 sprintfToken nextfmt;
03646 sprintfTag tag;
03647 char * t, * te;
03648 int isxml;
03649 int isyaml;
03650 int need;
03651
03652 hsa->h = headerLink(h);
03653 hsa->fmt = xstrdup(fmt);
03654
03655 hsa->exts = (headerSprintfExtension) extensions;
03656 hsa->tags = (headerTagTableEntry) tbltags;
03657
03658 hsa->errmsg = NULL;
03659
03660
03661 if (parseFormat(hsa, hsa->fmt, &hsa->format, &hsa->numTokens, NULL, PARSER_BEGIN))
03662 goto exit;
03663
03664
03665 hsa->ec = rpmecNew(hsa->exts);
03666 hsa->val = xstrdup("");
03667
03668 tag =
03669 (hsa->format->type == PTOK_TAG
03670 ? &hsa->format->u.tag :
03671 (hsa->format->type == PTOK_ARRAY
03672 ? &hsa->format->u.array.format->u.tag :
03673 NULL));
03674 isxml = (tag != NULL && tag->tag == -2 && tag->type != NULL && !strcmp(tag->type, "xml"));
03675 isyaml = (tag != NULL && tag->tag == -2 && tag->type != NULL && !strcmp(tag->type, "yaml"));
03676
03677 if (isxml) {
03678 need = sizeof("<rpmHeader>\n") - 1;
03679 t = hsaReserve(hsa, need);
03680
03681 te = stpcpy(t, "<rpmHeader>\n");
03682
03683 hsa->vallen += (te - t);
03684 }
03685 if (isyaml) {
03686 need = sizeof("- !!omap\n") - 1;
03687 t = hsaReserve(hsa, need);
03688
03689 te = stpcpy(t, "- !!omap\n");
03690
03691 hsa->vallen += (te - t);
03692 }
03693
03694 hsa = hsaInit(hsa);
03695 while ((nextfmt = hsaNext(hsa)) != NULL) {
03696 te = singleSprintf(hsa, nextfmt, 0);
03697 if (te == NULL) {
03698 hsa->val = _free(hsa->val);
03699 break;
03700 }
03701 }
03702 hsa = hsaFini(hsa);
03703
03704 if (isxml) {
03705 need = sizeof("</rpmHeader>\n") - 1;
03706 t = hsaReserve(hsa, need);
03707
03708 te = stpcpy(t, "</rpmHeader>\n");
03709
03710 hsa->vallen += (te - t);
03711 }
03712 if (isyaml) {
03713 need = sizeof("\n") - 1;
03714 t = hsaReserve(hsa, need);
03715
03716 te = stpcpy(t, "\n");
03717
03718 hsa->vallen += (te - t);
03719 }
03720
03721 if (hsa->val != NULL && hsa->vallen < hsa->alloced)
03722 hsa->val = xrealloc(hsa->val, hsa->vallen+1);
03723
03724 hsa->ec = rpmecFree(hsa->exts, hsa->ec);
03725 hsa->format = freeFormat(hsa->format, hsa->numTokens);
03726
03727 exit:
03728
03729 if (errmsg)
03730 *errmsg = hsa->errmsg;
03731
03732 hsa->h = headerFree(hsa->h);
03733 hsa->fmt = _free(hsa->fmt);
03734 return hsa->val;
03735 }
03736
03746 static char * octalFormat(int_32 type, hPTR_t data,
03747 char * formatPrefix, int padding, int element)
03748
03749 {
03750 char * val;
03751
03752 if (type == RPM_INT32_TYPE) {
03753 val = xmalloc(20 + padding);
03754
03755 strcat(formatPrefix, "o");
03756
03757
03758 sprintf(val, formatPrefix, *((int_32 *) data));
03759
03760 } else if (type == RPM_INT64_TYPE) {
03761 val = xmalloc(40 + padding);
03762
03763 strcat(formatPrefix, "llo");
03764
03765
03766 sprintf(val, formatPrefix, *((int_64 *) data));
03767
03768 } else
03769 val = xstrdup(_("(not a number)"));
03770
03771 return val;
03772 }
03773
03783 static char * hexFormat(int_32 type, hPTR_t data,
03784 char * formatPrefix, int padding, int element)
03785
03786 {
03787 char * val;
03788
03789 if (type == RPM_INT32_TYPE) {
03790 val = xmalloc(20 + padding);
03791
03792 strcat(formatPrefix, "x");
03793
03794
03795 sprintf(val, formatPrefix, *((int_32 *) data));
03796
03797 } else if (type == RPM_INT64_TYPE) {
03798 val = xmalloc(40 + padding);
03799
03800 strcat(formatPrefix, "llx");
03801
03802
03803 sprintf(val, formatPrefix, *((int_64 *) data));
03804
03805 } else
03806 val = xstrdup(_("(not a number)"));
03807
03808 return val;
03809 }
03810
03821 static char * realDateFormat(int_32 type, hPTR_t data,
03822 char * formatPrefix, int padding, int element,
03823 const char * strftimeFormat)
03824
03825 {
03826 char * val;
03827
03828 if (type != RPM_INT32_TYPE) {
03829 val = xstrdup(_("(not a number)"));
03830 } else {
03831 struct tm * tstruct;
03832 char buf[50];
03833
03834 val = xmalloc(50 + padding);
03835
03836 strcat(formatPrefix, "s");
03837
03838
03839
03840 { time_t dateint = *((int_32 *) data);
03841 tstruct = localtime(&dateint);
03842 }
03843 buf[0] = '\0';
03844 if (tstruct)
03845 (void) strftime(buf, sizeof(buf) - 1, strftimeFormat, tstruct);
03846
03847 sprintf(val, formatPrefix, buf);
03848
03849 }
03850
03851 return val;
03852 }
03853
03863 static char * dateFormat(int_32 type, hPTR_t data,
03864 char * formatPrefix, int padding, int element)
03865
03866 {
03867 return realDateFormat(type, data, formatPrefix, padding, element,
03868 _("%c"));
03869 }
03870
03880 static char * dayFormat(int_32 type, hPTR_t data,
03881 char * formatPrefix, int padding, int element)
03882
03883 {
03884 return realDateFormat(type, data, formatPrefix, padding, element,
03885 _("%a %b %d %Y"));
03886 }
03887
03897 static char * shescapeFormat(int_32 type, hPTR_t data,
03898 char * formatPrefix, int padding, int element)
03899
03900 {
03901 char * result, * dst, * src, * buf;
03902
03903 if (type == RPM_INT32_TYPE) {
03904 result = xmalloc(padding + 20);
03905
03906 strcat(formatPrefix, "d");
03907
03908
03909 sprintf(result, formatPrefix, *((int_32 *) data));
03910
03911 } else if (type == RPM_INT64_TYPE) {
03912 result = xmalloc(padding + 40);
03913
03914 strcat(formatPrefix, "lld");
03915
03916
03917 sprintf(result, formatPrefix, *((int_64 *) data));
03918
03919 } else {
03920 buf = alloca(strlen(data) + padding + 2);
03921
03922 strcat(formatPrefix, "s");
03923
03924
03925 sprintf(buf, formatPrefix, data);
03926
03927
03928
03929 result = dst = xmalloc(strlen(buf) * 4 + 3);
03930 *dst++ = '\'';
03931 for (src = buf; *src != '\0'; src++) {
03932 if (*src == '\'') {
03933 *dst++ = '\'';
03934 *dst++ = '\\';
03935 *dst++ = '\'';
03936 *dst++ = '\'';
03937 } else {
03938 *dst++ = *src;
03939 }
03940 }
03941 *dst++ = '\'';
03942 *dst = '\0';
03943
03944
03945 }
03946
03947 return result;
03948 }
03949
03950
03951 const struct headerSprintfExtension_s headerDefaultFormats[] = {
03952 { HEADER_EXT_FORMAT, "octal", { octalFormat } },
03953 { HEADER_EXT_FORMAT, "hex", { hexFormat } },
03954 { HEADER_EXT_FORMAT, "date", { dateFormat } },
03955 { HEADER_EXT_FORMAT, "day", { dayFormat } },
03956 { HEADER_EXT_FORMAT, "shescape", { shescapeFormat } },
03957 { HEADER_EXT_LAST, NULL, { NULL } }
03958 };
03959
03960
03967 static
03968 void headerCopyTags(Header headerFrom, Header headerTo, hTAG_t tagstocopy)
03969
03970 {
03971 int * p;
03972
03973 if (headerFrom == headerTo)
03974 return;
03975
03976 for (p = tagstocopy; *p != 0; p++) {
03977 char *s;
03978 int_32 type;
03979 int_32 count;
03980 if (headerIsEntry(headerTo, *p))
03981 continue;
03982
03983 if (!headerGetEntryMinMemory(headerFrom, *p, &type, &s, &count))
03984 continue;
03985
03986 (void) headerAddEntry(headerTo, *p, type, s, count);
03987 s = headerFreeData(s, type);
03988 }
03989 }
03990
03991
03992 static struct HV_s hdrVec1 = {
03993 headerLink,
03994 headerUnlink,
03995 headerFree,
03996 headerNew,
03997 headerSort,
03998 headerUnsort,
03999 headerSizeof,
04000 headerUnload,
04001 headerReload,
04002 headerCopy,
04003 headerLoad,
04004 headerCopyLoad,
04005 headerRead,
04006 headerWrite,
04007 headerIsEntry,
04008 headerFreeTag,
04009 headerGetEntry,
04010 headerGetEntryMinMemory,
04011 headerAddEntry,
04012 headerAppendEntry,
04013 headerAddOrAppendEntry,
04014 headerAddI18NString,
04015 headerModifyEntry,
04016 headerRemoveEntry,
04017 headerSprintf,
04018 headerCopyTags,
04019 headerFreeIterator,
04020 headerInitIterator,
04021 headerNextIterator,
04022 headerGetOrigin,
04023 headerSetOrigin,
04024 headerGetInstance,
04025 headerSetInstance,
04026 NULL, NULL,
04027 1
04028 };
04029
04030
04031
04032 HV_t hdrVec = &hdrVec1;
04033