#include "AbstractXMLLoader.h" namespace LogicalBodyTypes { AbstractXMLLoader::AbstractXMLLoader(XML_StartElementHandler startHandler, XML_EndElementHandler endHandler, XML_CharacterDataHandler charHandler, ParseDataFactoryFunc parseDataFactF) { startElementHandler = startHandler; endElementHandler = endHandler; characterDataHandler = charHandler; parseDataFactFuncPntr = parseDataFactF; } AbstractXMLLoader::~AbstractXMLLoader(void) { } AbstractXMLLoader::ParseData::ParseData(XML_Parser* parser) { pParser = parser; state = E_NONE; level = 0; szCharData[0] = '\0'; szErrorTxt[0] = '\0'; } AbstractXMLLoader::ParseData* AbstractXMLLoader::MakeParseData(XML_Parser* parser) { return new ParseData(parser); } bool AbstractXMLLoader::LoadFromFile(const char* directoryName, const char* fileName) { HWFILE hFile; UINT32 uiBytesRead; UINT32 uiFSize; CHAR8* lpcBuffer; char fileNameFull[MAX_PATH + 1]; if (strlen(fileName) + strlen(directoryName) >= MAX_PATH) { LiveMessage("Can't load file. Concatinated filename too long for buffer!"); return false; } SetDirectoryName(directoryName); SetFileName(fileName); strcpy(fileNameFull, directoryName); strcat(fileNameFull, fileName); XML_Parser parser = XML_ParserCreate(NULL); AbstractXMLLoader::ParseData* data = parseDataFactFuncPntr(&parser); std::string msg = "Loading "; msg += fileName; DebugMsg(TOPIC_JA2, DBG_LEVEL_3, msg.c_str()); hFile = FileOpen(fileNameFull, FILE_ACCESS_READ, FALSE); if (!hFile) { delete data; return false; } uiFSize = FileGetSize(hFile); lpcBuffer = (CHAR8*)MemAlloc(uiFSize + 1); if (!FileRead(hFile, lpcBuffer, uiFSize, &uiBytesRead)) { MemFree(lpcBuffer); delete data; return false; } lpcBuffer[uiFSize] = 0; FileClose(hFile); ExternalEntityArgs eeArgs; eeArgs.directoryName = directoryName; eeArgs.fileName = fileName; eeArgs.pParser = &parser; XML_SetElementHandler(parser, startElementHandler, endElementHandler); XML_SetCharacterDataHandler(parser, characterDataHandler); XML_SetUserData(parser, data); XML_SetExternalEntityRefHandler(parser, ExternalEntityHandler); XML_SetExternalEntityRefHandlerArg(parser, (void*)&eeArgs); try { if (!XML_Parse(parser, lpcBuffer, uiFSize, TRUE)) { CHAR8 errorBuf[512]; sprintf(errorBuf, "XML Parser Error in %s[%d]: %s", fileNameFull, XML_GetCurrentLineNumber(parser), XML_ErrorString(XML_GetErrorCode(parser))); LiveMessage(errorBuf); MemFree(lpcBuffer); delete data; return false; } } catch (XMLParseException e) { CHAR8 errorBuf[512]; sprintf(errorBuf, "XML Parser Exception in %s[%d]: %s", fileNameFull, e._LINE, e.what()); LiveMessage(errorBuf); MemFree(lpcBuffer); XML_ParserFree(parser); delete data; return false; } MemFree(lpcBuffer); XML_ParserFree(parser); delete data; return true; } int XMLCALL AbstractXMLLoader::ExternalEntityHandler(XML_Parser args, const XML_Char* context, const XML_Char* base, const XML_Char* systemId, const XML_Char* publicId) { ExternalEntityArgs* eArgs = (ExternalEntityArgs*)args; char fileNameFull[MAX_PATH + 1]; UINT32 uiBytesRead; UINT32 uiFSize; CHAR8* lpcBuffer; HWFILE hFile; if (strlen(eArgs->directoryName) + strlen(systemId) >= MAX_PATH) { LiveMessage("Can't load file specified in external entity. Concatinated filename too long for buffer!"); return XML_STATUS_ERROR; } strcpy(fileNameFull, eArgs->directoryName); strcat(fileNameFull, systemId); hFile = FileOpen(fileNameFull, FILE_ACCESS_READ, FALSE); if (!hFile) { LiveMessage("File specified in external entity can't be opened!"); return XML_STATUS_ERROR; } uiFSize = FileGetSize(hFile); lpcBuffer = (CHAR8*)MemAlloc(uiFSize + 1); if (!FileRead(hFile, lpcBuffer, uiFSize, &uiBytesRead)) { LiveMessage("File specified in external entity couldn't be read!"); MemFree(lpcBuffer); return XML_STATUS_ERROR; } lpcBuffer[uiFSize] = 0; FileClose(hFile); XML_Parser extParser = XML_ExternalEntityParserCreate(*eArgs->pParser, context, NULL); ParseData* data = (ParseData*)XML_GetUserData(*eArgs->pParser); data->pParser = &extParser; try { if (!XML_Parse(extParser, lpcBuffer, uiFSize, TRUE)) { CHAR8 errorBuf[512]; sprintf(errorBuf, "XML Parser Error in external entity %s[%d]: %s", systemId, XML_GetCurrentLineNumber(extParser), XML_ErrorString(XML_GetErrorCode(extParser))); LiveMessage(errorBuf); MemFree(lpcBuffer); return XML_STATUS_ERROR; } } catch (XMLParseException e) { CHAR8 errorBuf[512]; sprintf(errorBuf, "XML Parser Exception in external entity %s[%d]: %s", systemId, e._LINE, e.what()); LiveMessage(errorBuf); XML_ParserFree(extParser); MemFree(lpcBuffer); return XML_STATUS_ERROR; } data->pParser = eArgs->pParser; XML_ParserFree(extParser); MemFree(lpcBuffer); return XML_STATUS_OK; }; const char* AbstractXMLLoader::GetFileName() { return fileName; } const char* AbstractXMLLoader::GetDirectoryName() { return directoryName; } void AbstractXMLLoader::SetFileName(const char* fileName) { strcpy(this->fileName, fileName); } void AbstractXMLLoader::SetDirectoryName(const char* directoryName) { strcpy(this->directoryName, directoryName); } const XML_Char* AbstractXMLLoader::GetAttribute(const XML_Char* name, const XML_Char** atts) { for (const XML_Char** pIter = atts; *pIter != NULL; pIter++) { const XML_Char* key = *pIter++; if (strcmp(key, name) == 0) return *pIter; } return NULL; } bool AbstractXMLLoader::ConvertStringToINT8(const XML_Char* num, INT8* int8) { long l = strtol(num, NULL, 10); if (l > 127 || l < -128) return false; if (l == 0 && strcmp(num, "0") != 0) return false; *int8 = (INT8)l; return true; } bool AbstractXMLLoader::ConvertStringToUINT8(const XML_Char* num, UINT8* uInt8) { unsigned long ul = strtoul(num, NULL, 10); if (ul > 255) return false; if (ul == 0 && strcmp(num, "0") != 0) return false; *uInt8 = (UINT8)ul; return true; } bool AbstractXMLLoader::ConvertStringToINT32(const XML_Char* num, INT32* int32) { long l = strtol(num, NULL, 10); // TODO: add range checks also for long types (and use the defined macros) // TODO: string should be trimmed (other convert functions also) if (l == 0 && strcmp(num, "0") != 0) return false; *int32 = (INT32)l; return true; } bool AbstractXMLLoader::ConvertStringToUINT32(const XML_Char* num, UINT32* uInt32) { unsigned long ul = strtoul(num, NULL, 10); if (ul == 0 && strcmp(num, "0") != 0) return false; *uInt32 = ul; return true; } bool AbstractXMLLoader::ConvertStringToBOOLEAN(const XML_Char* num, BOOLEAN* fBoolean) { unsigned long ul = strtoul(num, NULL, 10); if (ul == 0 && strcmp(num, "0") != 0) return false; *fBoolean = ul != 0; return true; } }