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 #include <base/SimpleXMLSerializer>
00026
00027 #include <base/Serializable>
00028
00029 using base::SimpleXMLSerializer;
00030 using base::Serializer;
00031 using base::Serializable;
00032 using base::Referenced;
00033 using base::VFile;
00034 using base::ref;
00035
00036 using std::iostream;
00037 using std::istream;
00038 using std::ostream;
00039
00040
00041 #ifdef DEBUG
00042
00043
00044
00045
00046 #endif
00047
00048
00049 SimpleXMLSerializer::SimpleXMLSerializer(SerializerType type, ref<VFile> archive)
00050 : Serializer(type,archive),
00051 istream(output?0:&archive->iostream(iostream::in)),
00052 ostream(output?&archive->iostream(iostream::out):0),
00053 indent(0)
00054 {
00055 serializeHeader(archive->name().str());
00056
00057 #ifdef SDEBUG
00058 Debugln(Ser,"Constructed:" << (isOutput()?String("Output"):String("Input")) );
00059 #endif
00060 }
00061
00062 SimpleXMLSerializer::SimpleXMLSerializer(SerializerType type, std::ios& stream)
00063 : Serializer(type,stream),
00064 indent(0)
00065 {
00066 Assert(output?instanceof(stream, std::ostream)
00067 :instanceof(stream, std::istream));
00068 if (output)
00069 ostream = dynamic_cast<std::ostream*>(&stream);
00070 else
00071 istream = dynamic_cast<std::istream*>(&stream);
00072
00073 serializeHeader(String("stream"));
00074
00075 #ifdef SDEBUG
00076 Debugln(Ser,"Constructed:" << (isOutput()?String("Output"):String("Input")) );
00077 #endif
00078 }
00079
00080
00081 SimpleXMLSerializer::~SimpleXMLSerializer()
00082 {
00083 if (aborted) {
00084 if (output) flush();
00085 return;
00086 }
00087
00088 if (output) {
00089 indent--;
00090 (*ostream) << "</serialization>" << std::endl;
00091 flush();
00092 }
00093 else {
00094 readEndTag("serialization");
00095 }
00096 }
00097
00098
00099 bool SimpleXMLSerializer::followReferences(bool follow)
00100 {
00101 #ifdef SDEBUG
00102 Debugln(Ser,"Reference following " << (follow?String("enabled"):String("disabled")));
00103 #endif
00104 return Serializer::followReferences(follow);
00105 }
00106
00107
00108 Serializer& SimpleXMLSerializer::serialize(char& c, const String& memberName)
00109 {
00110 String tagName(memberName.empty()?"char":memberName);
00111 if (output) {
00112 try {
00113 (*ostream) << String(indent,' ') << "<" << tagName << ">" << c << "</" << tagName << ">" << std::endl;
00114 } catch (std::exception& e) { abort(e.what()); }
00115 }
00116 else {
00117 TagData tag;
00118 if (readStartTag(tag)) {
00119 if ((tag.name != tagName) && (tag.name != "char"))
00120 abort("expected element "+tagName+" but got "+tag.name);
00121 try {
00122 (*istream) >> c;
00123 } catch (std::exception& e) { abort(e.what()); }
00124 readEndTag(tag.name);
00125 }
00126 }
00127
00128 #ifdef SDEBUG
00129
00130 #endif
00131 return *this;
00132 }
00133
00134 Serializer& SimpleXMLSerializer::serialize(Byte& b, const String& memberName)
00135 {
00136 String tagName(memberName.empty()?"Byte":memberName);
00137 if (output) {
00138 try {
00139 (*ostream) << String(indent,' ') << "<" << tagName << ">" << Int(b) << "</" << tagName << ">" << std::endl;
00140 } catch (std::exception& e) { abort(e.what()); }
00141 }
00142 else {
00143 TagData tag;
00144 if (readStartTag(tag)) {
00145 if (tag.name != tagName)
00146 abort("expected element "+tagName+" but got "+tag.name);
00147 Int i;
00148 try {
00149 (*istream) >> i;
00150 } catch (std::exception& e) { abort(e.what()); }
00151 b = Byte(i);
00152 readEndTag(tag.name);
00153 }
00154 }
00155
00156 #ifdef SDEBUG
00157 Debugln(Ser,"serialized Byte:" << b);
00158 #endif
00159 return *this;
00160 }
00161
00162 Serializer& SimpleXMLSerializer::serialize(bool& b, const String& memberName)
00163 {
00164 String tagName(memberName.empty()?"bool":memberName);
00165 if (output) {
00166 try {
00167 (*ostream) << std::boolalpha;
00168 (*ostream) << String(indent,' ') << "<" << tagName << ">" << b << "</" << tagName << ">" << std::endl;
00169 } catch (std::exception& e) { abort(e.what()); }
00170 }
00171 else {
00172 TagData tag;
00173 if (readStartTag(tag)) {
00174 if (tag.name != tagName)
00175 abort("expected element "+tagName+" but got "+tag.name);
00176 try {
00177 (*istream) >> std::boolalpha;
00178 (*istream) >> b;
00179 } catch (std::exception& e) { abort(e.what()); }
00180 readEndTag(tag.name);
00181 }
00182 }
00183
00184 #ifdef SDEBUG
00185 Debugln(Ser,"serialized bool:" << b);
00186 #endif
00187 return *this;
00188 }
00189
00190 Serializer& SimpleXMLSerializer::serialize(SInt& i, const String& memberName)
00191 {
00192 String tagName(memberName.empty()?"SInt":memberName);
00193 if (output) {
00194 try {
00195 (*ostream) << String(indent,' ') << "<" << tagName << ">" << base::intToString(i) << "</" << tagName << ">" << std::endl;
00196 } catch (std::exception& e) { abort(e.what()); }
00197 }
00198 else {
00199 TagData tag;
00200 if (readStartTag(tag)) {
00201 if (tag.name != tagName)
00202 abort("expected element "+tagName+" but got "+tag.name);
00203 try {
00204 (*istream) >> i;
00205 } catch (std::exception& e) { abort(e.what()); }
00206 readEndTag(tag.name);
00207 }
00208 }
00209
00210 #ifdef SDEBUG
00211 Debugln(Ser,"serialized SInt:" << i);
00212 #endif
00213 return *this;
00214 }
00215
00216 Serializer& SimpleXMLSerializer::serialize(Int& i, const String& memberName)
00217 {
00218 String tagName(memberName.empty()?"Int":memberName);
00219 if (output) {
00220 try {
00221 (*ostream) << String(indent,' ') << "<" << tagName << ">" << base::intToString(i) << "</" << tagName << ">" << std::endl;
00222 } catch (std::exception& e) { abort(e.what()); }
00223 }
00224 else {
00225 TagData tag;
00226 if (readStartTag(tag)) {
00227 if (tag.name != tagName)
00228 abort("expected element "+tagName+" but got "+tag.name);
00229 try {
00230 (*istream) >> i;
00231 } catch (std::exception& e) { abort(e.what()); }
00232 readEndTag(tag.name);
00233 }
00234 }
00235 #ifdef SDEBUG
00236 Debugln(Ser,"serialized Int:" << i);
00237 #endif
00238 return *this;
00239 }
00240
00241 Serializer& SimpleXMLSerializer::serialize(LInt& i, const String& memberName)
00242 {
00243 String tagName(memberName.empty()?"LInt":memberName);
00244 if (output) {
00245 try {
00246 (*ostream) << String(indent,' ') << "<" << tagName << ">" << base::intToString(i) << "</" << tagName << ">" << std::endl;
00247 } catch (std::exception& e) { abort(e.what()); }
00248 }
00249 else {
00250 TagData tag;
00251 if (readStartTag(tag)) {
00252 if (tag.name != tagName)
00253 abort("expected element "+tagName+" but got "+tag.name);
00254 try {
00255 (*istream) >> i;
00256 } catch (std::exception& e) { abort(e.what()); }
00257 readEndTag(tag.name);
00258 }
00259 }
00260
00261 #ifdef SDEBUG
00262 Debugln(Ser,"serialized LInt:" << i);
00263 #endif
00264 return *this;
00265 }
00266
00267 Serializer& SimpleXMLSerializer::serialize(String& s, const String& memberName)
00268 {
00269 String tagName(memberName.empty()?"string":memberName);
00270 if (output) {
00271 try {
00272 (*ostream) << String(indent,' ') << "<" << tagName << ">" << s << "</" << tagName << ">" << std::endl;
00273 } catch (std::exception& e) { abort(e.what()); }
00274 }
00275 else {
00276 TagData tag;
00277 if (readStartTag(tag)) {
00278 if (tag.name != tagName)
00279 abort("expected element "+tagName+" but got "+tag.name);
00280 try {
00281 s.clear();
00282
00283 char p = nextChar();
00284 while (p != '<') { s += p; p = nextChar(); }
00285 istream->putback(p);
00286 } catch (std::exception& e) { abort(e.what()); }
00287 readEndTag(tag.name);
00288 }
00289 }
00290
00291 #ifdef SDEBUG
00292 Debugln(Ser,"serialized String:" << s);
00293 #endif
00294 return *this;
00295 }
00296
00297 Serializer& SimpleXMLSerializer::serialize(Real& r, const String& memberName)
00298 {
00299 String tagName(memberName.empty()?"real":memberName);
00300 if (output) {
00301 try {
00302 (*ostream) << String(indent,' ') << "<" << tagName << ">" << base::realToString(r) << "</" << tagName << ">" << std::endl;
00303 } catch (std::exception& e) { abort(e.what()); }
00304 }
00305 else {
00306 TagData tag;
00307 if (readStartTag(tag)) {
00308 if (tag.name != tagName)
00309 abort("expected element "+tagName+" but got "+tag.name);
00310 try {
00311 (*istream) >> r;
00312 } catch (std::exception& e) { abort(e.what()); }
00313 readEndTag(tag.name);
00314 }
00315 }
00316
00317 #ifdef SDEBUG
00318 Debugln(Ser,"serialized Real:" << r);
00319 #endif
00320 return *this;
00321 }
00322
00323 void SimpleXMLSerializer::flush()
00324 {
00325 if (output)
00326 (*ostream) << std::flush;
00327 }
00328
00329
00330
00331
00332 Serializer::TypeModifier SimpleXMLSerializer::preSerializeObject(String& typeName, TypeModifier typeModifier, const String& memberName, bool forceTypeSerialization)
00333 {
00334 String tagName(memberName.empty()?"object":memberName);
00335 String typeString;
00336
00337 if (output) {
00338
00339 try {
00340 typeString = base::demangleTypeidName(typeName);
00341 } catch (std::exception& e) {
00342 abort(String("error demangling typeName:")+typeName+" for element:" +tagName+" - "+e.what());
00343 }
00344
00345 String modifierString;
00346 if (typeModifier == ReferencedObjectType)
00347 modifierString = "ro";
00348 else if (typeModifier == ObjectReferenceType)
00349 modifierString = "r";
00350
00351 if (!modifierString.empty())
00352 modifierString = String(" ref=\""+modifierString+"\"");
00353
00354 (*ostream) << String(indent,' ') << "<" << tagName << " type=\"" << typeString << "\"" << modifierString << ">" << std::endl;
00355 indent++;
00356
00357 return typeModifier;
00358 }
00359 else {
00360 TagData tag;
00361
00362 if (readStartTag(tag)) {
00363
00364 if (tag.name != tagName)
00365 abort("expected element "+tagName+" but got "+tag.name);
00366
00367 if (!typeName.empty()) {
00368 try {
00369 typeString = base::demangleTypeidName(typeName);
00370 } catch (std::exception& e) {
00371 abort(String("error demangling typeName:")+typeName+" for element:" +tagName+" - "+e.what());
00372 }
00373
00374 if (tag.attribute("type") != typeString)
00375 abort("expected object of type "+typeString+" but got "+tag.attribute("type"));
00376 }
00377 else
00378 typeName = tag.attribute("type");
00379
00380 String modifierString(tag.attribute("ref"));
00381 TypeModifier readTypeModifier = ObjectType;
00382
00383 if (modifierString == "r")
00384 readTypeModifier = ObjectReferenceType;
00385 else if (modifierString == "ro")
00386 readTypeModifier = ReferencedObjectType;
00387
00388 if (typeModifier != UnknownType)
00389 if (typeModifier != readTypeModifier)
00390 abort("got difference object reference type modifier than expected");
00391
00392 return readTypeModifier;
00393 }
00394 else
00395 return UnknownType;
00396 }
00397 }
00398
00399
00400 void SimpleXMLSerializer::postSerializeObject(const String& memberName)
00401 {
00402 String tagName(memberName.empty()?"object":memberName);
00403
00404 if (output) {
00405 indent--;
00406 (*ostream) << String(indent,' ') << "</" << tagName << ">" << std::endl;
00407 }
00408 else {
00409 readEndTag(tagName);
00410 }
00411 }
00412
00413
00414 void SimpleXMLSerializer::serializeComment(const String& comment)
00415 {
00416 if (output) {
00417 (*ostream) << String(indent,' ') << "<!-- " << comment << " -->" << std::endl;
00418 }
00419 }
00420
00421
00422 Serializer& SimpleXMLSerializer::hint(Int h)
00423 {
00424 if (h == Indent) indent++;
00425 else if (h == Unindent) indent--;
00426 return *this;
00427 }
00428
00429
00430 bool SimpleXMLSerializer::serializeHeader(const String& target)
00431 {
00432
00433 if (output) {
00434 try {
00435 (*ostream) << "<?xml version =\"1.0\" encoding=\"UTF-8\" standalone=\"yes\" ?>" << std::endl;
00436 (*ostream) << "<serialization type=\"base::SimpleXMLSerializer\" version=\"1.0\" target=\"" << target << "\">" << std::endl;
00437 indent++;
00438 } catch (std::exception& e) { abort(e.what()); }
00439 }
00440 else {
00441 TagData tag;
00442 bool xmlTagOK = readStartTag(tag);
00443 if (xmlTagOK) {
00444 if (tag.name != "?xml") {
00445 xmlTagOK = false;
00446 }
00447 }
00448
00449 if (!xmlTagOK)
00450 abort("Bad XML header");
00451
00452 bool rootElementOK = readStartTag(tag);
00453 if (rootElementOK) {
00454 if (tag.name != "serialization") {
00455 rootElementOK = false;
00456 }
00457 else {
00458 if (tag.attribute("type") != "base::SimpleXMLSerializer")
00459 abort("Serialization format not supported");
00460
00461 if (tag.attribute("version") != "1.0")
00462 abort("Only serialization format version 1.0 is supported");
00463 }
00464 }
00465
00466 if (!rootElementOK)
00467 abort("This XML format or version not is supported");
00468
00469 }
00470
00471 return true;
00472 }
00473
00474
00475 bool SimpleXMLSerializer::readStartTag(TagData& tag)
00476 {
00477 Assert(!output);
00478
00479 tag.name.clear();
00480 tag.attributeNames.clear();
00481 tag.attributeValues.clear();
00482
00483 (*istream) >> std::noskipws;
00484
00485 char p = nextNWSChar();
00486 if (p == '<') {
00487
00488 p = nextChar();
00489 tag.name += p;
00490 if (p=='!') {
00491 tag.name += p;
00492 do { p = nextChar(); tag.name += p; } while (p==' ');
00493 if (p=='-') {
00494 tag.name += p;
00495 p = nextChar();
00496 if (p=='-') {
00497 tag.name.clear();
00498
00499 bool endcomment = false;
00500 do {
00501 p = nextChar();
00502 if (p == '-') {
00503 p = nextChar();
00504 if (p == '-') {
00505 p = nextChar();
00506 if (p == '>') {
00507 endcomment = true;
00508
00509 p = nextNWSChar();
00510 if (p!='<') {
00511 istream->putback(p);
00512 return false;
00513 }
00514 }
00515 }
00516 }
00517 } while (!endcomment);
00518 }
00519 }
00520 }
00521
00522
00523 p = nextChar();
00524 while ((p != '>') && (p != ' ')) {
00525 tag.name += p;
00526 p = nextChar();
00527 }
00528
00529
00530 if (p!='>') {
00531 p = nextNWSChar();
00532 if (p!='>')
00533 istream->putback(p);
00534 }
00535
00536 if (p!='>') {
00537 bool tagclose=false;
00538 do {
00539 String attribName;
00540 p = nextNWSChar();
00541 while ((p!=' ') && (p!='=')) { attribName += p; p = nextChar(); }
00542 if (p!='=') p = nextNWSChar();
00543 if (p!='=') abort("'=' expected after attribute name:"+attribName+" of element:"+tag.name);
00544 p = nextNWSChar();
00545 if (p!='\"') abort("attribute value must be quoted (in attribute name:"+attribName+" of element:"+tag.name+")");
00546
00547 String attribValue;
00548 p = nextChar();
00549 while (p!='\"') { attribValue += p; p = nextChar(); }
00550 tag.attributeNames.push_back(attribName);
00551 tag.attributeValues.push_back(attribValue);
00552
00553 p = nextNWSChar();
00554
00555 if ((tag.name[0]=='?') && (p=='?'))
00556 p = nextChar();
00557
00558 if (p == '>') tagclose=true;
00559
00560 if (p == '<')
00561 abort("unexpected '<' - element "+tag.name+" not terminated?");
00562
00563 if (!tagclose) istream->putback(p);
00564
00565 } while (!tagclose);
00566
00567 }
00568
00569 return true;
00570 }
00571
00572 istream->putback(p);
00573 return false;
00574
00575 }
00576
00577
00578 bool SimpleXMLSerializer::readEndTag(const String& tagName)
00579 {
00580 Assert(!output);
00581
00582 (*istream) >> std::noskipws;
00583
00584 String name;
00585 char p = nextNWSChar();
00586 if (p == '<') {
00587
00588 p = nextChar();
00589 name += p;
00590 if (p=='!') {
00591 name += p;
00592 do { p = nextChar(); name += p; } while (p==' ');
00593 if (p=='-') {
00594 name += p;
00595 p = nextChar();
00596 if (p=='-') {
00597 name.clear();
00598
00599 bool endcomment = false;
00600 do {
00601 p = nextChar();
00602 if (p == '-') {
00603 p = nextChar();
00604 if (p == '-') {
00605 p = nextChar();
00606 if (p == '>') {
00607 endcomment = true;
00608
00609 p = nextNWSChar();
00610 if (p!='<') {
00611 istream->putback(p);
00612 return false;
00613 }
00614 }
00615 }
00616 }
00617 } while (!endcomment);
00618 }
00619 }
00620 }
00621
00622
00623 p = nextChar();
00624 while ((p != '>') && (p != ' ')) {
00625 name += p;
00626 p = nextChar();
00627 }
00628
00629
00630
00631 if (p!='>')
00632 p = nextNWSChar();
00633
00634 if (p!='>')
00635 abort("expected '>' to close element:<"+name);
00636
00637 if (!tagName.empty())
00638 if (name != String("/"+tagName))
00639 abort("expected closing element </"+tagName+"> but read <"+name+">");
00640
00641 return true;
00642 }
00643
00644 return false;
00645 }
00646