File: | libs/libtpl-1.5/src/tpl.c |
Location: | line 2379, column 17 |
Description: | Null pointer passed as an argument to a 'nonnull' parameter |
1 | /* | |||
2 | Copyright (c) 2005-2010, Troy D. Hanson http://tpl.sourceforge.net | |||
3 | All rights reserved. | |||
4 | ||||
5 | Redistribution and use in source and binary forms, with or without | |||
6 | modification, 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 | ||||
11 | THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS | |||
12 | IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED | |||
13 | TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A | |||
14 | PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER | |||
15 | OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, | |||
16 | EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, | |||
17 | PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR | |||
18 | PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF | |||
19 | LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING | |||
20 | NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS | |||
21 | SOFTWARE, 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 | |||
47 | typedef unsigned short ushort; | |||
48 | typedef __int16 int16_t; | |||
49 | typedef __int32 int32_t; | |||
50 | typedef __int64 int64_t; | |||
51 | typedef unsigned __int16 uint16_t; | |||
52 | typedef unsigned __int32 uint32_t; | |||
53 | typedef 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 */ | |||
125 | typedef struct tpl_pidx { | |||
126 | struct tpl_node *node; | |||
127 | struct tpl_pidx *next,*prev; | |||
128 | } tpl_pidx; | |||
129 | ||||
130 | /* A(...) node datum */ | |||
131 | typedef 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 */ | |||
139 | typedef 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 */ | |||
151 | typedef struct tpl_mmap_rec { | |||
152 | int fd; | |||
153 | void *text; | |||
154 | size_t text_sz; | |||
155 | } tpl_mmap_rec; | |||
156 | ||||
157 | /* root node datum */ | |||
158 | typedef 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 */ | |||
167 | struct tpl_type_t { | |||
168 | char c; | |||
169 | int sz; | |||
170 | }; | |||
171 | ||||
172 | ||||
173 | /* Internal prototypes */ | |||
174 | static tpl_node *tpl_node_new(tpl_node *parent); | |||
175 | static tpl_node *tpl_find_i(tpl_node *n, int i); | |||
176 | static void *tpl_cpv(void *datav, void *data, size_t sz); | |||
177 | static void *tpl_extend_backbone(tpl_node *n); | |||
178 | static char *tpl_fmt(tpl_node *r); | |||
179 | static void *tpl_dump_atyp(tpl_node *n, tpl_atyp* at, void *dv); | |||
180 | static size_t tpl_ser_osz(tpl_node *n); | |||
181 | static void tpl_free_atyp(tpl_node *n,tpl_atyp *atyp); | |||
182 | static int tpl_dump_to_mem(tpl_node *r, void *addr, size_t sz); | |||
183 | static int tpl_mmap_file(char *filename, tpl_mmap_rec *map_rec); | |||
184 | static int tpl_mmap_output_file(char *filename, size_t sz, void **text_out); | |||
185 | static int tpl_cpu_bigendian(void); | |||
186 | static int tpl_needs_endian_swap(void *); | |||
187 | static void tpl_byteswap(void *word, int len); | |||
188 | static void tpl_fatal(char *fmt, ...); | |||
189 | static int tpl_serlen(tpl_node *r, tpl_node *n, void *dv, size_t *serlen); | |||
190 | static int tpl_unpackA0(tpl_node *r); | |||
191 | static int tpl_oops(const char *fmt, ...); | |||
192 | static int tpl_gather_mem( char *buf, size_t len, tpl_gather_t **gs, tpl_gather_cb *cb, void *data); | |||
193 | static int tpl_gather_nonblocking( int fd, tpl_gather_t **gs, tpl_gather_cb *cb, void *data); | |||
194 | static int tpl_gather_blocking(int fd, void **img, size_t *sz); | |||
195 | static 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 | */ | |||
203 | struct 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 */ | |||
210 | struct tpl_int64_alignment_detector { | |||
211 | int i; | |||
212 | int64_t j; /* some platforms align this on +4, others on +8 */ | |||
213 | }; | |||
214 | ||||
215 | typedef 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. */ | |||
222 | tpl_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 | ||||
231 | static const char tpl_fmt_chars[] = "AS($)BiucsfIUjv#"; /* valid format chars */ | |||
232 | //static const char tpl_S_fmt_chars[] = "iucsfIUjv#$()"; /* valid within S(...) */ | |||
233 | static const char tpl_datapeek_ok_chars[] = "iucsfIUjv"; /* valid in datapeek */ | |||
234 | static 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. */ | |||
251 | static 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 | ||||
260 | static 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 | */ | |||
283 | char *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 | ||||
310 | TPL_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 | ||||
320 | static 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 | ||||
565 | fail: | |||
566 | tpl_hook.oops("failed to parse %s\n", fmt); | |||
567 | tpl_free(root); | |||
568 | return NULL((void*)0); | |||
569 | } | |||
570 | ||||
571 | static 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 | ||||
582 | static 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 | ||||
677 | TPL_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) */ | |||
777 | static 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 | ||||
788 | static 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 | ||||
793 | static void *tpl_extend_backbone(tpl_node *n) { | |||
794 | tpl_backbone *bb; | |||
795 | bb = (tpl_backbone*)tpl_hook.malloc(sizeof(tpl_backbone) + | |||
796 | ((tpl_atyp*)(n->data))->sz ); /* datum hangs on coattails of bb */ | |||
797 | if (!bb) fatal_oom()tpl_hook.fatal("out of memory\n"); | |||
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); | |||
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) */ | |||
817 | static 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) */ | |||
822 | static 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 | */ | |||
831 | static 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*/ | |||
906 | static 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 | ||||
979 | TPL_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 | */ | |||
1059 | static 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 | ||||
1148 | static 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 | */ | |||
1164 | static 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 | ||||
1232 | static 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 | ||||
1245 | static 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 | ||||
1253 | static 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 | ||||
1261 | TPL_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 | ||||
1411 | fail: | |||
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); */ | |||
1420 | TPL_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 | ||||
1458 | fail: | |||
1459 | va_end(ap)__builtin_va_end(ap); | |||
1460 | return rc; | |||
1461 | } | |||
1462 | ||||
1463 | TPL_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 | ||||
1537 | TPL_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 | ||||
1549 | static 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 | */ | |||
1621 | static 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 | ||||
1712 | static 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 | ||||
1745 | static 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 | ||||
1770 | TPL_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 | ||||
1934 | TPL_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 */ | |||
2073 | static 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 */ | |||
2147 | static 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 | ||||
2158 | static 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 | ||||
2170 | TPL_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 | */ | |||
2214 | static 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. */ | |||
2283 | static 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 */ | |||
2391 | static 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 | } |