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