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
01755 return ((entry->data != NULL) && *(char*)(entry->data)) ? _(entry->data) : entry->data;
01756 }
01757
01768 static int intGetEntry(Header h, int_32 tag,
01769 hTAG_t type,
01770 hPTR_t * p,
01771 hCNT_t c,
01772 int minMem)
01773
01774
01775 {
01776 indexEntry entry;
01777 int rc;
01778
01779
01780
01781 entry = findEntry(h, tag, RPM_NULL_TYPE);
01782
01783 if (entry == NULL) {
01784 if (type) type = 0;
01785 if (p) *p = NULL;
01786 if (c) *c = 0;
01787 return 0;
01788 }
01789
01790 switch (entry->info.type) {
01791 case RPM_I18NSTRING_TYPE:
01792 rc = 1;
01793 if (type) *type = RPM_STRING_TYPE;
01794 if (c) *c = 1;
01795
01796 if (p) *p = headerFindI18NString(h, entry);
01797
01798 break;
01799 default:
01800 rc = copyEntry(entry, type, p, c, minMem);
01801 break;
01802 }
01803
01804
01805 return ((rc == 1) ? 1 : 0);
01806 }
01807
01815 static void * headerFreeTag( Header h,
01816 const void * data, rpmTagType type)
01817
01818 {
01819 if (data) {
01820
01821 if (type == -1 ||
01822 type == RPM_STRING_ARRAY_TYPE ||
01823 type == RPM_I18NSTRING_TYPE ||
01824 type == RPM_BIN_TYPE ||
01825 type == RPM_ASN1_TYPE ||
01826 type == RPM_OPENPGP_TYPE)
01827 data = _free(data);
01828
01829 }
01830 return NULL;
01831 }
01832
01846 static
01847 int headerGetEntry(Header h, int_32 tag,
01848 hTYP_t type,
01849 void ** p,
01850 hCNT_t c)
01851
01852
01853 {
01854 return intGetEntry(h, tag, type, (hPTR_t *)p, c, 0);
01855 }
01856
01869 static
01870 int headerGetEntryMinMemory(Header h, int_32 tag,
01871 hTYP_t type,
01872 hPTR_t * p,
01873 hCNT_t c)
01874
01875
01876 {
01877 return intGetEntry(h, tag, type, p, c, 1);
01878 }
01879
01880 int headerGetRawEntry(Header h, int_32 tag, int_32 * type, hPTR_t * p,
01881 int_32 * c)
01882 {
01883 indexEntry entry;
01884 int rc;
01885
01886 if (p == NULL) return headerIsEntry(h, tag);
01887
01888
01889
01890 entry = findEntry(h, tag, RPM_NULL_TYPE);
01891
01892 if (!entry) {
01893 if (p) *p = NULL;
01894 if (c) *c = 0;
01895 return 0;
01896 }
01897
01898 rc = copyEntry(entry, type, p, c, 0);
01899
01900
01901 return ((rc == 1) ? 1 : 0);
01902 }
01903
01906 static void copyData(int_32 type, void * dstPtr, const void * srcPtr,
01907 int_32 cnt, int dataLength)
01908
01909 {
01910 switch (type) {
01911 case RPM_STRING_ARRAY_TYPE:
01912 case RPM_I18NSTRING_TYPE:
01913 { const char ** av = (const char **) srcPtr;
01914 char * t = dstPtr;
01915
01916
01917 while (cnt-- > 0 && dataLength > 0) {
01918 const char * s;
01919 if ((s = *av++) == NULL)
01920 continue;
01921 do {
01922 *t++ = *s++;
01923 } while (s[-1] && --dataLength > 0);
01924 }
01925
01926 } break;
01927
01928 default:
01929
01930 memmove(dstPtr, srcPtr, dataLength);
01931
01932 break;
01933 }
01934 }
01935
01944
01945 static void *
01946 grabData(int_32 type, hPTR_t p, int_32 c, int * lengthPtr)
01947
01948
01949 {
01950 void * data = NULL;
01951 int length;
01952
01953 length = dataLength(type, p, c, 0, NULL);
01954
01955 if (length > 0) {
01956 data = xmalloc(length);
01957 copyData(type, data, p, c, length);
01958 }
01959
01960
01961 if (lengthPtr)
01962 *lengthPtr = length;
01963 return data;
01964 }
01965
01980 static
01981 int headerAddEntry(Header h, int_32 tag, int_32 type, const void * p, int_32 c)
01982
01983 {
01984 indexEntry entry;
01985 void * data;
01986 int length;
01987
01988
01989 if (c <= 0)
01990 return 0;
01991
01992 if (hdrchkType(type))
01993 return 0;
01994 if (hdrchkData(c))
01995 return 0;
01996
01997 length = 0;
01998
01999 data = grabData(type, p, c, &length);
02000
02001 if (data == NULL || length <= 0)
02002 return 0;
02003
02004
02005 if (h->indexUsed == h->indexAlloced) {
02006 h->indexAlloced += INDEX_MALLOC_SIZE;
02007 h->index = xrealloc(h->index, h->indexAlloced * sizeof(*h->index));
02008 }
02009
02010
02011 entry = h->index + h->indexUsed;
02012 entry->info.tag = tag;
02013 entry->info.type = type;
02014 entry->info.count = c;
02015 entry->info.offset = 0;
02016 entry->data = data;
02017 entry->length = length;
02018
02019
02020 if (h->indexUsed > 0 && tag < h->index[h->indexUsed-1].info.tag)
02021 h->flags &= ~HEADERFLAG_SORTED;
02022
02023 h->indexUsed++;
02024
02025 return 1;
02026 }
02027
02042 static
02043 int headerAppendEntry(Header h, int_32 tag, int_32 type,
02044 const void * p, int_32 c)
02045
02046 {
02047 indexEntry entry;
02048 int length;
02049
02050 if (type == RPM_STRING_TYPE || type == RPM_I18NSTRING_TYPE) {
02051
02052 return 0;
02053 }
02054
02055
02056 entry = findEntry(h, tag, type);
02057 if (!entry)
02058 return 0;
02059
02060 length = dataLength(type, p, c, 0, NULL);
02061 if (length < 0)
02062 return 0;
02063
02064 if (ENTRY_IN_REGION(entry)) {
02065 char * t = xmalloc(entry->length + length);
02066
02067 memcpy(t, entry->data, entry->length);
02068
02069 entry->data = t;
02070 entry->info.offset = 0;
02071 } else
02072 entry->data = xrealloc(entry->data, entry->length + length);
02073
02074 copyData(type, ((char *) entry->data) + entry->length, p, c, length);
02075
02076 entry->length += length;
02077
02078 entry->info.count += c;
02079
02080 return 1;
02081 }
02082
02092 static
02093 int headerAddOrAppendEntry(Header h, int_32 tag, int_32 type,
02094 const void * p, int_32 c)
02095
02096 {
02097 return (findEntry(h, tag, type)
02098 ? headerAppendEntry(h, tag, type, p, c)
02099 : headerAddEntry(h, tag, type, p, c));
02100 }
02101
02122 static
02123 int headerAddI18NString(Header h, int_32 tag, const char * string,
02124 const char * lang)
02125
02126 {
02127 indexEntry table, entry;
02128 const char ** strArray;
02129 int length;
02130 int ghosts;
02131 int i, langNum;
02132 char * buf;
02133
02134 table = findEntry(h, HEADER_I18NTABLE, RPM_STRING_ARRAY_TYPE);
02135 entry = findEntry(h, tag, RPM_I18NSTRING_TYPE);
02136
02137 if (!table && entry)
02138 return 0;
02139
02140 if (!table && !entry) {
02141 const char * charArray[2];
02142 int count = 0;
02143 if (!lang || (lang[0] == 'C' && lang[1] == '\0')) {
02144
02145 charArray[count++] = "C";
02146
02147 } else {
02148
02149 charArray[count++] = "C";
02150
02151 charArray[count++] = lang;
02152 }
02153 if (!headerAddEntry(h, HEADER_I18NTABLE, RPM_STRING_ARRAY_TYPE,
02154 &charArray, count))
02155 return 0;
02156 table = findEntry(h, HEADER_I18NTABLE, RPM_STRING_ARRAY_TYPE);
02157 }
02158
02159 if (!table)
02160 return 0;
02161
02162 if (!lang) lang = "C";
02163
02164
02165 { const char * l = table->data;
02166 for (langNum = 0; langNum < table->info.count; langNum++) {
02167 if (!strcmp(l, lang)) break;
02168 l += strlen(l) + 1;
02169 }
02170 }
02171
02172 if (langNum >= table->info.count) {
02173 length = strlen(lang) + 1;
02174 if (ENTRY_IN_REGION(table)) {
02175 char * t = xmalloc(table->length + length);
02176 memcpy(t, table->data, table->length);
02177 table->data = t;
02178 table->info.offset = 0;
02179 } else
02180 table->data = xrealloc(table->data, table->length + length);
02181 memmove(((char *)table->data) + table->length, lang, length);
02182 table->length += length;
02183 table->info.count++;
02184 }
02185
02186 if (!entry) {
02187 strArray = alloca(sizeof(*strArray) * (langNum + 1));
02188 for (i = 0; i < langNum; i++)
02189 strArray[i] = "";
02190 strArray[langNum] = string;
02191 return headerAddEntry(h, tag, RPM_I18NSTRING_TYPE, strArray,
02192 langNum + 1);
02193 } else if (langNum >= entry->info.count) {
02194 ghosts = langNum - entry->info.count;
02195
02196 length = strlen(string) + 1 + ghosts;
02197 if (ENTRY_IN_REGION(entry)) {
02198 char * t = xmalloc(entry->length + length);
02199 memcpy(t, entry->data, entry->length);
02200 entry->data = t;
02201 entry->info.offset = 0;
02202 } else
02203 entry->data = xrealloc(entry->data, entry->length + length);
02204
02205 memset(((char *)entry->data) + entry->length, '\0', ghosts);
02206 memmove(((char *)entry->data) + entry->length + ghosts, string, strlen(string)+1);
02207
02208 entry->length += length;
02209 entry->info.count = langNum + 1;
02210 } else {
02211 char *b, *be, *e, *ee, *t;
02212 size_t bn, sn, en;
02213
02214
02215 b = be = e = ee = entry->data;
02216 for (i = 0; i < table->info.count; i++) {
02217 if (i == langNum)
02218 be = ee;
02219 ee += strlen(ee) + 1;
02220 if (i == langNum)
02221 e = ee;
02222 }
02223
02224
02225 bn = (be-b);
02226 sn = strlen(string) + 1;
02227 en = (ee-e);
02228 length = bn + sn + en;
02229 t = buf = xmalloc(length);
02230
02231
02232 memcpy(t, b, bn);
02233 t += bn;
02234
02235 memcpy(t, string, sn);
02236 t += sn;
02237 memcpy(t, e, en);
02238 t += en;
02239
02240
02241
02242 entry->length -= strlen(be) + 1;
02243 entry->length += sn;
02244
02245 if (ENTRY_IN_REGION(entry)) {
02246 entry->info.offset = 0;
02247 } else
02248 entry->data = _free(entry->data);
02249
02250 entry->data = buf;
02251
02252 }
02253
02254 return 0;
02255 }
02256
02267 static
02268 int headerModifyEntry(Header h, int_32 tag, int_32 type,
02269 const void * p, int_32 c)
02270
02271 {
02272 indexEntry entry;
02273 void * oldData;
02274 void * data;
02275 int length;
02276
02277
02278 entry = findEntry(h, tag, type);
02279 if (!entry)
02280 return 0;
02281
02282 length = 0;
02283 data = grabData(type, p, c, &length);
02284 if (data == NULL || length <= 0)
02285 return 0;
02286
02287
02288 while (entry > h->index && (entry - 1)->info.tag == tag)
02289 entry--;
02290
02291
02292
02293 oldData = entry->data;
02294
02295 entry->info.count = c;
02296 entry->info.type = type;
02297 entry->data = data;
02298 entry->length = length;
02299
02300
02301 if (ENTRY_IN_REGION(entry)) {
02302 entry->info.offset = 0;
02303 } else
02304 oldData = _free(oldData);
02305
02306
02307 return 1;
02308 }
02309
02312 static char escapedChar(const char ch)
02313 {
02314 switch (ch) {
02315 case 'a': return '\a';
02316 case 'b': return '\b';
02317 case 'f': return '\f';
02318 case 'n': return '\n';
02319 case 'r': return '\r';
02320 case 't': return '\t';
02321 case 'v': return '\v';
02322 default: return ch;
02323 }
02324 }
02325
02332 static sprintfToken
02333 freeFormat( sprintfToken format, int num)
02334
02335 {
02336 int i;
02337
02338 if (format == NULL) return NULL;
02339
02340 for (i = 0; i < num; i++) {
02341 switch (format[i].type) {
02342 case PTOK_ARRAY:
02343
02344 format[i].u.array.format =
02345 freeFormat(format[i].u.array.format,
02346 format[i].u.array.numTokens);
02347
02348 break;
02349 case PTOK_COND:
02350
02351 format[i].u.cond.ifFormat =
02352 freeFormat(format[i].u.cond.ifFormat,
02353 format[i].u.cond.numIfTokens);
02354 format[i].u.cond.elseFormat =
02355 freeFormat(format[i].u.cond.elseFormat,
02356 format[i].u.cond.numElseTokens);
02357
02358 break;
02359 case PTOK_NONE:
02360 case PTOK_TAG:
02361 case PTOK_STRING:
02362 default:
02363 break;
02364 }
02365 }
02366 format = _free(format);
02367 return NULL;
02368 }
02369
02373 struct headerIterator_s {
02374
02375 Header h;
02376
02377 int next_index;
02378 };
02379
02385 static
02386 HeaderIterator headerFreeIterator( HeaderIterator hi)
02387
02388 {
02389 if (hi != NULL) {
02390 hi->h = headerFree(hi->h);
02391 hi = _free(hi);
02392 }
02393 return hi;
02394 }
02395
02401 static
02402 HeaderIterator headerInitIterator(Header h)
02403
02404 {
02405 HeaderIterator hi = xmalloc(sizeof(*hi));
02406
02407 headerSort(h);
02408
02409 hi->h = headerLink(h);
02410 hi->next_index = 0;
02411 return hi;
02412 }
02413
02423 static
02424 int headerNextIterator(HeaderIterator hi,
02425 hTAG_t tag,
02426 hTYP_t type,
02427 hPTR_t * p,
02428 hCNT_t c)
02429
02430
02431
02432 {
02433 Header h = hi->h;
02434 int slot = hi->next_index;
02435 indexEntry entry = NULL;
02436 int rc;
02437
02438 for (slot = hi->next_index; slot < h->indexUsed; slot++) {
02439 entry = h->index + slot;
02440 if (!ENTRY_IS_REGION(entry))
02441 break;
02442 }
02443 hi->next_index = slot;
02444 if (entry == NULL || slot >= h->indexUsed)
02445 return 0;
02446
02447
02448 hi->next_index++;
02449
02450
02451 if (tag)
02452 *tag = entry->info.tag;
02453
02454 rc = copyEntry(entry, type, p, c, 0);
02455
02456
02457 return ((rc == 1) ? 1 : 0);
02458 }
02459
02465 static
02466 Header headerCopy(Header h)
02467
02468 {
02469 Header nh = headerNew();
02470 HeaderIterator hi;
02471 int_32 tag, type, count;
02472 hPTR_t ptr;
02473
02474
02475 for (hi = headerInitIterator(h);
02476 headerNextIterator(hi, &tag, &type, &ptr, &count);
02477 ptr = headerFreeData((void *)ptr, type))
02478 {
02479 if (ptr) (void) headerAddEntry(nh, tag, type, ptr, count);
02480 }
02481 hi = headerFreeIterator(hi);
02482
02483
02484 return headerReload(nh, HEADER_IMAGE);
02485 }
02486
02489 typedef struct headerSprintfArgs_s {
02490 Header h;
02491 char * fmt;
02492
02493 headerTagTableEntry tags;
02494
02495 headerSprintfExtension exts;
02496
02497 const char * errmsg;
02498 rpmec ec;
02499 sprintfToken format;
02500
02501 HeaderIterator hi;
02502
02503 char * val;
02504 size_t vallen;
02505 size_t alloced;
02506 int numTokens;
02507 int i;
02508 } * headerSprintfArgs;
02509
02515 static headerSprintfArgs hsaInit( headerSprintfArgs hsa)
02516
02517 {
02518 sprintfTag tag =
02519 (hsa->format->type == PTOK_TAG
02520 ? &hsa->format->u.tag :
02521 (hsa->format->type == PTOK_ARRAY
02522 ? &hsa->format->u.array.format->u.tag :
02523 NULL));
02524
02525 if (hsa != NULL) {
02526 hsa->i = 0;
02527 if (tag != NULL && tag->tag == -2)
02528 hsa->hi = headerInitIterator(hsa->h);
02529 }
02530
02531 return hsa;
02532
02533 }
02534
02540
02541 static sprintfToken hsaNext( headerSprintfArgs hsa)
02542
02543 {
02544 sprintfToken fmt = NULL;
02545 sprintfTag tag =
02546 (hsa->format->type == PTOK_TAG
02547 ? &hsa->format->u.tag :
02548 (hsa->format->type == PTOK_ARRAY
02549 ? &hsa->format->u.array.format->u.tag :
02550 NULL));
02551
02552 if (hsa != NULL && hsa->i >= 0 && hsa->i < hsa->numTokens) {
02553 fmt = hsa->format + hsa->i;
02554 if (hsa->hi == NULL) {
02555 hsa->i++;
02556 } else {
02557 int_32 tagno;
02558 int_32 type;
02559 int_32 count;
02560
02561
02562 if (!headerNextIterator(hsa->hi, &tagno, &type, NULL, &count))
02563 fmt = NULL;
02564 tag->tag = tagno;
02565
02566 }
02567 }
02568
02569
02570 return fmt;
02571
02572 }
02573
02579 static headerSprintfArgs hsaFini( headerSprintfArgs hsa)
02580
02581 {
02582 if (hsa != NULL) {
02583 hsa->hi = headerFreeIterator(hsa->hi);
02584 hsa->i = 0;
02585 }
02586
02587 return hsa;
02588
02589 }
02590
02597
02598 static char * hsaReserve(headerSprintfArgs hsa, size_t need)
02599
02600 {
02601 if ((hsa->vallen + need) >= hsa->alloced) {
02602 if (hsa->alloced <= need)
02603 hsa->alloced += need;
02604 hsa->alloced <<= 1;
02605 hsa->val = xrealloc(hsa->val, hsa->alloced+1);
02606 }
02607 return hsa->val + hsa->vallen;
02608 }
02609
02618
02619 static const char * myTagName(headerTagTableEntry tbl, int val,
02620 int *typep)
02621
02622 {
02623 static char name[128];
02624 const char * s;
02625 char *t;
02626
02627 for (; tbl->name != NULL; tbl++) {
02628 if (tbl->val == val)
02629 break;
02630 }
02631 if ((s = tbl->name) == NULL)
02632 return NULL;
02633 s += sizeof("RPMTAG_") - 1;
02634 t = name;
02635 *t++ = *s++;
02636 while (*s != '\0')
02637 *t++ = xtolower(*s++);
02638 *t = '\0';
02639 if (typep)
02640 *typep = tbl->type;
02641 return name;
02642 }
02643
02651 static int myTagValue(headerTagTableEntry tbl, const char * name)
02652
02653 {
02654 for (; tbl->name != NULL; tbl++) {
02655 if (!xstrcasecmp(tbl->name, name))
02656 return tbl->val;
02657 }
02658 return 0;
02659 }
02660
02668 static int findTag(headerSprintfArgs hsa, sprintfToken token, const char * name)
02669
02670 {
02671 headerSprintfExtension ext;
02672 sprintfTag stag = (token->type == PTOK_COND
02673 ? &token->u.cond.tag : &token->u.tag);
02674
02675 stag->fmt = NULL;
02676 stag->ext = NULL;
02677 stag->extNum = 0;
02678 stag->tag = -1;
02679
02680 if (!strcmp(name, "*")) {
02681 stag->tag = -2;
02682 goto bingo;
02683 }
02684
02685
02686 if (strncmp("RPMTAG_", name, sizeof("RPMTAG_")-1)) {
02687
02688 char * t = alloca(strlen(name) + sizeof("RPMTAG_"));
02689 (void) stpcpy( stpcpy(t, "RPMTAG_"), name);
02690 name = t;
02691
02692 }
02693
02694
02695
02696 for (ext = hsa->exts; ext != NULL && ext->type != HEADER_EXT_LAST;
02697 ext = (ext->type == HEADER_EXT_MORE ? ext->u.more : ext+1))
02698 {
02699 if (ext->name == NULL || ext->type != HEADER_EXT_TAG)
02700 continue;
02701 if (!xstrcasecmp(ext->name, name)) {
02702 stag->ext = ext->u.tagFunction;
02703 stag->extNum = ext - hsa->exts;
02704 goto bingo;
02705 }
02706 }
02707
02708
02709 stag->tag = myTagValue(hsa->tags, name);
02710 if (stag->tag != 0)
02711 goto bingo;
02712
02713 return 1;
02714
02715 bingo:
02716
02717 if (stag->type != NULL)
02718 for (ext = hsa->exts; ext != NULL && ext->type != HEADER_EXT_LAST;
02719 ext = (ext->type == HEADER_EXT_MORE ? ext->u.more : ext+1))
02720 {
02721 if (ext->name == NULL || ext->type != HEADER_EXT_FORMAT)
02722 continue;
02723 if (!strcmp(ext->name, stag->type)) {
02724 stag->fmt = ext->u.formatFunction;
02725 break;
02726 }
02727 }
02728 return 0;
02729 }
02730
02731
02740 static int parseExpression(headerSprintfArgs hsa, sprintfToken token,
02741 char * str, char ** endPtr)
02742
02743 ;
02744
02755 static int parseFormat(headerSprintfArgs hsa, char * str,
02756 sprintfToken * formatPtr, int * numTokensPtr,
02757 char ** endPtr, int state)
02758
02759
02760
02761 {
02762 char * chptr, * start, * next, * dst;
02763 sprintfToken format;
02764 sprintfToken token;
02765 int numTokens;
02766 int i;
02767 int done = 0;
02768
02769
02770 numTokens = 0;
02771 if (str != NULL)
02772 for (chptr = str; *chptr != '\0'; chptr++)
02773 if (*chptr == '%') numTokens++;
02774 numTokens = numTokens * 2 + 1;
02775
02776 format = xcalloc(numTokens, sizeof(*format));
02777 if (endPtr) *endPtr = NULL;
02778
02779
02780 dst = start = str;
02781 numTokens = 0;
02782 token = NULL;
02783 if (start != NULL)
02784 while (*start != '\0') {
02785 switch (*start) {
02786 case '%':
02787
02788 if (*(start + 1) == '%') {
02789 if (token == NULL || token->type != PTOK_STRING) {
02790 token = format + numTokens++;
02791 token->type = PTOK_STRING;
02792
02793 dst = token->u.string.string = start;
02794
02795 }
02796 start++;
02797
02798 *dst++ = *start++;
02799
02800 break;
02801 }
02802
02803 token = format + numTokens++;
02804
02805 *dst++ = '\0';
02806
02807 start++;
02808
02809 if (*start == '|') {
02810 char * newEnd;
02811
02812 start++;
02813
02814 if (parseExpression(hsa, token, start, &newEnd))
02815 {
02816 format = freeFormat(format, numTokens);
02817 return 1;
02818 }
02819
02820 start = newEnd;
02821 break;
02822 }
02823
02824
02825 token->u.tag.format = start;
02826
02827 token->u.tag.pad = 0;
02828 token->u.tag.justOne = 0;
02829 token->u.tag.arrayCount = 0;
02830
02831 chptr = start;
02832 while (*chptr && *chptr != '{' && *chptr != '%') chptr++;
02833 if (!*chptr || *chptr == '%') {
02834 hsa->errmsg = _("missing { after %");
02835 format = freeFormat(format, numTokens);
02836 return 1;
02837 }
02838
02839
02840 *chptr++ = '\0';
02841
02842
02843 while (start < chptr) {
02844 if (xisdigit(*start)) {
02845 i = strtoul(start, &start, 10);
02846 token->u.tag.pad += i;
02847 } else {
02848 start++;
02849 }
02850 }
02851
02852 if (*start == '=') {
02853 token->u.tag.justOne = 1;
02854 start++;
02855 } else if (*start == '#') {
02856 token->u.tag.justOne = 1;
02857 token->u.tag.arrayCount = 1;
02858 start++;
02859 }
02860
02861 next = start;
02862 while (*next && *next != '}') next++;
02863 if (!*next) {
02864 hsa->errmsg = _("missing } after %{");
02865 format = freeFormat(format, numTokens);
02866 return 1;
02867 }
02868
02869 *next++ = '\0';
02870
02871
02872 chptr = start;
02873 while (*chptr && *chptr != ':') chptr++;
02874
02875 if (*chptr != '\0') {
02876
02877 *chptr++ = '\0';
02878
02879 if (!*chptr) {
02880 hsa->errmsg = _("empty tag format");
02881 format = freeFormat(format, numTokens);
02882 return 1;
02883 }
02884
02885 token->u.tag.type = chptr;
02886
02887 } else {
02888 token->u.tag.type = NULL;
02889 }
02890
02891 if (!*start) {
02892 hsa->errmsg = _("empty tag name");
02893 format = freeFormat(format, numTokens);
02894 return 1;
02895 }
02896
02897 i = 0;
02898 token->type = PTOK_TAG;
02899
02900 if (findTag(hsa, token, start)) {
02901 hsa->errmsg = _("unknown tag");
02902 format = freeFormat(format, numTokens);
02903 return 1;
02904 }
02905
02906 start = next;
02907 break;
02908
02909 case '[':
02910
02911 *dst++ = '\0';
02912 *start++ = '\0';
02913
02914 token = format + numTokens++;
02915
02916
02917 if (parseFormat(hsa, start,
02918 &token->u.array.format,
02919 &token->u.array.numTokens,
02920 &start, PARSER_IN_ARRAY))
02921 {
02922 format = freeFormat(format, numTokens);
02923 return 1;
02924 }
02925
02926
02927 if (!start) {
02928 hsa->errmsg = _("] expected at end of array");
02929 format = freeFormat(format, numTokens);
02930 return 1;
02931 }
02932
02933 dst = start;
02934
02935 token->type = PTOK_ARRAY;
02936
02937 break;
02938
02939 case ']':
02940 if (state != PARSER_IN_ARRAY) {
02941 hsa->errmsg = _("unexpected ]");
02942 format = freeFormat(format, numTokens);
02943 return 1;
02944 }
02945
02946 *start++ = '\0';
02947
02948 if (endPtr) *endPtr = start;
02949 done = 1;
02950 break;
02951
02952 case '}':
02953 if (state != PARSER_IN_EXPR) {
02954 hsa->errmsg = _("unexpected }");
02955 format = freeFormat(format, numTokens);
02956 return 1;
02957 }
02958
02959 *start++ = '\0';
02960
02961 if (endPtr) *endPtr = start;
02962 done = 1;
02963 break;
02964
02965 default:
02966 if (token == NULL || token->type != PTOK_STRING) {
02967 token = format + numTokens++;
02968 token->type = PTOK_STRING;
02969
02970 dst = token->u.string.string = start;
02971
02972 }
02973
02974
02975 if (*start == '\\') {
02976 start++;
02977 *dst++ = escapedChar(*start++);
02978 } else {
02979 *dst++ = *start++;
02980 }
02981
02982 break;
02983 }
02984 if (done)
02985 break;
02986 }
02987
02988
02989
02990 if (dst != NULL)
02991 *dst = '\0';
02992
02993
02994 for (i = 0; i < numTokens; i++) {
02995 token = format + i;
02996 if (token->type == PTOK_STRING)
02997 token->u.string.len = strlen(token->u.string.string);
02998 }
02999
03000 *numTokensPtr = numTokens;
03001 *formatPtr = format;
03002
03003 return 0;
03004 }
03005
03006
03007 static int parseExpression(headerSprintfArgs hsa, sprintfToken token,
03008 char * str, char ** endPtr)
03009 {
03010 char * chptr;
03011 char * end;
03012
03013 hsa->errmsg = NULL;
03014 chptr = str;
03015 while (*chptr && *chptr != '?') chptr++;
03016
03017 if (*chptr != '?') {
03018 hsa->errmsg = _("? expected in expression");
03019 return 1;
03020 }
03021
03022 *chptr++ = '\0';;
03023
03024 if (*chptr != '{') {
03025 hsa->errmsg = _("{ expected after ? in expression");
03026 return 1;
03027 }
03028
03029 chptr++;
03030
03031 if (parseFormat(hsa, chptr, &token->u.cond.ifFormat,
03032 &token->u.cond.numIfTokens, &end, PARSER_IN_EXPR))
03033 return 1;
03034
03035
03036 if (!(end && *end)) {
03037 hsa->errmsg = _("} expected in expression");
03038 token->u.cond.ifFormat =
03039 freeFormat(token->u.cond.ifFormat, token->u.cond.numIfTokens);
03040 return 1;
03041 }
03042
03043 chptr = end;
03044 if (*chptr != ':' && *chptr != '|') {
03045 hsa->errmsg = _(": expected following ? subexpression");
03046 token->u.cond.ifFormat =
03047 freeFormat(token->u.cond.ifFormat, token->u.cond.numIfTokens);
03048 return 1;
03049 }
03050
03051 if (*chptr == '|') {
03052 if (parseFormat(hsa, NULL, &token->u.cond.elseFormat,
03053 &token->u.cond.numElseTokens, &end, PARSER_IN_EXPR))
03054 {
03055 token->u.cond.ifFormat =
03056 freeFormat(token->u.cond.ifFormat, token->u.cond.numIfTokens);
03057 return 1;
03058 }
03059 } else {
03060 chptr++;
03061
03062 if (*chptr != '{') {
03063 hsa->errmsg = _("{ expected after : in expression");
03064 token->u.cond.ifFormat =
03065 freeFormat(token->u.cond.ifFormat, token->u.cond.numIfTokens);
03066 return 1;
03067 }
03068
03069 chptr++;
03070
03071 if (parseFormat(hsa, chptr, &token->u.cond.elseFormat,
03072 &token->u.cond.numElseTokens, &end, PARSER_IN_EXPR))
03073 return 1;
03074
03075
03076 if (!(end && *end)) {
03077 hsa->errmsg = _("} expected in expression");
03078 token->u.cond.ifFormat =
03079 freeFormat(token->u.cond.ifFormat, token->u.cond.numIfTokens);
03080 return 1;
03081 }
03082
03083 chptr = end;
03084 if (*chptr != '|') {
03085 hsa->errmsg = _("| expected at end of expression");
03086 token->u.cond.ifFormat =
03087 freeFormat(token->u.cond.ifFormat, token->u.cond.numIfTokens);
03088 token->u.cond.elseFormat =
03089 freeFormat(token->u.cond.elseFormat, token->u.cond.numElseTokens);
03090 return 1;
03091 }
03092 }
03093
03094 chptr++;
03095
03096 *endPtr = chptr;
03097
03098 token->type = PTOK_COND;
03099
03100 (void) findTag(hsa, token, str);
03101
03102 return 0;
03103 }
03104
03105
03116 static int getExtension(headerSprintfArgs hsa, headerTagTagFunction fn,
03117 hTYP_t typeptr,
03118 hPTR_t * data,
03119 hCNT_t countptr,
03120 rpmec ec)
03121
03122
03123
03124 {
03125 if (!ec->avail) {
03126 if (fn(hsa->h, &ec->type, &ec->data, &ec->count, &ec->freeit))
03127 return 1;
03128 ec->avail = 1;
03129 }
03130
03131 if (typeptr) *typeptr = ec->type;
03132 if (data) *data = ec->data;
03133 if (countptr) *countptr = ec->count;
03134
03135 return 0;
03136 }
03137
03145
03146 static char * formatValue(headerSprintfArgs hsa, sprintfTag tag, int element)
03147
03148 {
03149 char * val = NULL;
03150 size_t need = 0;
03151 char * t, * te;
03152 char buf[20];
03153 int_32 count, type;
03154 hPTR_t data;
03155 unsigned int intVal;
03156 uint_64 llVal;
03157 const char ** strarray;
03158 int datafree = 0;
03159 int countBuf;
03160
03161 memset(buf, 0, sizeof(buf));
03162 if (tag->ext) {
03163
03164 if (getExtension(hsa, tag->ext, &type, &data, &count, hsa->ec + tag->extNum))
03165 {
03166 count = 1;
03167 type = RPM_STRING_TYPE;
03168 data = "(none)";
03169 }
03170
03171 } else {
03172
03173 if (!headerGetEntry(hsa->h, tag->tag, &type, (void **)&data, &count)) {
03174 count = 1;
03175 type = RPM_STRING_TYPE;
03176 data = "(none)";
03177 }
03178
03179
03180
03181 switch (type) {
03182 default:
03183 if (element >= count) {
03184
03185 data = headerFreeData(data, type);
03186
03187
03188 hsa->errmsg = _("(index out of range)");
03189 return NULL;
03190 }
03191 break;
03192 case RPM_OPENPGP_TYPE:
03193 case RPM_ASN1_TYPE:
03194 case RPM_BIN_TYPE:
03195 case RPM_STRING_TYPE:
03196 break;
03197 }
03198 datafree = 1;
03199 }
03200
03201 if (tag->arrayCount) {
03202
03203 if (datafree)
03204 data = headerFreeData(data, type);
03205
03206
03207 countBuf = count;
03208 data = &countBuf;
03209 count = 1;
03210 type = RPM_INT32_TYPE;
03211 }
03212
03213
03214 (void) stpcpy( stpcpy(buf, "%"), tag->format);
03215
03216
03217
03218 if (data)
03219 switch (type) {
03220 case RPM_STRING_ARRAY_TYPE:
03221 strarray = (const char **)data;
03222
03223 if (tag->fmt)
03224 val = tag->fmt(RPM_STRING_TYPE, strarray[element], buf, tag->pad, (count > 1 ? element : -1));
03225
03226 if (val) {
03227 need = strlen(val);
03228 } else {
03229 need = strlen(strarray[element]) + tag->pad + 20;
03230 val = xmalloc(need+1);
03231 strcat(buf, "s");
03232
03233 sprintf(val, buf, strarray[element]);
03234
03235 }
03236
03237 break;
03238
03239 case RPM_STRING_TYPE:
03240 if (tag->fmt)
03241 val = tag->fmt(RPM_STRING_TYPE, data, buf, tag->pad, -1);
03242
03243 if (val) {
03244 need = strlen(val);
03245 } else {
03246 need = strlen(data) + tag->pad + 20;
03247 val = xmalloc(need+1);
03248 strcat(buf, "s");
03249
03250 sprintf(val, buf, data);
03251
03252 }
03253 break;
03254
03255 case RPM_INT64_TYPE:
03256 llVal = *(((int_64 *) data) + element);
03257 if (tag->fmt)
03258 val = tag->fmt(RPM_INT64_TYPE, &llVal, buf, tag->pad, (count > 1 ? element : -1));
03259 if (val) {
03260 need = strlen(val);
03261 } else {
03262 need = 10 + tag->pad + 40;
03263 val = xmalloc(need+1);
03264 strcat(buf, "lld");
03265
03266 sprintf(val, buf, llVal);
03267
03268 }
03269 break;
03270
03271 case RPM_CHAR_TYPE:
03272 case RPM_INT8_TYPE:
03273 case RPM_INT16_TYPE:
03274 case RPM_INT32_TYPE:
03275 switch (type) {
03276 case RPM_CHAR_TYPE:
03277 case RPM_INT8_TYPE:
03278 intVal = *(((int_8 *) data) + element);
03279 break;
03280 case RPM_INT16_TYPE:
03281 intVal = *(((uint_16 *) data) + element);
03282 break;
03283 default:
03284 case RPM_INT32_TYPE:
03285 intVal = *(((int_32 *) data) + element);
03286 break;
03287 }
03288
03289 if (tag->fmt)
03290 val = tag->fmt(RPM_INT32_TYPE, &intVal, buf, tag->pad, (count > 1 ? element : -1));
03291
03292 if (val) {
03293 need = strlen(val);
03294 } else {
03295 need = 10 + tag->pad + 20;
03296 val = xmalloc(need+1);
03297 strcat(buf, "d");
03298
03299 sprintf(val, buf, intVal);
03300
03301 }
03302 break;
03303
03304 case RPM_OPENPGP_TYPE:
03305 case RPM_ASN1_TYPE:
03306 case RPM_BIN_TYPE:
03307
03308 if (tag->fmt)
03309 val = tag->fmt(RPM_BIN_TYPE, data, buf, tag->pad, count);
03310
03311 if (val) {
03312 need = strlen(val);
03313 } else {
03314 #ifdef NOTYET
03315 val = memcpy(xmalloc(count), data, count);
03316 #else
03317
03318 static char hex[] = "0123456789abcdef";
03319 const char * s = data;
03320
03321
03322 need = 2*count + tag->pad;
03323 val = t = xmalloc(need+1);
03324 while (count-- > 0) {
03325 unsigned int i;
03326 i = *s++;
03327 *t++ = hex[ (i >> 4) & 0xf ];
03328 *t++ = hex[ (i ) & 0xf ];
03329 }
03330 *t = '\0';
03331
03332 #endif
03333 }
03334 break;
03335
03336 default:
03337 need = sizeof("(unknown type)") - 1;
03338 val = xstrdup("(unknown type)");
03339 break;
03340 }
03341
03342
03343
03344 if (datafree)
03345 data = headerFreeData(data, type);
03346
03347
03348
03349 if (val && need > 0) {
03350 t = hsaReserve(hsa, need);
03351
03352 te = stpcpy(t, val);
03353
03354 hsa->vallen += (te - t);
03355 val = _free(val);
03356 }
03357
03358
03359 return (hsa->val + hsa->vallen);
03360 }
03361
03369
03370 static char * singleSprintf(headerSprintfArgs hsa, sprintfToken token,
03371 int element)
03372
03373 {
03374 char numbuf[64];
03375 char * t, * te;
03376 int i, j;
03377 int numElements;
03378 int_32 type;
03379 int_32 count;
03380 sprintfToken spft;
03381 int condNumFormats;
03382 size_t need;
03383
03384
03385
03386 switch (token->type) {
03387 case PTOK_NONE:
03388 break;
03389
03390 case PTOK_STRING:
03391 need = token->u.string.len;
03392 if (need == 0) break;
03393 t = hsaReserve(hsa, need);
03394
03395 te = stpcpy(t, token->u.string.string);
03396
03397 hsa->vallen += (te - t);
03398 break;
03399
03400 case PTOK_TAG:
03401 t = hsa->val + hsa->vallen;
03402 te = formatValue(hsa, &token->u.tag,
03403 (token->u.tag.justOne ? 0 : element));
03404 if (te == NULL)
03405 return NULL;
03406 break;
03407
03408 case PTOK_COND:
03409 if (token->u.cond.tag.ext || headerIsEntry(hsa->h, token->u.cond.tag.tag)) {
03410 spft = token->u.cond.ifFormat;
03411 condNumFormats = token->u.cond.numIfTokens;
03412 } else {
03413 spft = token->u.cond.elseFormat;
03414 condNumFormats = token->u.cond.numElseTokens;
03415 }
03416
03417 need = condNumFormats * 20;
03418 if (spft == NULL || need == 0) break;
03419
03420 t = hsaReserve(hsa, need);
03421 for (i = 0; i < condNumFormats; i++, spft++) {
03422 te = singleSprintf(hsa, spft, element);
03423 if (te == NULL)
03424 return NULL;
03425 }
03426 break;
03427
03428 case PTOK_ARRAY:
03429 numElements = -1;
03430 spft = token->u.array.format;
03431 for (i = 0; i < token->u.array.numTokens; i++, spft++)
03432 {
03433 if (spft->type != PTOK_TAG ||
03434 spft->u.tag.arrayCount ||
03435 spft->u.tag.justOne) continue;
03436
03437 if (spft->u.tag.ext) {
03438
03439 if (getExtension(hsa, spft->u.tag.ext, &type, NULL, &count,
03440 hsa->ec + spft->u.tag.extNum))
03441 continue;
03442
03443 } else {
03444
03445 if (!headerGetEntry(hsa->h, spft->u.tag.tag, &type, NULL, &count))
03446 continue;
03447
03448 }
03449
03450 if (type == RPM_BIN_TYPE || type == RPM_ASN1_TYPE || type == RPM_OPENPGP_TYPE)
03451 count = 1;
03452
03453 if (numElements > 1 && count != numElements)
03454 switch (type) {
03455 default:
03456 hsa->errmsg =
03457 _("array iterator used with different sized arrays");
03458 return NULL;
03459 break;
03460 case RPM_OPENPGP_TYPE:
03461 case RPM_ASN1_TYPE:
03462 case RPM_BIN_TYPE:
03463 case RPM_STRING_TYPE:
03464 break;
03465 }
03466 if (count > numElements)
03467 numElements = count;
03468 }
03469
03470 if (numElements == -1) {
03471 #ifdef DYING
03472 need = sizeof("(none)\n") - 1;
03473 t = hsaReserve(hsa, need);
03474
03475 te = stpcpy(t, "(none)\n");
03476
03477 hsa->vallen += (te - t);
03478 #endif
03479 } else {
03480 int isxml;
03481 int isyaml;
03482
03483 need = numElements * token->u.array.numTokens;
03484 if (need == 0) break;
03485
03486 spft = token->u.array.format;
03487 isxml = (spft->type == PTOK_TAG && spft->u.tag.type != NULL &&
03488 !strcmp(spft->u.tag.type, "xml"));
03489 isyaml = (spft->type == PTOK_TAG && spft->u.tag.type != NULL &&
03490 !strcmp(spft->u.tag.type, "yaml"));
03491
03492 if (isxml) {
03493 const char * tagN = myTagName(hsa->tags, spft->u.tag.tag, NULL);
03494
03495 if (tagN == NULL) {
03496 (void) snprintf(numbuf, sizeof(numbuf), "Tag_0x%08x",
03497 spft->u.tag.tag);
03498 numbuf[sizeof(numbuf)-1] = '\0';
03499 tagN = numbuf;
03500 }
03501 need = sizeof(" <rpmTag name=\"\">\n") + strlen(tagN);
03502 te = t = hsaReserve(hsa, need);
03503
03504 te = stpcpy( stpcpy( stpcpy(te, " <rpmTag name=\""), tagN), "\">\n");
03505
03506 hsa->vallen += (te - t);
03507 }
03508 if (isyaml) {
03509 int tagT = -1;
03510 const char * tagN = myTagName(hsa->tags, spft->u.tag.tag, &tagT);
03511
03512 if (tagN == NULL) {
03513 (void) snprintf(numbuf, sizeof(numbuf), "Tag_0x%08x",
03514 spft->u.tag.tag);
03515 numbuf[sizeof(numbuf)-1] = '\0';
03516 tagN = numbuf;
03517 tagT = numElements > 1
03518 ? RPM_ARRAY_RETURN_TYPE : RPM_SCALAR_RETURN_TYPE;
03519 }
03520 need = sizeof(" : - ") + strlen(tagN);
03521 te = t = hsaReserve(hsa, need);
03522
03523 *te++ = ' ';
03524 *te++ = ' ';
03525 te = stpcpy(te, tagN);
03526 *te++ = ':';
03527 *te++ = (((tagT & RPM_MASK_RETURN_TYPE) == RPM_ARRAY_RETURN_TYPE)
03528 ? '\n' : ' ');
03529
03530 if (((tagT & RPM_MASK_RETURN_TYPE) == RPM_ARRAY_RETURN_TYPE)
03531 && numElements == 1) {
03532 te = stpcpy(te, " ");
03533 if (spft->u.tag.tag != 1118)
03534 te = stpcpy(te, "- ");
03535 }
03536 *te = '\0';
03537
03538 hsa->vallen += (te - t);
03539 }
03540
03541 need = numElements * token->u.array.numTokens * 10;
03542 t = hsaReserve(hsa, need);
03543 for (j = 0; j < numElements; j++) {
03544 spft = token->u.array.format;
03545 for (i = 0; i < token->u.array.numTokens; i++, spft++) {
03546 te = singleSprintf(hsa, spft, j);
03547 if (te == NULL)
03548 return NULL;
03549 }
03550 }
03551
03552 if (isxml) {
03553 need = sizeof(" </rpmTag>\n") - 1;
03554 te = t = hsaReserve(hsa, need);
03555
03556 te = stpcpy(te, " </rpmTag>\n");
03557
03558 hsa->vallen += (te - t);
03559 }
03560 if (isyaml) {
03561 #if 0
03562 need = sizeof("\n") - 1;
03563 te = t = hsaReserve(hsa, need);
03564
03565 te = stpcpy(te, "\n");
03566
03567 hsa->vallen += (te - t);
03568 #endif
03569 }
03570
03571 }
03572 break;
03573 }
03574
03575 return (hsa->val + hsa->vallen);
03576 }
03577
03583 static rpmec
03584 rpmecNew(const headerSprintfExtension exts)
03585
03586 {
03587 headerSprintfExtension ext;
03588 rpmec ec;
03589 int i = 0;
03590
03591 for (ext = exts; ext != NULL && ext->type != HEADER_EXT_LAST;
03592 ext = (ext->type == HEADER_EXT_MORE ? ext->u.more : ext+1))
03593 {
03594 i++;
03595 }
03596
03597 ec = xcalloc(i, sizeof(*ec));
03598 return ec;
03599 }
03600
03607 static rpmec
03608 rpmecFree(const headerSprintfExtension exts, rpmec ec)
03609
03610 {
03611 headerSprintfExtension ext;
03612 int i = 0;
03613
03614 for (ext = exts; ext != NULL && ext->type != HEADER_EXT_LAST;
03615 ext = (ext->type == HEADER_EXT_MORE ? ext->u.more : ext+1))
03616 {
03617
03618 if (ec[i].freeit) ec[i].data = _free(ec[i].data);
03619
03620 i++;
03621 }
03622
03623 ec = _free(ec);
03624 return NULL;
03625 }
03626
03638 static
03639 char * headerSprintf(Header h, const char * fmt,
03640 const struct headerTagTableEntry_s * tbltags,
03641 const struct headerSprintfExtension_s * extensions,
03642 errmsg_t * errmsg)
03643
03644
03645 {
03646 headerSprintfArgs hsa = memset(alloca(sizeof(*hsa)), 0, sizeof(*hsa));
03647 sprintfToken nextfmt;
03648 sprintfTag tag;
03649 char * t, * te;
03650 int isxml;
03651 int isyaml;
03652 int need;
03653
03654 hsa->h = headerLink(h);
03655 hsa->fmt = xstrdup(fmt);
03656
03657 hsa->exts = (headerSprintfExtension) extensions;
03658 hsa->tags = (headerTagTableEntry) tbltags;
03659
03660 hsa->errmsg = NULL;
03661
03662
03663 if (parseFormat(hsa, hsa->fmt, &hsa->format, &hsa->numTokens, NULL, PARSER_BEGIN))
03664 goto exit;
03665
03666
03667 hsa->ec = rpmecNew(hsa->exts);
03668 hsa->val = xstrdup("");
03669
03670 tag =
03671 (hsa->format->type == PTOK_TAG
03672 ? &hsa->format->u.tag :
03673 (hsa->format->type == PTOK_ARRAY
03674 ? &hsa->format->u.array.format->u.tag :
03675 NULL));
03676 isxml = (tag != NULL && tag->tag == -2 && tag->type != NULL && !strcmp(tag->type, "xml"));
03677 isyaml = (tag != NULL && tag->tag == -2 && tag->type != NULL && !strcmp(tag->type, "yaml"));
03678
03679 if (isxml) {
03680 need = sizeof("<rpmHeader>\n") - 1;
03681 t = hsaReserve(hsa, need);
03682
03683 te = stpcpy(t, "<rpmHeader>\n");
03684
03685 hsa->vallen += (te - t);
03686 }
03687 if (isyaml) {
03688 need = sizeof("- !!omap\n") - 1;
03689 t = hsaReserve(hsa, need);
03690
03691 te = stpcpy(t, "- !!omap\n");
03692
03693 hsa->vallen += (te - t);
03694 }
03695
03696 hsa = hsaInit(hsa);
03697 while ((nextfmt = hsaNext(hsa)) != NULL) {
03698 te = singleSprintf(hsa, nextfmt, 0);
03699 if (te == NULL) {
03700 hsa->val = _free(hsa->val);
03701 break;
03702 }
03703 }
03704 hsa = hsaFini(hsa);
03705
03706 if (isxml) {
03707 need = sizeof("</rpmHeader>\n") - 1;
03708 t = hsaReserve(hsa, need);
03709
03710 te = stpcpy(t, "</rpmHeader>\n");
03711
03712 hsa->vallen += (te - t);
03713 }
03714 if (isyaml) {
03715 need = sizeof("\n") - 1;
03716 t = hsaReserve(hsa, need);
03717
03718 te = stpcpy(t, "\n");
03719
03720 hsa->vallen += (te - t);
03721 }
03722
03723 if (hsa->val != NULL && hsa->vallen < hsa->alloced)
03724 hsa->val = xrealloc(hsa->val, hsa->vallen+1);
03725
03726 hsa->ec = rpmecFree(hsa->exts, hsa->ec);
03727 hsa->format = freeFormat(hsa->format, hsa->numTokens);
03728
03729 exit:
03730
03731 if (errmsg)
03732 *errmsg = hsa->errmsg;
03733
03734 hsa->h = headerFree(hsa->h);
03735 hsa->fmt = _free(hsa->fmt);
03736 return hsa->val;
03737 }
03738
03748 static char * octalFormat(int_32 type, hPTR_t data,
03749 char * formatPrefix, int padding, int element)
03750
03751 {
03752 char * val;
03753
03754 if (type == RPM_INT32_TYPE) {
03755 val = xmalloc(20 + padding);
03756
03757 strcat(formatPrefix, "o");
03758
03759
03760 sprintf(val, formatPrefix, *((int_32 *) data));
03761
03762 } else if (type == RPM_INT64_TYPE) {
03763 val = xmalloc(40 + padding);
03764
03765 strcat(formatPrefix, "llo");
03766
03767
03768 sprintf(val, formatPrefix, *((int_64 *) data));
03769
03770 } else
03771 val = xstrdup(_("(not a number)"));
03772
03773 return val;
03774 }
03775
03785 static char * hexFormat(int_32 type, hPTR_t data,
03786 char * formatPrefix, int padding, int element)
03787
03788 {
03789 char * val;
03790
03791 if (type == RPM_INT32_TYPE) {
03792 val = xmalloc(20 + padding);
03793
03794 strcat(formatPrefix, "x");
03795
03796
03797 sprintf(val, formatPrefix, *((int_32 *) data));
03798
03799 } else if (type == RPM_INT64_TYPE) {
03800 val = xmalloc(40 + padding);
03801
03802 strcat(formatPrefix, "llx");
03803
03804
03805 sprintf(val, formatPrefix, *((int_64 *) data));
03806
03807 } else
03808 val = xstrdup(_("(not a number)"));
03809
03810 return val;
03811 }
03812
03823 static char * realDateFormat(int_32 type, hPTR_t data,
03824 char * formatPrefix, int padding, int element,
03825 const char * strftimeFormat)
03826
03827 {
03828 char * val;
03829
03830 if (type != RPM_INT32_TYPE) {
03831 val = xstrdup(_("(not a number)"));
03832 } else {
03833 struct tm * tstruct;
03834 char buf[50];
03835
03836 val = xmalloc(50 + padding);
03837
03838 strcat(formatPrefix, "s");
03839
03840
03841
03842 { time_t dateint = *((int_32 *) data);
03843 tstruct = localtime(&dateint);
03844 }
03845 buf[0] = '\0';
03846 if (tstruct)
03847 (void) strftime(buf, sizeof(buf) - 1, strftimeFormat, tstruct);
03848
03849 sprintf(val, formatPrefix, buf);
03850
03851 }
03852
03853 return val;
03854 }
03855
03865 static char * dateFormat(int_32 type, hPTR_t data,
03866 char * formatPrefix, int padding, int element)
03867
03868 {
03869 return realDateFormat(type, data, formatPrefix, padding, element,
03870 _("%c"));
03871 }
03872
03882 static char * dayFormat(int_32 type, hPTR_t data,
03883 char * formatPrefix, int padding, int element)
03884
03885 {
03886 return realDateFormat(type, data, formatPrefix, padding, element,
03887 _("%a %b %d %Y"));
03888 }
03889
03899 static char * shescapeFormat(int_32 type, hPTR_t data,
03900 char * formatPrefix, int padding, int element)
03901
03902 {
03903 char * result, * dst, * src, * buf;
03904
03905 if (type == RPM_INT32_TYPE) {
03906 result = xmalloc(padding + 20);
03907
03908 strcat(formatPrefix, "d");
03909
03910
03911 sprintf(result, formatPrefix, *((int_32 *) data));
03912
03913 } else if (type == RPM_INT64_TYPE) {
03914 result = xmalloc(padding + 40);
03915
03916 strcat(formatPrefix, "lld");
03917
03918
03919 sprintf(result, formatPrefix, *((int_64 *) data));
03920
03921 } else {
03922 buf = alloca(strlen(data) + padding + 2);
03923
03924 strcat(formatPrefix, "s");
03925
03926
03927 sprintf(buf, formatPrefix, data);
03928
03929
03930
03931 result = dst = xmalloc(strlen(buf) * 4 + 3);
03932 *dst++ = '\'';
03933 for (src = buf; *src != '\0'; src++) {
03934 if (*src == '\'') {
03935 *dst++ = '\'';
03936 *dst++ = '\\';
03937 *dst++ = '\'';
03938 *dst++ = '\'';
03939 } else {
03940 *dst++ = *src;
03941 }
03942 }
03943 *dst++ = '\'';
03944 *dst = '\0';
03945
03946
03947 }
03948
03949 return result;
03950 }
03951
03952
03953 const struct headerSprintfExtension_s headerDefaultFormats[] = {
03954 { HEADER_EXT_FORMAT, "octal", { octalFormat } },
03955 { HEADER_EXT_FORMAT, "hex", { hexFormat } },
03956 { HEADER_EXT_FORMAT, "date", { dateFormat } },
03957 { HEADER_EXT_FORMAT, "day", { dayFormat } },
03958 { HEADER_EXT_FORMAT, "shescape", { shescapeFormat } },
03959 { HEADER_EXT_LAST, NULL, { NULL } }
03960 };
03961
03962
03969 static
03970 void headerCopyTags(Header headerFrom, Header headerTo, hTAG_t tagstocopy)
03971
03972 {
03973 int * p;
03974
03975 if (headerFrom == headerTo)
03976 return;
03977
03978 for (p = tagstocopy; *p != 0; p++) {
03979 char *s;
03980 int_32 type;
03981 int_32 count;
03982 if (headerIsEntry(headerTo, *p))
03983 continue;
03984
03985 if (!headerGetEntryMinMemory(headerFrom, *p, &type,
03986 (hPTR_t *) &s, &count))
03987 continue;
03988
03989 (void) headerAddEntry(headerTo, *p, type, s, count);
03990 s = headerFreeData(s, type);
03991 }
03992 }
03993
03994
03995 static struct HV_s hdrVec1 = {
03996 headerLink,
03997 headerUnlink,
03998 headerFree,
03999 headerNew,
04000 headerSort,
04001 headerUnsort,
04002 headerSizeof,
04003 headerUnload,
04004 headerReload,
04005 headerCopy,
04006 headerLoad,
04007 headerCopyLoad,
04008 headerRead,
04009 headerWrite,
04010 headerIsEntry,
04011 headerFreeTag,
04012 headerGetEntry,
04013 headerGetEntryMinMemory,
04014 headerAddEntry,
04015 headerAppendEntry,
04016 headerAddOrAppendEntry,
04017 headerAddI18NString,
04018 headerModifyEntry,
04019 headerRemoveEntry,
04020 headerSprintf,
04021 headerCopyTags,
04022 headerFreeIterator,
04023 headerInitIterator,
04024 headerNextIterator,
04025 headerGetOrigin,
04026 headerSetOrigin,
04027 headerGetInstance,
04028 headerSetInstance,
04029 NULL, NULL,
04030 1
04031 };
04032
04033
04034
04035 HV_t hdrVec = &hdrVec1;
04036