#include #include #include #include typedef struct { XML_Parser parser; XML_Char* (*decoder)(const XML_Char*); int locations; } MyParser; typedef struct { size_t offset; size_t capacity; uint8_t* block; MyParser* mp; } Block; /*! * Allocate the specified amount of room in the buffer. */ static void* alloc(Block* blk, size_t room) { size_t minCapacity = blk->offset + room; size_t start = blk->offset; { int changed = 0; size_t capacity = blk->capacity; while (capacity < minCapacity) { capacity = capacity * 2; changed = 1; } if (changed) { blk->capacity = capacity; blk->block = realloc(blk->block, capacity); } } blk->offset += room; return blk->block + start; } static void pushType(Block* blk, uint32_t type) { *(uint32_t*)alloc(blk, 4) = type; if (blk->mp->locations) { int64_t* loc = alloc(blk, 32); loc[0] = (int64_t)XML_GetCurrentLineNumber(blk->mp->parser); loc[1] = (int64_t)XML_GetCurrentColumnNumber(blk->mp->parser); loc[2] = (int64_t)XML_GetCurrentByteIndex(blk->mp->parser); loc[3] = (int64_t)XML_GetCurrentByteCount(blk->mp->parser); } } #define ROUND_UP_32(x) (((x) + 3) & ~3) static void startElement( void *userData, const XML_Char *name, const XML_Char **atts) { Block* blk = userData; size_t nameLen = strlen(name) + 1; size_t nAtts, i; for (nAtts = 0; atts[nAtts] != NULL; nAtts += 2) ; pushType(blk, 1); *(uint32_t*)alloc(blk, 4) = nAtts; memcpy(alloc(blk, nameLen), name, nameLen); for (i = 0; i < nAtts; i++) { size_t attLen = strlen(atts[i]) + 1; memcpy(alloc(blk, attLen), atts[i], attLen); } blk->offset = ROUND_UP_32(blk->offset); } static void endElement(void *userData, const XML_Char *name) { Block* blk = userData; size_t nameLen = strlen(name) + 1; pushType(blk, 2); memcpy(alloc(blk, nameLen), name, nameLen); blk->offset = ROUND_UP_32(blk->offset); } static void characterData( void *userData, const XML_Char *s, int len) { Block* blk = userData; pushType(blk, 3); *(uint32_t*)alloc(blk, 4) = len; memcpy(alloc(blk, (size_t)len), s, (size_t)len); blk->offset = ROUND_UP_32(blk->offset); } static void xmlDeclHandler(void *userData, const XML_Char *version, const XML_Char *encoding, int standalone) { Block* blk = userData; int verLen = strlen(version) + 1; pushType(blk, 4); memcpy(alloc(blk, verLen), version, verLen); if (encoding != NULL) { int encLen = strlen(encoding)+1; uint8_t* pEnc = alloc(blk, encLen+1); pEnc[0] = 1; memcpy(pEnc+1, encoding, encLen); } else *(uint8_t*)alloc(blk, 1) = 0; *(int8_t*)alloc(blk, 1) = (int8_t)standalone; blk->offset = ROUND_UP_32(blk->offset); } static void startCData(void* userData) { Block* blk = userData; pushType(blk, 5); } static void endCData(void* userData) { Block* blk = userData; pushType(blk, 6); } static void processingInstruction(void *userData, const XML_Char *target, const XML_Char *data) { Block* blk = userData; int targetLen = strlen(target) + 1; int dataLen = strlen(data) + 1; pushType(blk, 7); memcpy(alloc(blk, targetLen), target, targetLen); memcpy(alloc(blk, dataLen), data, dataLen); blk->offset = ROUND_UP_32(blk->offset); } static void comment(void* userData, const XML_Char *text) { Block* blk = userData; int textLen = strlen(text) + 1; pushType(blk, 8); memcpy(alloc(blk, textLen), text, textLen); blk->offset = ROUND_UP_32(blk->offset); } MyParser* hexpatNewParser(const XML_Char* encoding, int locations) { MyParser* mp = malloc(sizeof(MyParser)); XML_Parser p = XML_ParserCreate(encoding); XML_SetStartElementHandler(p, startElement); XML_SetEndElementHandler(p, endElement); XML_SetCharacterDataHandler(p, characterData); XML_SetXmlDeclHandler(p, xmlDeclHandler); XML_SetCdataSectionHandler(p, startCData, endCData); XML_SetProcessingInstructionHandler(p, processingInstruction); XML_SetCommentHandler(p, comment); mp->parser = p; mp->locations = locations; return mp; } void hexpatFreeParser(MyParser* mp) { XML_ParserFree(mp->parser); free(mp); } static int externalEntityRef(XML_Parser parser, const XML_Char *context, const XML_Char *base, const XML_Char *systemId, const XML_Char *publicId) { if (systemId == NULL && publicId == NULL) { XML_Parser eep = XML_ExternalEntityParserCreate(parser, context, NULL); enum XML_Status ret = XML_Parse(eep, "", 0, XML_TRUE); if (ret == XML_STATUS_OK) { XML_ParserFree(eep); } else { XML_ParserFree(eep); XML_StopParser(parser, 0); } } else XML_StopParser(parser, 0); } static void skippedEntity(void *userData, const XML_Char *entityName, int is_parameter_entity) { Block* blk = userData; if (is_parameter_entity) XML_StopParser(blk->mp->parser, 0); else { XML_Char* out = blk->mp->decoder(entityName); if (out != NULL) { characterData(blk, out, strlen(out)); free(out); } else XML_StopParser(blk->mp->parser, 0); } } enum XML_Status hexpatParse( MyParser* mp, const char* s, int len, int isFinal, uint8_t** buffer, int* length) { enum XML_Status ret; Block blk; blk.offset = 0; blk.capacity = 256; blk.block = malloc(blk.capacity); blk.mp = mp; XML_SetUserData(mp->parser, &blk); ret = XML_Parse(mp->parser, s, len, isFinal); *(uint32_t*)alloc(&blk, 4) = 0; *buffer = blk.block; *length = (int)blk.offset; return ret; } void hexpatSetEntityHandler( MyParser* mp, XML_Char* (*decoder)(const XML_Char*)) { mp->decoder = decoder; XML_UseForeignDTD(mp->parser, XML_TRUE); XML_SetExternalEntityRefHandler(mp->parser, externalEntityRef); XML_SetSkippedEntityHandler(mp->parser, skippedEntity); } XML_Parser hexpatGetParser(MyParser* mp) { return mp->parser; }