Update rapidjson-amalgamation to include error/en.h and cursorstreamwrapper.h.
Now schema validation is getting to work.
diff --git a/README.md b/README.md
index e085c02..7ac0e2b 100644
--- a/README.md
+++ b/README.md
@@ -70,6 +70,7 @@
## For developer
Generate single rapidjson file using this node.js script: https://github.com/Tencent/rapidjson/issues/863
+Add `cursorstreamwrapper.h` and `error/en.h` inclusion in `rapidjson-all.h` before running merge script.
## TODOs
diff --git a/loader_example.cc b/loader_example.cc
index c0eec95..6bcff91 100644
--- a/loader_example.cc
+++ b/loader_example.cc
@@ -2,6 +2,7 @@
// TODO(syoyo): Print extensions and extras for each glTF object.
//
#define TINYGLTF_IMPLEMENTATION
+#define TINYGLTF_ENABLE_SCHEMA_VALIDATOR
#define STB_IMAGE_IMPLEMENTATION
#define STB_IMAGE_WRITE_IMPLEMENTATION
#include "tiny_gltf.h"
@@ -640,8 +641,13 @@
} else {
std::cout << "Reading ASCII glTF" << std::endl;
// assume ascii glTF.
+#if defined(TINYGLTF_ENABLE_SCHEMA_VALIDATOR)
+ ret =
+ gltf_ctx.LoadASCIIFromFileWithValidation(&model, &err, &warn, input_filename.c_str());
+#else
ret =
gltf_ctx.LoadASCIIFromFile(&model, &err, &warn, input_filename.c_str());
+#endif
}
if (!warn.empty()) {
diff --git a/rapidjson-amalgamation.h b/rapidjson-amalgamation.h
index 2578092..0d15082 100644
--- a/rapidjson-amalgamation.h
+++ b/rapidjson-amalgamation.h
@@ -1581,7 +1581,7 @@
// End file:allocators.h
-// Begin file: document.h
+// Begin file: error/en.h
// Tencent is pleased to support the open source community by making RapidJSON available.
//
// Copyright (C) 2015 THL A29 Limited, a Tencent company, and Milo Yip. All rights reserved.
@@ -1596,13 +1596,240 @@
// CONDITIONS OF ANY KIND, either express or implied. See the License for the
// specific language governing permissions and limitations under the License.
-#ifndef RAPIDJSON_DOCUMENT_H_
-#define RAPIDJSON_DOCUMENT_H_
-
-/*! \file document.h */
+#ifndef RAPIDJSON_ERROR_EN_H_
+#define RAPIDJSON_ERROR_EN_H_
-// Begin file: reader.h
+// Begin file: error.h
+// Tencent is pleased to support the open source community by making RapidJSON available.
+//
+// Copyright (C) 2015 THL A29 Limited, a Tencent company, and Milo Yip. All rights reserved.
+//
+// Licensed under the MIT License (the "License"); you may not use this file except
+// in compliance with the License. You may obtain a copy of the License at
+//
+// http://opensource.org/licenses/MIT
+//
+// Unless required by applicable law or agreed to in writing, software distributed
+// under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR
+// CONDITIONS OF ANY KIND, either express or implied. See the License for the
+// specific language governing permissions and limitations under the License.
+
+#ifndef RAPIDJSON_ERROR_ERROR_H_
+#define RAPIDJSON_ERROR_ERROR_H_
+
+
+// Begin file: ../rapidjson.h
+// already included
+// End file:../rapidjson.h
+
+
+#ifdef __clang__
+RAPIDJSON_DIAG_PUSH
+RAPIDJSON_DIAG_OFF(padded)
+#endif
+
+/*! \file error.h */
+
+/*! \defgroup RAPIDJSON_ERRORS RapidJSON error handling */
+
+///////////////////////////////////////////////////////////////////////////////
+// RAPIDJSON_ERROR_CHARTYPE
+
+//! Character type of error messages.
+/*! \ingroup RAPIDJSON_ERRORS
+ The default character type is \c char.
+ On Windows, user can define this macro as \c TCHAR for supporting both
+ unicode/non-unicode settings.
+*/
+#ifndef RAPIDJSON_ERROR_CHARTYPE
+#define RAPIDJSON_ERROR_CHARTYPE char
+#endif
+
+///////////////////////////////////////////////////////////////////////////////
+// RAPIDJSON_ERROR_STRING
+
+//! Macro for converting string literial to \ref RAPIDJSON_ERROR_CHARTYPE[].
+/*! \ingroup RAPIDJSON_ERRORS
+ By default this conversion macro does nothing.
+ On Windows, user can define this macro as \c _T(x) for supporting both
+ unicode/non-unicode settings.
+*/
+#ifndef RAPIDJSON_ERROR_STRING
+#define RAPIDJSON_ERROR_STRING(x) x
+#endif
+
+RAPIDJSON_NAMESPACE_BEGIN
+
+///////////////////////////////////////////////////////////////////////////////
+// ParseErrorCode
+
+//! Error code of parsing.
+/*! \ingroup RAPIDJSON_ERRORS
+ \see GenericReader::Parse, GenericReader::GetParseErrorCode
+*/
+enum ParseErrorCode {
+ kParseErrorNone = 0, //!< No error.
+
+ kParseErrorDocumentEmpty, //!< The document is empty.
+ kParseErrorDocumentRootNotSingular, //!< The document root must not follow by other values.
+
+ kParseErrorValueInvalid, //!< Invalid value.
+
+ kParseErrorObjectMissName, //!< Missing a name for object member.
+ kParseErrorObjectMissColon, //!< Missing a colon after a name of object member.
+ kParseErrorObjectMissCommaOrCurlyBracket, //!< Missing a comma or '}' after an object member.
+
+ kParseErrorArrayMissCommaOrSquareBracket, //!< Missing a comma or ']' after an array element.
+
+ kParseErrorStringUnicodeEscapeInvalidHex, //!< Incorrect hex digit after \\u escape in string.
+ kParseErrorStringUnicodeSurrogateInvalid, //!< The surrogate pair in string is invalid.
+ kParseErrorStringEscapeInvalid, //!< Invalid escape character in string.
+ kParseErrorStringMissQuotationMark, //!< Missing a closing quotation mark in string.
+ kParseErrorStringInvalidEncoding, //!< Invalid encoding in string.
+
+ kParseErrorNumberTooBig, //!< Number too big to be stored in double.
+ kParseErrorNumberMissFraction, //!< Miss fraction part in number.
+ kParseErrorNumberMissExponent, //!< Miss exponent in number.
+
+ kParseErrorTermination, //!< Parsing was terminated.
+ kParseErrorUnspecificSyntaxError //!< Unspecific syntax error.
+};
+
+//! Result of parsing (wraps ParseErrorCode)
+/*!
+ \ingroup RAPIDJSON_ERRORS
+ \code
+ Document doc;
+ ParseResult ok = doc.Parse("[42]");
+ if (!ok) {
+ fprintf(stderr, "JSON parse error: %s (%u)",
+ GetParseError_En(ok.Code()), ok.Offset());
+ exit(EXIT_FAILURE);
+ }
+ \endcode
+ \see GenericReader::Parse, GenericDocument::Parse
+*/
+struct ParseResult {
+ //!! Unspecified boolean type
+ typedef bool (ParseResult::*BooleanType)() const;
+public:
+ //! Default constructor, no error.
+ ParseResult() : code_(kParseErrorNone), offset_(0) {}
+ //! Constructor to set an error.
+ ParseResult(ParseErrorCode code, size_t offset) : code_(code), offset_(offset) {}
+
+ //! Get the error code.
+ ParseErrorCode Code() const { return code_; }
+ //! Get the error offset, if \ref IsError(), 0 otherwise.
+ size_t Offset() const { return offset_; }
+
+ //! Explicit conversion to \c bool, returns \c true, iff !\ref IsError().
+ operator BooleanType() const { return !IsError() ? &ParseResult::IsError : NULL; }
+ //! Whether the result is an error.
+ bool IsError() const { return code_ != kParseErrorNone; }
+
+ bool operator==(const ParseResult& that) const { return code_ == that.code_; }
+ bool operator==(ParseErrorCode code) const { return code_ == code; }
+ friend bool operator==(ParseErrorCode code, const ParseResult & err) { return code == err.code_; }
+
+ bool operator!=(const ParseResult& that) const { return !(*this == that); }
+ bool operator!=(ParseErrorCode code) const { return !(*this == code); }
+ friend bool operator!=(ParseErrorCode code, const ParseResult & err) { return err != code; }
+
+ //! Reset error code.
+ void Clear() { Set(kParseErrorNone); }
+ //! Update error code and offset.
+ void Set(ParseErrorCode code, size_t offset = 0) { code_ = code; offset_ = offset; }
+
+private:
+ ParseErrorCode code_;
+ size_t offset_;
+};
+
+//! Function pointer type of GetParseError().
+/*! \ingroup RAPIDJSON_ERRORS
+
+ This is the prototype for \c GetParseError_X(), where \c X is a locale.
+ User can dynamically change locale in runtime, e.g.:
+\code
+ GetParseErrorFunc GetParseError = GetParseError_En; // or whatever
+ const RAPIDJSON_ERROR_CHARTYPE* s = GetParseError(document.GetParseErrorCode());
+\endcode
+*/
+typedef const RAPIDJSON_ERROR_CHARTYPE* (*GetParseErrorFunc)(ParseErrorCode);
+
+RAPIDJSON_NAMESPACE_END
+
+#ifdef __clang__
+RAPIDJSON_DIAG_POP
+#endif
+
+#endif // RAPIDJSON_ERROR_ERROR_H_
+
+// End file:error.h
+
+
+#ifdef __clang__
+RAPIDJSON_DIAG_PUSH
+RAPIDJSON_DIAG_OFF(switch-enum)
+RAPIDJSON_DIAG_OFF(covered-switch-default)
+#endif
+
+RAPIDJSON_NAMESPACE_BEGIN
+
+//! Maps error code of parsing into error message.
+/*!
+ \ingroup RAPIDJSON_ERRORS
+ \param parseErrorCode Error code obtained in parsing.
+ \return the error message.
+ \note User can make a copy of this function for localization.
+ Using switch-case is safer for future modification of error codes.
+*/
+inline const RAPIDJSON_ERROR_CHARTYPE* GetParseError_En(ParseErrorCode parseErrorCode) {
+ switch (parseErrorCode) {
+ case kParseErrorNone: return RAPIDJSON_ERROR_STRING("No error.");
+
+ case kParseErrorDocumentEmpty: return RAPIDJSON_ERROR_STRING("The document is empty.");
+ case kParseErrorDocumentRootNotSingular: return RAPIDJSON_ERROR_STRING("The document root must not be followed by other values.");
+
+ case kParseErrorValueInvalid: return RAPIDJSON_ERROR_STRING("Invalid value.");
+
+ case kParseErrorObjectMissName: return RAPIDJSON_ERROR_STRING("Missing a name for object member.");
+ case kParseErrorObjectMissColon: return RAPIDJSON_ERROR_STRING("Missing a colon after a name of object member.");
+ case kParseErrorObjectMissCommaOrCurlyBracket: return RAPIDJSON_ERROR_STRING("Missing a comma or '}' after an object member.");
+
+ case kParseErrorArrayMissCommaOrSquareBracket: return RAPIDJSON_ERROR_STRING("Missing a comma or ']' after an array element.");
+
+ case kParseErrorStringUnicodeEscapeInvalidHex: return RAPIDJSON_ERROR_STRING("Incorrect hex digit after \\u escape in string.");
+ case kParseErrorStringUnicodeSurrogateInvalid: return RAPIDJSON_ERROR_STRING("The surrogate pair in string is invalid.");
+ case kParseErrorStringEscapeInvalid: return RAPIDJSON_ERROR_STRING("Invalid escape character in string.");
+ case kParseErrorStringMissQuotationMark: return RAPIDJSON_ERROR_STRING("Missing a closing quotation mark in string.");
+ case kParseErrorStringInvalidEncoding: return RAPIDJSON_ERROR_STRING("Invalid encoding in string.");
+
+ case kParseErrorNumberTooBig: return RAPIDJSON_ERROR_STRING("Number too big to be stored in double.");
+ case kParseErrorNumberMissFraction: return RAPIDJSON_ERROR_STRING("Miss fraction part in number.");
+ case kParseErrorNumberMissExponent: return RAPIDJSON_ERROR_STRING("Miss exponent in number.");
+
+ case kParseErrorTermination: return RAPIDJSON_ERROR_STRING("Terminate parsing due to Handler error.");
+ case kParseErrorUnspecificSyntaxError: return RAPIDJSON_ERROR_STRING("Unspecific syntax error.");
+
+ default: return RAPIDJSON_ERROR_STRING("Unknown error.");
+ }
+}
+
+RAPIDJSON_NAMESPACE_END
+
+#ifdef __clang__
+RAPIDJSON_DIAG_POP
+#endif
+
+#endif // RAPIDJSON_ERROR_EN_H_
+
+// End file:error/en.h
+
+
+// Begin file: cursorstreamwrapper.h
// Tencent is pleased to support the open source community by making RapidJSON available.
//
// Copyright (C) 2015 THL A29 Limited, a Tencent company, and Milo Yip. All rights reserved.
@@ -1617,15 +1844,8 @@
// CONDITIONS OF ANY KIND, either express or implied. See the License for the
// specific language governing permissions and limitations under the License.
-#ifndef RAPIDJSON_READER_H_
-#define RAPIDJSON_READER_H_
-
-/*! \file reader.h */
-
-
-// Begin file: allocators.h
-// already included
-// End file:allocators.h
+#ifndef RAPIDJSON_CURSORSTREAMWRAPPER_H_
+#define RAPIDJSON_CURSORSTREAMWRAPPER_H_
// Begin file: stream.h
@@ -2584,6 +2804,121 @@
// End file:stream.h
+#if defined(__GNUC__)
+RAPIDJSON_DIAG_PUSH
+RAPIDJSON_DIAG_OFF(effc++)
+#endif
+
+#if defined(_MSC_VER) && _MSC_VER <= 1800
+RAPIDJSON_DIAG_PUSH
+RAPIDJSON_DIAG_OFF(4702) // unreachable code
+RAPIDJSON_DIAG_OFF(4512) // assignment operator could not be generated
+#endif
+
+RAPIDJSON_NAMESPACE_BEGIN
+
+
+//! Cursor stream wrapper for counting line and column number if error exists.
+/*!
+ \tparam InputStream Any stream that implements Stream Concept
+*/
+template <typename InputStream, typename Encoding = UTF8<> >
+class CursorStreamWrapper : public GenericStreamWrapper<InputStream, Encoding> {
+public:
+ typedef typename Encoding::Ch Ch;
+
+ CursorStreamWrapper(InputStream& is):
+ GenericStreamWrapper<InputStream, Encoding>(is), line_(1), col_(0) {}
+
+ // counting line and column number
+ Ch Take() {
+ Ch ch = this->is_.Take();
+ if(ch == '\n') {
+ line_ ++;
+ col_ = 0;
+ } else {
+ col_ ++;
+ }
+ return ch;
+ }
+
+ //! Get the error line number, if error exists.
+ size_t GetLine() const { return line_; }
+ //! Get the error column number, if error exists.
+ size_t GetColumn() const { return col_; }
+
+private:
+ size_t line_; //!< Current Line
+ size_t col_; //!< Current Column
+};
+
+#if defined(_MSC_VER) && _MSC_VER <= 1800
+RAPIDJSON_DIAG_POP
+#endif
+
+#if defined(__GNUC__)
+RAPIDJSON_DIAG_POP
+#endif
+
+RAPIDJSON_NAMESPACE_END
+
+#endif // RAPIDJSON_CURSORSTREAMWRAPPER_H_
+
+// End file:cursorstreamwrapper.h
+
+
+// Begin file: document.h
+// Tencent is pleased to support the open source community by making RapidJSON available.
+//
+// Copyright (C) 2015 THL A29 Limited, a Tencent company, and Milo Yip. All rights reserved.
+//
+// Licensed under the MIT License (the "License"); you may not use this file except
+// in compliance with the License. You may obtain a copy of the License at
+//
+// http://opensource.org/licenses/MIT
+//
+// Unless required by applicable law or agreed to in writing, software distributed
+// under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR
+// CONDITIONS OF ANY KIND, either express or implied. See the License for the
+// specific language governing permissions and limitations under the License.
+
+#ifndef RAPIDJSON_DOCUMENT_H_
+#define RAPIDJSON_DOCUMENT_H_
+
+/*! \file document.h */
+
+
+// Begin file: reader.h
+// Tencent is pleased to support the open source community by making RapidJSON available.
+//
+// Copyright (C) 2015 THL A29 Limited, a Tencent company, and Milo Yip. All rights reserved.
+//
+// Licensed under the MIT License (the "License"); you may not use this file except
+// in compliance with the License. You may obtain a copy of the License at
+//
+// http://opensource.org/licenses/MIT
+//
+// Unless required by applicable law or agreed to in writing, software distributed
+// under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR
+// CONDITIONS OF ANY KIND, either express or implied. See the License for the
+// specific language governing permissions and limitations under the License.
+
+#ifndef RAPIDJSON_READER_H_
+#define RAPIDJSON_READER_H_
+
+/*! \file reader.h */
+
+
+// Begin file: allocators.h
+// already included
+// End file:allocators.h
+
+
+// Begin file: stream.h
+// already included
+// End file:stream.h
+
+
// Begin file: encodedstream.h
// Tencent is pleased to support the open source community by making RapidJSON available.
//
@@ -4582,172 +4917,7 @@
// Begin file: error/error.h
-// Tencent is pleased to support the open source community by making RapidJSON available.
-//
-// Copyright (C) 2015 THL A29 Limited, a Tencent company, and Milo Yip. All rights reserved.
-//
-// Licensed under the MIT License (the "License"); you may not use this file except
-// in compliance with the License. You may obtain a copy of the License at
-//
-// http://opensource.org/licenses/MIT
-//
-// Unless required by applicable law or agreed to in writing, software distributed
-// under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR
-// CONDITIONS OF ANY KIND, either express or implied. See the License for the
-// specific language governing permissions and limitations under the License.
-
-#ifndef RAPIDJSON_ERROR_ERROR_H_
-#define RAPIDJSON_ERROR_ERROR_H_
-
-
-// Begin file: ../rapidjson.h
// already included
-// End file:../rapidjson.h
-
-
-#ifdef __clang__
-RAPIDJSON_DIAG_PUSH
-RAPIDJSON_DIAG_OFF(padded)
-#endif
-
-/*! \file error.h */
-
-/*! \defgroup RAPIDJSON_ERRORS RapidJSON error handling */
-
-///////////////////////////////////////////////////////////////////////////////
-// RAPIDJSON_ERROR_CHARTYPE
-
-//! Character type of error messages.
-/*! \ingroup RAPIDJSON_ERRORS
- The default character type is \c char.
- On Windows, user can define this macro as \c TCHAR for supporting both
- unicode/non-unicode settings.
-*/
-#ifndef RAPIDJSON_ERROR_CHARTYPE
-#define RAPIDJSON_ERROR_CHARTYPE char
-#endif
-
-///////////////////////////////////////////////////////////////////////////////
-// RAPIDJSON_ERROR_STRING
-
-//! Macro for converting string literial to \ref RAPIDJSON_ERROR_CHARTYPE[].
-/*! \ingroup RAPIDJSON_ERRORS
- By default this conversion macro does nothing.
- On Windows, user can define this macro as \c _T(x) for supporting both
- unicode/non-unicode settings.
-*/
-#ifndef RAPIDJSON_ERROR_STRING
-#define RAPIDJSON_ERROR_STRING(x) x
-#endif
-
-RAPIDJSON_NAMESPACE_BEGIN
-
-///////////////////////////////////////////////////////////////////////////////
-// ParseErrorCode
-
-//! Error code of parsing.
-/*! \ingroup RAPIDJSON_ERRORS
- \see GenericReader::Parse, GenericReader::GetParseErrorCode
-*/
-enum ParseErrorCode {
- kParseErrorNone = 0, //!< No error.
-
- kParseErrorDocumentEmpty, //!< The document is empty.
- kParseErrorDocumentRootNotSingular, //!< The document root must not follow by other values.
-
- kParseErrorValueInvalid, //!< Invalid value.
-
- kParseErrorObjectMissName, //!< Missing a name for object member.
- kParseErrorObjectMissColon, //!< Missing a colon after a name of object member.
- kParseErrorObjectMissCommaOrCurlyBracket, //!< Missing a comma or '}' after an object member.
-
- kParseErrorArrayMissCommaOrSquareBracket, //!< Missing a comma or ']' after an array element.
-
- kParseErrorStringUnicodeEscapeInvalidHex, //!< Incorrect hex digit after \\u escape in string.
- kParseErrorStringUnicodeSurrogateInvalid, //!< The surrogate pair in string is invalid.
- kParseErrorStringEscapeInvalid, //!< Invalid escape character in string.
- kParseErrorStringMissQuotationMark, //!< Missing a closing quotation mark in string.
- kParseErrorStringInvalidEncoding, //!< Invalid encoding in string.
-
- kParseErrorNumberTooBig, //!< Number too big to be stored in double.
- kParseErrorNumberMissFraction, //!< Miss fraction part in number.
- kParseErrorNumberMissExponent, //!< Miss exponent in number.
-
- kParseErrorTermination, //!< Parsing was terminated.
- kParseErrorUnspecificSyntaxError //!< Unspecific syntax error.
-};
-
-//! Result of parsing (wraps ParseErrorCode)
-/*!
- \ingroup RAPIDJSON_ERRORS
- \code
- Document doc;
- ParseResult ok = doc.Parse("[42]");
- if (!ok) {
- fprintf(stderr, "JSON parse error: %s (%u)",
- GetParseError_En(ok.Code()), ok.Offset());
- exit(EXIT_FAILURE);
- }
- \endcode
- \see GenericReader::Parse, GenericDocument::Parse
-*/
-struct ParseResult {
- //!! Unspecified boolean type
- typedef bool (ParseResult::*BooleanType)() const;
-public:
- //! Default constructor, no error.
- ParseResult() : code_(kParseErrorNone), offset_(0) {}
- //! Constructor to set an error.
- ParseResult(ParseErrorCode code, size_t offset) : code_(code), offset_(offset) {}
-
- //! Get the error code.
- ParseErrorCode Code() const { return code_; }
- //! Get the error offset, if \ref IsError(), 0 otherwise.
- size_t Offset() const { return offset_; }
-
- //! Explicit conversion to \c bool, returns \c true, iff !\ref IsError().
- operator BooleanType() const { return !IsError() ? &ParseResult::IsError : NULL; }
- //! Whether the result is an error.
- bool IsError() const { return code_ != kParseErrorNone; }
-
- bool operator==(const ParseResult& that) const { return code_ == that.code_; }
- bool operator==(ParseErrorCode code) const { return code_ == code; }
- friend bool operator==(ParseErrorCode code, const ParseResult & err) { return code == err.code_; }
-
- bool operator!=(const ParseResult& that) const { return !(*this == that); }
- bool operator!=(ParseErrorCode code) const { return !(*this == code); }
- friend bool operator!=(ParseErrorCode code, const ParseResult & err) { return err != code; }
-
- //! Reset error code.
- void Clear() { Set(kParseErrorNone); }
- //! Update error code and offset.
- void Set(ParseErrorCode code, size_t offset = 0) { code_ = code; offset_ = offset; }
-
-private:
- ParseErrorCode code_;
- size_t offset_;
-};
-
-//! Function pointer type of GetParseError().
-/*! \ingroup RAPIDJSON_ERRORS
-
- This is the prototype for \c GetParseError_X(), where \c X is a locale.
- User can dynamically change locale in runtime, e.g.:
-\code
- GetParseErrorFunc GetParseError = GetParseError_En; // or whatever
- const RAPIDJSON_ERROR_CHARTYPE* s = GetParseError(document.GetParseErrorCode());
-\endcode
-*/
-typedef const RAPIDJSON_ERROR_CHARTYPE* (*GetParseErrorFunc)(ParseErrorCode);
-
-RAPIDJSON_NAMESPACE_END
-
-#ifdef __clang__
-RAPIDJSON_DIAG_POP
-#endif
-
-#endif // RAPIDJSON_ERROR_ERROR_H_
-
// End file:error/error.h
@@ -16733,3 +16903,4 @@
// Begin file: writer.h
// already included
// End file:writer.h
+
diff --git a/tiny_gltf.h b/tiny_gltf.h
index 9c7a479..b702597 100644
--- a/tiny_gltf.h
+++ b/tiny_gltf.h
@@ -921,13 +921,13 @@
#pragma clang diagnostic ignored "-Wc++98-compat"
#endif
- TinyGLTF() : bin_data_(nullptr), bin_size_(0), is_binary_(false) {}
+ TinyGLTF();
#ifdef __clang__
#pragma clang diagnostic pop
#endif
- ~TinyGLTF() {}
+ ~TinyGLTF();
///
/// Loads glTF ASCII asset from a file.
@@ -1048,8 +1048,12 @@
nullptr;
#endif
void *write_image_user_data_ = reinterpret_cast<void *>(&fs);
+
+ class PImpl;
+ PImpl *pimpl_;
};
+
#ifdef __clang__
#pragma clang diagnostic pop // -Wpadded
#endif
@@ -1200,7 +1204,7 @@
#if defined(TINYGLTF_ENABLE_SCHEMA_VALIDATOR)
// Include glTF Schema as embedded C string
-#include "glTF.schema.resolved.inc"
+#include "gltf.schema.resolved.inc"
#endif
// Equals function for Value, for recursivity
@@ -1617,6 +1621,55 @@
#pragma clang diagnostic pop
#endif
+class TinyGLTF::PImpl
+{
+ public:
+
+ PImpl() {
+#if defined(TINYGLTF_ENABLE_SCHEMA_VALIDATOR)
+ validator_ = nullptr;
+#endif
+ }
+
+ ~PImpl()
+ {
+#if defined(TINYGLTF_ENABLE_SCHEMA_VALIDATOR)
+ if (schema_doc_) {
+ delete schema_doc_;
+ }
+
+ if (schema_) {
+ delete schema_;
+ }
+
+ if (validator_) {
+ delete validator_;
+ }
+
+#endif
+ }
+
+#if defined(TINYGLTF_ENABLE_SCHEMA_VALIDATOR)
+
+ std::string schema_json_string_;
+ rapidjson::Document *schema_doc_;
+ rapidjson::SchemaDocument *schema_;
+ rapidjson::SchemaValidator *validator_;
+#endif
+};
+
+
+TinyGLTF::TinyGLTF() : bin_data_(nullptr), bin_size_(0), is_binary_(false) {
+ pimpl_ = new TinyGLTF::PImpl();
+}
+
+TinyGLTF::~TinyGLTF()
+{
+ if (pimpl_) {
+ delete pimpl_;
+ }
+}
+
static bool LoadExternalFile(std::vector<unsigned char> *out, std::string *err,
std::string *warn, const std::string &filename,
const std::string &basedir, bool required,
@@ -3722,13 +3775,25 @@
return false;
}
+ // To enable error report with lines and columns,
+ // We'll use CursorStreamWrapper.
+ // https://github.com/Tencent/rapidjson/pull/1070
+ // It looks StringStream does not have a constrcutor with (str, len),
+ // so create a temporary string and ensure it ends with NULL character.
+ // although this is a bit redundant...
+ std::string in_str(str, length);
+
+ rapidjson::StringStream sis(in_str.c_str());
+
+ rapidjson::CursorStreamWrapper<rapidjson::StringStream> csw(sis);
+
rapidjson::Document v;
#if (defined(__cpp_exceptions) || defined(__EXCEPTIONS) || \
defined(_CPPUNWIND)) && \
!defined(TINYGLTF_NOEXCEPTION)
try {
- v.Parse(str);
+ v.ParseStream(csw);
} catch (const std::exception &e) {
if (err) {
@@ -3738,14 +3803,49 @@
}
if (v.HasParseError()) {
- // TODO(syoyo): Report error
+ if (err) {
+ std::stringstream ss;
+ ss << "JSON parse error: (byte offset " << v.GetErrorOffset()
+ << ", line " << csw.GetLine()
+ << ", column " << csw.GetColumn()
+ << "): " << rapidjson::GetParseError_En(v.GetParseError());
+ (*err) = ss.str();
+ }
return false;
}
#else
{
- v.Parse(str);
+ v.ParseStream(csw);
if (v.HasParseError()) {
- // TODO(syoyo): Report error
+ if (err) {
+ std::stringstream ss;
+ ss << "JSON parse error: (byte offset " << v.GetErrorOffset()
+ << ", line " << csw.GetLine()
+ << ", column " << csw.GetColumn()
+ << "): " << rapidjson::GetParseError_En(v.GetParseError());
+ (*err) = ss.str();
+ }
+ return false;
+ }
+ }
+#endif
+
+#if defined(TINYGLTF_ENABLE_SCHEMA_VALIDATOR)
+ if (pimpl_->validator_) {
+ if (!v.Accept(*(pimpl_->validator_))) {
+ // Input JSON is invalid according to the schema
+ // Output diagnostic information
+ rapidjson::StringBuffer sb;
+ pimpl_->validator_->GetInvalidSchemaPointer().StringifyUriFragment(sb);
+
+ std::stringstream ss;
+ printf("Invalid schema: %s\n", sb.GetString());
+ ss << "glTF schema validation error. Invalid keyword: " << pimpl_->validator_->GetInvalidSchemaKeyword();
+ sb.Clear();
+
+ if (err) {
+ (*err) = ss.str();
+ }
return false;
}
}
@@ -4334,6 +4434,53 @@
check_sections);
}
+#if defined(TINYGLTF_ENABLE_SCHEMA_VALIDATOR)
+bool TinyGLTF::LoadASCIIFromStringWithValidation(Model *model, std::string *err,
+ std::string *warn, const char *str,
+ unsigned int length,
+ const std::string &base_dir,
+ unsigned int check_sections) {
+ is_binary_ = false;
+ bin_data_ = nullptr;
+ bin_size_ = 0;
+
+ if (!pimpl_->validator_) {
+
+ pimpl_->schema_json_string_ = std::string();
+
+ // Construct glTF JSON schema string.
+ const size_t num_str = sizeof(kglTFSchemaStrings)/sizeof(kglTFSchemaStrings[0]);
+ for (size_t i = 0; i < num_str; i++) {
+ pimpl_->schema_json_string_ += std::string(kglTFSchemaStrings[i]);
+ }
+
+ // Validate input glTF string
+ if (pimpl_->schema_doc_) {
+ delete pimpl_->schema_doc_;
+ }
+ pimpl_->schema_doc_ = new rapidjson::Document();
+ pimpl_->schema_doc_->Parse(pimpl_->schema_json_string_.c_str(), pimpl_->schema_json_string_.size());
+
+ if (pimpl_->schema_doc_->HasParseError()) {
+ if(err) {
+ (*err) += "Internal error. Failed to parse glTF schema JSON.";
+ }
+ return false;
+ }
+
+ if (pimpl_->schema_) {
+ delete pimpl_->schema_;
+ }
+ pimpl_->schema_ = new rapidjson::SchemaDocument(*pimpl_->schema_doc_);
+
+ pimpl_->validator_ = new rapidjson::SchemaValidator(*pimpl_->schema_);
+ }
+
+ return LoadFromString(model, err, warn, str, length, base_dir,
+ check_sections);
+}
+#endif
+
bool TinyGLTF::LoadASCIIFromFile(Model *model, std::string *err,
std::string *warn, const std::string &filename,
unsigned int check_sections) {
@@ -4377,6 +4524,51 @@
return ret;
}
+#if defined(TINYGLTF_ENABLE_SCHEMA_VALIDATOR)
+bool TinyGLTF::LoadASCIIFromFileWithValidation(Model *model, std::string *err,
+ std::string *warn, const std::string &filename,
+ unsigned int check_sections) {
+ std::stringstream ss;
+
+ if (fs.ReadWholeFile == nullptr) {
+ // Programmer error, assert() ?
+ ss << "Failed to read file: " << filename
+ << ": one or more FS callback not set" << std::endl;
+ if (err) {
+ (*err) = ss.str();
+ }
+ return false;
+ }
+
+ std::vector<unsigned char> data;
+ std::string fileerr;
+ bool fileread = fs.ReadWholeFile(&data, &fileerr, filename, fs.user_data);
+ if (!fileread) {
+ ss << "Failed to read file: " << filename << ": " << fileerr << std::endl;
+ if (err) {
+ (*err) = ss.str();
+ }
+ return false;
+ }
+
+ size_t sz = data.size();
+ if (sz == 0) {
+ if (err) {
+ (*err) = "Empty file.";
+ }
+ return false;
+ }
+
+ std::string basedir = GetBaseDir(filename);
+
+ bool ret = LoadASCIIFromStringWithValidation(
+ model, err, warn, reinterpret_cast<const char *>(&data.at(0)),
+ static_cast<unsigned int>(data.size()), basedir, check_sections);
+
+ return ret;
+}
+#endif
+
bool TinyGLTF::LoadBinaryFromMemory(Model *model, std::string *err,
std::string *warn,
const unsigned char *bytes,