12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576777879808182838485868788899091929394959697989910010110210310410510610710810911011111211311411511611711811912012112212312412512612712812913013113213313413513613713813914014114214314414514614714814915015115215315415515615715815916016116216316416516616716816917017117217317417517617717817918018118218318418518618718818919019119219319419519619719819920020120220320420520620720820921021121221321421521621721821922022122222322422522622722822923023123223323423523623723823924024124224324424524624724824925025125225325425525625725825926026126226326426526626726826927027127227327427527627727827928028128228328428528628728828929029129229329429529629729829930030130230330430530630730830931031131231331431531631731831932032132232332432532632732832933033133233333433533633733833934034134234334434534634734834935035135235335435535635735835936036136236336436536636736836937037137237337437537637737837938038138238338438538638738838939039139239339439539639739839940040140240340440540640740840941041141241341441541641741841942042142242342442542642742842943043143243343443543643743843944044144244344444544644744844945045145245345445545645745845946046146246346446546646746846947047147247347447547647747847948048148248348448548648748848949049149249349449549649749849950050150250350450550650750850951051151251351451551651751851952052152252352452552652752852953053153253353453553653753853954054154254354454554654754854955055155255355455555655755855956056156256356456556656756856957057157257357457557657757857958058158258358458558658758858959059159259359459559659759859960060160260360460560660760860961061161261361461561661761861962062162262362462562662762862963063163263363463563663763863964064164264364464564664764864965065165265365465565665765865966066166266366466566666766866967067167267367467567667767867968068168268368468568668768868969069169269369469569669769869970070170270370470570670770870971071171271371471571671771871972072172272372472572672772872973073173273373473573673773873974074174274374474574674774874975075175275375475575675775875976076176276376476576676776876977077177277377477577677777877978078178278378478578678778878979079179279379479579679779879980080180280380480580680780880981081181281381481581681781881982082182282382482582682782882983083183283383483583683783883984084184284384484584684784884985085185285385485585685785885986086186286386486586686786886987087187287387487587687787887988088188288388488588688788888989089189289389489589689789889990090190290390490590690790890991091191291391491591691791891992092192292392492592692792892993093193293393493593693793893994094194294394494594694794894995095195295395495595695795895996096196296396496596696796896997097197297397497597697797897998098198298398498598698798898999099199299399499599699799899910001001100210031004100510061007100810091010101110121013101410151016101710181019102010211022102310241025102610271028102910301031103210331034103510361037103810391040104110421043104410451046104710481049105010511052105310541055105610571058105910601061106210631064106510661067106810691070107110721073107410751076107710781079108010811082108310841085108610871088108910901091109210931094109510961097109810991100110111021103110411051106110711081109111011111112111311141115111611171118111911201121112211231124112511261127112811291130113111321133113411351136113711381139114011411142114311441145114611471148114911501151115211531154115511561157115811591160116111621163116411651166116711681169117011711172117311741175117611771178117911801181118211831184118511861187118811891190119111921193119411951196119711981199120012011202120312041205120612071208120912101211121212131214121512161217121812191220122112221223122412251226122712281229123012311232123312341235123612371238123912401241124212431244124512461247124812491250125112521253125412551256125712581259126012611262126312641265126612671268126912701271127212731274127512761277127812791280128112821283128412851286128712881289129012911292129312941295129612971298129913001301130213031304130513061307130813091310131113121313131413151316131713181319132013211322132313241325132613271328132913301331133213331334133513361337133813391340134113421343134413451346134713481349135013511352135313541355135613571358135913601361136213631364136513661367136813691370137113721373137413751376137713781379138013811382138313841385138613871388138913901391139213931394139513961397139813991400140114021403140414051406140714081409141014111412141314141415141614171418141914201421142214231424142514261427142814291430143114321433143414351436143714381439144014411442144314441445144614471448144914501451145214531454145514561457145814591460146114621463146414651466146714681469147014711472147314741475147614771478147914801481148214831484148514861487148814891490149114921493149414951496149714981499150015011502150315041505150615071508150915101511151215131514151515161517151815191520152115221523152415251526152715281529153015311532153315341535153615371538153915401541154215431544154515461547154815491550155115521553155415551556155715581559156015611562156315641565156615671568156915701571157215731574157515761577157815791580158115821583158415851586158715881589159015911592159315941595159615971598159916001601160216031604160516061607160816091610161116121613161416151616161716181619162016211622162316241625162616271628162916301631163216331634163516361637163816391640164116421643164416451646164716481649165016511652165316541655165616571658165916601661166216631664166516661667166816691670167116721673167416751676167716781679168016811682168316841685168616871688168916901691169216931694169516961697169816991700170117021703170417051706170717081709171017111712171317141715171617171718171917201721172217231724172517261727172817291730173117321733173417351736173717381739174017411742174317441745174617471748174917501751175217531754175517561757175817591760176117621763176417651766176717681769177017711772177317741775177617771778177917801781178217831784178517861787178817891790179117921793179417951796179717981799180018011802180318041805180618071808180918101811181218131814181518161817181818191820182118221823182418251826182718281829183018311832183318341835183618371838183918401841184218431844184518461847184818491850185118521853185418551856185718581859186018611862186318641865186618671868186918701871187218731874187518761877187818791880188118821883188418851886188718881889189018911892189318941895189618971898189919001901190219031904190519061907190819091910191119121913191419151916191719181919192019211922192319241925192619271928192919301931193219331934193519361937193819391940194119421943194419451946194719481949195019511952195319541955195619571958195919601961196219631964196519661967196819691970197119721973197419751976197719781979198019811982198319841985198619871988198919901991199219931994199519961997199819992000200120022003200420052006200720082009201020112012201320142015201620172018201920202021202220232024202520262027202820292030203120322033203420352036203720382039204020412042204320442045204620472048204920502051205220532054205520562057205820592060206120622063206420652066206720682069207020712072207320742075207620772078207920802081208220832084208520862087208820892090209120922093209420952096209720982099210021012102210321042105210621072108210921102111211221132114211521162117211821192120212121222123212421252126212721282129213021312132213321342135213621372138213921402141214221432144214521462147214821492150215121522153215421552156215721582159216021612162216321642165216621672168216921702171217221732174217521762177217821792180218121822183218421852186218721882189219021912192219321942195219621972198219922002201220222032204220522062207220822092210221122122213221422152216221722182219222022212222222322242225222622272228222922302231223222332234223522362237223822392240224122422243224422452246224722482249225022512252225322542255225622572258225922602261226222632264226522662267226822692270227122722273227422752276227722782279228022812282228322842285228622872288228922902291229222932294229522962297229822992300230123022303230423052306230723082309231023112312231323142315231623172318231923202321232223232324232523262327232823292330233123322333233423352336233723382339234023412342234323442345234623472348234923502351235223532354235523562357235823592360236123622363236423652366236723682369237023712372237323742375237623772378237923802381238223832384238523862387238823892390239123922393239423952396239723982399240024012402240324042405240624072408240924102411241224132414241524162417241824192420242124222423242424252426242724282429243024312432243324342435243624372438243924402441244224432444244524462447244824492450245124522453245424552456245724582459246024612462246324642465246624672468246924702471247224732474247524762477247824792480248124822483248424852486248724882489 |
- /*
- Copyright (c) 2005-2013, Troy D. Hanson http://troydhanson.github.com/tpl/
- All rights reserved.
- Redistribution and use in source and binary forms, with or without
- modification, are permitted provided that the following conditions are met:
- * Redistributions of source code must retain the above copyright
- notice, this list of conditions and the following disclaimer.
- THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS
- IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
- TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A
- PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER
- OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
- EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
- PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
- PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
- LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
- NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
- SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
- */
- #define TPL_VERSION 1.6
- static const char id[]="$Id: tpl.c 192 2009-04-24 10:35:30Z thanson $";
- #include <stdlib.h> /* malloc */
- #include <stdarg.h> /* va_list */
- #include <string.h> /* memcpy, memset, strchr */
- #include <stdio.h> /* printf (tpl_hook.oops default function) */
- #ifndef _WIN32
- #include <unistd.h> /* for ftruncate */
- #else
- #include <io.h>
- #define ftruncate(x,y) _chsize(x,y)
- #endif
- #include <sys/types.h> /* for 'open' */
- #include <sys/stat.h> /* for 'open' */
- #include <fcntl.h> /* for 'open' */
- #include <errno.h>
- #ifndef _WIN32
- #include <inttypes.h> /* uint32_t, uint64_t, etc */
- #else
- typedef unsigned short ushort;
- typedef __int16 int16_t;
- typedef __int32 int32_t;
- typedef __int64 int64_t;
- typedef unsigned __int16 uint16_t;
- typedef unsigned __int32 uint32_t;
- typedef unsigned __int64 uint64_t;
- #endif
- #ifndef S_ISREG
- #define S_ISREG(mode) (((mode) & S_IFMT) == S_IFREG)
- #endif
- #if ( defined __CYGWIN__ || defined __MINGW32__ || defined _WIN32 )
- #include "win/mman.h" /* mmap */
- #else
- #include <sys/mman.h> /* mmap */
- #endif
- #include "tpl.h"
- #define TPL_GATHER_BUFLEN 8192
- #define TPL_MAGIC "tpl"
- /* macro to add a structure to a doubly-linked list */
- #define DL_ADD(head,add) \
- do { \
- if (head) { \
- (add)->prev = (head)->prev; \
- (head)->prev->next = (add); \
- (head)->prev = (add); \
- (add)->next = NULL; \
- } else { \
- (head)=(add); \
- (head)->prev = (head); \
- (head)->next = NULL; \
- } \
- } while (0);
- #define fatal_oom() tpl_hook.fatal("out of memory\n")
- /* bit flags (internal). preceded by the external flags in tpl.h */
- #define TPL_WRONLY (1 << 9) /* app has initiated tpl packing */
- #define TPL_RDONLY (1 << 10) /* tpl was loaded (for unpacking) */
- #define TPL_XENDIAN (1 << 11) /* swap endianness when unpacking */
- #define TPL_OLD_STRING_FMT (1 << 12) /* tpl has strings in 1.2 format */
- /* values for the flags byte that appears after the magic prefix */
- #define TPL_SUPPORTED_BITFLAGS 3
- #define TPL_FL_BIGENDIAN (1 << 0)
- #define TPL_FL_NULLSTRINGS (1 << 1)
- /* char values for node type */
- #define TPL_TYPE_ROOT 0
- #define TPL_TYPE_INT32 1
- #define TPL_TYPE_UINT32 2
- #define TPL_TYPE_BYTE 3
- #define TPL_TYPE_STR 4
- #define TPL_TYPE_ARY 5
- #define TPL_TYPE_BIN 6
- #define TPL_TYPE_DOUBLE 7
- #define TPL_TYPE_INT64 8
- #define TPL_TYPE_UINT64 9
- #define TPL_TYPE_INT16 10
- #define TPL_TYPE_UINT16 11
- #define TPL_TYPE_POUND 12
- /* error codes */
- #define ERR_NOT_MINSIZE (-1)
- #define ERR_MAGIC_MISMATCH (-2)
- #define ERR_INCONSISTENT_SZ (-3)
- #define ERR_FMT_INVALID (-4)
- #define ERR_FMT_MISSING_NUL (-5)
- #define ERR_FMT_MISMATCH (-6)
- #define ERR_FLEN_MISMATCH (-7)
- #define ERR_INCONSISTENT_SZ2 (-8)
- #define ERR_INCONSISTENT_SZ3 (-9)
- #define ERR_INCONSISTENT_SZ4 (-10)
- #define ERR_UNSUPPORTED_FLAGS (-11)
- /* access to A(...) nodes by index */
- typedef struct tpl_pidx {
- struct tpl_node *node;
- struct tpl_pidx *next,*prev;
- } tpl_pidx;
- /* A(...) node datum */
- typedef struct tpl_atyp {
- uint32_t num; /* num elements */
- size_t sz; /* size of each backbone's datum */
- struct tpl_backbone *bb,*bbtail;
- void *cur;
- } tpl_atyp;
- /* backbone to extend A(...) lists dynamically */
- typedef struct tpl_backbone {
- struct tpl_backbone *next;
- /* when this structure is malloc'd, extra space is alloc'd at the
- * end to store the backbone "datum", and data points to it. */
- #if __STDC_VERSION__ < 199901
- char *data;
- #else
- char data[];
- #endif
- } tpl_backbone;
- /* mmap record */
- typedef struct tpl_mmap_rec {
- int fd;
- void *text;
- size_t text_sz;
- } tpl_mmap_rec;
- /* root node datum */
- typedef struct tpl_root_data {
- int flags;
- tpl_pidx *pidx;
- tpl_mmap_rec mmap;
- char *fmt;
- int *fxlens, num_fxlens;
- } tpl_root_data;
- /* node type to size mapping */
- struct tpl_type_t {
- char c;
- int sz;
- };
- /* Internal prototypes */
- static tpl_node *tpl_node_new(tpl_node *parent);
- static tpl_node *tpl_find_i(tpl_node *n, int i);
- static void *tpl_cpv(void *datav, const void *data, size_t sz);
- static void *tpl_extend_backbone(tpl_node *n);
- static char *tpl_fmt(tpl_node *r);
- static void *tpl_dump_atyp(tpl_node *n, tpl_atyp* at, void *dv);
- static size_t tpl_ser_osz(tpl_node *n);
- static void tpl_free_atyp(tpl_node *n,tpl_atyp *atyp);
- static int tpl_dump_to_mem(tpl_node *r, void *addr, size_t sz);
- static int tpl_mmap_file(char *filename, tpl_mmap_rec *map_rec);
- static int tpl_mmap_output_file(char *filename, size_t sz, void **text_out);
- static int tpl_cpu_bigendian(void);
- static int tpl_needs_endian_swap(void *);
- static void tpl_byteswap(void *word, int len);
- static void tpl_fatal(const char *fmt, ...);
- static int tpl_serlen(tpl_node *r, tpl_node *n, void *dv, size_t *serlen);
- static int tpl_unpackA0(tpl_node *r);
- static int tpl_oops(const char *fmt, ...);
- static int tpl_gather_mem( char *buf, size_t len, tpl_gather_t **gs, tpl_gather_cb *cb, void *data);
- static int tpl_gather_nonblocking( int fd, tpl_gather_t **gs, tpl_gather_cb *cb, void *data);
- static int tpl_gather_blocking(int fd, void **img, size_t *sz);
- /* This is used internally to help calculate padding when a 'double'
- * follows a smaller datatype in a structure. Normally under gcc
- * on x86, d will be aligned at +4, however use of -malign-double
- * causes d to be aligned at +8 (this is actually faster on x86).
- * Also SPARC and x86_64 seem to align always on +8.
- */
- struct tpl_double_alignment_detector {
- char a;
- double d; /* some platforms align this on +4, others on +8 */
- };
- /* this is another case where alignment varies. mac os x/gcc was observed
- * to align the int64_t at +4 under -m32 and at +8 under -m64 */
- struct tpl_int64_alignment_detector {
- int i;
- int64_t j; /* some platforms align this on +4, others on +8 */
- };
- typedef struct {
- size_t inter_elt_len; /* padded inter-element len; i.e. &a[1].field - &a[0].field */
- tpl_node *iter_start_node; /* node to jump back to, as we start each new iteration */
- size_t iternum; /* current iteration number (total req'd. iter's in n->num) */
- } tpl_pound_data;
- /* Hooks for customizing tpl mem alloc, error handling, etc. Set defaults. */
- tpl_hook_t tpl_hook = {
- /* .oops = */ tpl_oops,
- /* .malloc = */ malloc,
- /* .realloc = */ realloc,
- /* .free = */ free,
- /* .fatal = */ tpl_fatal,
- /* .gather_max = */ 0 /* max tpl size (bytes) for tpl_gather */
- };
- static const char tpl_fmt_chars[] = "AS($)BiucsfIUjv#"; /* valid format chars */
- static const char tpl_S_fmt_chars[] = "iucsfIUjv#$()"; /* valid within S(...) */
- static const char tpl_datapeek_ok_chars[] = "iucsfIUjv"; /* valid in datapeek */
- static const struct tpl_type_t tpl_types[] = {
- /* [TPL_TYPE_ROOT] = */ {'r', 0},
- /* [TPL_TYPE_INT32] = */ {'i', sizeof(int32_t)},
- /* [TPL_TYPE_UINT32] = */ {'u', sizeof(uint32_t)},
- /* [TPL_TYPE_BYTE] = */ {'c', sizeof(char)},
- /* [TPL_TYPE_STR] = */ {'s', sizeof(char*)},
- /* [TPL_TYPE_ARY] = */ {'A', 0},
- /* [TPL_TYPE_BIN] = */ {'B', 0},
- /* [TPL_TYPE_DOUBLE] = */ {'f', 8}, /* not sizeof(double) as that varies */
- /* [TPL_TYPE_INT64] = */ {'I', sizeof(int64_t)},
- /* [TPL_TYPE_UINT64] = */ {'U', sizeof(uint64_t)},
- /* [TPL_TYPE_INT16] = */ {'j', sizeof(int16_t)},
- /* [TPL_TYPE_UINT16] = */ {'v', sizeof(uint16_t)},
- /* [TPL_TYPE_POUND] = */ {'#', 0},
- };
- /* default error-reporting function. Just writes to stderr. */
- static int tpl_oops(const char *fmt, ...) {
- va_list ap;
- va_start(ap,fmt);
- vfprintf(stderr,fmt,ap);
- va_end(ap);
- return 0;
- }
- static tpl_node *tpl_node_new(tpl_node *parent) {
- tpl_node *n;
- if ((n=tpl_hook.malloc(sizeof(tpl_node))) == NULL) {
- fatal_oom();
- }
- n->addr=NULL;
- n->data=NULL;
- n->num=1;
- n->ser_osz=0;
- n->children=NULL;
- n->next=NULL;
- n->parent=parent;
- return n;
- }
- /* Used in S(..) formats to pack several fields from a structure based on
- * only the structure address. We need to calculate field addresses
- * manually taking into account the size of the fields and intervening padding.
- * The wrinkle is that double is not normally aligned on x86-32 but the
- * -malign-double compiler option causes it to be. Double are aligned
- * on Sparc, and apparently on 64 bit x86. We use a helper structure
- * to detect whether double is aligned in this compilation environment.
- */
- char *calc_field_addr(tpl_node *parent, int type,char *struct_addr, int ordinal) {
- tpl_node *prev;
- int offset;
- int align_sz;
- if (ordinal == 1) return struct_addr; /* first field starts on structure address */
- /* generate enough padding so field addr is divisible by it's align_sz. 4, 8, etc */
- prev = parent->children->prev;
- switch(type) {
- case TPL_TYPE_DOUBLE:
- align_sz = sizeof(struct tpl_double_alignment_detector) > 12 ? 8 : 4;
- break;
- case TPL_TYPE_INT64:
- case TPL_TYPE_UINT64:
- align_sz = sizeof(struct tpl_int64_alignment_detector) > 12 ? 8 : 4;
- break;
- default:
- align_sz = tpl_types[type].sz;
- break;
- }
- offset = ((uintptr_t)prev->addr - (uintptr_t)struct_addr)
- + (tpl_types[prev->type].sz * prev->num);
- offset = (offset + align_sz - 1) / align_sz * align_sz;
- return struct_addr + offset;
- }
- TPL_API tpl_node *tpl_map(char *fmt,...) {
- va_list ap;
- tpl_node *tn;
- va_start(ap,fmt);
- tn = tpl_map_va(fmt, ap);
- va_end(ap);
- return tn;
- }
- TPL_API tpl_node *tpl_map_va(char *fmt, va_list ap) {
- int lparen_level=0,expect_lparen=0,t=0,in_structure=0,ordinal=0;
- int in_nested_structure=0;
- char *c, *peek, *struct_addr=NULL, *struct_next;
- tpl_node *root,*parent,*n=NULL,*preceding,*iter_start_node=NULL,
- *struct_widest_node=NULL, *np; tpl_pidx *pidx;
- tpl_pound_data *pd;
- int *fxlens, num_fxlens, pound_num, pound_prod, applies_to_struct;
- int contig_fxlens[10]; /* temp space for contiguous fxlens */
- int num_contig_fxlens, i, j;
- ptrdiff_t inter_elt_len=0; /* padded element length of contiguous structs in array */
- root = tpl_node_new(NULL);
- root->type = TPL_TYPE_ROOT;
- root->data = (tpl_root_data*)tpl_hook.malloc(sizeof(tpl_root_data));
- if (!root->data) fatal_oom();
- memset((tpl_root_data*)root->data,0,sizeof(tpl_root_data));
- /* set up root nodes special ser_osz to reflect overhead of preamble */
- root->ser_osz = sizeof(uint32_t); /* tpl leading length */
- root->ser_osz += strlen(fmt) + 1; /* fmt + NUL-terminator */
- root->ser_osz += 4; /* 'tpl' magic prefix + flags byte */
- parent=root;
- c=fmt;
- while (*c != '\0') {
- switch (*c) {
- case 'c':
- case 'i':
- case 'u':
- case 'j':
- case 'v':
- case 'I':
- case 'U':
- case 'f':
- if (*c=='c') t=TPL_TYPE_BYTE;
- else if (*c=='i') t=TPL_TYPE_INT32;
- else if (*c=='u') t=TPL_TYPE_UINT32;
- else if (*c=='j') t=TPL_TYPE_INT16;
- else if (*c=='v') t=TPL_TYPE_UINT16;
- else if (*c=='I') t=TPL_TYPE_INT64;
- else if (*c=='U') t=TPL_TYPE_UINT64;
- else if (*c=='f') t=TPL_TYPE_DOUBLE;
- if (expect_lparen) goto fail;
- n = tpl_node_new(parent);
- n->type = t;
- if (in_structure) {
- if (ordinal == 1) {
- /* for S(...)# iteration. Apply any changes to case 's' too!!! */
- iter_start_node = n;
- struct_widest_node = n;
- }
- if (tpl_types[n->type].sz > tpl_types[struct_widest_node->type].sz) {
- struct_widest_node = n;
- }
- n->addr = calc_field_addr(parent,n->type,struct_addr,ordinal++);
- } else n->addr = (void*)va_arg(ap,void*);
- n->data = tpl_hook.malloc(tpl_types[t].sz);
- if (!n->data) fatal_oom();
- if (n->parent->type == TPL_TYPE_ARY)
- ((tpl_atyp*)(n->parent->data))->sz += tpl_types[t].sz;
- DL_ADD(parent->children,n);
- break;
- case 's':
- if (expect_lparen) goto fail;
- n = tpl_node_new(parent);
- n->type = TPL_TYPE_STR;
- if (in_structure) {
- if (ordinal == 1) {
- iter_start_node = n; /* for S(...)# iteration */
- struct_widest_node = n;
- }
- if (tpl_types[n->type].sz > tpl_types[struct_widest_node->type].sz) {
- struct_widest_node = n;
- }
- n->addr = calc_field_addr(parent,n->type,struct_addr,ordinal++);
- } else n->addr = (void*)va_arg(ap,void*);
- n->data = tpl_hook.malloc(sizeof(char*));
- if (!n->data) fatal_oom();
- *(char**)(n->data) = NULL;
- if (n->parent->type == TPL_TYPE_ARY)
- ((tpl_atyp*)(n->parent->data))->sz += sizeof(void*);
- DL_ADD(parent->children,n);
- break;
- case '#':
- /* apply a 'num' to preceding atom */
- if (!parent->children) goto fail;
- preceding = parent->children->prev; /* first child's prev is 'last child'*/
- t = preceding->type;
- applies_to_struct = (*(c-1) == ')') ? 1 : 0;
- if (!applies_to_struct) {
- if (!(t == TPL_TYPE_BYTE || t == TPL_TYPE_INT32 ||
- t == TPL_TYPE_UINT32 || t == TPL_TYPE_DOUBLE ||
- t == TPL_TYPE_UINT64 || t == TPL_TYPE_INT64 ||
- t == TPL_TYPE_UINT16 || t == TPL_TYPE_INT16 ||
- t == TPL_TYPE_STR )) goto fail;
- }
- /* count up how many contiguous # and form their product */
- pound_prod=1;
- num_contig_fxlens=0;
- for(peek=c; *peek == '#'; peek++) {
- pound_num = va_arg(ap, int);
- if (pound_num < 1) {
- tpl_hook.fatal("non-positive iteration count %d\n", pound_num);
- }
- if (num_contig_fxlens >= (sizeof(contig_fxlens)/sizeof(contig_fxlens[0]))) {
- tpl_hook.fatal("contiguous # exceeds hardcoded limit\n");
- }
- contig_fxlens[num_contig_fxlens++] = pound_num;
- pound_prod *= pound_num;
- }
- /* increment c to skip contiguous # so its points to last one */
- c = peek-1;
- /* differentiate atom-# from struct-# by noting preceding rparen */
- if (applies_to_struct) { /* insert # node to induce looping */
- n = tpl_node_new(parent);
- n->type = TPL_TYPE_POUND;
- n->num = pound_prod;
- n->data = tpl_hook.malloc(sizeof(tpl_pound_data));
- if (!n->data) fatal_oom();
- pd = (tpl_pound_data*)n->data;
- pd->inter_elt_len = inter_elt_len;
- pd->iter_start_node = iter_start_node;
- pd->iternum = 0;
- DL_ADD(parent->children,n);
- /* multiply the 'num' and data space on each atom in the structure */
- for(np = iter_start_node; np != n; np = np->next) {
- if (n->parent->type == TPL_TYPE_ARY) {
- ((tpl_atyp*)(n->parent->data))->sz +=
- tpl_types[np->type].sz * (np->num * (n->num - 1));
- }
- np->data = tpl_hook.realloc(np->data, tpl_types[np->type].sz *
- np->num * n->num);
- if (!np->data) fatal_oom();
- memset(np->data, 0, tpl_types[np->type].sz * np->num * n->num);
- }
- } else { /* simple atom-# form does not require a loop */
- preceding->num = pound_prod;
- preceding->data = tpl_hook.realloc(preceding->data,
- tpl_types[t].sz * preceding->num);
- if (!preceding->data) fatal_oom();
- memset(preceding->data,0,tpl_types[t].sz * preceding->num);
- if (n->parent->type == TPL_TYPE_ARY) {
- ((tpl_atyp*)(n->parent->data))->sz += tpl_types[t].sz *
- (preceding->num-1);
- }
- }
- root->ser_osz += (sizeof(uint32_t) * num_contig_fxlens);
- j = ((tpl_root_data*)root->data)->num_fxlens; /* before incrementing */
- (((tpl_root_data*)root->data)->num_fxlens) += num_contig_fxlens;
- num_fxlens = ((tpl_root_data*)root->data)->num_fxlens; /* new value */
- fxlens = ((tpl_root_data*)root->data)->fxlens;
- fxlens = tpl_hook.realloc(fxlens, sizeof(int) * num_fxlens);
- if (!fxlens) fatal_oom();
- ((tpl_root_data*)root->data)->fxlens = fxlens;
- for(i=0; i < num_contig_fxlens; i++) fxlens[j++] = contig_fxlens[i];
- break;
- case 'B':
- if (expect_lparen) goto fail;
- if (in_structure) goto fail;
- n = tpl_node_new(parent);
- n->type = TPL_TYPE_BIN;
- n->addr = (tpl_bin*)va_arg(ap,void*);
- n->data = tpl_hook.malloc(sizeof(tpl_bin*));
- if (!n->data) fatal_oom();
- *((tpl_bin**)n->data) = NULL;
- if (n->parent->type == TPL_TYPE_ARY)
- ((tpl_atyp*)(n->parent->data))->sz += sizeof(tpl_bin);
- DL_ADD(parent->children,n);
- break;
- case 'A':
- if (in_structure) goto fail;
- n = tpl_node_new(parent);
- n->type = TPL_TYPE_ARY;
- DL_ADD(parent->children,n);
- parent = n;
- expect_lparen=1;
- pidx = (tpl_pidx*)tpl_hook.malloc(sizeof(tpl_pidx));
- if (!pidx) fatal_oom();
- pidx->node = n;
- pidx->next = NULL;
- DL_ADD(((tpl_root_data*)(root->data))->pidx,pidx);
- /* set up the A's tpl_atyp */
- n->data = (tpl_atyp*)tpl_hook.malloc(sizeof(tpl_atyp));
- if (!n->data) fatal_oom();
- ((tpl_atyp*)(n->data))->num = 0;
- ((tpl_atyp*)(n->data))->sz = 0;
- ((tpl_atyp*)(n->data))->bb = NULL;
- ((tpl_atyp*)(n->data))->bbtail = NULL;
- ((tpl_atyp*)(n->data))->cur = NULL;
- if (n->parent->type == TPL_TYPE_ARY)
- ((tpl_atyp*)(n->parent->data))->sz += sizeof(void*);
- break;
- case 'S':
- if (in_structure) goto fail;
- expect_lparen=1;
- ordinal=1; /* index upcoming atoms in S(..) */
- in_structure=1+lparen_level; /* so we can tell where S fmt ends */
- struct_addr = (char*)va_arg(ap,void*);
- break;
- case '$': /* nested structure */
- if (!in_structure) goto fail;
- expect_lparen=1;
- in_nested_structure++;
- break;
- case ')':
- lparen_level--;
- if (lparen_level < 0) goto fail;
- if (*(c-1) == '(') goto fail;
- if (in_nested_structure) in_nested_structure--;
- else if (in_structure && (in_structure-1 == lparen_level)) {
- /* calculate delta between contiguous structures in array */
- struct_next = calc_field_addr(parent, struct_widest_node->type,
- struct_addr, ordinal++);
- inter_elt_len = struct_next - struct_addr;
- in_structure=0;
- }
- else parent = parent->parent; /* rparen ends A() type, not S() type */
- break;
- case '(':
- if (!expect_lparen) goto fail;
- expect_lparen=0;
- lparen_level++;
- break;
- default:
- tpl_hook.oops("unsupported option %c\n", *c);
- goto fail;
- }
- c++;
- }
- if (lparen_level != 0) goto fail;
- /* copy the format string, save for convenience */
- ((tpl_root_data*)(root->data))->fmt = tpl_hook.malloc(strlen(fmt)+1);
- if (((tpl_root_data*)(root->data))->fmt == NULL)
- fatal_oom();
- memcpy(((tpl_root_data*)(root->data))->fmt,fmt,strlen(fmt)+1);
- return root;
- fail:
- tpl_hook.oops("failed to parse %s\n", fmt);
- tpl_free(root);
- return NULL;
- }
- static int tpl_unmap_file( tpl_mmap_rec *mr) {
- if ( munmap( mr->text, mr->text_sz ) == -1 ) {
- tpl_hook.oops("Failed to munmap: %s\n", strerror(errno));
- }
- close(mr->fd);
- mr->text = NULL;
- mr->text_sz = 0;
- return 0;
- }
- static void tpl_free_keep_map(tpl_node *r) {
- int mmap_bits = (TPL_RDONLY|TPL_FILE);
- int ufree_bits = (TPL_MEM|TPL_UFREE);
- tpl_node *nxtc,*c;
- int find_next_node=0,looking,i;
- size_t sz;
- /* For mmap'd files, or for 'ufree' memory images , do appropriate release */
- if ((((tpl_root_data*)(r->data))->flags & mmap_bits) == mmap_bits) {
- tpl_unmap_file( &((tpl_root_data*)(r->data))->mmap);
- } else if ((((tpl_root_data*)(r->data))->flags & ufree_bits) == ufree_bits) {
- tpl_hook.free( ((tpl_root_data*)(r->data))->mmap.text );
- }
- c = r->children;
- if (c) {
- while(c->type != TPL_TYPE_ROOT) { /* loop until we come back to root node */
- switch (c->type) {
- case TPL_TYPE_BIN:
- /* free any binary buffer hanging from tpl_bin */
- if ( *((tpl_bin**)(c->data)) ) {
- if ( (*((tpl_bin**)(c->data)))->addr ) {
- tpl_hook.free( (*((tpl_bin**)(c->data)))->addr );
- }
- *((tpl_bin**)c->data) = NULL; /* reset tpl_bin */
- }
- find_next_node=1;
- break;
- case TPL_TYPE_STR:
- /* free any packed (copied) string */
- for(i=0; i < c->num; i++) {
- char *str = ((char**)c->data)[i];
- if (str) {
- tpl_hook.free(str);
- ((char**)c->data)[i] = NULL;
- }
- }
- find_next_node=1;
- break;
- case TPL_TYPE_INT32:
- case TPL_TYPE_UINT32:
- case TPL_TYPE_INT64:
- case TPL_TYPE_UINT64:
- case TPL_TYPE_BYTE:
- case TPL_TYPE_DOUBLE:
- case TPL_TYPE_INT16:
- case TPL_TYPE_UINT16:
- case TPL_TYPE_POUND:
- find_next_node=1;
- break;
- case TPL_TYPE_ARY:
- c->ser_osz = 0; /* zero out the serialization output size */
- sz = ((tpl_atyp*)(c->data))->sz; /* save sz to use below */
- tpl_free_atyp(c,c->data);
- /* make new atyp */
- c->data = (tpl_atyp*)tpl_hook.malloc(sizeof(tpl_atyp));
- if (!c->data) fatal_oom();
- ((tpl_atyp*)(c->data))->num = 0;
- ((tpl_atyp*)(c->data))->sz = sz; /* restore bb datum sz */
- ((tpl_atyp*)(c->data))->bb = NULL;
- ((tpl_atyp*)(c->data))->bbtail = NULL;
- ((tpl_atyp*)(c->data))->cur = NULL;
- c = c->children;
- break;
- default:
- tpl_hook.fatal("unsupported format character\n");
- break;
- }
- if (find_next_node) {
- find_next_node=0;
- looking=1;
- while(looking) {
- if (c->next) {
- nxtc=c->next;
- c=nxtc;
- looking=0;
- } else {
- if (c->type == TPL_TYPE_ROOT) break; /* root node */
- else {
- nxtc=c->parent;
- c=nxtc;
- }
- }
- }
- }
- }
- }
- ((tpl_root_data*)(r->data))->flags = 0; /* reset flags */
- }
- TPL_API void tpl_free(tpl_node *r) {
- int mmap_bits = (TPL_RDONLY|TPL_FILE);
- int ufree_bits = (TPL_MEM|TPL_UFREE);
- tpl_node *nxtc,*c;
- int find_next_node=0,looking,num,i;
- tpl_pidx *pidx,*pidx_nxt;
- /* For mmap'd files, or for 'ufree' memory images , do appropriate release */
- if ((((tpl_root_data*)(r->data))->flags & mmap_bits) == mmap_bits) {
- tpl_unmap_file( &((tpl_root_data*)(r->data))->mmap);
- } else if ((((tpl_root_data*)(r->data))->flags & ufree_bits) == ufree_bits) {
- tpl_hook.free( ((tpl_root_data*)(r->data))->mmap.text );
- }
- c = r->children;
- if (c) {
- while(c->type != TPL_TYPE_ROOT) { /* loop until we come back to root node */
- switch (c->type) {
- case TPL_TYPE_BIN:
- /* free any binary buffer hanging from tpl_bin */
- if ( *((tpl_bin**)(c->data)) ) {
- if ( (*((tpl_bin**)(c->data)))->sz != 0 ) {
- tpl_hook.free( (*((tpl_bin**)(c->data)))->addr );
- }
- tpl_hook.free(*((tpl_bin**)c->data)); /* free tpl_bin */
- }
- tpl_hook.free(c->data); /* free tpl_bin* */
- find_next_node=1;
- break;
- case TPL_TYPE_STR:
- /* free any packed (copied) string */
- num = 1;
- nxtc = c->next;
- while (nxtc) {
- if (nxtc->type == TPL_TYPE_POUND) {
- num = nxtc->num;
- }
- nxtc = nxtc->next;
- }
- for (i = 0; i < c->num * num; i++) {
- char *str = ((char**)c->data)[i];
- if (str) {
- tpl_hook.free(str);
- ((char**)c->data)[i] = NULL;
- }
- }
- tpl_hook.free(c->data);
- find_next_node=1;
- break;
- case TPL_TYPE_INT32:
- case TPL_TYPE_UINT32:
- case TPL_TYPE_INT64:
- case TPL_TYPE_UINT64:
- case TPL_TYPE_BYTE:
- case TPL_TYPE_DOUBLE:
- case TPL_TYPE_INT16:
- case TPL_TYPE_UINT16:
- case TPL_TYPE_POUND:
- tpl_hook.free(c->data);
- find_next_node=1;
- break;
- case TPL_TYPE_ARY:
- tpl_free_atyp(c,c->data);
- if (c->children) c = c->children; /* normal case */
- else find_next_node=1; /* edge case, handle bad format A() */
- break;
- default:
- tpl_hook.fatal("unsupported format character\n");
- break;
- }
- if (find_next_node) {
- find_next_node=0;
- looking=1;
- while(looking) {
- if (c->next) {
- nxtc=c->next;
- tpl_hook.free(c);
- c=nxtc;
- looking=0;
- } else {
- if (c->type == TPL_TYPE_ROOT) break; /* root node */
- else {
- nxtc=c->parent;
- tpl_hook.free(c);
- c=nxtc;
- }
- }
- }
- }
- }
- }
- /* free root */
- for(pidx=((tpl_root_data*)(r->data))->pidx; pidx; pidx=pidx_nxt) {
- pidx_nxt = pidx->next;
- tpl_hook.free(pidx);
- }
- tpl_hook.free(((tpl_root_data*)(r->data))->fmt);
- if (((tpl_root_data*)(r->data))->num_fxlens > 0) {
- tpl_hook.free(((tpl_root_data*)(r->data))->fxlens);
- }
- tpl_hook.free(r->data); /* tpl_root_data */
- tpl_hook.free(r);
- }
- /* Find the i'th packable ('A' node) */
- static tpl_node *tpl_find_i(tpl_node *n, int i) {
- int j=0;
- tpl_pidx *pidx;
- if (n->type != TPL_TYPE_ROOT) return NULL;
- if (i == 0) return n; /* packable 0 is root */
- for(pidx=((tpl_root_data*)(n->data))->pidx; pidx; pidx=pidx->next) {
- if (++j == i) return pidx->node;
- }
- return NULL;
- }
- static void *tpl_cpv(void *datav, const void *data, size_t sz) {
- if (sz>0) memcpy(datav,data,sz);
- return (void*)((uintptr_t)datav + sz);
- }
- static void *tpl_extend_backbone(tpl_node *n) {
- tpl_backbone *bb;
- bb = (tpl_backbone*)tpl_hook.malloc(sizeof(tpl_backbone) +
- ((tpl_atyp*)(n->data))->sz ); /* datum hangs on coattails of bb */
- if (!bb) fatal_oom();
- #if __STDC_VERSION__ < 199901
- bb->data = (char*)((uintptr_t)bb + sizeof(tpl_backbone));
- #endif
- memset(bb->data,0,((tpl_atyp*)(n->data))->sz);
- bb->next = NULL;
- /* Add the new backbone to the tail, also setting head if necessary */
- if (((tpl_atyp*)(n->data))->bb == NULL) {
- ((tpl_atyp*)(n->data))->bb = bb;
- ((tpl_atyp*)(n->data))->bbtail = bb;
- } else {
- ((tpl_atyp*)(n->data))->bbtail->next = bb;
- ((tpl_atyp*)(n->data))->bbtail = bb;
- }
- ((tpl_atyp*)(n->data))->num++;
- return bb->data;
- }
- /* Get the format string corresponding to a given tpl (root node) */
- static char *tpl_fmt(tpl_node *r) {
- return ((tpl_root_data*)(r->data))->fmt;
- }
- /* Get the fmt # lengths as a contiguous buffer of ints (length num_fxlens) */
- static int *tpl_fxlens(tpl_node *r, int *num_fxlens) {
- *num_fxlens = ((tpl_root_data*)(r->data))->num_fxlens;
- return ((tpl_root_data*)(r->data))->fxlens;
- }
- /* called when serializing an 'A' type node into a buffer which has
- * already been set up with the proper space. The backbone is walked
- * which was obtained from the tpl_atyp header passed in.
- */
- static void *tpl_dump_atyp(tpl_node *n, tpl_atyp* at, void *dv) {
- tpl_backbone *bb;
- tpl_node *c;
- void *datav;
- uint32_t slen;
- tpl_bin *binp;
- char *strp;
- tpl_atyp *atypp;
- tpl_pound_data *pd;
- int i;
- size_t itermax;
- /* handle 'A' nodes */
- dv = tpl_cpv(dv,&at->num,sizeof(uint32_t)); /* array len */
- for(bb=at->bb; bb; bb=bb->next) {
- datav = bb->data;
- c=n->children;
- while(c) {
- switch (c->type) {
- case TPL_TYPE_BYTE:
- case TPL_TYPE_DOUBLE:
- case TPL_TYPE_INT32:
- case TPL_TYPE_UINT32:
- case TPL_TYPE_INT64:
- case TPL_TYPE_UINT64:
- case TPL_TYPE_INT16:
- case TPL_TYPE_UINT16:
- dv = tpl_cpv(dv,datav,tpl_types[c->type].sz * c->num);
- datav = (void*)((uintptr_t)datav + tpl_types[c->type].sz * c->num);
- break;
- case TPL_TYPE_BIN:
- /* dump the buffer length followed by the buffer */
- memcpy(&binp,datav,sizeof(tpl_bin*)); /* cp to aligned */
- slen = binp->sz;
- dv = tpl_cpv(dv,&slen,sizeof(uint32_t));
- dv = tpl_cpv(dv,binp->addr,slen);
- datav = (void*)((uintptr_t)datav + sizeof(tpl_bin*));
- break;
- case TPL_TYPE_STR:
- /* dump the string length followed by the string */
- for(i=0; i < c->num; i++) {
- memcpy(&strp,datav,sizeof(char*)); /* cp to aligned */
- slen = strp ? (strlen(strp)+1) : 0;
- dv = tpl_cpv(dv,&slen,sizeof(uint32_t));
- if (slen > 1) dv = tpl_cpv(dv,strp,slen-1);
- datav = (void*)((uintptr_t)datav + sizeof(char*));
- }
- break;
- case TPL_TYPE_ARY:
- memcpy(&atypp,datav,sizeof(tpl_atyp*)); /* cp to aligned */
- dv = tpl_dump_atyp(c,atypp,dv);
- datav = (void*)((uintptr_t)datav + sizeof(void*));
- break;
- case TPL_TYPE_POUND:
- /* iterate over the preceding nodes */
- pd = (tpl_pound_data*)c->data;
- itermax = c->num;
- if (++(pd->iternum) < itermax) {
- c = pd->iter_start_node;
- continue;
- } else { /* loop complete. */
- pd->iternum = 0;
- }
- break;
- default:
- tpl_hook.fatal("unsupported format character\n");
- break;
- }
- c=c->next;
- }
- }
- return dv;
- }
- /* figure the serialization output size needed for tpl whose root is n*/
- static size_t tpl_ser_osz(tpl_node *n) {
- tpl_node *c, *np;
- size_t sz, itermax;
- tpl_bin *binp;
- char *strp;
- tpl_pound_data *pd;
- int i;
- /* handle the root node ONLY (subtree's ser_osz have been bubbled-up) */
- if (n->type != TPL_TYPE_ROOT) {
- tpl_hook.fatal("internal error: tpl_ser_osz on non-root node\n");
- }
- sz = n->ser_osz; /* start with fixed overhead, already stored */
- c=n->children;
- while (c) {
- switch (c->type) {
- case TPL_TYPE_BYTE:
- case TPL_TYPE_DOUBLE:
- case TPL_TYPE_INT32:
- case TPL_TYPE_UINT32:
- case TPL_TYPE_INT64:
- case TPL_TYPE_UINT64:
- case TPL_TYPE_INT16:
- case TPL_TYPE_UINT16:
- sz += tpl_types[c->type].sz * c->num;
- break;
- case TPL_TYPE_BIN:
- sz += sizeof(uint32_t); /* binary buf len */
- memcpy(&binp,c->data,sizeof(tpl_bin*)); /* cp to aligned */
- sz += binp->sz;
- break;
- case TPL_TYPE_STR:
- for(i=0; i < c->num; i++) {
- sz += sizeof(uint32_t); /* string len */
- memcpy(&strp,&((char**)c->data)[i],sizeof(char*)); /* cp to aligned */
- sz += strp ? strlen(strp) : 0;
- }
- break;
- case TPL_TYPE_ARY:
- sz += sizeof(uint32_t); /* array len */
- sz += c->ser_osz; /* bubbled-up child array ser_osz */
- break;
- case TPL_TYPE_POUND:
- /* iterate over the preceding nodes */
- itermax = c->num;
- pd = (tpl_pound_data*)c->data;
- if (++(pd->iternum) < itermax) {
- for(np=pd->iter_start_node; np != c; np = np->next) {
- np->data = (char*)(np->data) +
- (tpl_types[np->type].sz * np->num);
- }
- c = pd->iter_start_node;
- continue;
- } else { /* loop complete. */
- pd->iternum = 0;
- for(np=pd->iter_start_node; np != c; np = np->next) {
- np->data = (char*)(np->data) - ((itermax-1) *
- tpl_types[np->type].sz *
- np->num);
- }
- }
- break;
- default:
- tpl_hook.fatal("unsupported format character\n");
- break;
- }
- c=c->next;
- }
- return sz;
- }
- TPL_API int tpl_dump(tpl_node *r, int mode, ...) {
- va_list ap;
- char *filename, *bufv;
- void **addr_out,*buf, *pa_addr;
- int fd,rc=0;
- size_t sz,*sz_out, pa_sz;
- struct stat sbuf;
- if (((tpl_root_data*)(r->data))->flags & TPL_RDONLY) { /* unusual */
- tpl_hook.oops("error: tpl_dump called for a loaded tpl\n");
- return -1;
- }
- sz = tpl_ser_osz(r); /* compute the size needed to serialize */
- va_start(ap,mode);
- if (mode & TPL_FILE) {
- filename = va_arg(ap,char*);
- fd = tpl_mmap_output_file(filename, sz, &buf);
- if (fd == -1) rc = -1;
- else {
- rc = tpl_dump_to_mem(r,buf,sz);
- if (msync(buf,sz,MS_SYNC) == -1) {
- tpl_hook.oops("msync failed on fd %d: %s\n", fd, strerror(errno));
- }
- if (munmap(buf, sz) == -1) {
- tpl_hook.oops("munmap failed on fd %d: %s\n", fd, strerror(errno));
- }
- close(fd);
- }
- } else if (mode & TPL_FD) {
- fd = va_arg(ap, int);
- if ( (buf = tpl_hook.malloc(sz)) == NULL) fatal_oom();
- tpl_dump_to_mem(r,buf,sz);
- bufv = buf;
- do {
- rc = write(fd,bufv,sz);
- if (rc > 0) {
- sz -= rc;
- bufv += rc;
- } else if (rc == -1) {
- if (errno == EINTR || errno == EAGAIN) continue;
- tpl_hook.oops("error writing to fd %d: %s\n", fd, strerror(errno));
- /* attempt to rewind partial write to a regular file */
- if (fstat(fd,&sbuf) == 0 && S_ISREG(sbuf.st_mode)) {
- if (ftruncate(fd,sbuf.st_size - (bufv-(char*)buf)) == -1) {
- tpl_hook.oops("can't rewind: %s\n", strerror(errno));
- }
- }
- free(buf);
- return -1;
- }
- } while (sz > 0);
- free(buf);
- rc = 0;
- } else if (mode & TPL_MEM) {
- if (mode & TPL_PREALLOCD) { /* caller allocated */
- pa_addr = (void*)va_arg(ap, void*);
- pa_sz = va_arg(ap, size_t);
- if (pa_sz < sz) {
- tpl_hook.oops("tpl_dump: buffer too small, need %d bytes\n", sz);
- return -1;
- }
- rc=tpl_dump_to_mem(r,pa_addr,sz);
- } else { /* we allocate */
- addr_out = (void**)va_arg(ap, void*);
- sz_out = va_arg(ap, size_t*);
- if ( (buf = tpl_hook.malloc(sz)) == NULL) fatal_oom();
- *sz_out = sz;
- *addr_out = buf;
- rc=tpl_dump_to_mem(r,buf,sz);
- }
- } else if (mode & TPL_GETSIZE) {
- sz_out = va_arg(ap, size_t*);
- *sz_out = sz;
- } else {
- tpl_hook.oops("unsupported tpl_dump mode %d\n", mode);
- rc=-1;
- }
- va_end(ap);
- return rc;
- }
- /* This function expects the caller to have set up a memory buffer of
- * adequate size to hold the serialized tpl. The sz parameter must be
- * the result of tpl_ser_osz(r).
- */
- static int tpl_dump_to_mem(tpl_node *r,void *addr,size_t sz) {
- uint32_t slen, sz32;
- int *fxlens, num_fxlens, i;
- void *dv;
- char *fmt,flags;
- tpl_node *c, *np;
- tpl_pound_data *pd;
- size_t itermax;
- fmt = tpl_fmt(r);
- flags = 0;
- if (tpl_cpu_bigendian()) flags |= TPL_FL_BIGENDIAN;
- if (strchr(fmt,'s')) flags |= TPL_FL_NULLSTRINGS;
- sz32 = sz;
- dv = addr;
- dv = tpl_cpv(dv,TPL_MAGIC,3); /* copy tpl magic prefix */
- dv = tpl_cpv(dv,&flags,1); /* copy flags byte */
- dv = tpl_cpv(dv,&sz32,sizeof(uint32_t));/* overall length (inclusive) */
- dv = tpl_cpv(dv,fmt,strlen(fmt)+1); /* copy format with NUL-term */
- fxlens = tpl_fxlens(r,&num_fxlens);
- dv = tpl_cpv(dv,fxlens,num_fxlens*sizeof(uint32_t));/* fmt # lengths */
- /* serialize the tpl content, iterating over direct children of root */
- c = r->children;
- while (c) {
- switch (c->type) {
- case TPL_TYPE_BYTE:
- case TPL_TYPE_DOUBLE:
- case TPL_TYPE_INT32:
- case TPL_TYPE_UINT32:
- case TPL_TYPE_INT64:
- case TPL_TYPE_UINT64:
- case TPL_TYPE_INT16:
- case TPL_TYPE_UINT16:
- dv = tpl_cpv(dv,c->data,tpl_types[c->type].sz * c->num);
- break;
- case TPL_TYPE_BIN:
- slen = (*(tpl_bin**)(c->data))->sz;
- dv = tpl_cpv(dv,&slen,sizeof(uint32_t)); /* buffer len */
- dv = tpl_cpv(dv,(*(tpl_bin**)(c->data))->addr,slen); /* buf */
- break;
- case TPL_TYPE_STR:
- for(i=0; i < c->num; i++) {
- char *str = ((char**)c->data)[i];
- slen = str ? strlen(str)+1 : 0;
- dv = tpl_cpv(dv,&slen,sizeof(uint32_t)); /* string len */
- if (slen>1) dv = tpl_cpv(dv,str,slen-1); /*string*/
- }
- break;
- case TPL_TYPE_ARY:
- dv = tpl_dump_atyp(c,(tpl_atyp*)c->data,dv);
- break;
- case TPL_TYPE_POUND:
- pd = (tpl_pound_data*)c->data;
- itermax = c->num;
- if (++(pd->iternum) < itermax) {
- /* in start or midst of loop. advance data pointers. */
- for(np=pd->iter_start_node; np != c; np = np->next) {
- np->data = (char*)(np->data) +
- (tpl_types[np->type].sz * np->num);
- }
- /* do next iteration */
- c = pd->iter_start_node;
- continue;
- } else { /* loop complete. */
-
- /* reset iteration index and addr/data pointers. */
- pd->iternum = 0;
- for(np=pd->iter_start_node; np != c; np = np->next) {
- np->data = (char*)(np->data) - ((itermax-1) *
- tpl_types[np->type].sz *
- np->num);
- }
- }
- break;
- default:
- tpl_hook.fatal("unsupported format character\n");
- break;
- }
- c = c->next;
- }
- return 0;
- }
- static int tpl_cpu_bigendian() {
- unsigned i = 1;
- char *c;
- c = (char*)&i;
- return (c[0] == 1 ? 0 : 1);
- }
- /*
- * algorithm for sanity-checking a tpl image:
- * scan the tpl whilst not exceeding the buffer size (bufsz) ,
- * formulating a calculated (expected) size of the tpl based
- * on walking its data. When calcsize has been calculated it
- * should exactly match the buffer size (bufsz) and the internal
- * recorded size (intlsz)
- */
- static int tpl_sanity(tpl_node *r, int excess_ok) {
- uint32_t intlsz;
- int found_nul=0,rc, octothorpes=0, num_fxlens, *fxlens, flen;
- void *d, *dv;
- char intlflags, *fmt, c, *mapfmt;
- size_t bufsz, serlen;
- d = ((tpl_root_data*)(r->data))->mmap.text;
- bufsz = ((tpl_root_data*)(r->data))->mmap.text_sz;
- dv = d;
- if (bufsz < (4 + sizeof(uint32_t) + 1)) return ERR_NOT_MINSIZE; /* min sz: magic+flags+len+nul */
- if (memcmp(dv,TPL_MAGIC, 3) != 0) return ERR_MAGIC_MISMATCH; /* missing tpl magic prefix */
- if (tpl_needs_endian_swap(dv)) ((tpl_root_data*)(r->data))->flags |= TPL_XENDIAN;
- dv = (void*)((uintptr_t)dv + 3);
- memcpy(&intlflags,dv,sizeof(char)); /* extract flags */
- if (intlflags & ~TPL_SUPPORTED_BITFLAGS) return ERR_UNSUPPORTED_FLAGS;
- /* TPL1.3 stores strings with a "length+1" prefix to discern NULL strings from
- empty strings from non-empty strings; TPL1.2 only handled the latter two.
- So we need to be mindful of which string format we're reading from. */
- if (!(intlflags & TPL_FL_NULLSTRINGS)) {
- ((tpl_root_data*)(r->data))->flags |= TPL_OLD_STRING_FMT;
- }
- dv = (void*)((uintptr_t)dv + 1);
- memcpy(&intlsz,dv,sizeof(uint32_t)); /* extract internal size */
- if (((tpl_root_data*)(r->data))->flags & TPL_XENDIAN) tpl_byteswap(&intlsz, sizeof(uint32_t));
- if (!excess_ok && (intlsz != bufsz)) return ERR_INCONSISTENT_SZ; /* inconsisent buffer/internal size */
- dv = (void*)((uintptr_t)dv + sizeof(uint32_t));
- /* dv points to the start of the format string. Look for nul w/in buf sz */
- fmt = (char*)dv;
- while ((uintptr_t)dv-(uintptr_t)d < bufsz && !found_nul) {
- if ( (c = *(char*)dv) != '\0') {
- if (strchr(tpl_fmt_chars,c) == NULL)
- return ERR_FMT_INVALID; /* invalid char in format string */
- if ( (c = *(char*)dv) == '#') octothorpes++;
- dv = (void*)((uintptr_t)dv + 1);
- }
- else found_nul = 1;
- }
- if (!found_nul) return ERR_FMT_MISSING_NUL; /* runaway format string */
- dv = (void*)((uintptr_t)dv + 1); /* advance to octothorpe lengths buffer */
-
- /* compare the map format to the format of this tpl image */
- mapfmt = tpl_fmt(r);
- rc = strcmp(mapfmt,fmt);
- if (rc != 0) return ERR_FMT_MISMATCH;
- /* compare octothorpe lengths in image to the mapped values */
- if ((((uintptr_t)dv + (octothorpes * 4)) - (uintptr_t)d) > bufsz) return ERR_INCONSISTENT_SZ4;
- fxlens = tpl_fxlens(r,&num_fxlens); /* mapped fxlens */
- while(num_fxlens--) {
- memcpy(&flen,dv,sizeof(uint32_t)); /* stored flen */
- if (((tpl_root_data*)(r->data))->flags & TPL_XENDIAN) tpl_byteswap(&flen, sizeof(uint32_t));
- if (flen != *fxlens) return ERR_FLEN_MISMATCH;
- dv = (void*)((uintptr_t)dv + sizeof(uint32_t));
- fxlens++;
- }
- /* dv now points to beginning of data */
- rc = tpl_serlen(r,r,dv,&serlen); /* get computed serlen of data part */
- if (rc == -1) return ERR_INCONSISTENT_SZ2; /* internal inconsistency in tpl image */
- serlen += ((uintptr_t)dv - (uintptr_t)d); /* add back serlen of preamble part */
- if (excess_ok && (bufsz < serlen)) return ERR_INCONSISTENT_SZ3;
- if (!excess_ok && (serlen != bufsz)) return ERR_INCONSISTENT_SZ3; /* buffer/internal sz exceeds serlen */
- return 0;
- }
- static void *tpl_find_data_start(void *d) {
- int octothorpes=0;
- d = (void*)((uintptr_t)d + 4); /* skip TPL_MAGIC and flags byte */
- d = (void*)((uintptr_t)d + 4); /* skip int32 overall len */
- while(*(char*)d != '\0') {
- if (*(char*)d == '#') octothorpes++;
- d = (void*)((uintptr_t)d + 1);
- }
- d = (void*)((uintptr_t)d + 1); /* skip NUL */
- d = (void*)((uintptr_t)d + (octothorpes * sizeof(uint32_t))); /* skip # array lens */
- return d;
- }
- static int tpl_needs_endian_swap(void *d) {
- char *c;
- int cpu_is_bigendian;
- c = (char*)d;
- cpu_is_bigendian = tpl_cpu_bigendian();
- return ((c[3] & TPL_FL_BIGENDIAN) == cpu_is_bigendian) ? 0 : 1;
- }
- static size_t tpl_size_for(char c) {
- int i;
- for(i=0; i < sizeof(tpl_types)/sizeof(tpl_types[0]); i++) {
- if (tpl_types[i].c == c) return tpl_types[i].sz;
- }
- return 0;
- }
- TPL_API char* tpl_peek(int mode, ...) {
- va_list ap;
- int xendian=0,found_nul=0,old_string_format=0;
- char *filename=NULL, *datapeek_f=NULL, *datapeek_c, *datapeek_s;
- void *addr=NULL, *dv, *datapeek_p=NULL;
- size_t sz=0, fmt_len, first_atom, num_fxlens=0;
- uint32_t datapeek_ssz, datapeek_csz, datapeek_flen;
- tpl_mmap_rec mr = {0,NULL,0};
- char *fmt,*fmt_cpy=NULL,c;
- uint32_t intlsz, **fxlens=NULL, *num_fxlens_out=NULL, *fxlensv;
- va_start(ap,mode);
- if ((mode & TPL_FXLENS) && (mode & TPL_DATAPEEK)) {
- tpl_hook.oops("TPL_FXLENS and TPL_DATAPEEK mutually exclusive\n");
- goto fail;
- }
- if (mode & TPL_FILE) filename = va_arg(ap,char *);
- else if (mode & TPL_MEM) {
- addr = va_arg(ap,void *);
- sz = va_arg(ap,size_t);
- } else {
- tpl_hook.oops("unsupported tpl_peek mode %d\n", mode);
- goto fail;
- }
- if (mode & TPL_DATAPEEK) {
- datapeek_f = va_arg(ap, char*);
- }
- if (mode & TPL_FXLENS) {
- num_fxlens_out = va_arg(ap,uint32_t *);
- fxlens = va_arg(ap,uint32_t **);
- *num_fxlens_out = 0;
- *fxlens = NULL;
- }
- if (mode & TPL_FILE) {
- if (tpl_mmap_file(filename, &mr) != 0) {
- tpl_hook.oops("tpl_peek failed for file %s\n", filename);
- goto fail;
- }
- addr = mr.text;
- sz = mr.text_sz;
- }
- dv = addr;
- if (sz < (4 + sizeof(uint32_t) + 1)) goto fail; /* min sz */
- if (memcmp(dv,TPL_MAGIC, 3) != 0) goto fail; /* missing tpl magic prefix */
- if (tpl_needs_endian_swap(dv)) xendian=1;
- if ((((char*)dv)[3] & TPL_FL_NULLSTRINGS)==0) old_string_format=1;
- dv = (void*)((uintptr_t)dv + 4);
- memcpy(&intlsz,dv,sizeof(uint32_t)); /* extract internal size */
- if (xendian) tpl_byteswap(&intlsz, sizeof(uint32_t));
- if (intlsz != sz) goto fail; /* inconsisent buffer/internal size */
- dv = (void*)((uintptr_t)dv + sizeof(uint32_t));
- /* dv points to the start of the format string. Look for nul w/in buf sz */
- fmt = (char*)dv;
- while ((uintptr_t)dv-(uintptr_t)addr < sz && !found_nul) {
- if ( (c = *(char*)dv) == '\0') {
- found_nul = 1;
- } else if (c == '#') {
- num_fxlens++;
- }
- dv = (void*)((uintptr_t)dv + 1);
- }
- if (!found_nul) goto fail; /* runaway format string */
- fmt_len = (char*)dv - fmt; /* include space for \0 */
- fmt_cpy = tpl_hook.malloc(fmt_len);
- if (fmt_cpy == NULL) {
- fatal_oom();
- }
- memcpy(fmt_cpy, fmt, fmt_len);
- /* retrieve the octothorpic lengths if requested */
- if (num_fxlens > 0) {
- if (sz < ((uintptr_t)dv + (num_fxlens * sizeof(uint32_t)) - (uintptr_t)addr)) {
- goto fail;
- }
- }
- if ((mode & TPL_FXLENS) && (num_fxlens > 0)) {
- *fxlens = tpl_hook.malloc(num_fxlens * sizeof(uint32_t));
- if (*fxlens == NULL) tpl_hook.fatal("out of memory");
- *num_fxlens_out = num_fxlens;
- fxlensv = *fxlens;
- while(num_fxlens--) {
- memcpy(fxlensv,dv,sizeof(uint32_t));
- if (xendian) tpl_byteswap(fxlensv, sizeof(uint32_t));
- dv = (void*)((uintptr_t)dv + sizeof(uint32_t));
- fxlensv++;
- }
- }
- /* if caller requested, peek into the specified data elements */
- if (mode & TPL_DATAPEEK) {
- first_atom = strspn(fmt, "S()"); /* skip any leading S() */
- datapeek_flen = strlen(datapeek_f);
- if (strspn(datapeek_f, tpl_datapeek_ok_chars) < datapeek_flen) {
- tpl_hook.oops("invalid TPL_DATAPEEK format: %s\n", datapeek_f);
- tpl_hook.free(fmt_cpy); fmt_cpy = NULL; /* fail */
- goto fail;
- }
- if (strncmp( &fmt[first_atom], datapeek_f, datapeek_flen) != 0) {
- tpl_hook.oops("TPL_DATAPEEK format mismatches tpl iamge\n");
- tpl_hook.free(fmt_cpy); fmt_cpy = NULL; /* fail */
- goto fail;
- }
- /* advance to data start, then copy out requested elements */
- dv = (void*)((uintptr_t)dv + (num_fxlens * sizeof(uint32_t)));
- for(datapeek_c = datapeek_f; *datapeek_c != '\0'; datapeek_c++) {
- datapeek_p = va_arg(ap, void*);
- if (*datapeek_c == 's') { /* special handling for strings */
- if ((uintptr_t)dv-(uintptr_t)addr + sizeof(uint32_t) > sz) {
- tpl_hook.oops("tpl_peek: tpl has insufficient length\n");
- tpl_hook.free(fmt_cpy); fmt_cpy = NULL; /* fail */
- goto fail;
- }
- memcpy(&datapeek_ssz,dv,sizeof(uint32_t)); /* get slen */
- if (xendian) tpl_byteswap(&datapeek_ssz, sizeof(uint32_t));
- if (old_string_format) datapeek_ssz++;
- dv = (void*)((uintptr_t)dv + sizeof(uint32_t)); /* adv. to str */
- if (datapeek_ssz == 0) datapeek_s = NULL;
- else {
- if ((uintptr_t)dv-(uintptr_t)addr + datapeek_ssz-1 > sz) {
- tpl_hook.oops("tpl_peek: tpl has insufficient length\n");
- tpl_hook.free(fmt_cpy); fmt_cpy = NULL; /* fail */
- goto fail;
- }
- datapeek_s = tpl_hook.malloc(datapeek_ssz);
- if (datapeek_s == NULL) fatal_oom();
- memcpy(datapeek_s, dv, datapeek_ssz-1);
- datapeek_s[datapeek_ssz-1] = '\0';
- dv = (void*)((uintptr_t)dv + datapeek_ssz-1);
- }
- *(char**)datapeek_p = datapeek_s;
- } else {
- datapeek_csz = tpl_size_for(*datapeek_c);
- if ((uintptr_t)dv-(uintptr_t)addr + datapeek_csz > sz) {
- tpl_hook.oops("tpl_peek: tpl has insufficient length\n");
- tpl_hook.free(fmt_cpy); fmt_cpy = NULL; /* fail */
- goto fail;
- }
- memcpy(datapeek_p, dv, datapeek_csz);
- if (xendian) tpl_byteswap(datapeek_p, datapeek_csz);
- dv = (void*)((uintptr_t)dv + datapeek_csz);
- }
- }
- }
- fail:
- va_end(ap);
- if ((mode & TPL_FILE) && mr.text != NULL) tpl_unmap_file( &mr );
- return fmt_cpy;
- }
- /* tpl_jot(TPL_FILE, "file.tpl", "si", &s, &i); */
- /* tpl_jot(TPL_MEM, &buf, &sz, "si", &s, &i); */
- /* tpl_jot(TPL_FD, fd, "si", &s, &i); */
- TPL_API int tpl_jot(int mode, ...) {
- va_list ap;
- char *filename, *fmt;
- size_t *sz;
- int fd, rc=0;
- void **buf;
- tpl_node *tn;
- va_start(ap,mode);
- if (mode & TPL_FILE) {
- filename = va_arg(ap,char*);
- fmt = va_arg(ap,char*);
- tn = tpl_map_va(fmt, ap);
- if (tn == NULL) { rc=-1; goto fail;}
- tpl_pack(tn, 0);
- rc = tpl_dump(tn, TPL_FILE, filename);
- tpl_free(tn);
- } else if (mode & TPL_MEM) {
- buf = va_arg(ap,void*);
- sz = va_arg(ap,size_t*);
- fmt = va_arg(ap,char*);
- tn = tpl_map_va(fmt,ap);
- if (tn == NULL) { rc=-1; goto fail;}
- tpl_pack(tn,0);
- rc = tpl_dump(tn, TPL_MEM, buf, sz);
- tpl_free(tn);
- } else if (mode & TPL_FD) {
- fd = va_arg(ap,int);
- fmt = va_arg(ap,char*);
- tn = tpl_map_va(fmt,ap);
- if (tn == NULL) { rc=-1; goto fail;}
- tpl_pack(tn,0);
- rc = tpl_dump(tn, TPL_FD, fd);
- tpl_free(tn);
- } else {
- tpl_hook.fatal("invalid tpl_jot mode\n");
- }
- fail:
- va_end(ap);
- return rc;
- }
- TPL_API int tpl_load(tpl_node *r, int mode, ...) {
- va_list ap;
- int rc=0,fd=0;
- char *filename=NULL;
- void *addr;
- size_t sz;
- va_start(ap,mode);
- if (mode & TPL_FILE) filename = va_arg(ap,char *);
- else if (mode & TPL_MEM) {
- addr = va_arg(ap,void *);
- sz = va_arg(ap,size_t);
- } else if (mode & TPL_FD) {
- fd = va_arg(ap,int);
- } else {
- tpl_hook.oops("unsupported tpl_load mode %d\n", mode);
- return -1;
- }
- va_end(ap);
- if (r->type != TPL_TYPE_ROOT) {
- tpl_hook.oops("error: tpl_load to non-root node\n");
- return -1;
- }
- if (((tpl_root_data*)(r->data))->flags & (TPL_WRONLY|TPL_RDONLY)) {
- /* already packed or loaded, so reset it as if newly mapped */
- tpl_free_keep_map(r);
- }
- if (mode & TPL_FILE) {
- if (tpl_mmap_file(filename, &((tpl_root_data*)(r->data))->mmap) != 0) {
- tpl_hook.oops("tpl_load failed for file %s\n", filename);
- return -1;
- }
- if ( (rc = tpl_sanity(r, (mode & TPL_EXCESS_OK))) != 0) {
- if (rc == ERR_FMT_MISMATCH) {
- tpl_hook.oops("%s: format signature mismatch\n", filename);
- } else if (rc == ERR_FLEN_MISMATCH) {
- tpl_hook.oops("%s: array lengths mismatch\n", filename);
- } else {
- tpl_hook.oops("%s: not a valid tpl file\n", filename);
- }
- tpl_unmap_file( &((tpl_root_data*)(r->data))->mmap );
- return -1;
- }
- ((tpl_root_data*)(r->data))->flags = (TPL_FILE | TPL_RDONLY);
- } else if (mode & TPL_MEM) {
- ((tpl_root_data*)(r->data))->mmap.text = addr;
- ((tpl_root_data*)(r->data))->mmap.text_sz = sz;
- if ( (rc = tpl_sanity(r, (mode & TPL_EXCESS_OK))) != 0) {
- if (rc == ERR_FMT_MISMATCH) {
- tpl_hook.oops("format signature mismatch\n");
- } else {
- tpl_hook.oops("not a valid tpl file\n");
- }
- return -1;
- }
- ((tpl_root_data*)(r->data))->flags = (TPL_MEM | TPL_RDONLY);
- if (mode & TPL_UFREE) ((tpl_root_data*)(r->data))->flags |= TPL_UFREE;
- } else if (mode & TPL_FD) {
- /* if fd read succeeds, resulting mem img is used for load */
- if (tpl_gather(TPL_GATHER_BLOCKING,fd,&addr,&sz) > 0) {
- return tpl_load(r, TPL_MEM|TPL_UFREE, addr, sz);
- } else return -1;
- } else {
- tpl_hook.oops("invalid tpl_load mode %d\n", mode);
- return -1;
- }
- /* this applies to TPL_MEM or TPL_FILE */
- if (tpl_needs_endian_swap(((tpl_root_data*)(r->data))->mmap.text))
- ((tpl_root_data*)(r->data))->flags |= TPL_XENDIAN;
- tpl_unpackA0(r); /* prepare root A nodes for use */
- return 0;
- }
- TPL_API int tpl_Alen(tpl_node *r, int i) {
- tpl_node *n;
- n = tpl_find_i(r,i);
- if (n == NULL) {
- tpl_hook.oops("invalid index %d to tpl_unpack\n", i);
- return -1;
- }
- if (n->type != TPL_TYPE_ARY) return -1;
- return ((tpl_atyp*)(n->data))->num;
- }
- static void tpl_free_atyp(tpl_node *n, tpl_atyp *atyp) {
- tpl_backbone *bb,*bbnxt;
- tpl_node *c;
- void *dv;
- tpl_bin *binp;
- tpl_atyp *atypp;
- char *strp;
- size_t itermax;
- tpl_pound_data *pd;
- int i;
- bb = atyp->bb;
- while (bb) {
- bbnxt = bb->next;
- dv = bb->data;
- c=n->children;
- while (c) {
- switch (c->type) {
- case TPL_TYPE_BYTE:
- case TPL_TYPE_DOUBLE:
- case TPL_TYPE_INT32:
- case TPL_TYPE_UINT32:
- case TPL_TYPE_INT64:
- case TPL_TYPE_UINT64:
- case TPL_TYPE_INT16:
- case TPL_TYPE_UINT16:
- dv = (void*)((uintptr_t)dv + tpl_types[c->type].sz*c->num);
- break;
- case TPL_TYPE_BIN:
- memcpy(&binp,dv,sizeof(tpl_bin*)); /* cp to aligned */
- if (binp->addr) tpl_hook.free( binp->addr ); /* free buf */
- tpl_hook.free(binp); /* free tpl_bin */
- dv = (void*)((uintptr_t)dv + sizeof(tpl_bin*));
- break;
- case TPL_TYPE_STR:
- for(i=0; i < c->num; i++) {
- memcpy(&strp,dv,sizeof(char*)); /* cp to aligned */
- if (strp) tpl_hook.free(strp); /* free string */
- dv = (void*)((uintptr_t)dv + sizeof(char*));
- }
- break;
- case TPL_TYPE_POUND:
- /* iterate over the preceding nodes */
- itermax = c->num;
- pd = (tpl_pound_data*)c->data;
- if (++(pd->iternum) < itermax) {
- c = pd->iter_start_node;
- continue;
- } else { /* loop complete. */
- pd->iternum = 0;
- }
- break;
- case TPL_TYPE_ARY:
- memcpy(&atypp,dv,sizeof(tpl_atyp*)); /* cp to aligned */
- tpl_free_atyp(c,atypp); /* free atyp */
- dv = (void*)((uintptr_t)dv + sizeof(void*));
- break;
- default:
- tpl_hook.fatal("unsupported format character\n");
- break;
- }
- c=c->next;
- }
- tpl_hook.free(bb);
- bb = bbnxt;
- }
- tpl_hook.free(atyp);
- }
- /* determine (by walking) byte length of serialized r/A node at address dv
- * returns 0 on success, or -1 if the tpl isn't trustworthy (fails consistency)
- */
- static int tpl_serlen(tpl_node *r, tpl_node *n, void *dv, size_t *serlen) {
- uint32_t slen;
- int num=0,fidx;
- tpl_node *c;
- size_t len=0, alen, buf_past, itermax;
- tpl_pound_data *pd;
- buf_past = ((uintptr_t)((tpl_root_data*)(r->data))->mmap.text +
- ((tpl_root_data*)(r->data))->mmap.text_sz);
- if (n->type == TPL_TYPE_ROOT) num = 1;
- else if (n->type == TPL_TYPE_ARY) {
- if ((uintptr_t)dv + sizeof(uint32_t) > buf_past) return -1;
- memcpy(&num,dv,sizeof(uint32_t));
- if (((tpl_root_data*)(r->data))->flags & TPL_XENDIAN)
- tpl_byteswap(&num, sizeof(uint32_t));
- dv = (void*)((uintptr_t)dv + sizeof(uint32_t));
- len += sizeof(uint32_t);
- } else tpl_hook.fatal("internal error in tpl_serlen\n");
- while (num-- > 0) {
- c=n->children;
- while (c) {
- switch (c->type) {
- case TPL_TYPE_BYTE:
- case TPL_TYPE_DOUBLE:
- case TPL_TYPE_INT32:
- case TPL_TYPE_UINT32:
- case TPL_TYPE_INT64:
- case TPL_TYPE_UINT64:
- case TPL_TYPE_INT16:
- case TPL_TYPE_UINT16:
- for(fidx=0; fidx < c->num; fidx++) { /* octothorpe support */
- if ((uintptr_t)dv + tpl_types[c->type].sz > buf_past) return -1;
- dv = (void*)((uintptr_t)dv + tpl_types[c->type].sz);
- len += tpl_types[c->type].sz;
- }
- break;
- case TPL_TYPE_BIN:
- len += sizeof(uint32_t);
- if ((uintptr_t)dv + sizeof(uint32_t) > buf_past) return -1;
- memcpy(&slen,dv,sizeof(uint32_t));
- if (((tpl_root_data*)(r->data))->flags & TPL_XENDIAN)
- tpl_byteswap(&slen, sizeof(uint32_t));
- len += slen;
- dv = (void*)((uintptr_t)dv + sizeof(uint32_t));
- if ((uintptr_t)dv + slen > buf_past) return -1;
- dv = (void*)((uintptr_t)dv + slen);
- break;
- case TPL_TYPE_STR:
- for(fidx=0; fidx < c->num; fidx++) { /* octothorpe support */
- len += sizeof(uint32_t);
- if ((uintptr_t)dv + sizeof(uint32_t) > buf_past) return -1;
- memcpy(&slen,dv,sizeof(uint32_t));
- if (((tpl_root_data*)(r->data))->flags & TPL_XENDIAN)
- tpl_byteswap(&slen, sizeof(uint32_t));
- if (!(((tpl_root_data*)(r->data))->flags & TPL_OLD_STRING_FMT))
- slen = (slen>1) ? (slen-1) : 0;
- len += slen;
- dv = (void*)((uintptr_t)dv + sizeof(uint32_t));
- if ((uintptr_t)dv + slen > buf_past) return -1;
- dv = (void*)((uintptr_t)dv + slen);
- }
- break;
- case TPL_TYPE_ARY:
- if ( tpl_serlen(r,c,dv, &alen) == -1) return -1;
- dv = (void*)((uintptr_t)dv + alen);
- len += alen;
- break;
- case TPL_TYPE_POUND:
- /* iterate over the preceding nodes */
- itermax = c->num;
- pd = (tpl_pound_data*)c->data;
- if (++(pd->iternum) < itermax) {
- c = pd->iter_start_node;
- continue;
- } else { /* loop complete. */
- pd->iternum = 0;
- }
- break;
- default:
- tpl_hook.fatal("unsupported format character\n");
- break;
- }
- c=c->next;
- }
- }
- *serlen = len;
- return 0;
- }
- static int tpl_mmap_output_file(char *filename, size_t sz, void **text_out) {
- void *text;
- int fd,perms;
- #ifndef _WIN32
- perms = S_IRUSR|S_IWUSR|S_IWGRP|S_IRGRP|S_IROTH; /* ug+w o+r */
- fd=open(filename,O_CREAT|O_TRUNC|O_RDWR,perms);
- #else
- perms = _S_IWRITE;
- fd=_open(filename,_O_CREAT|_O_TRUNC|_O_RDWR,perms);
- #endif
- if ( fd == -1 ) {
- tpl_hook.oops("Couldn't open file %s: %s\n", filename, strerror(errno));
- return -1;
- }
- text = mmap(0, sz, PROT_READ|PROT_WRITE, MAP_SHARED, fd, 0);
- if (text == MAP_FAILED) {
- tpl_hook.oops("Failed to mmap %s: %s\n", filename, strerror(errno));
- close(fd);
- return -1;
- }
- if (ftruncate(fd,sz) == -1) {
- tpl_hook.oops("ftruncate failed: %s\n", strerror(errno));
- munmap( text, sz );
- close(fd);
- return -1;
- }
- *text_out = text;
- return fd;
- }
- static int tpl_mmap_file(char *filename, tpl_mmap_rec *mr) {
- struct stat stat_buf;
- if ( (mr->fd = open(filename, O_RDONLY)) == -1 ) {
- tpl_hook.oops("Couldn't open file %s: %s\n", filename, strerror(errno));
- return -1;
- }
- if ( fstat(mr->fd, &stat_buf) == -1) {
- close(mr->fd);
- tpl_hook.oops("Couldn't stat file %s: %s\n", filename, strerror(errno));
- return -1;
- }
- mr->text_sz = (size_t)stat_buf.st_size;
- mr->text = mmap(0, stat_buf.st_size, PROT_READ, MAP_PRIVATE, mr->fd, 0);
- if (mr->text == MAP_FAILED) {
- close(mr->fd);
- tpl_hook.oops("Failed to mmap %s: %s\n", filename, strerror(errno));
- return -1;
- }
- return 0;
- }
- TPL_API int tpl_pack(tpl_node *r, int i) {
- tpl_node *n, *child, *np;
- void *datav=NULL;
- size_t sz, itermax;
- uint32_t slen;
- char *str;
- tpl_bin *bin;
- tpl_pound_data *pd;
- int fidx;
- n = tpl_find_i(r,i);
- if (n == NULL) {
- tpl_hook.oops("invalid index %d to tpl_pack\n", i);
- return -1;
- }
- if (((tpl_root_data*)(r->data))->flags & TPL_RDONLY) {
- /* convert to an writeable tpl, initially empty */
- tpl_free_keep_map(r);
- }
- ((tpl_root_data*)(r->data))->flags |= TPL_WRONLY;
- if (n->type == TPL_TYPE_ARY) datav = tpl_extend_backbone(n);
- child = n->children;
- while(child) {
- switch(child->type) {
- case TPL_TYPE_BYTE:
- case TPL_TYPE_DOUBLE:
- case TPL_TYPE_INT32:
- case TPL_TYPE_UINT32:
- case TPL_TYPE_INT64:
- case TPL_TYPE_UINT64:
- case TPL_TYPE_INT16:
- case TPL_TYPE_UINT16:
- /* no need to use fidx iteration here; we can copy multiple values in one memcpy */
- memcpy(child->data,child->addr,tpl_types[child->type].sz * child->num);
- if (datav) datav = tpl_cpv(datav,child->data,tpl_types[child->type].sz * child->num);
- if (n->type == TPL_TYPE_ARY) n->ser_osz += tpl_types[child->type].sz * child->num;
- break;
- case TPL_TYPE_BIN:
- /* copy the buffer to be packed */
- slen = ((tpl_bin*)child->addr)->sz;
- if (slen >0) {
- str = tpl_hook.malloc(slen);
- if (!str) fatal_oom();
- memcpy(str,((tpl_bin*)child->addr)->addr,slen);
- } else str = NULL;
- /* and make a tpl_bin to point to it */
- bin = tpl_hook.malloc(sizeof(tpl_bin));
- if (!bin) fatal_oom();
- bin->addr = str;
- bin->sz = slen;
- /* now pack its pointer, first deep freeing any pre-existing bin */
- if (*(tpl_bin**)(child->data) != NULL) {
- if ((*(tpl_bin**)(child->data))->sz != 0) {
- tpl_hook.free( (*(tpl_bin**)(child->data))->addr );
- }
- tpl_hook.free(*(tpl_bin**)(child->data));
- }
- memcpy(child->data,&bin,sizeof(tpl_bin*));
- if (datav) {
- datav = tpl_cpv(datav, &bin, sizeof(tpl_bin*));
- *(tpl_bin**)(child->data) = NULL;
- }
- if (n->type == TPL_TYPE_ARY) {
- n->ser_osz += sizeof(uint32_t); /* binary buf len word */
- n->ser_osz += bin->sz; /* binary buf */
- }
- break;
- case TPL_TYPE_STR:
- for(fidx=0; fidx < child->num; fidx++) {
- /* copy the string to be packed. slen includes \0. this
- block also works if the string pointer is NULL. */
- char *caddr = ((char**)child->addr)[fidx];
- char **cdata = &((char**)child->data)[fidx];
- slen = caddr ? (strlen(caddr) + 1) : 0;
- if (slen) {
- str = tpl_hook.malloc(slen);
- if (!str) fatal_oom();
- memcpy(str,caddr,slen); /* include \0 */
- } else {
- str = NULL;
- }
- /* now pack its pointer, first freeing any pre-existing string */
- if (*cdata != NULL) {
- tpl_hook.free(*cdata);
- }
- memcpy(cdata,&str,sizeof(char*));
- if (datav) {
- datav = tpl_cpv(datav, &str, sizeof(char*));
- *cdata = NULL;
- }
- if (n->type == TPL_TYPE_ARY) {
- n->ser_osz += sizeof(uint32_t); /* string len word */
- if (slen>1) n->ser_osz += slen-1;/* string (without nul) */
- }
- }
- break;
- case TPL_TYPE_ARY:
- /* copy the child's tpl_atype* and reset it to empty */
- if (datav) {
- sz = ((tpl_atyp*)(child->data))->sz;
- datav = tpl_cpv(datav, &child->data, sizeof(void*));
- child->data = tpl_hook.malloc(sizeof(tpl_atyp));
- if (!child->data) fatal_oom();
- ((tpl_atyp*)(child->data))->num = 0;
- ((tpl_atyp*)(child->data))->sz = sz;
- ((tpl_atyp*)(child->data))->bb = NULL;
- ((tpl_atyp*)(child->data))->bbtail = NULL;
- }
- /* parent is array? then bubble up child array's ser_osz */
- if (n->type == TPL_TYPE_ARY) {
- n->ser_osz += sizeof(uint32_t); /* array len word */
- n->ser_osz += child->ser_osz; /* child array ser_osz */
- child->ser_osz = 0; /* reset child array ser_osz */
- }
- break;
- case TPL_TYPE_POUND:
- /* we need to iterate n times over preceding nodes in S(...).
- * we may be in the midst of an iteration each time or starting. */
- pd = (tpl_pound_data*)child->data;
- itermax = child->num;
- /* itermax is total num of iterations needed */
- /* pd->iternum is current iteration index */
- /* pd->inter_elt_len is element-to-element len of contiguous structs */
- /* pd->iter_start_node is where we jump to at each iteration. */
- if (++(pd->iternum) < itermax) {
- /* in start or midst of loop. advance addr/data pointers. */
- for(np=pd->iter_start_node; np != child; np = np->next) {
- np->data = (char*)(np->data) +
- (tpl_types[np->type].sz * np->num);
- np->addr = (char*)(np->addr) + pd->inter_elt_len;
- }
- /* do next iteration */
- child = pd->iter_start_node;
- continue;
- } else { /* loop complete. */
-
- /* reset iteration index and addr/data pointers. */
- pd->iternum = 0;
- for(np=pd->iter_start_node; np != child; np = np->next) {
- np->data = (char*)(np->data) - ((itermax-1) *
- tpl_types[np->type].sz *
- np->num);
- np->addr = (char*)(np->addr) - ((itermax-1) * pd->inter_elt_len);
- }
- }
- break;
- default:
- tpl_hook.fatal("unsupported format character\n");
- break;
- }
- child=child->next;
- }
- return 0;
- }
- TPL_API int tpl_unpack(tpl_node *r, int i) {
- tpl_node *n, *c, *np;
- uint32_t slen;
- int rc=1, fidx;
- char *str;
- void *dv=NULL, *caddr;
- size_t A_bytes, itermax;
- tpl_pound_data *pd;
- void *img;
- size_t sz;
- /* handle unusual case of tpl_pack,tpl_unpack without an
- * intervening tpl_dump. do a dump/load implicitly. */
- if (((tpl_root_data*)(r->data))->flags & TPL_WRONLY) {
- if (tpl_dump(r,TPL_MEM,&img,&sz) != 0) return -1;
- if (tpl_load(r,TPL_MEM|TPL_UFREE,img,sz) != 0) {
- tpl_hook.free(img);
- return -1;
- };
- }
- n = tpl_find_i(r,i);
- if (n == NULL) {
- tpl_hook.oops("invalid index %d to tpl_unpack\n", i);
- return -1;
- }
- /* either root node or an A node */
- if (n->type == TPL_TYPE_ROOT) {
- dv = tpl_find_data_start( ((tpl_root_data*)(n->data))->mmap.text );
- } else if (n->type == TPL_TYPE_ARY) {
- if (((tpl_atyp*)(n->data))->num <= 0) return 0; /* array consumed */
- else rc = ((tpl_atyp*)(n->data))->num--;
- dv = ((tpl_atyp*)(n->data))->cur;
- if (!dv) tpl_hook.fatal("must unpack parent of node before node itself\n");
- }
- c = n->children;
- while (c) {
- switch (c->type) {
- case TPL_TYPE_BYTE:
- case TPL_TYPE_DOUBLE:
- case TPL_TYPE_INT32:
- case TPL_TYPE_UINT32:
- case TPL_TYPE_INT64:
- case TPL_TYPE_UINT64:
- case TPL_TYPE_INT16:
- case TPL_TYPE_UINT16:
- /* unpack elements of cross-endian octothorpic array individually */
- if (((tpl_root_data*)(r->data))->flags & TPL_XENDIAN) {
- for(fidx=0; fidx < c->num; fidx++) {
- caddr = (void*)((uintptr_t)c->addr + (fidx * tpl_types[c->type].sz));
- memcpy(caddr,dv,tpl_types[c->type].sz);
- tpl_byteswap(caddr, tpl_types[c->type].sz);
- dv = (void*)((uintptr_t)dv + tpl_types[c->type].sz);
- }
- } else {
- /* bulk unpack ok if not cross-endian */
- memcpy(c->addr, dv, tpl_types[c->type].sz * c->num);
- dv = (void*)((uintptr_t)dv + tpl_types[c->type].sz * c->num);
- }
- break;
- case TPL_TYPE_BIN:
- memcpy(&slen,dv,sizeof(uint32_t));
- if (((tpl_root_data*)(r->data))->flags & TPL_XENDIAN)
- tpl_byteswap(&slen, sizeof(uint32_t));
- if (slen > 0) {
- str = (char*)tpl_hook.malloc(slen);
- if (!str) fatal_oom();
- } else str=NULL;
- dv = (void*)((uintptr_t)dv + sizeof(uint32_t));
- if (slen>0) memcpy(str,dv,slen);
- memcpy(&(((tpl_bin*)c->addr)->addr),&str,sizeof(void*));
- memcpy(&(((tpl_bin*)c->addr)->sz),&slen,sizeof(uint32_t));
- dv = (void*)((uintptr_t)dv + slen);
- break;
- case TPL_TYPE_STR:
- for(fidx=0; fidx < c->num; fidx++) {
- memcpy(&slen,dv,sizeof(uint32_t));
- if (((tpl_root_data*)(r->data))->flags & TPL_XENDIAN)
- tpl_byteswap(&slen, sizeof(uint32_t));
- if (((tpl_root_data*)(r->data))->flags & TPL_OLD_STRING_FMT)
- slen += 1;
- dv = (void*)((uintptr_t)dv + sizeof(uint32_t));
- if (slen) { /* slen includes \0 */
- str = (char*)tpl_hook.malloc(slen);
- if (!str) fatal_oom();
- if (slen>1) memcpy(str,dv,slen-1);
- str[slen-1] = '\0'; /* nul terminate */
- dv = (void*)((uintptr_t)dv + slen-1);
- } else str=NULL;
- memcpy(&((char**)c->addr)[fidx],&str,sizeof(char*));
- }
- break;
- case TPL_TYPE_POUND:
- /* iterate over preceding nodes */
- pd = (tpl_pound_data*)c->data;
- itermax = c->num;
- if (++(pd->iternum) < itermax) {
- /* in start or midst of loop. advance addr/data pointers. */
- for(np=pd->iter_start_node; np != c; np = np->next) {
- np->addr = (char*)(np->addr) + pd->inter_elt_len;
- }
- /* do next iteration */
- c = pd->iter_start_node;
- continue;
- } else { /* loop complete. */
-
- /* reset iteration index and addr/data pointers. */
- pd->iternum = 0;
- for(np=pd->iter_start_node; np != c; np = np->next) {
- np->addr = (char*)(np->addr) - ((itermax-1) * pd->inter_elt_len);
- }
- }
- break;
- case TPL_TYPE_ARY:
- if (tpl_serlen(r,c,dv, &A_bytes) == -1)
- tpl_hook.fatal("internal error in unpack\n");
- memcpy( &((tpl_atyp*)(c->data))->num, dv, sizeof(uint32_t));
- if (((tpl_root_data*)(r->data))->flags & TPL_XENDIAN)
- tpl_byteswap(&((tpl_atyp*)(c->data))->num, sizeof(uint32_t));
- ((tpl_atyp*)(c->data))->cur = (void*)((uintptr_t)dv+sizeof(uint32_t));
- dv = (void*)((uintptr_t)dv + A_bytes);
- break;
- default:
- tpl_hook.fatal("unsupported format character\n");
- break;
- }
- c = c->next;
- }
- if (n->type == TPL_TYPE_ARY) ((tpl_atyp*)(n->data))->cur = dv; /* next element */
- return rc;
- }
- /* Specialized function that unpacks only the root's A nodes, after tpl_load */
- static int tpl_unpackA0(tpl_node *r) {
- tpl_node *n, *c;
- uint32_t slen;
- int rc=1,fidx,i;
- void *dv;
- size_t A_bytes, itermax;
- tpl_pound_data *pd;
- n = r;
- dv = tpl_find_data_start( ((tpl_root_data*)(r->data))->mmap.text);
- c=n->children;
- while (c) {
- switch (c->type) {
- case TPL_TYPE_BYTE:
- case TPL_TYPE_DOUBLE:
- case TPL_TYPE_INT32:
- case TPL_TYPE_UINT32:
- case TPL_TYPE_INT64:
- case TPL_TYPE_UINT64:
- case TPL_TYPE_INT16:
- case TPL_TYPE_UINT16:
- for(fidx=0;fidx < c->num; fidx++) {
- dv = (void*)((uintptr_t)dv + tpl_types[c->type].sz);
- }
- break;
- case TPL_TYPE_BIN:
- memcpy(&slen,dv,sizeof(uint32_t));
- if (((tpl_root_data*)(r->data))->flags & TPL_XENDIAN)
- tpl_byteswap(&slen, sizeof(uint32_t));
- dv = (void*)((uintptr_t)dv + sizeof(uint32_t));
- dv = (void*)((uintptr_t)dv + slen);
- break;
- case TPL_TYPE_STR:
- for(i=0; i<c->num; i++) {
- memcpy(&slen,dv,sizeof(uint32_t));
- if (((tpl_root_data*)(r->data))->flags & TPL_XENDIAN)
- tpl_byteswap(&slen, sizeof(uint32_t));
- if (((tpl_root_data*)(r->data))->flags & TPL_OLD_STRING_FMT)
- slen += 1;
- dv = (void*)((uintptr_t)dv + sizeof(uint32_t));
- if (slen>1) dv = (void*)((uintptr_t)dv + slen-1);
- }
- break;
- case TPL_TYPE_POUND:
- /* iterate over the preceding nodes */
- itermax = c->num;
- pd = (tpl_pound_data*)c->data;
- if (++(pd->iternum) < itermax) {
- c = pd->iter_start_node;
- continue;
- } else { /* loop complete. */
- pd->iternum = 0;
- }
- break;
- case TPL_TYPE_ARY:
- if ( tpl_serlen(r,c,dv, &A_bytes) == -1)
- tpl_hook.fatal("internal error in unpackA0\n");
- memcpy( &((tpl_atyp*)(c->data))->num, dv, sizeof(uint32_t));
- if (((tpl_root_data*)(r->data))->flags & TPL_XENDIAN)
- tpl_byteswap(&((tpl_atyp*)(c->data))->num, sizeof(uint32_t));
- ((tpl_atyp*)(c->data))->cur = (void*)((uintptr_t)dv+sizeof(uint32_t));
- dv = (void*)((uintptr_t)dv + A_bytes);
- break;
- default:
- tpl_hook.fatal("unsupported format character\n");
- break;
- }
- c=c->next;
- }
- return rc;
- }
- /* In-place byte order swapping of a word of length "len" bytes */
- static void tpl_byteswap(void *word, int len) {
- int i;
- char c, *w;
- w = (char*)word;
- for(i=0; i<len/2; i++) {
- c = w[i];
- w[i] = w[len-1-i];
- w[len-1-i] = c;
- }
- }
- static void tpl_fatal(const char *fmt, ...) {
- va_list ap;
- char exit_msg[100];
- va_start(ap,fmt);
- vsnprintf(exit_msg, 100, fmt, ap);
- va_end(ap);
- tpl_hook.oops("%s", exit_msg);
- exit(-1);
- }
- TPL_API int tpl_gather(int mode, ...) {
- va_list ap;
- int fd,rc=0;
- size_t *szp,sz;
- void **img,*addr,*data;
- tpl_gather_t **gs;
- tpl_gather_cb *cb;
- va_start(ap,mode);
- switch (mode) {
- case TPL_GATHER_BLOCKING:
- fd = va_arg(ap,int);
- img = va_arg(ap,void*);
- szp = va_arg(ap,size_t*);
- rc = tpl_gather_blocking(fd,img,szp);
- break;
- case TPL_GATHER_NONBLOCKING:
- fd = va_arg(ap,int);
- gs = (tpl_gather_t**)va_arg(ap,void*);
- cb = (tpl_gather_cb*)va_arg(ap,tpl_gather_cb*);
- data = va_arg(ap,void*);
- rc = tpl_gather_nonblocking(fd,gs,cb,data);
- break;
- case TPL_GATHER_MEM:
- addr = va_arg(ap,void*);
- sz = va_arg(ap,size_t);
- gs = (tpl_gather_t**)va_arg(ap,void*);
- cb = (tpl_gather_cb*)va_arg(ap,tpl_gather_cb*);
- data = va_arg(ap,void*);
- rc = tpl_gather_mem(addr,sz,gs,cb,data);
- break;
- default:
- tpl_hook.fatal("unsupported tpl_gather mode %d\n",mode);
- break;
- }
- va_end(ap);
- return rc;
- }
- /* dequeue a tpl by reading until one full tpl image is obtained.
- * We take care not to read past the end of the tpl.
- * This is intended as a blocking call i.e. for use with a blocking fd.
- * It can be given a non-blocking fd, but the read spins if we have to wait.
- */
- static int tpl_gather_blocking(int fd, void **img, size_t *sz) {
- char preamble[8];
- int i=0, rc;
- uint32_t tpllen;
- do {
- rc = read(fd,&preamble[i],8-i);
- i += (rc>0) ? rc : 0;
- } while ((rc==-1 && (errno==EINTR||errno==EAGAIN)) || (rc>0 && i<8));
- if (rc<0) {
- tpl_hook.oops("tpl_gather_fd_blocking failed: %s\n", strerror(errno));
- return -1;
- } else if (rc == 0) {
- /* tpl_hook.oops("tpl_gather_fd_blocking: eof\n"); */
- return 0;
- } else if (i != 8) {
- tpl_hook.oops("internal error\n");
- return -1;
- }
- if (preamble[0] == 't' && preamble[1] == 'p' && preamble[2] == 'l') {
- memcpy(&tpllen,&preamble[4],4);
- if (tpl_needs_endian_swap(preamble)) tpl_byteswap(&tpllen,4);
- } else {
- tpl_hook.oops("tpl_gather_fd_blocking: non-tpl input\n");
- return -1;
- }
- /* malloc space for remainder of tpl image (overall length tpllen)
- * and read it in
- */
- if (tpl_hook.gather_max > 0 &&
- tpllen > tpl_hook.gather_max) {
- tpl_hook.oops("tpl exceeds max length %d\n",
- tpl_hook.gather_max);
- return -2;
- }
- *sz = tpllen;
- if ( (*img = tpl_hook.malloc(tpllen)) == NULL) {
- fatal_oom();
- }
- memcpy(*img,preamble,8); /* copy preamble to output buffer */
- i=8;
- do {
- rc = read(fd,&((*(char**)img)[i]),tpllen-i);
- i += (rc>0) ? rc : 0;
- } while ((rc==-1 && (errno==EINTR||errno==EAGAIN)) || (rc>0 && i<tpllen));
- if (rc<0) {
- tpl_hook.oops("tpl_gather_fd_blocking failed: %s\n", strerror(errno));
- tpl_hook.free(*img);
- return -1;
- } else if (rc == 0) {
- /* tpl_hook.oops("tpl_gather_fd_blocking: eof\n"); */
- tpl_hook.free(*img);
- return 0;
- } else if (i != tpllen) {
- tpl_hook.oops("internal error\n");
- tpl_hook.free(*img);
- return -1;
- }
- return 1;
- }
- /* Used by select()-driven apps which want to gather tpl images piecemeal */
- /* the file descriptor must be non-blocking for this functino to work. */
- static int tpl_gather_nonblocking( int fd, tpl_gather_t **gs, tpl_gather_cb *cb, void *data) {
- char buf[TPL_GATHER_BUFLEN], *img, *tpl;
- int rc, keep_looping, cbrc=0;
- size_t catlen;
- uint32_t tpllen;
- while (1) {
- rc = read(fd,buf,TPL_GATHER_BUFLEN);
- if (rc == -1) {
- if (errno == EINTR) continue; /* got signal during read, ignore */
- if (errno == EAGAIN) return 1; /* nothing to read right now */
- else {
- tpl_hook.oops("tpl_gather failed: %s\n", strerror(errno));
- if (*gs) {
- tpl_hook.free((*gs)->img);
- tpl_hook.free(*gs);
- *gs = NULL;
- }
- return -1; /* error, caller should close fd */
- }
- } else if (rc == 0) {
- if (*gs) {
- tpl_hook.oops("tpl_gather: partial tpl image precedes EOF\n");
- tpl_hook.free((*gs)->img);
- tpl_hook.free(*gs);
- *gs = NULL;
- }
- return 0; /* EOF, caller should close fd */
- } else {
- /* concatenate any partial tpl from last read with new buffer */
- if (*gs) {
- catlen = (*gs)->len + rc;
- if (tpl_hook.gather_max > 0 &&
- catlen > tpl_hook.gather_max) {
- tpl_hook.free( (*gs)->img );
- tpl_hook.free( (*gs) );
- *gs = NULL;
- tpl_hook.oops("tpl exceeds max length %d\n",
- tpl_hook.gather_max);
- return -2; /* error, caller should close fd */
- }
- if ( (img = tpl_hook.realloc((*gs)->img, catlen)) == NULL) {
- fatal_oom();
- }
- memcpy(img + (*gs)->len, buf, rc);
- tpl_hook.free(*gs);
- *gs = NULL;
- } else {
- img = buf;
- catlen = rc;
- }
- /* isolate any full tpl(s) in img and invoke cb for each */
- tpl = img;
- keep_looping = (tpl+8 < img+catlen) ? 1 : 0;
- while (keep_looping) {
- if (strncmp("tpl", tpl, 3) != 0) {
- tpl_hook.oops("tpl prefix invalid\n");
- if (img != buf) tpl_hook.free(img);
- tpl_hook.free(*gs);
- *gs = NULL;
- return -3; /* error, caller should close fd */
- }
- memcpy(&tpllen,&tpl[4],4);
- if (tpl_needs_endian_swap(tpl)) tpl_byteswap(&tpllen,4);
- if (tpl+tpllen <= img+catlen) {
- cbrc = (cb)(tpl,tpllen,data); /* invoke cb for tpl image */
- tpl += tpllen; /* point to next tpl image */
- if (cbrc < 0) keep_looping = 0;
- else keep_looping = (tpl+8 < img+catlen) ? 1 : 0;
- } else keep_looping=0;
- }
- /* check if app callback requested closure of tpl source */
- if (cbrc < 0) {
- tpl_hook.oops("tpl_fd_gather aborted by app callback\n");
- if (img != buf) tpl_hook.free(img);
- if (*gs) tpl_hook.free(*gs);
- *gs = NULL;
- return -4;
- }
- /* store any leftover, partial tpl fragment for next read */
- if (tpl == img && img != buf) {
- /* consumed nothing from img!=buf */
- if ( (*gs = tpl_hook.malloc(sizeof(tpl_gather_t))) == NULL ) {
- fatal_oom();
- }
- (*gs)->img = tpl;
- (*gs)->len = catlen;
- } else if (tpl < img+catlen) {
- /* consumed 1+ tpl(s) from img!=buf or 0 from img==buf */
- if ( (*gs = tpl_hook.malloc(sizeof(tpl_gather_t))) == NULL ) {
- fatal_oom();
- }
- if ( ((*gs)->img = tpl_hook.malloc(img+catlen - tpl)) == NULL ) {
- fatal_oom();
- }
- (*gs)->len = img+catlen - tpl;
- memcpy( (*gs)->img, tpl, img+catlen - tpl);
- /* free partially consumed concat buffer if used */
- if (img != buf) tpl_hook.free(img);
- } else { /* tpl(s) fully consumed */
- /* free consumed concat buffer if used */
- if (img != buf) tpl_hook.free(img);
- }
- }
- }
- }
- /* gather tpl piecemeal from memory buffer (not fd) e.g., from a lower-level api */
- static int tpl_gather_mem( char *buf, size_t len, tpl_gather_t **gs, tpl_gather_cb *cb, void *data) {
- char *img, *tpl;
- int keep_looping, cbrc=0;
- size_t catlen;
- uint32_t tpllen;
- /* concatenate any partial tpl from last read with new buffer */
- if (*gs) {
- catlen = (*gs)->len + len;
- if (tpl_hook.gather_max > 0 &&
- catlen > tpl_hook.gather_max) {
- tpl_hook.free( (*gs)->img );
- tpl_hook.free( (*gs) );
- *gs = NULL;
- tpl_hook.oops("tpl exceeds max length %d\n",
- tpl_hook.gather_max);
- return -2; /* error, caller should stop accepting input from source*/
- }
- if ( (img = tpl_hook.realloc((*gs)->img, catlen)) == NULL) {
- fatal_oom();
- }
- memcpy(img + (*gs)->len, buf, len);
- tpl_hook.free(*gs);
- *gs = NULL;
- } else {
- img = buf;
- catlen = len;
- }
- /* isolate any full tpl(s) in img and invoke cb for each */
- tpl = img;
- keep_looping = (tpl+8 < img+catlen) ? 1 : 0;
- while (keep_looping) {
- if (strncmp("tpl", tpl, 3) != 0) {
- tpl_hook.oops("tpl prefix invalid\n");
- if (img != buf) tpl_hook.free(img);
- tpl_hook.free(*gs);
- *gs = NULL;
- return -3; /* error, caller should stop accepting input from source*/
- }
- memcpy(&tpllen,&tpl[4],4);
- if (tpl_needs_endian_swap(tpl)) tpl_byteswap(&tpllen,4);
- if (tpl+tpllen <= img+catlen) {
- cbrc = (cb)(tpl,tpllen,data); /* invoke cb for tpl image */
- tpl += tpllen; /* point to next tpl image */
- if (cbrc < 0) keep_looping = 0;
- else keep_looping = (tpl+8 < img+catlen) ? 1 : 0;
- } else keep_looping=0;
- }
- /* check if app callback requested closure of tpl source */
- if (cbrc < 0) {
- tpl_hook.oops("tpl_mem_gather aborted by app callback\n");
- if (img != buf) tpl_hook.free(img);
- if (*gs) tpl_hook.free(*gs);
- *gs = NULL;
- return -4;
- }
- /* store any leftover, partial tpl fragment for next read */
- if (tpl == img && img != buf) {
- /* consumed nothing from img!=buf */
- if ( (*gs = tpl_hook.malloc(sizeof(tpl_gather_t))) == NULL ) {
- fatal_oom();
- }
- (*gs)->img = tpl;
- (*gs)->len = catlen;
- } else if (tpl < img+catlen) {
- /* consumed 1+ tpl(s) from img!=buf or 0 from img==buf */
- if ( (*gs = tpl_hook.malloc(sizeof(tpl_gather_t))) == NULL ) {
- fatal_oom();
- }
- if ( ((*gs)->img = tpl_hook.malloc(img+catlen - tpl)) == NULL ) {
- fatal_oom();
- }
- (*gs)->len = img+catlen - tpl;
- memcpy( (*gs)->img, tpl, img+catlen - tpl);
- /* free partially consumed concat buffer if used */
- if (img != buf) tpl_hook.free(img);
- } else { /* tpl(s) fully consumed */
- /* free consumed concat buffer if used */
- if (img != buf) tpl_hook.free(img);
- }
- return 1;
- }
|