00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018
00019
00020
00021
00022
00023
00024
00025
00026
00027
00028
00029 #include "tXmlParser.h"
00030 #include "tResourceManager.h"
00031 #include "tDirectories.h"
00032 #include "tConsole.h"
00033 #include "tArray.h"
00034
00035 #ifdef WIN32
00036 #define vsnprintf _vsnprintf
00037 #endif
00038
00039 #ifdef __MINGW32__
00040 #define xmlFree(x) free(x)
00041 #endif
00042
00043
00044 #define CALL_MEMBER_FN(object,ptrToMember) ((object)->*(ptrToMember))
00045
00046 namespace tXmlParserNamespace {
00047
00048
00049
00050 void cb_startDocument(void *userData) {
00051 CALL_MEMBER_FN((tXmlParser*)userData,&tXmlParser::cb_startDocument)();
00052 }
00053
00054 void cb_endDocument(void *userData) {
00055 CALL_MEMBER_FN((tXmlParser*)userData,&tXmlParser::cb_endDocument)();
00056 }
00057
00058 void cb_startElement(void *userData, const xmlChar *name, const xmlChar **attrs) {
00059 CALL_MEMBER_FN((tXmlParser*)userData,&tXmlParser::cb_startElement)(name, attrs);
00060 }
00061
00062 void cb_endElement(void *userData, const xmlChar *name) {
00063 CALL_MEMBER_FN((tXmlParser*)userData,&tXmlParser::cb_endElement)(name);
00064 }
00065
00066
00067
00068 void cb_warning(void *ctx , const char *msg, ...)
00069 {
00070 va_list args;
00071
00072 va_start(args, msg);
00073 fprintf(stdout, "SAX.warning: ");
00074 vfprintf(stdout, msg, args);
00075 va_end(args);
00076 }
00077
00078 void cb_error(void *ctx , const char *msg, ...)
00079 {
00080 va_list args;
00081
00082 va_start(args, msg);
00083 fprintf(stdout, "SAX.error: ");
00084 vfprintf(stdout, msg, args);
00085 va_end(args);
00086 }
00087
00088 void cb_fatalError(void *ctx , const char *msg, ...)
00089 {
00090 va_list args;
00091
00092 va_start(args, msg);
00093 fprintf(stdout, "SAX.fatalError: ");
00094 vfprintf(stdout, msg, args);
00095 va_end(args);
00096 }
00097
00098
00099
00100
00101
00102
00103
00104
00105
00106
00107
00108
00109
00110
00111
00112
00113
00114
00115
00116
00117
00118
00119
00120
00121
00122
00123
00124
00125
00126
00127 xmlSAXHandler aaSaxCallsback = {
00128 NULL,
00129 NULL,
00130 NULL,
00131 NULL,
00132 NULL,
00133 NULL,
00134 NULL,
00135 NULL,
00136 NULL,
00137 NULL,
00138 NULL,
00139 NULL,
00140 cb_startDocument,
00141 cb_endDocument,
00142 cb_startElement,
00143 cb_endElement,
00144 NULL,
00145 NULL,
00146 NULL,
00147 NULL,
00148 NULL,
00149 cb_warning,
00150 cb_error,
00151 cb_fatalError,
00152 NULL,
00153 NULL,
00154 NULL,
00155 1,
00156 NULL,
00157 NULL,
00158 NULL,
00159 NULL
00160 };
00161
00162 int myxmlInputReadFILE (void *context, char *buffer, int len) {
00163 return fread(buffer, 1, len, (FILE *)context);
00164 }
00165
00166 int myxmlInputCloseFILE (void *context) {
00167 return (fclose((FILE *)context) == 0) ? 0 : -1;
00168 }
00169
00170 #ifndef HAVE_LIBXML2_WO_PIBCREATE
00171 static bool sg_IgnoreRequest( tString const & URI )
00172 {
00173 #ifdef WIN32
00174 return URI.EndsWith( "../etc/catalog" );
00175 #else
00176 return URI.StartsWith( "file:///" ) && strstr( URI, "xml" ) && URI.EndsWith( "catalog" );
00177 #endif
00178 }
00179
00180 xmlParserInputBufferPtr myxmlParserInputBufferCreateFilenameFunc (const char *URI, xmlCharEncoding enc) {
00181 if ( sg_IgnoreRequest( tString( URI ) ) )
00182 {
00183 #ifdef DEBUG
00184 printf("Ignoring xml request for %s\n", URI);
00185 #endif
00186 return NULL;
00187 }
00188 #ifdef DEBUG
00189
00190 #endif
00191 FILE *f = tResourceManager::openResource(URI, NULL);
00192 if (f == NULL)
00193 return NULL;
00194 xmlParserInputBufferPtr ret = xmlAllocParserInputBuffer(enc);
00195 ret->context = f;
00196 ret->readcallback = myxmlInputReadFILE;
00197 ret->closecallback = myxmlInputCloseFILE;
00198 return ret;
00199 }
00200 #endif
00201
00202 void tXmlParser::cb_startDocument() {
00203 startDocument();
00204 }
00205
00206 void tXmlParser::startDocument() {
00207
00208 }
00209
00210 void tXmlParser::cb_endDocument() {
00211 endDocument();
00212 }
00213
00214 void tXmlParser::endDocument() {
00215
00216 }
00217
00218 void tXmlParser::cb_startElement(const xmlChar* name, const xmlChar** attrs) {
00219 tAttributeList attributes;
00220 if (attrs != NULL) {
00221 for (int i = 0; (attrs[i] != NULL); i++) {
00222 tString attributeName( (const char*) attrs[i] );
00223 tString attributeValue;
00224 i++;
00225
00226 if (attrs[i] != NULL) {
00227 attributeValue = tString( (const char*)attrs[i] );
00228 } else {
00229 attributeValue = tString();
00230 }
00231 attributes[attributeName] = attributeValue;
00232 }
00233 tString elementName((const char*)name);
00234 startElement(elementName, attributes );
00235 }
00236 }
00237
00238 void tXmlParser::startElement(tString &element, tAttributeList &attributes) {
00239
00240 }
00241
00242 tXmlParser::~tXmlParser() {
00243 if (m_Doc)
00244 {
00245 xmlFreeDoc(m_Doc);
00246 m_Doc=0;
00247 }
00248 }
00249
00250 void tXmlParser::cb_endElement(const xmlChar *name) {
00251 tString elementName((const char*)name);
00252 endElement(elementName);
00253 }
00254
00255 void tXmlParser::endElement(tString &element) {
00256
00257 }
00258
00259 bool tXmlParser::LoadWithoutParsing(const char* filename, const char* uri) {
00260 bool success=false;
00261 FILE* docfd;
00262
00263 docfd = tResourceManager::openResource(filename, uri);
00264 m_Filename = tResourceManager::locateResource(filename, uri);
00265
00266 if ( docfd )
00267 {
00268 success = ValidateXml(docfd, uri, filename);
00269 fclose(docfd);
00270 }
00271
00272 return success;
00273 }
00274
00275 bool tXmlParser::LoadWithParsing(const char* filename, const char *uri) {
00276 bool success=false;
00277 FILE* docfd;
00278
00279 if(!(docfd = tResourceManager::openResource(filename, uri))) {
00280 con << "Loading XML file '" << filename << "' failed!\n";
00281 return false;
00282 }
00283 m_Filename = tResourceManager::locateResource(filename, uri);
00284
00285 success = ValidateXml(docfd, uri, filename);
00286 fclose(docfd);
00287 if(success) {
00288 return Parse();
00289 } else {
00290 return false;
00291 }
00292 }
00293
00294 bool tXmlResource::LoadFile(const char* filename, const char* uri) {
00295 m_Filename = tResourceManager::locateResource(filename, uri);
00296 return LoadXmlFile(m_Filename, uri);
00297 }
00298
00299 bool tXmlParser::LoadFile(const char* filename, const char* uri) {
00300 return LoadXmlFile(filename, uri);
00301 }
00302
00303 bool tXmlParser::LoadXmlFile(const char* filename, const char* uri) {
00304 bool goOn;
00305
00306 FILE* docfd;
00307
00308 docfd = fopen(filename, "r");
00309
00310 goOn = ValidateXml(docfd, uri, filename);
00311
00312 if(goOn) {
00313 return Parse();
00314 } else {
00315 return false;
00316 }
00317 }
00318
00319 bool tXmlParser::Parse() {
00320 if(m_Mode == DOM) {
00321 return ParseDom();
00322 } else {
00323 return ParseSax();
00324 }
00325 }
00326
00327
00328 bool tXmlParser::ParseDom() {
00329 return true;
00330 }
00331
00332 bool tXmlParser::ParseSax() {
00333 if (xmlSAXUserParseFile(&aaSaxCallsback, this, m_Filename) < 0) {
00334 return false;
00335 } else
00336 return true;
00337 }
00338
00339 #ifndef DEDICATED
00340 static tString st_errorLeadIn("");
00341
00342 static void st_ErrorFunc( void * ctx,
00343 const char * msg,
00344 ... )
00345 {
00346
00347 static int maxlen = 100;
00348 tArray<char> buffer;
00349 bool retry = true;
00350 while ( retry )
00351 {
00352 buffer.SetLen( maxlen );
00353 va_list ap;
00354 va_start(ap, msg);
00355 retry = vsnprintf(&buffer[0], maxlen, msg, ap) >= maxlen;
00356 va_end(ap);
00357
00358 if ( retry )
00359 maxlen *= 2;
00360 }
00361 char * message = &buffer[0];
00362
00363
00364 if ( st_errorLeadIn.Len() > 2 )
00365 {
00366 con << st_errorLeadIn;
00367 #ifndef DEBUG
00368 std::cerr << st_errorLeadIn;
00369 #endif
00370 st_errorLeadIn = "";
00371 }
00372
00373 #ifndef DEBUG
00374 std::cerr << message;
00375 #endif
00376
00377 con << message;
00378 }
00379 #endif
00380
00381 bool tXmlParser::ValidateXml(FILE* docfd, const char* uri, const char* filepath)
00382 {
00383 #ifndef DEDICATED
00384
00385 xmlGenericErrorFunc errorFunc = &st_ErrorFunc;
00386 initGenericErrorDefaultFunc( &errorFunc );
00387 st_errorLeadIn = "XML validation error in ";
00388 st_errorLeadIn += filepath;
00389 st_errorLeadIn += ":\n\n";
00390 #endif
00391
00392 bool validated = false;
00393
00394 if (docfd == NULL) {
00395 printf("LoadAndValidateMapXML passed a NULL docfd (we should really trap this somewhere else!)\n");
00396 return false;
00397 }
00398
00399 #ifndef HAVE_LIBXML2_WO_PIBCREATE
00400
00401 xmlParserInputBufferCreateFilenameDefault(myxmlParserInputBufferCreateFilenameFunc);
00402 #endif
00403
00404 if (m_Doc)
00405 {
00406 xmlFreeDoc(m_Doc);
00407 m_Doc=0;
00408 }
00409
00410
00411 xmlParserCtxtPtr ctxt;
00412
00413 ctxt = xmlNewParserCtxt();
00414
00415 if (ctxt == 0) {
00416 fprintf(stderr, "Failed to allocate parser context\n");
00417 return false;
00418 }
00419
00420
00421 m_Doc = xmlCtxtReadIO(ctxt, myxmlInputReadFILE, 0, docfd,
00422 #if HAVE_LIBXML2_WO_PIBCREATE
00423 (const char *)tDirectories::Resource().GetReadPath("map-0.1.dtd")
00424
00425 #else
00426 uri
00427 #endif
00428 , NULL, XML_PARSE_DTDVALID);
00429
00430
00431
00432 if (m_Doc == NULL) {
00433 fprintf(stderr, "Failed to parse \n");
00434 } else {
00435
00436 if (ctxt->valid == 0) {
00437 fprintf(stderr, "Failed to validate \n");
00438 xmlFreeDoc(m_Doc);
00439 m_Doc=NULL;
00440 }
00441 else
00442 {
00443 validated = true;
00444 }
00445 }
00446
00447
00448 xmlFreeParserCtxt(ctxt);
00449
00450 #ifndef DEDICATED
00451
00452 initGenericErrorDefaultFunc( NULL );
00453 #endif
00454 return validated;
00455 }
00456
00457 bool tXmlResource::ValidateXml(FILE* docfd, const char* uri, const char* filepath) {
00458 bool validated = tXmlParser::ValidateXml(docfd, uri, filepath);
00459
00460
00461 if ( validated && filepath )
00462 {
00463 node root = GetRoot();
00464
00465 if (!root) {
00466 con << "Empty document\n";
00467 return false;
00468 } else if (root.IsOfType("Resource")) {
00469 m_Path = tResourcePath (
00470 root.GetProp("author"),
00471 root.GetProp("category"),
00472 root.GetProp("name"),
00473 root.GetProp("version"),
00474 root.GetProp("type"),
00475 tString("xml"),
00476 tString("")
00477 );
00478 tString rightFilepath( m_Path.Path() );
00479 tString pureFilepath( filepath );
00480 int pos;
00481 while((pos = pureFilepath.StrPos("//")) != -1) {
00482 pureFilepath.RemoveSubStr(pos, 1);
00483 }
00484 tResourcePath purepath(pureFilepath);
00485 if ( purepath != m_Path )
00486 {
00487 con << "\nWARNING: incorrect filepath. The resource wants to be at \"" << rightFilepath << "\", but was loaded from \"" << filepath << "\".\n\n";
00488 }
00489 }
00490 else {
00491 con << "Root node is not of type 'Resource' but '" << root.GetName() << "'.\n";
00492 return false;
00493 }
00494 }
00495
00496 return validated;
00497 }
00498
00499 tXmlParser::node tXmlResource::GetFileContents(void) {
00500 for(node cur = GetRoot().GetFirstChild(); cur; ++cur) {
00501 if(!cur.IsOfType("comment") && !cur.IsOfType("text")) {
00502 return cur;
00503 }
00504 }
00505 return 0;
00506 }
00507
00508 tXmlParser::node tXmlParser::GetRoot() {
00509 return node(xmlDocGetRootElement(m_Doc));
00510 }
00511
00513 tXmlParser::node::node(xmlNode *cur) : m_cur(cur) {
00514
00515 }
00516
00519 bool tXmlParser::node::IsOfType(CHAR const *name) const {
00520 tASSERT(m_cur);
00521 return(!xmlStrcmp(m_cur->name, reinterpret_cast<xmlChar const *>(name)));
00522 }
00523
00525 tString tXmlParser::node::GetName(void) const {
00526 tASSERT(m_cur);
00527 return tString(reinterpret_cast<const char *>(m_cur->name));
00528 }
00529
00532 bool tXmlParser::node::HasProp(CHAR const *prop) const {
00533 tASSERT(m_cur);
00534 return xmlHasProp(m_cur,
00535 reinterpret_cast<const xmlChar *>
00536 (prop)
00537 );
00538 }
00539
00543 tString tXmlParser::node::GetProp(CHAR const *prop) const {
00544 tASSERT(m_cur);
00545 xmlChar *val = xmlGetProp(m_cur,
00546 reinterpret_cast<const xmlChar *>
00547 (prop)
00548 );
00549 if(val == 0) {
00550 tERR_WARN(tString("Call for non- existent Attribute '") + tString(prop) + "' of element of type '" + GetName() + '"');
00551 st_Breakpoint();
00552 return tString();
00553 }
00554 tString ret(reinterpret_cast<const char *>(val));
00555 xmlFree(val);
00556 return(ret);
00557 }
00558
00562 bool tXmlParser::node::GetPropBool(CHAR const *prop) const {
00563 tString string(GetProp(prop));
00564 if (string.empty()) return false;
00565 switch(string[0]) {
00566 case 't': case 'T':
00567 case 'y': case 'Y':
00568 return true;
00569 default:
00570 if(string == "on") return true;
00571 int i;
00572 return string.Convert(i) && i;
00573 }
00574 }
00575
00577 tXmlParser::node &tXmlParser::node::operator++() {
00578 tASSERT(m_cur);
00579 m_cur=m_cur->next;
00580 return *this;
00581 }
00583 tXmlParser::node const tXmlParser::node::operator++(int) {
00584 tASSERT(m_cur);
00585 xmlNode *old = m_cur;
00586 m_cur=m_cur->next;
00587 return old;
00588 }
00589
00591 tXmlParser::node tXmlParser::node::GetFirstChild(void) const {
00592 tASSERT(m_cur);
00593 return m_cur->xmlChildrenNode;
00594 }
00595
00597 tXmlParser::node::operator bool() const {
00598 return(m_cur != 0);
00599 }
00600
00601 }
00602
00603 #ifdef _MSC_VER
00604 void tXmlParser::node::GetProp(CHAR const *prop, int &target) const {
00605 if(!(GetProp(prop).Convert(target))) {
00606 tERR_WARN( "Property '" + tString(prop) + "' of node of type '" + GetName() + "' is '" + GetProp(prop) + "' which isn't of type '" + typeid(int).name() + "' as needed.");
00607 }
00608 }
00609 void tXmlParser::node::GetProp(CHAR const *prop, REAL &target) const {
00610 if(!(GetProp(prop).Convert(target))) {
00611 tERR_WARN( "Property '" + tString(prop) + "' of node of type '" + GetName() + "' is '" + GetProp(prop) + "' which isn't of type '" + typeid(REAL).name() + "' as needed.");
00612 }
00613 }
00614 #endif
00615