18 #include "precompiled.h"
32 #include <libxml/parser.h>
37 std::string message = error->message;
38 if (message.length() > 0 && message[message.length()-1] ==
'\n')
39 message.erase(message.length()-1);
41 LOGERROR(L
"CXeromyces: Parse %ls: %hs:%d: %hs",
42 error->level == XML_ERR_WARNING ? L
"warning" : L
"error",
43 error->file, error->line, message.c_str());
51 ENSURE(!g_XeromycesStarted);
54 g_XeromycesStarted =
true;
59 ENSURE(g_XeromycesStarted);
61 xmlSetStructuredErrorFunc(NULL, NULL);
62 g_XeromycesStarted =
false;
67 ENSURE(g_XeromycesStarted);
96 LOGERROR(L
"CCacheLoader failed to find archived or source file for: \"%ls\"", filename.
string().c_str());
116 if (input.
Load(vfs, filename))
118 LOGERROR(L
"CXeromyces: Failed to open XML file %ls", filename.
string().c_str());
122 CStr8 filename8(CStrW(filename.
string()).ToUTF8());
124 filename8.c_str(), NULL, XML_PARSE_NONET|XML_PARSE_NOCDATA);
127 LOGERROR(L
"CXeromyces: Failed to parse XML file %ls", filename.
string().c_str());
137 vfs->CreateFile(xmbPath, writeBuffer.
Data(), writeBuffer.
Size());
169 ENSURE(g_XeromycesStarted);
171 xmlDocPtr doc = xmlReadMemory(xml, (
int)strlen(xml),
"", NULL, XML_PARSE_NONET|XML_PARSE_NOCDATA);
174 LOGERROR(L
"CXeromyces: Failed to parse XML string");
193 static void FindNames(
const xmlNodePtr node, std::set<std::string>& elementNames, std::set<std::string>& attributeNames)
195 elementNames.insert((
const char*)node->name);
197 for (xmlAttrPtr attr = node->properties; attr; attr = attr->next)
198 attributeNames.insert((
const char*)attr->name);
200 for (xmlNodePtr child = node->children; child; child = child->next)
201 if (child->type == XML_ELEMENT_NODE)
202 FindNames(child, elementNames, attributeNames);
206 std::map<std::string, u32>& elementIDs,
207 std::map<std::string, u32>& attributeIDs
211 size_t posLength = writeBuffer.
Size();
212 writeBuffer.
Append(
"????", 4);
214 writeBuffer.
Append(&elementIDs[(
const char*)node->name], 4);
217 for (xmlAttrPtr attr = node->properties; attr; attr = attr->next)
219 writeBuffer.
Append(&attrCount, 4);
222 for (xmlNodePtr child = node->children; child; child = child->next)
223 if (child->type == XML_ELEMENT_NODE)
225 writeBuffer.
Append(&childCount, 4);
228 size_t posChildrenOffset = writeBuffer.
Size();
229 writeBuffer.
Append(
"????", 4);
236 std::string whitespace =
" \t\r\n";
238 for (xmlNodePtr child = node->children; child; child = child->next)
240 if (child->type == XML_TEXT_NODE)
242 xmlChar* content = xmlNodeGetContent(child);
243 text += std::string((
const char*)content);
248 u32 linenum = xmlGetLineNo(node);
251 size_t first = text.find_first_not_of(whitespace);
253 if (first == text.npos)
261 std::string trimmed (text.begin(), text.begin()+first);
262 linenum += std::count(trimmed.begin(), trimmed.end(),
'\n');
266 size_t last = text.find_last_not_of(whitespace);
267 text = text.substr(first, 1+last-first);
272 if (text.length() == 0)
275 writeBuffer.
Append(
"\0\0\0\0", 4);
280 utf16string textW = CStr8(text).FromUTF8().utf16();
281 u32 nodeLen =
u32(4 + 2*(textW.length()+1));
282 writeBuffer.
Append(&nodeLen, 4);
283 writeBuffer.
Append(&linenum, 4);
284 writeBuffer.
Append((
void*)textW.c_str(), nodeLen-4);
288 for (xmlAttrPtr attr = node->properties; attr; attr = attr->next)
290 writeBuffer.
Append(&attributeIDs[(
const char*)attr->name], 4);
292 xmlChar* value = xmlNodeGetContent(attr->children);
293 utf16string textW = CStr8((
const char*)value).FromUTF8().utf16();
295 u32 attrLen =
u32(2*(textW.length()+1));
296 writeBuffer.
Append(&attrLen, 4);
297 writeBuffer.
Append((
void*)textW.c_str(), attrLen);
301 u32 childrenOffset = (
u32)(writeBuffer.
Size() - (posChildrenOffset+4));
302 writeBuffer.
Overwrite(&childrenOffset, 4, posChildrenOffset);
305 for (xmlNodePtr child = node->children; child; child = child->next)
306 if (child->type == XML_ELEMENT_NODE)
310 u32 length = (
u32)(writeBuffer.
Size() - posLength);
311 writeBuffer.
Overwrite(&length, 4, posLength);
319 std::set<std::string>::iterator it;
323 std::set<std::string> elementNames;
324 std::set<std::string> attributeNames;
325 FindNames(xmlDocGetRootElement(doc), elementNames, attributeNames);
327 std::map<std::string, u32> elementIDs;
328 std::map<std::string, u32> attributeIDs;
332 u32 elementCount = (
u32)elementNames.size();
333 writeBuffer.
Append(&elementCount, 4);
334 for (it = elementNames.begin(); it != elementNames.end(); ++it)
336 u32 textLen = (
u32)it->length()+1;
337 writeBuffer.
Append(&textLen, 4);
338 writeBuffer.
Append((
void*)it->c_str(), textLen);
339 elementIDs[*it] = i++;
344 u32 attributeCount = (
u32)attributeNames.size();
345 writeBuffer.
Append(&attributeCount, 4);
346 for (it = attributeNames.begin(); it != attributeNames.end(); ++it)
348 u32 textLen = (
u32)it->length()+1;
349 writeBuffer.
Append(&textLen, 4);
350 writeBuffer.
Append((
void*)it->c_str(), textLen);
351 attributeIDs[*it] = i++;
354 OutputElement(xmlDocGetRootElement(doc), writeBuffer, elementIDs, attributeIDs);
const PSRETURN PSRETURN_Xeromyces_XMLParseError
#define UNUSED(param)
mark a function parameter as unused and avoid the corresponding compiler warning. ...
Path VfsPath
VFS path of the form "(dir/)*file?".
void Append(const void *data, size_t size)
PSRETURN Load(const PIVFS &vfs, const VfsPath &filename)
Load from an XML file (with invisible XMB caching).
const char * UnfinishedHeaderMagicStr
const PSRETURN PSRETURN_OK
Reads a file, then gives read-only access to the contents.
const char * HeaderMagicStr
void Overwrite(const void *data, size_t size, size_t offset)
#define ENSURE(expr)
ensure the expression <expr> evaluates to non-zero.
bool Initialise(const char *FileData)
bool ReadXMBFile(const PIVFS &vfs, const VfsPath &filename)
static bool g_XeromycesStarted
VfsPath ArchiveCachePath(const VfsPath &sourcePath)
Return the path of the archive cache for the given source file.
shared_ptr< u8 > Data() const
const String & string() const
bool GenerateCachedXMB(const PIVFS &vfs, const VfsPath &sourcePath, VfsPath &archiveCachePath)
Convert the given XML file into an XMB in the archive cache.
PSRETURN LoadString(const char *xml)
Load from an in-memory XML string (with no caching).
const PSRETURN PSRETURN_Xeromyces_XMLOpenFailed
const u8 * GetBuffer() const
Returns buffer of this file as a stream of bytes.
i64 Status
Error handling system.
static void Terminate()
Call once when shutting down the program, to unload libxml2.
shared_ptr< u8 > m_XMBBuffer
std::basic_string< utf16_t, utf16_traits > utf16string
PSRETURN Load(const PIVFS &vfs, const VfsPath &filename)
Returns either PSRETURN_OK or PSRETURN_CVFSFile_LoadFailed.
size_t GetBufferSize() const
JSBool error(JSContext *cx, uintN argc, jsval *vp)
void errorHandler(void *ctx, const char *msg,...)
Error handler for libxml2.
static void Startup()
Call once when initialising the program, to load libxml2.
static void FindNames(const xmlNodePtr node, std::set< std::string > &elementNames, std::set< std::string > &attributeNames)
Status TryLoadingCached(const VfsPath &sourcePath, const MD5 &initialHash, u32 version, VfsPath &loadPath)
Attempts to find a valid cached which can be loaded.
static void OutputElement(const xmlNodePtr node, WriteBuffer &writeBuffer, std::map< std::string, u32 > &elementIDs, std::map< std::string, u32 > &attributeIDs)
Helper class for systems that have an expensive cacheable conversion process when loading files...
PSRETURN ConvertFile(const PIVFS &vfs, const VfsPath &filename, const VfsPath &xmbPath)
static PSRETURN CreateXMB(const xmlDocPtr doc, WriteBuffer &writeBuffer)