| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278 |
- // Filename: binaryXml.cxx
- // Created by: drose (13Jul09)
- //
- ////////////////////////////////////////////////////////////////////
- //
- // PANDA 3D SOFTWARE
- // Copyright (c) Carnegie Mellon University. All rights reserved.
- //
- // All use of this software is subject to the terms of the revised BSD
- // license. You should have received a copy of this license along
- // with this source code in a file named "LICENSE."
- //
- ////////////////////////////////////////////////////////////////////
- #include "binaryXml.h"
- #include <sstream>
- static const bool debug_xml_output = false;
- #define DO_BINARY_XML 1
- enum NodeType {
- NT_unknown,
- NT_document,
- NT_element,
- NT_text,
- };
- ////////////////////////////////////////////////////////////////////
- // Function: write_xml_node
- // Description: Recursively writes a node and all of its children to
- // the given stream.
- ////////////////////////////////////////////////////////////////////
- static void
- write_xml_node(ostream &out, TiXmlNode *xnode) {
- NodeType type = NT_element;
- if (xnode->ToDocument() != NULL) {
- type = NT_document;
- } else if (xnode->ToElement() != NULL) {
- type = NT_element;
- } else if (xnode->ToText() != NULL) {
- type = NT_text;
- } else {
- type = NT_unknown;
- }
- out.put((char)type);
- // We don't bother to write any data for the unknown types.
- if (type == NT_unknown) {
- return;
- }
- const string &value = xnode->ValueStr();
- size_t value_length = value.length();
- out.write((char *)&value_length, sizeof(value_length));
- out.write(value.data(), value_length);
- if (type == NT_element) {
- // Write the element attributes.
- TiXmlElement *xelement = xnode->ToElement();
- assert(xelement != NULL);
- const TiXmlAttribute *xattrib = xelement->FirstAttribute();
- while (xattrib != NULL) {
- // We have an attribute.
- out.put((char)true);
-
- string name = xattrib->Name();
- size_t name_length = name.length();
- out.write((char *)&name_length, sizeof(name_length));
- out.write(name.data(), name_length);
-
- const string &value = xattrib->ValueStr();
- size_t value_length = value.length();
- out.write((char *)&value_length, sizeof(value_length));
- out.write(value.data(), value_length);
-
- xattrib = xattrib->Next();
- }
- // The end of the attributes list.
- out.put((char)false);
- }
- // Now write all of the children.
- TiXmlNode *xchild = xnode->FirstChild();
- while (xchild != NULL) {
- // We have a child.
- out.put((char)true);
- write_xml_node(out, xchild);
- xchild = xchild->NextSibling();
- }
-
- // The end of the children list.
- out.put((char)false);
- }
- ////////////////////////////////////////////////////////////////////
- // Function: read_xml_node
- // Description: Recursively reads a node and all of its children to
- // the given stream. Returns the newly-allocated node.
- // The caller is responsible for eventually deleting the
- // return value. Returns NULL on error.
- ////////////////////////////////////////////////////////////////////
- static TiXmlNode *
- read_xml_node(istream &in, char *&buffer, size_t &buffer_length) {
- NodeType type = (NodeType)in.get();
- if (type == NT_unknown) {
- return NULL;
- }
- size_t value_length;
- in.read((char *)&value_length, sizeof(value_length));
- if (in.gcount() != sizeof(value_length)) {
- return NULL;
- }
- if (value_length > buffer_length) {
- delete[] buffer;
- buffer_length = value_length;
- buffer = new char[buffer_length];
- }
- in.read(buffer, value_length);
- string value(buffer, value_length);
- TiXmlNode *xnode = NULL;
- if (type == NT_element) {
- xnode = new TiXmlElement(value);
- } else if (type == NT_document) {
- xnode = new TiXmlDocument;
- } else if (type == NT_text) {
- xnode = new TiXmlText(value);
- } else {
- assert(false);
- }
- if (type == NT_element) {
- // Read the element attributes.
- TiXmlElement *xelement = xnode->ToElement();
- assert(xelement != NULL);
- bool got_attrib = (bool)(in.get() != 0);
- while (got_attrib && in && !in.eof()) {
- // We have an attribute.
- size_t name_length;
- in.read((char *)&name_length, sizeof(name_length));
- if (in.gcount() != sizeof(name_length)) {
- delete xnode;
- return NULL;
- }
- if (name_length > buffer_length) {
- delete[] buffer;
- buffer_length = name_length;
- buffer = new char[buffer_length];
- }
- in.read(buffer, name_length);
- string name(buffer, name_length);
- size_t value_length;
- in.read((char *)&value_length, sizeof(value_length));
- if (in.gcount() != sizeof(value_length)) {
- delete xnode;
- return NULL;
- }
- if (value_length > buffer_length) {
- delete[] buffer;
- buffer_length = value_length;
- buffer = new char[buffer_length];
- }
- in.read(buffer, value_length);
- string value(buffer, value_length);
- xelement->SetAttribute(name, value);
- got_attrib = (bool)(in.get() != 0);
- }
- }
- // Now read all of the children.
- bool got_child = (bool)(in.get() != 0);
-
- while (got_child && in && !in.eof()) {
- // We have a child.
- TiXmlNode *xchild = read_xml_node(in, buffer, buffer_length);
- if (xchild != NULL) {
- xnode->LinkEndChild(xchild);
- }
- got_child = (bool)(in.get() != 0);
- }
- return xnode;
- }
- ////////////////////////////////////////////////////////////////////
- // Function: write_xml
- // Description: Writes the indicated TinyXml document to the given
- // stream.
- ////////////////////////////////////////////////////////////////////
- void
- write_xml(ostream &out, TiXmlDocument *doc, ostream &logfile) {
- #ifdef DO_BINARY_XML
- // Binary write.
- write_xml_node(out, doc);
- #else
- // Formatted ASCII write.
- // We need a declaration to write it safely.
- TiXmlDeclaration decl("1.0", "utf-8", "");
- doc->InsertBeforeChild(doc->FirstChild(), decl);
- out << *doc;
- #endif
- out << flush;
- if (debug_xml_output) {
- // Write via ostringstream, so it all goes in one operation, to
- // help out the interleaving from multiple threads.
- ostringstream logout;
- logout << "sent: " << *doc << "\n";
- logfile << logout.str() << flush;
- }
- }
- ////////////////////////////////////////////////////////////////////
- // Function: read_xml
- // Description: Reads a TinyXml document from the given stream, and
- // returns it. If the document is not yet available,
- // blocks until it is, or until there is an error
- // condition on the input.
- //
- // The return value is NULL if there is an error, or the
- // newly-allocated document if it is successfully read.
- // If not NULL, the document has been allocated with
- // new, and should be eventually freed by the caller
- // with delete.
- ////////////////////////////////////////////////////////////////////
- TiXmlDocument *
- read_xml(istream &in, ostream &logfile) {
- #if DO_BINARY_XML
- // binary read.
- size_t buffer_length = 128;
- char *buffer = new char[buffer_length];
- TiXmlNode *xnode = read_xml_node(in, buffer, buffer_length);
- delete[] buffer;
- if (xnode == NULL) {
- return NULL;
- }
- TiXmlDocument *doc = xnode->ToDocument();
- assert(doc != NULL);
- #else
- // standard ASCII read.
- TiXmlDocument *doc = new TiXmlDocument;
- in >> *doc;
- #endif
- if (debug_xml_output) {
- // Write via ostringstream, so it all goes in one operation, to
- // help out the interleaving from multiple threads.
- ostringstream logout;
- logout << "received: " << *doc << "\n";
- logfile << logout.str() << flush;
- }
-
- return doc;
- }
|