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