瀏覽代碼

Split PrettyPrinting functionality from VFS printing

Lukas Aldershaab 3 年之前
父節點
當前提交
5abd66dfa3
共有 2 個文件被更改,包括 212 次插入149 次删除
  1. 111 143
      Engine/source/persistence/taml/fsTinyXml.cpp
  2. 101 6
      Engine/source/persistence/taml/fsTinyXml.h

+ 111 - 143
Engine/source/persistence/taml/fsTinyXml.cpp

@@ -26,49 +26,10 @@
 
 #include "console/console.h"
 
-
-// Re-implement private functionality in TinyXML2
-
-static const char LINE_FEED = static_cast<char>(0x0a);			// all line endings are normalized to LF
-static const char LF = LINE_FEED;
-static const char CARRIAGE_RETURN = static_cast<char>(0x0d);			// CR gets filtered out
-static const char CR = CARRIAGE_RETURN;
-static const char SINGLE_QUOTE = '\'';
-static const char DOUBLE_QUOTE = '\"';
-
-struct Entity {
-   const char* pattern;
-   int length;
-   char value;
-};
-
-static const int NUM_ENTITIES = 5;
-static const Entity entities[NUM_ENTITIES] = {
-    { "quot", 4,	DOUBLE_QUOTE },
-    { "amp", 3,		'&'  },
-    { "apos", 4,	SINGLE_QUOTE },
-    { "lt",	2, 		'<'	 },
-    { "gt",	2,		'>'	 }
-};
-
 VfsXMLPrinter::VfsXMLPrinter(FileStream& stream, bool compact, int depth)
    : XMLPrinter(NULL, compact, depth),
-     m_Stream(stream),
-     _depth(depth)
+     m_Stream(stream)
 {
-   for (int i = 0; i < ENTITY_RANGE; ++i) {
-      _entityFlag[i] = false;
-      _restrictedEntityFlag[i] = false;
-   }
-   for (int i = 0; i < NUM_ENTITIES; ++i) {
-      const char entityValue = entities[i].value;
-      const unsigned char flagIndex = static_cast<unsigned char>(entityValue);
-      TIXMLASSERT(flagIndex < ENTITY_RANGE);
-      _entityFlag[flagIndex] = true;
-   }
-   _restrictedEntityFlag[static_cast<unsigned char>('&')] = true;
-   _restrictedEntityFlag[static_cast<unsigned char>('<')] = true;
-   _restrictedEntityFlag[static_cast<unsigned char>('>')] = true;	// not required, but consistency is nice
 }
 
 VfsXMLPrinter::~VfsXMLPrinter()
@@ -77,72 +38,6 @@ VfsXMLPrinter::~VfsXMLPrinter()
    m_Stream.close();
 }
 
-void VfsXMLPrinter::PrintString(const char* p, bool restricted)
-{
-   // Look for runs of bytes between entities to print.
-   const char* q = p;
-
-   if (_processEntities) {
-      const bool* flag = restricted ? _restrictedEntityFlag : _entityFlag;
-      while (*q) {
-         TIXMLASSERT(p <= q);
-         // Remember, char is sometimes signed. (How many times has that bitten me?)
-         if (*q > 0 && *q < ENTITY_RANGE) {
-            // Check for entities. If one is found, flush
-            // the stream up until the entity, write the
-            // entity, and keep looking.
-            if (flag[static_cast<unsigned char>(*q)]) {
-               while (p < q) {
-                  const size_t delta = q - p;
-                  const int toPrint = (INT_MAX < delta) ? INT_MAX : static_cast<int>(delta);
-                  Write(p, toPrint);
-                  p += toPrint;
-               }
-               bool entityPatternPrinted = false;
-               for (int i = 0; i < NUM_ENTITIES; ++i) {
-                  if (entities[i].value == *q) {
-                     Putc('&');
-                     Write(entities[i].pattern, entities[i].length);
-                     Putc(';');
-                     entityPatternPrinted = true;
-                     break;
-                  }
-               }
-               if (!entityPatternPrinted) {
-                  // TIXMLASSERT( entityPatternPrinted ) causes gcc -Wunused-but-set-variable in release
-                  TIXMLASSERT(false);
-               }
-               ++p;
-            }
-         }
-         ++q;
-         TIXMLASSERT(p <= q);
-      }
-      // Flush the remaining string. This will be the entire
-      // string if an entity wasn't found.
-      if (p < q) {
-         const size_t delta = q - p;
-         const int toPrint = (INT_MAX < delta) ? INT_MAX : static_cast<int>(delta);
-         Write(p, toPrint);
-      }
-   }
-   else {
-      Write(p);
-   }
-}
-
-bool VfsXMLPrinter::VisitEnter(const tinyxml2::XMLDocument& doc)
-{
-   _processEntities = doc.ProcessEntities();
-   return XMLPrinter::VisitEnter(doc);
-}
-
-bool VfsXMLPrinter::VisitExit(const tinyxml2::XMLElement& element)
-{
-   _depth--;
-   return XMLPrinter::VisitExit(element);
-}
-
 
 // Add VFS friendly implementations of output functions
 
@@ -166,42 +61,6 @@ void VfsXMLPrinter::Putc(char ch)
    m_Stream.write(static_cast<U8>(ch));
 }
 
-// Overwrite Visitation of elements to add newlines before attributes
-
-bool VfsXMLPrinter::VisitEnter(const tinyxml2::XMLElement& element, const tinyxml2::XMLAttribute* attribute)
-{
-   const tinyxml2::XMLElement* parentElem = 0;
-   if (element.Parent()) {
-      parentElem = element.Parent()->ToElement();
-   }
-   const bool compactMode = parentElem ? CompactMode(*parentElem) : CompactMode(element);
-   OpenElement(element.Name(), compactMode);
-   _depth++;
-   while (attribute) {
-      PushAttribute(attribute->Name(), attribute->Value(), compactMode);
-      attribute = attribute->Next();
-   }
-   return true;
-}
-
-void VfsXMLPrinter::PushAttribute(const char* name, const char* value, bool compactMode)
-{
-   TIXMLASSERT(_elementJustOpened);
-   if (compactMode)
-   {
-      Putc(' ');
-   }
-   else
-   {
-      Putc('\n');
-      PrintSpace(_depth);
-   }
-   Write(name);
-   Write("=\"");
-   PrintString(value, false);
-   Putc('\"');
-}
-
 bool VfsXMLDocument::LoadFile(const char* pFilename)
 {
    // Expand the file-path.
@@ -340,7 +199,8 @@ bool VfsXMLDocument::SaveFile(FileStream& stream)
    // for *this* call.
    ClearError();
    VfsXMLPrinter printer(stream, false, 0);
-   Print(&printer);
+   PrettyXMLPrinter prettyPrinter(printer);
+   Print(&prettyPrinter);
    return !Error();
 }
 
@@ -401,3 +261,111 @@ void VfsXMLDocument::SetError(tinyxml2::XMLError error, int lineNum, const char*
    _errorStr.SetStr(buffer);
    delete[] buffer;
 }
+
+
+// Overwrite Visitation of elements to add newlines before attributes
+PrettyXMLPrinter::PrettyXMLPrinter(VfsXMLPrinter& innerPrinter, int depth)
+   : mInnerPrinter(innerPrinter),
+   _depth(depth)
+{
+   for (int i = 0; i < ENTITY_RANGE; ++i) {
+      _entityFlag[i] = false;
+      _restrictedEntityFlag[i] = false;
+   }
+   for (int i = 0; i < NUM_ENTITIES; ++i) {
+      const char entityValue = entities[i].value;
+      const unsigned char flagIndex = static_cast<unsigned char>(entityValue);
+      TIXMLASSERT(flagIndex < ENTITY_RANGE);
+      _entityFlag[flagIndex] = true;
+   }
+   _restrictedEntityFlag[static_cast<unsigned char>('&')] = true;
+   _restrictedEntityFlag[static_cast<unsigned char>('<')] = true;
+   _restrictedEntityFlag[static_cast<unsigned char>('>')] = true;	// not required, but consistency is nice
+}
+
+void PrettyXMLPrinter::PrintString(const char* p, bool restricted)
+{
+   // Look for runs of bytes between entities to print.
+   const char* q = p;
+
+   if (_processEntities) {
+      const bool* flag = restricted ? _restrictedEntityFlag : _entityFlag;
+      while (*q) {
+         TIXMLASSERT(p <= q);
+         // Remember, char is sometimes signed. (How many times has that bitten me?)
+         if (*q > 0 && *q < ENTITY_RANGE) {
+            // Check for entities. If one is found, flush
+            // the stream up until the entity, write the
+            // entity, and keep looking.
+            if (flag[static_cast<unsigned char>(*q)]) {
+               while (p < q) {
+                  const size_t delta = q - p;
+                  const int toPrint = (INT_MAX < delta) ? INT_MAX : static_cast<int>(delta);
+                  mInnerPrinter.Write(p, toPrint);
+                  p += toPrint;
+               }
+               bool entityPatternPrinted = false;
+               for (int i = 0; i < NUM_ENTITIES; ++i) {
+                  if (entities[i].value == *q) {
+                     mInnerPrinter.Putc('&');
+                     mInnerPrinter.Write(entities[i].pattern, entities[i].length);
+                     mInnerPrinter.Putc(';');
+                     entityPatternPrinted = true;
+                     break;
+                  }
+               }
+               if (!entityPatternPrinted) {
+                  // TIXMLASSERT( entityPatternPrinted ) causes gcc -Wunused-but-set-variable in release
+                  TIXMLASSERT(false);
+               }
+               ++p;
+            }
+         }
+         ++q;
+         TIXMLASSERT(p <= q);
+      }
+      // Flush the remaining string. This will be the entire
+      // string if an entity wasn't found.
+      if (p < q) {
+         const size_t delta = q - p;
+         const int toPrint = (INT_MAX < delta) ? INT_MAX : static_cast<int>(delta);
+         mInnerPrinter.Write(p, toPrint);
+      }
+   }
+   else {
+      mInnerPrinter.Write(p);
+   }
+}
+
+bool PrettyXMLPrinter::VisitEnter(const tinyxml2::XMLElement& element, const tinyxml2::XMLAttribute* attribute)
+{
+   const tinyxml2::XMLElement* parentElem = 0;
+   if (element.Parent()) {
+      parentElem = element.Parent()->ToElement();
+   }
+   const bool compactMode = parentElem ? mInnerPrinter.CompactMode(*parentElem) : mInnerPrinter.CompactMode(element);
+   mInnerPrinter.OpenElement(element.Name(), compactMode);
+   _depth++;
+   while (attribute) {
+      PushAttribute(attribute->Name(), attribute->Value(), compactMode);
+      attribute = attribute->Next();
+   }
+   return true;
+}
+
+void PrettyXMLPrinter::PushAttribute(const char* name, const char* value, bool compactMode)
+{
+   if (compactMode)
+   {
+      mInnerPrinter.Putc(' ');
+   }
+   else
+   {
+      mInnerPrinter.Putc('\n');
+      mInnerPrinter.PrintSpace(_depth);
+   }
+   mInnerPrinter.Write(name);
+   mInnerPrinter.Write("=\"");
+   PrintString(value, false);
+   mInnerPrinter.Putc('\"');
+}

+ 101 - 6
Engine/source/persistence/taml/fsTinyXml.h

@@ -41,19 +41,16 @@ public:
    ~VfsXMLPrinter() override;
 
    // Re-implement private functionality in TinyXML2 library, this is just a copy-paste job
-   void PrintString(const char*, bool restrictedEntitySet);	// prints out, after detecting entities.
-
-   virtual bool VisitEnter(const tinyxml2::XMLDocument& /*doc*/);
-   virtual bool VisitExit(const tinyxml2::XMLElement& element);
+   bool CompactMode(const tinyxml2::XMLElement& element) override { return tinyxml2::XMLPrinter::CompactMode(element); }
 
    // Add VFS friendly implementations of output functions
    void Print(const char* format, ...) override;
    void Write(const char* data, size_t size) override;
    inline void Write(const char* data) { Write(data, strlen(data)); }
    void Putc(char ch) override;
+   void PrintSpace(int depth) override { tinyxml2::XMLPrinter::PrintSpace(depth); }
 
    // Overwrite Visitation of elements to add newlines before attributes
-   virtual bool VisitEnter(const tinyxml2::XMLElement& element, const tinyxml2::XMLAttribute* attribute);
    void PushAttribute(const char* name, const char* value, bool compactMode);
 
    // Accept a virtual FileStream instead of a FILE pointer
@@ -63,10 +60,12 @@ public:
    int _depth;
    bool _processEntities;
 
-   enum {
+   enum
+   {
       ENTITY_RANGE = 64,
       BUF_SIZE = 200
    };
+
    bool _entityFlag[ENTITY_RANGE];
    bool _restrictedEntityFlag[ENTITY_RANGE];
 };
@@ -152,4 +151,100 @@ public:
    }
 };
 
+class PrettyXMLPrinter : public tinyxml2::XMLPrinter
+{
+   // Re-implement private functionality in TinyXML2
+   static const char LINE_FEED = static_cast<char>(0x0a); // all line endings are normalized to LF
+   static const char LF = LINE_FEED;
+   static const char CARRIAGE_RETURN = static_cast<char>(0x0d); // CR gets filtered out
+   static const char CR = CARRIAGE_RETURN;
+   static const char SINGLE_QUOTE = '\'';
+   static const char DOUBLE_QUOTE = '\"';
+
+   struct Entity
+   {
+      const char* pattern;
+      int length;
+      char value;
+   };
+
+   static const int NUM_ENTITIES = 5;
+   static constexpr  Entity entities[NUM_ENTITIES] = {
+      {"quot", 4, DOUBLE_QUOTE},
+      {"amp", 3, '&'},
+      {"apos", 4, SINGLE_QUOTE},
+      {"lt", 2, '<'},
+      {"gt", 2, '>'}
+   };
+public:
+   PrettyXMLPrinter(VfsXMLPrinter& innerPrinter, int depth = 0);
+
+   /// Visit a document.
+   virtual bool VisitEnter(const tinyxml2::XMLDocument& doc)
+   {
+      _processEntities = doc.ProcessEntities();
+      return mInnerPrinter.VisitEnter(doc);
+   }
+
+   /// Visit a document.
+   virtual bool VisitExit(const tinyxml2::XMLDocument& doc)
+   {
+      return mInnerPrinter.VisitExit(doc);
+   }
+
+   /// Visit an element.
+   virtual bool VisitEnter(const tinyxml2::XMLElement& element, const tinyxml2::XMLAttribute* firstAttribute);
+   /// Visit an element.
+   virtual bool VisitExit(const tinyxml2::XMLElement& element)
+   {
+      _depth--;
+      return mInnerPrinter.VisitExit(element);
+   }
+
+   /// Visit a declaration.
+   virtual bool Visit(const tinyxml2::XMLDeclaration& declaration)
+   {
+      return mInnerPrinter.Visit(declaration);
+   }
+
+   /// Visit a text node.
+   virtual bool Visit(const tinyxml2::XMLText& text)
+   {
+      return mInnerPrinter.Visit(text);
+   }
+
+   /// Visit a comment node.
+   virtual bool Visit(const tinyxml2::XMLComment& comment)
+   {
+      return mInnerPrinter.Visit(comment);
+   }
+
+   /// Visit an unknown node.
+   virtual bool Visit(const tinyxml2::XMLUnknown& unknown)
+   {
+      return mInnerPrinter.Visit(unknown);
+   }
+
+   void PushAttribute(const char* name, const char* value, bool compactMode);
+
+   // Re-implement private functionality in TinyXML2 library, this is just a copy-paste job
+   void PrintString(const char*, bool restrictedEntitySet); // prints out, after detecting entities.
+   VfsXMLPrinter& mInnerPrinter;
+
+   // Track private fields that are necessary for private functionality in TinyXML2
+   int _depth;
+   bool _processEntities;
+   bool _compactMode;
+
+   enum
+   {
+      ENTITY_RANGE = 64,
+      BUF_SIZE = 200
+   };
+
+   bool _entityFlag[ENTITY_RANGE];
+   bool _restrictedEntityFlag[ENTITY_RANGE];
+};
+
+
 #endif //_FSTINYXML_H_