| File: | libs/libtpl-1.5/src/tpl.c |
| Location: | line 464, column 19 |
| 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 | } |