12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576777879808182838485868788899091929394959697989910010110210310410510610710810911011111211311411511611711811912012112212312412512612712812913013113213313413513613713813914014114214314414514614714814915015115215315415515615715815916016116216316416516616716816917017117217317417517617717817918018118218318418518618718818919019119219319419519619719819920020120220320420520620720820921021121221321421521621721821922022122222322422522622722822923023123223323423523623723823924024124224324424524624724824925025125225325425525625725825926026126226326426526626726826927027127227327427527627727827928028128228328428528628728828929029129229329429529629729829930030130230330430530630730830931031131231331431531631731831932032132232332432532632732832933033133233333433533633733833934034134234334434534634734834935035135235335435535635735835936036136236336436536636736836937037137237337437537637737837938038138238338438538638738838939039139239339439539639739839940040140240340440540640740840941041141241341441541641741841942042142242342442542642742842943043143243343443543643743843944044144244344444544644744844945045145245345445545645745845946046146246346446546646746846947047147247347447547647747847948048148248348448548648748848949049149249349449549649749849950050150250350450550650750850951051151251351451551651751851952052152252352452552652752852953053153253353453553653753853954054154254354454554654754854955055155255355455555655755855956056156256356456556656756856957057157257357457557657757857958058158258358458558658758858959059159259359459559659759859960060160260360460560660760860961061161261361461561661761861962062162262362462562662762862963063163263363463563663763863964064164264364464564664764864965065165265365465565665765865966066166266366466566666766866967067167267367467567667767867968068168268368468568668768868969069169269369469569669769869970070170270370470570670770870971071171271371471571671771871972072172272372472572672772872973073173273373473573673773873974074174274374474574674774874975075175275375475575675775875976076176276376476576676776876977077177277377477577677777877978078178278378478578678778878979079179279379479579679779879980080180280380480580680780880981081181281381481581681781881982082182282382482582682782882983083183283383483583683783883984084184284384484584684784884985085185285385485585685785885986086186286386486586686786886987087187287387487587687787887988088188288388488588688788888989089189289389489589689789889990090190290390490590690790890991091191291391491591691791891992092192292392492592692792892993093193293393493593693793893994094194294394494594694794894995095195295395495595695795895996096196296396496596696796896997097197297397497597697797897998098198298398498598698798898999099199299399499599699799899910001001100210031004100510061007100810091010101110121013101410151016101710181019102010211022102310241025102610271028102910301031103210331034103510361037103810391040104110421043104410451046104710481049105010511052105310541055105610571058105910601061106210631064106510661067106810691070107110721073107410751076107710781079108010811082108310841085108610871088108910901091109210931094109510961097109810991100110111021103110411051106110711081109111011111112111311141115111611171118111911201121112211231124112511261127112811291130113111321133113411351136113711381139114011411142114311441145114611471148114911501151115211531154115511561157115811591160116111621163116411651166116711681169117011711172117311741175117611771178117911801181118211831184118511861187118811891190119111921193119411951196119711981199120012011202120312041205120612071208120912101211121212131214121512161217121812191220122112221223122412251226122712281229123012311232123312341235123612371238123912401241124212431244124512461247124812491250125112521253125412551256125712581259126012611262126312641265126612671268126912701271127212731274127512761277127812791280128112821283128412851286128712881289129012911292129312941295129612971298129913001301130213031304130513061307130813091310131113121313131413151316131713181319132013211322132313241325132613271328132913301331133213331334133513361337133813391340134113421343134413451346134713481349135013511352135313541355135613571358135913601361136213631364136513661367136813691370137113721373137413751376137713781379138013811382138313841385138613871388138913901391139213931394139513961397139813991400140114021403140414051406140714081409141014111412141314141415141614171418141914201421142214231424142514261427142814291430143114321433143414351436143714381439144014411442144314441445144614471448144914501451145214531454145514561457145814591460146114621463146414651466146714681469147014711472147314741475147614771478147914801481148214831484148514861487148814891490149114921493149414951496149714981499150015011502150315041505150615071508150915101511151215131514151515161517151815191520152115221523152415251526152715281529153015311532153315341535153615371538153915401541154215431544154515461547154815491550155115521553155415551556155715581559156015611562156315641565156615671568156915701571157215731574157515761577157815791580158115821583158415851586158715881589159015911592159315941595159615971598159916001601160216031604160516061607160816091610161116121613161416151616161716181619162016211622162316241625162616271628162916301631163216331634163516361637163816391640164116421643164416451646164716481649165016511652165316541655165616571658165916601661166216631664166516661667166816691670167116721673167416751676167716781679168016811682168316841685168616871688168916901691169216931694169516961697169816991700170117021703170417051706170717081709171017111712171317141715171617171718171917201721172217231724172517261727172817291730173117321733173417351736173717381739174017411742174317441745174617471748174917501751175217531754175517561757175817591760176117621763176417651766176717681769177017711772177317741775177617771778177917801781178217831784178517861787178817891790179117921793179417951796179717981799180018011802180318041805180618071808180918101811181218131814181518161817181818191820182118221823182418251826182718281829183018311832183318341835183618371838183918401841184218431844184518461847184818491850185118521853185418551856185718581859186018611862186318641865186618671868186918701871187218731874187518761877187818791880188118821883188418851886188718881889189018911892189318941895189618971898189919001901190219031904190519061907190819091910191119121913191419151916191719181919192019211922192319241925192619271928192919301931193219331934193519361937193819391940194119421943194419451946194719481949195019511952195319541955195619571958195919601961196219631964196519661967196819691970197119721973197419751976197719781979198019811982198319841985198619871988198919901991199219931994199519961997199819992000200120022003200420052006200720082009201020112012201320142015201620172018201920202021202220232024202520262027202820292030203120322033203420352036203720382039204020412042204320442045204620472048204920502051205220532054205520562057205820592060206120622063206420652066206720682069207020712072207320742075207620772078207920802081208220832084208520862087208820892090209120922093209420952096209720982099210021012102210321042105210621072108210921102111211221132114211521162117211821192120212121222123212421252126212721282129213021312132213321342135213621372138213921402141214221432144214521462147214821492150215121522153215421552156215721582159216021612162216321642165216621672168216921702171217221732174217521762177217821792180218121822183218421852186218721882189219021912192219321942195219621972198219922002201220222032204220522062207220822092210221122122213221422152216221722182219222022212222222322242225222622272228222922302231223222332234223522362237223822392240224122422243224422452246224722482249225022512252225322542255225622572258225922602261226222632264226522662267226822692270227122722273227422752276227722782279228022812282228322842285228622872288228922902291229222932294229522962297229822992300230123022303230423052306230723082309231023112312231323142315231623172318231923202321232223232324232523262327232823292330233123322333233423352336233723382339234023412342234323442345234623472348234923502351235223532354235523562357235823592360236123622363236423652366236723682369237023712372237323742375237623772378237923802381238223832384238523862387238823892390239123922393239423952396239723982399240024012402240324042405240624072408240924102411241224132414241524162417241824192420242124222423242424252426242724282429243024312432243324342435243624372438243924402441244224432444244524462447244824492450245124522453245424552456245724582459246024612462246324642465246624672468246924702471247224732474247524762477247824792480248124822483248424852486248724882489 |
- #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"
- #else
- #include <sys/mman.h> /* mmap */
- #endif
- #include "tpl.h"
- #define TPL_GATHER_BUFLEN 8192
- #define TPL_MAGIC "tpl"
- #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")
- #define TPL_WRONLY (1 << 9)
- #define TPL_RDONLY (1 << 10)
- #define TPL_XENDIAN (1 << 11)
- #define TPL_OLD_STRING_FMT (1 << 12)
- #define TPL_SUPPORTED_BITFLAGS 3
- #define TPL_FL_BIGENDIAN (1 << 0)
- #define TPL_FL_NULLSTRINGS (1 << 1)
- #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
- #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)
- typedef struct tpl_pidx {
- struct tpl_node *node;
- struct tpl_pidx *next,*prev;
- } tpl_pidx;
- typedef struct tpl_atyp {
- uint32_t num;
- size_t sz;
- struct tpl_backbone *bb,*bbtail;
- void *cur;
- } tpl_atyp;
- typedef struct tpl_backbone {
- struct tpl_backbone *next;
-
- #if __STDC_VERSION__ < 199901
- char *data;
- #else
- char data[];
- #endif
- } tpl_backbone;
- typedef struct tpl_mmap_rec {
- int fd;
- void *text;
- size_t text_sz;
- } tpl_mmap_rec;
- typedef struct tpl_root_data {
- int flags;
- tpl_pidx *pidx;
- tpl_mmap_rec mmap;
- char *fmt;
- int *fxlens, num_fxlens;
- } tpl_root_data;
- struct tpl_type_t {
- char c;
- int sz;
- };
- 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);
- struct tpl_double_alignment_detector {
- char a;
- double d;
- };
- struct tpl_int64_alignment_detector {
- int i;
- int64_t j;
- };
- typedef struct {
- size_t inter_elt_len;
- tpl_node *iter_start_node;
- size_t iternum;
- } tpl_pound_data;
- tpl_hook_t tpl_hook = {
- tpl_oops,
- malloc,
- realloc,
- free,
- tpl_fatal,
- 0
- };
- static const char tpl_fmt_chars[] = "AS($)BiucsfIUjv#";
- static const char tpl_S_fmt_chars[] = "iucsfIUjv#$()";
- static const char tpl_datapeek_ok_chars[] = "iucsfIUjv";
- static const struct tpl_type_t tpl_types[] = {
- {'r', 0},
- {'i', sizeof(int32_t)},
- {'u', sizeof(uint32_t)},
- {'c', sizeof(char)},
- {'s', sizeof(char*)},
- {'A', 0},
- {'B', 0},
- {'f', 8},
- {'I', sizeof(int64_t)},
- {'U', sizeof(uint64_t)},
- {'j', sizeof(int16_t)},
- {'v', sizeof(uint16_t)},
- {'#', 0},
- };
- 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;
- }
- 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;
-
- 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];
- int num_contig_fxlens, i, j;
- ptrdiff_t inter_elt_len=0;
- 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));
-
- root->ser_osz = sizeof(uint32_t);
- root->ser_osz += strlen(fmt) + 1;
- root->ser_osz += 4;
- 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) {
-
- 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;
- 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 '#':
-
- if (!parent->children) goto fail;
- preceding = parent->children->prev;
- 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;
- }
-
- 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;
- }
-
- c = peek-1;
-
- if (applies_to_struct) {
- 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);
-
- 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 {
- 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;
- (((tpl_root_data*)root->data)->num_fxlens) += num_contig_fxlens;
- num_fxlens = ((tpl_root_data*)root->data)->num_fxlens;
- 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);
-
- 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;
- in_structure=1+lparen_level;
- struct_addr = (char*)va_arg(ap,void*);
- break;
- case '$':
- 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)) {
-
- 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;
- 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;
-
- ((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;
-
- 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) {
- switch (c->type) {
- case TPL_TYPE_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;
- }
- find_next_node=1;
- break;
- case TPL_TYPE_STR:
-
- 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;
- sz = ((tpl_atyp*)(c->data))->sz;
- tpl_free_atyp(c,c->data);
-
- 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;
- ((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;
- else {
- nxtc=c->parent;
- c=nxtc;
- }
- }
- }
- }
- }
- }
- ((tpl_root_data*)(r->data))->flags = 0;
- }
- 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;
-
- 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) {
- switch (c->type) {
- case TPL_TYPE_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));
- }
- tpl_hook.free(c->data);
- find_next_node=1;
- break;
- case TPL_TYPE_STR:
-
- 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;
- else find_next_node=1;
- 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;
- else {
- nxtc=c->parent;
- tpl_hook.free(c);
- c=nxtc;
- }
- }
- }
- }
- }
- }
-
- 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_hook.free(r);
- }
- 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;
- 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 );
- 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;
-
- 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;
- }
- static char *tpl_fmt(tpl_node *r) {
- return ((tpl_root_data*)(r->data))->fmt;
- }
- 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;
- }
- 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;
-
- dv = tpl_cpv(dv,&at->num,sizeof(uint32_t));
- 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:
-
- memcpy(&binp,datav,sizeof(tpl_bin*));
- 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:
-
- for(i=0; i < c->num; i++) {
- memcpy(&strp,datav,sizeof(char*));
- 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*));
- dv = tpl_dump_atyp(c,atypp,dv);
- datav = (void*)((uintptr_t)datav + sizeof(void*));
- break;
- case TPL_TYPE_POUND:
-
- pd = (tpl_pound_data*)c->data;
- itermax = c->num;
- if (++(pd->iternum) < itermax) {
- c = pd->iter_start_node;
- continue;
- } else {
- pd->iternum = 0;
- }
- break;
- default:
- tpl_hook.fatal("unsupported format character\n");
- break;
- }
- c=c->next;
- }
- }
- return dv;
- }
- 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;
-
- if (n->type != TPL_TYPE_ROOT) {
- tpl_hook.fatal("internal error: tpl_ser_osz on non-root node\n");
- }
- sz = n->ser_osz;
- 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);
- memcpy(&binp,c->data,sizeof(tpl_bin*));
- sz += binp->sz;
- break;
- case TPL_TYPE_STR:
- for(i=0; i < c->num; i++) {
- sz += sizeof(uint32_t);
- memcpy(&strp,&((char**)c->data)[i],sizeof(char*));
- sz += strp ? strlen(strp) : 0;
- }
- break;
- case TPL_TYPE_ARY:
- sz += sizeof(uint32_t);
- sz += c->ser_osz;
- break;
- case TPL_TYPE_POUND:
-
- 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 {
- 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) {
- tpl_hook.oops("error: tpl_dump called for a loaded tpl\n");
- return -1;
- }
- sz = tpl_ser_osz(r);
- 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));
-
- 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) {
- 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 {
- 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;
- }
- 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);
- dv = tpl_cpv(dv,&flags,1);
- dv = tpl_cpv(dv,&sz32,sizeof(uint32_t));
- dv = tpl_cpv(dv,fmt,strlen(fmt)+1);
- fxlens = tpl_fxlens(r,&num_fxlens);
- dv = tpl_cpv(dv,fxlens,num_fxlens*sizeof(uint32_t));
-
- 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));
- dv = tpl_cpv(dv,(*(tpl_bin**)(c->data))->addr,slen);
- 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));
- if (slen>1) dv = tpl_cpv(dv,str,slen-1);
- }
- 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) {
-
- 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 {
-
-
- 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);
- }
- 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;
- if (memcmp(dv,TPL_MAGIC, 3) != 0) return ERR_MAGIC_MISMATCH;
- 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));
- if (intlflags & ~TPL_SUPPORTED_BITFLAGS) return ERR_UNSUPPORTED_FLAGS;
-
- 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));
- if (((tpl_root_data*)(r->data))->flags & TPL_XENDIAN) tpl_byteswap(&intlsz, sizeof(uint32_t));
- if (!excess_ok && (intlsz != bufsz)) return ERR_INCONSISTENT_SZ;
- dv = (void*)((uintptr_t)dv + sizeof(uint32_t));
-
- 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;
- if ( (c = *(char*)dv) == '#') octothorpes++;
- dv = (void*)((uintptr_t)dv + 1);
- }
- else found_nul = 1;
- }
- if (!found_nul) return ERR_FMT_MISSING_NUL;
- dv = (void*)((uintptr_t)dv + 1);
-
-
- mapfmt = tpl_fmt(r);
- rc = strcmp(mapfmt,fmt);
- if (rc != 0) return ERR_FMT_MISMATCH;
-
- if ((((uintptr_t)dv + (octothorpes * 4)) - (uintptr_t)d) > bufsz) return ERR_INCONSISTENT_SZ4;
- fxlens = tpl_fxlens(r,&num_fxlens);
- while(num_fxlens--) {
- memcpy(&flen,dv,sizeof(uint32_t));
- 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++;
- }
-
- rc = tpl_serlen(r,r,dv,&serlen);
- if (rc == -1) return ERR_INCONSISTENT_SZ2;
- serlen += ((uintptr_t)dv - (uintptr_t)d);
- if (excess_ok && (bufsz < serlen)) return ERR_INCONSISTENT_SZ3;
- if (!excess_ok && (serlen != bufsz)) return ERR_INCONSISTENT_SZ3;
- return 0;
- }
- static void *tpl_find_data_start(void *d) {
- int octothorpes=0;
- d = (void*)((uintptr_t)d + 4);
- d = (void*)((uintptr_t)d + 4);
- while(*(char*)d != '\0') {
- if (*(char*)d == '#') octothorpes++;
- d = (void*)((uintptr_t)d + 1);
- }
- d = (void*)((uintptr_t)d + 1);
- d = (void*)((uintptr_t)d + (octothorpes * sizeof(uint32_t)));
- 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;
- if (memcmp(dv,TPL_MAGIC, 3) != 0) goto fail;
- 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));
- if (xendian) tpl_byteswap(&intlsz, sizeof(uint32_t));
- if (intlsz != sz) goto fail;
- dv = (void*)((uintptr_t)dv + sizeof(uint32_t));
-
- 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;
- fmt_len = (char*)dv - fmt;
- fmt_cpy = tpl_hook.malloc(fmt_len);
- if (fmt_cpy == NULL) {
- fatal_oom();
- }
- memcpy(fmt_cpy, fmt, fmt_len);
-
- 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 (mode & TPL_DATAPEEK) {
- first_atom = strspn(fmt, "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;
- 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;
- goto fail;
- }
-
- 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') {
- 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;
- goto fail;
- }
- memcpy(&datapeek_ssz,dv,sizeof(uint32_t));
- if (xendian) tpl_byteswap(&datapeek_ssz, sizeof(uint32_t));
- if (old_string_format) datapeek_ssz++;
- dv = (void*)((uintptr_t)dv + sizeof(uint32_t));
- 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;
- 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;
- 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_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)) {
-
- 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 (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;
- }
-
- if (tpl_needs_endian_swap(((tpl_root_data*)(r->data))->mmap.text))
- ((tpl_root_data*)(r->data))->flags |= TPL_XENDIAN;
- tpl_unpackA0(r);
- 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*));
- if (binp->addr) tpl_hook.free( binp->addr );
- tpl_hook.free(binp);
- 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*));
- if (strp) tpl_hook.free(strp);
- dv = (void*)((uintptr_t)dv + sizeof(char*));
- }
- break;
- case TPL_TYPE_POUND:
-
- itermax = c->num;
- pd = (tpl_pound_data*)c->data;
- if (++(pd->iternum) < itermax) {
- c = pd->iter_start_node;
- continue;
- } else {
- pd->iternum = 0;
- }
- break;
- case TPL_TYPE_ARY:
- memcpy(&atypp,dv,sizeof(tpl_atyp*));
- tpl_free_atyp(c,atypp);
- 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);
- }
- 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++) {
- 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++) {
- 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:
-
- itermax = c->num;
- pd = (tpl_pound_data*)c->data;
- if (++(pd->iternum) < itermax) {
- c = pd->iter_start_node;
- continue;
- } else {
- 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;
- 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) {
-
- 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:
-
- 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:
-
- 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;
-
- bin = tpl_hook.malloc(sizeof(tpl_bin));
- if (!bin) fatal_oom();
- bin->addr = str;
- bin->sz = slen;
-
- 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);
- n->ser_osz += bin->sz;
- }
- break;
- case TPL_TYPE_STR:
- for(fidx=0; fidx < child->num; fidx++) {
-
- 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);
- } else {
- str = NULL;
- }
-
- 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);
- if (slen>1) n->ser_osz += slen-1;
- }
- }
- break;
- case TPL_TYPE_ARY:
-
- 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;
- }
-
- if (n->type == TPL_TYPE_ARY) {
- n->ser_osz += sizeof(uint32_t);
- n->ser_osz += child->ser_osz;
- child->ser_osz = 0;
- }
- break;
- case TPL_TYPE_POUND:
-
- pd = (tpl_pound_data*)child->data;
- itermax = child->num;
-
-
-
-
- if (++(pd->iternum) < itermax) {
-
- 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;
- }
-
- child = pd->iter_start_node;
- continue;
- } else {
-
-
- 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;
-
- 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;
- }
-
- 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;
- 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:
-
- 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 {
-
- 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) {
- str = (char*)tpl_hook.malloc(slen);
- if (!str) fatal_oom();
- if (slen>1) memcpy(str,dv,slen-1);
- str[slen-1] = '\0';
- dv = (void*)((uintptr_t)dv + slen-1);
- } else str=NULL;
- memcpy(&((char**)c->addr)[fidx],&str,sizeof(char*));
- }
- break;
- case TPL_TYPE_POUND:
-
- pd = (tpl_pound_data*)c->data;
- itermax = c->num;
- if (++(pd->iternum) < itermax) {
-
- for(np=pd->iter_start_node; np != c; np = np->next) {
- np->addr = (char*)(np->addr) + pd->inter_elt_len;
- }
-
- c = pd->iter_start_node;
- continue;
- } else {
-
-
- 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;
- return rc;
- }
- 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:
-
- itermax = c->num;
- pd = (tpl_pound_data*)c->data;
- if (++(pd->iternum) < itermax) {
- c = pd->iter_start_node;
- continue;
- } else {
- 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;
- }
- 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;
- }
- 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) {
-
- 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;
- }
-
- 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);
- 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.free(*img);
- return 0;
- } else if (i != tpllen) {
- tpl_hook.oops("internal error\n");
- tpl_hook.free(*img);
- return -1;
- }
- return 1;
- }
- 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;
- if (errno == EAGAIN) return 1;
- 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;
- }
- } 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;
- } else {
-
- 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;
- }
- 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;
- }
-
- 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;
- }
- 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);
- tpl += tpllen;
- if (cbrc < 0) keep_looping = 0;
- else keep_looping = (tpl+8 < img+catlen) ? 1 : 0;
- } else keep_looping=0;
- }
-
- 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;
- }
-
- if (tpl == img && 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) {
-
- 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);
-
- if (img != buf) tpl_hook.free(img);
- } else {
-
- if (img != buf) tpl_hook.free(img);
- }
- }
- }
- }
- 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;
-
- 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;
- }
- 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;
- }
-
- 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;
- }
- 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);
- tpl += tpllen;
- if (cbrc < 0) keep_looping = 0;
- else keep_looping = (tpl+8 < img+catlen) ? 1 : 0;
- } else keep_looping=0;
- }
-
- 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;
- }
-
- if (tpl == img && 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) {
-
- 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);
-
- if (img != buf) tpl_hook.free(img);
- } else {
-
- if (img != buf) tpl_hook.free(img);
- }
- return 1;
- }
|