Bug Summary

File:libs/libtpl-1.5/src/tpl.c
Location:line 802, column 14
Description:Access to field 'next' results in a dereference of a null pointer (loaded from variable 'bb')

Annotated Source Code

1/*
2Copyright (c) 2005-2010, Troy D. Hanson http://tpl.sourceforge.net
3All rights reserved.
4
5Redistribution and use in source and binary forms, with or without
6modification, are permitted provided that the following conditions are met:
7
8 * Redistributions of source code must retain the above copyright
9 notice, this list of conditions and the following disclaimer.
10
11THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS
12IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
13TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A
14PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER
15OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
16EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
17PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
18PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
19LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
20NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
21SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
22*/
23
24#define TPL_VERSION1.5 1.5
25
26//static const char id[]="$Id: tpl.c 192 2009-04-24 10:35:30Z thanson $";
27
28
29#include <stdlib.h> /* malloc */
30#include <stdarg.h> /* va_list */
31#include <string.h> /* memcpy, memset, strchr */
32#include <stdio.h> /* printf (tpl_hook.oops default function) */
33
34#ifndef _WIN32
35#include <unistd.h> /* for ftruncate */
36#else
37#include <io.h>
38#define ftruncate(x,y) _chsize(x,y)
39#endif
40#include <sys/types.h> /* for 'open' */
41#include <sys/stat.h> /* for 'open' */
42#include <fcntl.h> /* for 'open' */
43#include <errno(*__errno_location ()).h>
44#ifndef _WIN32
45#include <inttypes.h> /* uint32_t, uint64_t, etc */
46#else
47typedef unsigned short ushort;
48typedef __int16 int16_t;
49typedef __int32 int32_t;
50typedef __int64 int64_t;
51typedef unsigned __int16 uint16_t;
52typedef unsigned __int32 uint32_t;
53typedef unsigned __int64 uint64_t;
54#endif
55
56
57#if ( defined __CYGWIN__ || defined __MINGW32__ || defined _WIN32 )
58#include "win/mman.h" /* mmap */
59#else
60#include <sys/mman.h> /* mmap */
61#endif
62
63#include "tpl.h"
64
65#define TPL_GATHER_BUFLEN8192 8192
66#define TPL_MAGIC"tpl" "tpl"
67
68/* macro to add a structure to a doubly-linked list */
69#define DL_ADD(head,add)do { if (head) { (add)->prev = (head)->prev; (head)->
prev->next = (add); (head)->prev = (add); (add)->next
= ((void*)0); } else { (head)=(add); (head)->prev = (head
); (head)->next = ((void*)0); } } while (0);
\
70 do { \
71 if (head) { \
72 (add)->prev = (head)->prev; \
73 (head)->prev->next = (add); \
74 (head)->prev = (add); \
75 (add)->next = NULL((void*)0); \
76 } else { \
77 (head)=(add); \
78 (head)->prev = (head); \
79 (head)->next = NULL((void*)0); \
80 } \
81 } while (0);
82
83#define fatal_oom()tpl_hook.fatal("out of memory\n") tpl_hook.fatal("out of memory\n")
84
85/* bit flags (internal). preceded by the external flags in tpl.h */
86#define TPL_WRONLY(1 << 9) (1 << 9) /* app has initiated tpl packing */
87#define TPL_RDONLY(1 << 10) (1 << 10) /* tpl was loaded (for unpacking) */
88#define TPL_XENDIAN(1 << 11) (1 << 11) /* swap endianness when unpacking */
89#define TPL_OLD_STRING_FMT(1 << 12) (1 << 12) /* tpl has strings in 1.2 format */
90
91/* values for the flags byte that appears after the magic prefix */
92#define TPL_SUPPORTED_BITFLAGS3 3
93#define TPL_FL_BIGENDIAN(1 << 0) (1 << 0)
94#define TPL_FL_NULLSTRINGS(1 << 1) (1 << 1)
95
96/* char values for node type */
97#define TPL_TYPE_ROOT0 0
98#define TPL_TYPE_INT321 1
99#define TPL_TYPE_UINT322 2
100#define TPL_TYPE_BYTE3 3
101#define TPL_TYPE_STR4 4
102#define TPL_TYPE_ARY5 5
103#define TPL_TYPE_BIN6 6
104#define TPL_TYPE_DOUBLE7 7
105#define TPL_TYPE_INT648 8
106#define TPL_TYPE_UINT649 9
107#define TPL_TYPE_INT1610 10
108#define TPL_TYPE_UINT1611 11
109#define TPL_TYPE_POUND12 12
110
111/* error codes */
112#define ERR_NOT_MINSIZE(-1) (-1)
113#define ERR_MAGIC_MISMATCH(-2) (-2)
114#define ERR_INCONSISTENT_SZ(-3) (-3)
115#define ERR_FMT_INVALID(-4) (-4)
116#define ERR_FMT_MISSING_NUL(-5) (-5)
117#define ERR_FMT_MISMATCH(-6) (-6)
118#define ERR_FLEN_MISMATCH(-7) (-7)
119#define ERR_INCONSISTENT_SZ2(-8) (-8)
120#define ERR_INCONSISTENT_SZ3(-9) (-9)
121#define ERR_INCONSISTENT_SZ4(-10) (-10)
122#define ERR_UNSUPPORTED_FLAGS(-11) (-11)
123
124/* access to A(...) nodes by index */
125typedef struct tpl_pidx {
126 struct tpl_node *node;
127 struct tpl_pidx *next,*prev;
128} tpl_pidx;
129
130/* A(...) node datum */
131typedef struct tpl_atyp {
132 uint32_t num; /* num elements */
133 size_t sz; /* size of each backbone's datum */
134 struct tpl_backbone *bb,*bbtail;
135 void *cur;
136} tpl_atyp;
137
138/* backbone to extend A(...) lists dynamically */
139typedef struct tpl_backbone {
140 struct tpl_backbone *next;
141 /* when this structure is malloc'd, extra space is alloc'd at the
142 * end to store the backbone "datum", and data points to it. */
143#if __STDC_VERSION__199901L < 199901
144 char *data;
145#else
146 char data[];
147#endif
148} tpl_backbone;
149
150/* mmap record */
151typedef struct tpl_mmap_rec {
152 int fd;
153 void *text;
154 size_t text_sz;
155} tpl_mmap_rec;
156
157/* root node datum */
158typedef struct tpl_root_data {
159 int flags;
160 tpl_pidx *pidx;
161 tpl_mmap_rec mmap;
162 char *fmt;
163 int *fxlens, num_fxlens;
164} tpl_root_data;
165
166/* node type to size mapping */
167struct tpl_type_t {
168 char c;
169 int sz;
170};
171
172
173/* Internal prototypes */
174static tpl_node *tpl_node_new(tpl_node *parent);
175static tpl_node *tpl_find_i(tpl_node *n, int i);
176static void *tpl_cpv(void *datav, void *data, size_t sz);
177static void *tpl_extend_backbone(tpl_node *n);
178static char *tpl_fmt(tpl_node *r);
179static void *tpl_dump_atyp(tpl_node *n, tpl_atyp* at, void *dv);
180static size_t tpl_ser_osz(tpl_node *n);
181static void tpl_free_atyp(tpl_node *n,tpl_atyp *atyp);
182static int tpl_dump_to_mem(tpl_node *r, void *addr, size_t sz);
183static int tpl_mmap_file(char *filename, tpl_mmap_rec *map_rec);
184static int tpl_mmap_output_file(char *filename, size_t sz, void **text_out);
185static int tpl_cpu_bigendian(void);
186static int tpl_needs_endian_swap(void *);
187static void tpl_byteswap(void *word, int len);
188static void tpl_fatal(char *fmt, ...);
189static int tpl_serlen(tpl_node *r, tpl_node *n, void *dv, size_t *serlen);
190static int tpl_unpackA0(tpl_node *r);
191static int tpl_oops(const char *fmt, ...);
192static int tpl_gather_mem( char *buf, size_t len, tpl_gather_t **gs, tpl_gather_cb *cb, void *data);
193static int tpl_gather_nonblocking( int fd, tpl_gather_t **gs, tpl_gather_cb *cb, void *data);
194static int tpl_gather_blocking(int fd, void **img, size_t *sz);
195static tpl_node *tpl_map_va(char *fmt, va_list ap);
196
197/* This is used internally to help calculate padding when a 'double'
198 * follows a smaller datatype in a structure. Normally under gcc
199 * on x86, d will be aligned at +4, however use of -malign-double
200 * causes d to be aligned at +8 (this is actually faster on x86).
201 * Also SPARC and x86_64 seem to align always on +8.
202 */
203struct tpl_double_alignment_detector {
204 char a;
205 double d; /* some platforms align this on +4, others on +8 */
206};
207
208/* this is another case where alignment varies. mac os x/gcc was observed
209 * to align the int64_t at +4 under -m32 and at +8 under -m64 */
210struct tpl_int64_alignment_detector {
211 int i;
212 int64_t j; /* some platforms align this on +4, others on +8 */
213};
214
215typedef struct {
216 size_t inter_elt_len; /* padded inter-element len; i.e. &a[1].field - &a[0].field */
217 tpl_node *iter_start_node; /* node to jump back to, as we start each new iteration */
218 size_t iternum; /* current iteration number (total req'd. iter's in n->num) */
219} tpl_pound_data;
220
221/* Hooks for customizing tpl mem alloc, error handling, etc. Set defaults. */
222tpl_hook_t tpl_hook = {
223 /* .oops = */ tpl_oops,
224 /* .malloc = */ malloc,
225 /* .realloc = */ realloc,
226 /* .free = */ free,
227 /* .fatal = */ tpl_fatal,
228 /* .gather_max = */ 0 /* max tpl size (bytes) for tpl_gather */
229};
230
231static const char tpl_fmt_chars[] = "AS($)BiucsfIUjv#"; /* valid format chars */
232//static const char tpl_S_fmt_chars[] = "iucsfIUjv#$()"; /* valid within S(...) */
233static const char tpl_datapeek_ok_chars[] = "iucsfIUjv"; /* valid in datapeek */
234static const struct tpl_type_t tpl_types[] = {
235 /* [TPL_TYPE_ROOT] = */ {'r', 0},
236 /* [TPL_TYPE_INT32] = */ {'i', sizeof(int32_t)},
237 /* [TPL_TYPE_UINT32] = */ {'u', sizeof(uint32_t)},
238 /* [TPL_TYPE_BYTE] = */ {'c', sizeof(char)},
239 /* [TPL_TYPE_STR] = */ {'s', sizeof(char*)},
240 /* [TPL_TYPE_ARY] = */ {'A', 0},
241 /* [TPL_TYPE_BIN] = */ {'B', 0},
242 /* [TPL_TYPE_DOUBLE] = */ {'f', 8}, /* not sizeof(double) as that varies */
243 /* [TPL_TYPE_INT64] = */ {'I', sizeof(int64_t)},
244 /* [TPL_TYPE_UINT64] = */ {'U', sizeof(uint64_t)},
245 /* [TPL_TYPE_INT16] = */ {'j', sizeof(int16_t)},
246 /* [TPL_TYPE_UINT16] = */ {'v', sizeof(uint16_t)},
247 /* [TPL_TYPE_POUND] = */ {'#', 0},
248};
249
250/* default error-reporting function. Just writes to stderr. */
251static int tpl_oops(const char *fmt, ...) {
252 va_list ap;
253 va_start(ap,fmt)__builtin_va_start(ap, fmt);
254 vfprintf(stderrstderr,fmt,ap);
255 va_end(ap)__builtin_va_end(ap);
256 return 0;
257}
258
259
260static tpl_node *tpl_node_new(tpl_node *parent) {
261 tpl_node *n;
262 if ((n=tpl_hook.malloc(sizeof(tpl_node))) == NULL((void*)0)) {
263 fatal_oom()tpl_hook.fatal("out of memory\n");
264 }
265 n->addr=NULL((void*)0);
266 n->data=NULL((void*)0);
267 n->num=1;
268 n->ser_osz=0;
269 n->children=NULL((void*)0);
270 n->next=NULL((void*)0);
271 n->parent=parent;
272 return n;
273}
274
275/* Used in S(..) formats to pack several fields from a structure based on
276 * only the structure address. We need to calculate field addresses
277 * manually taking into account the size of the fields and intervening padding.
278 * The wrinkle is that double is not normally aligned on x86-32 but the
279 * -malign-double compiler option causes it to be. Double are aligned
280 * on Sparc, and apparently on 64 bit x86. We use a helper structure
281 * to detect whether double is aligned in this compilation environment.
282 */
283char *calc_field_addr(tpl_node *parent, int type,char *struct_addr, int ordinal) {
284 tpl_node *prev;
285 int offset;
286 int align_sz;
287
288 if (ordinal == 1) return struct_addr; /* first field starts on structure address */
289
290 /* generate enough padding so field addr is divisible by it's align_sz. 4, 8, etc */
291 prev = parent->children->prev;
292 switch(type) {
293 case TPL_TYPE_DOUBLE7:
294 align_sz = sizeof(struct tpl_double_alignment_detector) > 12 ? 8 : 4;
295 break;
296 case TPL_TYPE_INT648:
297 case TPL_TYPE_UINT649:
298 align_sz = sizeof(struct tpl_int64_alignment_detector) > 12 ? 8 : 4;
299 break;
300 default:
301 align_sz = tpl_types[type].sz;
302 break;
303 }
304 offset = ((uintptr_t)prev->addr - (uintptr_t)struct_addr)
305 + (tpl_types[prev->type].sz * prev->num);
306 offset = (offset + align_sz - 1) / align_sz * align_sz;
307 return struct_addr + offset;
308}
309
310TPL_API tpl_node *tpl_map(char *fmt,...) {
311 va_list ap;
312 tpl_node *tn;
313
314 va_start(ap,fmt)__builtin_va_start(ap, fmt);
315 tn = tpl_map_va(fmt, ap);
316 va_end(ap)__builtin_va_end(ap);
317 return tn;
318}
319
320static tpl_node *tpl_map_va(char *fmt, va_list ap) {
321 int lparen_level=0,expect_lparen=0,t=0,in_structure=0,ordinal=0;
322 int in_nested_structure=0;
323 char *c, *peek, *struct_addr=NULL((void*)0), *struct_next;
324 tpl_node *root,*parent,*n=NULL((void*)0),*preceding,*iter_start_node=NULL((void*)0),
325 *struct_widest_node=NULL((void*)0), *np; tpl_pidx *pidx;
326 tpl_pound_data *pd;
327 int *fxlens, num_fxlens, pound_num, pound_prod, applies_to_struct;
328 int contig_fxlens[10]; /* temp space for contiguous fxlens */
329 int num_contig_fxlens, i, j;
330 ptrdiff_t inter_elt_len=0; /* padded element length of contiguous structs in array */
331
332
333 root = tpl_node_new(NULL((void*)0));
334 root->type = TPL_TYPE_ROOT0;
335 root->data = (tpl_root_data*)tpl_hook.malloc(sizeof(tpl_root_data));
336 if (!root->data) fatal_oom()tpl_hook.fatal("out of memory\n");
337 memset((tpl_root_data*)root->data,0,sizeof(tpl_root_data));
338
339 /* set up root nodes special ser_osz to reflect overhead of preamble */
340 root->ser_osz = sizeof(uint32_t); /* tpl leading length */
341 root->ser_osz += strlen(fmt) + 1; /* fmt + NUL-terminator */
342 root->ser_osz += 4; /* 'tpl' magic prefix + flags byte */
343
344 parent=root;
345
346 c=fmt;
347 while (*c != '\0') {
348 switch (*c) {
349 case 'c':
350 case 'i':
351 case 'u':
352 case 'j':
353 case 'v':
354 case 'I':
355 case 'U':
356 case 'f':
357 if (*c=='c') t=TPL_TYPE_BYTE3;
358 else if (*c=='i') t=TPL_TYPE_INT321;
359 else if (*c=='u') t=TPL_TYPE_UINT322;
360 else if (*c=='j') t=TPL_TYPE_INT1610;
361 else if (*c=='v') t=TPL_TYPE_UINT1611;
362 else if (*c=='I') t=TPL_TYPE_INT648;
363 else if (*c=='U') t=TPL_TYPE_UINT649;
364 else if (*c=='f') t=TPL_TYPE_DOUBLE7;
365
366 if (expect_lparen) goto fail;
367 n = tpl_node_new(parent);
368 n->type = t;
369 if (in_structure) {
370 if (ordinal == 1) {
371 /* for S(...)# iteration. Apply any changes to case 's' too!!! */
372 iter_start_node = n;
373 struct_widest_node = n;
374 }
375 if (tpl_types[n->type].sz > tpl_types[struct_widest_node->type].sz) {
376 struct_widest_node = n;
377 }
378 n->addr = calc_field_addr(parent,n->type,struct_addr,ordinal++);
379 } else n->addr = (void*)va_arg(ap,void*)__builtin_va_arg(ap, void*);
380 n->data = tpl_hook.malloc(tpl_types[t].sz);
381 if (!n->data) fatal_oom()tpl_hook.fatal("out of memory\n");
382 if (n->parent->type == TPL_TYPE_ARY5)
383 ((tpl_atyp*)(n->parent->data))->sz += tpl_types[t].sz;
384 DL_ADD(parent->children,n)do { if (parent->children) { (n)->prev = (parent->children
)->prev; (parent->children)->prev->next = (n); (parent
->children)->prev = (n); (n)->next = ((void*)0); } else
{ (parent->children)=(n); (parent->children)->prev =
(parent->children); (parent->children)->next = ((void
*)0); } } while (0);
;
385 break;
386 case 's':
387 if (expect_lparen) goto fail;
388 n = tpl_node_new(parent);
389 n->type = TPL_TYPE_STR4;
390 if (in_structure) {
391 if (ordinal == 1) {
392 iter_start_node = n; /* for S(...)# iteration */
393 struct_widest_node = n;
394 }
395 if (tpl_types[n->type].sz > tpl_types[struct_widest_node->type].sz) {
396 struct_widest_node = n;
397 }
398 n->addr = calc_field_addr(parent,n->type,struct_addr,ordinal++);
399 } else n->addr = (void*)va_arg(ap,void*)__builtin_va_arg(ap, void*);
400 n->data = tpl_hook.malloc(sizeof(char*));
401 if (!n->data) fatal_oom()tpl_hook.fatal("out of memory\n");
402 *(char**)(n->data) = NULL((void*)0);
403 if (n->parent->type == TPL_TYPE_ARY5)
404 ((tpl_atyp*)(n->parent->data))->sz += sizeof(void*);
405 DL_ADD(parent->children,n)do { if (parent->children) { (n)->prev = (parent->children
)->prev; (parent->children)->prev->next = (n); (parent
->children)->prev = (n); (n)->next = ((void*)0); } else
{ (parent->children)=(n); (parent->children)->prev =
(parent->children); (parent->children)->next = ((void
*)0); } } while (0);
;
406 break;
407 case '#':
408 /* apply a 'num' to preceding atom */
409 if (!parent->children) goto fail;
410 preceding = parent->children->prev; /* first child's prev is 'last child'*/
411 t = preceding->type;
412 applies_to_struct = (*(c-1) == ')') ? 1 : 0;
413 if (!applies_to_struct) {
414 if (!(t == TPL_TYPE_BYTE3 || t == TPL_TYPE_INT321 ||
415 t == TPL_TYPE_UINT322 || t == TPL_TYPE_DOUBLE7 ||
416 t == TPL_TYPE_UINT649 || t == TPL_TYPE_INT648 ||
417 t == TPL_TYPE_UINT1611 || t == TPL_TYPE_INT1610 ||
418 t == TPL_TYPE_STR4 )) goto fail;
419 }
420 /* count up how many contiguous # and form their product */
421 pound_prod=1;
422 num_contig_fxlens=0;
423 for(peek=c; *peek == '#'; peek++) {
424 pound_num = va_arg(ap, int)__builtin_va_arg(ap, int);
425 if (pound_num < 1) {
426 tpl_hook.fatal("non-positive iteration count %d\n", pound_num);
427 }
428 if (num_contig_fxlens >= (sizeof(contig_fxlens)/sizeof(contig_fxlens[0]))) {
429 tpl_hook.fatal("contiguous # exceeds hardcoded limit\n");
430 }
431 contig_fxlens[num_contig_fxlens++] = pound_num;
432 pound_prod *= pound_num;
433 }
434 /* increment c to skip contiguous # so its points to last one */
435 c = peek-1;
436 /* differentiate atom-# from struct-# by noting preceding rparen */
437 if (applies_to_struct) { /* insert # node to induce looping */
438 n = tpl_node_new(parent);
439 n->type = TPL_TYPE_POUND12;
440 n->num = pound_prod;
441 n->data = tpl_hook.malloc(sizeof(tpl_pound_data));
442 if (!n->data) fatal_oom()tpl_hook.fatal("out of memory\n");
443 pd = (tpl_pound_data*)n->data;
444 pd->inter_elt_len = inter_elt_len;
445 pd->iter_start_node = iter_start_node;
446 pd->iternum = 0;
447 DL_ADD(parent->children,n)do { if (parent->children) { (n)->prev = (parent->children
)->prev; (parent->children)->prev->next = (n); (parent
->children)->prev = (n); (n)->next = ((void*)0); } else
{ (parent->children)=(n); (parent->children)->prev =
(parent->children); (parent->children)->next = ((void
*)0); } } while (0);
;
448 /* multiply the 'num' and data space on each atom in the structure */
449 for(np = iter_start_node; np != n; np = np->next) {
450 if (n->parent->type == TPL_TYPE_ARY5) {
451 ((tpl_atyp*)(n->parent->data))->sz +=
452 tpl_types[np->type].sz * (np->num * (n->num - 1));
453 }
454 np->data = tpl_hook.realloc(np->data, tpl_types[np->type].sz *
455 np->num * n->num);
456 if (!np->data) fatal_oom()tpl_hook.fatal("out of memory\n");
457 memset(np->data, 0, tpl_types[np->type].sz * np->num * n->num);
458 }
459 } else { /* simple atom-# form does not require a loop */
460 preceding->num = pound_prod;
461 preceding->data = tpl_hook.realloc(preceding->data,
462 tpl_types[t].sz * preceding->num);
463 if (!preceding->data) fatal_oom()tpl_hook.fatal("out of memory\n");
464 memset(preceding->data,0,tpl_types[t].sz * preceding->num);
465 if (n->parent->type == TPL_TYPE_ARY5) {
466 ((tpl_atyp*)(n->parent->data))->sz += tpl_types[t].sz *
467 (preceding->num-1);
468 }
469 }
470 root->ser_osz += (sizeof(uint32_t) * num_contig_fxlens);
471
472 j = ((tpl_root_data*)root->data)->num_fxlens; /* before incrementing */
473 (((tpl_root_data*)root->data)->num_fxlens) += num_contig_fxlens;
474 num_fxlens = ((tpl_root_data*)root->data)->num_fxlens; /* new value */
475 fxlens = ((tpl_root_data*)root->data)->fxlens;
476 fxlens = tpl_hook.realloc(fxlens, sizeof(int) * num_fxlens);
477 if (!fxlens) fatal_oom()tpl_hook.fatal("out of memory\n");
478 ((tpl_root_data*)root->data)->fxlens = fxlens;
479 for(i=0; i < num_contig_fxlens; i++) fxlens[j++] = contig_fxlens[i];
480
481 break;
482 case 'B':
483 if (expect_lparen) goto fail;
484 if (in_structure) goto fail;
485 n = tpl_node_new(parent);
486 n->type = TPL_TYPE_BIN6;
487 n->addr = (tpl_bin*)va_arg(ap,void*)__builtin_va_arg(ap, void*);
488 n->data = tpl_hook.malloc(sizeof(tpl_bin*));
489 if (!n->data) fatal_oom()tpl_hook.fatal("out of memory\n");
490 *((tpl_bin**)n->data) = NULL((void*)0);
491 if (n->parent->type == TPL_TYPE_ARY5)
492 ((tpl_atyp*)(n->parent->data))->sz += sizeof(tpl_bin);
493 DL_ADD(parent->children,n)do { if (parent->children) { (n)->prev = (parent->children
)->prev; (parent->children)->prev->next = (n); (parent
->children)->prev = (n); (n)->next = ((void*)0); } else
{ (parent->children)=(n); (parent->children)->prev =
(parent->children); (parent->children)->next = ((void
*)0); } } while (0);
;
494 break;
495 case 'A':
496 if (in_structure) goto fail;
497 n = tpl_node_new(parent);
498 n->type = TPL_TYPE_ARY5;
499 DL_ADD(parent->children,n)do { if (parent->children) { (n)->prev = (parent->children
)->prev; (parent->children)->prev->next = (n); (parent
->children)->prev = (n); (n)->next = ((void*)0); } else
{ (parent->children)=(n); (parent->children)->prev =
(parent->children); (parent->children)->next = ((void
*)0); } } while (0);
;
500 parent = n;
501 expect_lparen=1;
502 pidx = (tpl_pidx*)tpl_hook.malloc(sizeof(tpl_pidx));
503 if (!pidx) fatal_oom()tpl_hook.fatal("out of memory\n");
504 pidx->node = n;
505 pidx->next = NULL((void*)0);
506 DL_ADD(((tpl_root_data*)(root->data))->pidx,pidx)do { if (((tpl_root_data*)(root->data))->pidx) { (pidx)
->prev = (((tpl_root_data*)(root->data))->pidx)->
prev; (((tpl_root_data*)(root->data))->pidx)->prev->
next = (pidx); (((tpl_root_data*)(root->data))->pidx)->
prev = (pidx); (pidx)->next = ((void*)0); } else { (((tpl_root_data
*)(root->data))->pidx)=(pidx); (((tpl_root_data*)(root->
data))->pidx)->prev = (((tpl_root_data*)(root->data)
)->pidx); (((tpl_root_data*)(root->data))->pidx)->
next = ((void*)0); } } while (0);
;
507 /* set up the A's tpl_atyp */
508 n->data = (tpl_atyp*)tpl_hook.malloc(sizeof(tpl_atyp));
509 if (!n->data) fatal_oom()tpl_hook.fatal("out of memory\n");
510 ((tpl_atyp*)(n->data))->num = 0;
511 ((tpl_atyp*)(n->data))->sz = 0;
512 ((tpl_atyp*)(n->data))->bb = NULL((void*)0);
513 ((tpl_atyp*)(n->data))->bbtail = NULL((void*)0);
514 ((tpl_atyp*)(n->data))->cur = NULL((void*)0);
515 if (n->parent->type == TPL_TYPE_ARY5)
516 ((tpl_atyp*)(n->parent->data))->sz += sizeof(void*);
517 break;
518 case 'S':
519 if (in_structure) goto fail;
520 expect_lparen=1;
521 ordinal=1; /* index upcoming atoms in S(..) */
522 in_structure=1+lparen_level; /* so we can tell where S fmt ends */
523 struct_addr = (char*)va_arg(ap,void*)__builtin_va_arg(ap, void*);
524 break;
525 case '$': /* nested structure */
526 if (!in_structure) goto fail;
527 expect_lparen=1;
528 in_nested_structure++;
529 break;
530 case ')':
531 lparen_level--;
532 if (lparen_level < 0) goto fail;
533 if (*(c-1) == '(') goto fail;
534 if (in_nested_structure) in_nested_structure--;
535 else if (in_structure && (in_structure-1 == lparen_level)) {
536 /* calculate delta between contiguous structures in array */
537 struct_next = calc_field_addr(parent, struct_widest_node->type,
538 struct_addr, ordinal++);
539 inter_elt_len = struct_next - struct_addr;
540 in_structure=0;
541 }
542 else parent = parent->parent; /* rparen ends A() type, not S() type */
543 break;
544 case '(':
545 if (!expect_lparen) goto fail;
546 expect_lparen=0;
547 lparen_level++;
548 break;
549 default:
550 tpl_hook.oops("unsupported option %c\n", *c);
551 goto fail;
552 }
553 c++;
554 }
555 if (lparen_level != 0) goto fail;
556
557 /* copy the format string, save for convenience */
558 ((tpl_root_data*)(root->data))->fmt = tpl_hook.malloc(strlen(fmt)+1);
559 if (((tpl_root_data*)(root->data))->fmt == NULL((void*)0))
560 fatal_oom()tpl_hook.fatal("out of memory\n");
561 memcpy(((tpl_root_data*)(root->data))->fmt,fmt,strlen(fmt)+1);
562
563 return root;
564
565fail:
566 tpl_hook.oops("failed to parse %s\n", fmt);
567 tpl_free(root);
568 return NULL((void*)0);
569}
570
571static int tpl_unmap_file( tpl_mmap_rec *mr) {
572
573 if ( munmap( mr->text, mr->text_sz ) == -1 ) {
574 tpl_hook.oops("Failed to munmap: %s\n", strerror(errno(*__errno_location ())));
575 }
576 close(mr->fd);
577 mr->text = NULL((void*)0);
578 mr->text_sz = 0;
579 return 0;
580}
581
582static void tpl_free_keep_map(tpl_node *r) {
583 int mmap_bits = (TPL_RDONLY(1 << 10)|TPL_FILE(1 << 0));
584 int ufree_bits = (TPL_MEM(1 << 1)|TPL_UFREE(1 << 5));
585 tpl_node *nxtc,*c;
586 int find_next_node=0,looking,i;
587 size_t sz;
588
589 /* For mmap'd files, or for 'ufree' memory images , do appropriate release */
590 if ((((tpl_root_data*)(r->data))->flags & mmap_bits) == mmap_bits) {
591 tpl_unmap_file( &((tpl_root_data*)(r->data))->mmap);
592 } else if ((((tpl_root_data*)(r->data))->flags & ufree_bits) == ufree_bits) {
593 tpl_hook.free( ((tpl_root_data*)(r->data))->mmap.text );
594 }
595
596 c = r->children;
597 if (c) {
598 while(c->type != TPL_TYPE_ROOT0) { /* loop until we come back to root node */
599 switch (c->type) {
600 case TPL_TYPE_BIN6:
601 /* free any binary buffer hanging from tpl_bin */
602 if ( *((tpl_bin**)(c->data)) ) {
603 if ( (*((tpl_bin**)(c->data)))->addr ) {
604 tpl_hook.free( (*((tpl_bin**)(c->data)))->addr );
605 }
606 *((tpl_bin**)c->data) = NULL((void*)0); /* reset tpl_bin */
607 }
608 find_next_node=1;
609 break;
610 case TPL_TYPE_STR4:
611 /* free any packed (copied) string */
612 for(i=0; i < c->num; i++) {
613 char *str = ((char**)c->data)[i];
614 if (str) {
615 tpl_hook.free(str);
616 ((char**)c->data)[i] = NULL((void*)0);
617 }
618 }
619 find_next_node=1;
620 break;
621 case TPL_TYPE_INT321:
622 case TPL_TYPE_UINT322:
623 case TPL_TYPE_INT648:
624 case TPL_TYPE_UINT649:
625 case TPL_TYPE_BYTE3:
626 case TPL_TYPE_DOUBLE7:
627 case TPL_TYPE_INT1610:
628 case TPL_TYPE_UINT1611:
629 case TPL_TYPE_POUND12:
630 find_next_node=1;
631 break;
632 case TPL_TYPE_ARY5:
633 c->ser_osz = 0; /* zero out the serialization output size */
634
635 sz = ((tpl_atyp*)(c->data))->sz; /* save sz to use below */
636 tpl_free_atyp(c,c->data);
637
638 /* make new atyp */
639 c->data = (tpl_atyp*)tpl_hook.malloc(sizeof(tpl_atyp));
640 if (!c->data) fatal_oom()tpl_hook.fatal("out of memory\n");
641 ((tpl_atyp*)(c->data))->num = 0;
642 ((tpl_atyp*)(c->data))->sz = sz; /* restore bb datum sz */
643 ((tpl_atyp*)(c->data))->bb = NULL((void*)0);
644 ((tpl_atyp*)(c->data))->bbtail = NULL((void*)0);
645 ((tpl_atyp*)(c->data))->cur = NULL((void*)0);
646
647 c = c->children;
648 break;
649 default:
650 tpl_hook.fatal("unsupported format character\n");
651 break;
652 }
653
654 if (find_next_node) {
655 find_next_node=0;
656 looking=1;
657 while(looking) {
658 if (c->next) {
659 nxtc=c->next;
660 c=nxtc;
661 looking=0;
662 } else {
663 if (c->type == TPL_TYPE_ROOT0) break; /* root node */
664 else {
665 nxtc=c->parent;
666 c=nxtc;
667 }
668 }
669 }
670 }
671 }
672 }
673
674 ((tpl_root_data*)(r->data))->flags = 0; /* reset flags */
675}
676
677TPL_API void tpl_free(tpl_node *r) {
678 int mmap_bits = (TPL_RDONLY(1 << 10)|TPL_FILE(1 << 0));
679 int ufree_bits = (TPL_MEM(1 << 1)|TPL_UFREE(1 << 5));
680 tpl_node *nxtc,*c;
681 int find_next_node=0,looking,i;
682 tpl_pidx *pidx,*pidx_nxt;
683
684 /* For mmap'd files, or for 'ufree' memory images , do appropriate release */
685 if ((((tpl_root_data*)(r->data))->flags & mmap_bits) == mmap_bits) {
686 tpl_unmap_file( &((tpl_root_data*)(r->data))->mmap);
687 } else if ((((tpl_root_data*)(r->data))->flags & ufree_bits) == ufree_bits) {
688 tpl_hook.free( ((tpl_root_data*)(r->data))->mmap.text );
689 }
690
691 c = r->children;
692 if (c) {
693 while(c->type != TPL_TYPE_ROOT0) { /* loop until we come back to root node */
694 switch (c->type) {
695 case TPL_TYPE_BIN6:
696 /* free any binary buffer hanging from tpl_bin */
697 if ( *((tpl_bin**)(c->data)) ) {
698 if ( (*((tpl_bin**)(c->data)))->sz != 0 ) {
699 tpl_hook.free( (*((tpl_bin**)(c->data)))->addr );
700 }
701 tpl_hook.free(*((tpl_bin**)c->data)); /* free tpl_bin */
702 }
703 tpl_hook.free(c->data); /* free tpl_bin* */
704 find_next_node=1;
705 break;
706 case TPL_TYPE_STR4:
707 /* free any packed (copied) string */
708 for(i=0; i < c->num; i++) {
709 char *str = ((char**)c->data)[i];
710 if (str) {
711 tpl_hook.free(str);
712 ((char**)c->data)[i] = NULL((void*)0);
713 }
714 }
715 tpl_hook.free(c->data);
716 find_next_node=1;
717 break;
718 case TPL_TYPE_INT321:
719 case TPL_TYPE_UINT322:
720 case TPL_TYPE_INT648:
721 case TPL_TYPE_UINT649:
722 case TPL_TYPE_BYTE3:
723 case TPL_TYPE_DOUBLE7:
724 case TPL_TYPE_INT1610:
725 case TPL_TYPE_UINT1611:
726 case TPL_TYPE_POUND12:
727 tpl_hook.free(c->data);
728 find_next_node=1;
729 break;
730 case TPL_TYPE_ARY5:
731 tpl_free_atyp(c,c->data);
732 if (c->children) c = c->children; /* normal case */
733 else find_next_node=1; /* edge case, handle bad format A() */
734 break;
735 default:
736 tpl_hook.fatal("unsupported format character\n");
737 break;
738 }
739
740 if (find_next_node) {
741 find_next_node=0;
742 looking=1;
743 while(looking) {
744 if (c->next) {
745 nxtc=c->next;
746 tpl_hook.free(c);
747 c=nxtc;
748 looking=0;
749 } else {
750 if (c->type == TPL_TYPE_ROOT0) break; /* root node */
751 else {
752 nxtc=c->parent;
753 tpl_hook.free(c);
754 c=nxtc;
755 }
756 }
757 }
758 }
759 }
760 }
761
762 /* free root */
763 for(pidx=((tpl_root_data*)(r->data))->pidx; pidx; pidx=pidx_nxt) {
764 pidx_nxt = pidx->next;
765 tpl_hook.free(pidx);
766 }
767 tpl_hook.free(((tpl_root_data*)(r->data))->fmt);
768 if (((tpl_root_data*)(r->data))->num_fxlens > 0) {
769 tpl_hook.free(((tpl_root_data*)(r->data))->fxlens);
770 }
771 tpl_hook.free(r->data); /* tpl_root_data */
772 tpl_hook.free(r);
773}
774
775
776/* Find the i'th packable ('A' node) */
777static tpl_node *tpl_find_i(tpl_node *n, int i) {
778 int j=0;
779 tpl_pidx *pidx;
780 if (n->type != TPL_TYPE_ROOT0) return NULL((void*)0);
781 if (i == 0) return n; /* packable 0 is root */
782 for(pidx=((tpl_root_data*)(n->data))->pidx; pidx; pidx=pidx->next) {
783 if (++j == i) return pidx->node;
784 }
785 return NULL((void*)0);
786}
787
788static void *tpl_cpv(void *datav, void *data, size_t sz) {
789 if (sz>0) memcpy(datav,data,sz);
790 return (void*)((uintptr_t)datav + sz);
791}
792
793static void *tpl_extend_backbone(tpl_node *n) {
794 tpl_backbone *bb;
795 bb = (tpl_backbone*)tpl_hook.malloc(sizeof(tpl_backbone) +
1
Value assigned to 'bb'
796 ((tpl_atyp*)(n->data))->sz ); /* datum hangs on coattails of bb */
797 if (!bb) fatal_oom()tpl_hook.fatal("out of memory\n");
2
Assuming 'bb' is null
3
Taking true branch
798#if __STDC_VERSION__199901L < 199901
799 bb->data = (char*)((uintptr_t)bb + sizeof(tpl_backbone));
800#endif
801 memset(bb->data,0,((tpl_atyp*)(n->data))->sz);
802 bb->next = NULL((void*)0);
4
Access to field 'next' results in a dereference of a null pointer (loaded from variable 'bb')
803 /* Add the new backbone to the tail, also setting head if necessary */
804 if (((tpl_atyp*)(n->data))->bb == NULL((void*)0)) {
805 ((tpl_atyp*)(n->data))->bb = bb;
806 ((tpl_atyp*)(n->data))->bbtail = bb;
807 } else {
808 ((tpl_atyp*)(n->data))->bbtail->next = bb;
809 ((tpl_atyp*)(n->data))->bbtail = bb;
810 }
811
812 ((tpl_atyp*)(n->data))->num++;
813 return bb->data;
814}
815
816/* Get the format string corresponding to a given tpl (root node) */
817static char *tpl_fmt(tpl_node *r) {
818 return ((tpl_root_data*)(r->data))->fmt;
819}
820
821/* Get the fmt # lengths as a contiguous buffer of ints (length num_fxlens) */
822static int *tpl_fxlens(tpl_node *r, int *num_fxlens) {
823 *num_fxlens = ((tpl_root_data*)(r->data))->num_fxlens;
824 return ((tpl_root_data*)(r->data))->fxlens;
825}
826
827/* called when serializing an 'A' type node into a buffer which has
828 * already been set up with the proper space. The backbone is walked
829 * which was obtained from the tpl_atyp header passed in.
830 */
831static void *tpl_dump_atyp(tpl_node *n, tpl_atyp* at, void *dv) {
832 tpl_backbone *bb;
833 tpl_node *c;
834 void *datav;
835 uint32_t slen;
836 tpl_bin *binp;
837 char *strp;
838 tpl_atyp *atypp;
839 tpl_pound_data *pd;
840 int i;
841 size_t itermax;
842
843 /* handle 'A' nodes */
844 dv = tpl_cpv(dv,&at->num,sizeof(uint32_t)); /* array len */
845 for(bb=at->bb; bb; bb=bb->next) {
846 datav = bb->data;
847 c=n->children;
848 while(c) {
849 switch (c->type) {
850 case TPL_TYPE_BYTE3:
851 case TPL_TYPE_DOUBLE7:
852 case TPL_TYPE_INT321:
853 case TPL_TYPE_UINT322:
854 case TPL_TYPE_INT648:
855 case TPL_TYPE_UINT649:
856 case TPL_TYPE_INT1610:
857 case TPL_TYPE_UINT1611:
858 dv = tpl_cpv(dv,datav,tpl_types[c->type].sz * c->num);
859 datav = (void*)((uintptr_t)datav + tpl_types[c->type].sz * c->num);
860 break;
861 case TPL_TYPE_BIN6:
862 /* dump the buffer length followed by the buffer */
863 memcpy(&binp,datav,sizeof(tpl_bin*)); /* cp to aligned */
864 slen = binp->sz;
865 dv = tpl_cpv(dv,&slen,sizeof(uint32_t));
866 dv = tpl_cpv(dv,binp->addr,slen);
867 datav = (void*)((uintptr_t)datav + sizeof(tpl_bin*));
868 break;
869 case TPL_TYPE_STR4:
870 /* dump the string length followed by the string */
871 for(i=0; i < c->num; i++) {
872 memcpy(&strp,datav,sizeof(char*)); /* cp to aligned */
873 slen = strp ? (strlen(strp)+1) : 0;
874 dv = tpl_cpv(dv,&slen,sizeof(uint32_t));
875 if (slen > 1) dv = tpl_cpv(dv,strp,slen-1);
876 datav = (void*)((uintptr_t)datav + sizeof(char*));
877 }
878 break;
879 case TPL_TYPE_ARY5:
880 memcpy(&atypp,datav,sizeof(tpl_atyp*)); /* cp to aligned */
881 dv = tpl_dump_atyp(c,atypp,dv);
882 datav = (void*)((uintptr_t)datav + sizeof(void*));
883 break;
884 case TPL_TYPE_POUND12:
885 /* iterate over the preceding nodes */
886 pd = (tpl_pound_data*)c->data;
887 itermax = c->num;
888 if (++(pd->iternum) < itermax) {
889 c = pd->iter_start_node;
890 continue;
891 } else { /* loop complete. */
892 pd->iternum = 0;
893 }
894 break;
895 default:
896 tpl_hook.fatal("unsupported format character\n");
897 break;
898 }
899 c=c->next;
900 }
901 }
902 return dv;
903}
904
905/* figure the serialization output size needed for tpl whose root is n*/
906static size_t tpl_ser_osz(tpl_node *n) {
907 tpl_node *c, *np;
908 size_t sz, itermax;
909 tpl_bin *binp;
910 char *strp;
911 tpl_pound_data *pd;
912 int i;
913
914 /* handle the root node ONLY (subtree's ser_osz have been bubbled-up) */
915 if (n->type != TPL_TYPE_ROOT0) {
916 tpl_hook.fatal("internal error: tpl_ser_osz on non-root node\n");
917 }
918
919 sz = n->ser_osz; /* start with fixed overhead, already stored */
920 c=n->children;
921 while (c) {
922 switch (c->type) {
923 case TPL_TYPE_BYTE3:
924 case TPL_TYPE_DOUBLE7:
925 case TPL_TYPE_INT321:
926 case TPL_TYPE_UINT322:
927 case TPL_TYPE_INT648:
928 case TPL_TYPE_UINT649:
929 case TPL_TYPE_INT1610:
930 case TPL_TYPE_UINT1611:
931 sz += tpl_types[c->type].sz * c->num;
932 break;
933 case TPL_TYPE_BIN6:
934 sz += sizeof(uint32_t); /* binary buf len */
935 memcpy(&binp,c->data,sizeof(tpl_bin*)); /* cp to aligned */
936 sz += binp->sz;
937 break;
938 case TPL_TYPE_STR4:
939 for(i=0; i < c->num; i++) {
940 sz += sizeof(uint32_t); /* string len */
941 memcpy(&strp,&((char**)c->data)[i],sizeof(char*)); /* cp to aligned */
942 sz += strp ? strlen(strp) : 0;
943 }
944 break;
945 case TPL_TYPE_ARY5:
946 sz += sizeof(uint32_t); /* array len */
947 sz += c->ser_osz; /* bubbled-up child array ser_osz */
948 break;
949 case TPL_TYPE_POUND12:
950 /* iterate over the preceding nodes */
951 itermax = c->num;
952 pd = (tpl_pound_data*)c->data;
953 if (++(pd->iternum) < itermax) {
954 for(np=pd->iter_start_node; np != c; np = np->next) {
955 np->data = (char*)(np->data) +
956 (tpl_types[np->type].sz * np->num);
957 }
958 c = pd->iter_start_node;
959 continue;
960 } else { /* loop complete. */
961 pd->iternum = 0;
962 for(np=pd->iter_start_node; np != c; np = np->next) {
963 np->data = (char*)(np->data) - ((itermax-1) *
964 tpl_types[np->type].sz *
965 np->num);
966 }
967 }
968 break;
969 default:
970 tpl_hook.fatal("unsupported format character\n");
971 break;
972 }
973 c=c->next;
974 }
975 return sz;
976}
977
978
979TPL_API int tpl_dump(tpl_node *r, int mode, ...) {
980 va_list ap;
981 char *filename, *bufv;
982 void **addr_out,*buf, *pa_addr;
983 int fd,rc=0;
984 size_t sz,*sz_out, pa_sz;
985
986 if (((tpl_root_data*)(r->data))->flags & TPL_RDONLY(1 << 10)) { /* unusual */
987 tpl_hook.oops("error: tpl_dump called for a loaded tpl\n");
988 return -1;
989 }
990
991 sz = tpl_ser_osz(r); /* compute the size needed to serialize */
992
993 va_start(ap,mode)__builtin_va_start(ap, mode);
994 if (mode & TPL_FILE(1 << 0)) {
995 filename = va_arg(ap,char*)__builtin_va_arg(ap, char*);
996 fd = tpl_mmap_output_file(filename, sz, &buf);
997 if (fd == -1) rc = -1;
998 else {
999 rc = tpl_dump_to_mem(r,buf,sz);
1000 if (msync(buf,sz,MS_SYNC4) == -1) {
1001 tpl_hook.oops("msync failed on fd %d: %s\n", fd, strerror(errno(*__errno_location ())));
1002 }
1003 if (munmap(buf, sz) == -1) {
1004 tpl_hook.oops("munmap failed on fd %d: %s\n", fd, strerror(errno(*__errno_location ())));
1005 }
1006 close(fd);
1007 }
1008 } else if (mode & TPL_FD(1 << 4)) {
1009 fd = va_arg(ap, int)__builtin_va_arg(ap, int);
1010 if ( (buf = tpl_hook.malloc(sz)) == NULL((void*)0)) fatal_oom()tpl_hook.fatal("out of memory\n");
1011 tpl_dump_to_mem(r,buf,sz);
1012 bufv = buf;
1013 do {
1014 rc = write(fd,bufv,sz);
1015 if (rc > 0) {
1016 sz -= rc;
1017 bufv += rc;
1018 } else if (rc == -1) {
1019 if (errno(*__errno_location ()) == EINTR4 || errno(*__errno_location ()) == EAGAIN11) continue;
1020 tpl_hook.oops("error writing to fd %d: %s\n", fd, strerror(errno(*__errno_location ())));
1021 free(buf);
1022 return -1;
1023 }
1024 } while (sz > 0);
1025 free(buf);
1026 rc = 0;
1027 } else if (mode & TPL_MEM(1 << 1)) {
1028 if (mode & TPL_PREALLOCD(1 << 2)) { /* caller allocated */
1029 pa_addr = (void*)va_arg(ap, void*)__builtin_va_arg(ap, void*);
1030 pa_sz = va_arg(ap, size_t)__builtin_va_arg(ap, size_t);
1031 if (pa_sz < sz) {
1032 tpl_hook.oops("tpl_dump: buffer too small, need %d bytes\n", sz);
1033 return -1;
1034 }
1035 rc=tpl_dump_to_mem(r,pa_addr,sz);
1036 } else { /* we allocate */
1037 addr_out = (void**)va_arg(ap, void*)__builtin_va_arg(ap, void*);
1038 sz_out = va_arg(ap, size_t*)__builtin_va_arg(ap, size_t*);
1039 if ( (buf = tpl_hook.malloc(sz)) == NULL((void*)0)) fatal_oom()tpl_hook.fatal("out of memory\n");
1040 *sz_out = sz;
1041 *addr_out = buf;
1042 rc=tpl_dump_to_mem(r,buf,sz);
1043 }
1044 } else if (mode & TPL_GETSIZE(1 << 8)) {
1045 sz_out = va_arg(ap, size_t*)__builtin_va_arg(ap, size_t*);
1046 *sz_out = sz;
1047 } else {
1048 tpl_hook.oops("unsupported tpl_dump mode %d\n", mode);
1049 rc=-1;
1050 }
1051 va_end(ap)__builtin_va_end(ap);
1052 return rc;
1053}
1054
1055/* This function expects the caller to have set up a memory buffer of
1056 * adequate size to hold the serialized tpl. The sz parameter must be
1057 * the result of tpl_ser_osz(r).
1058 */
1059static int tpl_dump_to_mem(tpl_node *r,void *addr,size_t sz) {
1060 uint32_t slen, sz32;
1061 int *fxlens, num_fxlens, i;
1062 void *dv;
1063 char *fmt,flags;
1064 tpl_node *c, *np;
1065 tpl_pound_data *pd;
1066 size_t itermax;
1067
1068 fmt = tpl_fmt(r);
1069 flags = 0;
1070 if (tpl_cpu_bigendian()) flags |= TPL_FL_BIGENDIAN(1 << 0);
1071 if (strchr(fmt,'s')(__extension__ (__builtin_constant_p ('s') && !__builtin_constant_p
(fmt) && ('s') == '\0' ? (char *) __rawmemchr (fmt, 's'
) : __builtin_strchr (fmt, 's')))
) flags |= TPL_FL_NULLSTRINGS(1 << 1);
1072 sz32 = sz;
1073
1074 dv = addr;
1075 dv = tpl_cpv(dv,TPL_MAGIC"tpl",3); /* copy tpl magic prefix */
1076 dv = tpl_cpv(dv,&flags,1); /* copy flags byte */
1077 dv = tpl_cpv(dv,&sz32,sizeof(uint32_t));/* overall length (inclusive) */
1078 dv = tpl_cpv(dv,fmt,strlen(fmt)+1); /* copy format with NUL-term */
1079 fxlens = tpl_fxlens(r,&num_fxlens);
1080 dv = tpl_cpv(dv,fxlens,num_fxlens*sizeof(uint32_t));/* fmt # lengths */
1081
1082 /* serialize the tpl content, iterating over direct children of root */
1083 c = r->children;
1084 while (c) {
1085 switch (c->type) {
1086 case TPL_TYPE_BYTE3:
1087 case TPL_TYPE_DOUBLE7:
1088 case TPL_TYPE_INT321:
1089 case TPL_TYPE_UINT322:
1090 case TPL_TYPE_INT648:
1091 case TPL_TYPE_UINT649:
1092 case TPL_TYPE_INT1610:
1093 case TPL_TYPE_UINT1611:
1094 dv = tpl_cpv(dv,c->data,tpl_types[c->type].sz * c->num);
1095 break;
1096 case TPL_TYPE_BIN6:
1097 slen = (*(tpl_bin**)(c->data))->sz;
1098 dv = tpl_cpv(dv,&slen,sizeof(uint32_t)); /* buffer len */
1099 dv = tpl_cpv(dv,(*(tpl_bin**)(c->data))->addr,slen); /* buf */
1100 break;
1101 case TPL_TYPE_STR4:
1102 for(i=0; i < c->num; i++) {
1103 char *str = ((char**)c->data)[i];
1104 slen = str ? strlen(str)+1 : 0;
1105 dv = tpl_cpv(dv,&slen,sizeof(uint32_t)); /* string len */
1106 if (slen>1) dv = tpl_cpv(dv,str,slen-1); /*string*/
1107 }
1108 break;
1109 case TPL_TYPE_ARY5:
1110 dv = tpl_dump_atyp(c,(tpl_atyp*)c->data,dv);
1111 break;
1112 case TPL_TYPE_POUND12:
1113 pd = (tpl_pound_data*)c->data;
1114 itermax = c->num;
1115 if (++(pd->iternum) < itermax) {
1116
1117 /* in start or midst of loop. advance data pointers. */
1118 for(np=pd->iter_start_node; np != c; np = np->next) {
1119 np->data = (char*)(np->data) +
1120 (tpl_types[np->type].sz * np->num);
1121 }
1122 /* do next iteration */
1123 c = pd->iter_start_node;
1124 continue;
1125
1126 } else { /* loop complete. */
1127
1128 /* reset iteration index and addr/data pointers. */
1129 pd->iternum = 0;
1130 for(np=pd->iter_start_node; np != c; np = np->next) {
1131 np->data = (char*)(np->data) - ((itermax-1) *
1132 tpl_types[np->type].sz *
1133 np->num);
1134 }
1135
1136 }
1137 break;
1138 default:
1139 tpl_hook.fatal("unsupported format character\n");
1140 break;
1141 }
1142 c = c->next;
1143 }
1144
1145 return 0;
1146}
1147
1148static int tpl_cpu_bigendian() {
1149 unsigned i = 1;
1150 char *c;
1151 c = (char*)&i;
1152 return (c[0] == 1 ? 0 : 1);
1153}
1154
1155
1156/*
1157 * algorithm for sanity-checking a tpl image:
1158 * scan the tpl whilst not exceeding the buffer size (bufsz) ,
1159 * formulating a calculated (expected) size of the tpl based
1160 * on walking its data. When calcsize has been calculated it
1161 * should exactly match the buffer size (bufsz) and the internal
1162 * recorded size (intlsz)
1163 */
1164static int tpl_sanity(tpl_node *r, int excess_ok) {
1165 uint32_t intlsz;
1166 int found_nul=0,rc, octothorpes=0, num_fxlens, *fxlens, flen;
1167 void *d, *dv;
1168 char intlflags, *fmt, c, *mapfmt;
1169 size_t bufsz, serlen;
1170
1171 d = ((tpl_root_data*)(r->data))->mmap.text;
1172 bufsz = ((tpl_root_data*)(r->data))->mmap.text_sz;
1173
1174 dv = d;
1175 if (bufsz < (4 + sizeof(uint32_t) + 1)) return ERR_NOT_MINSIZE(-1); /* min sz: magic+flags+len+nul */
1176 if (memcmp(dv,TPL_MAGIC"tpl", 3) != 0) return ERR_MAGIC_MISMATCH(-2); /* missing tpl magic prefix */
1177 if (tpl_needs_endian_swap(dv)) ((tpl_root_data*)(r->data))->flags |= TPL_XENDIAN(1 << 11);
1178 dv = (void*)((uintptr_t)dv + 3);
1179 memcpy(&intlflags,dv,sizeof(char)); /* extract flags */
1180 if (intlflags & ~TPL_SUPPORTED_BITFLAGS3) return ERR_UNSUPPORTED_FLAGS(-11);
1181 /* TPL1.3 stores strings with a "length+1" prefix to discern NULL strings from
1182 empty strings from non-empty strings; TPL1.2 only handled the latter two.
1183 So we need to be mindful of which string format we're reading from. */
1184 if (!(intlflags & TPL_FL_NULLSTRINGS(1 << 1))) {
1185 ((tpl_root_data*)(r->data))->flags |= TPL_OLD_STRING_FMT(1 << 12);
1186 }
1187 dv = (void*)((uintptr_t)dv + 1);
1188 memcpy(&intlsz,dv,sizeof(uint32_t)); /* extract internal size */
1189 if (((tpl_root_data*)(r->data))->flags & TPL_XENDIAN(1 << 11)) tpl_byteswap(&intlsz, sizeof(uint32_t));
1190 if (!excess_ok && (intlsz != bufsz)) return ERR_INCONSISTENT_SZ(-3); /* inconsisent buffer/internal size */
1191 dv = (void*)((uintptr_t)dv + sizeof(uint32_t));
1192
1193 /* dv points to the start of the format string. Look for nul w/in buf sz */
1194 fmt = (char*)dv;
1195 while ((uintptr_t)dv-(uintptr_t)d < bufsz && !found_nul) {
1196 if ( (c = *(char*)dv) != '\0') {
1197 if (strchr(tpl_fmt_chars,c)(__extension__ (__builtin_constant_p (c) && !__builtin_constant_p
(tpl_fmt_chars) && (c) == '\0' ? (char *) __rawmemchr
(tpl_fmt_chars, c) : __builtin_strchr (tpl_fmt_chars, c)))
== NULL((void*)0))
1198 return ERR_FMT_INVALID(-4); /* invalid char in format string */
1199 if ( (c = *(char*)dv) == '#') octothorpes++;
1200 dv = (void*)((uintptr_t)dv + 1);
1201 }
1202 else found_nul = 1;
1203 }
1204 if (!found_nul) return ERR_FMT_MISSING_NUL(-5); /* runaway format string */
1205 dv = (void*)((uintptr_t)dv + 1); /* advance to octothorpe lengths buffer */
1206
1207 /* compare the map format to the format of this tpl image */
1208 mapfmt = tpl_fmt(r);
1209 rc = strcmp(mapfmt,fmt)__extension__ ({ size_t __s1_len, __s2_len; (__builtin_constant_p
(mapfmt) && __builtin_constant_p (fmt) && (__s1_len
= __builtin_strlen (mapfmt), __s2_len = __builtin_strlen (fmt
), (!((size_t)(const void *)((mapfmt) + 1) - (size_t)(const void
*)(mapfmt) == 1) || __s1_len >= 4) && (!((size_t)
(const void *)((fmt) + 1) - (size_t)(const void *)(fmt) == 1)
|| __s2_len >= 4)) ? __builtin_strcmp (mapfmt, fmt) : (__builtin_constant_p
(mapfmt) && ((size_t)(const void *)((mapfmt) + 1) - (
size_t)(const void *)(mapfmt) == 1) && (__s1_len = __builtin_strlen
(mapfmt), __s1_len < 4) ? (__builtin_constant_p (fmt) &&
((size_t)(const void *)((fmt) + 1) - (size_t)(const void *)(
fmt) == 1) ? __builtin_strcmp (mapfmt, fmt) : (__extension__ (
{ const unsigned char *__s2 = (const unsigned char *) (const char
*) (fmt); int __result = (((const unsigned char *) (const char
*) (mapfmt))[0] - __s2[0]); if (__s1_len > 0 && __result
== 0) { __result = (((const unsigned char *) (const char *) (
mapfmt))[1] - __s2[1]); if (__s1_len > 1 && __result
== 0) { __result = (((const unsigned char *) (const char *) (
mapfmt))[2] - __s2[2]); if (__s1_len > 2 && __result
== 0) __result = (((const unsigned char *) (const char *) (mapfmt
))[3] - __s2[3]); } } __result; }))) : (__builtin_constant_p (
fmt) && ((size_t)(const void *)((fmt) + 1) - (size_t)
(const void *)(fmt) == 1) && (__s2_len = __builtin_strlen
(fmt), __s2_len < 4) ? (__builtin_constant_p (mapfmt) &&
((size_t)(const void *)((mapfmt) + 1) - (size_t)(const void *
)(mapfmt) == 1) ? __builtin_strcmp (mapfmt, fmt) : (- (__extension__
({ const unsigned char *__s2 = (const unsigned char *) (const
char *) (mapfmt); int __result = (((const unsigned char *) (
const char *) (fmt))[0] - __s2[0]); if (__s2_len > 0 &&
__result == 0) { __result = (((const unsigned char *) (const
char *) (fmt))[1] - __s2[1]); if (__s2_len > 1 &&
__result == 0) { __result = (((const unsigned char *) (const
char *) (fmt))[2] - __s2[2]); if (__s2_len > 2 &&
__result == 0) __result = (((const unsigned char *) (const char
*) (fmt))[3] - __s2[3]); } } __result; })))) : __builtin_strcmp
(mapfmt, fmt)))); })
;
1210 if (rc != 0) return ERR_FMT_MISMATCH(-6);
1211
1212 /* compare octothorpe lengths in image to the mapped values */
1213 if ((((uintptr_t)dv + (octothorpes * 4)) - (uintptr_t)d) > bufsz) return ERR_INCONSISTENT_SZ4(-10);
1214 fxlens = tpl_fxlens(r,&num_fxlens); /* mapped fxlens */
1215 while(num_fxlens--) {
1216 memcpy(&flen,dv,sizeof(uint32_t)); /* stored flen */
1217 if (((tpl_root_data*)(r->data))->flags & TPL_XENDIAN(1 << 11)) tpl_byteswap(&flen, sizeof(uint32_t));
1218 if (flen != *fxlens) return ERR_FLEN_MISMATCH(-7);
1219 dv = (void*)((uintptr_t)dv + sizeof(uint32_t));
1220 fxlens++;
1221 }
1222
1223 /* dv now points to beginning of data */
1224 rc = tpl_serlen(r,r,dv,&serlen); /* get computed serlen of data part */
1225 if (rc == -1) return ERR_INCONSISTENT_SZ2(-8); /* internal inconsistency in tpl image */
1226 serlen += ((uintptr_t)dv - (uintptr_t)d); /* add back serlen of preamble part */
1227 if (excess_ok && (bufsz < serlen)) return ERR_INCONSISTENT_SZ3(-9);
1228 if (!excess_ok && (serlen != bufsz)) return ERR_INCONSISTENT_SZ3(-9); /* buffer/internal sz exceeds serlen */
1229 return 0;
1230}
1231
1232static void *tpl_find_data_start(void *d) {
1233 int octothorpes=0;
1234 d = (void*)((uintptr_t)d + 4); /* skip TPL_MAGIC and flags byte */
1235 d = (void*)((uintptr_t)d + 4); /* skip int32 overall len */
1236 while(*(char*)d != '\0') {
1237 if (*(char*)d == '#') octothorpes++;
1238 d = (void*)((uintptr_t)d + 1);
1239 }
1240 d = (void*)((uintptr_t)d + 1); /* skip NUL */
1241 d = (void*)((uintptr_t)d + (octothorpes * sizeof(uint32_t))); /* skip # array lens */
1242 return d;
1243}
1244
1245static int tpl_needs_endian_swap(void *d) {
1246 char *c;
1247 int cpu_is_bigendian;
1248 c = (char*)d;
1249 cpu_is_bigendian = tpl_cpu_bigendian();
1250 return ((c[3] & TPL_FL_BIGENDIAN(1 << 0)) == cpu_is_bigendian) ? 0 : 1;
1251}
1252
1253static size_t tpl_size_for(char c) {
1254 int i;
1255 for(i=0; i < sizeof(tpl_types)/sizeof(tpl_types[0]); i++) {
1256 if (tpl_types[i].c == c) return tpl_types[i].sz;
1257 }
1258 return 0;
1259}
1260
1261TPL_API char* tpl_peek(int mode, ...) {
1262 va_list ap;
1263 int xendian=0,found_nul=0,old_string_format=0;
1264 char *filename=NULL((void*)0), *datapeek_f=NULL((void*)0), *datapeek_c, *datapeek_s;
1265 void *addr=NULL((void*)0), *dv, *datapeek_p=NULL((void*)0);
1266 size_t sz=0, fmt_len, first_atom, num_fxlens=0;
1267 uint32_t datapeek_ssz, datapeek_csz, datapeek_flen;
1268 tpl_mmap_rec mr = {0,NULL((void*)0),0};
1269 char *fmt,*fmt_cpy=NULL((void*)0),c;
1270 uint32_t intlsz, **fxlens=NULL((void*)0), *num_fxlens_out=NULL((void*)0), *fxlensv;
1271
1272 va_start(ap,mode)__builtin_va_start(ap, mode);
1273 if ((mode & TPL_FXLENS(1 << 7)) && (mode & TPL_DATAPEEK(1 << 6))) {
1274 tpl_hook.oops("TPL_FXLENS and TPL_DATAPEEK mutually exclusive\n");
1275 goto fail;
1276 }
1277 if (mode & TPL_FILE(1 << 0)) filename = va_arg(ap,char *)__builtin_va_arg(ap, char *);
1278 else if (mode & TPL_MEM(1 << 1)) {
1279 addr = va_arg(ap,void *)__builtin_va_arg(ap, void *);
1280 sz = va_arg(ap,size_t)__builtin_va_arg(ap, size_t);
1281 } else {
1282 tpl_hook.oops("unsupported tpl_peek mode %d\n", mode);
1283 goto fail;
1284 }
1285 if (mode & TPL_DATAPEEK(1 << 6)) {
1286 datapeek_f = va_arg(ap, char*)__builtin_va_arg(ap, char*);
1287 }
1288 if (mode & TPL_FXLENS(1 << 7)) {
1289 num_fxlens_out = va_arg(ap,uint32_t *)__builtin_va_arg(ap, uint32_t *);
1290 fxlens = va_arg(ap,uint32_t **)__builtin_va_arg(ap, uint32_t **);
1291 *num_fxlens_out = 0;
1292 *fxlens = NULL((void*)0);
1293 }
1294
1295 if (mode & TPL_FILE(1 << 0)) {
1296 if (tpl_mmap_file(filename, &mr) != 0) {
1297 tpl_hook.oops("tpl_peek failed for file %s\n", filename);
1298 goto fail;
1299 }
1300 addr = mr.text;
1301 sz = mr.text_sz;
1302 }
1303
1304 dv = addr;
1305 if (sz < (4 + sizeof(uint32_t) + 1)) goto fail; /* min sz */
1306 if (memcmp(dv,TPL_MAGIC"tpl", 3) != 0) goto fail; /* missing tpl magic prefix */
1307 if (tpl_needs_endian_swap(dv)) xendian=1;
1308 if ((((char*)dv)[3] & TPL_FL_NULLSTRINGS(1 << 1))==0) old_string_format=1;
1309 dv = (void*)((uintptr_t)dv + 4);
1310 memcpy(&intlsz,dv,sizeof(uint32_t)); /* extract internal size */
1311 if (xendian) tpl_byteswap(&intlsz, sizeof(uint32_t));
1312 if (intlsz != sz) goto fail; /* inconsisent buffer/internal size */
1313 dv = (void*)((uintptr_t)dv + sizeof(uint32_t));
1314
1315 /* dv points to the start of the format string. Look for nul w/in buf sz */
1316 fmt = (char*)dv;
1317 while ((uintptr_t)dv-(uintptr_t)addr < sz && !found_nul) {
1318 if ( (c = *(char*)dv) == '\0') {
1319 found_nul = 1;
1320 } else if (c == '#') {
1321 num_fxlens++;
1322 }
1323 dv = (void*)((uintptr_t)dv + 1);
1324 }
1325 if (!found_nul) goto fail; /* runaway format string */
1326 fmt_len = (char*)dv - fmt; /* include space for \0 */
1327 fmt_cpy = tpl_hook.malloc(fmt_len);
1328 if (fmt_cpy == NULL((void*)0)) {
1329 fatal_oom()tpl_hook.fatal("out of memory\n");
1330 }
1331 memcpy(fmt_cpy, fmt, fmt_len);
1332
1333 /* retrieve the octothorpic lengths if requested */
1334 if (num_fxlens > 0) {
1335 if (sz < ((uintptr_t)dv + (num_fxlens * sizeof(uint32_t)) - (uintptr_t)addr)) {
1336 goto fail;
1337 }
1338 }
1339 if ((mode & TPL_FXLENS(1 << 7)) && (num_fxlens > 0)) {
1340 *fxlens = tpl_hook.malloc(num_fxlens * sizeof(uint32_t));
1341 if (*fxlens == NULL((void*)0)) tpl_hook.fatal("out of memory");
1342 *num_fxlens_out = num_fxlens;
1343 fxlensv = *fxlens;
1344 while(num_fxlens--) {
1345 memcpy(fxlensv,dv,sizeof(uint32_t));
1346 if (xendian) tpl_byteswap(fxlensv, sizeof(uint32_t));
1347 dv = (void*)((uintptr_t)dv + sizeof(uint32_t));
1348 fxlensv++;
1349 }
1350 }
1351 /* if caller requested, peek into the specified data elements */
1352 if (mode & TPL_DATAPEEK(1 << 6)) {
1353
1354 first_atom = strspn(fmt, "S()")__extension__ ({ char __a0, __a1, __a2; (__builtin_constant_p
("S()") && ((size_t)(const void *)(("S()") + 1) - (size_t
)(const void *)("S()") == 1) ? ((__builtin_constant_p (fmt) &&
((size_t)(const void *)((fmt) + 1) - (size_t)(const void *)(
fmt) == 1)) ? __builtin_strspn (fmt, "S()") : ((__a0 = ((const
char *) ("S()"))[0], __a0 == '\0') ? ((void) (fmt), (size_t)
0) : ((__a1 = ((const char *) ("S()"))[1], __a1 == '\0') ? __strspn_c1
(fmt, __a0) : ((__a2 = ((const char *) ("S()"))[2], __a2 == '\0'
) ? __strspn_c2 (fmt, __a0, __a1) : (((const char *) ("S()"))
[3] == '\0' ? __strspn_c3 (fmt, __a0, __a1, __a2) : __builtin_strspn
(fmt, "S()")))))) : __builtin_strspn (fmt, "S()")); })
; /* skip any leading S() */
1355
1356 datapeek_flen = strlen(datapeek_f);
1357 if (strspn(datapeek_f, tpl_datapeek_ok_chars)__extension__ ({ char __a0, __a1, __a2; (__builtin_constant_p
(tpl_datapeek_ok_chars) && ((size_t)(const void *)((
tpl_datapeek_ok_chars) + 1) - (size_t)(const void *)(tpl_datapeek_ok_chars
) == 1) ? ((__builtin_constant_p (datapeek_f) && ((size_t
)(const void *)((datapeek_f) + 1) - (size_t)(const void *)(datapeek_f
) == 1)) ? __builtin_strspn (datapeek_f, tpl_datapeek_ok_chars
) : ((__a0 = ((const char *) (tpl_datapeek_ok_chars))[0], __a0
== '\0') ? ((void) (datapeek_f), (size_t) 0) : ((__a1 = ((const
char *) (tpl_datapeek_ok_chars))[1], __a1 == '\0') ? __strspn_c1
(datapeek_f, __a0) : ((__a2 = ((const char *) (tpl_datapeek_ok_chars
))[2], __a2 == '\0') ? __strspn_c2 (datapeek_f, __a0, __a1) :
(((const char *) (tpl_datapeek_ok_chars))[3] == '\0' ? __strspn_c3
(datapeek_f, __a0, __a1, __a2) : __builtin_strspn (datapeek_f
, tpl_datapeek_ok_chars)))))) : __builtin_strspn (datapeek_f,
tpl_datapeek_ok_chars)); })
< datapeek_flen) {
1358 tpl_hook.oops("invalid TPL_DATAPEEK format: %s\n", datapeek_f);
1359 tpl_hook.free(fmt_cpy); fmt_cpy = NULL((void*)0); /* fail */
1360 goto fail;
1361 }
1362
1363 if (strncmp( &fmt[first_atom], datapeek_f, datapeek_flen)(__extension__ (__builtin_constant_p (datapeek_flen) &&
((__builtin_constant_p (&fmt[first_atom]) && strlen
(&fmt[first_atom]) < ((size_t) (datapeek_flen))) || (
__builtin_constant_p (datapeek_f) && strlen (datapeek_f
) < ((size_t) (datapeek_flen)))) ? __extension__ ({ size_t
__s1_len, __s2_len; (__builtin_constant_p (&fmt[first_atom
]) && __builtin_constant_p (datapeek_f) && (__s1_len
= __builtin_strlen (&fmt[first_atom]), __s2_len = __builtin_strlen
(datapeek_f), (!((size_t)(const void *)((&fmt[first_atom
]) + 1) - (size_t)(const void *)(&fmt[first_atom]) == 1) ||
__s1_len >= 4) && (!((size_t)(const void *)((datapeek_f
) + 1) - (size_t)(const void *)(datapeek_f) == 1) || __s2_len
>= 4)) ? __builtin_strcmp (&fmt[first_atom], datapeek_f
) : (__builtin_constant_p (&fmt[first_atom]) && (
(size_t)(const void *)((&fmt[first_atom]) + 1) - (size_t)
(const void *)(&fmt[first_atom]) == 1) && (__s1_len
= __builtin_strlen (&fmt[first_atom]), __s1_len < 4) ?
(__builtin_constant_p (datapeek_f) && ((size_t)(const
void *)((datapeek_f) + 1) - (size_t)(const void *)(datapeek_f
) == 1) ? __builtin_strcmp (&fmt[first_atom], datapeek_f)
: (__extension__ ({ const unsigned char *__s2 = (const unsigned
char *) (const char *) (datapeek_f); int __result = (((const
unsigned char *) (const char *) (&fmt[first_atom]))[0] -
__s2[0]); if (__s1_len > 0 && __result == 0) { __result
= (((const unsigned char *) (const char *) (&fmt[first_atom
]))[1] - __s2[1]); if (__s1_len > 1 && __result ==
0) { __result = (((const unsigned char *) (const char *) (&
fmt[first_atom]))[2] - __s2[2]); if (__s1_len > 2 &&
__result == 0) __result = (((const unsigned char *) (const char
*) (&fmt[first_atom]))[3] - __s2[3]); } } __result; })))
: (__builtin_constant_p (datapeek_f) && ((size_t)(const
void *)((datapeek_f) + 1) - (size_t)(const void *)(datapeek_f
) == 1) && (__s2_len = __builtin_strlen (datapeek_f),
__s2_len < 4) ? (__builtin_constant_p (&fmt[first_atom
]) && ((size_t)(const void *)((&fmt[first_atom]) +
1) - (size_t)(const void *)(&fmt[first_atom]) == 1) ? __builtin_strcmp
(&fmt[first_atom], datapeek_f) : (- (__extension__ ({ const
unsigned char *__s2 = (const unsigned char *) (const char *)
(&fmt[first_atom]); int __result = (((const unsigned char
*) (const char *) (datapeek_f))[0] - __s2[0]); if (__s2_len >
0 && __result == 0) { __result = (((const unsigned char
*) (const char *) (datapeek_f))[1] - __s2[1]); if (__s2_len >
1 && __result == 0) { __result = (((const unsigned char
*) (const char *) (datapeek_f))[2] - __s2[2]); if (__s2_len >
2 && __result == 0) __result = (((const unsigned char
*) (const char *) (datapeek_f))[3] - __s2[3]); } } __result;
})))) : __builtin_strcmp (&fmt[first_atom], datapeek_f))
)); }) : strncmp (&fmt[first_atom], datapeek_f, datapeek_flen
)))
!= 0) {
1364 tpl_hook.oops("TPL_DATAPEEK format mismatches tpl iamge\n");
1365 tpl_hook.free(fmt_cpy); fmt_cpy = NULL((void*)0); /* fail */
1366 goto fail;
1367 }
1368
1369 /* advance to data start, then copy out requested elements */
1370 dv = (void*)((uintptr_t)dv + (num_fxlens * sizeof(uint32_t)));
1371 for(datapeek_c = datapeek_f; *datapeek_c != '\0'; datapeek_c++) {
1372 datapeek_p = va_arg(ap, void*)__builtin_va_arg(ap, void*);
1373 if (*datapeek_c == 's') { /* special handling for strings */
1374 if ((uintptr_t)dv-(uintptr_t)addr + sizeof(uint32_t) > sz) {
1375 tpl_hook.oops("tpl_peek: tpl has insufficient length\n");
1376 tpl_hook.free(fmt_cpy); fmt_cpy = NULL((void*)0); /* fail */
1377 goto fail;
1378 }
1379 memcpy(&datapeek_ssz,dv,sizeof(uint32_t)); /* get slen */
1380 if (xendian) tpl_byteswap(&datapeek_ssz, sizeof(uint32_t));
1381 if (old_string_format) datapeek_ssz++;
1382 dv = (void*)((uintptr_t)dv + sizeof(uint32_t)); /* adv. to str */
1383 if (datapeek_ssz == 0) datapeek_s = NULL((void*)0);
1384 else {
1385 if ((uintptr_t)dv-(uintptr_t)addr + datapeek_ssz-1 > sz) {
1386 tpl_hook.oops("tpl_peek: tpl has insufficient length\n");
1387 tpl_hook.free(fmt_cpy); fmt_cpy = NULL((void*)0); /* fail */
1388 goto fail;
1389 }
1390 datapeek_s = tpl_hook.malloc(datapeek_ssz);
1391 if (datapeek_s == NULL((void*)0)) fatal_oom()tpl_hook.fatal("out of memory\n");
1392 memcpy(datapeek_s, dv, datapeek_ssz-1);
1393 datapeek_s[datapeek_ssz-1] = '\0';
1394 dv = (void*)((uintptr_t)dv + datapeek_ssz-1);
1395 }
1396 *(char**)datapeek_p = datapeek_s;
1397 } else {
1398 datapeek_csz = tpl_size_for(*datapeek_c);
1399 if ((uintptr_t)dv-(uintptr_t)addr + datapeek_csz > sz) {
1400 tpl_hook.oops("tpl_peek: tpl has insufficient length\n");
1401 tpl_hook.free(fmt_cpy); fmt_cpy = NULL((void*)0); /* fail */
1402 goto fail;
1403 }
1404 memcpy(datapeek_p, dv, datapeek_csz);
1405 if (xendian) tpl_byteswap(datapeek_p, datapeek_csz);
1406 dv = (void*)((uintptr_t)dv + datapeek_csz);
1407 }
1408 }
1409 }
1410
1411fail:
1412 va_end(ap)__builtin_va_end(ap);
1413 if ((mode & TPL_FILE(1 << 0)) && mr.text != NULL((void*)0)) tpl_unmap_file( &mr );
1414 return fmt_cpy;
1415}
1416
1417/* tpl_jot(TPL_FILE, "file.tpl", "si", &s, &i); */
1418/* tpl_jot(TPL_MEM, &buf, &sz, "si", &s, &i); */
1419/* tpl_jot(TPL_FD, fd, "si", &s, &i); */
1420TPL_API int tpl_jot(int mode, ...) {
1421 va_list ap;
1422 char *filename, *fmt;
1423 size_t *sz;
1424 int fd, rc=0;
1425 void **buf;
1426 tpl_node *tn;
1427
1428 va_start(ap,mode)__builtin_va_start(ap, mode);
1429 if (mode & TPL_FILE(1 << 0)) {
1430 filename = va_arg(ap,char*)__builtin_va_arg(ap, char*);
1431 fmt = va_arg(ap,char*)__builtin_va_arg(ap, char*);
1432 tn = tpl_map_va(fmt, ap);
1433 if (tn == NULL((void*)0)) { rc=-1; goto fail;}
1434 tpl_pack(tn, 0);
1435 rc = tpl_dump(tn, TPL_FILE(1 << 0), filename);
1436 tpl_free(tn);
1437 } else if (mode & TPL_MEM(1 << 1)) {
1438 buf = va_arg(ap,void*)__builtin_va_arg(ap, void*);
1439 sz = va_arg(ap,size_t*)__builtin_va_arg(ap, size_t*);
1440 fmt = va_arg(ap,char*)__builtin_va_arg(ap, char*);
1441 tn = tpl_map_va(fmt,ap);
1442 if (tn == NULL((void*)0)) { rc=-1; goto fail;}
1443 tpl_pack(tn,0);
1444 rc = tpl_dump(tn, TPL_MEM(1 << 1), buf, sz);
1445 tpl_free(tn);
1446 } else if (mode & TPL_FD(1 << 4)) {
1447 fd = va_arg(ap,int)__builtin_va_arg(ap, int);
1448 fmt = va_arg(ap,char*)__builtin_va_arg(ap, char*);
1449 tn = tpl_map_va(fmt,ap);
1450 if (tn == NULL((void*)0)) { rc=-1; goto fail;}
1451 tpl_pack(tn,0);
1452 rc = tpl_dump(tn, TPL_FD(1 << 4), fd);
1453 tpl_free(tn);
1454 } else {
1455 tpl_hook.fatal("invalid tpl_jot mode\n");
1456 }
1457
1458fail:
1459 va_end(ap)__builtin_va_end(ap);
1460 return rc;
1461}
1462
1463TPL_API int tpl_load(tpl_node *r, int mode, ...) {
1464 va_list ap;
1465 int rc=0,fd=0;
1466 char *filename=NULL((void*)0);
1467 void *addr;
1468 size_t sz;
1469
1470 va_start(ap,mode)__builtin_va_start(ap, mode);
1471 if (mode & TPL_FILE(1 << 0)) filename = va_arg(ap,char *)__builtin_va_arg(ap, char *);
1472 else if (mode & TPL_MEM(1 << 1)) {
1473 addr = va_arg(ap,void *)__builtin_va_arg(ap, void *);
1474 sz = va_arg(ap,size_t)__builtin_va_arg(ap, size_t);
1475 } else if (mode & TPL_FD(1 << 4)) {
1476 fd = va_arg(ap,int)__builtin_va_arg(ap, int);
1477 } else {
1478 tpl_hook.oops("unsupported tpl_load mode %d\n", mode);
1479 return -1;
1480 }
1481 va_end(ap)__builtin_va_end(ap);
1482
1483 if (r->type != TPL_TYPE_ROOT0) {
1484 tpl_hook.oops("error: tpl_load to non-root node\n");
1485 return -1;
1486 }
1487 if (((tpl_root_data*)(r->data))->flags & (TPL_WRONLY(1 << 9)|TPL_RDONLY(1 << 10))) {
1488 /* already packed or loaded, so reset it as if newly mapped */
1489 tpl_free_keep_map(r);
1490 }
1491 if (mode & TPL_FILE(1 << 0)) {
1492 if (tpl_mmap_file(filename, &((tpl_root_data*)(r->data))->mmap) != 0) {
1493 tpl_hook.oops("tpl_load failed for file %s\n", filename);
1494 return -1;
1495 }
1496 if ( (rc = tpl_sanity(r, (mode & TPL_EXCESS_OK(1 << 3)))) != 0) {
1497 if (rc == ERR_FMT_MISMATCH(-6)) {
1498 tpl_hook.oops("%s: format signature mismatch\n", filename);
1499 } else if (rc == ERR_FLEN_MISMATCH(-7)) {
1500 tpl_hook.oops("%s: array lengths mismatch\n", filename);
1501 } else {
1502 tpl_hook.oops("%s: not a valid tpl file\n", filename);
1503 }
1504 tpl_unmap_file( &((tpl_root_data*)(r->data))->mmap );
1505 return -1;
1506 }
1507 ((tpl_root_data*)(r->data))->flags = (TPL_FILE(1 << 0) | TPL_RDONLY(1 << 10));
1508 } else if (mode & TPL_MEM(1 << 1)) {
1509 ((tpl_root_data*)(r->data))->mmap.text = addr;
1510 ((tpl_root_data*)(r->data))->mmap.text_sz = sz;
1511 if ( (rc = tpl_sanity(r, (mode & TPL_EXCESS_OK(1 << 3)))) != 0) {
1512 if (rc == ERR_FMT_MISMATCH(-6)) {
1513 tpl_hook.oops("format signature mismatch\n");
1514 } else {
1515 tpl_hook.oops("not a valid tpl file\n");
1516 }
1517 return -1;
1518 }
1519 ((tpl_root_data*)(r->data))->flags = (TPL_MEM(1 << 1) | TPL_RDONLY(1 << 10));
1520 if (mode & TPL_UFREE(1 << 5)) ((tpl_root_data*)(r->data))->flags |= TPL_UFREE(1 << 5);
1521 } else if (mode & TPL_FD(1 << 4)) {
1522 /* if fd read succeeds, resulting mem img is used for load */
1523 if (tpl_gather(TPL_GATHER_BLOCKING1,fd,&addr,&sz) > 0) {
1524 return tpl_load(r, TPL_MEM(1 << 1)|TPL_UFREE(1 << 5), addr, sz);
1525 } else return -1;
1526 } else {
1527 tpl_hook.oops("invalid tpl_load mode %d\n", mode);
1528 return -1;
1529 }
1530 /* this applies to TPL_MEM or TPL_FILE */
1531 if (tpl_needs_endian_swap(((tpl_root_data*)(r->data))->mmap.text))
1532 ((tpl_root_data*)(r->data))->flags |= TPL_XENDIAN(1 << 11);
1533 tpl_unpackA0(r); /* prepare root A nodes for use */
1534 return 0;
1535}
1536
1537TPL_API int tpl_Alen(tpl_node *r, int i) {
1538 tpl_node *n;
1539
1540 n = tpl_find_i(r,i);
1541 if (n == NULL((void*)0)) {
1542 tpl_hook.oops("invalid index %d to tpl_unpack\n", i);
1543 return -1;
1544 }
1545 if (n->type != TPL_TYPE_ARY5) return -1;
1546 return ((tpl_atyp*)(n->data))->num;
1547}
1548
1549static void tpl_free_atyp(tpl_node *n, tpl_atyp *atyp) {
1550 tpl_backbone *bb,*bbnxt;
1551 tpl_node *c;
1552 void *dv;
1553 tpl_bin *binp;
1554 tpl_atyp *atypp;
1555 char *strp;
1556 size_t itermax;
1557 tpl_pound_data *pd;
1558 int i;
1559
1560 bb = atyp->bb;
1561 while (bb) {
1562 bbnxt = bb->next;
1563 dv = bb->data;
1564 c=n->children;
1565 while (c) {
1566 switch (c->type) {
1567 case TPL_TYPE_BYTE3:
1568 case TPL_TYPE_DOUBLE7:
1569 case TPL_TYPE_INT321:
1570 case TPL_TYPE_UINT322:
1571 case TPL_TYPE_INT648:
1572 case TPL_TYPE_UINT649:
1573 case TPL_TYPE_INT1610:
1574 case TPL_TYPE_UINT1611:
1575 dv = (void*)((uintptr_t)dv + tpl_types[c->type].sz*c->num);
1576 break;
1577 case TPL_TYPE_BIN6:
1578 memcpy(&binp,dv,sizeof(tpl_bin*)); /* cp to aligned */
1579 if (binp->addr) tpl_hook.free( binp->addr ); /* free buf */
1580 tpl_hook.free(binp); /* free tpl_bin */
1581 dv = (void*)((uintptr_t)dv + sizeof(tpl_bin*));
1582 break;
1583 case TPL_TYPE_STR4:
1584 for(i=0; i < c->num; i++) {
1585 memcpy(&strp,dv,sizeof(char*)); /* cp to aligned */
1586 if (strp) tpl_hook.free(strp); /* free string */
1587 dv = (void*)((uintptr_t)dv + sizeof(char*));
1588 }
1589 break;
1590 case TPL_TYPE_POUND12:
1591 /* iterate over the preceding nodes */
1592 itermax = c->num;
1593 pd = (tpl_pound_data*)c->data;
1594 if (++(pd->iternum) < itermax) {
1595 c = pd->iter_start_node;
1596 continue;
1597 } else { /* loop complete. */
1598 pd->iternum = 0;
1599 }
1600 break;
1601 case TPL_TYPE_ARY5:
1602 memcpy(&atypp,dv,sizeof(tpl_atyp*)); /* cp to aligned */
1603 tpl_free_atyp(c,atypp); /* free atyp */
1604 dv = (void*)((uintptr_t)dv + sizeof(void*));
1605 break;
1606 default:
1607 tpl_hook.fatal("unsupported format character\n");
1608 break;
1609 }
1610 c=c->next;
1611 }
1612 tpl_hook.free(bb);
1613 bb = bbnxt;
1614 }
1615 tpl_hook.free(atyp);
1616}
1617
1618/* determine (by walking) byte length of serialized r/A node at address dv
1619 * returns 0 on success, or -1 if the tpl isn't trustworthy (fails consistency)
1620 */
1621static int tpl_serlen(tpl_node *r, tpl_node *n, void *dv, size_t *serlen) {
1622 uint32_t slen;
1623 int num = 0,fidx;
1624 tpl_node *c;
1625 size_t len=0, alen, buf_past, itermax;
1626 tpl_pound_data *pd;
1627
1628 buf_past = ((uintptr_t)((tpl_root_data*)(r->data))->mmap.text +
1629 ((tpl_root_data*)(r->data))->mmap.text_sz);
1630
1631 if (n->type == TPL_TYPE_ROOT0) num = 1;
1632 else if (n->type == TPL_TYPE_ARY5) {
1633 if ((uintptr_t)dv + sizeof(uint32_t) > buf_past) return -1;
1634 memcpy(&num,dv,sizeof(uint32_t));
1635 if (((tpl_root_data*)(r->data))->flags & TPL_XENDIAN(1 << 11))
1636 tpl_byteswap(&num, sizeof(uint32_t));
1637 dv = (void*)((uintptr_t)dv + sizeof(uint32_t));
1638 len += sizeof(uint32_t);
1639 } else tpl_hook.fatal("internal error in tpl_serlen\n");
1640
1641 while (num-- > 0) {
1642 c=n->children;
1643 while (c) {
1644 switch (c->type) {
1645 case TPL_TYPE_BYTE3:
1646 case TPL_TYPE_DOUBLE7:
1647 case TPL_TYPE_INT321:
1648 case TPL_TYPE_UINT322:
1649 case TPL_TYPE_INT648:
1650 case TPL_TYPE_UINT649:
1651 case TPL_TYPE_INT1610:
1652 case TPL_TYPE_UINT1611:
1653 for(fidx=0; fidx < c->num; fidx++) { /* octothorpe support */
1654 if ((uintptr_t)dv + tpl_types[c->type].sz > buf_past) return -1;
1655 dv = (void*)((uintptr_t)dv + tpl_types[c->type].sz);
1656 len += tpl_types[c->type].sz;
1657 }
1658 break;
1659 case TPL_TYPE_BIN6:
1660 len += sizeof(uint32_t);
1661 if ((uintptr_t)dv + sizeof(uint32_t) > buf_past) return -1;
1662 memcpy(&slen,dv,sizeof(uint32_t));
1663 if (((tpl_root_data*)(r->data))->flags & TPL_XENDIAN(1 << 11))
1664 tpl_byteswap(&slen, sizeof(uint32_t));
1665 len += slen;
1666 dv = (void*)((uintptr_t)dv + sizeof(uint32_t));
1667 if ((uintptr_t)dv + slen > buf_past) return -1;
1668 dv = (void*)((uintptr_t)dv + slen);
1669 break;
1670 case TPL_TYPE_STR4:
1671 for(fidx=0; fidx < c->num; fidx++) { /* octothorpe support */
1672 len += sizeof(uint32_t);
1673 if ((uintptr_t)dv + sizeof(uint32_t) > buf_past) return -1;
1674 memcpy(&slen,dv,sizeof(uint32_t));
1675 if (((tpl_root_data*)(r->data))->flags & TPL_XENDIAN(1 << 11))
1676 tpl_byteswap(&slen, sizeof(uint32_t));
1677 if (!(((tpl_root_data*)(r->data))->flags & TPL_OLD_STRING_FMT(1 << 12)))
1678 slen = (slen>1) ? (slen-1) : 0;
1679 len += slen;
1680 dv = (void*)((uintptr_t)dv + sizeof(uint32_t));
1681 if ((uintptr_t)dv + slen > buf_past) return -1;
1682 dv = (void*)((uintptr_t)dv + slen);
1683 }
1684 break;
1685 case TPL_TYPE_ARY5:
1686 if ( tpl_serlen(r,c,dv, &alen) == -1) return -1;
1687 dv = (void*)((uintptr_t)dv + alen);
1688 len += alen;
1689 break;
1690 case TPL_TYPE_POUND12:
1691 /* iterate over the preceding nodes */
1692 itermax = c->num;
1693 pd = (tpl_pound_data*)c->data;
1694 if (++(pd->iternum) < itermax) {
1695 c = pd->iter_start_node;
1696 continue;
1697 } else { /* loop complete. */
1698 pd->iternum = 0;
1699 }
1700 break;
1701 default:
1702 tpl_hook.fatal("unsupported format character\n");
1703 break;
1704 }
1705 c=c->next;
1706 }
1707 }
1708 *serlen = len;
1709 return 0;
1710}
1711
1712static int tpl_mmap_output_file(char *filename, size_t sz, void **text_out) {
1713 void *text;
1714 int fd,perms;
1715
1716#ifndef _WIN32
1717 perms = S_IRUSR0400|S_IWUSR0200|S_IWGRP(0200 >> 3)|S_IRGRP(0400 >> 3)|S_IROTH((0400 >> 3) >> 3); /* ug+w o+r */
1718 fd=open(filename,O_CREAT0100|O_TRUNC01000|O_RDWR02,perms);
1719#else
1720 perms = _S_IWRITE;
1721 fd=_open(filename,_O_CREAT|_O_TRUNC|_O_RDWR,perms);
1722#endif
1723
1724 if ( fd == -1 ) {
1725 tpl_hook.oops("Couldn't open file %s: %s\n", filename, strerror(errno(*__errno_location ())));
1726 return -1;
1727 }
1728
1729 text = mmap(0, sz, PROT_READ0x1|PROT_WRITE0x2, MAP_SHARED0x01, fd, 0);
1730 if (text == MAP_FAILED((void *) -1)) {
1731 tpl_hook.oops("Failed to mmap %s: %s\n", filename, strerror(errno(*__errno_location ())));
1732 close(fd);
1733 return -1;
1734 }
1735 if (ftruncate(fd,sz) == -1) {
1736 tpl_hook.oops("ftruncate failed: %s\n", strerror(errno(*__errno_location ())));
1737 munmap( text, sz );
1738 close(fd);
1739 return -1;
1740 }
1741 *text_out = text;
1742 return fd;
1743}
1744
1745static int tpl_mmap_file(char *filename, tpl_mmap_rec *mr) {
1746 struct stat stat_buf;
1747
1748 if ( (mr->fd = open(filename, O_RDONLY00)) == -1 ) {
1749 tpl_hook.oops("Couldn't open file %s: %s\n", filename, strerror(errno(*__errno_location ())));
1750 return -1;
1751 }
1752
1753 if ( fstat(mr->fd, &stat_buf) == -1) {
1754 close(mr->fd);
1755 tpl_hook.oops("Couldn't stat file %s: %s\n", filename, strerror(errno(*__errno_location ())));
1756 return -1;
1757 }
1758
1759 mr->text_sz = (size_t)stat_buf.st_size;
1760 mr->text = mmap(0, stat_buf.st_size, PROT_READ0x1, MAP_PRIVATE0x02, mr->fd, 0);
1761 if (mr->text == MAP_FAILED((void *) -1)) {
1762 close(mr->fd);
1763 tpl_hook.oops("Failed to mmap %s: %s\n", filename, strerror(errno(*__errno_location ())));
1764 return -1;
1765 }
1766
1767 return 0;
1768}
1769
1770TPL_API int tpl_pack(tpl_node *r, int i) {
1771 tpl_node *n, *child, *np;
1772 void *datav=NULL((void*)0);
1773 size_t sz, itermax;
1774 uint32_t slen;
1775 char *str;
1776 tpl_bin *bin;
1777 tpl_pound_data *pd;
1778 int fidx;
1779
1780 n = tpl_find_i(r,i);
1781 if (n == NULL((void*)0)) {
1782 tpl_hook.oops("invalid index %d to tpl_pack\n", i);
1783 return -1;
1784 }
1785
1786 if (((tpl_root_data*)(r->data))->flags & TPL_RDONLY(1 << 10)) {
1787 /* convert to an writeable tpl, initially empty */
1788 tpl_free_keep_map(r);
1789 }
1790
1791 ((tpl_root_data*)(r->data))->flags |= TPL_WRONLY(1 << 9);
1792
1793 if (n->type == TPL_TYPE_ARY5) datav = tpl_extend_backbone(n);
1794 child = n->children;
1795 while(child) {
1796 switch(child->type) {
1797 case TPL_TYPE_BYTE3:
1798 case TPL_TYPE_DOUBLE7:
1799 case TPL_TYPE_INT321:
1800 case TPL_TYPE_UINT322:
1801 case TPL_TYPE_INT648:
1802 case TPL_TYPE_UINT649:
1803 case TPL_TYPE_INT1610:
1804 case TPL_TYPE_UINT1611:
1805 /* no need to use fidx iteration here; we can copy multiple values in one memcpy */
1806 memcpy(child->data,child->addr,tpl_types[child->type].sz * child->num);
1807 if (datav) datav = tpl_cpv(datav,child->data,tpl_types[child->type].sz * child->num);
1808 if (n->type == TPL_TYPE_ARY5) n->ser_osz += tpl_types[child->type].sz * child->num;
1809 break;
1810 case TPL_TYPE_BIN6:
1811 /* copy the buffer to be packed */
1812 slen = ((tpl_bin*)child->addr)->sz;
1813 if (slen >0) {
1814 str = tpl_hook.malloc(slen);
1815 if (!str) fatal_oom()tpl_hook.fatal("out of memory\n");
1816 memcpy(str,((tpl_bin*)child->addr)->addr,slen);
1817 } else str = NULL((void*)0);
1818 /* and make a tpl_bin to point to it */
1819 bin = tpl_hook.malloc(sizeof(tpl_bin));
1820 if (!bin) fatal_oom()tpl_hook.fatal("out of memory\n");
1821 bin->addr = str;
1822 bin->sz = slen;
1823 /* now pack its pointer, first deep freeing any pre-existing bin */
1824 if (*(tpl_bin**)(child->data) != NULL((void*)0)) {
1825 if ((*(tpl_bin**)(child->data))->sz != 0) {
1826 tpl_hook.free( (*(tpl_bin**)(child->data))->addr );
1827 }
1828 tpl_hook.free(*(tpl_bin**)(child->data));
1829 }
1830 memcpy(child->data,&bin,sizeof(tpl_bin*));
1831 if (datav) {
1832 datav = tpl_cpv(datav, &bin, sizeof(tpl_bin*));
1833 *(tpl_bin**)(child->data) = NULL((void*)0);
1834 }
1835 if (n->type == TPL_TYPE_ARY5) {
1836 n->ser_osz += sizeof(uint32_t); /* binary buf len word */
1837 n->ser_osz += bin->sz; /* binary buf */
1838 }
1839 break;
1840 case TPL_TYPE_STR4:
1841 for(fidx=0; fidx < child->num; fidx++) {
1842 /* copy the string to be packed. slen includes \0. this
1843 block also works if the string pointer is NULL. */
1844 char *caddr = ((char**)child->addr)[fidx];
1845 char **cdata = &((char**)child->data)[fidx];
1846 slen = caddr ? (strlen(caddr) + 1) : 0;
1847 if (slen) {
1848 str = tpl_hook.malloc(slen);
1849 if (!str) fatal_oom()tpl_hook.fatal("out of memory\n");
1850 memcpy(str,caddr,slen); /* include \0 */
1851 } else {
1852 str = NULL((void*)0);
1853 }
1854 /* now pack its pointer, first freeing any pre-existing string */
1855 if (*cdata != NULL((void*)0)) {
1856 tpl_hook.free(*cdata);
1857 }
1858 memcpy(cdata,&str,sizeof(char*));
1859 if (datav) {
1860 datav = tpl_cpv(datav, &str, sizeof(char*));
1861 *cdata = NULL((void*)0);
1862 }
1863 if (n->type == TPL_TYPE_ARY5) {
1864 n->ser_osz += sizeof(uint32_t); /* string len word */
1865 if (slen>1) n->ser_osz += slen-1;/* string (without nul) */
1866 }
1867 }
1868 break;
1869 case TPL_TYPE_ARY5:
1870 /* copy the child's tpl_atype* and reset it to empty */
1871 if (datav) {
1872 sz = ((tpl_atyp*)(child->data))->sz;
1873 datav = tpl_cpv(datav, &child->data, sizeof(void*));
1874 child->data = tpl_hook.malloc(sizeof(tpl_atyp));
1875 if (!child->data) fatal_oom()tpl_hook.fatal("out of memory\n");
1876 ((tpl_atyp*)(child->data))->num = 0;
1877 ((tpl_atyp*)(child->data))->sz = sz;
1878 ((tpl_atyp*)(child->data))->bb = NULL((void*)0);
1879 ((tpl_atyp*)(child->data))->bbtail = NULL((void*)0);
1880 }
1881 /* parent is array? then bubble up child array's ser_osz */
1882 if (n->type == TPL_TYPE_ARY5) {
1883 n->ser_osz += sizeof(uint32_t); /* array len word */
1884 n->ser_osz += child->ser_osz; /* child array ser_osz */
1885 child->ser_osz = 0; /* reset child array ser_osz */
1886 }
1887 break;
1888
1889 case TPL_TYPE_POUND12:
1890 /* we need to iterate n times over preceding nodes in S(...).
1891 * we may be in the midst of an iteration each time or starting. */
1892 pd = (tpl_pound_data*)child->data;
1893 itermax = child->num;
1894
1895 /* itermax is total num of iterations needed */
1896 /* pd->iternum is current iteration index */
1897 /* pd->inter_elt_len is element-to-element len of contiguous structs */
1898 /* pd->iter_start_node is where we jump to at each iteration. */
1899
1900 if (++(pd->iternum) < itermax) {
1901
1902 /* in start or midst of loop. advance addr/data pointers. */
1903 for(np=pd->iter_start_node; np != child; np = np->next) {
1904 np->data = (char*)(np->data) +
1905 (tpl_types[np->type].sz * np->num);
1906 np->addr = (char*)(np->addr) + pd->inter_elt_len;
1907 }
1908 /* do next iteration */
1909 child = pd->iter_start_node;
1910 continue;
1911
1912 } else { /* loop complete. */
1913
1914 /* reset iteration index and addr/data pointers. */
1915 pd->iternum = 0;
1916 for(np=pd->iter_start_node; np != child; np = np->next) {
1917 np->data = (char*)(np->data) - ((itermax-1) *
1918 tpl_types[np->type].sz *
1919 np->num);
1920 np->addr = (char*)(np->addr) - ((itermax-1) * pd->inter_elt_len);
1921 }
1922
1923 }
1924 break;
1925 default:
1926 tpl_hook.fatal("unsupported format character\n");
1927 break;
1928 }
1929 child=child->next;
1930 }
1931 return 0;
1932}
1933
1934TPL_API int tpl_unpack(tpl_node *r, int i) {
1935 tpl_node *n, *c, *np;
1936 uint32_t slen;
1937 int rc=1, fidx;
1938 char *str;
1939 void *dv=NULL((void*)0), *caddr;
1940 size_t A_bytes, itermax;
1941 tpl_pound_data *pd;
1942 void *img;
1943 size_t sz;
1944
1945
1946 /* handle unusual case of tpl_pack,tpl_unpack without an
1947 * intervening tpl_dump. do a dump/load implicitly. */
1948 if (((tpl_root_data*)(r->data))->flags & TPL_WRONLY(1 << 9)) {
1949 if (tpl_dump(r,TPL_MEM(1 << 1),&img,&sz) != 0) return -1;
1950 if (tpl_load(r,TPL_MEM(1 << 1)|TPL_UFREE(1 << 5),img,sz) != 0) {
1951 tpl_hook.free(img);
1952 return -1;
1953 };
1954 }
1955
1956 n = tpl_find_i(r,i);
1957 if (n == NULL((void*)0)) {
1958 tpl_hook.oops("invalid index %d to tpl_unpack\n", i);
1959 return -1;
1960 }
1961
1962 /* either root node or an A node */
1963 if (n->type == TPL_TYPE_ROOT0) {
1964 dv = tpl_find_data_start( ((tpl_root_data*)(n->data))->mmap.text );
1965 } else if (n->type == TPL_TYPE_ARY5) {
1966 if (((tpl_atyp*)(n->data))->num <= 0) return 0; /* array consumed */
1967 else rc = ((tpl_atyp*)(n->data))->num--;
1968 dv = ((tpl_atyp*)(n->data))->cur;
1969 if (!dv) tpl_hook.fatal("must unpack parent of node before node itself\n");
1970 }
1971
1972 c = n->children;
1973 while (c) {
1974 switch (c->type) {
1975 case TPL_TYPE_BYTE3:
1976 case TPL_TYPE_DOUBLE7:
1977 case TPL_TYPE_INT321:
1978 case TPL_TYPE_UINT322:
1979 case TPL_TYPE_INT648:
1980 case TPL_TYPE_UINT649:
1981 case TPL_TYPE_INT1610:
1982 case TPL_TYPE_UINT1611:
1983 /* unpack elements of cross-endian octothorpic array individually */
1984 if (((tpl_root_data*)(r->data))->flags & TPL_XENDIAN(1 << 11)) {
1985 for(fidx=0; fidx < c->num; fidx++) {
1986 caddr = (void*)((uintptr_t)c->addr + (fidx * tpl_types[c->type].sz));
1987 memcpy(caddr,dv,tpl_types[c->type].sz);
1988 tpl_byteswap(caddr, tpl_types[c->type].sz);
1989 dv = (void*)((uintptr_t)dv + tpl_types[c->type].sz);
1990 }
1991 } else {
1992 /* bulk unpack ok if not cross-endian */
1993 memcpy(c->addr, dv, tpl_types[c->type].sz * c->num);
1994 dv = (void*)((uintptr_t)dv + tpl_types[c->type].sz * c->num);
1995 }
1996 break;
1997 case TPL_TYPE_BIN6:
1998 memcpy(&slen,dv,sizeof(uint32_t));
1999 if (((tpl_root_data*)(r->data))->flags & TPL_XENDIAN(1 << 11))
2000 tpl_byteswap(&slen, sizeof(uint32_t));
2001 if (slen > 0) {
2002 str = (char*)tpl_hook.malloc(slen);
2003 if (!str) fatal_oom()tpl_hook.fatal("out of memory\n");
2004 } else str=NULL((void*)0);
2005 dv = (void*)((uintptr_t)dv + sizeof(uint32_t));
2006 if (slen>0) memcpy(str,dv,slen);
2007 memcpy(&(((tpl_bin*)c->addr)->addr),&str,sizeof(void*));
2008 memcpy(&(((tpl_bin*)c->addr)->sz),&slen,sizeof(uint32_t));
2009 dv = (void*)((uintptr_t)dv + slen);
2010 break;
2011 case TPL_TYPE_STR4:
2012 for(fidx=0; fidx < c->num; fidx++) {
2013 memcpy(&slen,dv,sizeof(uint32_t));
2014 if (((tpl_root_data*)(r->data))->flags & TPL_XENDIAN(1 << 11))
2015 tpl_byteswap(&slen, sizeof(uint32_t));
2016 if (((tpl_root_data*)(r->data))->flags & TPL_OLD_STRING_FMT(1 << 12))
2017 slen += 1;
2018 dv = (void*)((uintptr_t)dv + sizeof(uint32_t));
2019 if (slen) { /* slen includes \0 */
2020 str = (char*)tpl_hook.malloc(slen);
2021 if (!str) fatal_oom()tpl_hook.fatal("out of memory\n");
2022 if (slen>1) memcpy(str,dv,slen-1);
2023 str[slen-1] = '\0'; /* nul terminate */
2024 dv = (void*)((uintptr_t)dv + slen-1);
2025 } else str=NULL((void*)0);
2026 memcpy(&((char**)c->addr)[fidx],&str,sizeof(char*));
2027 }
2028 break;
2029 case TPL_TYPE_POUND12:
2030 /* iterate over preceding nodes */
2031 pd = (tpl_pound_data*)c->data;
2032 itermax = c->num;
2033 if (++(pd->iternum) < itermax) {
2034 /* in start or midst of loop. advance addr/data pointers. */
2035 for(np=pd->iter_start_node; np != c; np = np->next) {
2036 np->addr = (char*)(np->addr) + pd->inter_elt_len;
2037 }
2038 /* do next iteration */
2039 c = pd->iter_start_node;
2040 continue;
2041
2042 } else { /* loop complete. */
2043
2044 /* reset iteration index and addr/data pointers. */
2045 pd->iternum = 0;
2046 for(np=pd->iter_start_node; np != c; np = np->next) {
2047 np->addr = (char*)(np->addr) - ((itermax-1) * pd->inter_elt_len);
2048 }
2049
2050 }
2051 break;
2052 case TPL_TYPE_ARY5:
2053 if (tpl_serlen(r,c,dv, &A_bytes) == -1)
2054 tpl_hook.fatal("internal error in unpack\n");
2055 memcpy( &((tpl_atyp*)(c->data))->num, dv, sizeof(uint32_t));
2056 if (((tpl_root_data*)(r->data))->flags & TPL_XENDIAN(1 << 11))
2057 tpl_byteswap(&((tpl_atyp*)(c->data))->num, sizeof(uint32_t));
2058 ((tpl_atyp*)(c->data))->cur = (void*)((uintptr_t)dv+sizeof(uint32_t));
2059 dv = (void*)((uintptr_t)dv + A_bytes);
2060 break;
2061 default:
2062 tpl_hook.fatal("unsupported format character\n");
2063 break;
2064 }
2065
2066 c = c->next;
2067 }
2068 if (n->type == TPL_TYPE_ARY5) ((tpl_atyp*)(n->data))->cur = dv; /* next element */
2069 return rc;
2070}
2071
2072/* Specialized function that unpacks only the root's A nodes, after tpl_load */
2073static int tpl_unpackA0(tpl_node *r) {
2074 tpl_node *n, *c;
2075 uint32_t slen;
2076 int rc=1,fidx,i;
2077 void *dv;
2078 size_t A_bytes, itermax;
2079 tpl_pound_data *pd;
2080
2081 n = r;
2082 dv = tpl_find_data_start( ((tpl_root_data*)(r->data))->mmap.text);
2083
2084 c=n->children;
2085 while (c) {
2086 switch (c->type) {
2087 case TPL_TYPE_BYTE3:
2088 case TPL_TYPE_DOUBLE7:
2089 case TPL_TYPE_INT321:
2090 case TPL_TYPE_UINT322:
2091 case TPL_TYPE_INT648:
2092 case TPL_TYPE_UINT649:
2093 case TPL_TYPE_INT1610:
2094 case TPL_TYPE_UINT1611:
2095 for(fidx=0;fidx < c->num; fidx++) {
2096 dv = (void*)((uintptr_t)dv + tpl_types[c->type].sz);
2097 }
2098 break;
2099 case TPL_TYPE_BIN6:
2100 memcpy(&slen,dv,sizeof(uint32_t));
2101 if (((tpl_root_data*)(r->data))->flags & TPL_XENDIAN(1 << 11))
2102 tpl_byteswap(&slen, sizeof(uint32_t));
2103 dv = (void*)((uintptr_t)dv + sizeof(uint32_t));
2104 dv = (void*)((uintptr_t)dv + slen);
2105 break;
2106 case TPL_TYPE_STR4:
2107 for(i=0; i<c->num; i++) {
2108 memcpy(&slen,dv,sizeof(uint32_t));
2109 if (((tpl_root_data*)(r->data))->flags & TPL_XENDIAN(1 << 11))
2110 tpl_byteswap(&slen, sizeof(uint32_t));
2111 if (((tpl_root_data*)(r->data))->flags & TPL_OLD_STRING_FMT(1 << 12))
2112 slen += 1;
2113 dv = (void*)((uintptr_t)dv + sizeof(uint32_t));
2114 if (slen>1) dv = (void*)((uintptr_t)dv + slen-1);
2115 }
2116 break;
2117 case TPL_TYPE_POUND12:
2118 /* iterate over the preceding nodes */
2119 itermax = c->num;
2120 pd = (tpl_pound_data*)c->data;
2121 if (++(pd->iternum) < itermax) {
2122 c = pd->iter_start_node;
2123 continue;
2124 } else { /* loop complete. */
2125 pd->iternum = 0;
2126 }
2127 break;
2128 case TPL_TYPE_ARY5:
2129 if ( tpl_serlen(r,c,dv, &A_bytes) == -1)
2130 tpl_hook.fatal("internal error in unpackA0\n");
2131 memcpy( &((tpl_atyp*)(c->data))->num, dv, sizeof(uint32_t));
2132 if (((tpl_root_data*)(r->data))->flags & TPL_XENDIAN(1 << 11))
2133 tpl_byteswap(&((tpl_atyp*)(c->data))->num, sizeof(uint32_t));
2134 ((tpl_atyp*)(c->data))->cur = (void*)((uintptr_t)dv+sizeof(uint32_t));
2135 dv = (void*)((uintptr_t)dv + A_bytes);
2136 break;
2137 default:
2138 tpl_hook.fatal("unsupported format character\n");
2139 break;
2140 }
2141 c=c->next;
2142 }
2143 return rc;
2144}
2145
2146/* In-place byte order swapping of a word of length "len" bytes */
2147static void tpl_byteswap(void *word, int len) {
2148 int i;
2149 char c, *w;
2150 w = (char*)word;
2151 for(i=0; i<len/2; i++) {
2152 c = w[i];
2153 w[i] = w[len-1-i];
2154 w[len-1-i] = c;
2155 }
2156}
2157
2158static void tpl_fatal(char *fmt, ...) {
2159 va_list ap;
2160 char exit_msg[100];
2161
2162 va_start(ap,fmt)__builtin_va_start(ap, fmt);
2163 vsnprintf(exit_msg, 100, fmt, ap);
2164 va_end(ap)__builtin_va_end(ap);
2165
2166 tpl_hook.oops("%s", exit_msg);
2167 exit(-1);
2168}
2169
2170TPL_API int tpl_gather(int mode, ...) {
2171 va_list ap;
2172 int fd,rc=0;
2173 size_t *szp,sz;
2174 void **img,*addr,*data;
2175 tpl_gather_t **gs;
2176 tpl_gather_cb *cb;
2177
2178 va_start(ap,mode)__builtin_va_start(ap, mode);
2179 switch (mode) {
2180 case TPL_GATHER_BLOCKING1:
2181 fd = va_arg(ap,int)__builtin_va_arg(ap, int);
2182 img = va_arg(ap,void*)__builtin_va_arg(ap, void*);
2183 szp = va_arg(ap,size_t*)__builtin_va_arg(ap, size_t*);
2184 rc = tpl_gather_blocking(fd,img,szp);
2185 break;
2186 case TPL_GATHER_NONBLOCKING2:
2187 fd = va_arg(ap,int)__builtin_va_arg(ap, int);
2188 gs = (tpl_gather_t**)va_arg(ap,void*)__builtin_va_arg(ap, void*);
2189 cb = (tpl_gather_cb*)va_arg(ap,tpl_gather_cb*)__builtin_va_arg(ap, tpl_gather_cb*);
2190 data = va_arg(ap,void*)__builtin_va_arg(ap, void*);
2191 rc = tpl_gather_nonblocking(fd,gs,cb,data);
2192 break;
2193 case TPL_GATHER_MEM3:
2194 addr = va_arg(ap,void*)__builtin_va_arg(ap, void*);
2195 sz = va_arg(ap,size_t)__builtin_va_arg(ap, size_t);
2196 gs = (tpl_gather_t**)va_arg(ap,void*)__builtin_va_arg(ap, void*);
2197 cb = (tpl_gather_cb*)va_arg(ap,tpl_gather_cb*)__builtin_va_arg(ap, tpl_gather_cb*);
2198 data = va_arg(ap,void*)__builtin_va_arg(ap, void*);
2199 rc = tpl_gather_mem(addr,sz,gs,cb,data);
2200 break;
2201 default:
2202 tpl_hook.fatal("unsupported tpl_gather mode %d\n",mode);
2203 break;
2204 }
2205 va_end(ap)__builtin_va_end(ap);
2206 return rc;
2207}
2208
2209/* dequeue a tpl by reading until one full tpl image is obtained.
2210 * We take care not to read past the end of the tpl.
2211 * This is intended as a blocking call i.e. for use with a blocking fd.
2212 * It can be given a non-blocking fd, but the read spins if we have to wait.
2213 */
2214static int tpl_gather_blocking(int fd, void **img, size_t *sz) {
2215 char preamble[8];
2216 int i=0, rc;
2217 uint32_t tpllen;
2218
2219 do {
2220 rc = read(fd,&preamble[i],8-i);
2221 i += (rc>0) ? rc : 0;
2222 } while ((rc==-1 && (errno(*__errno_location ())==EINTR4||errno(*__errno_location ())==EAGAIN11)) || (rc>0 && i<8));
2223
2224 if (rc<0) {
2225 tpl_hook.oops("tpl_gather_fd_blocking failed: %s\n", strerror(errno(*__errno_location ())));
2226 return -1;
2227 } else if (rc == 0) {
2228 /* tpl_hook.oops("tpl_gather_fd_blocking: eof\n"); */
2229 return 0;
2230 } else if (i != 8) {
2231 tpl_hook.oops("internal error\n");
2232 return -1;
2233 }
2234
2235 if (preamble[0] == 't' && preamble[1] == 'p' && preamble[2] == 'l') {
2236 memcpy(&tpllen,&preamble[4],4);
2237 if (tpl_needs_endian_swap(preamble)) tpl_byteswap(&tpllen,4);
2238 } else {
2239 tpl_hook.oops("tpl_gather_fd_blocking: non-tpl input\n");
2240 return -1;
2241 }
2242
2243 /* malloc space for remainder of tpl image (overall length tpllen)
2244 * and read it in
2245 */
2246 if (tpl_hook.gather_max > 0 &&
2247 tpllen > tpl_hook.gather_max) {
2248 tpl_hook.oops("tpl exceeds max length %d\n",
2249 tpl_hook.gather_max);
2250 return -2;
2251 }
2252 *sz = tpllen;
2253 if ( (*img = tpl_hook.malloc(tpllen)) == NULL((void*)0)) {
2254 fatal_oom()tpl_hook.fatal("out of memory\n");
2255 }
2256
2257 memcpy(*img,preamble,8); /* copy preamble to output buffer */
2258 i=8;
2259 do {
2260 rc = read(fd,&((*(char**)img)[i]),tpllen-i);
2261 i += (rc>0) ? rc : 0;
2262 } while ((rc==-1 && (errno(*__errno_location ())==EINTR4||errno(*__errno_location ())==EAGAIN11)) || (rc>0 && i<tpllen));
2263
2264 if (rc<0) {
2265 tpl_hook.oops("tpl_gather_fd_blocking failed: %s\n", strerror(errno(*__errno_location ())));
2266 tpl_hook.free(*img);
2267 return -1;
2268 } else if (rc == 0) {
2269 /* tpl_hook.oops("tpl_gather_fd_blocking: eof\n"); */
2270 tpl_hook.free(*img);
2271 return 0;
2272 } else if (i != tpllen) {
2273 tpl_hook.oops("internal error\n");
2274 tpl_hook.free(*img);
2275 return -1;
2276 }
2277
2278 return 1;
2279}
2280
2281/* Used by select()-driven apps which want to gather tpl images piecemeal */
2282/* the file descriptor must be non-blocking for this functino to work. */
2283static int tpl_gather_nonblocking( int fd, tpl_gather_t **gs, tpl_gather_cb *cb, void *data) {
2284 char buf[TPL_GATHER_BUFLEN8192], *img, *tpl;
2285 int rc, keep_looping, cbrc=0;
2286 size_t catlen;
2287 uint32_t tpllen;
2288
2289 while (1) {
2290 rc = read(fd,buf,TPL_GATHER_BUFLEN8192);
2291 if (rc == -1) {
2292 if (errno(*__errno_location ()) == EINTR4) continue; /* got signal during read, ignore */
2293 if (errno(*__errno_location ()) == EAGAIN11) return 1; /* nothing to read right now */
2294 else {
2295 tpl_hook.oops("tpl_gather failed: %s\n", strerror(errno(*__errno_location ())));
2296 if (*gs) {
2297 tpl_hook.free((*gs)->img);
2298 tpl_hook.free(*gs);
2299 *gs = NULL((void*)0);
2300 }
2301 return -1; /* error, caller should close fd */
2302 }
2303 } else if (rc == 0) {
2304 if (*gs) {
2305 tpl_hook.oops("tpl_gather: partial tpl image precedes EOF\n");
2306 tpl_hook.free((*gs)->img);
2307 tpl_hook.free(*gs);
2308 *gs = NULL((void*)0);
2309 }
2310 return 0; /* EOF, caller should close fd */
2311 } else {
2312 /* concatenate any partial tpl from last read with new buffer */
2313 if (*gs) {
2314 catlen = (*gs)->len + rc;
2315 if (tpl_hook.gather_max > 0 &&
2316 catlen > tpl_hook.gather_max) {
2317 tpl_hook.free( (*gs)->img );
2318 tpl_hook.free( (*gs) );
2319 *gs = NULL((void*)0);
2320 tpl_hook.oops("tpl exceeds max length %d\n",
2321 tpl_hook.gather_max);
2322 return -2; /* error, caller should close fd */
2323 }
2324 if ( (img = tpl_hook.realloc((*gs)->img, catlen)) == NULL((void*)0)) {
2325 fatal_oom()tpl_hook.fatal("out of memory\n");
2326 }
2327 memcpy(img + (*gs)->len, buf, rc);
2328 tpl_hook.free(*gs);
2329 *gs = NULL((void*)0);
2330 } else {
2331 img = buf;
2332 catlen = rc;
2333 }
2334 /* isolate any full tpl(s) in img and invoke cb for each */
2335 tpl = img;
2336 keep_looping = (tpl+8 < img+catlen) ? 1 : 0;
2337 while (keep_looping) {
2338 if (strncmp("tpl", tpl, 3)(__extension__ (__builtin_constant_p (3) && ((__builtin_constant_p
("tpl") && strlen ("tpl") < ((size_t) (3))) || (__builtin_constant_p
(tpl) && strlen (tpl) < ((size_t) (3)))) ? __extension__
({ size_t __s1_len, __s2_len; (__builtin_constant_p ("tpl") &&
__builtin_constant_p (tpl) && (__s1_len = __builtin_strlen
("tpl"), __s2_len = __builtin_strlen (tpl), (!((size_t)(const
void *)(("tpl") + 1) - (size_t)(const void *)("tpl") == 1) ||
__s1_len >= 4) && (!((size_t)(const void *)((tpl)
+ 1) - (size_t)(const void *)(tpl) == 1) || __s2_len >= 4
)) ? __builtin_strcmp ("tpl", tpl) : (__builtin_constant_p ("tpl"
) && ((size_t)(const void *)(("tpl") + 1) - (size_t)(
const void *)("tpl") == 1) && (__s1_len = __builtin_strlen
("tpl"), __s1_len < 4) ? (__builtin_constant_p (tpl) &&
((size_t)(const void *)((tpl) + 1) - (size_t)(const void *)(
tpl) == 1) ? __builtin_strcmp ("tpl", tpl) : (__extension__ (
{ const unsigned char *__s2 = (const unsigned char *) (const char
*) (tpl); int __result = (((const unsigned char *) (const char
*) ("tpl"))[0] - __s2[0]); if (__s1_len > 0 && __result
== 0) { __result = (((const unsigned char *) (const char *) (
"tpl"))[1] - __s2[1]); if (__s1_len > 1 && __result
== 0) { __result = (((const unsigned char *) (const char *) (
"tpl"))[2] - __s2[2]); if (__s1_len > 2 && __result
== 0) __result = (((const unsigned char *) (const char *) ("tpl"
))[3] - __s2[3]); } } __result; }))) : (__builtin_constant_p (
tpl) && ((size_t)(const void *)((tpl) + 1) - (size_t)
(const void *)(tpl) == 1) && (__s2_len = __builtin_strlen
(tpl), __s2_len < 4) ? (__builtin_constant_p ("tpl") &&
((size_t)(const void *)(("tpl") + 1) - (size_t)(const void *
)("tpl") == 1) ? __builtin_strcmp ("tpl", tpl) : (- (__extension__
({ const unsigned char *__s2 = (const unsigned char *) (const
char *) ("tpl"); int __result = (((const unsigned char *) (const
char *) (tpl))[0] - __s2[0]); if (__s2_len > 0 &&
__result == 0) { __result = (((const unsigned char *) (const
char *) (tpl))[1] - __s2[1]); if (__s2_len > 1 &&
__result == 0) { __result = (((const unsigned char *) (const
char *) (tpl))[2] - __s2[2]); if (__s2_len > 2 &&
__result == 0) __result = (((const unsigned char *) (const char
*) (tpl))[3] - __s2[3]); } } __result; })))) : __builtin_strcmp
("tpl", tpl)))); }) : strncmp ("tpl", tpl, 3)))
!= 0) {
2339 tpl_hook.oops("tpl prefix invalid\n");
2340 if (img != buf) tpl_hook.free(img);
2341 tpl_hook.free(*gs);
2342 *gs = NULL((void*)0);
2343 return -3; /* error, caller should close fd */
2344 }
2345 memcpy(&tpllen,&tpl[4],4);
2346 if (tpl_needs_endian_swap(tpl)) tpl_byteswap(&tpllen,4);
2347 if (tpl+tpllen <= img+catlen) {
2348 cbrc = (cb)(tpl,tpllen,data); /* invoke cb for tpl image */
2349 tpl += tpllen; /* point to next tpl image */
2350 if (cbrc < 0) keep_looping = 0;
2351 else keep_looping = (tpl+8 < img+catlen) ? 1 : 0;
2352 } else keep_looping=0;
2353 }
2354 /* check if app callback requested closure of tpl source */
2355 if (cbrc < 0) {
2356 tpl_hook.oops("tpl_fd_gather aborted by app callback\n");
2357 if (img != buf) tpl_hook.free(img);
2358 if (*gs) tpl_hook.free(*gs);
2359 *gs = NULL((void*)0);
2360 return -4;
2361 }
2362 /* store any leftover, partial tpl fragment for next read */
2363 if (tpl == img && img != buf) {
2364 /* consumed nothing from img!=buf */
2365 if ( (*gs = tpl_hook.malloc(sizeof(tpl_gather_t))) == NULL((void*)0) ) {
2366 fatal_oom()tpl_hook.fatal("out of memory\n");
2367 }
2368 (*gs)->img = tpl;
2369 (*gs)->len = catlen;
2370 } else if (tpl < img+catlen) {
2371 /* consumed 1+ tpl(s) from img!=buf or 0 from img==buf */
2372 if ( (*gs = tpl_hook.malloc(sizeof(tpl_gather_t))) == NULL((void*)0) ) {
2373 fatal_oom()tpl_hook.fatal("out of memory\n");
2374 }
2375 if ( ((*gs)->img = tpl_hook.malloc(img+catlen - tpl)) == NULL((void*)0) ) {
2376 fatal_oom()tpl_hook.fatal("out of memory\n");
2377 }
2378 (*gs)->len = img+catlen - tpl;
2379 memcpy( (*gs)->img, tpl, img+catlen - tpl);
2380 /* free partially consumed concat buffer if used */
2381 if (img != buf) tpl_hook.free(img);
2382 } else { /* tpl(s) fully consumed */
2383 /* free consumed concat buffer if used */
2384 if (img != buf) tpl_hook.free(img);
2385 }
2386 }
2387 }
2388}
2389
2390/* gather tpl piecemeal from memory buffer (not fd) e.g., from a lower-level api */
2391static int tpl_gather_mem( char *buf, size_t len, tpl_gather_t **gs, tpl_gather_cb *cb, void *data) {
2392 char *img, *tpl;
2393 int keep_looping, cbrc=0;
2394 size_t catlen;
2395 uint32_t tpllen;
2396
2397 /* concatenate any partial tpl from last read with new buffer */
2398 if (*gs) {
2399 catlen = (*gs)->len + len;
2400 if (tpl_hook.gather_max > 0 &&
2401 catlen > tpl_hook.gather_max) {
2402 tpl_hook.free( (*gs)->img );
2403 tpl_hook.free( (*gs) );
2404 *gs = NULL((void*)0);
2405 tpl_hook.oops("tpl exceeds max length %d\n",
2406 tpl_hook.gather_max);
2407 return -2; /* error, caller should stop accepting input from source*/
2408 }
2409 if ( (img = tpl_hook.realloc((*gs)->img, catlen)) == NULL((void*)0)) {
2410 fatal_oom()tpl_hook.fatal("out of memory\n");
2411 }
2412 memcpy(img + (*gs)->len, buf, len);
2413 tpl_hook.free(*gs);
2414 *gs = NULL((void*)0);
2415 } else {
2416 img = buf;
2417 catlen = len;
2418 }
2419 /* isolate any full tpl(s) in img and invoke cb for each */
2420 tpl = img;
2421 keep_looping = (tpl+8 < img+catlen) ? 1 : 0;
2422 while (keep_looping) {
2423 if (strncmp("tpl", tpl, 3)(__extension__ (__builtin_constant_p (3) && ((__builtin_constant_p
("tpl") && strlen ("tpl") < ((size_t) (3))) || (__builtin_constant_p
(tpl) && strlen (tpl) < ((size_t) (3)))) ? __extension__
({ size_t __s1_len, __s2_len; (__builtin_constant_p ("tpl") &&
__builtin_constant_p (tpl) && (__s1_len = __builtin_strlen
("tpl"), __s2_len = __builtin_strlen (tpl), (!((size_t)(const
void *)(("tpl") + 1) - (size_t)(const void *)("tpl") == 1) ||
__s1_len >= 4) && (!((size_t)(const void *)((tpl)
+ 1) - (size_t)(const void *)(tpl) == 1) || __s2_len >= 4
)) ? __builtin_strcmp ("tpl", tpl) : (__builtin_constant_p ("tpl"
) && ((size_t)(const void *)(("tpl") + 1) - (size_t)(
const void *)("tpl") == 1) && (__s1_len = __builtin_strlen
("tpl"), __s1_len < 4) ? (__builtin_constant_p (tpl) &&
((size_t)(const void *)((tpl) + 1) - (size_t)(const void *)(
tpl) == 1) ? __builtin_strcmp ("tpl", tpl) : (__extension__ (
{ const unsigned char *__s2 = (const unsigned char *) (const char
*) (tpl); int __result = (((const unsigned char *) (const char
*) ("tpl"))[0] - __s2[0]); if (__s1_len > 0 && __result
== 0) { __result = (((const unsigned char *) (const char *) (
"tpl"))[1] - __s2[1]); if (__s1_len > 1 && __result
== 0) { __result = (((const unsigned char *) (const char *) (
"tpl"))[2] - __s2[2]); if (__s1_len > 2 && __result
== 0) __result = (((const unsigned char *) (const char *) ("tpl"
))[3] - __s2[3]); } } __result; }))) : (__builtin_constant_p (
tpl) && ((size_t)(const void *)((tpl) + 1) - (size_t)
(const void *)(tpl) == 1) && (__s2_len = __builtin_strlen
(tpl), __s2_len < 4) ? (__builtin_constant_p ("tpl") &&
((size_t)(const void *)(("tpl") + 1) - (size_t)(const void *
)("tpl") == 1) ? __builtin_strcmp ("tpl", tpl) : (- (__extension__
({ const unsigned char *__s2 = (const unsigned char *) (const
char *) ("tpl"); int __result = (((const unsigned char *) (const
char *) (tpl))[0] - __s2[0]); if (__s2_len > 0 &&
__result == 0) { __result = (((const unsigned char *) (const
char *) (tpl))[1] - __s2[1]); if (__s2_len > 1 &&
__result == 0) { __result = (((const unsigned char *) (const
char *) (tpl))[2] - __s2[2]); if (__s2_len > 2 &&
__result == 0) __result = (((const unsigned char *) (const char
*) (tpl))[3] - __s2[3]); } } __result; })))) : __builtin_strcmp
("tpl", tpl)))); }) : strncmp ("tpl", tpl, 3)))
!= 0) {
2424 tpl_hook.oops("tpl prefix invalid\n");
2425 if (img != buf) tpl_hook.free(img);
2426 tpl_hook.free(*gs);
2427 *gs = NULL((void*)0);
2428 return -3; /* error, caller should stop accepting input from source*/
2429 }
2430 memcpy(&tpllen,&tpl[4],4);
2431 if (tpl_needs_endian_swap(tpl)) tpl_byteswap(&tpllen,4);
2432 if (tpl+tpllen <= img+catlen) {
2433 cbrc = (cb)(tpl,tpllen,data); /* invoke cb for tpl image */
2434 tpl += tpllen; /* point to next tpl image */
2435 if (cbrc < 0) keep_looping = 0;
2436 else keep_looping = (tpl+8 < img+catlen) ? 1 : 0;
2437 } else keep_looping=0;
2438 }
2439 /* check if app callback requested closure of tpl source */
2440 if (cbrc < 0) {
2441 tpl_hook.oops("tpl_mem_gather aborted by app callback\n");
2442 if (img != buf) tpl_hook.free(img);
2443 if (*gs) tpl_hook.free(*gs);
2444 *gs = NULL((void*)0);
2445 return -4;
2446 }
2447 /* store any leftover, partial tpl fragment for next read */
2448 if (tpl == img && img != buf) {
2449 /* consumed nothing from img!=buf */
2450 if ( (*gs = tpl_hook.malloc(sizeof(tpl_gather_t))) == NULL((void*)0) ) {
2451 fatal_oom()tpl_hook.fatal("out of memory\n");
2452 }
2453 (*gs)->img = tpl;
2454 (*gs)->len = catlen;
2455 } else if (tpl < img+catlen) {
2456 /* consumed 1+ tpl(s) from img!=buf or 0 from img==buf */
2457 if ( (*gs = tpl_hook.malloc(sizeof(tpl_gather_t))) == NULL((void*)0) ) {
2458 fatal_oom()tpl_hook.fatal("out of memory\n");
2459 }
2460 if ( ((*gs)->img = tpl_hook.malloc(img+catlen - tpl)) == NULL((void*)0) ) {
2461 fatal_oom()tpl_hook.fatal("out of memory\n");
2462 }
2463 (*gs)->len = img+catlen - tpl;
2464 memcpy( (*gs)->img, tpl, img+catlen - tpl);
2465 /* free partially consumed concat buffer if used */
2466 if (img != buf) tpl_hook.free(img);
2467 } else { /* tpl(s) fully consumed */
2468 /* free consumed concat buffer if used */
2469 if (img != buf) tpl_hook.free(img);
2470 }
2471 return 1;
2472}