1 #include "Macros.h" 2 3 #if IS_GNUC_AND_GNUC_VERSION_LT(5,1,1) 4 #include <cstring> 5 #endif 6 7 #include "XmlDoc.h" 8 #include "XmlNode.h" 9 #include "XmlNamespace.h" 10 11 #include "no_warning_fstream" 12 #include "no_warning_vector" 13 #include <sys/stat.h> 14 15 using namespace std; 16 17 #include "zlib.h" 18 19 namespace opencollada 20 { XmlDoc(XmlDoc && other)21 XmlDoc::XmlDoc(XmlDoc && other) 22 { 23 *this = move(other); 24 } 25 ~XmlDoc()26 XmlDoc::~XmlDoc() 27 { 28 reset(); 29 } 30 operator =(XmlDoc && other)31 const XmlDoc & XmlDoc::operator = (XmlDoc && other) 32 { 33 swap(mDoc, other.mDoc); 34 return *this; 35 } 36 readFile(const string & path)37 void XmlDoc::readFile(const string & path) 38 { 39 reset(); 40 41 ifstream ifile(path, ios_base::binary); 42 43 if (!ifile.is_open()) return; 44 45 struct stat st; 46 int r = stat(path.c_str(), &st); 47 auto size = 0; 48 if (r == 0) 49 size = st.st_size; 50 51 if (size <= 4) return; 52 53 vector<char> content(static_cast<size_t>(size)); 54 ifile.read(content.data(), size); 55 56 #if IS_MSVC_AND_MSVC_VERSION_LT(1900) 57 typedef unsigned int uint32_t; 58 #endif 59 uint32_t signature = *reinterpret_cast<const uint32_t*>(content.data()); 60 61 // Uncompressed document 62 // 1f8b08 63 if ((signature & 0x00FFFFFF) != 0x00088b1f) 64 { 65 mDoc = xmlReadMemory(content.data(), size, path.c_str(), NULL, 0); 66 } 67 // Compressed document (gzip only) 68 else 69 { 70 vector<char> decompressed_content(*reinterpret_cast<const uint32_t*>(content.data() + content.size() - 4)); 71 #if IS_GNUC_AND_GNUC_VERSION_LT(5,1,1) 72 z_stream zInfo; 73 memset(&zInfo, 0, sizeof(zInfo)); 74 #else 75 z_stream zInfo {}; 76 #endif 77 zInfo.total_in = zInfo.avail_in = static_cast<uInt>(content.size()); 78 zInfo.total_out = zInfo.avail_out = static_cast<uInt>(decompressed_content.size()); 79 zInfo.next_in = reinterpret_cast<Bytef*>(content.data()); 80 zInfo.next_out = reinterpret_cast<Bytef*>(decompressed_content.data()); 81 82 int nErr = inflateInit2(&zInfo, 16 + MAX_WBITS); 83 if (nErr == Z_OK) 84 { 85 nErr = inflate(&zInfo, Z_FINISH); 86 } 87 inflateEnd(&zInfo); 88 89 if (nErr == Z_STREAM_END) 90 mDoc = xmlReadMemory(decompressed_content.data(), static_cast<int>(decompressed_content.size()), path.c_str(), NULL, 0); 91 } 92 93 if (mDoc) 94 mDoc->_private = this; 95 } 96 operator bool() const97 XmlDoc::operator bool() const 98 { 99 return mDoc != nullptr; 100 } 101 reset()102 void XmlDoc::reset() 103 { 104 mXPathCache.clear(); 105 106 if (mDoc) 107 { 108 xmlFreeDoc(mDoc); 109 mDoc = nullptr; 110 } 111 } 112 root() const113 XmlNode XmlDoc::root() const 114 { 115 return xmlDocGetRootElement(mDoc); 116 } 117 getRootNamespace() const118 string XmlDoc::getRootNamespace() const 119 { 120 if (auto r = root()) 121 if (auto n = r.ns()) 122 return n.href(); 123 return ""; 124 } 125 setTempRoot(const XmlNode & node) const126 XmlDoc::TempRootMod XmlDoc::setTempRoot(const XmlNode & node) const 127 { 128 TempRootMod trm(mDoc->children); 129 mDoc->children = node.mNode; 130 mDoc->last = mDoc->children; 131 return trm; 132 } 133 TempRootMod(const XmlNode & old_root)134 XmlDoc::TempRootMod::TempRootMod(const XmlNode & old_root) 135 : mOldDocChildren(old_root.mNode->doc->children) 136 , mOldDocLast(old_root.mNode->doc->last) 137 {} 138 TempRootMod(TempRootMod && other)139 XmlDoc::TempRootMod::TempRootMod(TempRootMod && other) 140 { 141 swap(mOldDocChildren, other.mOldDocChildren); 142 swap(mOldDocLast, other.mOldDocLast); 143 } 144 ~TempRootMod()145 XmlDoc::TempRootMod::~TempRootMod() 146 { 147 // Restore old root 148 if (mOldDocChildren) 149 { 150 const XmlDoc & doc = mOldDocChildren.doc(); 151 doc.mDoc->children = mOldDocChildren.mNode; 152 doc.mDoc->last = mOldDocLast.mNode; 153 } 154 } 155 GetXmlDoc(xmlDocPtr doc)156 XmlDoc & XmlDoc::GetXmlDoc(xmlDocPtr doc) 157 { 158 return *static_cast<XmlDoc*>(doc->_private); 159 } 160 } 161