Update rapidjson-amalgamation to include error/en.h and cursorstreamwrapper.h.

Now schema validation is getting to work.
This commit is contained in:
Syoyo Fujita 2019-06-14 22:03:11 +09:00
parent f3ee08c595
commit ddf0a0e83c
4 changed files with 557 additions and 187 deletions

View File

@ -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

View File

@ -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 @@ int main(int argc, char **argv) {
} 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()) {

View File

@ -1581,7 +1581,7 @@ RAPIDJSON_NAMESPACE_END
// 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,11 @@ RAPIDJSON_NAMESPACE_END
// 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.
@ -1617,15 +1615,237 @@ RAPIDJSON_NAMESPACE_END
// 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 */
#ifndef RAPIDJSON_ERROR_ERROR_H_
#define RAPIDJSON_ERROR_ERROR_H_
// Begin file: allocators.h
// Begin file: ../rapidjson.h
// already included
// End file:allocators.h
// 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.
//
// 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_CURSORSTREAMWRAPPER_H_
#define RAPIDJSON_CURSORSTREAMWRAPPER_H_
// Begin file: stream.h
@ -2584,6 +2804,121 @@ RAPIDJSON_NAMESPACE_END
// 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 @@ RAPIDJSON_DIAG_OFF(effc++)
// 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 @@ RAPIDJSON_DIAG_POP
// Begin file: writer.h
// already included
// End file:writer.h

View File

@ -921,13 +921,13 @@ class TinyGLTF {
#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 @@ class TinyGLTF {
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 @@ namespace tinygltf {
#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 @@ std::string base64_decode(std::string const &encoded_string) {
#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 @@ bool TinyGLTF::LoadFromString(Model *model, std::string *err, std::string *warn,
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 @@ bool TinyGLTF::LoadFromString(Model *model, std::string *err, std::string *warn,
}
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 @@ bool TinyGLTF::LoadASCIIFromString(Model *model, std::string *err,
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 @@ bool TinyGLTF::LoadASCIIFromFile(Model *model, std::string *err,
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,