/* Open Asset Import Library (assimp) ---------------------------------------------------------------------- Copyright (c) 2006-2018, assimp team All rights reserved. Redistribution and use of this software in source and binary forms, with or without modification, are permitted provided that the following conditions are met: * Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer. * Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the following disclaimer in the documentation and/or other materials provided with the distribution. * Neither the name of the assimp team, nor the names of its contributors may be used to endorse or promote products derived from this software without specific prior written permission of the assimp team. THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. ---------------------------------------------------------------------- */ /// \file FIReader.cpp /// \brief Reader for Fast Infoset encoded binary XML files. /// \date 2017 /// \author Patrick Daehne #ifndef ASSIMP_BUILD_NO_X3D_IMPORTER #include "FIReader.hpp" #include // Workaround for issue #1361 // https://github.com/assimp/assimp/issues/1361 #ifdef __ANDROID__ # define _GLIBCXX_USE_C99 1 #endif #include #include #include #include #include #include "../contrib/utf8cpp/source/utf8.h" #include #include #include #include #include #include namespace Assimp { static const std::string parseErrorMessage = "Fast Infoset parse error"; static const char *xmlDeclarations[] = { "", "", "", "", "", "", "", "", "" }; static size_t parseMagic(const uint8_t *data, const uint8_t *dataEnd) { if (dataEnd - data < 4) { return 0; } uint32_t magic = (data[0] << 24) | (data[1] << 16) | (data[2] << 8) | data[3]; switch (magic) { case 0xe0000001: return 4; case 0x3c3f786d: // "= xmlDeclarationLength) && (memcmp(xmlDeclaration, data, xmlDeclarationLength) == 0)) { data += xmlDeclarationLength; if (dataEnd - data < 4) { return 0; } magic = (data[0] << 24) | (data[1] << 16) | (data[2] << 8) | data[3]; return magic == 0xe0000001 ? xmlDeclarationLength + 4 : 0; } } return 0; } default: return 0; } } static std::string parseUTF8String(const uint8_t *data, size_t len) { return std::string((char*)data, len); } static std::string parseUTF16String(const uint8_t *data, size_t len) { if (len & 1) { throw DeadlyImportError(parseErrorMessage); } size_t numShorts = len / 2; std::vector utf16; utf16.reserve(numShorts); for (size_t i = 0; i < numShorts; ++i) { short v = (data[0] << 8) | data[1]; utf16.push_back(v); data += 2; } std::string result; utf8::utf16to8(utf16.begin(), utf16.end(), back_inserter(result)); return result; } struct FIStringValueImpl: public FIStringValue { inline FIStringValueImpl(std::string &&value_) { value = std::move(value_); } virtual const std::string &toString() const /*override*/ { return value; } }; std::shared_ptr FIStringValue::create(std::string &&value) { return std::make_shared(std::move(value)); } struct FIHexValueImpl: public FIHexValue { mutable std::string strValue; mutable bool strValueValid; inline FIHexValueImpl(std::vector &&value_): strValueValid(false) { value = std::move(value_); } virtual const std::string &toString() const /*override*/ { if (!strValueValid) { strValueValid = true; std::ostringstream os; os << std::hex << std::uppercase << std::setfill('0'); std::for_each(value.begin(), value.end(), [&](uint8_t c) { os << std::setw(2) << static_cast(c); }); strValue = os.str(); } return strValue; }; }; std::shared_ptr FIHexValue::create(std::vector &&value) { return std::make_shared(std::move(value)); } struct FIBase64ValueImpl: public FIBase64Value { mutable std::string strValue; mutable bool strValueValid; inline FIBase64ValueImpl(std::vector &&value_): strValueValid(false) { value = std::move(value_); } virtual const std::string &toString() const /*override*/ { if (!strValueValid) { strValueValid = true; std::ostringstream os; uint8_t c1 = 0, c2; int imod3 = 0; std::vector::size_type valueSize = value.size(); for (std::vector::size_type i = 0; i < valueSize; ++i) { c2 = value[i]; switch (imod3) { case 0: os << basis_64[c2 >> 2]; imod3 = 1; break; case 1: os << basis_64[((c1 & 0x03) << 4) | ((c2 & 0xf0) >> 4)]; imod3 = 2; break; case 2: os << basis_64[((c1 & 0x0f) << 2) | ((c2 & 0xc0) >> 6)] << basis_64[c2 & 0x3f]; imod3 = 0; break; } c1 = c2; } switch (imod3) { case 1: os << basis_64[(c1 & 0x03) << 4] << "=="; break; case 2: os << basis_64[(c1 & 0x0f) << 2] << '='; break; } strValue = os.str(); } return strValue; }; static const char basis_64[]; }; const char FIBase64ValueImpl::basis_64[] = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/"; std::shared_ptr FIBase64Value::create(std::vector &&value) { return std::make_shared(std::move(value)); } struct FIShortValueImpl: public FIShortValue { mutable std::string strValue; mutable bool strValueValid; inline FIShortValueImpl(std::vector &&value_): strValueValid(false) { value = std::move(value_); } virtual const std::string &toString() const /*override*/ { if (!strValueValid) { strValueValid = true; std::ostringstream os; int n = 0; std::for_each(value.begin(), value.end(), [&](int16_t s) { if (++n > 1) os << ' '; os << s; }); strValue = os.str(); } return strValue; } }; std::shared_ptr FIShortValue::create(std::vector &&value) { return std::make_shared(std::move(value)); } struct FIIntValueImpl: public FIIntValue { mutable std::string strValue; mutable bool strValueValid; inline FIIntValueImpl(std::vector &&value_): strValueValid(false) { value = std::move(value_); } virtual const std::string &toString() const /*override*/ { if (!strValueValid) { strValueValid = true; std::ostringstream os; int n = 0; std::for_each(value.begin(), value.end(), [&](int32_t i) { if (++n > 1) os << ' '; os << i; }); strValue = os.str(); } return strValue; }; }; std::shared_ptr FIIntValue::create(std::vector &&value) { return std::make_shared(std::move(value)); } struct FILongValueImpl: public FILongValue { mutable std::string strValue; mutable bool strValueValid; inline FILongValueImpl(std::vector &&value_): strValueValid(false) { value = std::move(value_); } virtual const std::string &toString() const /*override*/ { if (!strValueValid) { strValueValid = true; std::ostringstream os; int n = 0; std::for_each(value.begin(), value.end(), [&](int64_t l) { if (++n > 1) os << ' '; os << l; }); strValue = os.str(); } return strValue; }; }; std::shared_ptr FILongValue::create(std::vector &&value) { return std::make_shared(std::move(value)); } struct FIBoolValueImpl: public FIBoolValue { mutable std::string strValue; mutable bool strValueValid; inline FIBoolValueImpl(std::vector &&value_): strValueValid(false) { value = std::move(value_); } virtual const std::string &toString() const /*override*/ { if (!strValueValid) { strValueValid = true; std::ostringstream os; os << std::boolalpha; int n = 0; std::for_each(value.begin(), value.end(), [&](bool b) { if (++n > 1) os << ' '; os << b; }); strValue = os.str(); } return strValue; }; }; std::shared_ptr FIBoolValue::create(std::vector &&value) { return std::make_shared(std::move(value)); } struct FIFloatValueImpl: public FIFloatValue { mutable std::string strValue; mutable bool strValueValid; inline FIFloatValueImpl(std::vector &&value_): strValueValid(false) { value = std::move(value_); } virtual const std::string &toString() const /*override*/ { if (!strValueValid) { strValueValid = true; std::ostringstream os; int n = 0; std::for_each(value.begin(), value.end(), [&](float f) { if (++n > 1) os << ' '; os << f; }); strValue = os.str(); } return strValue; } }; std::shared_ptr FIFloatValue::create(std::vector &&value) { return std::make_shared(std::move(value)); } struct FIDoubleValueImpl: public FIDoubleValue { mutable std::string strValue; mutable bool strValueValid; inline FIDoubleValueImpl(std::vector &&value_): strValueValid(false) { value = std::move(value_); } virtual const std::string &toString() const /*override*/ { if (!strValueValid) { strValueValid = true; std::ostringstream os; int n = 0; std::for_each(value.begin(), value.end(), [&](double d) { if (++n > 1) os << ' '; os << d; }); strValue = os.str(); } return strValue; } }; std::shared_ptr FIDoubleValue::create(std::vector &&value) { return std::make_shared(std::move(value)); } struct FIUUIDValueImpl: public FIUUIDValue { mutable std::string strValue; mutable bool strValueValid; inline FIUUIDValueImpl(std::vector &&value_): strValueValid(false) { value = std::move(value_); } virtual const std::string &toString() const /*override*/ { if (!strValueValid) { strValueValid = true; std::ostringstream os; os << std::hex << std::uppercase << std::setfill('0'); std::vector::size_type valueSize = value.size(); for (std::vector::size_type i = 0; i < valueSize; ++i) { switch (i & 15) { case 0: if (i > 0) { os << ' '; } os << std::setw(2) << static_cast(value[i]); break; case 4: case 6: case 8: case 10: os << '-'; // intentionally fall through! case 1: case 2: case 3: case 5: case 7: case 9: case 11: case 12: case 13: case 14: case 15: os << std::setw(2) << static_cast(value[i]); break; } } strValue = os.str(); } return strValue; }; }; std::shared_ptr FIUUIDValue::create(std::vector &&value) { return std::make_shared(std::move(value)); } struct FICDATAValueImpl: public FICDATAValue { inline FICDATAValueImpl(std::string &&value_) { value = std::move(value_); } virtual const std::string &toString() const /*override*/ { return value; } }; std::shared_ptr FICDATAValue::create(std::string &&value) { return std::make_shared(std::move(value)); } struct FIHexDecoder: public FIDecoder { virtual std::shared_ptr decode(const uint8_t *data, size_t len) /*override*/ { return FIHexValue::create(std::vector(data, data + len)); } }; struct FIBase64Decoder: public FIDecoder { virtual std::shared_ptr decode(const uint8_t *data, size_t len) /*override*/ { return FIBase64Value::create(std::vector(data, data + len)); } }; struct FIShortDecoder: public FIDecoder { virtual std::shared_ptr decode(const uint8_t *data, size_t len) /*override*/ { if (len & 1) { throw DeadlyImportError(parseErrorMessage); } std::vector value; size_t numShorts = len / 2; value.reserve(numShorts); for (size_t i = 0; i < numShorts; ++i) { int16_t v = (data[0] << 8) | data[1]; value.push_back(v); data += 2; } return FIShortValue::create(std::move(value)); } }; struct FIIntDecoder: public FIDecoder { virtual std::shared_ptr decode(const uint8_t *data, size_t len) /*override*/ { if (len & 3) { throw DeadlyImportError(parseErrorMessage); } std::vector value; size_t numInts = len / 4; value.reserve(numInts); for (size_t i = 0; i < numInts; ++i) { int32_t v = (data[0] << 24) | (data[1] << 16) | (data[2] << 8) | data[3]; value.push_back(v); data += 4; } return FIIntValue::create(std::move(value)); } }; struct FILongDecoder: public FIDecoder { virtual std::shared_ptr decode(const uint8_t *data, size_t len) /*override*/ { if (len & 7) { throw DeadlyImportError(parseErrorMessage); } std::vector value; size_t numLongs = len / 8; value.reserve(numLongs); for (size_t i = 0; i < numLongs; ++i) { int64_t b0 = data[0], b1 = data[1], b2 = data[2], b3 = data[3], b4 = data[4], b5 = data[5], b6 = data[6], b7 = data[7]; int64_t v = (b0 << 56) | (b1 << 48) | (b2 << 40) | (b3 << 32) | (b4 << 24) | (b5 << 16) | (b6 << 8) | b7; value.push_back(v); data += 8; } return FILongValue::create(std::move(value)); } }; struct FIBoolDecoder: public FIDecoder { virtual std::shared_ptr decode(const uint8_t *data, size_t len) /*override*/ { if (len < 1) { throw DeadlyImportError(parseErrorMessage); } std::vector value; uint8_t b = *data++; size_t unusedBits = b >> 4; size_t numBools = (len * 8) - 4 - unusedBits; value.reserve(numBools); uint8_t mask = 1 << 3; for (size_t i = 0; i < numBools; ++i) { if (!mask) { mask = 1 << 7; b = *data++; } value.push_back((b & mask) != 0); } return FIBoolValue::create(std::move(value)); } }; struct FIFloatDecoder: public FIDecoder { virtual std::shared_ptr decode(const uint8_t *data, size_t len) /*override*/ { if (len & 3) { throw DeadlyImportError(parseErrorMessage); } std::vector value; size_t numFloats = len / 4; value.reserve(numFloats); for (size_t i = 0; i < numFloats; ++i) { int v = (data[0] << 24) | (data[1] << 16) | (data[2] << 8) | data[3]; float f; memcpy(&f, &v, 4); value.push_back(f); data += 4; } return FIFloatValue::create(std::move(value)); } }; struct FIDoubleDecoder: public FIDecoder { virtual std::shared_ptr decode(const uint8_t *data, size_t len) /*override*/ { if (len & 7) { throw DeadlyImportError(parseErrorMessage); } std::vector value; size_t numDoubles = len / 8; value.reserve(numDoubles); for (size_t i = 0; i < numDoubles; ++i) { long long b0 = data[0], b1 = data[1], b2 = data[2], b3 = data[3], b4 = data[4], b5 = data[5], b6 = data[6], b7 = data[7]; long long v = (b0 << 56) | (b1 << 48) | (b2 << 40) | (b3 << 32) | (b4 << 24) | (b5 << 16) | (b6 << 8) | b7; double f; memcpy(&f, &v, 8); value.push_back(f); data += 8; } return FIDoubleValue::create(std::move(value)); } }; struct FIUUIDDecoder: public FIDecoder { virtual std::shared_ptr decode(const uint8_t *data, size_t len) /*override*/ { if (len & 15) { throw DeadlyImportError(parseErrorMessage); } return FIUUIDValue::create(std::vector(data, data + len)); } }; struct FICDATADecoder: public FIDecoder { virtual std::shared_ptr decode(const uint8_t *data, size_t len) /*override*/ { return FICDATAValue::create(parseUTF8String(data, len)); } }; class CFIReaderImpl: public FIReader { public: CFIReaderImpl(std::unique_ptr data_, size_t size): data(std::move(data_)), dataP(data.get()), dataEnd(data.get() + size), currentNodeType(irr::io::EXN_NONE), emptyElement(false), headerPending(true), terminatorPending(false) {} virtual ~CFIReaderImpl() {} virtual bool read() /*override*/ { if (headerPending) { headerPending = false; parseHeader(); } if (terminatorPending) { terminatorPending = false; if (elementStack.empty()) { return false; } else { nodeName = elementStack.top(); elementStack.pop(); currentNodeType = nodeName.empty() ? irr::io::EXN_UNKNOWN : irr::io::EXN_ELEMENT_END; return true; } } if (dataP >= dataEnd) { return false; } uint8_t b = *dataP; if (b < 0x80) { // Element (C.2.11.2, C.3.7.2) // C.3 parseElement(); return true; } else if (b < 0xc0) { // Characters (C.3.7.5) // C.7 auto chars = parseNonIdentifyingStringOrIndex3(vocabulary.charactersTable); nodeName = chars->toString(); currentNodeType = irr::io::EXN_TEXT; return true; } else if (b < 0xe0) { if ((b & 0xfc) == 0xc4) { // DTD (C.2.11.5) // C.9 ++dataP; if (b & 0x02) { /*const std::string &systemID =*/ parseIdentifyingStringOrIndex(vocabulary.otherURITable); } if (b & 0x01) { /*const std::string &publicID =*/ parseIdentifyingStringOrIndex(vocabulary.otherURITable); } elementStack.push(EmptyString); currentNodeType = irr::io::EXN_UNKNOWN; return true; } else if ((b & 0xfc) == 0xc8) { // Unexpanded entity reference (C.3.7.4) // C.6 ++dataP; /*const std::string &name =*/ parseIdentifyingStringOrIndex(vocabulary.otherNCNameTable); if (b & 0x02) { /*const std::string &systemID =*/ parseIdentifyingStringOrIndex(vocabulary.otherURITable); } if (b & 0x01) { /*const std::string &publicID =*/ parseIdentifyingStringOrIndex(vocabulary.otherURITable); } currentNodeType = irr::io::EXN_UNKNOWN; return true; } } else if (b < 0xf0) { if (b == 0xe1) { // Processing instruction (C.2.11.3, C.3.7.3) // C.5 ++dataP; /*const std::string &target =*/ parseIdentifyingStringOrIndex(vocabulary.otherNCNameTable); if (dataEnd - dataP < 1) { throw DeadlyImportError(parseErrorMessage); } /*std::shared_ptr data =*/ parseNonIdentifyingStringOrIndex1(vocabulary.otherStringTable); currentNodeType = irr::io::EXN_UNKNOWN; return true; } else if (b == 0xe2) { // Comment (C.2.11.4, C.3.7.6) // C.8 ++dataP; if (dataEnd - dataP < 1) { throw DeadlyImportError(parseErrorMessage); } std::shared_ptr comment = parseNonIdentifyingStringOrIndex1(vocabulary.otherStringTable); nodeName = comment->toString(); currentNodeType = irr::io::EXN_COMMENT; return true; } } else { // Terminator (C.2.12, C.3.8) ++dataP; if (b == 0xff) { terminatorPending = true; } if (elementStack.empty()) { return false; } else { nodeName = elementStack.top(); elementStack.pop(); currentNodeType = nodeName.empty() ? irr::io::EXN_UNKNOWN : irr::io::EXN_ELEMENT_END; return true; } } throw DeadlyImportError(parseErrorMessage); } virtual irr::io::EXML_NODE getNodeType() const /*override*/ { return currentNodeType; } virtual int getAttributeCount() const /*override*/ { return static_cast(attributes.size()); } virtual const char* getAttributeName(int idx) const /*override*/ { if (idx < 0 || idx >= (int)attributes.size()) { return nullptr; } return attributes[idx].name.c_str(); } virtual const char* getAttributeValue(int idx) const /*override*/ { if (idx < 0 || idx >= (int)attributes.size()) { return nullptr; } return attributes[idx].value->toString().c_str(); } virtual const char* getAttributeValue(const char* name) const /*override*/ { const Attribute* attr = getAttributeByName(name); if (!attr) { return nullptr; } return attr->value->toString().c_str(); } virtual const char* getAttributeValueSafe(const char* name) const /*override*/ { const Attribute* attr = getAttributeByName(name); if (!attr) { return EmptyString.c_str(); } return attr->value->toString().c_str(); } virtual int getAttributeValueAsInt(const char* name) const /*override*/ { const Attribute* attr = getAttributeByName(name); if (!attr) { return 0; } std::shared_ptr intValue = std::dynamic_pointer_cast(attr->value); if (intValue) { return intValue->value.size() == 1 ? intValue->value.front() : 0; } return atoi(attr->value->toString().c_str()); } virtual int getAttributeValueAsInt(int idx) const /*override*/ { if (idx < 0 || idx >= (int)attributes.size()) { return 0; } std::shared_ptr intValue = std::dynamic_pointer_cast(attributes[idx].value); if (intValue) { return intValue->value.size() == 1 ? intValue->value.front() : 0; } return atoi(attributes[idx].value->toString().c_str()); } virtual float getAttributeValueAsFloat(const char* name) const /*override*/ { const Attribute* attr = getAttributeByName(name); if (!attr) { return 0; } std::shared_ptr floatValue = std::dynamic_pointer_cast(attr->value); if (floatValue) { return floatValue->value.size() == 1 ? floatValue->value.front() : 0; } return fast_atof(attr->value->toString().c_str()); } virtual float getAttributeValueAsFloat(int idx) const /*override*/ { if (idx < 0 || idx >= (int)attributes.size()) { return 0; } std::shared_ptr floatValue = std::dynamic_pointer_cast(attributes[idx].value); if (floatValue) { return floatValue->value.size() == 1 ? floatValue->value.front() : 0; } return fast_atof(attributes[idx].value->toString().c_str()); } virtual const char* getNodeName() const /*override*/ { return nodeName.c_str(); } virtual const char* getNodeData() const /*override*/ { return nodeName.c_str(); } virtual bool isEmptyElement() const /*override*/ { return emptyElement; } virtual irr::io::ETEXT_FORMAT getSourceFormat() const /*override*/ { return irr::io::ETF_UTF8; } virtual irr::io::ETEXT_FORMAT getParserFormat() const /*override*/ { return irr::io::ETF_UTF8; } virtual std::shared_ptr getAttributeEncodedValue(int idx) const /*override*/ { if (idx < 0 || idx >= (int)attributes.size()) { return nullptr; } return attributes[idx].value; } virtual std::shared_ptr getAttributeEncodedValue(const char* name) const /*override*/ { const Attribute* attr = getAttributeByName(name); if (!attr) { return nullptr; } return attr->value; } virtual void registerDecoder(const std::string &algorithmUri, std::unique_ptr decoder) /*override*/ { decoderMap[algorithmUri] = std::move(decoder); } virtual void registerVocabulary(const std::string &vocabularyUri, const FIVocabulary *vocabulary) /*override*/ { vocabularyMap[vocabularyUri] = vocabulary; } private: struct QName { std::string prefix; std::string uri; std::string name; inline QName() {} inline QName(const FIQName &qname): prefix(qname.prefix ? qname.prefix : ""), uri(qname.uri ? qname.uri : ""), name(qname.name) {} }; struct Attribute { QName qname; std::string name; std::shared_ptr value; }; struct Vocabulary { std::vector restrictedAlphabetTable; std::vector encodingAlgorithmTable; std::vector prefixTable; std::vector namespaceNameTable; std::vector localNameTable; std::vector otherNCNameTable; std::vector otherURITable; std::vector> attributeValueTable; std::vector> charactersTable; std::vector> otherStringTable; std::vector elementNameTable; std::vector attributeNameTable; Vocabulary() { prefixTable.push_back("xml"); namespaceNameTable.push_back("http://www.w3.org/XML/1998/namespace"); } }; const Attribute* getAttributeByName(const char* name) const { if (!name) { return 0; } std::string n = name; for (int i=0; i<(int)attributes.size(); ++i) { if (attributes[i].name == n) { return &attributes[i]; } } return 0; } size_t parseInt2() { // C.25 uint8_t b = *dataP++; if (!(b & 0x40)) { // x0...... (C.25.2) return b & 0x3f; } else if ((b & 0x60) == 0x40) { // x10..... ........ (C.25.3) if (dataEnd - dataP > 0) { return (((b & 0x1f) << 8) | *dataP++) + 0x40; } } else if ((b & 0x70) == 0x60) { // x110.... ........ ........ (C.25.4) if (dataEnd - dataP > 1) { size_t result = (((b & 0x0f) << 16) | (dataP[0] << 8) | dataP[1]) + 0x2040; dataP += 2; return result; } } throw DeadlyImportError(parseErrorMessage); } size_t parseInt3() { // C.27 uint8_t b = *dataP++; if (!(b & 0x20)) { // xx0..... (C.27.2) return b & 0x1f; } else if ((b & 0x38) == 0x20) { // xx100... ........ (C.27.3) if (dataEnd - dataP > 0) { return (((b & 0x07) << 8) | *dataP++) + 0x20; } } else if ((b & 0x38) == 0x28) { // xx101... ........ ........ (C.27.4) if (dataEnd - dataP > 1) { size_t result = (((b & 0x07) << 16) | (dataP[0] << 8) | dataP[1]) + 0x820; dataP += 2; return result; } } else if ((b & 0x3f) == 0x30) { // xx110000 0000.... ........ ........ (C.27.5) if ((dataEnd - dataP > 2) && !(dataP[0] & 0xf0)) { size_t result = (((dataP[0] & 0x0f) << 16) | (dataP[1] << 8) | dataP[2]) + 0x80820; dataP += 3; return result; } } throw DeadlyImportError(parseErrorMessage); } size_t parseInt4() { // C.28 uint8_t b = *dataP++; if (!(b & 0x10)) { // xxx0.... (C.28.2) return b & 0x0f; } else if ((b & 0x1c) == 0x10) { // xxx100.. ........ (C.28.3) if (dataEnd - dataP > 0) { return (((b & 0x03) << 8) | *dataP++) + 0x10; } } else if ((b & 0x1c) == 0x14) { // xxx101.. ........ ........ (C.28.4) if (dataEnd - dataP > 1) { size_t result = (((b & 0x03) << 16) | (dataP[0] << 8) | dataP[1]) + 0x410; dataP += 2; return result; } } else if ((b & 0x1f) == 0x18) { // xxx11000 0000.... ........ ........ (C.28.5) if ((dataEnd - dataP > 2) && !(dataP[0] & 0xf0)) { size_t result = (((dataP[0] & 0x0f) << 16) | (dataP[1] << 8) | dataP[2]) + 0x40410; dataP += 3; return result; } } throw DeadlyImportError(parseErrorMessage); } size_t parseSequenceLen() { // C.21 if (dataEnd - dataP > 0) { uint8_t b = *dataP++; if (b < 0x80) { // 0....... (C.21.2) return b; } else if ((b & 0xf0) == 0x80) { // 1000.... ........ ........ (C.21.3) if (dataEnd - dataP > 1) { size_t result = (((b & 0x0f) << 16) | (dataP[0] << 8) | dataP[1]) + 0x80; dataP += 2; return result; } } } throw DeadlyImportError(parseErrorMessage); } std::string parseNonEmptyOctetString2() { // C.22 // Parse the length of the string uint8_t b = *dataP++ & 0x7f; size_t len; if (!(b & 0x40)) { // x0...... (C.22.3.1) len = b + 1; } else if (b == 0x40) { // x1000000 ........ (C.22.3.2) if (dataEnd - dataP < 1) { throw DeadlyImportError(parseErrorMessage); } len = *dataP++ + 0x41; } else if (b == 0x60) { // x1100000 ........ ........ ........ ........ (C.22.3.3) if (dataEnd - dataP < 4) { throw DeadlyImportError(parseErrorMessage); } len = ((dataP[0] << 24) | (dataP[1] << 16) | (dataP[2] << 8) | dataP[3]) + 0x141; dataP += 4; } else { throw DeadlyImportError(parseErrorMessage); } // Parse the string (C.22.4) if (dataEnd - dataP < static_cast(len)) { throw DeadlyImportError(parseErrorMessage); } std::string s = parseUTF8String(dataP, len); dataP += len; return s; } size_t parseNonEmptyOctetString5Length() { // C.23 // Parse the length of the string size_t b = *dataP++ & 0x0f; if (!(b & 0x08)) { // xxxx0... (C.23.3.1) return b + 1; } else if (b == 0x08) { // xxxx1000 ........ (C.23.3.2) if (dataEnd - dataP > 0) { return *dataP++ + 0x09; } } else if (b == 0x0c) { // xxxx1100 ........ ........ ........ ........ (C.23.3.3) if (dataEnd - dataP > 3) { size_t result = ((dataP[0] << 24) | (dataP[1] << 16) | (dataP[2] << 8) | dataP[3]) + 0x109; dataP += 4; return result; } } throw DeadlyImportError(parseErrorMessage); } size_t parseNonEmptyOctetString7Length() { // C.24 // Parse the length of the string size_t b = *dataP++ & 0x03; if (!(b & 0x02)) { // xxxxxx0. (C.24.3.1) return b + 1; } else if (b == 0x02) { // xxxxxx10 ........ (C.24.3.2) if (dataEnd - dataP > 0) { return *dataP++ + 0x3; } } else if (b == 0x03) { // xxxxxx11 ........ ........ ........ ........ (C.24.3.3) if (dataEnd - dataP > 3) { size_t result = ((dataP[0] << 24) | (dataP[1] << 16) | (dataP[2] << 8) | dataP[3]) + 0x103; dataP += 4; return result; } } throw DeadlyImportError(parseErrorMessage); } std::shared_ptr parseEncodedData(size_t index, size_t len) { if (index < 32) { FIDecoder *decoder = defaultDecoder[index]; if (!decoder) { throw DeadlyImportError("Invalid encoding algorithm index " + to_string(index)); } return decoder->decode(dataP, len); } else { if (index - 32 >= vocabulary.encodingAlgorithmTable.size()) { throw DeadlyImportError("Invalid encoding algorithm index " + to_string(index)); } std::string uri = vocabulary.encodingAlgorithmTable[index - 32]; auto it = decoderMap.find(uri); if (it == decoderMap.end()) { throw DeadlyImportError("Unsupported encoding algorithm " + uri); } else { return it->second->decode(dataP, len); } } } std::shared_ptr parseRestrictedAlphabet(size_t index, size_t len) { std::string alphabet; if (index < 16) { switch (index) { case 0: // numeric alphabet = "0123456789-+.e "; break; case 1: // date and time alphabet = "0123456789-:TZ "; break; default: throw DeadlyImportError("Invalid restricted alphabet index " + to_string(index)); } } else { if (index - 16 >= vocabulary.restrictedAlphabetTable.size()) { throw DeadlyImportError("Invalid restricted alphabet index " + to_string(index)); } alphabet = vocabulary.restrictedAlphabetTable[index - 16]; } std::vector alphabetUTF32; utf8::utf8to32(alphabet.begin(), alphabet.end(), back_inserter(alphabetUTF32)); std::string::size_type alphabetLength = alphabetUTF32.size(); if (alphabetLength < 2) { throw DeadlyImportError("Invalid restricted alphabet length " + to_string(alphabetLength)); } std::string::size_type bitsPerCharacter = 1; while ((1ull << bitsPerCharacter) <= alphabetLength) { ++bitsPerCharacter; } size_t bitsAvail = 0; uint8_t mask = (1 << bitsPerCharacter) - 1; uint32_t bits = 0; std::string s; for (size_t i = 0; i < len; ++i) { bits = (bits << 8) | dataP[i]; bitsAvail += 8; while (bitsAvail >= bitsPerCharacter) { bitsAvail -= bitsPerCharacter; size_t charIndex = (bits >> bitsAvail) & mask; if (charIndex < alphabetLength) { s.push_back(alphabetUTF32[charIndex]); } else if (charIndex != mask) { throw DeadlyImportError(parseErrorMessage); } } } return FIStringValue::create(std::move(s)); } std::shared_ptr parseEncodedCharacterString3() { // C.19 std::shared_ptr result; size_t len; uint8_t b = *dataP; if (b & 0x20) { ++dataP; if (dataEnd - dataP < 1) { throw DeadlyImportError(parseErrorMessage); } size_t index = ((b & 0x0f) << 4) | ((*dataP & 0xf0) >> 4); // C.29 len = parseNonEmptyOctetString5Length(); if (dataEnd - dataP < static_cast(len)) { throw DeadlyImportError(parseErrorMessage); } if (b & 0x10) { // encoding algorithm (C.19.3.4) result = parseEncodedData(index, len); } else { // Restricted alphabet (C.19.3.3) result = parseRestrictedAlphabet(index, len); } } else { len = parseNonEmptyOctetString5Length(); if (dataEnd - dataP < static_cast(len)) { throw DeadlyImportError(parseErrorMessage); } if (b & 0x10) { // UTF-16 (C.19.3.2) if (len & 1) { throw DeadlyImportError(parseErrorMessage); } result = FIStringValue::create(parseUTF16String(dataP, len)); } else { // UTF-8 (C.19.3.1) result = FIStringValue::create(parseUTF8String(dataP, len)); } } dataP += len; return result; } std::shared_ptr parseEncodedCharacterString5() { // C.20 std::shared_ptr result; size_t len; uint8_t b = *dataP; if (b & 0x08) { ++dataP; if (dataEnd - dataP < 1) { throw DeadlyImportError(parseErrorMessage); } size_t index = ((b & 0x03) << 6) | ((*dataP & 0xfc) >> 2); /* C.29 */ len = parseNonEmptyOctetString7Length(); if (dataEnd - dataP < static_cast(len)) { throw DeadlyImportError(parseErrorMessage); } if (b & 0x04) { // encoding algorithm (C.20.3.4) result = parseEncodedData(index, len); } else { // Restricted alphabet (C.20.3.3) result = parseRestrictedAlphabet(index, len); } } else { len = parseNonEmptyOctetString7Length(); if (dataEnd - dataP < static_cast(len)) { throw DeadlyImportError(parseErrorMessage); } if (b & 0x04) { // UTF-16 (C.20.3.2) if (len & 1) { throw DeadlyImportError(parseErrorMessage); } result = FIStringValue::create(parseUTF16String(dataP, len)); } else { // UTF-8 (C.20.3.1) result = FIStringValue::create(parseUTF8String(dataP, len)); } } dataP += len; return result; } const std::string &parseIdentifyingStringOrIndex(std::vector &stringTable) { // C.13 if (dataEnd - dataP < 1) { throw DeadlyImportError(parseErrorMessage); } uint8_t b = *dataP; if (b & 0x80) { // We have an index (C.13.4) size_t index = parseInt2(); if (index >= stringTable.size()) { throw DeadlyImportError(parseErrorMessage); } return stringTable[index]; } else { // We have a string (C.13.3) stringTable.push_back(parseNonEmptyOctetString2()); return stringTable.back(); } } QName parseNameSurrogate() { // C.16 if (dataEnd - dataP < 1) { throw DeadlyImportError(parseErrorMessage); } uint8_t b = *dataP++; if (b & 0xfc) { // Padding '000000' C.2.5.5 throw DeadlyImportError(parseErrorMessage); } QName result; size_t index; if (b & 0x02) { // prefix (C.16.3) if ((dataEnd - dataP < 1) || (*dataP & 0x80)) { throw DeadlyImportError(parseErrorMessage); } index = parseInt2(); if (index >= vocabulary.prefixTable.size()) { throw DeadlyImportError(parseErrorMessage); } result.prefix = vocabulary.prefixTable[index]; } if (b & 0x01) { // namespace-name (C.16.4) if ((dataEnd - dataP < 1) || (*dataP & 0x80)) { throw DeadlyImportError(parseErrorMessage); } index = parseInt2(); if (index >= vocabulary.namespaceNameTable.size()) { throw DeadlyImportError(parseErrorMessage); } result.uri = vocabulary.namespaceNameTable[index]; } // local-name if ((dataEnd - dataP < 1) || (*dataP & 0x80)) { throw DeadlyImportError(parseErrorMessage); } index = parseInt2(); if (index >= vocabulary.localNameTable.size()) { throw DeadlyImportError(parseErrorMessage); } result.name = vocabulary.localNameTable[index]; return result; } const QName &parseQualifiedNameOrIndex2(std::vector &qNameTable) { // C.17 uint8_t b = *dataP; if ((b & 0x7c) == 0x78) { // x11110.. // We have a literal (C.17.3) ++dataP; QName result; // prefix (C.17.3.1) result.prefix = b & 0x02 ? parseIdentifyingStringOrIndex(vocabulary.prefixTable) : std::string(); // namespace-name (C.17.3.1) result.uri = b & 0x01 ? parseIdentifyingStringOrIndex(vocabulary.namespaceNameTable) : std::string(); // local-name result.name = parseIdentifyingStringOrIndex(vocabulary.localNameTable); qNameTable.push_back(result); return qNameTable.back(); } else { // We have an index (C.17.4) size_t index = parseInt2(); if (index >= qNameTable.size()) { throw DeadlyImportError(parseErrorMessage); } return qNameTable[index]; } } const QName &parseQualifiedNameOrIndex3(std::vector &qNameTable) { // C.18 uint8_t b = *dataP; if ((b & 0x3c) == 0x3c) { // xx1111.. // We have a literal (C.18.3) ++dataP; QName result; // prefix (C.18.3.1) result.prefix = b & 0x02 ? parseIdentifyingStringOrIndex(vocabulary.prefixTable) : std::string(); // namespace-name (C.18.3.1) result.uri = b & 0x01 ? parseIdentifyingStringOrIndex(vocabulary.namespaceNameTable) : std::string(); // local-name result.name = parseIdentifyingStringOrIndex(vocabulary.localNameTable); qNameTable.push_back(result); return qNameTable.back(); } else { // We have an index (C.18.4) size_t index = parseInt3(); if (index >= qNameTable.size()) { throw DeadlyImportError(parseErrorMessage); } return qNameTable[index]; } } std::shared_ptr parseNonIdentifyingStringOrIndex1(std::vector> &valueTable) { // C.14 uint8_t b = *dataP; if (b == 0xff) { // C.26.2 // empty string ++dataP; return EmptyFIString; } else if (b & 0x80) { // C.14.4 // We have an index size_t index = parseInt2(); if (index >= valueTable.size()) { throw DeadlyImportError(parseErrorMessage); } return valueTable[index]; } else { // C.14.3 // We have a literal std::shared_ptr result = parseEncodedCharacterString3(); if (b & 0x40) { // C.14.3.1 valueTable.push_back(result); } return result; } } std::shared_ptr parseNonIdentifyingStringOrIndex3(std::vector> &valueTable) { // C.15 uint8_t b = *dataP; if (b & 0x20) { // C.15.4 // We have an index size_t index = parseInt4(); if (index >= valueTable.size()) { throw DeadlyImportError(parseErrorMessage); } return valueTable[index]; } else { // C.15.3 // We have a literal std::shared_ptr result = parseEncodedCharacterString5(); if (b & 0x10) { // C.15.3.1 valueTable.push_back(result); } return result; } } void parseElement() { // C.3 attributes.clear(); uint8_t b = *dataP; bool hasAttributes = (b & 0x40) != 0; // C.3.3 if ((b & 0x3f) == 0x38) { // C.3.4.1 // Parse namespaces ++dataP; for (;;) { if (dataEnd - dataP < 1) { throw DeadlyImportError(parseErrorMessage); } b = *dataP++; if (b == 0xf0) { // C.3.4.3 break; } if ((b & 0xfc) != 0xcc) { // C.3.4.2 throw DeadlyImportError(parseErrorMessage); } // C.12 Attribute attr; attr.qname.prefix = "xmlns"; attr.qname.name = b & 0x02 ? parseIdentifyingStringOrIndex(vocabulary.prefixTable) : std::string(); attr.qname.uri = b & 0x01 ? parseIdentifyingStringOrIndex(vocabulary.namespaceNameTable) : std::string(); attr.name = attr.qname.name.empty() ? "xmlns" : "xmlns:" + attr.qname.name; attr.value = FIStringValue::create(std::string(attr.qname.uri)); attributes.push_back(attr); } if ((dataEnd - dataP < 1) || (*dataP & 0xc0)) { throw DeadlyImportError(parseErrorMessage); } } // Parse Element name (C.3.5) const QName &elemName = parseQualifiedNameOrIndex3(vocabulary.elementNameTable); nodeName = elemName.prefix.empty() ? elemName.name : elemName.prefix + ':' + elemName.name; if (hasAttributes) { for (;;) { if (dataEnd - dataP < 1) { throw DeadlyImportError(parseErrorMessage); } b = *dataP; if (b < 0x80) { // C.3.6.1 // C.4 Attribute attr; attr.qname = parseQualifiedNameOrIndex2(vocabulary.attributeNameTable); attr.name = attr.qname.prefix.empty() ? attr.qname.name : attr.qname.prefix + ':' + attr.qname.name; if (dataEnd - dataP < 1) { throw DeadlyImportError(parseErrorMessage); } attr.value = parseNonIdentifyingStringOrIndex1(vocabulary.attributeValueTable); attributes.push_back(attr); } else { if ((b & 0xf0) != 0xf0) { // C.3.6.2 throw DeadlyImportError(parseErrorMessage); } emptyElement = b == 0xff; // C.3.6.2, C.3.8 ++dataP; break; } } } else { if (dataEnd - dataP < 1) { throw DeadlyImportError(parseErrorMessage); } b = *dataP; switch (b) { case 0xff: terminatorPending = true; // Intentionally fall through case 0xf0: emptyElement = true; ++dataP; break; default: emptyElement = false; } } if (!emptyElement) { elementStack.push(nodeName); } currentNodeType = irr::io::EXN_ELEMENT; } void parseHeader() { // Parse header (C.1.3) size_t magicSize = parseMagic(dataP, dataEnd); if (!magicSize) { throw DeadlyImportError(parseErrorMessage); } dataP += magicSize; // C.2.3 if (dataEnd - dataP < 1) { throw DeadlyImportError(parseErrorMessage); } uint8_t b = *dataP++; if (b & 0x40) { // Parse additional data (C.2.4) size_t len = parseSequenceLen(); for (size_t i = 0; i < len; ++i) { if (dataEnd - dataP < 1) { throw DeadlyImportError(parseErrorMessage); } /*std::string id =*/ parseNonEmptyOctetString2(); if (dataEnd - dataP < 1) { throw DeadlyImportError(parseErrorMessage); } /*std::string data =*/ parseNonEmptyOctetString2(); } } if (b & 0x20) { // Parse initial vocabulary (C.2.5) if (dataEnd - dataP < 2) { throw DeadlyImportError(parseErrorMessage); } uint16_t b1 = (dataP[0] << 8) | dataP[1]; dataP += 2; if (b1 & 0x1000) { // External vocabulary (C.2.5.2) if (dataEnd - dataP < 1) { throw DeadlyImportError(parseErrorMessage); } std::string uri = parseNonEmptyOctetString2(); auto it = vocabularyMap.find(uri); if (it == vocabularyMap.end()) { throw DeadlyImportError("Unknown vocabulary " + uri); } const FIVocabulary *externalVocabulary = it->second; if (externalVocabulary->restrictedAlphabetTable) { std::copy(externalVocabulary->restrictedAlphabetTable, externalVocabulary->restrictedAlphabetTable + externalVocabulary->restrictedAlphabetTableSize, std::back_inserter(vocabulary.restrictedAlphabetTable)); } if (externalVocabulary->encodingAlgorithmTable) { std::copy(externalVocabulary->encodingAlgorithmTable, externalVocabulary->encodingAlgorithmTable + externalVocabulary->encodingAlgorithmTableSize, std::back_inserter(vocabulary.encodingAlgorithmTable)); } if (externalVocabulary->prefixTable) { std::copy(externalVocabulary->prefixTable, externalVocabulary->prefixTable + externalVocabulary->prefixTableSize, std::back_inserter(vocabulary.prefixTable)); } if (externalVocabulary->namespaceNameTable) { std::copy(externalVocabulary->namespaceNameTable, externalVocabulary->namespaceNameTable + externalVocabulary->namespaceNameTableSize, std::back_inserter(vocabulary.namespaceNameTable)); } if (externalVocabulary->localNameTable) { std::copy(externalVocabulary->localNameTable, externalVocabulary->localNameTable + externalVocabulary->localNameTableSize, std::back_inserter(vocabulary.localNameTable)); } if (externalVocabulary->otherNCNameTable) { std::copy(externalVocabulary->otherNCNameTable, externalVocabulary->otherNCNameTable + externalVocabulary->otherNCNameTableSize, std::back_inserter(vocabulary.otherNCNameTable)); } if (externalVocabulary->otherURITable) { std::copy(externalVocabulary->otherURITable, externalVocabulary->otherURITable + externalVocabulary->otherURITableSize, std::back_inserter(vocabulary.otherURITable)); } if (externalVocabulary->attributeValueTable) { std::copy(externalVocabulary->attributeValueTable, externalVocabulary->attributeValueTable + externalVocabulary->attributeValueTableSize, std::back_inserter(vocabulary.attributeValueTable)); } if (externalVocabulary->charactersTable) { std::copy(externalVocabulary->charactersTable, externalVocabulary->charactersTable + externalVocabulary->charactersTableSize, std::back_inserter(vocabulary.charactersTable)); } if (externalVocabulary->otherStringTable) { std::copy(externalVocabulary->otherStringTable, externalVocabulary->otherStringTable + externalVocabulary->otherStringTableSize, std::back_inserter(vocabulary.otherStringTable)); } if (externalVocabulary->elementNameTable) { std::copy(externalVocabulary->elementNameTable, externalVocabulary->elementNameTable + externalVocabulary->elementNameTableSize, std::back_inserter(vocabulary.elementNameTable)); } if (externalVocabulary->attributeNameTable) { std::copy(externalVocabulary->attributeNameTable, externalVocabulary->attributeNameTable + externalVocabulary->attributeNameTableSize, std::back_inserter(vocabulary.attributeNameTable)); } } if (b1 & 0x0800) { // Parse restricted alphabets (C.2.5.3) for (size_t len = parseSequenceLen(); len > 0; --len) { if (dataEnd - dataP < 1) { throw DeadlyImportError(parseErrorMessage); } vocabulary.restrictedAlphabetTable.push_back(parseNonEmptyOctetString2()); } } if (b1 & 0x0400) { // Parse encoding algorithms (C.2.5.3) for (size_t len = parseSequenceLen(); len > 0; --len) { if (dataEnd - dataP < 1) { throw DeadlyImportError(parseErrorMessage); } vocabulary.encodingAlgorithmTable.push_back(parseNonEmptyOctetString2()); } } if (b1 & 0x0200) { // Parse prefixes (C.2.5.3) for (size_t len = parseSequenceLen(); len > 0; --len) { if (dataEnd - dataP < 1) { throw DeadlyImportError(parseErrorMessage); } vocabulary.prefixTable.push_back(parseNonEmptyOctetString2()); } } if (b1 & 0x0100) { // Parse namespace names (C.2.5.3) for (size_t len = parseSequenceLen(); len > 0; --len) { if (dataEnd - dataP < 1) { throw DeadlyImportError(parseErrorMessage); } vocabulary.namespaceNameTable.push_back(parseNonEmptyOctetString2()); } } if (b1 & 0x0080) { // Parse local names (C.2.5.3) for (size_t len = parseSequenceLen(); len > 0; --len) { if (dataEnd - dataP < 1) { throw DeadlyImportError(parseErrorMessage); } vocabulary.localNameTable.push_back(parseNonEmptyOctetString2()); } } if (b1 & 0x0040) { // Parse other ncnames (C.2.5.3) for (size_t len = parseSequenceLen(); len > 0; --len) { if (dataEnd - dataP < 1) { throw DeadlyImportError(parseErrorMessage); } vocabulary.otherNCNameTable.push_back(parseNonEmptyOctetString2()); } } if (b1 & 0x0020) { // Parse other uris (C.2.5.3) for (size_t len = parseSequenceLen(); len > 0; --len) { if (dataEnd - dataP < 1) { throw DeadlyImportError(parseErrorMessage); } vocabulary.otherURITable.push_back(parseNonEmptyOctetString2()); } } if (b1 & 0x0010) { // Parse attribute values (C.2.5.4) for (size_t len = parseSequenceLen(); len > 0; --len) { if (dataEnd - dataP < 1) { throw DeadlyImportError(parseErrorMessage); } vocabulary.attributeValueTable.push_back(parseEncodedCharacterString3()); } } if (b1 & 0x0008) { // Parse content character chunks (C.2.5.4) for (size_t len = parseSequenceLen(); len > 0; --len) { if (dataEnd - dataP < 1) { throw DeadlyImportError(parseErrorMessage); } vocabulary.charactersTable.push_back(parseEncodedCharacterString3()); } } if (b1 & 0x0004) { // Parse other strings (C.2.5.4) for (size_t len = parseSequenceLen(); len > 0; --len) { if (dataEnd - dataP < 1) { throw DeadlyImportError(parseErrorMessage); } vocabulary.otherStringTable.push_back(parseEncodedCharacterString3()); } } if (b1 & 0x0002) { // Parse element name surrogates (C.2.5.5) for (size_t len = parseSequenceLen(); len > 0; --len) { vocabulary.elementNameTable.push_back(parseNameSurrogate()); } } if (b1 & 0x0001) { // Parse attribute name surrogates (C.2.5.5) for (size_t len = parseSequenceLen(); len > 0; --len) { vocabulary.attributeNameTable.push_back(parseNameSurrogate()); } } } if (b & 0x10) { // Parse notations (C.2.6) for (;;) { if (dataEnd - dataP < 1) { throw DeadlyImportError(parseErrorMessage); } uint8_t b1 = *dataP++; if (b1 == 0xf0) { break; } if ((b1 & 0xfc) != 0xc0) { throw DeadlyImportError(parseErrorMessage); } /* C.11 */ /*const std::string &name =*/ parseIdentifyingStringOrIndex(vocabulary.otherNCNameTable); if (b1 & 0x02) { /*const std::string &systemId =*/ parseIdentifyingStringOrIndex(vocabulary.otherURITable); } if (b1 & 0x01) { /*const std::string &publicId =*/ parseIdentifyingStringOrIndex(vocabulary.otherURITable); } } } if (b & 0x08) { // Parse unparsed entities (C.2.7) for (;;) { if (dataEnd - dataP < 1) { throw DeadlyImportError(parseErrorMessage); } uint8_t b1 = *dataP++; if (b1 == 0xf0) { break; } if ((b1 & 0xfe) != 0xd0) { throw DeadlyImportError(parseErrorMessage); } /* C.10 */ /*const std::string &name =*/ parseIdentifyingStringOrIndex(vocabulary.otherNCNameTable); /*const std::string &systemId =*/ parseIdentifyingStringOrIndex(vocabulary.otherURITable); if (b1 & 0x01) { /*const std::string &publicId =*/ parseIdentifyingStringOrIndex(vocabulary.otherURITable); } /*const std::string ¬ationName =*/ parseIdentifyingStringOrIndex(vocabulary.otherNCNameTable); } } if (b & 0x04) { // Parse character encoding scheme (C.2.8) if (dataEnd - dataP < 1) { throw DeadlyImportError(parseErrorMessage); } /*std::string characterEncodingScheme =*/ parseNonEmptyOctetString2(); } if (b & 0x02) { // Parse standalone flag (C.2.9) if (dataEnd - dataP < 1) { throw DeadlyImportError(parseErrorMessage); } uint8_t b1 = *dataP++; if (b1 & 0xfe) { throw DeadlyImportError(parseErrorMessage); } //bool standalone = b1 & 0x01; } if (b & 0x01) { // Parse version (C.2.10) if (dataEnd - dataP < 1) { throw DeadlyImportError(parseErrorMessage); } /*std::shared_ptr version =*/ parseNonIdentifyingStringOrIndex1(vocabulary.otherStringTable); } } std::unique_ptr data; uint8_t *dataP, *dataEnd; irr::io::EXML_NODE currentNodeType; bool emptyElement; bool headerPending; bool terminatorPending; Vocabulary vocabulary; std::vector attributes; std::stack elementStack; std::string nodeName; std::map> decoderMap; std::map vocabularyMap; static const std::string EmptyString; static std::shared_ptr EmptyFIString; static FIHexDecoder hexDecoder; static FIBase64Decoder base64Decoder; static FIShortDecoder shortDecoder; static FIIntDecoder intDecoder; static FILongDecoder longDecoder; static FIBoolDecoder boolDecoder; static FIFloatDecoder floatDecoder; static FIDoubleDecoder doubleDecoder; static FIUUIDDecoder uuidDecoder; static FICDATADecoder cdataDecoder; static FIDecoder *defaultDecoder[32]; }; const std::string CFIReaderImpl::EmptyString; std::shared_ptr CFIReaderImpl::EmptyFIString = FIStringValue::create(std::string()); FIHexDecoder CFIReaderImpl::hexDecoder; FIBase64Decoder CFIReaderImpl::base64Decoder; FIShortDecoder CFIReaderImpl::shortDecoder; FIIntDecoder CFIReaderImpl::intDecoder; FILongDecoder CFIReaderImpl::longDecoder; FIBoolDecoder CFIReaderImpl::boolDecoder; FIFloatDecoder CFIReaderImpl::floatDecoder; FIDoubleDecoder CFIReaderImpl::doubleDecoder; FIUUIDDecoder CFIReaderImpl::uuidDecoder; FICDATADecoder CFIReaderImpl::cdataDecoder; FIDecoder *CFIReaderImpl::defaultDecoder[32] = { &hexDecoder, &base64Decoder, &shortDecoder, &intDecoder, &longDecoder, &boolDecoder, &floatDecoder, &doubleDecoder, &uuidDecoder, &cdataDecoder }; class CXMLReaderImpl : public FIReader { public: //! Constructor CXMLReaderImpl(std::unique_ptr> reader_) : reader(std::move(reader_)) {} virtual ~CXMLReaderImpl() {} virtual bool read() /*override*/ { return reader->read(); } virtual irr::io::EXML_NODE getNodeType() const /*override*/ { return reader->getNodeType(); } virtual int getAttributeCount() const /*override*/ { return reader->getAttributeCount(); } virtual const char* getAttributeName(int idx) const /*override*/ { return reader->getAttributeName(idx); } virtual const char* getAttributeValue(int idx) const /*override*/ { return reader->getAttributeValue(idx); } virtual const char* getAttributeValue(const char* name) const /*override*/ { return reader->getAttributeValue(name); } virtual const char* getAttributeValueSafe(const char* name) const /*override*/ { return reader->getAttributeValueSafe(name); } virtual int getAttributeValueAsInt(const char* name) const /*override*/ { return reader->getAttributeValueAsInt(name); } virtual int getAttributeValueAsInt(int idx) const /*override*/ { return reader->getAttributeValueAsInt(idx); } virtual float getAttributeValueAsFloat(const char* name) const /*override*/ { return reader->getAttributeValueAsFloat(name); } virtual float getAttributeValueAsFloat(int idx) const /*override*/ { return reader->getAttributeValueAsFloat(idx); } virtual const char* getNodeName() const /*override*/ { return reader->getNodeName(); } virtual const char* getNodeData() const /*override*/ { return reader->getNodeData(); } virtual bool isEmptyElement() const /*override*/ { return reader->isEmptyElement(); } virtual irr::io::ETEXT_FORMAT getSourceFormat() const /*override*/ { return reader->getSourceFormat(); } virtual irr::io::ETEXT_FORMAT getParserFormat() const /*override*/ { return reader->getParserFormat(); } virtual std::shared_ptr getAttributeEncodedValue(int /*idx*/) const /*override*/ { return nullptr; } virtual std::shared_ptr getAttributeEncodedValue(const char* /*name*/) const /*override*/ { return nullptr; } virtual void registerDecoder(const std::string & /*algorithmUri*/, std::unique_ptr /*decoder*/) /*override*/ {} virtual void registerVocabulary(const std::string &/*vocabularyUri*/, const FIVocabulary * /*vocabulary*/) /*override*/ {} private: std::unique_ptr> reader; }; static std::unique_ptr readFile(IOStream *stream, size_t &size, bool &isFI) { size = stream->FileSize(); std::unique_ptr data = std::unique_ptr(new uint8_t[size]); if (stream->Read(data.get(), size, 1) != 1) { size = 0; data.reset(); } isFI = parseMagic(data.get(), data.get() + size) > 0; return data; } std::unique_ptr FIReader::create(IOStream *stream) { size_t size; bool isFI; auto data = readFile(stream, size, isFI); if (isFI) { return std::unique_ptr(new CFIReaderImpl(std::move(data), size)); } else { auto memios = std::unique_ptr(new MemoryIOStream(data.release(), size, true)); auto callback = std::unique_ptr(new CIrrXML_IOStreamReader(memios.get())); return std::unique_ptr(new CXMLReaderImpl(std::unique_ptr>(createIrrXMLReader(callback.get())))); } } }// namespace Assimp #endif // !ASSIMP_BUILD_NO_X3D_IMPORTER