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 #include "config.h"
00027
00028 #include <stdio.h>
00029 #include <stdlib.h>
00030 #include <stdarg.h>
00031
00032 #ifdef WIN32
00033 #define vsnprintf _vsnprintf
00034 #endif
00035
00036 #include "AISDatabaseParser.h"
00037 #include "util.h"
00038 #include "debug.h"
00039
00040 using namespace std;
00041
00042 static const not_used char *states[] =
00043 {
00044 "START",
00045 "FINISH",
00046 "AIS",
00047 "ENTRY",
00048 "PRIMARY",
00049 "ANCILLARY",
00050 "UNKNOWN",
00051 "ERROR"
00052 };
00053
00060
00064 void
00065 AISDatabaseParser::aisStartDocument(AISParserState *state)
00066 {
00067 state->state = PARSER_START;
00068 state->unknown_depth = 0;
00069 state->prev_state = PARSER_UNKNOWN;
00070 state->error_msg = "";
00071
00072 DBG2(cerr << "Parser state: " << states[state->state] << endl);
00073 }
00074
00077 void
00078 AISDatabaseParser::aisEndDocument(AISParserState *state)
00079 {
00080 DBG2(cerr << "Ending state == " << states[state->state] << endl);
00081
00082 if (state->unknown_depth != 0) {
00083 AISDatabaseParser::aisFatalError(state, "The document contained unbalanced tags.");
00084
00085 DBG(cerr << "unknown_depth != 0 (" << state->unknown_depth << ")"
00086 << endl);
00087 }
00088 }
00089
00098 void
00099 AISDatabaseParser::aisStartElement(AISParserState *state, const char *name,
00100 const char **attrs)
00101 {
00102 switch (state->state) {
00103 case PARSER_START:
00104 if (strcmp(name, "ais") != 0) {
00105 DBG(cerr << "Expecting ais. Got " << name << endl);
00106 }
00107 state->state = AIS;
00108 break;
00109
00110 case PARSER_FINISH:
00111 break;
00112
00113 case AIS:
00114 if (strcmp(name, "entry") == 0) {
00115 state->prev_state = state->state;
00116 state->state = ENTRY;
00117 }
00118 else {
00119 state->prev_state = state->state;
00120 state->state = PARSER_UNKNOWN;
00121 state->unknown_depth++;
00122 }
00123 break;
00124
00125 case ENTRY:
00126 if (strcmp(name, "primary") == 0) {
00127 state->prev_state = state->state;
00128 state->state = PRIMARY;
00129
00130 if (attrs) {
00131 if (strcmp(attrs[0], "url") == 0) {
00132 state->regexp = false;
00133 state->primary = attrs[1];
00134 }
00135 else if (strcmp(attrs[0], "regexp") == 0) {
00136 state->regexp = true;
00137 state->primary = attrs[1];
00138 }
00139 }
00140 else {
00141 AISDatabaseParser::aisFatalError(state, "Required attribute 'url' or 'regexp' missing from element 'primary'.");
00142 break;
00143 }
00144 }
00145 else if (strcmp(name, "ancillary") == 0) {
00146 state->prev_state = state->state;
00147 state->state = ANCILLARY;
00148
00149 string url = "";
00150 string rule = "overwrite";
00151 for (int i = 0; attrs && attrs[i] != 0; i = i + 2) {
00152 if (strcmp(attrs[i], "url") == 0)
00153 url = attrs[i+1];
00154 else if (strcmp(attrs[i], "rule") == 0)
00155 rule = attrs[i+1];
00156 }
00157
00158
00159
00160 if (url == "") {
00161 AISDatabaseParser::aisFatalError(state, "Required attribute 'url' missing from element 'ancillary'.");
00162 break;
00163 }
00164
00165 if (rule != "overwrite" && rule != "replace" && rule != "fallback") {
00166 string msg = string("Optional attribute 'rule' in element 'ancillary' has a bad value: ") + rule + "\nIt should be one of 'overwrite', 'replace' or 'fallback'.";
00167 AISDatabaseParser::aisFatalError(state, msg.c_str());
00168 break;
00169 }
00170
00171 Resource r(url, rule);
00172 state->rv.push_back(r);
00173 }
00174 else {
00175 state->prev_state = state->state;
00176 state->state = PARSER_UNKNOWN;
00177 state->unknown_depth++;
00178 }
00179 break;
00180
00181 case PRIMARY:
00182 break;
00183
00184 case ANCILLARY:
00185 break;
00186
00187 case PARSER_UNKNOWN:
00188 state->unknown_depth++;
00189 break;
00190
00191 case PARSER_ERROR:
00192 break;
00193 }
00194
00195 DBG2(cerr << "Start element " << name << " (state "
00196 << states[state->state] << ")" << endl);
00197 }
00198
00203 void
00204 AISDatabaseParser::aisEndElement(AISParserState *state, const char *)
00205 {
00206 DBG2(cerr << "End element " << name << " (state " << states[state->state]
00207 << ")" << endl);
00208
00209 switch (state->state) {
00210 case AIS:
00211 state->prev_state = state->state;
00212 state->state = PARSER_FINISH;
00213 break;
00214
00215 case ENTRY:
00216 state->prev_state = state->state;
00217 state->state = AIS;
00218
00219
00220 if (state->regexp)
00221 state->ais->add_regexp_resource(state->primary, state->rv);
00222 else
00223 state->ais->add_url_resource(state->primary, state->rv);
00224
00225
00226 state->rv.erase(state->rv.begin(), state->rv.end());
00227 break;
00228
00229 case PRIMARY:
00230 state->prev_state = state->state;
00231 state->state = ENTRY;
00232 break;
00233
00234 case ANCILLARY:
00235 state->prev_state = state->state;
00236 state->state = ENTRY;
00237 break;
00238
00239 case PARSER_UNKNOWN:
00240
00241 state->unknown_depth--;
00242 break;
00243
00244 case PARSER_ERROR:
00245 break;
00246
00247 default:
00248 break;
00249 }
00250 }
00251
00255 xmlEntityPtr
00256 AISDatabaseParser::aisGetEntity(AISParserState *, const xmlChar *name)
00257 {
00258 return xmlGetPredefinedEntity(name);
00259 }
00260
00265 void
00266 AISDatabaseParser::aisWarning(AISParserState *state, const char *msg, ...)
00267 {
00268 va_list args;
00269
00270 state->state = PARSER_ERROR;
00271
00272 va_start(args, msg);
00273 char str[1024];
00274 vsnprintf(str, 1024, msg, args);
00275 va_end(args);
00276
00277 #ifdef LIBXML2_6_16
00278
00279 int line = xmlSAX2GetLineNumber(state->ctxt);
00280 #else
00281 int line = getLineNumber(state->ctxt);
00282 #endif
00283 state->error_msg += "At line: " + long_to_string(line) + ": ";
00284 state->error_msg += string(str) + string("\n");
00285 }
00286
00291 void
00292 AISDatabaseParser::aisError(AISParserState *state, const char *msg, ...)
00293 {
00294 va_list args;
00295
00296 state->state = PARSER_ERROR;
00297
00298 va_start(args, msg);
00299 char str[1024];
00300 vsnprintf(str, 1024, msg, args);
00301 va_end(args);
00302
00303 #ifdef LIBXML2_6_16
00304
00305 int line = xmlSAX2GetLineNumber(state->ctxt);
00306 #else
00307 int line = getLineNumber(state->ctxt);
00308 #endif
00309 state->error_msg += "At line: " + long_to_string(line) + ": ";
00310 state->error_msg += string(str) + string("\n");
00311 }
00312
00316 void
00317 AISDatabaseParser::aisFatalError(AISParserState *state, const char *msg, ...)
00318 {
00319 va_list args;
00320
00321 state->state = PARSER_ERROR;
00322
00323 va_start(args, msg);
00324 char str[1024];
00325 vsnprintf(str, 1024, msg, args);
00326 va_end(args);
00327
00328 #ifdef LIBXML2_6_16
00329
00330 int line = xmlSAX2GetLineNumber(state->ctxt);
00331 #else
00332 int line = getLineNumber(state->ctxt);
00333 #endif
00334 state->error_msg += "At line: " + long_to_string(line) + ": ";
00335 state->error_msg += string(str) + string("\n");
00336 }
00337
00339
00342 static xmlSAXHandler aisSAXParser =
00343 {
00344 0,
00345 0,
00346 0,
00347 0,
00348 0,
00349 (getEntitySAXFunc)AISDatabaseParser::aisGetEntity,
00350 0,
00351 0,
00352 0,
00353 0,
00354 0,
00355 0,
00356 (startDocumentSAXFunc)AISDatabaseParser::aisStartDocument,
00357 (endDocumentSAXFunc)AISDatabaseParser::aisEndDocument,
00358 (startElementSAXFunc)AISDatabaseParser::aisStartElement,
00359 (endElementSAXFunc)AISDatabaseParser::aisEndElement,
00360 0,
00361 0,
00362 0,
00363 0,
00364 0,
00365 (warningSAXFunc)AISDatabaseParser::aisWarning,
00366 (errorSAXFunc)AISDatabaseParser::aisError,
00367 (fatalErrorSAXFunc)AISDatabaseParser::aisFatalError,
00368 #ifdef LIBXML2_5_10
00369 0,
00370 0,
00371 0,
00372 0,
00373 #endif
00374 #ifdef LIBXML2_6_16
00375 0,
00376 0,
00377 0,
00378 0
00379 #endif
00380 };
00381
00388 void
00389 AISDatabaseParser::intern(const string &database, AISResources *ais)
00390 {
00391 xmlParserCtxtPtr ctxt;
00392 AISParserState state;
00393
00394 ctxt = xmlCreateFileParserCtxt(database.c_str());
00395 if (!ctxt)
00396 return;
00397
00398 state.ais = ais;
00399 state.ctxt = ctxt;
00400
00401 ctxt->sax = &aisSAXParser;
00402 ctxt->userData = &state;
00403 ctxt->validate = true;
00404
00405 xmlParseDocument(ctxt);
00406
00407
00408 if (!ctxt->wellFormed) {
00409 ctxt->sax = NULL;
00410 xmlFreeParserCtxt(ctxt);
00411 throw AISDatabaseReadFailed(string("\nThe database is not a well formed XML document.\n") + state.error_msg);
00412 }
00413
00414 if (!ctxt->valid) {
00415 ctxt->sax = NULL;
00416 xmlFreeParserCtxt(ctxt);
00417 throw AISDatabaseReadFailed(string("\nThe database is not a valid document.\n") + state.error_msg);
00418 }
00419
00420 if (state.state == PARSER_ERROR) {
00421 ctxt->sax = NULL;
00422 xmlFreeParserCtxt(ctxt);
00423 throw AISDatabaseReadFailed(string("\nError parsing AIS resources.\n") + state.error_msg);
00424 }
00425
00426 ctxt->sax = NULL;
00427 xmlFreeParserCtxt(ctxt);
00428 }