5
/* RPM - Copyright (C) 1995-2000 Red Hat Software */
7
/* Data written to file descriptors is in network byte order. */
8
/* Data read from file descriptors is expected to be in */
9
/* network byte order and is converted on the fly to host order. */
13
#define __HEADER_PROTOTYPES__
15
#include <header_internal.h>
19
/*@-redecl@*/ /* FIX: avoid rpmlib.h, need for debugging. */
20
/*@observer@*/ const char *const tagName(int tag) /*@*/;
23
/*@access entryInfo @*/
24
/*@access indexEntry @*/
26
/*@access extensionCache @*/
27
/*@access sprintfTag @*/
28
/*@access sprintfToken @*/
31
#define PARSER_BEGIN 0
32
#define PARSER_IN_ARRAY 1
33
#define PARSER_IN_EXPR 2
37
static unsigned char header_magic[8] = {
38
0x8e, 0xad, 0xe8, 0x01, 0x00, 0x00, 0x00, 0x00
42
* Maximum no. of bytes permitted in a header.
44
static size_t headerMaxbytes = (32*1024*1024);
47
* Sanity check on no. of tags.
48
* This check imposes a limit of 65K tags, more than enough.
50
#define hdrchkTags(_ntags) ((_ntags) & 0xffff0000)
53
* Sanity check on data size and/or offset.
54
* This check imposes a limit of 16Mb, more than enough.
56
#define hdrchkData(_nbytes) ((_nbytes) & 0xff000000)
59
* Alignment needs (and sizeof scalars types) for internal rpm data types.
61
static int typeSizes[] = {
62
0, /*!< RPM_NULL_TYPE */
63
1, /*!< RPM_CHAR_TYPE */
64
1, /*!< RPM_INT8_TYPE */
65
2, /*!< RPM_INT16_TYPE */
66
4, /*!< RPM_INT32_TYPE */
67
-1, /*!< RPM_INT64_TYPE */
68
-1, /*!< RPM_STRING_TYPE */
69
1, /*!< RPM_BIN_TYPE */
70
-1, /*!< RPM_STRING_ARRAY_TYPE */
71
-1 /*!< RPM_I18NSTRING_TYPE */
74
HV_t hdrVec; /* forward reference */
77
* Wrapper to free(3), hides const compilation noise, permit NULL, return NULL.
78
* @param p memory to free
81
/*@unused@*/ static inline /*@null@*/ void *
82
_free(/*@only@*/ /*@null@*/ const void * p) /*@modifies *p @*/
84
if (p != NULL) free((void *)p);
90
Header h = xcalloc(1, sizeof(*h));
93
h->hv = *hdrVec; /* structure assignment */
96
h->indexAlloced = INDEX_MALLOC_SIZE;
98
h->flags = HEADERFLAG_SORTED;
101
h->index = (h->indexAlloced
102
? xcalloc(h->indexAlloced, sizeof(*h->index))
110
Header headerFree(Header h)
112
if (h == NULL || --h->nrefs > 0)
113
return NULL; /* XXX return previous header? */
116
indexEntry entry = h->index;
118
for (i = 0; i < h->indexUsed; i++, entry++) {
119
if ((h->flags & HEADERFLAG_ALLOCATED) && ENTRY_IS_REGION(entry)) {
120
if (entry->length > 0) {
121
int_32 * ei = entry->data;
122
if ((ei - 2) == h->blob) h->blob = _free(h->blob);
125
} else if (!ENTRY_IN_REGION(entry)) {
126
entry->data = _free(entry->data);
130
h->index = _free(h->index);
133
/*@-refcounttrans@*/ h = _free(h); /*@=refcounttrans@*/
137
Header headerLink(Header h)
140
/*@-refcounttrans@*/ return h; /*@=refcounttrans@*/
145
static int indexCmp(const void * avp, const void * bvp) /*@*/
148
indexEntry ap = (indexEntry) avp, bp = (indexEntry) bvp;
150
return (ap->info.tag - bp->info.tag);
153
void headerSort(Header h)
155
if (!(h->flags & HEADERFLAG_SORTED)) {
156
qsort(h->index, h->indexUsed, sizeof(*h->index), indexCmp);
157
h->flags |= HEADERFLAG_SORTED;
163
static int offsetCmp(const void * avp, const void * bvp) /*@*/
166
indexEntry ap = (indexEntry) avp, bp = (indexEntry) bvp;
168
int rc = (ap->info.offset - bp->info.offset);
171
/* Within a region, entries sort by address. Added drips sort by tag. */
172
if (ap->info.offset < 0)
173
rc = (((char *)ap->data) - ((char *)bp->data));
175
rc = (ap->info.tag - bp->info.tag);
180
void headerUnsort(Header h)
182
qsort(h->index, h->indexUsed, sizeof(*h->index), offsetCmp);
185
unsigned int headerSizeof(Header h, enum hMagic magicp)
188
unsigned int size = 0;
189
unsigned int pad = 0;
198
case HEADER_MAGIC_YES:
199
size += sizeof(header_magic);
201
case HEADER_MAGIC_NO:
205
size += 2 * sizeof(int_32); /* count of index entries */
207
for (i = 0, entry = h->index; i < h->indexUsed; i++, entry++) {
211
/* Regions go in as is ... */
212
if (ENTRY_IS_REGION(entry)) {
213
size += entry->length;
214
/* XXX Legacy regions do not include the region tag and data. */
215
if (i == 0 && (h->flags & HEADERFLAG_LEGACY))
216
size += sizeof(struct entryInfo) + entry->info.count;
220
/* ... and region elements are skipped. */
221
if (entry->info.offset < 0)
225
type = entry->info.type;
226
if (typeSizes[type] > 1) {
227
diff = typeSizes[type] - (size % typeSizes[type]);
228
if (diff != typeSizes[type]) {
234
size += sizeof(struct entryInfo) + entry->length;
241
* Return length of entry data.
242
* @param type entry data type
243
* @param p entry data
244
* @param count entry item count
245
* @param onDisk data is concatenated strings (with NUL's))?
246
* @return no. bytes in data
249
static int dataLength(int_32 type, hPTR_t p, int_32 count, int onDisk)
250
/*@modifies fileSystem @*/
255
case RPM_STRING_TYPE:
256
if (count == 1) { /* Special case -- p is just the string */
257
length = strlen(p) + 1;
260
/* This should not be allowed */
261
fprintf(stderr, _("dataLength() RPM_STRING_TYPE count must be 1.\n"));
263
/*@notreached@*/ break;
265
case RPM_STRING_ARRAY_TYPE:
266
case RPM_I18NSTRING_TYPE:
269
/* This is like RPM_STRING_TYPE, except it's *always* an array */
270
/* Compute sum of length of all strings, including null terminators */
274
const char * chptr = p;
278
thisLen = strlen(chptr) + 1;
283
const char ** src = (const char **)p;
285
/* add one for null termination */
286
length += strlen(*src++) + 1;
292
if (typeSizes[type] != -1) {
293
length = typeSizes[type] * count;
296
fprintf(stderr, _("Data type %d not supported\n"), (int) type);
298
/*@notreached@*/ break;
305
* Swap int_32 and int_16 arrays within header region.
307
* This code is way more twisty than I would like.
309
* A bug with RPM_I18NSTRING_TYPE in rpm-2.5.x (fixed in August 1998)
310
* causes the offset and length of elements in a header region to disagree
311
* regarding the total length of the region data.
313
* The "fix" is to compute the size using both offset and length and
314
* return the larger of the two numbers as the size of the region.
315
* Kinda like computing left and right Riemann sums of the data elements
316
* to determine the size of a data structure, go figger :-).
318
* There's one other twist if a header region tag is in the set to be swabbed,
319
* as the data for a header region is located after all other tag data.
321
* @param entry header entry
322
* @param il no. of entries
323
* @param dl start no. bytes of data
324
* @param pe header physical entry pointer (swapped)
325
* @param dataStart header data
326
* @param regionid region offset
327
* @return no. bytes of data in region, -1 on error
329
static int regionSwab(/*@null@*/ indexEntry entry, int il, int dl,
330
entryInfo pe, char * dataStart, int regionid)
331
/*@modifies *entry, *dataStart @*/
336
struct indexEntry ieprev;
338
memset(&ieprev, 0, sizeof(ieprev));
339
for (; il > 0; il--, pe++) {
340
struct indexEntry ie;
343
ie.info.tag = ntohl(pe->tag);
344
ie.info.type = ntohl(pe->type);
345
if (ie.info.type < RPM_MIN_TYPE || ie.info.type > RPM_MAX_TYPE)
347
ie.info.count = ntohl(pe->count);
348
ie.info.offset = ntohl(pe->offset);
349
ie.data = t = dataStart + ie.info.offset;
350
ie.length = dataLength(ie.info.type, ie.data, ie.info.count, 1);
354
ie.info.offset = regionid;
355
*entry = ie; /* structure assignment */
361
if (typeSizes[type] > 1) {
363
diff = typeSizes[type] - (dl % typeSizes[type]);
364
if (diff != typeSizes[type]) {
366
if (ieprev.info.type == RPM_I18NSTRING_TYPE)
367
ieprev.length += diff;
370
tdel = (tprev ? (t - tprev) : 0);
371
if (ieprev.info.type == RPM_I18NSTRING_TYPE)
372
tdel = ieprev.length;
374
if (ie.info.tag >= HEADER_I18NTABLE) {
378
/* XXX HEADER_IMAGE tags don't include region sub-tag. */
379
if (ie.info.tag != HEADER_IMMUTABLE)
380
tprev -= REGION_TAG_COUNT;
383
/* Perform endian conversions */
384
switch (ntohl(pe->type)) {
386
{ int_32 * it = (int_32 *)t;
387
for (; ie.info.count > 0; ie.info.count--, it += 1)
392
{ int_16 * it = (int_16 *) t;
393
for (; ie.info.count > 0; ie.info.count--, it += 1)
404
ieprev = ie; /* structure assignment */
407
tdel = (tprev ? (t - tprev) : 0);
411
* There are two hacks here:
412
* 1) tl is 16b (i.e. REGION_TAG_COUNT) short while doing headerReload().
413
* 2) the 8/98 rpm bug with inserting i18n tags needs to use tl, not dl.
415
if (tl+REGION_TAG_COUNT == dl)
416
tl += REGION_TAG_COUNT;
422
int headerDrips(const Header h)
427
for (i = 0, entry = h->index; i < h->indexUsed; i++, entry++) {
428
if (ENTRY_IS_REGION(entry)) {
429
int rid = entry->info.offset;
431
for (; i < h->indexUsed && entry->info.offset <= rid+1; i++, entry++) {
432
if (entry->info.offset <= rid)
440
/* Ignore deleted drips. */
441
if (entry->data == NULL || entry->length <= 0)
450
static /*@only@*/ /*@null@*/ void * doHeaderUnload(Header h,
451
/*@out@*/ int * lengthPtr)
452
/*@modifies h, *lengthPtr @*/
465
int drlen, ndribbles;
469
/* Sort entries by (offset,tag). */
472
/* Compute (il,dl) for all tags, including those deleted in region. */
474
drlen = ndribbles = driplen = ndrips = 0;
475
for (i = 0, entry = h->index; i < h->indexUsed; i++, entry++) {
476
if (ENTRY_IS_REGION(entry)) {
477
int_32 rdl = -entry->info.offset; /* negative offset */
478
int_32 ril = rdl/sizeof(*pe);
479
int rid = entry->info.offset;
482
dl += entry->rdlen + entry->info.count;
483
/* XXX Legacy regions do not include the region tag and data. */
484
if (i == 0 && (h->flags & HEADERFLAG_LEGACY))
487
/* Skip rest of entries in region, but account for dribbles. */
488
for (; i < h->indexUsed && entry->info.offset <= rid+1; i++, entry++) {
489
if (entry->info.offset <= rid)
493
type = entry->info.type;
494
if (typeSizes[type] > 1) {
496
diff = typeSizes[type] - (dl % typeSizes[type]);
497
if (diff != typeSizes[type]) {
506
drlen += entry->length;
514
/* Ignore deleted drips. */
515
if (entry->data == NULL || entry->length <= 0)
519
type = entry->info.type;
520
if (typeSizes[type] > 1) {
522
diff = typeSizes[type] - (dl % typeSizes[type]);
523
if (diff != typeSizes[type]) {
533
driplen += entry->length;
537
/* Sanity checks on header intro. */
538
if (hdrchkTags(il) || hdrchkData(dl))
541
len = sizeof(il) + sizeof(dl) + (il * sizeof(*pe)) + dl;
547
pe = (entryInfo) &ei[2];
548
dataStart = te = (char *) (pe + il);
551
for (i = 0, entry = h->index; i < h->indexUsed; i++, entry++) {
557
if (entry->data == NULL || entry->length <= 0)
561
pe->tag = htonl(entry->info.tag);
562
pe->type = htonl(entry->info.type);
563
pe->count = htonl(entry->info.count);
565
if (ENTRY_IS_REGION(entry)) {
566
int_32 rdl = -entry->info.offset; /* negative offset */
567
int_32 ril = rdl/sizeof(*pe) + ndribbles;
568
int rid = entry->info.offset;
570
src = (char *)entry->data;
571
rdlen = entry->rdlen;
573
/* XXX Legacy regions do not include the region tag and data. */
574
if (i == 0 && (h->flags & HEADERFLAG_LEGACY)) {
578
memcpy(pe+1, src, rdl);
579
memcpy(te, src + rdl, rdlen);
582
pe->offset = htonl(te - dataStart);
585
stei[2] = htonl(-rdl-entry->info.count);
587
memcpy(te, stei, entry->info.count);
588
te += entry->info.count;
590
rdlen += entry->info.count;
592
count = regionSwab(NULL, ril, 0, pe, t, 0);
598
memcpy(pe+1, src + sizeof(*pe), ((ril-1) * sizeof(*pe)));
599
memcpy(te, src + (ril * sizeof(*pe)), rdlen+entry->info.count+drlen);
602
entryInfo se = (entryInfo)src;
604
int off = ntohl(se->offset);
605
pe->offset = (off) ? htonl(te - dataStart) : htonl(off);
607
te += entry->info.count + drlen;
609
count = regionSwab(NULL, ril, 0, pe, t, 0);
610
if (count != (rdlen + entry->info.count + drlen))
614
/* Skip rest of entries in region. */
615
while (i < h->indexUsed && entry->info.offset <= rid+1) {
625
/* Ignore deleted drips. */
626
if (entry->data == NULL || entry->length <= 0)
630
type = entry->info.type;
631
if (typeSizes[type] > 1) {
633
diff = typeSizes[type] - ((te - dataStart) % typeSizes[type]);
634
if (diff != typeSizes[type]) {
641
pe->offset = htonl(te - dataStart);
643
/* copy data w/ endian conversions */
644
switch (entry->info.type) {
646
count = entry->info.count;
649
*((int_32 *)te) = htonl(*((int_32 *)src));
650
te += sizeof(int_32);
651
src += sizeof(int_32);
656
count = entry->info.count;
659
*((int_16 *)te) = htons(*((int_16 *)src));
660
te += sizeof(int_16);
661
src += sizeof(int_16);
666
memcpy(te, entry->data, entry->length);
673
/* Insure that there are no memcpy underruns/overruns. */
674
if (((char *)pe) != dataStart)
676
if ((((char *)ei)+len) != te)
682
h->flags &= ~HEADERFLAG_SORTED;
694
void * headerUnload(Header h)
697
void * uh = doHeaderUnload(h, &length);
701
Header headerReload(Header h, int tag)
706
void * uh = doHeaderUnload(h, &length);
717
if (nh->flags & HEADERFLAG_ALLOCATED)
719
nh->flags |= HEADERFLAG_ALLOCATED;
720
if (ENTRY_IS_REGION(nh->index)) {
721
if (tag == HEADER_SIGNATURES || tag == HEADER_IMMUTABLE)
722
nh->index[0].info.tag = tag;
727
Header headerCopy(Header h)
729
Header nh = headerNew();
731
int_32 tag, type, count;
734
for (hi = headerInitIterator(h);
735
headerNextIterator(hi, &tag, &type, &ptr, &count);
736
ptr = headerFreeData((void *)ptr, type))
738
if (ptr) (void) headerAddEntry(nh, tag, type, ptr, count);
740
hi = headerFreeIterator(hi);
742
return headerReload(nh, HEADER_IMAGE);
745
Header headerLoad(void * uh)
747
int_32 * ei = (int_32 *) uh;
748
int_32 il = ntohl(ei[0]); /* index length */
749
int_32 dl = ntohl(ei[1]); /* data length */
750
size_t pvlen = sizeof(il) + sizeof(dl) +
751
(il * sizeof(struct entryInfo)) + dl;
760
/* Sanity checks on header intro. */
761
if (hdrchkTags(il) || hdrchkData(dl))
766
pe = (entryInfo) &ei[2];
768
dataStart = (char *) (pe + il);
770
h = xcalloc(1, sizeof(*h));
772
h->hv = *hdrVec; /* structure assignment */
774
/*@-assignexpose -kepttrans@*/
776
/*@=assignexpose =kepttrans@*/
777
h->indexAlloced = il + 1;
779
h->index = xcalloc(h->indexAlloced, sizeof(*h->index));
780
h->flags = HEADERFLAG_SORTED;
784
* XXX XFree86-libs, ash, and pdksh from Red Hat 5.2 have bogus
785
* %verifyscript tag that needs to be diddled.
787
if (ntohl(pe->tag) == 15 &&
788
ntohl(pe->type) == RPM_STRING_TYPE &&
789
ntohl(pe->count) == 1)
791
pe->tag = htonl(1079);
796
if (!(htonl(pe->tag) < HEADER_I18NTABLE)) {
797
h->flags |= HEADERFLAG_LEGACY;
798
entry->info.type = REGION_TAG_TYPE;
799
entry->info.tag = HEADER_IMAGE;
800
entry->info.count = REGION_TAG_COUNT;
801
entry->info.offset = ((char *)pe - dataStart); /* negative offset */
806
entry->length = pvlen - sizeof(il) - sizeof(dl);
807
rdlen = regionSwab(entry+1, il, 0, pe, dataStart, entry->info.offset);
808
#if 0 /* XXX don't check, the 8/98 i18n bug fails here. */
812
entry->rdlen = rdlen;
816
int nb = ntohl(pe->count);
820
h->flags &= ~HEADERFLAG_LEGACY;
822
entry->info.type = htonl(pe->type);
823
if (entry->info.type < RPM_MIN_TYPE || entry->info.type > RPM_MAX_TYPE)
825
entry->info.count = htonl(pe->count);
827
if (hdrchkTags(entry->info.count))
830
{ int off = ntohl(pe->offset);
835
int_32 * stei = memcpy(alloca(nb), dataStart + off, nb);
836
rdl = -ntohl(stei[2]); /* negative offset */
837
ril = rdl/sizeof(*pe);
838
if (hdrchkTags(ril) || hdrchkData(rdl))
840
entry->info.tag = htonl(pe->tag);
843
rdl = (ril * sizeof(struct entryInfo));
844
entry->info.tag = HEADER_IMAGE;
847
entry->info.offset = -rdl; /* negative offset */
852
entry->length = pvlen - sizeof(il) - sizeof(dl);
853
rdlen = regionSwab(entry+1, ril-1, 0, pe+1, dataStart, entry->info.offset);
856
entry->rdlen = rdlen;
858
if (ril < h->indexUsed) {
859
indexEntry newEntry = entry + ril;
860
int ne = (h->indexUsed - ril);
861
int rid = entry->info.offset+1;
864
/* Load dribble entries from region. */
865
rc = regionSwab(newEntry, ne, 0, pe+ril, dataStart, rid);
870
{ indexEntry firstEntry = newEntry;
871
int save = h->indexUsed;
874
/* Dribble entries replace duplicate region entries. */
876
for (j = 0; j < ne; j++, newEntry++) {
877
(void) headerRemoveEntry(h, newEntry->info.tag);
878
if (newEntry->info.tag == HEADER_BASENAMES)
879
(void) headerRemoveEntry(h, HEADER_OLDFILENAMES);
882
/* If any duplicate entries were replaced, move new entries down. */
883
if (h->indexUsed < (save - ne)) {
884
memmove(h->index + h->indexUsed, firstEntry,
885
(ne * sizeof(*entry)));
892
h->flags &= ~HEADERFLAG_SORTED;
902
h->index = _free(h->index);
908
/*@-refcounttrans -globstate@*/
910
/*@=refcounttrans =globstate@*/
913
Header headerCopyLoad(const void * uh)
915
int_32 * ei = (int_32 *) uh;
916
int_32 il = ntohl(ei[0]); /* index length */
917
int_32 dl = ntohl(ei[1]); /* data length */
918
size_t pvlen = sizeof(il) + sizeof(dl) +
919
(il * sizeof(struct entryInfo)) + dl;
923
/* Sanity checks on header intro. */
924
if (!(hdrchkTags(il) || hdrchkData(dl)) && pvlen < headerMaxbytes) {
925
nuh = memcpy(xmalloc(pvlen), uh, pvlen);
926
if ((h = headerLoad(nuh)) != NULL)
927
h->flags |= HEADERFLAG_ALLOCATED;
934
Header headerRead(FD_t fd, enum hMagic magicp)
946
memset(block, 0, sizeof(block));
948
if (magicp == HEADER_MAGIC_YES)
951
if (timedRead(fd, (char *)block, i*sizeof(*block)) != (i * sizeof(*block)))
956
if (magicp == HEADER_MAGIC_YES) {
958
if (memcmp(&magic, header_magic, sizeof(magic)))
960
reserved = block[i++];
963
il = ntohl(block[i++]);
964
dl = ntohl(block[i++]);
966
len = sizeof(il) + sizeof(dl) + (il * sizeof(struct entryInfo)) + dl;
968
/* Sanity checks on header intro. */
969
if (hdrchkTags(il) || hdrchkData(dl) || len > headerMaxbytes)
975
len -= sizeof(il) + sizeof(dl);
977
if (timedRead(fd, (char *)&ei[2], len) != len)
984
if (h->flags & HEADERFLAG_ALLOCATED)
986
h->flags |= HEADERFLAG_ALLOCATED;
989
/*@-mustmod@*/ /* FIX: timedRead macro obscures annotation */
994
int headerWrite(FD_t fd, Header h, enum hMagic magicp)
1002
uh = doHeaderUnload(h, &length);
1006
case HEADER_MAGIC_YES:
1007
nb = Fwrite(header_magic, sizeof(char), sizeof(header_magic), fd);
1008
if (nb != sizeof(header_magic))
1011
case HEADER_MAGIC_NO:
1015
nb = Fwrite(uh, sizeof(char), length, fd);
1019
return (nb == length ? 0 : 1);
1023
* Find matching (tag,type) entry in header.
1025
* @param tag entry tag
1026
* @param type entry type
1027
* @return header entry
1030
indexEntry findEntry(/*@null@*/ Header h, int_32 tag, int_32 type)
1033
indexEntry entry, entry2, last;
1034
struct indexEntry key;
1036
if (h == NULL) return NULL;
1037
if (!(h->flags & HEADERFLAG_SORTED)) headerSort(h);
1042
bsearch(&key, h->index, h->indexUsed, sizeof(*h->index), indexCmp);
1046
if (type == RPM_NULL_TYPE)
1049
/* look backwards */
1050
while (entry->info.tag == tag && entry->info.type != type &&
1051
entry > h->index) entry--;
1053
if (entry->info.tag == tag && entry->info.type == type)
1056
last = h->index + h->indexUsed;
1057
while (entry2->info.tag == tag && entry2->info.type != type &&
1058
entry2 < last) entry2++;
1060
if (entry->info.tag == tag && entry->info.type == type)
1066
int headerIsEntry(Header h, int_32 tag)
1068
/*@-mods@*/ /*@ FIX: h modified by sort. */
1069
return (findEntry(h, tag, RPM_NULL_TYPE) ? 1 : 0);
1074
* Retrieve data from header entry.
1075
* @todo Permit retrieval of regions other than HEADER_IMUTABLE.
1076
* @param entry header entry
1077
* @retval type address of type (or NULL)
1078
* @retval p address of data (or NULL)
1079
* @retval c address of count (or NULL)
1080
* @param minMem string pointers refer to header memory?
1081
* @return 1 on success, otherwise error.
1083
static int copyEntry(const indexEntry entry,
1084
/*@null@*/ /*@out@*/ hTYP_t type,
1085
/*@null@*/ /*@out@*/ hPTR_t * p,
1086
/*@null@*/ /*@out@*/ hCNT_t c,
1088
/*@modifies *type, *p, *c @*/
1090
int_32 count = entry->info.count;
1091
int rc = 1; /* XXX 1 on success. */
1094
switch (entry->info.type) {
1096
/* XXX this only works for HEADER_IMMUTABLE */
1097
if (ENTRY_IS_REGION(entry)) {
1098
int_32 * ei = ((int_32 *)entry->data) - 2;
1100
entryInfo pe = (entryInfo) (ei + 2);
1102
char * dataStart = (char *) (pe + ntohl(ei[0]));
1103
int_32 rdl = -entry->info.offset; /* negative offset */
1104
int_32 ril = rdl/sizeof(*pe);
1106
count = 2 * sizeof(*ei) + (ril * sizeof(*pe)) +
1107
entry->rdlen + REGION_TAG_COUNT;
1108
*p = xmalloc(count);
1111
ei[1] = htonl(entry->rdlen + REGION_TAG_COUNT);
1113
pe = (entryInfo) memcpy(ei + 2, pe, (ril * sizeof(*pe)));
1115
dataStart = (char *) memcpy(pe + ril, dataStart,
1116
(entry->rdlen + REGION_TAG_COUNT));
1118
rc = regionSwab(NULL, ril, 0, pe, dataStart, 0);
1119
/* XXX 1 on success. */
1120
rc = (rc < 0) ? 0 : 1;
1122
count = entry->length;
1124
? memcpy(xmalloc(count), entry->data, count)
1128
case RPM_STRING_TYPE:
1134
case RPM_STRING_ARRAY_TYPE:
1135
case RPM_I18NSTRING_TYPE:
1136
{ const char ** ptrEntry;
1137
int tableSize = count * sizeof(char *);
1143
*p = xmalloc(tableSize);
1144
ptrEntry = (const char **) *p;
1147
t = xmalloc(tableSize + entry->length);
1149
ptrEntry = (const char **) *p;
1151
memcpy(t, entry->data, entry->length);
1154
for (i = 0; i < count; i++) {
1165
if (type) *type = entry->info.type;
1171
* Does locale match entry in header i18n table?
1174
* The range [l,le) contains the next locale to match:
1175
* ll[_CC][.EEEEE][@dddd]
1177
* ll ISO language code (in lowercase).
1178
* CC (optional) ISO coutnry code (in uppercase).
1179
* EEEEE (optional) encoding (not really standardized).
1180
* dddd (optional) dialect.
1183
* @param td header i18n table data, NUL terminated
1184
* @param l start of locale to match
1185
* @param le end of locale to match
1186
* @return 1 on match, 0 on no match
1188
static int headerMatchLocale(const char *td, const char *l, const char *le)
1195
{ const char *s, *ll, *CC, *EE, *dd;
1198
/* Copy the buffer and parse out components on the fly. */
1199
lbuf = alloca(le - l + 1);
1200
for (s = l, ll = t = lbuf; *s; s++, t++) {
1220
if (ll) /* ISO language should be lower case */
1221
for (t = ll; *t; t++) *t = tolower(*t);
1222
if (CC) /* ISO country code should be upper case */
1223
for (t = CC; *t; t++) *t = toupper(*t);
1225
/* There are a total of 16 cases to attempt to match. */
1229
/* First try a complete match. */
1230
if (strlen(td) == (le-l) && !strncmp(td, l, (le - l)))
1233
/* Next, try stripping optional dialect and matching. */
1234
for (fe = l; fe < le && *fe != '@'; fe++)
1236
if (fe < le && !strncmp(td, l, (fe - l)))
1239
/* Next, try stripping optional codeset and matching. */
1240
for (fe = l; fe < le && *fe != '.'; fe++)
1242
if (fe < le && !strncmp(td, l, (fe - l)))
1245
/* Finally, try stripping optional country code and matching. */
1246
for (fe = l; fe < le && *fe != '_'; fe++)
1248
if (fe < le && !strncmp(td, l, (fe - l)))
1255
* Return i18n string from header that matches locale.
1257
* @param entry i18n string data
1258
* @return matching i18n string (or 1st string if no match)
1260
/*@dependent@*/ static char *
1261
headerFindI18NString(Header h, indexEntry entry)
1263
const char *lang, *l, *le;
1266
/* XXX Drepper sez' this is the order. */
1267
if ((lang = getenv("LANGUAGE")) == NULL &&
1268
(lang = getenv("LC_ALL")) == NULL &&
1269
(lang = getenv("LC_MESSAGES")) == NULL &&
1270
(lang = getenv("LANG")) == NULL)
1271
/*@-retalias -retexpose@*/
1273
/*@=retalias =retexpose@*/
1275
if ((table = findEntry(h, HEADER_I18NTABLE, RPM_STRING_ARRAY_TYPE)) == NULL)
1276
/*@-retalias -retexpose@*/
1278
/*@=retalias =retexpose@*/
1280
for (l = lang; *l != '\0'; l = le) {
1285
while (*l && *l == ':') /* skip leading colons */
1289
for (le = l; *le && *le != ':'; le++) /* find end of this locale */
1292
/* For each entry in the header ... */
1293
for (langNum = 0, td = table->data, ed = entry->data;
1294
langNum < entry->info.count;
1295
langNum++, td += strlen(td) + 1, ed += strlen(ed) + 1) {
1297
if (headerMatchLocale(td, l, le))
1303
/*@-retalias -retexpose@*/
1305
/*@=retalias =retexpose@*/
1309
* Retrieve tag data from header.
1311
* @param tag tag to retrieve
1312
* @retval type address of type (or NULL)
1313
* @retval p address of data (or NULL)
1314
* @retval c address of count (or NULL)
1315
* @param minMem string pointers reference header memory?
1316
* @return 1 on success, 0 on not found
1318
static int intGetEntry(Header h, int_32 tag,
1319
/*@null@*/ /*@out@*/ hTAG_t type,
1320
/*@null@*/ /*@out@*/ hPTR_t * p,
1321
/*@null@*/ /*@out@*/ hCNT_t c,
1323
/*@modifies *type, *p, *c @*/
1328
/* First find the tag */
1329
/*@-mods@*/ /*@ FIX: h modified by sort. */
1330
entry = findEntry(h, tag, RPM_NULL_TYPE);
1332
if (entry == NULL) {
1339
switch (entry->info.type) {
1340
case RPM_I18NSTRING_TYPE:
1342
if (type) *type = RPM_STRING_TYPE;
1344
/*@-dependenttrans@*/
1345
if (p) *p = headerFindI18NString(h, entry);
1346
/*@=dependenttrans@*/
1349
rc = copyEntry(entry, type, p, c, minMem);
1353
/* XXX 1 on success */
1354
return ((rc == 1) ? 1 : 0);
1358
* Free data allocated when retrieved from header.
1360
* @param data address of data (or NULL)
1361
* @param type type of data (or -1 to force free)
1362
* @return NULL always
1364
static /*@null@*/ void * headerFreeTag(/*@unused@*/ Header h,
1365
/*@only@*/ /*@null@*/ const void * data, rpmTagType type)
1366
/*@modifies data @*/
1371
type == RPM_STRING_ARRAY_TYPE ||
1372
type == RPM_I18NSTRING_TYPE ||
1373
type == RPM_BIN_TYPE)
1380
int headerGetEntry(Header h, int_32 tag, hTYP_t type, void **p, hCNT_t c)
1382
return intGetEntry(h, tag, type, (hPTR_t *)p, c, 0);
1385
int headerGetEntryMinMemory(Header h, int_32 tag, hTYP_t type, hPTR_t * p,
1388
return intGetEntry(h, tag, type, p, c, 1);
1391
int headerGetRawEntry(Header h, int_32 tag, int_32 * type, hPTR_t * p,
1397
if (p == NULL) return headerIsEntry(h, tag);
1399
/* First find the tag */
1400
/*@-mods@*/ /*@ FIX: h modified by sort. */
1401
entry = findEntry(h, tag, RPM_NULL_TYPE);
1409
rc = copyEntry(entry, type, p, c, 0);
1411
/* XXX 1 on success */
1412
return ((rc == 1) ? 1 : 0);
1417
static void copyData(int_32 type, /*@out@*/ void * dstPtr, const void * srcPtr,
1418
int_32 c, int dataLength)
1419
/*@modifies *dstPtr @*/
1426
case RPM_STRING_ARRAY_TYPE:
1427
case RPM_I18NSTRING_TYPE:
1428
/* Otherwise, p is char** */
1430
src = (const char **) srcPtr;
1434
int len = strlen(*src) + 1;
1435
memcpy(dst, *src, len);
1443
memmove(dstPtr, srcPtr, dataLength);
1449
* Return (malloc'ed) copy of entry data.
1450
* @param type entry data type
1451
* @param p entry data
1452
* @param c entry item count
1453
* @retval lengthPtr no. bytes in returned data
1454
* @return (malloc'ed) copy of entry data
1456
static void * grabData(int_32 type, hPTR_t p, int_32 c,
1457
/*@out@*/ int * lengthPtr)
1458
/*@modifies *lengthPtr @*/
1460
int length = dataLength(type, p, c, 0);
1461
void * data = xmalloc(length);
1463
copyData(type, data, p, c, length);
1466
*lengthPtr = length;
1470
int headerAddEntry(Header h, int_32 tag, int_32 type, hPTR_t p, int_32 c)
1474
/* Count must always be >= 1 for headerAddEntry. */
1478
/* Allocate more index space if necessary */
1479
if (h->indexUsed == h->indexAlloced) {
1480
h->indexAlloced += INDEX_MALLOC_SIZE;
1481
h->index = xrealloc(h->index, h->indexAlloced * sizeof(*h->index));
1484
/* Fill in the index */
1485
entry = h->index + h->indexUsed;
1486
entry->info.tag = tag;
1487
entry->info.type = type;
1488
entry->info.count = c;
1489
entry->info.offset = 0;
1490
entry->data = grabData(type, p, c, &entry->length);
1492
if (h->indexUsed > 0 && tag < h->index[h->indexUsed-1].info.tag)
1493
h->flags &= ~HEADERFLAG_SORTED;
1499
int headerAppendEntry(Header h, int_32 tag, int_32 type,
1505
/* First find the tag */
1506
entry = findEntry(h, tag, type);
1510
if (type == RPM_STRING_TYPE || type == RPM_I18NSTRING_TYPE) {
1511
/* we can't do this */
1515
length = dataLength(type, p, c, 0);
1517
if (ENTRY_IN_REGION(entry)) {
1518
char * t = xmalloc(entry->length + length);
1519
memcpy(t, entry->data, entry->length);
1521
entry->info.offset = 0;
1523
entry->data = xrealloc(entry->data, entry->length + length);
1525
copyData(type, ((char *) entry->data) + entry->length, p, c, length);
1527
entry->length += length;
1529
entry->info.count += c;
1534
int headerAddOrAppendEntry(Header h, int_32 tag, int_32 type,
1537
return (findEntry(h, tag, type)
1538
? headerAppendEntry(h, tag, type, p, c)
1539
: headerAddEntry(h, tag, type, p, c));
1542
int headerAddI18NString(Header h, int_32 tag, const char * string, const char * lang)
1544
indexEntry table, entry;
1545
const char ** strArray;
1551
table = findEntry(h, HEADER_I18NTABLE, RPM_STRING_ARRAY_TYPE);
1552
entry = findEntry(h, tag, RPM_I18NSTRING_TYPE);
1554
if (!table && entry)
1555
return 0; /* this shouldn't ever happen!! */
1557
if (!table && !entry) {
1558
const char * charArray[2];
1560
if (!lang || (lang[0] == 'C' && lang[1] == '\0')) {
1561
/*@-observertrans -readonlytrans@*/
1562
charArray[count++] = "C";
1563
/*@=observertrans =readonlytrans@*/
1565
/*@-observertrans -readonlytrans@*/
1566
charArray[count++] = "C";
1567
/*@=observertrans =readonlytrans@*/
1568
charArray[count++] = lang;
1570
if (!headerAddEntry(h, HEADER_I18NTABLE, RPM_STRING_ARRAY_TYPE,
1573
table = findEntry(h, HEADER_I18NTABLE, RPM_STRING_ARRAY_TYPE);
1578
if (!lang) lang = "C";
1580
{ const char * l = table->data;
1581
for (langNum = 0; langNum < table->info.count; langNum++) {
1582
if (!strcmp(l, lang)) break;
1587
if (langNum >= table->info.count) {
1588
length = strlen(lang) + 1;
1589
if (ENTRY_IN_REGION(table)) {
1590
char * t = xmalloc(table->length + length);
1591
memcpy(t, table->data, table->length);
1593
table->info.offset = 0;
1595
table->data = xrealloc(table->data, table->length + length);
1596
memmove(((char *)table->data) + table->length, lang, length);
1597
table->length += length;
1598
table->info.count++;
1602
strArray = alloca(sizeof(*strArray) * (langNum + 1));
1603
for (i = 0; i < langNum; i++)
1605
strArray[langNum] = string;
1606
return headerAddEntry(h, tag, RPM_I18NSTRING_TYPE, strArray,
1608
} else if (langNum >= entry->info.count) {
1609
ghosts = langNum - entry->info.count;
1611
length = strlen(string) + 1 + ghosts;
1612
if (ENTRY_IN_REGION(entry)) {
1613
char * t = xmalloc(entry->length + length);
1614
memcpy(t, entry->data, entry->length);
1616
entry->info.offset = 0;
1618
entry->data = xrealloc(entry->data, entry->length + length);
1620
memset(((char *)entry->data) + entry->length, '\0', ghosts);
1621
memmove(((char *)entry->data) + entry->length + ghosts, string, strlen(string)+1);
1623
entry->length += length;
1624
entry->info.count = langNum + 1;
1626
char *b, *be, *e, *ee, *t;
1629
/* Set beginning/end pointers to previous data */
1630
b = be = e = ee = entry->data;
1631
for (i = 0; i < table->info.count; i++) {
1634
ee += strlen(ee) + 1;
1639
/* Get storage for new buffer */
1641
sn = strlen(string) + 1;
1643
length = bn + sn + en;
1644
t = buf = xmalloc(length);
1646
/* Copy values into new storage */
1649
memcpy(t, string, sn);
1654
/* Replace I18N string array */
1655
entry->length -= strlen(be) + 1;
1656
entry->length += sn;
1658
if (ENTRY_IN_REGION(entry)) {
1659
entry->info.offset = 0;
1661
entry->data = _free(entry->data);
1662
/*@-dependenttrans@*/
1664
/*@=dependenttrans@*/
1670
int headerModifyEntry(Header h, int_32 tag, int_32 type, hPTR_t p, int_32 c)
1675
/* First find the tag */
1676
entry = findEntry(h, tag, type);
1680
/* make sure entry points to the first occurence of this tag */
1681
while (entry > h->index && (entry - 1)->info.tag == tag)
1684
/* free after we've grabbed the new data in case the two are intertwined;
1685
that's a bad idea but at least we won't break */
1686
oldData = entry->data;
1688
entry->info.count = c;
1689
entry->info.type = type;
1690
entry->data = grabData(type, p, c, &entry->length);
1692
if (ENTRY_IN_REGION(entry)) {
1693
entry->info.offset = 0;
1695
oldData = _free(oldData);
1700
int headerRemoveEntry(Header h, int_32 tag)
1702
indexEntry last = h->index + h->indexUsed;
1703
indexEntry entry, first;
1706
entry = findEntry(h, tag, RPM_NULL_TYPE);
1707
if (!entry) return 1;
1709
/* Make sure entry points to the first occurence of this tag. */
1710
while (entry > h->index && (entry - 1)->info.tag == tag)
1713
/* Free data for tags being removed. */
1714
for (first = entry; first < last; first++) {
1716
if (first->info.tag != tag)
1721
if (ENTRY_IN_REGION(first))
1726
ne = (first - entry);
1731
memmove(entry, first, (ne * sizeof(*entry)));
1739
static char escapedChar(const char ch) /*@*/
1742
case 'a': return '\a';
1743
case 'b': return '\b';
1744
case 'f': return '\f';
1745
case 'n': return '\n';
1746
case 'r': return '\r';
1747
case 't': return '\t';
1748
case 'v': return '\v';
1754
* Destroy headerSprintf format array.
1755
* @param format sprintf format array
1756
* @param num number of elements
1757
* @return NULL always
1759
static /*@null@*/ sprintfToken
1760
freeFormat( /*@only@*/ /*@null@*/ sprintfToken format, int num)
1761
/*@modifies *format @*/
1765
if (format == NULL) return NULL;
1766
for (i = 0; i < num; i++) {
1767
switch (format[i].type) {
1769
format[i].u.array.format =
1770
freeFormat(format[i].u.array.format,
1771
format[i].u.array.numTokens);
1774
format[i].u.cond.ifFormat =
1775
freeFormat(format[i].u.cond.ifFormat,
1776
format[i].u.cond.numIfTokens);
1777
format[i].u.cond.elseFormat =
1778
freeFormat(format[i].u.cond.elseFormat,
1779
format[i].u.cond.numElseTokens);
1788
format = _free(format);
1794
static void findTag(char * name, const headerTagTableEntry tags,
1795
const headerSprintfExtension extensions,
1796
/*@out@*/ headerTagTableEntry * tagMatch,
1797
/*@out@*/ headerSprintfExtension * extMatch)
1798
/*@modifies *tagMatch, *extMatch @*/
1800
headerTagTableEntry entry;
1801
headerSprintfExtension ext;
1802
const char * tagname;
1807
if (strncmp("RPMTAG_", name, sizeof("RPMTAG_")-1)) {
1808
char * t = alloca(strlen(name) + sizeof("RPMTAG_"));
1809
(void) stpcpy( stpcpy(t, "RPMTAG_"), name);
1815
/* Search extensions first to permit overriding header tags. */
1817
while (ext->type != HEADER_EXT_LAST) {
1818
if (ext->name != NULL && ext->type == HEADER_EXT_TAG
1819
&& !xstrcasecmp(ext->name, tagname))
1822
if (ext->type == HEADER_EXT_MORE)
1828
if (ext->type == HEADER_EXT_TAG) {
1833
/* Search header tags. */
1834
for (entry = tags; entry->name; entry++)
1835
if (entry->name && !xstrcasecmp(entry->name, tagname))
1845
static int parseExpression(sprintfToken token, char * str,
1846
const headerTagTableEntry tags,
1847
const headerSprintfExtension extensions,
1848
/*@out@*/char ** endPtr, /*@null@*/ /*@out@*/ errmsg_t * errmsg)
1849
/*@modifies str, *str, *token, *endPtr, *errmsg @*/;
1853
static int parseFormat(char * str, const headerTagTableEntry tags,
1854
const headerSprintfExtension extensions,
1855
/*@out@*/sprintfToken * formatPtr, /*@out@*/int * numTokensPtr,
1856
/*@null@*/ /*@out@*/ char ** endPtr, int state,
1857
/*@null@*/ /*@out@*/ errmsg_t * errmsg)
1858
/*@modifies str, *str, *formatPtr, *numTokensPtr, *endPtr, *errmsg @*/
1860
char * chptr, * start, * next, * dst;
1861
sprintfToken format;
1864
headerTagTableEntry tag;
1865
headerSprintfExtension ext;
1869
/* upper limit on number of individual formats */
1871
for (chptr = str; *chptr != '\0'; chptr++)
1872
if (*chptr == '%') numTokens++;
1873
numTokens = numTokens * 2 + 1;
1875
format = xcalloc(numTokens, sizeof(*format));
1876
if (endPtr) *endPtr = NULL;
1881
while (*start != '\0') {
1885
if (*(start + 1) == '%') {
1886
if (currToken < 0 || format[currToken].type != PTOK_STRING) {
1888
format[currToken].type = PTOK_STRING;
1889
/*@-temptrans -assignexpose@*/
1890
dst = format[currToken].u.string.string = start;
1891
/*@=temptrans =assignexpose@*/
1898
break; /* out of switch */
1905
if (*start == '|') {
1909
if (parseExpression(format + currToken, start, tags,
1910
extensions, &newEnd, errmsg))
1912
format = freeFormat(format, numTokens);
1916
break; /* out of switch */
1920
format[currToken].u.tag.format = start;
1922
format[currToken].u.tag.pad = 0;
1923
format[currToken].u.tag.justOne = 0;
1924
format[currToken].u.tag.arrayCount = 0;
1927
while (*chptr && *chptr != '{' && *chptr != '%') chptr++;
1928
if (!*chptr || *chptr == '%') {
1929
/*@-observertrans -readonlytrans@*/
1930
if (errmsg) *errmsg = _("missing { after %");
1931
/*@=observertrans =readonlytrans@*/
1932
format = freeFormat(format, numTokens);
1938
while (start < chptr) {
1939
if (xisdigit(*start)) {
1940
i = strtoul(start, &start, 10);
1941
format[currToken].u.tag.pad += i;
1947
if (*start == '=') {
1948
format[currToken].u.tag.justOne = 1;
1950
} else if (*start == '#') {
1951
format[currToken].u.tag.justOne = 1;
1952
format[currToken].u.tag.arrayCount = 1;
1957
while (*next && *next != '}') next++;
1959
/*@-observertrans -readonlytrans@*/
1960
if (errmsg) *errmsg = _("missing } after %{");
1961
/*@=observertrans =readonlytrans@*/
1962
format = freeFormat(format, numTokens);
1968
while (*chptr && *chptr != ':') chptr++;
1970
if (*chptr != '\0') {
1973
/*@-observertrans -readonlytrans@*/
1974
if (errmsg) *errmsg = _("empty tag format");
1975
/*@=observertrans =readonlytrans@*/
1976
format = freeFormat(format, numTokens);
1980
format[currToken].u.tag.type = chptr;
1983
format[currToken].u.tag.type = NULL;
1987
/*@-observertrans -readonlytrans@*/
1988
if (errmsg) *errmsg = _("empty tag name");
1989
/*@=observertrans =readonlytrans@*/
1990
format = freeFormat(format, numTokens);
1995
findTag(start, tags, extensions, &tag, &ext);
1998
format[currToken].u.tag.ext = NULL;
1999
format[currToken].u.tag.tag = tag->val;
2001
format[currToken].u.tag.ext = ext->u.tagFunction;
2002
format[currToken].u.tag.extNum = ext - extensions;
2004
/*@-observertrans -readonlytrans@*/
2005
if (errmsg) *errmsg = _("unknown tag");
2006
/*@=observertrans =readonlytrans@*/
2007
format = freeFormat(format, numTokens);
2011
format[currToken].type = PTOK_TAG;
2022
if (parseFormat(start, tags, extensions,
2023
&format[currToken].u.array.format,
2024
&format[currToken].u.array.numTokens,
2025
&start, PARSER_IN_ARRAY, errmsg)) {
2026
format = freeFormat(format, numTokens);
2031
/*@-observertrans -readonlytrans@*/
2032
if (errmsg) *errmsg = _("] expected at end of array");
2033
/*@=observertrans =readonlytrans@*/
2034
format = freeFormat(format, numTokens);
2040
format[currToken].type = PTOK_ARRAY;
2046
if ((*start == ']' && state != PARSER_IN_ARRAY) ||
2047
(*start == '}' && state != PARSER_IN_EXPR)) {
2048
if (*start == ']') {
2049
/*@-observertrans -readonlytrans@*/
2050
if (errmsg) *errmsg = _("unexpected ]");
2051
/*@=observertrans =readonlytrans@*/
2053
/*@-observertrans -readonlytrans@*/
2054
if (errmsg) *errmsg = _("unexpected }");
2055
/*@=observertrans =readonlytrans@*/
2057
format = freeFormat(format, numTokens);
2061
if (endPtr) *endPtr = start;
2066
if (currToken < 0 || format[currToken].type != PTOK_STRING) {
2068
format[currToken].type = PTOK_STRING;
2069
/*@-temptrans -assignexpose@*/
2070
dst = format[currToken].u.string.string = start;
2071
/*@=temptrans =assignexpose@*/
2074
if (*start == '\\') {
2076
*dst++ = escapedChar(*start++);
2090
for (i = 0; i < currToken; i++) {
2091
if (format[i].type == PTOK_STRING)
2092
format[i].u.string.len = strlen(format[i].u.string.string);
2095
*numTokensPtr = currToken;
2096
*formatPtr = format;
2103
static int parseExpression(sprintfToken token, char * str,
2104
const headerTagTableEntry tags,
2105
const headerSprintfExtension extensions,
2106
/*@out@*/ char ** endPtr,
2107
/*@null@*/ /*@out@*/ errmsg_t * errmsg)
2109
headerTagTableEntry tag;
2110
headerSprintfExtension ext;
2114
if (errmsg) *errmsg = NULL;
2116
while (*chptr && *chptr != '?') chptr++;
2118
if (*chptr != '?') {
2119
/*@-observertrans -readonlytrans@*/
2120
if (errmsg) *errmsg = _("? expected in expression");
2121
/*@=observertrans =readonlytrans@*/
2127
if (*chptr != '{') {
2128
/*@-observertrans -readonlytrans@*/
2129
if (errmsg) *errmsg = _("{ expected after ? in expression");
2130
/*@=observertrans =readonlytrans@*/
2136
if (parseFormat(chptr, tags, extensions, &token->u.cond.ifFormat,
2137
&token->u.cond.numIfTokens, &end, PARSER_IN_EXPR, errmsg))
2141
/*@-observertrans -readonlytrans@*/
2142
if (errmsg) *errmsg = _("} expected in expression");
2143
/*@=observertrans =readonlytrans@*/
2144
token->u.cond.ifFormat =
2145
freeFormat(token->u.cond.ifFormat, token->u.cond.numIfTokens);
2150
if (*chptr != ':' && *chptr != '|') {
2151
/*@-observertrans -readonlytrans@*/
2152
if (errmsg) *errmsg = _(": expected following ? subexpression");
2153
/*@=observertrans =readonlytrans@*/
2154
token->u.cond.ifFormat =
2155
freeFormat(token->u.cond.ifFormat, token->u.cond.numIfTokens);
2159
if (*chptr == '|') {
2160
(void) parseFormat(xstrdup(""), tags, extensions,
2161
&token->u.cond.elseFormat,
2162
&token->u.cond.numElseTokens, &end, PARSER_IN_EXPR,
2167
if (*chptr != '{') {
2168
/*@-observertrans -readonlytrans@*/
2169
if (errmsg) *errmsg = _("{ expected after : in expression");
2170
/*@=observertrans =readonlytrans@*/
2171
token->u.cond.ifFormat =
2172
freeFormat(token->u.cond.ifFormat, token->u.cond.numIfTokens);
2178
if (parseFormat(chptr, tags, extensions, &token->u.cond.elseFormat,
2179
&token->u.cond.numElseTokens, &end, PARSER_IN_EXPR,
2183
/*@-observertrans -readonlytrans@*/
2184
if (errmsg) *errmsg = _("} expected in expression");
2185
/*@=observertrans =readonlytrans@*/
2186
token->u.cond.ifFormat =
2187
freeFormat(token->u.cond.ifFormat, token->u.cond.numIfTokens);
2192
if (*chptr != '|') {
2193
/*@-observertrans -readonlytrans@*/
2194
if (errmsg) *errmsg = _("| expected at end of expression");
2195
/*@=observertrans =readonlytrans@*/
2196
token->u.cond.ifFormat =
2197
freeFormat(token->u.cond.ifFormat, token->u.cond.numIfTokens);
2198
token->u.cond.elseFormat =
2199
freeFormat(token->u.cond.elseFormat, token->u.cond.numElseTokens);
2208
findTag(str, tags, extensions, &tag, &ext);
2211
token->u.cond.tag.ext = NULL;
2212
token->u.cond.tag.tag = tag->val;
2214
token->u.cond.tag.ext = ext->u.tagFunction;
2215
token->u.cond.tag.extNum = ext - extensions;
2217
token->u.cond.tag.ext = NULL;
2218
token->u.cond.tag.tag = -1;
2221
token->type = PTOK_COND;
2227
* @return 0 on success, 1 on failure
2229
static int getExtension(Header h, headerTagTagFunction fn,
2230
/*@out@*/ hTYP_t typeptr,
2231
/*@out@*/ hPTR_t * data,
2232
/*@out@*/ hCNT_t countptr,
2234
/*@modifies *typeptr, *data, *countptr, ext @*/
2237
if (fn(h, &ext->type, &ext->data, &ext->count, &ext->freeit))
2242
if (typeptr) *typeptr = ext->type;
2243
if (data) *data = ext->data;
2244
if (countptr) *countptr = ext->count;
2251
static char * formatValue(sprintfTag tag, Header h,
2252
const headerSprintfExtension extensions,
2253
extensionCache extCache, int element)
2254
/*@modifies extCache @*/
2260
unsigned int intVal;
2262
const char ** strarray;
2265
headerTagFormatFunction tagtype = NULL;
2266
headerSprintfExtension ext;
2268
memset(buf, 0, sizeof(buf));
2270
if (getExtension(h, tag->ext, &type, &data, &count,
2271
extCache + tag->extNum))
2274
type = RPM_STRING_TYPE;
2275
data = "(none)"; /* XXX i18n? NO!, sez; gafton */
2278
if (!headerGetEntry(h, tag->tag, &type, (void **)&data, &count)) {
2280
type = RPM_STRING_TYPE;
2281
data = "(none)"; /* XXX i18n? NO!, sez; gafton */
2287
if (tag->arrayCount) {
2288
/*@-observertrans -modobserver@*/
2289
data = headerFreeData(data, type);
2290
/*@=observertrans =modobserver@*/
2295
type = RPM_INT32_TYPE;
2298
(void) stpcpy( stpcpy(buf, "%"), tag->format);
2302
while (ext->type != HEADER_EXT_LAST) {
2303
if (ext->name != NULL && ext->type == HEADER_EXT_FORMAT
2304
&& !strcmp(ext->name, tag->type))
2306
tagtype = ext->u.formatFunction;
2310
if (ext->type == HEADER_EXT_MORE)
2318
case RPM_STRING_ARRAY_TYPE:
2319
strarray = (const char **)data;
2322
val = tagtype(RPM_STRING_TYPE, strarray[element], buf, tag->pad, 0);
2327
len = strlen(strarray[element]) + tag->pad + 20;
2330
sprintf(val, buf, strarray[element]);
2334
/*@-observertrans -modobserver@*/
2335
if (mayfree) data = _free(data);
2336
/*@=observertrans =modobserver@*/
2340
case RPM_STRING_TYPE:
2342
val = tagtype(RPM_STRING_ARRAY_TYPE, data, buf, tag->pad, 0);
2347
len = strlen(data) + tag->pad + 20;
2350
sprintf(val, buf, data);
2357
case RPM_INT16_TYPE:
2358
case RPM_INT32_TYPE:
2361
case RPM_INT8_TYPE: intVal = *(((int_8 *) data) + element); break;
2362
case RPM_INT16_TYPE: intVal = *(((uint_16 *) data) + element); break;
2363
default: /* keep -Wall quiet */
2364
case RPM_INT32_TYPE: intVal = *(((int_32 *) data) + element); break;
2368
val = tagtype(RPM_INT32_TYPE, &intVal, buf, tag->pad, element);
2372
len = 10 + tag->pad + 20;
2375
sprintf(val, buf, intVal);
2381
val = xstrdup(_("(unknown type)"));
2390
static const char * singleSprintf(Header h, sprintfToken token,
2391
const headerSprintfExtension extensions,
2392
extensionCache extCache, int element)
2393
/*@modifies h, extCache @*/
2396
const char * thisItem;
2402
sprintfToken condFormat;
2405
/* we assume the token and header have been validated already! */
2407
switch (token->type) {
2412
val = xmalloc(token->u.string.len + 1);
2413
strcpy(val, token->u.string.string);
2417
val = formatValue(&token->u.tag, h, extensions, extCache,
2418
token->u.tag.justOne ? 0 : element);
2422
if (token->u.cond.tag.ext ||
2423
headerIsEntry(h, token->u.cond.tag.tag)) {
2424
condFormat = token->u.cond.ifFormat;
2425
condNumFormats = token->u.cond.numIfTokens;
2427
condFormat = token->u.cond.elseFormat;
2428
condNumFormats = token->u.cond.numElseTokens;
2431
alloced = condNumFormats * 20;
2432
val = xmalloc(alloced ? alloced : 1);
2437
for (i = 0; i < condNumFormats; i++) {
2438
thisItem = singleSprintf(h, condFormat + i,
2439
extensions, extCache, element);
2440
thisItemLen = strlen(thisItem);
2441
if ((thisItemLen + len) >= alloced) {
2442
alloced = (thisItemLen + len) + 200;
2443
val = xrealloc(val, alloced);
2445
strcat(val, thisItem);
2447
thisItem = _free(thisItem);
2454
for (i = 0; i < token->u.array.numTokens; i++) {
2455
if (token->u.array.format[i].type != PTOK_TAG ||
2456
token->u.array.format[i].u.tag.arrayCount ||
2457
token->u.array.format[i].u.tag.justOne) continue;
2459
if (token->u.array.format[i].u.tag.ext) {
2461
if (getExtension(h, token->u.array.format[i].u.tag.ext,
2462
&type, &data, &numElements,
2464
token->u.array.format[i].u.tag.extNum))
2467
if (!headerGetEntry(h, token->u.array.format[i].u.tag.tag,
2468
&type, (void **) &val, &numElements))
2470
val = headerFreeData(val, type);
2472
/*@loopbreak@*/ break;
2475
if (numElements == -1) {
2476
val = xstrdup("(none)"); /* XXX i18n? NO!, sez; gafton */
2478
alloced = numElements * token->u.array.numTokens * 20;
2479
val = xmalloc(alloced);
2483
for (j = 0; j < numElements; j++) {
2484
for (i = 0; i < token->u.array.numTokens; i++) {
2485
thisItem = singleSprintf(h, token->u.array.format + i,
2486
extensions, extCache, j);
2487
thisItemLen = strlen(thisItem);
2488
if ((thisItemLen + len) >= alloced) {
2489
alloced = (thisItemLen + len) + 200;
2490
val = xrealloc(val, alloced);
2492
strcat(val, thisItem);
2494
thisItem = _free(thisItem);
2507
static /*@only@*/ extensionCache
2508
allocateExtensionCache(const headerSprintfExtension extensions)
2511
headerSprintfExtension ext = extensions;
2514
while (ext->type != HEADER_EXT_LAST) {
2516
if (ext->type == HEADER_EXT_MORE)
2522
return xcalloc(i, sizeof(struct extensionCache));
2526
* @return NULL always
2528
static /*@null@*/ extensionCache
2529
freeExtensionCache(const headerSprintfExtension extensions,
2530
/*@only@*/ extensionCache cache)
2533
headerSprintfExtension ext = extensions;
2536
while (ext->type != HEADER_EXT_LAST) {
2537
if (cache[i].freeit) cache[i].data = _free(cache[i].data);
2540
if (ext->type == HEADER_EXT_MORE)
2546
cache = _free(cache);
2550
char * headerSprintf(Header h, const char * fmt,
2551
const struct headerTagTableEntry_s * tabletags,
2552
const struct headerSprintfExtension_s * extensions,
2555
/*@-castexpose@*/ /* FIX: legacy API shouldn't change. */
2556
headerSprintfExtension exts = (headerSprintfExtension) extensions;
2557
headerTagTableEntry tags = (headerTagTableEntry) tabletags;
2560
sprintfToken format;
2566
extensionCache extCache;
2568
/*fmtString = escapeString(fmt);*/
2569
fmtString = xstrdup(fmt);
2571
if (parseFormat(fmtString, tags, exts, &format, &numTokens,
2572
NULL, PARSER_BEGIN, errmsg)) {
2573
fmtString = _free(fmtString);
2577
extCache = allocateExtensionCache(exts);
2579
answerAlloced = 1024;
2581
answer = xmalloc(answerAlloced);
2584
for (i = 0; i < numTokens; i++) {
2589
piece = singleSprintf(h, format + i, exts, extCache, 0);
2592
pieceLength = strlen(piece);
2593
if ((answerLength + pieceLength) >= answerAlloced) {
2594
while ((answerLength + pieceLength) >= answerAlloced)
2595
answerAlloced += 1024;
2596
answer = xrealloc(answer, answerAlloced);
2599
strcat(answer, piece);
2600
answerLength += pieceLength;
2601
piece = _free(piece);
2605
fmtString = _free(fmtString);
2606
extCache = freeExtensionCache(exts, extCache);
2607
format = _free(format);
2614
static char * octalFormat(int_32 type, hPTR_t data,
2615
char * formatPrefix, int padding, /*@unused@*/int element)
2616
/*@modifies formatPrefix @*/
2620
if (type != RPM_INT32_TYPE) {
2621
val = xstrdup(_("(not a number)"));
2623
val = xmalloc(20 + padding);
2624
strcat(formatPrefix, "o");
2626
sprintf(val, formatPrefix, *((int_32 *) data));
2635
static char * hexFormat(int_32 type, hPTR_t data,
2636
char * formatPrefix, int padding, /*@unused@*/int element)
2637
/*@modifies formatPrefix @*/
2641
if (type != RPM_INT32_TYPE) {
2642
val = xstrdup(_("(not a number)"));
2644
val = xmalloc(20 + padding);
2645
strcat(formatPrefix, "x");
2647
sprintf(val, formatPrefix, *((int_32 *) data));
2656
static char * realDateFormat(int_32 type, hPTR_t data,
2657
char * formatPrefix, int padding, /*@unused@*/int element,
2658
const char * strftimeFormat)
2659
/*@modifies formatPrefix @*/
2663
if (type != RPM_INT32_TYPE) {
2664
val = xstrdup(_("(not a number)"));
2666
struct tm * tstruct;
2669
val = xmalloc(50 + padding);
2670
strcat(formatPrefix, "s");
2672
/* this is important if sizeof(int_32) ! sizeof(time_t) */
2673
{ time_t dateint = *((int_32 *) data);
2674
tstruct = localtime(&dateint);
2678
(void) strftime(buf, sizeof(buf) - 1, strftimeFormat, tstruct);
2680
sprintf(val, formatPrefix, buf);
2689
static char * dateFormat(int_32 type, hPTR_t data,
2690
char * formatPrefix, int padding, int element)
2691
/*@modifies formatPrefix @*/
2693
return realDateFormat(type, data, formatPrefix, padding, element, "%c");
2698
static char * dayFormat(int_32 type, hPTR_t data,
2699
char * formatPrefix, int padding, int element)
2700
/*@modifies formatPrefix @*/
2702
return realDateFormat(type, data, formatPrefix, padding, element,
2708
static char * shescapeFormat(int_32 type, hPTR_t data,
2709
char * formatPrefix, int padding, /*@unused@*/int element)
2710
/*@modifies formatPrefix @*/
2712
char * result, * dst, * src, * buf;
2714
if (type == RPM_INT32_TYPE) {
2715
result = xmalloc(padding + 20);
2716
strcat(formatPrefix, "d");
2718
sprintf(result, formatPrefix, *((int_32 *) data));
2721
buf = alloca(strlen(data) + padding + 2);
2722
strcat(formatPrefix, "s");
2724
sprintf(buf, formatPrefix, data);
2727
result = dst = xmalloc(strlen(buf) * 4 + 3);
2729
for (src = buf; *src != '\0'; src++) {
2747
const struct headerSprintfExtension_s headerDefaultFormats[] = {
2748
{ HEADER_EXT_FORMAT, "octal", { octalFormat } },
2749
{ HEADER_EXT_FORMAT, "hex", { hexFormat } },
2750
{ HEADER_EXT_FORMAT, "date", { dateFormat } },
2751
{ HEADER_EXT_FORMAT, "day", { dayFormat } },
2752
{ HEADER_EXT_FORMAT, "shescape", { shescapeFormat } },
2753
{ HEADER_EXT_LAST, NULL, { NULL } }
2756
void headerCopyTags(Header headerFrom, Header headerTo, hTAG_t tagstocopy)
2760
if (headerFrom == headerTo)
2763
for (p = tagstocopy; *p != 0; p++) {
2767
if (headerIsEntry(headerTo, *p))
2769
if (!headerGetEntryMinMemory(headerFrom, *p, &type,
2770
(hPTR_t *) &s, &count))
2772
(void) headerAddEntry(headerTo, *p, type, s, count);
2773
s = headerFreeData(s, type);
2778
* Header tag iterator data structure.
2780
struct headerIteratorS {
2781
/*@unused@*/ Header h; /*!< Header being iterated. */
2782
/*@unused@*/ int next_index; /*!< Next tag index. */
2785
HeaderIterator headerFreeIterator(HeaderIterator hi)
2787
hi->h = headerFree(hi->h);
2792
HeaderIterator headerInitIterator(Header h)
2794
HeaderIterator hi = xmalloc(sizeof(struct headerIteratorS));
2798
hi->h = headerLink(h);
2803
int headerNextIterator(HeaderIterator hi,
2804
hTAG_t tag, hTYP_t type, hPTR_t * p, hCNT_t c)
2807
int slot = hi->next_index;
2808
indexEntry entry = NULL;
2811
for (slot = hi->next_index; slot < h->indexUsed; slot++) {
2812
entry = h->index + slot;
2813
if (!ENTRY_IS_REGION(entry))
2816
hi->next_index = slot;
2817
if (entry == NULL || slot >= h->indexUsed)
2819
/*@-noeffect@*/ /* LCL: no clue */
2824
*tag = entry->info.tag;
2826
rc = copyEntry(entry, type, p, c, 0);
2828
/* XXX 1 on success */
2829
return ((rc == 1) ? 1 : 0);
2831
static struct HV_s hdrVec1 = {
2848
headerGetEntryMinMemory,
2851
headerAddOrAppendEntry,
2852
headerAddI18NString,
2864
/*@-compmempass -redef@*/
2865
HV_t hdrVec = &hdrVec1;
2866
/*@=compmempass =redef@*/