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
00208
00209
00210 void
00211 AISDatabaseParser::aisEndElement(AISParserState *state, const char *)
00212 {
00213 DBG2(cerr << "End element " << name << " (state " << states[state->state]
00214 << ")" << endl);
00215
00216 switch (state->state) {
00217 case AIS:
00218 state->prev_state = state->state;
00219 state->state = PARSER_FINISH;
00220 break;
00221
00222 case ENTRY:
00223 state->prev_state = state->state;
00224 state->state = AIS;
00225
00226
00227 if (state->regexp)
00228 state->ais->add_regexp_resource(state->primary, state->rv);
00229 else
00230 state->ais->add_url_resource(state->primary, state->rv);
00231
00232
00233 state->rv.erase(state->rv.begin(), state->rv.end());
00234 break;
00235
00236 case PRIMARY:
00237 state->prev_state = state->state;
00238 state->state = ENTRY;
00239 break;
00240
00241 case ANCILLARY:
00242 state->prev_state = state->state;
00243 state->state = ENTRY;
00244 break;
00245
00246 case PARSER_UNKNOWN:
00247
00248 state->unknown_depth--;
00249 break;
00250
00251 case PARSER_ERROR:
00252 break;
00253
00254 default:
00255 break;
00256 }
00257 }
00258
00262 xmlEntityPtr
00263 AISDatabaseParser::aisGetEntity(AISParserState *, const xmlChar *name)
00264 {
00265 return xmlGetPredefinedEntity(name);
00266 }
00267
00272 void
00273 AISDatabaseParser::aisWarning(AISParserState *state, const char *msg, ...)
00274 {
00275 va_list args;
00276
00277 state->state = PARSER_ERROR;
00278
00279 va_start(args, msg);
00280 char str[1024];
00281 vsnprintf(str, 1024, msg, args);
00282 va_end(args);
00283
00284 #ifdef LIBXML2_6_16
00285
00286 int line = xmlSAX2GetLineNumber(state->ctxt);
00287 #else
00288 int line = getLineNumber(state->ctxt);
00289 #endif
00290 state->error_msg += "At line: " + long_to_string(line) + ": ";
00291 state->error_msg += string(str) + string("\n");
00292 }
00293
00298 void
00299 AISDatabaseParser::aisError(AISParserState *state, const char *msg, ...)
00300 {
00301 va_list args;
00302
00303 state->state = PARSER_ERROR;
00304
00305 va_start(args, msg);
00306 char str[1024];
00307 vsnprintf(str, 1024, msg, args);
00308 va_end(args);
00309
00310 #ifdef LIBXML2_6_16
00311
00312 int line = xmlSAX2GetLineNumber(state->ctxt);
00313 #else
00314 int line = getLineNumber(state->ctxt);
00315 #endif
00316 state->error_msg += "At line: " + long_to_string(line) + ": ";
00317 state->error_msg += string(str) + string("\n");
00318 }
00319
00323 void
00324 AISDatabaseParser::aisFatalError(AISParserState *state, const char *msg, ...)
00325 {
00326 va_list args;
00327
00328 state->state = PARSER_ERROR;
00329
00330 va_start(args, msg);
00331 char str[1024];
00332 vsnprintf(str, 1024, msg, args);
00333 va_end(args);
00334
00335 #ifdef LIBXML2_6_16
00336
00337 int line = xmlSAX2GetLineNumber(state->ctxt);
00338 #else
00339 int line = getLineNumber(state->ctxt);
00340 #endif
00341 state->error_msg += "At line: " + long_to_string(line) + ": ";
00342 state->error_msg += string(str) + string("\n");
00343 }
00344
00346
00349 static xmlSAXHandler aisSAXParser =
00350 {
00351 0,
00352 0,
00353 0,
00354 0,
00355 0,
00356 (getEntitySAXFunc)AISDatabaseParser::aisGetEntity,
00357 0,
00358 0,
00359 0,
00360 0,
00361 0,
00362 0,
00363 (startDocumentSAXFunc)AISDatabaseParser::aisStartDocument,
00364 (endDocumentSAXFunc)AISDatabaseParser::aisEndDocument,
00365 (startElementSAXFunc)AISDatabaseParser::aisStartElement,
00366 (endElementSAXFunc)AISDatabaseParser::aisEndElement,
00367 0,
00368 0,
00369 0,
00370 0,
00371 0,
00372 (warningSAXFunc)AISDatabaseParser::aisWarning,
00373 (errorSAXFunc)AISDatabaseParser::aisError,
00374 (fatalErrorSAXFunc)AISDatabaseParser::aisFatalError,
00375 #ifdef LIBXML2_5_10
00376 0,
00377 0,
00378 0,
00379 0,
00380 #endif
00381 #ifdef LIBXML2_6_16
00382 0,
00383 0,
00384 0,
00385 0
00386 #endif
00387 };
00388
00395 void
00396 AISDatabaseParser::intern(const string &database, AISResources *ais)
00397 {
00398 xmlParserCtxtPtr ctxt;
00399 AISParserState state;
00400
00401 ctxt = xmlCreateFileParserCtxt(database.c_str());
00402 if (!ctxt)
00403 return;
00404
00405 state.ais = ais;
00406 state.ctxt = ctxt;
00407
00408 ctxt->sax = &aisSAXParser;
00409 ctxt->userData = &state;
00410 ctxt->validate = true;
00411
00412 xmlParseDocument(ctxt);
00413
00414
00415 if (!ctxt->wellFormed) {
00416 ctxt->sax = NULL;
00417 xmlFreeParserCtxt(ctxt);
00418 throw AISDatabaseReadFailed(string("\nThe database is not a well formed XML document.\n") + state.error_msg);
00419 }
00420
00421 if (!ctxt->valid) {
00422 ctxt->sax = NULL;
00423 xmlFreeParserCtxt(ctxt);
00424 throw AISDatabaseReadFailed(string("\nThe database is not a valid document.\n") + state.error_msg);
00425 }
00426
00427 if (state.state == PARSER_ERROR) {
00428 ctxt->sax = NULL;
00429 xmlFreeParserCtxt(ctxt);
00430 throw AISDatabaseReadFailed(string("\nError parsing AIS resources.\n") + state.error_msg);
00431 }
00432
00433 ctxt->sax = NULL;
00434 xmlFreeParserCtxt(ctxt);
00435 }
00436
00437 }