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/Externalizer>
00026
00027 #include <base/Application>
00028 #include <base/Math>
00029 #include <base/Externalizable>
00030 #include <base/externalization_error>
00031 #include <base/io_error>
00032
00033 #include <cstdio>
00034
00035 using base::Externalizer;
00036 using base::Externalizable;
00037 using base::VFile;
00038 using base::Math;
00039
00040 using base::dom;
00041
00042 using std::iostream;
00043 using std::istream;
00044 using std::ostream;
00045
00046 bool Externalizer::xmlInitialized = false;
00047
00048
00049
00050 const String Externalizer::newline = String("\n");
00051
00052
00053 Externalizer::Externalizer(Externalizable::ExternalizationType type, ref<VFile> archive)
00054 : xmlMode(false), impl(0), doctype(0), isoutput(type & Externalizable::Output), aborted(false),
00055 istream(isoutput?0:&archive->iostream(iostream::in)),
00056 ostream(isoutput?&archive->iostream(iostream::out):0),
00057 path(archive->path())
00058 {
00059 }
00060
00061 Externalizer::Externalizer(Externalizable::ExternalizationType type, std::ios& stream)
00062 : xmlMode(false), impl(0), doctype(0), isoutput(type & Externalizable::Output), aborted(false),
00063 path(String())
00064 {
00065 Assert(isoutput?instanceof(stream, std::ostream)
00066 :instanceof(stream, std::istream));
00067 if (isoutput)
00068 ostream = dynamic_cast<std::ostream*>(&stream);
00069 else
00070 istream = dynamic_cast<std::istream*>(&stream);
00071 }
00072
00073
00074 Externalizer::~Externalizer()
00075 {
00076 if (xmlMode) {
00077 xmlWriteDocument(xmldoc);
00078 xmlReleaseDocument();
00079 }
00080 }
00081
00082
00083 const String Externalizer::inputToConstErrorString("cannot input to a const variable");
00084 const String Externalizer::inputDuringOutputErrorString("cannot input from an output Externalizer");
00085
00086
00087 void Externalizer::flush()
00088 {
00089 if (!xmlMode)
00090 if (isoutput)
00091 (*ostream) << std::flush;
00092 }
00093
00094
00095 String Externalizer::readLine()
00096 {
00097 if (isOutput()) abort(inputDuringOutputErrorString);
00098
00099 if (!xmlMode) {
00100 char linebuf[1024];
00101 istream->getline(linebuf,1024);
00102 linebuf[1023]=char(0);
00103 return String(linebuf);
00104 }
00105 else {
00106 Unimplemented;
00107 }
00108 }
00109
00110
00111 String Externalizer::readString(SInt maxLength)
00112 {
00113 if (isOutput()) abort(inputDuringOutputErrorString);
00114
00115 if (!xmlMode) {
00116 char* buf = new char[maxLength+1];
00117
00118 input().readsome(buf, maxLength);
00119 buf[maxLength] = 0;
00120
00121 String str(buf);
00122 delete[] buf;
00123
00124 return str;
00125 }
00126 else {
00127 Unimplemented;
00128 }
00129 }
00130
00131
00132 void Externalizer::writeLine(const String& line)
00133 {
00134 if (!isOutput()) return;
00135
00136 if (!xmlMode) {
00137 output() << line << std::endl;
00138 }
00139 else {
00140 appendText(xmlcontext.top(), line);
00141 }
00142 }
00143
00144
00145 void Externalizer::writeString(const String& str)
00146 {
00147 if (!isOutput()) return;
00148
00149 if (!xmlMode) {
00150 output() << str;
00151 }
00152 else {
00153 }
00154 }
00155
00156 void Externalizer::writeComment(const String& comment)
00157 {
00158 if (!isOutput()) return;
00159
00160 if (!xmlMode)
00161 writeLine(String("# ")+comment);
00162 else {
00163 appendComment(xmlcontext.top(), comment);
00164 }
00165
00166 }
00167
00168
00169
00170
00171
00172 void Externalizer::initXMLDoc(const String& rootElementName)
00173 {
00174 if (xmlMode) return;
00175
00176 xmlInitialize();
00177
00178 parser = 0; xmldoc = 0;
00179 impl = dom::DOMImplementationRegistry::getDOMImplementation(XS("LS"));
00180 xmlMode = true;
00181
00182 if (isInput()) {
00183
00184 xmldoc = xmlParseDocument();
00185 Assert(xmldoc);
00186 dom::DOMElement* docElem = xmldoc->getDocumentElement();
00187 if (!docElem)
00188 throw base::externalization_error(Exception("failed to obtain XML document element - invalid XML document."));
00189
00190 xmlcontext.push( docElem );
00191 }
00192 else {
00193
00194 try {
00195 xmldoc = impl->createDocument(
00196 XS("http://www.w3.org/XML/1998/namespace"),
00197 XS(rootElementName),
00198 doctype);
00199 } catch (dom::DOMException& e) {
00200 abort(String("error creating document:")+String(XS(e.msg)) );
00201 }
00202 xmlcontext.push( xmldoc->getDocumentElement() );
00203 xmlcontext.top()->appendChild(xmldoc->createTextNode(XS(newline)));
00204 }
00205
00206 }
00207
00208
00209 dom::DOMElement* Externalizer::createElement(const String& tagname, bool indenting)
00210 {
00211 dom::DOMElement* elem;
00212
00213 if (!xmlMode) {
00214 String name(tagname);
00215 if (name == "") name = base::Application::getShortName();
00216 initXMLDoc(tagname);
00217 elem = xmldoc->getDocumentElement();
00218 }
00219 else
00220 elem = xmldoc->createElement(XS(tagname));
00221
00222
00223
00224 if (indenting)
00225 elem->appendChild(xmldoc->createTextNode(XS(newline)));
00226
00227 return elem;
00228 }
00229
00230
00231 void Externalizer::appendElement(dom::DOMNode* n, const String& tagname, bool indenting)
00232 {
00233 n->appendChild( createElement(tagname, indenting) );
00234 }
00235
00236
00237 void Externalizer::appendProcessingInstruction(dom::DOMNode* n, const String& target, const String& data)
00238 {
00239 Assert(xmlMode);
00240 dom::DOMProcessingInstruction* pi = xmldoc->createProcessingInstruction(XS(target), XS(data));
00241 n->appendChild(pi);
00242 }
00243
00244
00245 void Externalizer::setDocumentType(const String& name, const String& publicid, const String& sysid)
00246 {
00247 if (doctype) return;
00248
00249 if (!impl)
00250 impl = dom::DOMImplementationRegistry::getDOMImplementation(XS("LS"));
00251
00252 try {
00253 doctype = impl->createDocumentType(XS(name),XS(publicid), XS(sysid));
00254 } catch (dom::DOMException& e) {
00255 abort(String("error setting document type:")+String(XS(e.msg)) );
00256 }
00257
00258 }
00259
00260
00261
00262 dom::DOMText* Externalizer::createText(const String& text)
00263 {
00264 Assert(xmlMode);
00265 return xmldoc->createTextNode(XS(text));
00266 }
00267
00268
00269 void Externalizer::appendText(dom::DOMNode* n, const String& text)
00270 {
00271 n->appendChild( createText(text) );
00272 }
00273
00274
00275 dom::DOMComment* Externalizer::createComment(const String& comment)
00276 {
00277 Assert(xmlMode);
00278 return xmldoc->createComment(XS(comment));
00279 }
00280
00281
00282 void Externalizer::appendComment(dom::DOMNode* n, const String& comment)
00283 {
00284 n->appendChild( createComment(comment) );
00285 }
00286
00287
00288 dom::DOMCDATASection* Externalizer::createCDATA(const String& text)
00289 {
00290 Assert(xmlMode);
00291 return xmldoc->createCDATASection(XS(text));
00292 }
00293
00294
00295 void Externalizer::appendCDATA(dom::DOMNode* n, const String& text)
00296 {
00297 Assert(xmlMode);
00298 n->appendChild( createCDATA(text) );
00299 }
00300
00301
00302 dom::DOMElement* Externalizer::getFirstElement(dom::DOMNode* n, const String& tagname, bool required)
00303 {
00304 Assert(xmlMode);
00305
00306 if (isElement(n, tagname))
00307 return dynamic_cast<dom::DOMElement*>(n);
00308 else
00309 return getFirstChildElement(n, tagname, required);
00310 }
00311
00312
00313 dom::DOMElement* Externalizer::getFirstChildElement(dom::DOMNode* n, const String& tagname, bool required)
00314 {
00315 Assert(xmlMode);
00316 dom::DOMElement* e = 0;
00317
00318 if (n->hasChildNodes()) {
00319 dom::DOMNode* c = n->getFirstChild();
00320 while (c && (e==0) ) {
00321 if (isElement(c, tagname))
00322 e = dynamic_cast<dom::DOMElement*>(c);
00323
00324 c = c->getNextSibling();
00325 }
00326
00327 }
00328
00329 if (required && (e==0)) {
00330 String pstr;
00331 if (isElement(n))
00332 pstr = " within element '"+elementTagName(n)+"'";
00333 abort(String("expected element '")+tagname+"'"+pstr);
00334 }
00335
00336 return e;
00337 }
00338
00339
00340 dom::DOMElement* Externalizer::getNextSiblingElement(dom::DOMNode* n, const String& tagname, bool required)
00341 {
00342 Assert(xmlMode);
00343 dom::DOMElement* e = 0;
00344
00345 dom::DOMNode* c = n->getNextSibling();
00346 while (c && (e == 0)) {
00347 if (isElement(c, tagname))
00348 e = dynamic_cast<dom::DOMElement*>(c);
00349
00350 c = c->getNextSibling();
00351 }
00352
00353 if (required && (e==0))
00354 abort(String("expected ")+tagname+" element");
00355
00356 return e;
00357 }
00358
00359
00360
00361 void Externalizer::removeElement(dom::DOMElement* e)
00362 {
00363 Assert(xmlMode);
00364 if (context()->isSameNode(e)) return;
00365
00366 dom::DOMNode* p = e->getParentNode();
00367 if (p)
00368 p->removeChild(e);
00369 }
00370
00371
00372 String Externalizer::getContainedText(dom::DOMNode* n, bool removeIndentation)
00373 {
00374 Assert(xmlMode);
00375 String text;
00376
00377 if (n->getNodeType() == dom::DOMNode::TEXT_NODE) {
00378 dom::DOMText* t = dynamic_cast<dom::DOMText*>(n);
00379 text += String(XS(t->getData()));
00380 }
00381 else if (n->getNodeType() == dom::DOMNode::CDATA_SECTION_NODE) {
00382 dom::DOMCDATASection* cd = dynamic_cast<dom::DOMCDATASection*>(n);
00383 text += String(XS(cd->getData()));
00384 }
00385 else if (n->hasChildNodes()) {
00386
00387 dom::DOMNode* c = n->getFirstChild();
00388
00389 while (c) {
00390 text += getContainedText(c);
00391 c = c->getNextSibling();
00392 }
00393
00394 }
00395
00396 if (removeIndentation) {
00397
00398
00399 String newtext;
00400 SInt pos=0;
00401 while (pos < SInt(text.size())) {
00402
00403
00404 while (((text[pos] == ' ') || (text[pos] == '\t')) && (pos < SInt(text.size())))
00405 pos++;
00406
00407 if (pos < SInt(text.size())) {
00408
00409
00410 Int nlpos = text.find( newline, pos );
00411 if (nlpos != String::npos) {
00412 newtext += text.substr(pos, nlpos - pos + 1);
00413 pos = nlpos+1;
00414 }
00415 else {
00416 newtext += text.substr(pos, text.size() - pos);
00417 pos = text.size();
00418 }
00419
00420 }
00421
00422 }
00423 text = newtext;
00424 }
00425
00426
00427 return text;
00428 }
00429
00430
00431 String Externalizer::getElementAttribute(dom::DOMElement* e, const String& attrname, bool required)
00432 {
00433 Assert(xmlMode);
00434 dom::DOMAttr* attr = e->getAttributeNode( XS(attrname) );
00435
00436 if (attr == 0) {
00437 if (required)
00438 abort(String("expected '")+attrname+"' attribute of element '"+String(XS(e->getTagName()))+"'" );
00439 else
00440 return String();
00441 }
00442
00443 if (required && !attr->getSpecified())
00444 abort(String("expected explicit value for '")+attrname+"' attribute of element '"+String(XS(e->getTagName()))+"'" );
00445
00446 return XS( attr->getValue() );
00447 }
00448
00449
00450 String Externalizer::getDefaultedElementAttribute(dom::DOMElement* e, const String& attrname, const String& defaultValue)
00451 {
00452 Assert(xmlMode);
00453 dom::DOMAttr* attr = e->getAttributeNode( XS(attrname) );
00454
00455 if (attr == 0)
00456 return defaultValue;
00457 else
00458 if (!attr->getSpecified())
00459 return (defaultValue=="DTD")?String(XS( attr->getValue() )):defaultValue;
00460
00461 return XS( attr->getValue() );
00462 }
00463
00464
00465
00466 array<String> Externalizer::splitIntoLines(const String& text, bool removeBlankLines)
00467 {
00468 array<String> lines;
00469
00470 Int pos=0;
00471 while (pos < text.size()) {
00472 SInt nlpos = text.find( newline, pos );
00473
00474 if (nlpos != -1) {
00475 if (nlpos-pos != 0) {
00476 String line( text.substr(pos, nlpos - pos) );
00477 lines.push_back( line );
00478 }
00479 else
00480 if (!removeBlankLines)
00481 lines.push_back( String() );
00482 pos = nlpos+1;
00483 }
00484 else {
00485 lines.push_back( text.substr(pos, text.size()-pos) );
00486 pos = text.length();
00487 }
00488 }
00489
00490 return lines;
00491 }
00492
00493
00494 array<String> Externalizer::splitAtDelimiter(const String& line, char delimiter)
00495 {
00496 array<String> fields;
00497
00498 if (line.size() == 0) return fields;
00499 if (line.size() == 1) {
00500 fields.push_back( line );
00501 return fields;
00502 }
00503
00504 Int pos=0;
00505 while (pos < line.size()) {
00506 SInt nlpos = line.find( delimiter, pos );
00507 if (nlpos != -1) {
00508 if (nlpos-pos != 0) {
00509 String field( line.substr(pos, nlpos - pos) );
00510 fields.push_back( field );
00511 }
00512 pos = nlpos+1;
00513 }
00514 else {
00515 fields.push_back( line.substr(pos, line.size()-pos) );
00516 pos = line.length();
00517 }
00518 }
00519
00520 return fields;
00521 }
00522
00523
00524 base::Vector Externalizer::stringsToReals(const array<String>& strings, bool acceptUnits)
00525 {
00526 Vector v( zeroVector(strings.size()) );
00527
00528 for(Int i=0; i<strings.size(); i++) {
00529 const String& s(strings[i]);
00530 v[i] = base::stringToReal(s);
00531 if (s.length() > 2) {
00532 if (s.substr(s.length()-2,s.length()-1) == "in")
00533 v[i] *= 0.0254;
00534 else if (s.substr(s.length()-3,s.length()-1) == "deg")
00535 v[i] = Math::degToRad(v[i]);
00536 }
00537 }
00538
00539 return v;
00540 }
00541
00542
00543 base::Matrix4 Externalizer::toMatrix4(const String& text)
00544 {
00545 array<String> lines = splitIntoLines(text, true);
00546 if (lines.size() != 4)
00547 throw base::externalization_error(Exception("expected 4x4 matrix"));
00548
00549 Matrix4 m;
00550 for(Int r=0; r<4; r++) {
00551 array<String> rowEltStrings = splitAtDelimiter(lines[r],' ');
00552 Vector row( stringsToReals(rowEltStrings) );
00553 if (row.size() != 4)
00554 throw base::externalization_error(Exception("expected 4x4 matrix"));
00555 m(r+1,1) = row[0];
00556 m(r+1,2) = row[1];
00557 m(r+1,3) = row[2];
00558 m(r+1,4) = row[3];
00559 }
00560 return m;
00561 }
00562
00563 String Externalizer::toString(const base::Matrix4& m)
00564 {
00565 char buf[256];
00566 sprintf(buf,"%8.4f %8.4f %8.4f %8.4f\n%8.4f %8.4f %8.4f %8.4f\n%8.4f %8.4f %8.4f %8.4f\n%8.4f %8.4f %8.4f %8.4f\n",
00567 m(1,1),m(1,2),m(1,3),m(1,4),
00568 m(2,1),m(2,2),m(2,3),m(2,4),
00569 m(3,1),m(3,2),m(3,3),m(3,4),
00570 m(4,1),m(4,2),m(4,3),m(4,4) );
00571 return String(buf);
00572 }
00573
00574
00575 base::Vector3 Externalizer::toVector3(const String& text, bool acceptUnits)
00576 {
00577 String s1( removeChar(text, '(') );
00578 String s2( removeChar(s1, ')') );
00579 array<String> eltStrings = splitAtDelimiter(s2,',');
00580 Vector v( stringsToReals(eltStrings, acceptUnits) );
00581 if (v.size() != 3)
00582 throw base::externalization_error(Exception("expected 3 dim vector"));
00583 return Vector3(v[0], v[1], v[2]);
00584 }
00585
00586 base::Vector Externalizer::toVector(const String& text, bool commasep, bool acceptUnits)
00587 {
00588 String s1( removeChar(text, '(') );
00589 String s2( removeChar(s1, ')') );
00590 array<String> eltStrings = splitAtDelimiter(s2,commasep?',':' ');
00591 return stringsToReals(eltStrings, acceptUnits);
00592 }
00593
00594
00595
00596 String Externalizer::toString(const base::Vector3& v)
00597 {
00598 char buf[48];
00599 sprintf(buf,"(%8.4f, %8.4f, %8.4f)",v.x,v.y,v.z);
00600 return String(buf);
00601 }
00602
00603
00604 String Externalizer::toString(const base::Vector& v, bool commasep)
00605 {
00606 String str;
00607 char buf[20];
00608 for(Int i=0; i<v.size(); i++) {
00609 sprintf(buf,"%8.4f",v[i]);
00610 str += String(buf);
00611 if (commasep && (i !=v.size()-1) )
00612 str += ",";
00613 else
00614 str += " ";
00615 }
00616
00617 if (commasep)
00618 str = String("(")+str+")";
00619
00620 return str;
00621 }
00622
00623
00624 String Externalizer::toString(const base::Matrix& m)
00625 {
00626 if ((m.size1() == 0) || (m.size2() == 0)) return String("[]");
00627
00628 String line("[");
00629 char buf[16];
00630
00631 for(Int r=0; r<m.size1(); r++) {
00632 String row;
00633 for(Int c=0; c<m.size2(); c++) {
00634 if (c!=m.size2())
00635 sprintf(buf,"%8.4f ",m(r,c));
00636 else
00637 sprintf(buf,"%8.4f",m(r,c));
00638 row+=String(buf);
00639 }
00640 if (r < m.size1()-1) row += "; ";
00641 line += row;
00642 }
00643 line += "]";
00644
00645 return line;
00646 }
00647
00648
00649 base::Matrix Externalizer::toMatrix(const String& text)
00650 {
00651 String s1( removeChar(text, '[') );
00652 String s2( removeChar(s1, ']') );
00653 array<String> rowStrings = splitAtDelimiter(s2,';');
00654 Int rows = rowStrings.size();
00655 Int cols = splitAtDelimiter(rowStrings[0],' ').size();
00656 Matrix m(rows,cols);
00657
00658 for(Int r=0; r<rows; r++) {
00659 array<String> eltStrings = splitAtDelimiter(rowStrings[r],' ');
00660 matrixRow(m,r) = stringsToReals(eltStrings);
00661 }
00662
00663 return m;
00664 }
00665
00666
00667 String Externalizer::toString(Real v, const String& units)
00668 {
00669 if (units=="m")
00670 return base::realToString(v);
00671 else
00672 return base::realToString(v)+units;
00673 }
00674
00675 Real Externalizer::toReal(const String& text, bool acceptUnits)
00676 {
00677 Real v = base::stringToReal(text);
00678 if (acceptUnits && (text.length() > 2)) {
00679 if (text.substr(text.length()-2,text.length()-1) == "in")
00680 v *= 0.0254;
00681 else if (text.substr(text.length()-3, text.length()-1) == "deg")
00682 v = Math::degToRad(v);
00683 }
00684 return v;
00685 }
00686
00687
00688
00689
00690 String Externalizer::removeChar(const String& text, char toRemove)
00691 {
00692 String newtext;
00693 for(Int i=0; i<text.size(); i++)
00694 if (text[i] != toRemove)
00695 newtext += text[i];
00696 return newtext;
00697 }
00698
00699
00700 bool Externalizer::isNumeric(const String& text)
00701 {
00702 bool numeric=true;
00703 std::locale loc;
00704 const std::ctype<char>& ct = std::use_facet<std::ctype<char> >(loc);
00705 Int i=0;
00706 while (numeric && (i<text.size())) {
00707 if (!ct.is(std::ctype_base::digit,text[i]))
00708 numeric=false;
00709 i++;
00710 }
00711 return numeric;
00712 }
00713
00714
00715
00716
00717
00718 void Externalizer::xmlInitialize()
00719 {
00720 if (!xmlInitialized) {
00721 try {
00722 dom::XMLPlatformUtils::Initialize();
00723 xmlInitialized = true;
00724 }
00725 catch (const dom::XMLException& toCatch) {
00726 throw std::runtime_error(Exception(String( dom::XMLString::transcode(toCatch.getMessage()) )));
00727 }
00728 }
00729 }
00730
00731
00732
00733 dom::DOMDocument* Externalizer::xmlParseDocument()
00734 {
00735 if (isOutput()) abort(inputDuringOutputErrorString);
00736
00737 xmlInitialize();
00738
00739 if (!impl)
00740 impl = dom::DOMImplementationRegistry::getDOMImplementation(XS("LS"));
00741 parser = ((dom::DOMImplementationLS*)impl)->createDOMBuilder(dom::DOMImplementationLS::MODE_SYNCHRONOUS, 0);
00742
00743
00744 if (parser->canSetFeature(dom::XMLUni::fgDOMValidation, true))
00745 parser->setFeature(dom::XMLUni::fgDOMValidation, true);
00746 if (parser->canSetFeature(dom::XMLUni::fgDOMNamespaces, true))
00747 parser->setFeature(dom::XMLUni::fgDOMNamespaces, true);
00748 if (parser->canSetFeature(dom::XMLUni::fgDOMDatatypeNormalization, true))
00749 parser->setFeature(dom::XMLUni::fgDOMDatatypeNormalization, true);
00750 if (parser->canSetFeature(dom::XMLUni::fgDOMComments, true))
00751 parser->setFeature(dom::XMLUni::fgDOMComments, false);
00752
00753
00754
00755 array<XByte> buffer(0,4096);
00756 XByte b;
00757 std::istream& is( input() );
00758 while (is.good()) {
00759 b = is.get();
00760 buffer.push_back(b);
00761 }
00762
00763 dom::MemBufInputSource memInputSrc(buffer.c_array(),buffer.size(),XS("ID"));
00764 dom::Wrapper4InputSource domInputSrc(&memInputSrc, false);
00765
00766 dom::DOMDocument *doc = 0;
00767
00768 try {
00769 doc = parser->parse(domInputSrc);
00770 }
00771 catch (const dom::XMLException& toCatch) {
00772 char* message = dom::XMLString::transcode(toCatch.getMessage());
00773 throw base::externalization_error(Exception(String("XML Error:")+message));
00774 }
00775 catch (const dom::DOMException& toCatch) {
00776 char* message = dom::XMLString::transcode(toCatch.msg);
00777 throw base::externalization_error(Exception(String("XML DOM Error:")+message));
00778 }
00779
00780 Assert(doc);
00781 return doc;
00782 }
00783
00784
00785 void Externalizer::xmlWriteDocument(dom::DOMDocument* doc)
00786 {
00787 if (isInput()) return;
00788
00789 xmlInitialize();
00790
00791 dom::DOMNode* docElem = doc->getDocumentElement();
00792 xmlFormat(docElem, 1);
00793
00794 dom::DOMNode* last = docElem->getLastChild();
00795 if (last)
00796 if (!isNewline(last))
00797 appendText(docElem, newline);
00798
00799 if (!impl)
00800 impl = dom::DOMImplementationRegistry::getDOMImplementation(XS("LS"));
00801 dom::DOMWriter* writer = ((dom::DOMImplementationLS*)impl)->createDOMWriter();
00802
00803
00804 if (writer->canSetFeature(dom::XMLUni::fgDOMWRTDiscardDefaultContent, true))
00805 writer->setFeature(dom::XMLUni::fgDOMWRTDiscardDefaultContent, true);
00806
00807 if (writer->canSetFeature(dom::XMLUni::fgDOMWRTFormatPrettyPrint, true))
00808 writer->setFeature(dom::XMLUni::fgDOMWRTFormatPrettyPrint, false);
00809
00810
00811
00812 dom::MemBufFormatTarget memBufTarget;
00813
00814 try {
00815
00816 writer->writeNode(&memBufTarget, *doc);
00817 }
00818 catch (const dom::XMLException& toCatch) {
00819 char* message = dom::XMLString::transcode(toCatch.getMessage());
00820 throw base::externalization_error(Exception(String("XML Error:")+message));
00821 }
00822 catch (const dom::DOMException& toCatch) {
00823 char* message = dom::XMLString::transcode(toCatch.msg);
00824 throw base::externalization_error(Exception(String("XML DOM Error:")+message));
00825 }
00826
00827
00828 std::ostream& os( output() );
00829 const XByte* bytes = memBufTarget.getRawBuffer();
00830 XByte b = *bytes;
00831 while (b != 0) {
00832 os.put(b);
00833 bytes++;
00834 b = *bytes;
00835 }
00836 os.flush();
00837
00838 }
00839
00840
00841 void Externalizer::xmlReleaseDocument()
00842 {
00843 if (xmlMode) {
00844
00845 if (parser) {
00846 parser->release();
00847 parser = 0;
00848 xmldoc = 0;
00849 }
00850
00851 xmlMode=0;
00852 }
00853
00854 }
00855
00856
00857 bool Externalizer::isNewline(dom::DOMNode* n)
00858 {
00859 if (n->getNodeType() == dom::DOMNode::TEXT_NODE) {
00860 dom::DOMText* t = dynamic_cast<dom::DOMText*>(n);
00861 return (dom::XMLString::compareString(t->getData(),
00862 XS(newline)) == 0);
00863 }
00864 return false;
00865 }
00866
00867
00868 bool Externalizer::equals(const XCh* str1, const String& str2)
00869 {
00870 return (dom::XMLString::compareString(str1, XS(str2)) == 0);
00871 }
00872
00873
00874 bool Externalizer::isElement(dom::DOMNode* n, const String& tagname)
00875 {
00876 if (n->getNodeType() == dom::DOMNode::ELEMENT_NODE) {
00877 dom::DOMElement* e = dynamic_cast<dom::DOMElement*>(n);
00878 return equals(e->getTagName(), tagname);
00879 }
00880 return false;
00881 }
00882
00883
00884
00885
00886 void Externalizer::xmlFormat(dom::DOMNode* n, Int indent)
00887 {
00888 if (!n->hasChildNodes()) return;
00889
00890 dom::DOMNode* c = n->getFirstChild();
00891 do {
00892
00893
00894
00895 switch (c->getNodeType()) {
00896 case dom::DOMNode::ELEMENT_NODE: {
00897 dom::DOMElement* e = dynamic_cast<dom::DOMElement*>(c);
00898 bool indenting = false;
00899 dom::DOMNode* first = e->getFirstChild();
00900 if (first) {
00901 if (isNewline(first)) {
00902
00903
00904 indenting = true;
00905
00906
00907 dom::DOMNode* p = e->getParentNode();
00908 if (p) {
00909 dom::DOMNode* prev = e->getPreviousSibling();
00910 if (prev)
00911 if (!isNewline(prev))
00912 p->insertBefore( createText(newline), e );
00913 p->insertBefore( createText(String(indent*indentSpaces, ' ')), e );
00914 }
00915
00916
00917
00918
00919
00920
00921 dom::DOMNode* last = e->getLastChild();
00922 if (last->isSameNode(first) && isNewline(last))
00923 e->removeChild(last);
00924 else {
00925
00926 xmlFormat(c,indent+1);
00927
00928 last = e->getLastChild();
00929 if (!isNewline(last))
00930 appendText(e, newline);
00931 appendText(e, String(indent*indentSpaces, ' ') );
00932
00933
00934
00935 dom::DOMNode* p = e->getParentNode();
00936 if (p) {
00937 dom::DOMNode* next = e->getNextSibling();
00938 if (next)
00939 p->insertBefore( createText(newline), next );
00940 else
00941 appendText(p, newline );
00942 }
00943 }
00944
00945 }
00946 }
00947
00948
00949
00950 dom::DOMNode* prev = e->getPreviousSibling();
00951 if (prev)
00952 if (isNewline(prev)) {
00953 dom::DOMNode* p = e->getParentNode();
00954 if (p)
00955 p->insertBefore( createText(String(indent*indentSpaces, ' ')), e );
00956 }
00957
00958
00959
00960 if (!indenting)
00961 xmlFormat(c,indent);
00962
00963 } break;
00964
00965 case dom::DOMNode::TEXT_NODE: {
00966
00967 if (!isNewline(c)) {
00968 dom::DOMText* t = dynamic_cast<dom::DOMText*>(c);
00969 dom::DOMNode* prev = t->getPreviousSibling();
00970 if (prev) {
00971 if (isNewline(prev)) {
00972 dom::DOMNode* p = t->getParentNode();
00973 if (p)
00974 p->insertBefore( createText(String(indent*indentSpaces, ' ')), t );
00975 }
00976 }
00977
00978
00979
00980 const XCh* text = t->getData();
00981 SInt newlineIndex = dom::XMLString::indexOf(text,XS(newline)[0]);
00982 if (newlineIndex != -1) {
00983 if (newlineIndex != SInt(t->getLength())-1) {
00984 t->splitText(newlineIndex);
00985 dom::DOMText* newtext = dynamic_cast<dom::DOMText*>(t->getNextSibling());
00986 newtext->deleteData(0,1);
00987
00988 dom::DOMNode* p = t->getParentNode();
00989 if (p)
00990 p->insertBefore(createText(newline), newtext );
00991 }
00992 else
00993 t->deleteData(t->getLength()-1,1);
00994 }
00995 }
00996
00997 xmlFormat(c,indent);
00998 } break;
00999
01000
01001 case dom::DOMNode::CDATA_SECTION_NODE:
01002 case dom::DOMNode::COMMENT_NODE: {
01003
01004
01005 dom::DOMNode* prev = c->getPreviousSibling();
01006 dom::DOMNode* p = c->getParentNode();
01007 if (prev) {
01008 if (!isNewline(prev)) {
01009 if (p) p->insertBefore( createText(newline), c);
01010 }
01011
01012 if (p)
01013 p->insertBefore( createText(String(indent*indentSpaces, ' ')), c );
01014 }
01015
01016
01017 dom::DOMNode* next = c->getNextSibling();
01018 if (next) {
01019 if (p) p->insertBefore( createText(newline), next );
01020 }
01021 else
01022 p->appendChild( createText(newline) );
01023
01024
01025 } break;
01026
01027 default: ;
01028 }
01029
01030 c = c->getNextSibling();
01031 } while(c);
01032
01033 }
01034
01035
01036
01037
01038
01039
01040 void Externalizer::abort(const String& exceptionString)
01041 {
01042 if (!aborted) {
01043 aborted=true;
01044 Logln(exceptionString);
01045 throw externalization_error(Exception(exceptionString));
01046 }
01047 }