Merge branch 'master' into ColladaAnimationFix
commit
cb15a0d8b0
|
@ -48,7 +48,7 @@ OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||||
#include <assimp/material.h>
|
#include <assimp/material.h>
|
||||||
#include <assimp/mesh.h>
|
#include <assimp/mesh.h>
|
||||||
|
|
||||||
#include <stdint.h>
|
#include <cstdint>
|
||||||
#include <map>
|
#include <map>
|
||||||
#include <set>
|
#include <set>
|
||||||
#include <vector>
|
#include <vector>
|
||||||
|
@ -206,7 +206,8 @@ struct SemanticMappingTable {
|
||||||
std::string mMatName;
|
std::string mMatName;
|
||||||
|
|
||||||
/// List of semantic map commands, grouped by effect semantic name
|
/// List of semantic map commands, grouped by effect semantic name
|
||||||
std::map<std::string, InputSemanticMapEntry> mMap;
|
using InputSemanticMap = std::map<std::string, InputSemanticMapEntry>;
|
||||||
|
InputSemanticMap mMap;
|
||||||
|
|
||||||
/// For std::find
|
/// For std::find
|
||||||
bool operator==(const std::string &s) const {
|
bool operator==(const std::string &s) const {
|
||||||
|
|
|
@ -63,6 +63,7 @@ OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||||
namespace Assimp {
|
namespace Assimp {
|
||||||
|
|
||||||
using namespace Assimp::Formatter;
|
using namespace Assimp::Formatter;
|
||||||
|
using namespace Assimp::Collada;
|
||||||
|
|
||||||
static const aiImporterDesc desc = {
|
static const aiImporterDesc desc = {
|
||||||
"Collada Importer",
|
"Collada Importer",
|
||||||
|
@ -271,7 +272,7 @@ aiNode *ColladaLoader::BuildHierarchy(const ColladaParser &pParser, const Collad
|
||||||
node->mTransformation = pParser.CalculateResultTransform(pNode->mTransforms);
|
node->mTransformation = pParser.CalculateResultTransform(pNode->mTransforms);
|
||||||
|
|
||||||
// now resolve node instances
|
// now resolve node instances
|
||||||
std::vector<const Collada::Node *> instances;
|
std::vector<const Node*> instances;
|
||||||
ResolveNodeInstances(pParser, pNode, instances);
|
ResolveNodeInstances(pParser, pNode, instances);
|
||||||
|
|
||||||
// add children. first the *real* ones
|
// add children. first the *real* ones
|
||||||
|
@ -298,8 +299,8 @@ aiNode *ColladaLoader::BuildHierarchy(const ColladaParser &pParser, const Collad
|
||||||
|
|
||||||
// ------------------------------------------------------------------------------------------------
|
// ------------------------------------------------------------------------------------------------
|
||||||
// Resolve node instances
|
// Resolve node instances
|
||||||
void ColladaLoader::ResolveNodeInstances(const ColladaParser &pParser, const Collada::Node *pNode,
|
void ColladaLoader::ResolveNodeInstances(const ColladaParser &pParser, const Node *pNode,
|
||||||
std::vector<const Collada::Node *> &resolved) {
|
std::vector<const Node*> &resolved) {
|
||||||
// reserve enough storage
|
// reserve enough storage
|
||||||
resolved.reserve(pNode->mNodeInstances.size());
|
resolved.reserve(pNode->mNodeInstances.size());
|
||||||
|
|
||||||
|
@ -307,7 +308,7 @@ void ColladaLoader::ResolveNodeInstances(const ColladaParser &pParser, const Col
|
||||||
for (const auto &nodeInst : pNode->mNodeInstances) {
|
for (const auto &nodeInst : pNode->mNodeInstances) {
|
||||||
// find the corresponding node in the library
|
// find the corresponding node in the library
|
||||||
const ColladaParser::NodeLibrary::const_iterator itt = pParser.mNodeLibrary.find(nodeInst.mNode);
|
const ColladaParser::NodeLibrary::const_iterator itt = pParser.mNodeLibrary.find(nodeInst.mNode);
|
||||||
const Collada::Node *nd = itt == pParser.mNodeLibrary.end() ? nullptr : (*itt).second;
|
const Node *nd = itt == pParser.mNodeLibrary.end() ? nullptr : (*itt).second;
|
||||||
|
|
||||||
// FIX for http://sourceforge.net/tracker/?func=detail&aid=3054873&group_id=226462&atid=1067632
|
// FIX for http://sourceforge.net/tracker/?func=detail&aid=3054873&group_id=226462&atid=1067632
|
||||||
// need to check for both name and ID to catch all. To avoid breaking valid files,
|
// need to check for both name and ID to catch all. To avoid breaking valid files,
|
||||||
|
@ -326,13 +327,13 @@ void ColladaLoader::ResolveNodeInstances(const ColladaParser &pParser, const Col
|
||||||
|
|
||||||
// ------------------------------------------------------------------------------------------------
|
// ------------------------------------------------------------------------------------------------
|
||||||
// Resolve UV channels
|
// Resolve UV channels
|
||||||
void ColladaLoader::ApplyVertexToEffectSemanticMapping(Collada::Sampler &sampler, const Collada::SemanticMappingTable &table) {
|
void ColladaLoader::ApplyVertexToEffectSemanticMapping(Sampler &sampler, const SemanticMappingTable &table) {
|
||||||
std::map<std::string, Collada::InputSemanticMapEntry>::const_iterator it = table.mMap.find(sampler.mUVChannel);
|
SemanticMappingTable::InputSemanticMap::const_iterator it = table.mMap.find(sampler.mUVChannel);
|
||||||
if (it == table.mMap.end()) {
|
if (it == table.mMap.end()) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (it->second.mType != Collada::IT_Texcoord) {
|
if (it->second.mType != IT_Texcoord) {
|
||||||
ASSIMP_LOG_ERROR("Collada: Unexpected effect input mapping");
|
ASSIMP_LOG_ERROR("Collada: Unexpected effect input mapping");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -341,8 +342,8 @@ void ColladaLoader::ApplyVertexToEffectSemanticMapping(Collada::Sampler &sampler
|
||||||
|
|
||||||
// ------------------------------------------------------------------------------------------------
|
// ------------------------------------------------------------------------------------------------
|
||||||
// Builds lights for the given node and references them
|
// Builds lights for the given node and references them
|
||||||
void ColladaLoader::BuildLightsForNode(const ColladaParser &pParser, const Collada::Node *pNode, aiNode *pTarget) {
|
void ColladaLoader::BuildLightsForNode(const ColladaParser &pParser, const Node *pNode, aiNode *pTarget) {
|
||||||
for (const Collada::LightInstance &lid : pNode->mLights) {
|
for (const LightInstance &lid : pNode->mLights) {
|
||||||
// find the referred light
|
// find the referred light
|
||||||
ColladaParser::LightLibrary::const_iterator srcLightIt = pParser.mLightLibrary.find(lid.mLight);
|
ColladaParser::LightLibrary::const_iterator srcLightIt = pParser.mLightLibrary.find(lid.mLight);
|
||||||
if (srcLightIt == pParser.mLightLibrary.end()) {
|
if (srcLightIt == pParser.mLightLibrary.end()) {
|
||||||
|
@ -406,8 +407,8 @@ void ColladaLoader::BuildLightsForNode(const ColladaParser &pParser, const Colla
|
||||||
|
|
||||||
// ------------------------------------------------------------------------------------------------
|
// ------------------------------------------------------------------------------------------------
|
||||||
// Builds cameras for the given node and references them
|
// Builds cameras for the given node and references them
|
||||||
void ColladaLoader::BuildCamerasForNode(const ColladaParser &pParser, const Collada::Node *pNode, aiNode *pTarget) {
|
void ColladaLoader::BuildCamerasForNode(const ColladaParser &pParser, const Node *pNode, aiNode *pTarget) {
|
||||||
for (const Collada::CameraInstance &cid : pNode->mCameras) {
|
for (const CameraInstance &cid : pNode->mCameras) {
|
||||||
// find the referred light
|
// find the referred light
|
||||||
ColladaParser::CameraLibrary::const_iterator srcCameraIt = pParser.mCameraLibrary.find(cid.mCamera);
|
ColladaParser::CameraLibrary::const_iterator srcCameraIt = pParser.mCameraLibrary.find(cid.mCamera);
|
||||||
if (srcCameraIt == pParser.mCameraLibrary.end()) {
|
if (srcCameraIt == pParser.mCameraLibrary.end()) {
|
||||||
|
@ -461,15 +462,15 @@ void ColladaLoader::BuildCamerasForNode(const ColladaParser &pParser, const Coll
|
||||||
|
|
||||||
// ------------------------------------------------------------------------------------------------
|
// ------------------------------------------------------------------------------------------------
|
||||||
// Builds meshes for the given node and references them
|
// Builds meshes for the given node and references them
|
||||||
void ColladaLoader::BuildMeshesForNode(const ColladaParser &pParser, const Collada::Node *pNode, aiNode *pTarget) {
|
void ColladaLoader::BuildMeshesForNode(const ColladaParser &pParser, const Node *pNode, aiNode *pTarget) {
|
||||||
// accumulated mesh references by this node
|
// accumulated mesh references by this node
|
||||||
std::vector<size_t> newMeshRefs;
|
std::vector<size_t> newMeshRefs;
|
||||||
newMeshRefs.reserve(pNode->mMeshes.size());
|
newMeshRefs.reserve(pNode->mMeshes.size());
|
||||||
|
|
||||||
// add a mesh for each subgroup in each collada mesh
|
// add a mesh for each subgroup in each collada mesh
|
||||||
for (const Collada::MeshInstance &mid : pNode->mMeshes) {
|
for (const MeshInstance &mid : pNode->mMeshes) {
|
||||||
const Collada::Mesh *srcMesh = nullptr;
|
const Mesh *srcMesh = nullptr;
|
||||||
const Collada::Controller *srcController = nullptr;
|
const Controller *srcController = nullptr;
|
||||||
|
|
||||||
// find the referred mesh
|
// find the referred mesh
|
||||||
ColladaParser::MeshLibrary::const_iterator srcMeshIt = pParser.mMeshLibrary.find(mid.mMeshOrController);
|
ColladaParser::MeshLibrary::const_iterator srcMeshIt = pParser.mMeshLibrary.find(mid.mMeshOrController);
|
||||||
|
@ -503,7 +504,7 @@ void ColladaLoader::BuildMeshesForNode(const ColladaParser &pParser, const Colla
|
||||||
|
|
||||||
// find material assigned to this submesh
|
// find material assigned to this submesh
|
||||||
std::string meshMaterial;
|
std::string meshMaterial;
|
||||||
std::map<std::string, Collada::SemanticMappingTable>::const_iterator meshMatIt = mid.mMaterials.find(submesh.mMaterial);
|
std::map<std::string, SemanticMappingTable>::const_iterator meshMatIt = mid.mMaterials.find(submesh.mMaterial);
|
||||||
|
|
||||||
const Collada::SemanticMappingTable *table = nullptr;
|
const Collada::SemanticMappingTable *table = nullptr;
|
||||||
if (meshMatIt != mid.mMaterials.end()) {
|
if (meshMatIt != mid.mMaterials.end()) {
|
||||||
|
@ -591,15 +592,15 @@ aiMesh *ColladaLoader::findMesh(const std::string &meshid) {
|
||||||
return nullptr;
|
return nullptr;
|
||||||
}
|
}
|
||||||
|
|
||||||
for (unsigned int i = 0; i < mMeshes.size(); ++i) {
|
for (auto & mMeshe : mMeshes) {
|
||||||
if (std::string(mMeshes[i]->mName.data) == meshid) {
|
if (std::string(mMeshe->mName.data) == meshid) {
|
||||||
return mMeshes[i];
|
return mMeshe;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
for (unsigned int i = 0; i < mTargetMeshes.size(); ++i) {
|
for (auto & mTargetMeshe : mTargetMeshes) {
|
||||||
if (std::string(mTargetMeshes[i]->mName.data) == meshid) {
|
if (std::string(mTargetMeshe->mName.data) == meshid) {
|
||||||
return mTargetMeshes[i];
|
return mTargetMeshe;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -608,8 +609,8 @@ aiMesh *ColladaLoader::findMesh(const std::string &meshid) {
|
||||||
|
|
||||||
// ------------------------------------------------------------------------------------------------
|
// ------------------------------------------------------------------------------------------------
|
||||||
// Creates a mesh for the given ColladaMesh face subset and returns the newly created mesh
|
// Creates a mesh for the given ColladaMesh face subset and returns the newly created mesh
|
||||||
aiMesh *ColladaLoader::CreateMesh(const ColladaParser &pParser, const Collada::Mesh *pSrcMesh, const Collada::SubMesh &pSubMesh,
|
aiMesh *ColladaLoader::CreateMesh(const ColladaParser &pParser, const Mesh *pSrcMesh, const SubMesh &pSubMesh,
|
||||||
const Collada::Controller *pSrcController, size_t pStartVertex, size_t pStartFace) {
|
const Controller *pSrcController, size_t pStartVertex, size_t pStartFace) {
|
||||||
std::unique_ptr<aiMesh> dstMesh(new aiMesh);
|
std::unique_ptr<aiMesh> dstMesh(new aiMesh);
|
||||||
|
|
||||||
if (useColladaName) {
|
if (useColladaName) {
|
||||||
|
@ -647,7 +648,7 @@ aiMesh *ColladaLoader::CreateMesh(const ColladaParser &pParser, const Collada::M
|
||||||
std::copy(pSrcMesh->mBitangents.begin() + pStartVertex, pSrcMesh->mBitangents.begin() + pStartVertex + numVertices, dstMesh->mBitangents);
|
std::copy(pSrcMesh->mBitangents.begin() + pStartVertex, pSrcMesh->mBitangents.begin() + pStartVertex + numVertices, dstMesh->mBitangents);
|
||||||
}
|
}
|
||||||
|
|
||||||
// same for texturecoords, as many as we have
|
// same for texture coords, as many as we have
|
||||||
// empty slots are not allowed, need to pack and adjust UV indexes accordingly
|
// empty slots are not allowed, need to pack and adjust UV indexes accordingly
|
||||||
for (size_t a = 0, real = 0; a < AI_MAX_NUMBER_OF_TEXTURECOORDS; ++a) {
|
for (size_t a = 0, real = 0; a < AI_MAX_NUMBER_OF_TEXTURECOORDS; ++a) {
|
||||||
if (pSrcMesh->mTexCoords[a].size() >= pStartVertex + numVertices) {
|
if (pSrcMesh->mTexCoords[a].size() >= pStartVertex + numVertices) {
|
||||||
|
@ -687,11 +688,11 @@ aiMesh *ColladaLoader::CreateMesh(const ColladaParser &pParser, const Collada::M
|
||||||
// create morph target meshes if any
|
// create morph target meshes if any
|
||||||
std::vector<aiMesh *> targetMeshes;
|
std::vector<aiMesh *> targetMeshes;
|
||||||
std::vector<float> targetWeights;
|
std::vector<float> targetWeights;
|
||||||
Collada::MorphMethod method = Collada::Normalized;
|
Collada::MorphMethod method = Normalized;
|
||||||
|
|
||||||
for (std::map<std::string, Collada::Controller>::const_iterator it = pParser.mControllerLibrary.begin();
|
for (std::map<std::string, Controller>::const_iterator it = pParser.mControllerLibrary.begin();
|
||||||
it != pParser.mControllerLibrary.end(); ++it) {
|
it != pParser.mControllerLibrary.end(); ++it) {
|
||||||
const Collada::Controller &c = it->second;
|
const Controller &c = it->second;
|
||||||
const Collada::Mesh *baseMesh = pParser.ResolveLibraryReference(pParser.mMeshLibrary, c.mMeshId);
|
const Collada::Mesh *baseMesh = pParser.ResolveLibraryReference(pParser.mMeshLibrary, c.mMeshId);
|
||||||
|
|
||||||
if (c.mType == Collada::Morph && baseMesh->mName == pSrcMesh->mName) {
|
if (c.mType == Collada::Morph && baseMesh->mName == pSrcMesh->mName) {
|
||||||
|
@ -710,8 +711,8 @@ aiMesh *ColladaLoader::CreateMesh(const ColladaParser &pParser, const Collada::M
|
||||||
throw DeadlyImportError("target weight data must not be textual ");
|
throw DeadlyImportError("target weight data must not be textual ");
|
||||||
}
|
}
|
||||||
|
|
||||||
for (unsigned int i = 0; i < targetData.mStrings.size(); ++i) {
|
for (const auto & mString : targetData.mStrings) {
|
||||||
const Collada::Mesh *targetMesh = pParser.ResolveLibraryReference(pParser.mMeshLibrary, targetData.mStrings.at(i));
|
const Mesh *targetMesh = pParser.ResolveLibraryReference(pParser.mMeshLibrary, mString);
|
||||||
|
|
||||||
aiMesh *aimesh = findMesh(useColladaName ? targetMesh->mName : targetMesh->mId);
|
aiMesh *aimesh = findMesh(useColladaName ? targetMesh->mName : targetMesh->mId);
|
||||||
if (!aimesh) {
|
if (!aimesh) {
|
||||||
|
@ -723,12 +724,12 @@ aiMesh *ColladaLoader::CreateMesh(const ColladaParser &pParser, const Collada::M
|
||||||
}
|
}
|
||||||
targetMeshes.push_back(aimesh);
|
targetMeshes.push_back(aimesh);
|
||||||
}
|
}
|
||||||
for (unsigned int i = 0; i < weightData.mValues.size(); ++i) {
|
for (float mValue : weightData.mValues) {
|
||||||
targetWeights.push_back(weightData.mValues.at(i));
|
targetWeights.push_back(mValue);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if (targetMeshes.size() > 0 && targetWeights.size() == targetMeshes.size()) {
|
if (!targetMeshes.empty() && targetWeights.size() == targetMeshes.size()) {
|
||||||
std::vector<aiAnimMesh *> animMeshes;
|
std::vector<aiAnimMesh *> animMeshes;
|
||||||
for (unsigned int i = 0; i < targetMeshes.size(); ++i) {
|
for (unsigned int i = 0; i < targetMeshes.size(); ++i) {
|
||||||
aiMesh *targetMesh = targetMeshes.at(i);
|
aiMesh *targetMesh = targetMeshes.at(i);
|
||||||
|
@ -738,7 +739,7 @@ aiMesh *ColladaLoader::CreateMesh(const ColladaParser &pParser, const Collada::M
|
||||||
animMesh->mName = targetMesh->mName;
|
animMesh->mName = targetMesh->mName;
|
||||||
animMeshes.push_back(animMesh);
|
animMeshes.push_back(animMesh);
|
||||||
}
|
}
|
||||||
dstMesh->mMethod = (method == Collada::Relative) ? aiMorphingMethod_MORPH_RELATIVE : aiMorphingMethod_MORPH_NORMALIZED;
|
dstMesh->mMethod = (method == Relative) ? aiMorphingMethod_MORPH_RELATIVE : aiMorphingMethod_MORPH_NORMALIZED;
|
||||||
dstMesh->mAnimMeshes = new aiAnimMesh *[animMeshes.size()];
|
dstMesh->mAnimMeshes = new aiAnimMesh *[animMeshes.size()];
|
||||||
dstMesh->mNumAnimMeshes = static_cast<unsigned int>(animMeshes.size());
|
dstMesh->mNumAnimMeshes = static_cast<unsigned int>(animMeshes.size());
|
||||||
for (unsigned int i = 0; i < animMeshes.size(); ++i) {
|
for (unsigned int i = 0; i < animMeshes.size(); ++i) {
|
||||||
|
@ -762,18 +763,20 @@ aiMesh *ColladaLoader::CreateMesh(const ColladaParser &pParser, const Collada::M
|
||||||
const Collada::Accessor &weightsAcc = pParser.ResolveLibraryReference(pParser.mAccessorLibrary, pSrcController->mWeightInputWeights.mAccessor);
|
const Collada::Accessor &weightsAcc = pParser.ResolveLibraryReference(pParser.mAccessorLibrary, pSrcController->mWeightInputWeights.mAccessor);
|
||||||
const Collada::Data &weights = pParser.ResolveLibraryReference(pParser.mDataLibrary, weightsAcc.mSource);
|
const Collada::Data &weights = pParser.ResolveLibraryReference(pParser.mDataLibrary, weightsAcc.mSource);
|
||||||
|
|
||||||
if (!jointNames.mIsStringArray || jointMatrices.mIsStringArray || weights.mIsStringArray)
|
if (!jointNames.mIsStringArray || jointMatrices.mIsStringArray || weights.mIsStringArray) {
|
||||||
throw DeadlyImportError("Data type mismatch while resolving mesh joints");
|
throw DeadlyImportError("Data type mismatch while resolving mesh joints");
|
||||||
|
}
|
||||||
// sanity check: we rely on the vertex weights always coming as pairs of BoneIndex-WeightIndex
|
// sanity check: we rely on the vertex weights always coming as pairs of BoneIndex-WeightIndex
|
||||||
if (pSrcController->mWeightInputJoints.mOffset != 0 || pSrcController->mWeightInputWeights.mOffset != 1)
|
if (pSrcController->mWeightInputJoints.mOffset != 0 || pSrcController->mWeightInputWeights.mOffset != 1) {
|
||||||
throw DeadlyImportError("Unsupported vertex_weight addressing scheme. ");
|
throw DeadlyImportError("Unsupported vertex_weight addressing scheme. ");
|
||||||
|
}
|
||||||
|
|
||||||
// create containers to collect the weights for each bone
|
// create containers to collect the weights for each bone
|
||||||
size_t numBones = jointNames.mStrings.size();
|
size_t numBones = jointNames.mStrings.size();
|
||||||
std::vector<std::vector<aiVertexWeight>> dstBones(numBones);
|
std::vector<std::vector<aiVertexWeight>> dstBones(numBones);
|
||||||
|
|
||||||
// build a temporary array of pointers to the start of each vertex's weights
|
// build a temporary array of pointers to the start of each vertex's weights
|
||||||
typedef std::vector<std::pair<size_t, size_t>> IndexPairVector;
|
using IndexPairVector = std::vector<std::pair<size_t, size_t>>;
|
||||||
std::vector<IndexPairVector::const_iterator> weightStartPerVertex;
|
std::vector<IndexPairVector::const_iterator> weightStartPerVertex;
|
||||||
weightStartPerVertex.resize(pSrcController->mWeightCounts.size(), pSrcController->mWeights.end());
|
weightStartPerVertex.resize(pSrcController->mWeightCounts.size(), pSrcController->mWeights.end());
|
||||||
|
|
||||||
|
@ -812,8 +815,8 @@ aiMesh *ColladaLoader::CreateMesh(const ColladaParser &pParser, const Collada::M
|
||||||
|
|
||||||
// count the number of bones which influence vertices of the current submesh
|
// count the number of bones which influence vertices of the current submesh
|
||||||
size_t numRemainingBones = 0;
|
size_t numRemainingBones = 0;
|
||||||
for (std::vector<std::vector<aiVertexWeight>>::const_iterator it = dstBones.begin(); it != dstBones.end(); ++it) {
|
for (const auto & dstBone : dstBones) {
|
||||||
if (it->size() > 0) {
|
if (!dstBone.empty()) {
|
||||||
++numRemainingBones;
|
++numRemainingBones;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -872,12 +875,12 @@ aiMesh *ColladaLoader::CreateMesh(const ColladaParser &pParser, const Collada::M
|
||||||
// and replace the bone's name by the node's name so that the user can use the standard
|
// and replace the bone's name by the node's name so that the user can use the standard
|
||||||
// find-by-name method to associate nodes with bones.
|
// find-by-name method to associate nodes with bones.
|
||||||
const Collada::Node *bnode = FindNode(pParser.mRootNode, bone->mName.data);
|
const Collada::Node *bnode = FindNode(pParser.mRootNode, bone->mName.data);
|
||||||
if (!bnode) {
|
if (nullptr == bnode) {
|
||||||
bnode = FindNodeBySID(pParser.mRootNode, bone->mName.data);
|
bnode = FindNodeBySID(pParser.mRootNode, bone->mName.data);
|
||||||
}
|
}
|
||||||
|
|
||||||
// assign the name that we would have assigned for the source node
|
// assign the name that we would have assigned for the source node
|
||||||
if (bnode) {
|
if (nullptr != bnode) {
|
||||||
bone->mName.Set(FindNameForNode(bnode));
|
bone->mName.Set(FindNameForNode(bnode));
|
||||||
} else {
|
} else {
|
||||||
ASSIMP_LOG_WARN_F("ColladaLoader::CreateMesh(): could not find corresponding node for joint \"", bone->mName.data, "\".");
|
ASSIMP_LOG_WARN_F("ColladaLoader::CreateMesh(): could not find corresponding node for joint \"", bone->mName.data, "\".");
|
||||||
|
@ -978,8 +981,8 @@ void ColladaLoader::StoreAnimations(aiScene *pScene, const ColladaParser &pParse
|
||||||
std::set<std::string> animTargets;
|
std::set<std::string> animTargets;
|
||||||
animTargets.insert(templateAnim->mChannels[0]->mNodeName.C_Str());
|
animTargets.insert(templateAnim->mChannels[0]->mNodeName.C_Str());
|
||||||
bool collectedAnimationsHaveDifferentChannels = true;
|
bool collectedAnimationsHaveDifferentChannels = true;
|
||||||
for (size_t b = 0; b < collectedAnimIndices.size(); ++b) {
|
for (unsigned long long collectedAnimIndice : collectedAnimIndices) {
|
||||||
aiAnimation *srcAnimation = mAnims[collectedAnimIndices[b]];
|
aiAnimation *srcAnimation = mAnims[collectedAnimIndice];
|
||||||
std::string channelName = std::string(srcAnimation->mChannels[0]->mNodeName.C_Str());
|
std::string channelName = std::string(srcAnimation->mChannels[0]->mNodeName.C_Str());
|
||||||
if (animTargets.find(channelName) == animTargets.end()) {
|
if (animTargets.find(channelName) == animTargets.end()) {
|
||||||
animTargets.insert(channelName);
|
animTargets.insert(channelName);
|
||||||
|
@ -989,8 +992,9 @@ void ColladaLoader::StoreAnimations(aiScene *pScene, const ColladaParser &pParse
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!collectedAnimationsHaveDifferentChannels)
|
if (!collectedAnimationsHaveDifferentChannels) {
|
||||||
continue;
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
// if there are other animations which fit the template anim, combine all channels into a single anim
|
// if there are other animations which fit the template anim, combine all channels into a single anim
|
||||||
if (!collectedAnimIndices.empty()) {
|
if (!collectedAnimIndices.empty()) {
|
||||||
|
@ -1037,16 +1041,18 @@ void ColladaLoader::StoreAnimations(aiScene *pScene, const ColladaParser &pParse
|
||||||
|
|
||||||
// ------------------------------------------------------------------------------------------------
|
// ------------------------------------------------------------------------------------------------
|
||||||
// Constructs the animations for the given source anim
|
// Constructs the animations for the given source anim
|
||||||
void ColladaLoader::StoreAnimations(aiScene *pScene, const ColladaParser &pParser, const Collada::Animation *pSrcAnim, const std::string &pPrefix) {
|
void ColladaLoader::StoreAnimations(aiScene *pScene, const ColladaParser &pParser, const Animation *pSrcAnim, const std::string &pPrefix) {
|
||||||
std::string animName = pPrefix.empty() ? pSrcAnim->mName : pPrefix + "_" + pSrcAnim->mName;
|
std::string animName = pPrefix.empty() ? pSrcAnim->mName : pPrefix + "_" + pSrcAnim->mName;
|
||||||
|
|
||||||
// create nested animations, if given
|
// create nested animations, if given
|
||||||
for (std::vector<Collada::Animation *>::const_iterator it = pSrcAnim->mSubAnims.begin(); it != pSrcAnim->mSubAnims.end(); ++it)
|
for (auto mSubAnim : pSrcAnim->mSubAnims) {
|
||||||
StoreAnimations(pScene, pParser, *it, animName);
|
StoreAnimations(pScene, pParser, mSubAnim, animName);
|
||||||
|
}
|
||||||
|
|
||||||
// create animation channels, if any
|
// create animation channels, if any
|
||||||
if (!pSrcAnim->mChannels.empty())
|
if (!pSrcAnim->mChannels.empty()) {
|
||||||
CreateAnimation(pScene, pParser, pSrcAnim, animName);
|
CreateAnimation(pScene, pParser, pSrcAnim, animName);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
struct MorphTimeValues {
|
struct MorphTimeValues {
|
||||||
|
@ -1062,7 +1068,7 @@ void insertMorphTimeValue(std::vector<MorphTimeValues> &values, float time, floa
|
||||||
MorphTimeValues::key k;
|
MorphTimeValues::key k;
|
||||||
k.mValue = value;
|
k.mValue = value;
|
||||||
k.mWeight = weight;
|
k.mWeight = weight;
|
||||||
if (values.size() == 0 || time < values[0].mTime) {
|
if (values.empty() || time < values[0].mTime) {
|
||||||
MorphTimeValues val;
|
MorphTimeValues val;
|
||||||
val.mTime = time;
|
val.mTime = time;
|
||||||
val.mKeys.push_back(k);
|
val.mKeys.push_back(k);
|
||||||
|
@ -1088,13 +1094,13 @@ void insertMorphTimeValue(std::vector<MorphTimeValues> &values, float time, floa
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
// should not get here
|
|
||||||
}
|
}
|
||||||
|
|
||||||
float getWeightAtKey(const std::vector<MorphTimeValues> &values, int key, unsigned int value) {
|
static float getWeightAtKey(const std::vector<MorphTimeValues> &values, int key, unsigned int value) {
|
||||||
for (unsigned int i = 0; i < values[key].mKeys.size(); i++) {
|
for (auto mKey : values[key].mKeys) {
|
||||||
if (values[key].mKeys[i].mValue == value)
|
if (mKey.mValue == value) {
|
||||||
return values[key].mKeys[i].mWeight;
|
return mKey.mWeight;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
// no value at key found, try to interpolate if present at other keys. if not, return zero
|
// no value at key found, try to interpolate if present at other keys. if not, return zero
|
||||||
// TODO: interpolation
|
// TODO: interpolation
|
||||||
|
@ -1103,7 +1109,7 @@ float getWeightAtKey(const std::vector<MorphTimeValues> &values, int key, unsign
|
||||||
|
|
||||||
// ------------------------------------------------------------------------------------------------
|
// ------------------------------------------------------------------------------------------------
|
||||||
// Constructs the animation for the given source anim
|
// Constructs the animation for the given source anim
|
||||||
void ColladaLoader::CreateAnimation(aiScene *pScene, const ColladaParser &pParser, const Collada::Animation *pSrcAnim, const std::string &pName) {
|
void ColladaLoader::CreateAnimation(aiScene *pScene, const ColladaParser &pParser, const Animation *pSrcAnim, const std::string &pName) {
|
||||||
// collect a list of animatable nodes
|
// collect a list of animatable nodes
|
||||||
std::vector<const aiNode *> nodes;
|
std::vector<const aiNode *> nodes;
|
||||||
CollectNodes(pScene->mRootNode, nodes);
|
CollectNodes(pScene->mRootNode, nodes);
|
||||||
|
@ -1111,23 +1117,23 @@ void ColladaLoader::CreateAnimation(aiScene *pScene, const ColladaParser &pParse
|
||||||
std::vector<aiNodeAnim *> anims;
|
std::vector<aiNodeAnim *> anims;
|
||||||
std::vector<aiMeshMorphAnim *> morphAnims;
|
std::vector<aiMeshMorphAnim *> morphAnims;
|
||||||
|
|
||||||
for (std::vector<const aiNode *>::const_iterator nit = nodes.begin(); nit != nodes.end(); ++nit) {
|
for (auto node : nodes) {
|
||||||
// find all the collada anim channels which refer to the current node
|
// find all the collada anim channels which refer to the current node
|
||||||
std::vector<Collada::ChannelEntry> entries;
|
std::vector<ChannelEntry> entries;
|
||||||
std::string nodeName = (*nit)->mName.data;
|
std::string nodeName = node->mName.data;
|
||||||
|
|
||||||
// find the collada node corresponding to the aiNode
|
// find the collada node corresponding to the aiNode
|
||||||
const Collada::Node *srcNode = FindNode(pParser.mRootNode, nodeName);
|
const Node *srcNode = FindNode(pParser.mRootNode, nodeName);
|
||||||
if (!srcNode) {
|
if (!srcNode) {
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
// now check all channels if they affect the current node
|
// now check all channels if they affect the current node
|
||||||
std::string targetID, subElement;
|
std::string targetID, subElement;
|
||||||
for (std::vector<Collada::AnimationChannel>::const_iterator cit = pSrcAnim->mChannels.begin();
|
for (std::vector<AnimationChannel>::const_iterator cit = pSrcAnim->mChannels.begin();
|
||||||
cit != pSrcAnim->mChannels.end(); ++cit) {
|
cit != pSrcAnim->mChannels.end(); ++cit) {
|
||||||
const Collada::AnimationChannel &srcChannel = *cit;
|
const AnimationChannel &srcChannel = *cit;
|
||||||
Collada::ChannelEntry entry;
|
ChannelEntry entry;
|
||||||
|
|
||||||
// we expect the animation target to be of type "nodeName/transformID.subElement". Ignore all others
|
// we expect the animation target to be of type "nodeName/transformID.subElement". Ignore all others
|
||||||
// find the slash that separates the node name - there should be only one
|
// find the slash that separates the node name - there should be only one
|
||||||
|
@ -1142,24 +1148,28 @@ void ColladaLoader::CreateAnimation(aiScene *pScene, const ColladaParser &pParse
|
||||||
entry.mChannel = &(*cit);
|
entry.mChannel = &(*cit);
|
||||||
entry.mTargetId = srcChannel.mTarget.substr(targetPos + pSrcAnim->mName.length(),
|
entry.mTargetId = srcChannel.mTarget.substr(targetPos + pSrcAnim->mName.length(),
|
||||||
srcChannel.mTarget.length() - targetPos - pSrcAnim->mName.length());
|
srcChannel.mTarget.length() - targetPos - pSrcAnim->mName.length());
|
||||||
if (entry.mTargetId.front() == '-')
|
if (entry.mTargetId.front() == '-') {
|
||||||
entry.mTargetId = entry.mTargetId.substr(1);
|
entry.mTargetId = entry.mTargetId.substr(1);
|
||||||
|
}
|
||||||
entries.push_back(entry);
|
entries.push_back(entry);
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
if (srcChannel.mTarget.find('/', slashPos + 1) != std::string::npos)
|
if (srcChannel.mTarget.find('/', slashPos + 1) != std::string::npos) {
|
||||||
continue;
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
targetID.clear();
|
targetID.clear();
|
||||||
targetID = srcChannel.mTarget.substr(0, slashPos);
|
targetID = srcChannel.mTarget.substr(0, slashPos);
|
||||||
if (targetID != srcNode->mID)
|
if (targetID != srcNode->mID) {
|
||||||
continue;
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
// find the dot that separates the transformID - there should be only one or zero
|
// find the dot that separates the transformID - there should be only one or zero
|
||||||
std::string::size_type dotPos = srcChannel.mTarget.find('.');
|
std::string::size_type dotPos = srcChannel.mTarget.find('.');
|
||||||
if (dotPos != std::string::npos) {
|
if (dotPos != std::string::npos) {
|
||||||
if (srcChannel.mTarget.find('.', dotPos + 1) != std::string::npos)
|
if (srcChannel.mTarget.find('.', dotPos + 1) != std::string::npos) {
|
||||||
continue;
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
entry.mTransformId = srcChannel.mTarget.substr(slashPos + 1, dotPos - slashPos - 1);
|
entry.mTransformId = srcChannel.mTarget.substr(slashPos + 1, dotPos - slashPos - 1);
|
||||||
|
|
||||||
|
@ -1176,7 +1186,7 @@ void ColladaLoader::CreateAnimation(aiScene *pScene, const ColladaParser &pParse
|
||||||
else
|
else
|
||||||
ASSIMP_LOG_WARN_F("Unknown anim subelement <", subElement, ">. Ignoring");
|
ASSIMP_LOG_WARN_F("Unknown anim subelement <", subElement, ">. Ignoring");
|
||||||
} else {
|
} else {
|
||||||
// no subelement following, transformId is remaining string
|
// no sub-element following, transformId is remaining string
|
||||||
entry.mTransformId = srcChannel.mTarget.substr(slashPos + 1);
|
entry.mTransformId = srcChannel.mTarget.substr(slashPos + 1);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1227,11 +1237,11 @@ void ColladaLoader::CreateAnimation(aiScene *pScene, const ColladaParser &pParse
|
||||||
entry.mTransformIndex = a;
|
entry.mTransformIndex = a;
|
||||||
|
|
||||||
if (entry.mTransformIndex == SIZE_MAX) {
|
if (entry.mTransformIndex == SIZE_MAX) {
|
||||||
if (entry.mTransformId.find("morph-weights") != std::string::npos) {
|
if (entry.mTransformId.find("morph-weights") == std::string::npos) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
entry.mTargetId = entry.mTransformId;
|
entry.mTargetId = entry.mTransformId;
|
||||||
entry.mTransformId = "";
|
entry.mTransformId = "";
|
||||||
} else
|
|
||||||
continue;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
entry.mChannel = &(*cit);
|
entry.mChannel = &(*cit);
|
||||||
|
@ -1239,21 +1249,22 @@ void ColladaLoader::CreateAnimation(aiScene *pScene, const ColladaParser &pParse
|
||||||
}
|
}
|
||||||
|
|
||||||
// if there's no channel affecting the current node, we skip it
|
// if there's no channel affecting the current node, we skip it
|
||||||
if (entries.empty())
|
if (entries.empty()) {
|
||||||
continue;
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
// resolve the data pointers for all anim channels. Find the minimum time while we're at it
|
// resolve the data pointers for all anim channels. Find the minimum time while we're at it
|
||||||
ai_real startTime = ai_real(1e20), endTime = ai_real(-1e20);
|
ai_real startTime = ai_real(1e20), endTime = ai_real(-1e20);
|
||||||
for (std::vector<Collada::ChannelEntry>::iterator it = entries.begin(); it != entries.end(); ++it) {
|
for (ChannelEntry & e : entries) {
|
||||||
Collada::ChannelEntry &e = *it;
|
|
||||||
e.mTimeAccessor = &pParser.ResolveLibraryReference(pParser.mAccessorLibrary, e.mChannel->mSourceTimes);
|
e.mTimeAccessor = &pParser.ResolveLibraryReference(pParser.mAccessorLibrary, e.mChannel->mSourceTimes);
|
||||||
e.mTimeData = &pParser.ResolveLibraryReference(pParser.mDataLibrary, e.mTimeAccessor->mSource);
|
e.mTimeData = &pParser.ResolveLibraryReference(pParser.mDataLibrary, e.mTimeAccessor->mSource);
|
||||||
e.mValueAccessor = &pParser.ResolveLibraryReference(pParser.mAccessorLibrary, e.mChannel->mSourceValues);
|
e.mValueAccessor = &pParser.ResolveLibraryReference(pParser.mAccessorLibrary, e.mChannel->mSourceValues);
|
||||||
e.mValueData = &pParser.ResolveLibraryReference(pParser.mDataLibrary, e.mValueAccessor->mSource);
|
e.mValueData = &pParser.ResolveLibraryReference(pParser.mDataLibrary, e.mValueAccessor->mSource);
|
||||||
|
|
||||||
// time count and value count must match
|
// time count and value count must match
|
||||||
if (e.mTimeAccessor->mCount != e.mValueAccessor->mCount)
|
if (e.mTimeAccessor->mCount != e.mValueAccessor->mCount) {
|
||||||
throw DeadlyImportError("Time count / value count mismatch in animation channel \"", e.mChannel->mTarget, "\".");
|
throw DeadlyImportError("Time count / value count mismatch in animation channel \"", e.mChannel->mTarget, "\".");
|
||||||
|
}
|
||||||
|
|
||||||
if (e.mTimeAccessor->mCount > 0) {
|
if (e.mTimeAccessor->mCount > 0) {
|
||||||
// find bounding times
|
// find bounding times
|
||||||
|
@ -1271,18 +1282,18 @@ void ColladaLoader::CreateAnimation(aiScene *pScene, const ColladaParser &pParse
|
||||||
// and apply them to the transform chain. Then the node's present transformation can be calculated.
|
// and apply them to the transform chain. Then the node's present transformation can be calculated.
|
||||||
ai_real time = startTime;
|
ai_real time = startTime;
|
||||||
while (1) {
|
while (1) {
|
||||||
for (std::vector<Collada::ChannelEntry>::iterator it = entries.begin(); it != entries.end(); ++it) {
|
for (ChannelEntry & e : entries) {
|
||||||
Collada::ChannelEntry &e = *it;
|
|
||||||
|
|
||||||
// find the keyframe behind the current point in time
|
// find the keyframe behind the current point in time
|
||||||
size_t pos = 0;
|
size_t pos = 0;
|
||||||
ai_real postTime = 0.0;
|
ai_real postTime = 0.0;
|
||||||
while (1) {
|
while (1) {
|
||||||
if (pos >= e.mTimeAccessor->mCount)
|
if (pos >= e.mTimeAccessor->mCount) {
|
||||||
break;
|
break;
|
||||||
|
}
|
||||||
postTime = ReadFloat(*e.mTimeAccessor, *e.mTimeData, pos, 0);
|
postTime = ReadFloat(*e.mTimeAccessor, *e.mTimeData, pos, 0);
|
||||||
if (postTime >= time)
|
if (postTime >= time) {
|
||||||
break;
|
break;
|
||||||
|
}
|
||||||
++pos;
|
++pos;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1290,8 +1301,9 @@ void ColladaLoader::CreateAnimation(aiScene *pScene, const ColladaParser &pParse
|
||||||
|
|
||||||
// read values from there
|
// read values from there
|
||||||
ai_real temp[16];
|
ai_real temp[16];
|
||||||
for (size_t c = 0; c < e.mValueAccessor->mSize; ++c)
|
for (size_t c = 0; c < e.mValueAccessor->mSize; ++c) {
|
||||||
temp[c] = ReadFloat(*e.mValueAccessor, *e.mValueData, pos, c);
|
temp[c] = ReadFloat(*e.mValueAccessor, *e.mValueData, pos, c);
|
||||||
|
}
|
||||||
|
|
||||||
// if not exactly at the key time, interpolate with previous value set
|
// if not exactly at the key time, interpolate with previous value set
|
||||||
if (postTime > time && pos > 0) {
|
if (postTime > time && pos > 0) {
|
||||||
|
@ -1317,9 +1329,7 @@ void ColladaLoader::CreateAnimation(aiScene *pScene, const ColladaParser &pParse
|
||||||
|
|
||||||
// find next point in time to evaluate. That's the closest frame larger than the current in any channel
|
// find next point in time to evaluate. That's the closest frame larger than the current in any channel
|
||||||
ai_real nextTime = ai_real(1e20);
|
ai_real nextTime = ai_real(1e20);
|
||||||
for (std::vector<Collada::ChannelEntry>::iterator it = entries.begin(); it != entries.end(); ++it) {
|
for (ChannelEntry & channelElement : entries) {
|
||||||
Collada::ChannelEntry &channelElement = *it;
|
|
||||||
|
|
||||||
// find the next time value larger than the current
|
// find the next time value larger than the current
|
||||||
size_t pos = 0;
|
size_t pos = 0;
|
||||||
while (pos < channelElement.mTimeAccessor->mCount) {
|
while (pos < channelElement.mTimeAccessor->mCount) {
|
||||||
|
@ -1334,7 +1344,7 @@ void ColladaLoader::CreateAnimation(aiScene *pScene, const ColladaParser &pParse
|
||||||
// https://github.com/assimp/assimp/issues/458
|
// https://github.com/assimp/assimp/issues/458
|
||||||
// Sub-sample axis-angle channels if the delta between two consecutive
|
// Sub-sample axis-angle channels if the delta between two consecutive
|
||||||
// key-frame angles is >= 180 degrees.
|
// key-frame angles is >= 180 degrees.
|
||||||
if (transforms[channelElement.mTransformIndex].mType == Collada::TF_ROTATE && channelElement.mSubElement == 3 && pos > 0 && pos < channelElement.mTimeAccessor->mCount) {
|
if (transforms[channelElement.mTransformIndex].mType == TF_ROTATE && channelElement.mSubElement == 3 && pos > 0 && pos < channelElement.mTimeAccessor->mCount) {
|
||||||
const ai_real cur_key_angle = ReadFloat(*channelElement.mValueAccessor, *channelElement.mValueData, pos, 0);
|
const ai_real cur_key_angle = ReadFloat(*channelElement.mValueAccessor, *channelElement.mValueData, pos, 0);
|
||||||
const ai_real last_key_angle = ReadFloat(*channelElement.mValueAccessor, *channelElement.mValueData, pos - 1, 0);
|
const ai_real last_key_angle = ReadFloat(*channelElement.mValueAccessor, *channelElement.mValueData, pos - 1, 0);
|
||||||
const ai_real cur_key_time = ReadFloat(*channelElement.mTimeAccessor, *channelElement.mTimeData, pos, 0);
|
const ai_real cur_key_time = ReadFloat(*channelElement.mTimeAccessor, *channelElement.mTimeData, pos, 0);
|
||||||
|
@ -1352,17 +1362,15 @@ void ColladaLoader::CreateAnimation(aiScene *pScene, const ColladaParser &pParse
|
||||||
}
|
}
|
||||||
|
|
||||||
// no more keys on any channel after the current time -> we're done
|
// no more keys on any channel after the current time -> we're done
|
||||||
if (nextTime > 1e19)
|
if (nextTime > 1e19) {
|
||||||
break;
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
// else construct next keyframe at this following time point
|
// else construct next key-frame at this following time point
|
||||||
time = nextTime;
|
time = nextTime;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// there should be some keyframes, but we aren't that fixated on valid input data
|
|
||||||
// ai_assert( resultTrafos.size() > 0);
|
|
||||||
|
|
||||||
// build an animation channel for the given node out of these trafo keys
|
// build an animation channel for the given node out of these trafo keys
|
||||||
if (!resultTrafos.empty()) {
|
if (!resultTrafos.empty()) {
|
||||||
aiNodeAnim *dstAnim = new aiNodeAnim;
|
aiNodeAnim *dstAnim = new aiNodeAnim;
|
||||||
|
@ -1391,17 +1399,17 @@ void ColladaLoader::CreateAnimation(aiScene *pScene, const ColladaParser &pParse
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!entries.empty() && entries.front().mTimeAccessor->mCount > 0) {
|
if (!entries.empty() && entries.front().mTimeAccessor->mCount > 0) {
|
||||||
std::vector<Collada::ChannelEntry> morphChannels;
|
std::vector<ChannelEntry> morphChannels;
|
||||||
for (std::vector<Collada::ChannelEntry>::iterator it = entries.begin(); it != entries.end(); ++it) {
|
for (ChannelEntry & e : entries) {
|
||||||
Collada::ChannelEntry &e = *it;
|
|
||||||
|
|
||||||
// skip non-transform types
|
// skip non-transform types
|
||||||
if (e.mTargetId.empty())
|
if (e.mTargetId.empty()) {
|
||||||
continue;
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
if (e.mTargetId.find("morph-weights") != std::string::npos)
|
if (e.mTargetId.find("morph-weights") != std::string::npos) {
|
||||||
morphChannels.push_back(e);
|
morphChannels.push_back(e);
|
||||||
}
|
}
|
||||||
|
}
|
||||||
if (!morphChannels.empty()) {
|
if (!morphChannels.empty()) {
|
||||||
// either 1) morph weight animation count should contain morph target count channels
|
// either 1) morph weight animation count should contain morph target count channels
|
||||||
// or 2) one channel with morph target count arrays
|
// or 2) one channel with morph target count arrays
|
||||||
|
@ -1412,13 +1420,14 @@ void ColladaLoader::CreateAnimation(aiScene *pScene, const ColladaParser &pParse
|
||||||
|
|
||||||
std::vector<MorphTimeValues> morphTimeValues;
|
std::vector<MorphTimeValues> morphTimeValues;
|
||||||
int morphAnimChannelIndex = 0;
|
int morphAnimChannelIndex = 0;
|
||||||
for (std::vector<Collada::ChannelEntry>::iterator it = morphChannels.begin(); it != morphChannels.end(); ++it) {
|
for (ChannelEntry & e : morphChannels) {
|
||||||
Collada::ChannelEntry &e = *it;
|
|
||||||
std::string::size_type apos = e.mTargetId.find('(');
|
std::string::size_type apos = e.mTargetId.find('(');
|
||||||
std::string::size_type bpos = e.mTargetId.find(')');
|
std::string::size_type bpos = e.mTargetId.find(')');
|
||||||
if (apos == std::string::npos || bpos == std::string::npos)
|
|
||||||
// unknown way to specify weight -> ignore this animation
|
// If unknown way to specify weight -> ignore this animation
|
||||||
|
if (apos == std::string::npos || bpos == std::string::npos) {
|
||||||
continue;
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
// weight target can be in format Weight_M_N, Weight_N, WeightN, or some other way
|
// weight target can be in format Weight_M_N, Weight_N, WeightN, or some other way
|
||||||
// we ignore the name and just assume the channels are in the right order
|
// we ignore the name and just assume the channels are in the right order
|
||||||
|
@ -1462,13 +1471,13 @@ void ColladaLoader::CreateAnimation(aiScene *pScene, const ColladaParser &pParse
|
||||||
std::copy(morphAnims.begin(), morphAnims.end(), anim->mMorphMeshChannels);
|
std::copy(morphAnims.begin(), morphAnims.end(), anim->mMorphMeshChannels);
|
||||||
}
|
}
|
||||||
anim->mDuration = 0.0f;
|
anim->mDuration = 0.0f;
|
||||||
for (size_t a = 0; a < anims.size(); ++a) {
|
for (auto & a : anims) {
|
||||||
anim->mDuration = std::max(anim->mDuration, anims[a]->mPositionKeys[anims[a]->mNumPositionKeys - 1].mTime);
|
anim->mDuration = std::max(anim->mDuration, a->mPositionKeys[a->mNumPositionKeys - 1].mTime);
|
||||||
anim->mDuration = std::max(anim->mDuration, anims[a]->mRotationKeys[anims[a]->mNumRotationKeys - 1].mTime);
|
anim->mDuration = std::max(anim->mDuration, a->mRotationKeys[a->mNumRotationKeys - 1].mTime);
|
||||||
anim->mDuration = std::max(anim->mDuration, anims[a]->mScalingKeys[anims[a]->mNumScalingKeys - 1].mTime);
|
anim->mDuration = std::max(anim->mDuration, a->mScalingKeys[a->mNumScalingKeys - 1].mTime);
|
||||||
}
|
}
|
||||||
for (size_t a = 0; a < morphAnims.size(); ++a) {
|
for (auto & morphAnim : morphAnims) {
|
||||||
anim->mDuration = std::max(anim->mDuration, morphAnims[a]->mKeys[morphAnims[a]->mNumKeys - 1].mTime);
|
anim->mDuration = std::max(anim->mDuration, morphAnim->mKeys[morphAnim->mNumKeys - 1].mTime);
|
||||||
}
|
}
|
||||||
anim->mTicksPerSecond = 1000.0;
|
anim->mTicksPerSecond = 1000.0;
|
||||||
mAnims.push_back(anim);
|
mAnims.push_back(anim);
|
||||||
|
@ -1477,10 +1486,12 @@ void ColladaLoader::CreateAnimation(aiScene *pScene, const ColladaParser &pParse
|
||||||
|
|
||||||
// ------------------------------------------------------------------------------------------------
|
// ------------------------------------------------------------------------------------------------
|
||||||
// Add a texture to a material structure
|
// Add a texture to a material structure
|
||||||
void ColladaLoader::AddTexture(aiMaterial &mat, const ColladaParser &pParser,
|
void ColladaLoader::AddTexture(aiMaterial &mat,
|
||||||
const Collada::Effect &effect,
|
const ColladaParser &pParser,
|
||||||
const Collada::Sampler &sampler,
|
const Effect &effect,
|
||||||
aiTextureType type, unsigned int idx) {
|
const Sampler &sampler,
|
||||||
|
aiTextureType type,
|
||||||
|
unsigned int idx) {
|
||||||
// first of all, basic file name
|
// first of all, basic file name
|
||||||
const aiString name = FindFilenameForEffectTexture(pParser, effect, sampler.mName);
|
const aiString name = FindFilenameForEffectTexture(pParser, effect, sampler.mName);
|
||||||
mat.AddProperty(&name, _AI_MATKEY_TEXTURE_BASE, type, idx);
|
mat.AddProperty(&name, _AI_MATKEY_TEXTURE_BASE, type, idx);
|
||||||
|
@ -1579,7 +1590,7 @@ void ColladaLoader::FillMaterials(const ColladaParser &pParser, aiScene * /*pSce
|
||||||
shadeMode = effect.mDoubleSided;
|
shadeMode = effect.mDoubleSided;
|
||||||
mat.AddProperty<int>(&shadeMode, 1, AI_MATKEY_TWOSIDED);
|
mat.AddProperty<int>(&shadeMode, 1, AI_MATKEY_TWOSIDED);
|
||||||
|
|
||||||
// wireframe?
|
// wire-frame?
|
||||||
shadeMode = effect.mWireframe;
|
shadeMode = effect.mWireframe;
|
||||||
mat.AddProperty<int>(&shadeMode, 1, AI_MATKEY_ENABLE_WIREFRAME);
|
mat.AddProperty<int>(&shadeMode, 1, AI_MATKEY_ENABLE_WIREFRAME);
|
||||||
|
|
||||||
|
@ -1657,12 +1668,12 @@ void ColladaLoader::BuildMaterials(ColladaParser &pParser, aiScene * /*pScene*/)
|
||||||
|
|
||||||
for (ColladaParser::MaterialLibrary::const_iterator matIt = pParser.mMaterialLibrary.begin();
|
for (ColladaParser::MaterialLibrary::const_iterator matIt = pParser.mMaterialLibrary.begin();
|
||||||
matIt != pParser.mMaterialLibrary.end(); ++matIt) {
|
matIt != pParser.mMaterialLibrary.end(); ++matIt) {
|
||||||
const Collada::Material &material = matIt->second;
|
const Material &material = matIt->second;
|
||||||
// a material is only a reference to an effect
|
// a material is only a reference to an effect
|
||||||
ColladaParser::EffectLibrary::iterator effIt = pParser.mEffectLibrary.find(material.mEffect);
|
ColladaParser::EffectLibrary::iterator effIt = pParser.mEffectLibrary.find(material.mEffect);
|
||||||
if (effIt == pParser.mEffectLibrary.end())
|
if (effIt == pParser.mEffectLibrary.end())
|
||||||
continue;
|
continue;
|
||||||
Collada::Effect &effect = effIt->second;
|
Effect &effect = effIt->second;
|
||||||
|
|
||||||
// create material
|
// create material
|
||||||
aiMaterial *mat = new aiMaterial;
|
aiMaterial *mat = new aiMaterial;
|
||||||
|
@ -1671,7 +1682,7 @@ void ColladaLoader::BuildMaterials(ColladaParser &pParser, aiScene * /*pScene*/)
|
||||||
|
|
||||||
// store the material
|
// store the material
|
||||||
mMaterialIndexByName[matIt->first] = newMats.size();
|
mMaterialIndexByName[matIt->first] = newMats.size();
|
||||||
newMats.push_back(std::pair<Collada::Effect *, aiMaterial *>(&effect, mat));
|
newMats.push_back(std::pair<Effect *, aiMaterial *>(&effect, mat));
|
||||||
}
|
}
|
||||||
// ScenePreprocessor generates a default material automatically if none is there.
|
// ScenePreprocessor generates a default material automatically if none is there.
|
||||||
// All further code here in this loader works well without a valid material so
|
// All further code here in this loader works well without a valid material so
|
||||||
|
@ -1679,17 +1690,16 @@ void ColladaLoader::BuildMaterials(ColladaParser &pParser, aiScene * /*pScene*/)
|
||||||
}
|
}
|
||||||
|
|
||||||
// ------------------------------------------------------------------------------------------------
|
// ------------------------------------------------------------------------------------------------
|
||||||
// Resolves the texture name for the given effect texture entry
|
// Resolves the texture name for the given effect texture entry and loads the texture data
|
||||||
// and loads the texture data
|
|
||||||
aiString ColladaLoader::FindFilenameForEffectTexture(const ColladaParser &pParser,
|
aiString ColladaLoader::FindFilenameForEffectTexture(const ColladaParser &pParser,
|
||||||
const Collada::Effect &pEffect, const std::string &pName) {
|
const Effect &pEffect, const std::string &pName) {
|
||||||
aiString result;
|
aiString result;
|
||||||
|
|
||||||
// recurse through the param references until we end up at an image
|
// recurse through the param references until we end up at an image
|
||||||
std::string name = pName;
|
std::string name = pName;
|
||||||
while (1) {
|
while (1) {
|
||||||
// the given string is a param entry. Find it
|
// the given string is a param entry. Find it
|
||||||
Collada::Effect::ParamLibrary::const_iterator it = pEffect.mParams.find(name);
|
Effect::ParamLibrary::const_iterator it = pEffect.mParams.find(name);
|
||||||
// if not found, we're at the end of the recursion. The resulting string should be the image ID
|
// if not found, we're at the end of the recursion. The resulting string should be the image ID
|
||||||
if (it == pEffect.mParams.end())
|
if (it == pEffect.mParams.end())
|
||||||
break;
|
break;
|
||||||
|
@ -1717,10 +1727,6 @@ aiString ColladaLoader::FindFilenameForEffectTexture(const ColladaParser &pParse
|
||||||
tex->mFilename.Set(imIt->second.mFileName.c_str());
|
tex->mFilename.Set(imIt->second.mFileName.c_str());
|
||||||
result.Set(imIt->second.mFileName);
|
result.Set(imIt->second.mFileName);
|
||||||
|
|
||||||
// TODO: check the possibility of using the flag "AI_CONFIG_IMPORT_FBX_EMBEDDED_TEXTURES_LEGACY_NAMING"
|
|
||||||
// result.data[0] = '*';
|
|
||||||
// result.length = 1 + ASSIMP_itoa10(result.data + 1, static_cast<unsigned int>(MAXLEN - 1), static_cast<int32_t>(mTextures.size()));
|
|
||||||
|
|
||||||
// setup format hint
|
// setup format hint
|
||||||
if (imIt->second.mEmbeddedFormat.length() >= HINTMAXTEXTURELEN) {
|
if (imIt->second.mEmbeddedFormat.length() >= HINTMAXTEXTURELEN) {
|
||||||
ASSIMP_LOG_WARN("Collada: texture format hint is too long, truncating to 3 characters");
|
ASSIMP_LOG_WARN("Collada: texture format hint is too long, truncating to 3 characters");
|
||||||
|
@ -1749,7 +1755,7 @@ aiString ColladaLoader::FindFilenameForEffectTexture(const ColladaParser &pParse
|
||||||
|
|
||||||
// ------------------------------------------------------------------------------------------------
|
// ------------------------------------------------------------------------------------------------
|
||||||
// Reads a float value from an accessor and its data array.
|
// Reads a float value from an accessor and its data array.
|
||||||
ai_real ColladaLoader::ReadFloat(const Collada::Accessor &pAccessor, const Collada::Data &pData, size_t pIndex, size_t pOffset) const {
|
ai_real ColladaLoader::ReadFloat(const Accessor &pAccessor, const Data &pData, size_t pIndex, size_t pOffset) const {
|
||||||
size_t pos = pAccessor.mStride * pIndex + pAccessor.mOffset + pOffset;
|
size_t pos = pAccessor.mStride * pIndex + pAccessor.mOffset + pOffset;
|
||||||
ai_assert(pos < pData.mValues.size());
|
ai_assert(pos < pData.mValues.size());
|
||||||
return pData.mValues[pos];
|
return pData.mValues[pos];
|
||||||
|
@ -1757,7 +1763,7 @@ ai_real ColladaLoader::ReadFloat(const Collada::Accessor &pAccessor, const Colla
|
||||||
|
|
||||||
// ------------------------------------------------------------------------------------------------
|
// ------------------------------------------------------------------------------------------------
|
||||||
// Reads a string value from an accessor and its data array.
|
// Reads a string value from an accessor and its data array.
|
||||||
const std::string &ColladaLoader::ReadString(const Collada::Accessor &pAccessor, const Collada::Data &pData, size_t pIndex) const {
|
const std::string &ColladaLoader::ReadString(const Accessor &pAccessor, const Data &pData, size_t pIndex) const {
|
||||||
size_t pos = pAccessor.mStride * pIndex + pAccessor.mOffset;
|
size_t pos = pAccessor.mStride * pIndex + pAccessor.mOffset;
|
||||||
ai_assert(pos < pData.mStrings.size());
|
ai_assert(pos < pData.mStrings.size());
|
||||||
return pData.mStrings[pos];
|
return pData.mStrings[pos];
|
||||||
|
@ -1774,12 +1780,12 @@ void ColladaLoader::CollectNodes(const aiNode *pNode, std::vector<const aiNode *
|
||||||
|
|
||||||
// ------------------------------------------------------------------------------------------------
|
// ------------------------------------------------------------------------------------------------
|
||||||
// Finds a node in the collada scene by the given name
|
// Finds a node in the collada scene by the given name
|
||||||
const Collada::Node *ColladaLoader::FindNode(const Collada::Node *pNode, const std::string &pName) const {
|
const Node *ColladaLoader::FindNode(const Node *pNode, const std::string &pName) const {
|
||||||
if (pNode->mName == pName || pNode->mID == pName)
|
if (pNode->mName == pName || pNode->mID == pName)
|
||||||
return pNode;
|
return pNode;
|
||||||
|
|
||||||
for (size_t a = 0; a < pNode->mChildren.size(); ++a) {
|
for (auto a : pNode->mChildren) {
|
||||||
const Collada::Node *node = FindNode(pNode->mChildren[a], pName);
|
const Collada::Node *node = FindNode(a, pName);
|
||||||
if (node) {
|
if (node) {
|
||||||
return node;
|
return node;
|
||||||
}
|
}
|
||||||
|
@ -1790,7 +1796,7 @@ const Collada::Node *ColladaLoader::FindNode(const Collada::Node *pNode, const s
|
||||||
|
|
||||||
// ------------------------------------------------------------------------------------------------
|
// ------------------------------------------------------------------------------------------------
|
||||||
// Finds a node in the collada scene by the given SID
|
// Finds a node in the collada scene by the given SID
|
||||||
const Collada::Node *ColladaLoader::FindNodeBySID(const Collada::Node *pNode, const std::string &pSID) const {
|
const Node *ColladaLoader::FindNodeBySID(const Node *pNode, const std::string &pSID) const {
|
||||||
if (nullptr == pNode) {
|
if (nullptr == pNode) {
|
||||||
return nullptr;
|
return nullptr;
|
||||||
}
|
}
|
||||||
|
@ -1799,8 +1805,8 @@ const Collada::Node *ColladaLoader::FindNodeBySID(const Collada::Node *pNode, co
|
||||||
return pNode;
|
return pNode;
|
||||||
}
|
}
|
||||||
|
|
||||||
for (size_t a = 0; a < pNode->mChildren.size(); ++a) {
|
for (auto a : pNode->mChildren) {
|
||||||
const Collada::Node *node = FindNodeBySID(pNode->mChildren[a], pSID);
|
const Collada::Node *node = FindNodeBySID(a, pSID);
|
||||||
if (node) {
|
if (node) {
|
||||||
return node;
|
return node;
|
||||||
}
|
}
|
||||||
|
@ -1812,7 +1818,7 @@ const Collada::Node *ColladaLoader::FindNodeBySID(const Collada::Node *pNode, co
|
||||||
// ------------------------------------------------------------------------------------------------
|
// ------------------------------------------------------------------------------------------------
|
||||||
// Finds a proper unique name for a node derived from the collada-node's properties.
|
// Finds a proper unique name for a node derived from the collada-node's properties.
|
||||||
// The name must be unique for proper node-bone association.
|
// The name must be unique for proper node-bone association.
|
||||||
std::string ColladaLoader::FindNameForNode(const Collada::Node *pNode) {
|
std::string ColladaLoader::FindNameForNode(const Node *pNode) {
|
||||||
// If explicitly requested, just use the collada name.
|
// If explicitly requested, just use the collada name.
|
||||||
if (useColladaName) {
|
if (useColladaName) {
|
||||||
if (!pNode->mName.empty()) {
|
if (!pNode->mName.empty()) {
|
||||||
|
|
|
@ -4,7 +4,7 @@
|
||||||
Open Asset Import Library (assimp)
|
Open Asset Import Library (assimp)
|
||||||
----------------------------------------------------------------------
|
----------------------------------------------------------------------
|
||||||
|
|
||||||
Copyright (c) 2006-2020, assimp team
|
Copyright (c) 2006-2021, assimp team
|
||||||
|
|
||||||
|
|
||||||
All rights reserved.
|
All rights reserved.
|
||||||
|
@ -45,8 +45,8 @@ OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||||
#ifndef AI_COLLADALOADER_H_INC
|
#ifndef AI_COLLADALOADER_H_INC
|
||||||
#define AI_COLLADALOADER_H_INC
|
#define AI_COLLADALOADER_H_INC
|
||||||
|
|
||||||
#include <assimp/BaseImporter.h>
|
|
||||||
#include "ColladaParser.h"
|
#include "ColladaParser.h"
|
||||||
|
#include <assimp/BaseImporter.h>
|
||||||
|
|
||||||
struct aiNode;
|
struct aiNode;
|
||||||
struct aiCamera;
|
struct aiCamera;
|
||||||
|
@ -54,28 +54,24 @@ struct aiLight;
|
||||||
struct aiTexture;
|
struct aiTexture;
|
||||||
struct aiAnimation;
|
struct aiAnimation;
|
||||||
|
|
||||||
namespace Assimp
|
namespace Assimp {
|
||||||
{
|
|
||||||
|
|
||||||
struct ColladaMeshIndex
|
struct ColladaMeshIndex {
|
||||||
{
|
|
||||||
std::string mMeshID;
|
std::string mMeshID;
|
||||||
size_t mSubMesh;
|
size_t mSubMesh;
|
||||||
std::string mMaterial;
|
std::string mMaterial;
|
||||||
ColladaMeshIndex( const std::string& pMeshID, size_t pSubMesh, const std::string& pMaterial)
|
ColladaMeshIndex(const std::string &pMeshID, size_t pSubMesh, const std::string &pMaterial) :
|
||||||
: mMeshID( pMeshID), mSubMesh( pSubMesh), mMaterial( pMaterial)
|
mMeshID(pMeshID), mSubMesh(pSubMesh), mMaterial(pMaterial) {
|
||||||
{ }
|
ai_assert(!pMeshID.empty());
|
||||||
|
}
|
||||||
|
|
||||||
bool operator < (const ColladaMeshIndex& p) const
|
bool operator<(const ColladaMeshIndex &p) const {
|
||||||
{
|
if (mMeshID == p.mMeshID) {
|
||||||
if( mMeshID == p.mMeshID)
|
if (mSubMesh == p.mSubMesh)
|
||||||
{
|
|
||||||
if( mSubMesh == p.mSubMesh)
|
|
||||||
return mMaterial < p.mMaterial;
|
return mMaterial < p.mMaterial;
|
||||||
else
|
else
|
||||||
return mSubMesh < p.mSubMesh;
|
return mSubMesh < p.mSubMesh;
|
||||||
} else
|
} else {
|
||||||
{
|
|
||||||
return mMeshID < p.mMeshID;
|
return mMeshID < p.mMeshID;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -84,105 +80,102 @@ struct ColladaMeshIndex
|
||||||
/** Loader class to read Collada scenes. Collada is over-engineered to death, with every new iteration bringing
|
/** Loader class to read Collada scenes. Collada is over-engineered to death, with every new iteration bringing
|
||||||
* more useless stuff, so I limited the data to what I think is useful for games.
|
* more useless stuff, so I limited the data to what I think is useful for games.
|
||||||
*/
|
*/
|
||||||
class ColladaLoader : public BaseImporter
|
class ColladaLoader : public BaseImporter {
|
||||||
{
|
|
||||||
public:
|
public:
|
||||||
|
/// The class constructor.
|
||||||
ColladaLoader();
|
ColladaLoader();
|
||||||
~ColladaLoader();
|
|
||||||
|
|
||||||
|
/// The class destructor.
|
||||||
|
~ColladaLoader() override;
|
||||||
|
|
||||||
public:
|
/// Returns whether the class can handle the format of the given file.
|
||||||
/** Returns whether the class can handle the format of the given file.
|
/// @see BaseImporter::CanRead() for more details.
|
||||||
* See BaseImporter::CanRead() for details. */
|
bool CanRead(const std::string &pFile, IOSystem *pIOHandler, bool checkSig) const override;
|
||||||
bool CanRead(const std::string& pFile, IOSystem* pIOHandler, bool checkSig) const override;
|
|
||||||
|
|
||||||
protected:
|
protected:
|
||||||
/** Return importer meta information.
|
/// See #BaseImporter::GetInfo for the details
|
||||||
* See #BaseImporter::GetInfo for the details
|
const aiImporterDesc *GetInfo() const override;
|
||||||
*/
|
|
||||||
const aiImporterDesc* GetInfo () const override;
|
|
||||||
|
|
||||||
void SetupProperties(const Importer* pImp) override;
|
/// See #BaseImporter::SetupProperties for the details
|
||||||
|
void SetupProperties(const Importer *pImp) override;
|
||||||
|
|
||||||
/** Imports the given file into the given scene structure.
|
/// See #BaseImporter::InternReadFile for the details
|
||||||
* See BaseImporter::InternReadFile() for details
|
void InternReadFile(const std::string &pFile, aiScene *pScene, IOSystem *pIOHandler) override;
|
||||||
*/
|
|
||||||
void InternReadFile( const std::string& pFile, aiScene* pScene, IOSystem* pIOHandler) override;
|
|
||||||
|
|
||||||
/** Recursively constructs a scene node for the given parser node and returns it. */
|
/** Recursively constructs a scene node for the given parser node and returns it. */
|
||||||
aiNode* BuildHierarchy( const ColladaParser& pParser, const Collada::Node* pNode);
|
aiNode *BuildHierarchy(const ColladaParser &pParser, const Collada::Node *pNode);
|
||||||
|
|
||||||
/** Resolve node instances */
|
/** Resolve node instances */
|
||||||
void ResolveNodeInstances( const ColladaParser& pParser, const Collada::Node* pNode,
|
void ResolveNodeInstances(const ColladaParser &pParser, const Collada::Node *pNode,
|
||||||
std::vector<const Collada::Node*>& resolved);
|
std::vector<const Collada::Node *> &resolved);
|
||||||
|
|
||||||
/** Builds meshes for the given node and references them */
|
/** Builds meshes for the given node and references them */
|
||||||
void BuildMeshesForNode( const ColladaParser& pParser, const Collada::Node* pNode,
|
void BuildMeshesForNode(const ColladaParser &pParser, const Collada::Node *pNode,
|
||||||
aiNode* pTarget);
|
aiNode *pTarget);
|
||||||
|
|
||||||
aiMesh *findMesh(const std::string& meshid);
|
aiMesh *findMesh(const std::string &meshid);
|
||||||
|
|
||||||
/** Creates a mesh for the given ColladaMesh face subset and returns the newly created mesh */
|
/** Creates a mesh for the given ColladaMesh face subset and returns the newly created mesh */
|
||||||
aiMesh* CreateMesh( const ColladaParser& pParser, const Collada::Mesh* pSrcMesh, const Collada::SubMesh& pSubMesh,
|
aiMesh *CreateMesh(const ColladaParser &pParser, const Collada::Mesh *pSrcMesh, const Collada::SubMesh &pSubMesh,
|
||||||
const Collada::Controller* pSrcController, size_t pStartVertex, size_t pStartFace);
|
const Collada::Controller *pSrcController, size_t pStartVertex, size_t pStartFace);
|
||||||
|
|
||||||
/** Builds cameras for the given node and references them */
|
/** Builds cameras for the given node and references them */
|
||||||
void BuildCamerasForNode( const ColladaParser& pParser, const Collada::Node* pNode,
|
void BuildCamerasForNode(const ColladaParser &pParser, const Collada::Node *pNode,
|
||||||
aiNode* pTarget);
|
aiNode *pTarget);
|
||||||
|
|
||||||
/** Builds lights for the given node and references them */
|
/** Builds lights for the given node and references them */
|
||||||
void BuildLightsForNode( const ColladaParser& pParser, const Collada::Node* pNode,
|
void BuildLightsForNode(const ColladaParser &pParser, const Collada::Node *pNode,
|
||||||
aiNode* pTarget);
|
aiNode *pTarget);
|
||||||
|
|
||||||
/** Stores all meshes in the given scene */
|
/** Stores all meshes in the given scene */
|
||||||
void StoreSceneMeshes( aiScene* pScene);
|
void StoreSceneMeshes(aiScene *pScene);
|
||||||
|
|
||||||
/** Stores all materials in the given scene */
|
/** Stores all materials in the given scene */
|
||||||
void StoreSceneMaterials( aiScene* pScene);
|
void StoreSceneMaterials(aiScene *pScene);
|
||||||
|
|
||||||
/** Stores all lights in the given scene */
|
/** Stores all lights in the given scene */
|
||||||
void StoreSceneLights( aiScene* pScene);
|
void StoreSceneLights(aiScene *pScene);
|
||||||
|
|
||||||
/** Stores all cameras in the given scene */
|
/** Stores all cameras in the given scene */
|
||||||
void StoreSceneCameras( aiScene* pScene);
|
void StoreSceneCameras(aiScene *pScene);
|
||||||
|
|
||||||
/** Stores all textures in the given scene */
|
/** Stores all textures in the given scene */
|
||||||
void StoreSceneTextures( aiScene* pScene);
|
void StoreSceneTextures(aiScene *pScene);
|
||||||
|
|
||||||
/** Stores all animations
|
/** Stores all animations
|
||||||
* @param pScene target scene to store the anims
|
* @param pScene target scene to store the anims
|
||||||
*/
|
*/
|
||||||
void StoreAnimations( aiScene* pScene, const ColladaParser& pParser);
|
void StoreAnimations(aiScene *pScene, const ColladaParser &pParser);
|
||||||
|
|
||||||
/** Stores all animations for the given source anim and its nested child animations
|
/** Stores all animations for the given source anim and its nested child animations
|
||||||
* @param pScene target scene to store the anims
|
* @param pScene target scene to store the anims
|
||||||
* @param pSrcAnim the source animation to process
|
* @param pSrcAnim the source animation to process
|
||||||
* @param pPrefix Prefix to the name in case of nested animations
|
* @param pPrefix Prefix to the name in case of nested animations
|
||||||
*/
|
*/
|
||||||
void StoreAnimations( aiScene* pScene, const ColladaParser& pParser, const Collada::Animation* pSrcAnim, const std::string& pPrefix);
|
void StoreAnimations(aiScene *pScene, const ColladaParser &pParser, const Collada::Animation *pSrcAnim, const std::string &pPrefix);
|
||||||
|
|
||||||
/** Constructs the animation for the given source anim */
|
/** Constructs the animation for the given source anim */
|
||||||
void CreateAnimation( aiScene* pScene, const ColladaParser& pParser, const Collada::Animation* pSrcAnim, const std::string& pName);
|
void CreateAnimation(aiScene *pScene, const ColladaParser &pParser, const Collada::Animation *pSrcAnim, const std::string &pName);
|
||||||
|
|
||||||
/** Constructs materials from the collada material definitions */
|
/** Constructs materials from the collada material definitions */
|
||||||
void BuildMaterials( ColladaParser& pParser, aiScene* pScene);
|
void BuildMaterials(ColladaParser &pParser, aiScene *pScene);
|
||||||
|
|
||||||
/** Fill materials from the collada material definitions */
|
/** Fill materials from the collada material definitions */
|
||||||
void FillMaterials( const ColladaParser& pParser, aiScene* pScene);
|
void FillMaterials(const ColladaParser &pParser, aiScene *pScene);
|
||||||
|
|
||||||
/** Resolve UV channel mappings*/
|
/** Resolve UV channel mappings*/
|
||||||
void ApplyVertexToEffectSemanticMapping(Collada::Sampler& sampler,
|
void ApplyVertexToEffectSemanticMapping(Collada::Sampler &sampler,
|
||||||
const Collada::SemanticMappingTable& table);
|
const Collada::SemanticMappingTable &table);
|
||||||
|
|
||||||
/** Add a texture and all of its sampling properties to a material*/
|
/** Add a texture and all of its sampling properties to a material*/
|
||||||
void AddTexture ( aiMaterial& mat, const ColladaParser& pParser,
|
void AddTexture(aiMaterial &mat, const ColladaParser &pParser,
|
||||||
const Collada::Effect& effect,
|
const Collada::Effect &effect,
|
||||||
const Collada::Sampler& sampler,
|
const Collada::Sampler &sampler,
|
||||||
aiTextureType type, unsigned int idx = 0);
|
aiTextureType type, unsigned int idx = 0);
|
||||||
|
|
||||||
/** Resolves the texture name for the given effect texture entry */
|
/** Resolves the texture name for the given effect texture entry */
|
||||||
aiString FindFilenameForEffectTexture( const ColladaParser& pParser,
|
aiString FindFilenameForEffectTexture(const ColladaParser &pParser,
|
||||||
const Collada::Effect& pEffect, const std::string& pName);
|
const Collada::Effect &pEffect, const std::string &pName);
|
||||||
|
|
||||||
/** Reads a float value from an accessor and its data array.
|
/** Reads a float value from an accessor and its data array.
|
||||||
* @param pAccessor The accessor to use for reading
|
* @param pAccessor The accessor to use for reading
|
||||||
|
@ -191,7 +184,7 @@ protected:
|
||||||
* @param pOffset Offset into the element, for multipart elements such as vectors or matrices
|
* @param pOffset Offset into the element, for multipart elements such as vectors or matrices
|
||||||
* @return the specified value
|
* @return the specified value
|
||||||
*/
|
*/
|
||||||
ai_real ReadFloat( const Collada::Accessor& pAccessor, const Collada::Data& pData, size_t pIndex, size_t pOffset) const;
|
ai_real ReadFloat(const Collada::Accessor &pAccessor, const Collada::Data &pData, size_t pIndex, size_t pOffset) const;
|
||||||
|
|
||||||
/** Reads a string value from an accessor and its data array.
|
/** Reads a string value from an accessor and its data array.
|
||||||
* @param pAccessor The accessor to use for reading
|
* @param pAccessor The accessor to use for reading
|
||||||
|
@ -199,18 +192,18 @@ protected:
|
||||||
* @param pIndex The index of the element to retrieve
|
* @param pIndex The index of the element to retrieve
|
||||||
* @return the specified value
|
* @return the specified value
|
||||||
*/
|
*/
|
||||||
const std::string& ReadString( const Collada::Accessor& pAccessor, const Collada::Data& pData, size_t pIndex) const;
|
const std::string &ReadString(const Collada::Accessor &pAccessor, const Collada::Data &pData, size_t pIndex) const;
|
||||||
|
|
||||||
/** Recursively collects all nodes into the given array */
|
/** Recursively collects all nodes into the given array */
|
||||||
void CollectNodes( const aiNode* pNode, std::vector<const aiNode*>& poNodes) const;
|
void CollectNodes(const aiNode *pNode, std::vector<const aiNode *> &poNodes) const;
|
||||||
|
|
||||||
/** Finds a node in the collada scene by the given name */
|
/** Finds a node in the collada scene by the given name */
|
||||||
const Collada::Node* FindNode( const Collada::Node* pNode, const std::string& pName) const;
|
const Collada::Node *FindNode(const Collada::Node *pNode, const std::string &pName) const;
|
||||||
/** Finds a node in the collada scene by the given SID */
|
/** Finds a node in the collada scene by the given SID */
|
||||||
const Collada::Node* FindNodeBySID( const Collada::Node* pNode, const std::string& pSID) const;
|
const Collada::Node *FindNodeBySID(const Collada::Node *pNode, const std::string &pSID) const;
|
||||||
|
|
||||||
/** Finds a proper name for a node derived from the collada-node's properties */
|
/** Finds a proper name for a node derived from the collada-node's properties */
|
||||||
std::string FindNameForNode( const Collada::Node* pNode);
|
std::string FindNameForNode(const Collada::Node *pNode);
|
||||||
|
|
||||||
protected:
|
protected:
|
||||||
/** Filename, for a verbose error message */
|
/** Filename, for a verbose error message */
|
||||||
|
@ -223,25 +216,25 @@ protected:
|
||||||
std::map<std::string, size_t> mMaterialIndexByName;
|
std::map<std::string, size_t> mMaterialIndexByName;
|
||||||
|
|
||||||
/** Accumulated meshes for the target scene */
|
/** Accumulated meshes for the target scene */
|
||||||
std::vector<aiMesh*> mMeshes;
|
std::vector<aiMesh *> mMeshes;
|
||||||
|
|
||||||
/** Accumulated morph target meshes */
|
/** Accumulated morph target meshes */
|
||||||
std::vector<aiMesh*> mTargetMeshes;
|
std::vector<aiMesh *> mTargetMeshes;
|
||||||
|
|
||||||
/** Temporary material list */
|
/** Temporary material list */
|
||||||
std::vector<std::pair<Collada::Effect*, aiMaterial*> > newMats;
|
std::vector<std::pair<Collada::Effect *, aiMaterial *>> newMats;
|
||||||
|
|
||||||
/** Temporary camera list */
|
/** Temporary camera list */
|
||||||
std::vector<aiCamera*> mCameras;
|
std::vector<aiCamera *> mCameras;
|
||||||
|
|
||||||
/** Temporary light list */
|
/** Temporary light list */
|
||||||
std::vector<aiLight*> mLights;
|
std::vector<aiLight *> mLights;
|
||||||
|
|
||||||
/** Temporary texture list */
|
/** Temporary texture list */
|
||||||
std::vector<aiTexture*> mTextures;
|
std::vector<aiTexture *> mTextures;
|
||||||
|
|
||||||
/** Accumulated animations for the target scene */
|
/** Accumulated animations for the target scene */
|
||||||
std::vector<aiAnimation*> mAnims;
|
std::vector<aiAnimation *> mAnims;
|
||||||
|
|
||||||
bool noSkeletonMesh;
|
bool noSkeletonMesh;
|
||||||
bool ignoreUpDirection;
|
bool ignoreUpDirection;
|
||||||
|
|
|
@ -54,6 +54,7 @@ OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||||
#include <assimp/light.h>
|
#include <assimp/light.h>
|
||||||
#include <assimp/DefaultLogger.hpp>
|
#include <assimp/DefaultLogger.hpp>
|
||||||
#include <assimp/IOSystem.hpp>
|
#include <assimp/IOSystem.hpp>
|
||||||
|
#include <memory>
|
||||||
|
|
||||||
using namespace Assimp;
|
using namespace Assimp;
|
||||||
using namespace Assimp::Collada;
|
using namespace Assimp::Collada;
|
||||||
|
@ -158,9 +159,9 @@ ColladaParser::ColladaParser(IOSystem *pIOHandler, const std::string &pFile) :
|
||||||
if (colladaNode.empty()) {
|
if (colladaNode.empty()) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
ReadContents(colladaNode);
|
|
||||||
|
|
||||||
// read embedded textures
|
// Read content and embedded textures
|
||||||
|
ReadContents(colladaNode);
|
||||||
if (zip_archive && zip_archive->isOpen()) {
|
if (zip_archive && zip_archive->isOpen()) {
|
||||||
ReadEmbeddedTextures(*zip_archive);
|
ReadEmbeddedTextures(*zip_archive);
|
||||||
}
|
}
|
||||||
|
@ -169,11 +170,11 @@ ColladaParser::ColladaParser(IOSystem *pIOHandler, const std::string &pFile) :
|
||||||
// ------------------------------------------------------------------------------------------------
|
// ------------------------------------------------------------------------------------------------
|
||||||
// Destructor, private as well
|
// Destructor, private as well
|
||||||
ColladaParser::~ColladaParser() {
|
ColladaParser::~ColladaParser() {
|
||||||
for (NodeLibrary::iterator it = mNodeLibrary.begin(); it != mNodeLibrary.end(); ++it) {
|
for (auto & it : mNodeLibrary) {
|
||||||
delete it->second;
|
delete it.second;
|
||||||
}
|
}
|
||||||
for (MeshLibrary::iterator it = mMeshLibrary.begin(); it != mMeshLibrary.end(); ++it) {
|
for (auto & it : mMeshLibrary) {
|
||||||
delete it->second;
|
delete it.second;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -289,7 +290,7 @@ void ColladaParser::ReadContents(XmlNode &node) {
|
||||||
// Reads the structure of the file
|
// Reads the structure of the file
|
||||||
void ColladaParser::ReadStructure(XmlNode &node) {
|
void ColladaParser::ReadStructure(XmlNode &node) {
|
||||||
for (XmlNode ¤tNode : node.children()) {
|
for (XmlNode ¤tNode : node.children()) {
|
||||||
const std::string ¤tName = std::string(currentNode.name());
|
const std::string ¤tName = currentNode.name();
|
||||||
if (currentName == "asset") {
|
if (currentName == "asset") {
|
||||||
ReadAssetInfo(currentNode);
|
ReadAssetInfo(currentNode);
|
||||||
} else if (currentName == "library_animations") {
|
} else if (currentName == "library_animations") {
|
||||||
|
@ -407,7 +408,7 @@ void ColladaParser::ReadAnimationClipLibrary(XmlNode &node) {
|
||||||
const std::string ¤tName = currentNode.name();
|
const std::string ¤tName = currentNode.name();
|
||||||
if (currentName == "instance_animation") {
|
if (currentName == "instance_animation") {
|
||||||
std::string url;
|
std::string url;
|
||||||
readUrlAttribute(node, url);
|
readUrlAttribute(currentNode, url);
|
||||||
clip.second.push_back(url);
|
clip.second.push_back(url);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -419,8 +420,8 @@ void ColladaParser::ReadAnimationClipLibrary(XmlNode &node) {
|
||||||
|
|
||||||
void ColladaParser::PostProcessControllers() {
|
void ColladaParser::PostProcessControllers() {
|
||||||
std::string meshId;
|
std::string meshId;
|
||||||
for (ControllerLibrary::iterator it = mControllerLibrary.begin(); it != mControllerLibrary.end(); ++it) {
|
for (auto & it : mControllerLibrary) {
|
||||||
meshId = it->second.mMeshId;
|
meshId = it.second.mMeshId;
|
||||||
if (meshId.empty()) {
|
if (meshId.empty()) {
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
@ -431,7 +432,7 @@ void ColladaParser::PostProcessControllers() {
|
||||||
findItr = mControllerLibrary.find(meshId);
|
findItr = mControllerLibrary.find(meshId);
|
||||||
}
|
}
|
||||||
|
|
||||||
it->second.mMeshId = meshId;
|
it.second.mMeshId = meshId;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -444,17 +445,15 @@ void ColladaParser::PostProcessRootAnimations() {
|
||||||
}
|
}
|
||||||
|
|
||||||
Animation temp;
|
Animation temp;
|
||||||
for (AnimationClipLibrary::iterator it = mAnimationClipLibrary.begin(); it != mAnimationClipLibrary.end(); ++it) {
|
for (auto & it : mAnimationClipLibrary) {
|
||||||
std::string clipName = it->first;
|
std::string clipName = it.first;
|
||||||
|
|
||||||
Animation *clip = new Animation();
|
Animation *clip = new Animation();
|
||||||
clip->mName = clipName;
|
clip->mName = clipName;
|
||||||
|
|
||||||
temp.mSubAnims.push_back(clip);
|
temp.mSubAnims.push_back(clip);
|
||||||
|
|
||||||
for (std::vector<std::string>::iterator a = it->second.begin(); a != it->second.end(); ++a) {
|
for (std::string animationID : it.second) {
|
||||||
std::string animationID = *a;
|
|
||||||
|
|
||||||
AnimationLibrary::iterator animation = mAnimationLibrary.find(animationID);
|
AnimationLibrary::iterator animation = mAnimationLibrary.find(animationID);
|
||||||
|
|
||||||
if (animation != mAnimationLibrary.end()) {
|
if (animation != mAnimationLibrary.end()) {
|
||||||
|
@ -494,7 +493,7 @@ void ColladaParser::ReadAnimation(XmlNode &node, Collada::Animation *pParent) {
|
||||||
|
|
||||||
// an <animation> element may be a container for grouping sub-elements or an animation channel
|
// an <animation> element may be a container for grouping sub-elements or an animation channel
|
||||||
// this is the channel collection by ID, in case it has channels
|
// this is the channel collection by ID, in case it has channels
|
||||||
using ChannelMap = std::map<std::string, AnimationChannel> ;
|
using ChannelMap = std::map<std::string, AnimationChannel>;
|
||||||
ChannelMap channels;
|
ChannelMap channels;
|
||||||
// this is the anim container in case we're a container
|
// this is the anim container in case we're a container
|
||||||
Animation *anim = nullptr;
|
Animation *anim = nullptr;
|
||||||
|
@ -553,8 +552,8 @@ void ColladaParser::ReadAnimation(XmlNode &node, Collada::Animation *pParent) {
|
||||||
pParent->mSubAnims.push_back(anim);
|
pParent->mSubAnims.push_back(anim);
|
||||||
}
|
}
|
||||||
|
|
||||||
for (ChannelMap::const_iterator it = channels.begin(); it != channels.end(); ++it) {
|
for (const auto & channel : channels) {
|
||||||
anim->mChannels.push_back(it->second);
|
anim->mChannels.push_back(channel.second);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (idAttr) {
|
if (idAttr) {
|
||||||
|
@ -609,50 +608,62 @@ void ColladaParser::ReadControllerLibrary(XmlNode &node) {
|
||||||
if (currentName != "controller") {
|
if (currentName != "controller") {
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
std::string id = node.attribute("id").as_string();
|
std::string id;
|
||||||
|
if (XmlParser::getStdStrAttribute(currentNode, "id", id)) {
|
||||||
mControllerLibrary[id] = Controller();
|
mControllerLibrary[id] = Controller();
|
||||||
ReadController(node, mControllerLibrary[id]);
|
ReadController(currentNode, mControllerLibrary[id]);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// ------------------------------------------------------------------------------------------------
|
// ------------------------------------------------------------------------------------------------
|
||||||
// Reads a controller into the given mesh structure
|
// Reads a controller into the given mesh structure
|
||||||
void ColladaParser::ReadController(XmlNode &node, Collada::Controller &pController) {
|
void ColladaParser::ReadController(XmlNode &node, Collada::Controller &controller) {
|
||||||
// initial values
|
// initial values
|
||||||
pController.mType = Skin;
|
controller.mType = Skin;
|
||||||
pController.mMethod = Normalized;
|
controller.mMethod = Normalized;
|
||||||
for (XmlNode ¤tNode : node.children()) {
|
|
||||||
|
XmlNodeIterator xmlIt(node);
|
||||||
|
xmlIt.collectChildrenPreOrder(node);
|
||||||
|
XmlNode currentNode;
|
||||||
|
while (xmlIt.getNext(currentNode)) {
|
||||||
|
|
||||||
|
//for (XmlNode ¤tNode : node.children()) {
|
||||||
const std::string ¤tName = currentNode.name();
|
const std::string ¤tName = currentNode.name();
|
||||||
if (currentName == "morph") {
|
if (currentName == "morph") {
|
||||||
pController.mType = Morph;
|
controller.mType = Morph;
|
||||||
pController.mMeshId = currentNode.attribute("source").as_string();
|
controller.mMeshId = currentNode.attribute("source").as_string();
|
||||||
int methodIndex = currentNode.attribute("method").as_int();
|
int methodIndex = currentNode.attribute("method").as_int();
|
||||||
if (methodIndex > 0) {
|
if (methodIndex > 0) {
|
||||||
std::string method;
|
std::string method;
|
||||||
XmlParser::getValueAsString(currentNode, method);
|
XmlParser::getValueAsString(currentNode, method);
|
||||||
|
|
||||||
if (method == "RELATIVE") {
|
if (method == "RELATIVE") {
|
||||||
pController.mMethod = Relative;
|
controller.mMethod = Relative;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
} else if (currentName == "skin") {
|
} else if (currentName == "skin") {
|
||||||
pController.mMeshId = currentNode.attribute("source").as_string();
|
std::string id;
|
||||||
|
if (XmlParser::getStdStrAttribute(currentNode, "source", id)) {
|
||||||
|
controller.mMeshId = id.substr(1, id.size()-1);
|
||||||
|
}
|
||||||
} else if (currentName == "bind_shape_matrix") {
|
} else if (currentName == "bind_shape_matrix") {
|
||||||
std::string v;
|
std::string v;
|
||||||
XmlParser::getValueAsString(currentNode, v);
|
XmlParser::getValueAsString(currentNode, v);
|
||||||
const char *content = v.c_str();
|
const char *content = v.c_str();
|
||||||
for (unsigned int a = 0; a < 16; a++) {
|
for (unsigned int a = 0; a < 16; a++) {
|
||||||
|
SkipSpacesAndLineEnd(&content);
|
||||||
// read a number
|
// read a number
|
||||||
content = fast_atoreal_move<ai_real>(content, pController.mBindShapeMatrix[a]);
|
content = fast_atoreal_move<ai_real>(content, controller.mBindShapeMatrix[a]);
|
||||||
// skip whitespace after it
|
// skip whitespace after it
|
||||||
SkipSpacesAndLineEnd(&content);
|
SkipSpacesAndLineEnd(&content);
|
||||||
}
|
}
|
||||||
} else if (currentName == "source") {
|
} else if (currentName == "source") {
|
||||||
ReadSource(currentNode);
|
ReadSource(currentNode);
|
||||||
} else if (currentName == "joints") {
|
} else if (currentName == "joints") {
|
||||||
ReadControllerJoints(currentNode, pController);
|
ReadControllerJoints(currentNode, controller);
|
||||||
} else if (currentName == "vertex_weights") {
|
} else if (currentName == "vertex_weights") {
|
||||||
ReadControllerWeights(currentNode, pController);
|
ReadControllerWeights(currentNode, controller);
|
||||||
} else if (currentName == "targets") {
|
} else if (currentName == "targets") {
|
||||||
for (XmlNode currentChildNode = node.first_child(); currentNode; currentNode = currentNode.next_sibling()) {
|
for (XmlNode currentChildNode = node.first_child(); currentNode; currentNode = currentNode.next_sibling()) {
|
||||||
const std::string ¤tChildName = currentChildNode.name();
|
const std::string ¤tChildName = currentChildNode.name();
|
||||||
|
@ -660,9 +671,9 @@ void ColladaParser::ReadController(XmlNode &node, Collada::Controller &pControll
|
||||||
const char *semantics = currentChildNode.attribute("semantic").as_string();
|
const char *semantics = currentChildNode.attribute("semantic").as_string();
|
||||||
const char *source = currentChildNode.attribute("source").as_string();
|
const char *source = currentChildNode.attribute("source").as_string();
|
||||||
if (strcmp(semantics, "MORPH_TARGET") == 0) {
|
if (strcmp(semantics, "MORPH_TARGET") == 0) {
|
||||||
pController.mMorphTarget = source + 1;
|
controller.mMorphTarget = source + 1;
|
||||||
} else if (strcmp(semantics, "MORPH_WEIGHT") == 0) {
|
} else if (strcmp(semantics, "MORPH_WEIGHT") == 0) {
|
||||||
pController.mMorphWeight = source + 1;
|
controller.mMorphWeight = source + 1;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -700,6 +711,7 @@ void ColladaParser::ReadControllerWeights(XmlNode &node, Collada::Controller &pC
|
||||||
// Read vertex count from attributes and resize the array accordingly
|
// Read vertex count from attributes and resize the array accordingly
|
||||||
int vertexCount=0;
|
int vertexCount=0;
|
||||||
XmlParser::getIntAttribute(node, "count", vertexCount);
|
XmlParser::getIntAttribute(node, "count", vertexCount);
|
||||||
|
pController.mWeightCounts.resize(vertexCount);
|
||||||
|
|
||||||
for (XmlNode ¤tNode : node.children()) {
|
for (XmlNode ¤tNode : node.children()) {
|
||||||
const std::string ¤tName = currentNode.name();
|
const std::string ¤tName = currentNode.name();
|
||||||
|
@ -725,7 +737,7 @@ void ColladaParser::ReadControllerWeights(XmlNode &node, Collada::Controller &pC
|
||||||
throw DeadlyImportError("Unknown semantic \"", attrSemantic, "\" in <vertex_weights> data <input> element");
|
throw DeadlyImportError("Unknown semantic \"", attrSemantic, "\" in <vertex_weights> data <input> element");
|
||||||
}
|
}
|
||||||
} else if (currentName == "vcount" && vertexCount > 0) {
|
} else if (currentName == "vcount" && vertexCount > 0) {
|
||||||
const char *text = currentNode.value();
|
const char *text = currentNode.text().as_string();
|
||||||
size_t numWeights = 0;
|
size_t numWeights = 0;
|
||||||
for (std::vector<size_t>::iterator it = pController.mWeightCounts.begin(); it != pController.mWeightCounts.end(); ++it) {
|
for (std::vector<size_t>::iterator it = pController.mWeightCounts.begin(); it != pController.mWeightCounts.end(); ++it) {
|
||||||
if (*text == 0) {
|
if (*text == 0) {
|
||||||
|
@ -762,20 +774,17 @@ void ColladaParser::ReadControllerWeights(XmlNode &node, Collada::Controller &pC
|
||||||
// ------------------------------------------------------------------------------------------------
|
// ------------------------------------------------------------------------------------------------
|
||||||
// Reads the image library contents
|
// Reads the image library contents
|
||||||
void ColladaParser::ReadImageLibrary(XmlNode &node) {
|
void ColladaParser::ReadImageLibrary(XmlNode &node) {
|
||||||
if (node.empty()) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
for (XmlNode ¤tNode : node.children()) {
|
for (XmlNode ¤tNode : node.children()) {
|
||||||
const std::string ¤tName = currentNode.name();
|
const std::string ¤tName = currentNode.name();
|
||||||
if (currentName == "image") {
|
if (currentName == "image") {
|
||||||
std::string id = currentNode.attribute("id").as_string();
|
std::string id;
|
||||||
|
if (XmlParser::getStdStrAttribute( currentNode, "id", id )) {
|
||||||
mImageLibrary[id] = Image();
|
mImageLibrary[id] = Image();
|
||||||
|
|
||||||
// read on from there
|
// read on from there
|
||||||
ReadImage(currentNode, mImageLibrary[id]);
|
ReadImage(currentNode, mImageLibrary[id]);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// ------------------------------------------------------------------------------------------------
|
// ------------------------------------------------------------------------------------------------
|
||||||
|
@ -792,7 +801,7 @@ void ColladaParser::ReadImage(XmlNode &node, Collada::Image &pImage) {
|
||||||
if (!currentNode.empty()) {
|
if (!currentNode.empty()) {
|
||||||
// element content is filename - hopefully
|
// element content is filename - hopefully
|
||||||
const char *sz = currentNode.text().as_string();
|
const char *sz = currentNode.text().as_string();
|
||||||
if (sz) {
|
if (nullptr != sz) {
|
||||||
aiString filepath(sz);
|
aiString filepath(sz);
|
||||||
UriDecodePath(filepath);
|
UriDecodePath(filepath);
|
||||||
pImage.mFileName = filepath.C_Str();
|
pImage.mFileName = filepath.C_Str();
|
||||||
|
@ -842,10 +851,6 @@ void ColladaParser::ReadImage(XmlNode &node, Collada::Image &pImage) {
|
||||||
// ------------------------------------------------------------------------------------------------
|
// ------------------------------------------------------------------------------------------------
|
||||||
// Reads the material library
|
// Reads the material library
|
||||||
void ColladaParser::ReadMaterialLibrary(XmlNode &node) {
|
void ColladaParser::ReadMaterialLibrary(XmlNode &node) {
|
||||||
if (node.empty()) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
std::map<std::string, int> names;
|
std::map<std::string, int> names;
|
||||||
for (XmlNode ¤tNode : node.children()) {
|
for (XmlNode ¤tNode : node.children()) {
|
||||||
std::string id = currentNode.attribute("id").as_string();
|
std::string id = currentNode.attribute("id").as_string();
|
||||||
|
@ -872,10 +877,6 @@ void ColladaParser::ReadMaterialLibrary(XmlNode &node) {
|
||||||
// ------------------------------------------------------------------------------------------------
|
// ------------------------------------------------------------------------------------------------
|
||||||
// Reads the light library
|
// Reads the light library
|
||||||
void ColladaParser::ReadLightLibrary(XmlNode &node) {
|
void ColladaParser::ReadLightLibrary(XmlNode &node) {
|
||||||
if (node.empty()) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
for (XmlNode ¤tNode : node.children()) {
|
for (XmlNode ¤tNode : node.children()) {
|
||||||
const std::string ¤tName = currentNode.name();
|
const std::string ¤tName = currentNode.name();
|
||||||
if (currentName == "light") {
|
if (currentName == "light") {
|
||||||
|
@ -890,10 +891,6 @@ void ColladaParser::ReadLightLibrary(XmlNode &node) {
|
||||||
// ------------------------------------------------------------------------------------------------
|
// ------------------------------------------------------------------------------------------------
|
||||||
// Reads the camera library
|
// Reads the camera library
|
||||||
void ColladaParser::ReadCameraLibrary(XmlNode &node) {
|
void ColladaParser::ReadCameraLibrary(XmlNode &node) {
|
||||||
if (node.empty()) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
for (XmlNode ¤tNode : node.children()) {
|
for (XmlNode ¤tNode : node.children()) {
|
||||||
const std::string ¤tName = currentNode.name();
|
const std::string ¤tName = currentNode.name();
|
||||||
if (currentName == "camera") {
|
if (currentName == "camera") {
|
||||||
|
|
|
@ -571,7 +571,6 @@ namespace glTF2 {
|
||||||
|
|
||||||
inline void Write(Value& obj, Node& n, AssetWriter& w)
|
inline void Write(Value& obj, Node& n, AssetWriter& w)
|
||||||
{
|
{
|
||||||
|
|
||||||
if (n.matrix.isPresent) {
|
if (n.matrix.isPresent) {
|
||||||
Value val;
|
Value val;
|
||||||
obj.AddMember("matrix", MakeValue(val, n.matrix.value, w.mAl).Move(), w.mAl);
|
obj.AddMember("matrix", MakeValue(val, n.matrix.value, w.mAl).Move(), w.mAl);
|
||||||
|
@ -597,14 +596,13 @@ namespace glTF2 {
|
||||||
obj.AddMember("mesh", n.meshes[0]->index, w.mAl);
|
obj.AddMember("mesh", n.meshes[0]->index, w.mAl);
|
||||||
}
|
}
|
||||||
|
|
||||||
AddRefsVector(obj, "skeletons", n.skeletons, w.mAl);
|
|
||||||
|
|
||||||
if (n.skin) {
|
if (n.skin) {
|
||||||
obj.AddMember("skin", n.skin->index, w.mAl);
|
obj.AddMember("skin", n.skin->index, w.mAl);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!n.jointName.empty()) {
|
//gltf2 spec does not support "skeletons" under node
|
||||||
obj.AddMember("jointName", n.jointName, w.mAl);
|
if(n.skeletons.size()) {
|
||||||
|
AddRefsVector(obj, "skeletons", n.skeletons, w.mAl);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -1095,6 +1095,7 @@ void glTF2Exporter::ExportMeshes()
|
||||||
//----------------------------------------
|
//----------------------------------------
|
||||||
// Finish the skin
|
// Finish the skin
|
||||||
// Create the Accessor for skinRef->inverseBindMatrices
|
// Create the Accessor for skinRef->inverseBindMatrices
|
||||||
|
bool bAddCustomizedProperty = this->mProperties->HasPropertyBool("GLTF2_CUSTOMIZE_PROPERTY");
|
||||||
if (createSkin) {
|
if (createSkin) {
|
||||||
mat4* invBindMatrixData = new mat4[inverseBindMatricesData.size()];
|
mat4* invBindMatrixData = new mat4[inverseBindMatricesData.size()];
|
||||||
for ( unsigned int idx_joint = 0; idx_joint < inverseBindMatricesData.size(); ++idx_joint) {
|
for ( unsigned int idx_joint = 0; idx_joint < inverseBindMatricesData.size(); ++idx_joint) {
|
||||||
|
@ -1110,7 +1111,7 @@ void glTF2Exporter::ExportMeshes()
|
||||||
|
|
||||||
// Identity Matrix =====> skinRef->bindShapeMatrix
|
// Identity Matrix =====> skinRef->bindShapeMatrix
|
||||||
// Temporary. Hard-coded identity matrix here
|
// Temporary. Hard-coded identity matrix here
|
||||||
skinRef->bindShapeMatrix.isPresent = true;
|
skinRef->bindShapeMatrix.isPresent = bAddCustomizedProperty;
|
||||||
IdentityMatrix4(skinRef->bindShapeMatrix.value);
|
IdentityMatrix4(skinRef->bindShapeMatrix.value);
|
||||||
|
|
||||||
// Find nodes that contain a mesh with bones and add "skeletons" and "skin" attributes to those nodes.
|
// Find nodes that contain a mesh with bones and add "skeletons" and "skin" attributes to those nodes.
|
||||||
|
@ -1131,6 +1132,7 @@ void glTF2Exporter::ExportMeshes()
|
||||||
std::string meshID = mesh->id;
|
std::string meshID = mesh->id;
|
||||||
FindMeshNode(rootNode, meshNode, meshID);
|
FindMeshNode(rootNode, meshNode, meshID);
|
||||||
Ref<Node> rootJoint = FindSkeletonRootJoint(skinRef);
|
Ref<Node> rootJoint = FindSkeletonRootJoint(skinRef);
|
||||||
|
if(bAddCustomizedProperty)
|
||||||
meshNode->skeletons.push_back(rootJoint);
|
meshNode->skeletons.push_back(rootJoint);
|
||||||
meshNode->skin = skinRef;
|
meshNode->skin = skinRef;
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,6 +1,6 @@
|
||||||
// Tencent is pleased to support the open source community by making RapidJSON available.
|
// 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.
|
// Copyright (C) 2015 THL A29 Limited, a Tencent company, and Milo Yip.
|
||||||
//
|
//
|
||||||
// Licensed under the MIT License (the "License"); you may not use this file except
|
// 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
|
// in compliance with the License. You may obtain a copy of the License at
|
||||||
|
@ -52,6 +52,19 @@ concept Allocator {
|
||||||
\endcode
|
\endcode
|
||||||
*/
|
*/
|
||||||
|
|
||||||
|
|
||||||
|
/*! \def RAPIDJSON_ALLOCATOR_DEFAULT_CHUNK_CAPACITY
|
||||||
|
\ingroup RAPIDJSON_CONFIG
|
||||||
|
\brief User-defined kDefaultChunkCapacity definition.
|
||||||
|
|
||||||
|
User can define this as any \c size that is a power of 2.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#ifndef RAPIDJSON_ALLOCATOR_DEFAULT_CHUNK_CAPACITY
|
||||||
|
#define RAPIDJSON_ALLOCATOR_DEFAULT_CHUNK_CAPACITY (64 * 1024)
|
||||||
|
#endif
|
||||||
|
|
||||||
|
|
||||||
///////////////////////////////////////////////////////////////////////////////
|
///////////////////////////////////////////////////////////////////////////////
|
||||||
// CrtAllocator
|
// CrtAllocator
|
||||||
|
|
||||||
|
@ -64,19 +77,19 @@ public:
|
||||||
static const bool kNeedFree = true;
|
static const bool kNeedFree = true;
|
||||||
void* Malloc(size_t size) {
|
void* Malloc(size_t size) {
|
||||||
if (size) // behavior of malloc(0) is implementation defined.
|
if (size) // behavior of malloc(0) is implementation defined.
|
||||||
return std::malloc(size);
|
return RAPIDJSON_MALLOC(size);
|
||||||
else
|
else
|
||||||
return NULL; // standardize to returning NULL.
|
return NULL; // standardize to returning NULL.
|
||||||
}
|
}
|
||||||
void* Realloc(void* originalPtr, size_t originalSize, size_t newSize) {
|
void* Realloc(void* originalPtr, size_t originalSize, size_t newSize) {
|
||||||
(void)originalSize;
|
(void)originalSize;
|
||||||
if (newSize == 0) {
|
if (newSize == 0) {
|
||||||
std::free(originalPtr);
|
RAPIDJSON_FREE(originalPtr);
|
||||||
return NULL;
|
return NULL;
|
||||||
}
|
}
|
||||||
return std::realloc(originalPtr, newSize);
|
return RAPIDJSON_REALLOC(originalPtr, newSize);
|
||||||
}
|
}
|
||||||
static void Free(void *ptr) { std::free(ptr); }
|
static void Free(void *ptr) { RAPIDJSON_FREE(ptr); }
|
||||||
};
|
};
|
||||||
|
|
||||||
///////////////////////////////////////////////////////////////////////////////
|
///////////////////////////////////////////////////////////////////////////////
|
||||||
|
@ -248,7 +261,7 @@ private:
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
static const int kDefaultChunkCapacity = 64 * 1024; //!< Default chunk capacity.
|
static const int kDefaultChunkCapacity = RAPIDJSON_ALLOCATOR_DEFAULT_CHUNK_CAPACITY; //!< Default chunk capacity.
|
||||||
|
|
||||||
//! Chunk header for perpending to each chunk.
|
//! Chunk header for perpending to each chunk.
|
||||||
/*! Chunks are stored as a singly linked list.
|
/*! Chunks are stored as a singly linked list.
|
||||||
|
|
|
@ -0,0 +1,78 @@
|
||||||
|
// 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.
|
||||||
|
//
|
||||||
|
// 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_
|
||||||
|
|
||||||
|
#include "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_
|
|
@ -1,6 +1,6 @@
|
||||||
// Tencent is pleased to support the open source community by making RapidJSON available.
|
// 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.
|
// Copyright (C) 2015 THL A29 Limited, a Tencent company, and Milo Yip.
|
||||||
//
|
//
|
||||||
// Licensed under the MIT License (the "License"); you may not use this file except
|
// 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
|
// in compliance with the License. You may obtain a copy of the License at
|
||||||
|
@ -17,11 +17,6 @@
|
||||||
|
|
||||||
/*! \file document.h */
|
/*! \file document.h */
|
||||||
|
|
||||||
#if (__GNUC__ >= 8 && __GNUC_MINOR__ >= 0)
|
|
||||||
#pragma GCC diagnostic push
|
|
||||||
#pragma GCC diagnostic ignored "-Wclass-memaccess"
|
|
||||||
#endif
|
|
||||||
|
|
||||||
#include "reader.h"
|
#include "reader.h"
|
||||||
#include "internal/meta.h"
|
#include "internal/meta.h"
|
||||||
#include "internal/strfunc.h"
|
#include "internal/strfunc.h"
|
||||||
|
@ -29,28 +24,26 @@
|
||||||
#include "encodedstream.h"
|
#include "encodedstream.h"
|
||||||
#include <new> // placement new
|
#include <new> // placement new
|
||||||
#include <limits>
|
#include <limits>
|
||||||
|
#ifdef __cpp_lib_three_way_comparison
|
||||||
RAPIDJSON_DIAG_PUSH
|
#include <compare>
|
||||||
#if defined(_MSC_VER) && !(__clang__)
|
|
||||||
RAPIDJSON_DIAG_OFF(4127) // conditional expression is constant
|
|
||||||
RAPIDJSON_DIAG_OFF(4244) // conversion from kXxxFlags to 'uint16_t', possible loss of data
|
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
RAPIDJSON_DIAG_PUSH
|
||||||
#ifdef __clang__
|
#ifdef __clang__
|
||||||
RAPIDJSON_DIAG_OFF(padded)
|
RAPIDJSON_DIAG_OFF(padded)
|
||||||
RAPIDJSON_DIAG_OFF(switch-enum)
|
RAPIDJSON_DIAG_OFF(switch-enum)
|
||||||
RAPIDJSON_DIAG_OFF(c++98-compat)
|
RAPIDJSON_DIAG_OFF(c++98-compat)
|
||||||
|
#elif defined(_MSC_VER)
|
||||||
|
RAPIDJSON_DIAG_OFF(4127) // conditional expression is constant
|
||||||
|
RAPIDJSON_DIAG_OFF(4244) // conversion from kXxxFlags to 'uint16_t', possible loss of data
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
#ifdef __GNUC__
|
#ifdef __GNUC__
|
||||||
RAPIDJSON_DIAG_OFF(effc++)
|
RAPIDJSON_DIAG_OFF(effc++)
|
||||||
#if __GNUC__ >= 6
|
|
||||||
RAPIDJSON_DIAG_OFF(terminate) // ignore throwing RAPIDJSON_ASSERT in RAPIDJSON_NOEXCEPT functions
|
|
||||||
#endif
|
|
||||||
#endif // __GNUC__
|
#endif // __GNUC__
|
||||||
|
|
||||||
#ifndef RAPIDJSON_NOMEMBERITERATORCLASS
|
#ifndef RAPIDJSON_NOMEMBERITERATORCLASS
|
||||||
#include <iterator> // std::iterator, std::random_access_iterator_tag
|
#include <iterator> // std::random_access_iterator_tag
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
#if RAPIDJSON_HAS_CXX11_RVALUE_REFS
|
#if RAPIDJSON_HAS_CXX11_RVALUE_REFS
|
||||||
|
@ -66,6 +59,48 @@ class GenericValue;
|
||||||
template <typename Encoding, typename Allocator, typename StackAllocator>
|
template <typename Encoding, typename Allocator, typename StackAllocator>
|
||||||
class GenericDocument;
|
class GenericDocument;
|
||||||
|
|
||||||
|
/*! \def RAPIDJSON_DEFAULT_ALLOCATOR
|
||||||
|
\ingroup RAPIDJSON_CONFIG
|
||||||
|
\brief Allows to choose default allocator.
|
||||||
|
|
||||||
|
User can define this to use CrtAllocator or MemoryPoolAllocator.
|
||||||
|
*/
|
||||||
|
#ifndef RAPIDJSON_DEFAULT_ALLOCATOR
|
||||||
|
#define RAPIDJSON_DEFAULT_ALLOCATOR MemoryPoolAllocator<CrtAllocator>
|
||||||
|
#endif
|
||||||
|
|
||||||
|
/*! \def RAPIDJSON_DEFAULT_STACK_ALLOCATOR
|
||||||
|
\ingroup RAPIDJSON_CONFIG
|
||||||
|
\brief Allows to choose default stack allocator for Document.
|
||||||
|
|
||||||
|
User can define this to use CrtAllocator or MemoryPoolAllocator.
|
||||||
|
*/
|
||||||
|
#ifndef RAPIDJSON_DEFAULT_STACK_ALLOCATOR
|
||||||
|
#define RAPIDJSON_DEFAULT_STACK_ALLOCATOR CrtAllocator
|
||||||
|
#endif
|
||||||
|
|
||||||
|
/*! \def RAPIDJSON_VALUE_DEFAULT_OBJECT_CAPACITY
|
||||||
|
\ingroup RAPIDJSON_CONFIG
|
||||||
|
\brief User defined kDefaultObjectCapacity value.
|
||||||
|
|
||||||
|
User can define this as any natural number.
|
||||||
|
*/
|
||||||
|
#ifndef RAPIDJSON_VALUE_DEFAULT_OBJECT_CAPACITY
|
||||||
|
// number of objects that rapidjson::Value allocates memory for by default
|
||||||
|
#define RAPIDJSON_VALUE_DEFAULT_OBJECT_CAPACITY 16
|
||||||
|
#endif
|
||||||
|
|
||||||
|
/*! \def RAPIDJSON_VALUE_DEFAULT_ARRAY_CAPACITY
|
||||||
|
\ingroup RAPIDJSON_CONFIG
|
||||||
|
\brief User defined kDefaultArrayCapacity value.
|
||||||
|
|
||||||
|
User can define this as any natural number.
|
||||||
|
*/
|
||||||
|
#ifndef RAPIDJSON_VALUE_DEFAULT_ARRAY_CAPACITY
|
||||||
|
// number of array elements that rapidjson::Value allocates memory for by default
|
||||||
|
#define RAPIDJSON_VALUE_DEFAULT_ARRAY_CAPACITY 16
|
||||||
|
#endif
|
||||||
|
|
||||||
//! Name-value pair in a JSON object value.
|
//! Name-value pair in a JSON object value.
|
||||||
/*!
|
/*!
|
||||||
This class was internal to GenericValue. It used to be a inner struct.
|
This class was internal to GenericValue. It used to be a inner struct.
|
||||||
|
@ -73,9 +108,45 @@ class GenericDocument;
|
||||||
https://code.google.com/p/rapidjson/issues/detail?id=64
|
https://code.google.com/p/rapidjson/issues/detail?id=64
|
||||||
*/
|
*/
|
||||||
template <typename Encoding, typename Allocator>
|
template <typename Encoding, typename Allocator>
|
||||||
struct GenericMember {
|
class GenericMember {
|
||||||
|
public:
|
||||||
GenericValue<Encoding, Allocator> name; //!< name of member (must be a string)
|
GenericValue<Encoding, Allocator> name; //!< name of member (must be a string)
|
||||||
GenericValue<Encoding, Allocator> value; //!< value of member.
|
GenericValue<Encoding, Allocator> value; //!< value of member.
|
||||||
|
|
||||||
|
#if RAPIDJSON_HAS_CXX11_RVALUE_REFS
|
||||||
|
//! Move constructor in C++11
|
||||||
|
GenericMember(GenericMember&& rhs) RAPIDJSON_NOEXCEPT
|
||||||
|
: name(std::move(rhs.name)),
|
||||||
|
value(std::move(rhs.value))
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
//! Move assignment in C++11
|
||||||
|
GenericMember& operator=(GenericMember&& rhs) RAPIDJSON_NOEXCEPT {
|
||||||
|
return *this = static_cast<GenericMember&>(rhs);
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
|
//! Assignment with move semantics.
|
||||||
|
/*! \param rhs Source of the assignment. Its name and value will become a null value after assignment.
|
||||||
|
*/
|
||||||
|
GenericMember& operator=(GenericMember& rhs) RAPIDJSON_NOEXCEPT {
|
||||||
|
if (RAPIDJSON_LIKELY(this != &rhs)) {
|
||||||
|
name = rhs.name;
|
||||||
|
value = rhs.value;
|
||||||
|
}
|
||||||
|
return *this;
|
||||||
|
}
|
||||||
|
|
||||||
|
// swap() for std::sort() and other potential use in STL.
|
||||||
|
friend inline void swap(GenericMember& a, GenericMember& b) RAPIDJSON_NOEXCEPT {
|
||||||
|
a.name.Swap(b.name);
|
||||||
|
a.value.Swap(b.value);
|
||||||
|
}
|
||||||
|
|
||||||
|
private:
|
||||||
|
//! Copy constructor is not permitted.
|
||||||
|
GenericMember(const GenericMember& rhs);
|
||||||
};
|
};
|
||||||
|
|
||||||
///////////////////////////////////////////////////////////////////////////////
|
///////////////////////////////////////////////////////////////////////////////
|
||||||
|
@ -103,16 +174,13 @@ struct GenericMember {
|
||||||
\see GenericMember, GenericValue::MemberIterator, GenericValue::ConstMemberIterator
|
\see GenericMember, GenericValue::MemberIterator, GenericValue::ConstMemberIterator
|
||||||
*/
|
*/
|
||||||
template <bool Const, typename Encoding, typename Allocator>
|
template <bool Const, typename Encoding, typename Allocator>
|
||||||
class GenericMemberIterator
|
class GenericMemberIterator {
|
||||||
: public std::iterator<std::random_access_iterator_tag
|
|
||||||
, typename internal::MaybeAddConst<Const,GenericMember<Encoding,Allocator> >::Type> {
|
|
||||||
|
|
||||||
friend class GenericValue<Encoding,Allocator>;
|
friend class GenericValue<Encoding,Allocator>;
|
||||||
template <bool, typename, typename> friend class GenericMemberIterator;
|
template <bool, typename, typename> friend class GenericMemberIterator;
|
||||||
|
|
||||||
typedef GenericMember<Encoding,Allocator> PlainType;
|
typedef GenericMember<Encoding,Allocator> PlainType;
|
||||||
typedef typename internal::MaybeAddConst<Const,PlainType>::Type ValueType;
|
typedef typename internal::MaybeAddConst<Const,PlainType>::Type ValueType;
|
||||||
typedef std::iterator<std::random_access_iterator_tag,ValueType> BaseType;
|
|
||||||
|
|
||||||
public:
|
public:
|
||||||
//! Iterator type itself
|
//! Iterator type itself
|
||||||
|
@ -122,12 +190,21 @@ public:
|
||||||
//! Non-constant iterator type
|
//! Non-constant iterator type
|
||||||
typedef GenericMemberIterator<false,Encoding,Allocator> NonConstIterator;
|
typedef GenericMemberIterator<false,Encoding,Allocator> NonConstIterator;
|
||||||
|
|
||||||
|
/** \name std::iterator_traits support */
|
||||||
|
//@{
|
||||||
|
typedef ValueType value_type;
|
||||||
|
typedef ValueType * pointer;
|
||||||
|
typedef ValueType & reference;
|
||||||
|
typedef std::ptrdiff_t difference_type;
|
||||||
|
typedef std::random_access_iterator_tag iterator_category;
|
||||||
|
//@}
|
||||||
|
|
||||||
//! Pointer to (const) GenericMember
|
//! Pointer to (const) GenericMember
|
||||||
typedef typename BaseType::pointer Pointer;
|
typedef pointer Pointer;
|
||||||
//! Reference to (const) GenericMember
|
//! Reference to (const) GenericMember
|
||||||
typedef typename BaseType::reference Reference;
|
typedef reference Reference;
|
||||||
//! Signed integer type (e.g. \c ptrdiff_t)
|
//! Signed integer type (e.g. \c ptrdiff_t)
|
||||||
typedef typename BaseType::difference_type DifferenceType;
|
typedef difference_type DifferenceType;
|
||||||
|
|
||||||
//! Default constructor (singular value)
|
//! Default constructor (singular value)
|
||||||
/*! Creates an iterator pointing to no element.
|
/*! Creates an iterator pointing to no element.
|
||||||
|
@ -173,12 +250,16 @@ public:
|
||||||
|
|
||||||
//! @name relations
|
//! @name relations
|
||||||
//@{
|
//@{
|
||||||
bool operator==(ConstIterator that) const { return ptr_ == that.ptr_; }
|
template <bool Const_> bool operator==(const GenericMemberIterator<Const_, Encoding, Allocator>& that) const { return ptr_ == that.ptr_; }
|
||||||
bool operator!=(ConstIterator that) const { return ptr_ != that.ptr_; }
|
template <bool Const_> bool operator!=(const GenericMemberIterator<Const_, Encoding, Allocator>& that) const { return ptr_ != that.ptr_; }
|
||||||
bool operator<=(ConstIterator that) const { return ptr_ <= that.ptr_; }
|
template <bool Const_> bool operator<=(const GenericMemberIterator<Const_, Encoding, Allocator>& that) const { return ptr_ <= that.ptr_; }
|
||||||
bool operator>=(ConstIterator that) const { return ptr_ >= that.ptr_; }
|
template <bool Const_> bool operator>=(const GenericMemberIterator<Const_, Encoding, Allocator>& that) const { return ptr_ >= that.ptr_; }
|
||||||
bool operator< (ConstIterator that) const { return ptr_ < that.ptr_; }
|
template <bool Const_> bool operator< (const GenericMemberIterator<Const_, Encoding, Allocator>& that) const { return ptr_ < that.ptr_; }
|
||||||
bool operator> (ConstIterator that) const { return ptr_ > that.ptr_; }
|
template <bool Const_> bool operator> (const GenericMemberIterator<Const_, Encoding, Allocator>& that) const { return ptr_ > that.ptr_; }
|
||||||
|
|
||||||
|
#ifdef __cpp_lib_three_way_comparison
|
||||||
|
template <bool Const_> std::strong_ordering operator<=>(const GenericMemberIterator<Const_, Encoding, Allocator>& that) const { return ptr_ <=> that.ptr_; }
|
||||||
|
#endif
|
||||||
//@}
|
//@}
|
||||||
|
|
||||||
//! @name dereference
|
//! @name dereference
|
||||||
|
@ -203,17 +284,19 @@ private:
|
||||||
// class-based member iterator implementation disabled, use plain pointers
|
// class-based member iterator implementation disabled, use plain pointers
|
||||||
|
|
||||||
template <bool Const, typename Encoding, typename Allocator>
|
template <bool Const, typename Encoding, typename Allocator>
|
||||||
struct GenericMemberIterator;
|
class GenericMemberIterator;
|
||||||
|
|
||||||
//! non-const GenericMemberIterator
|
//! non-const GenericMemberIterator
|
||||||
template <typename Encoding, typename Allocator>
|
template <typename Encoding, typename Allocator>
|
||||||
struct GenericMemberIterator<false,Encoding,Allocator> {
|
class GenericMemberIterator<false,Encoding,Allocator> {
|
||||||
|
public:
|
||||||
//! use plain pointer as iterator type
|
//! use plain pointer as iterator type
|
||||||
typedef GenericMember<Encoding,Allocator>* Iterator;
|
typedef GenericMember<Encoding,Allocator>* Iterator;
|
||||||
};
|
};
|
||||||
//! const GenericMemberIterator
|
//! const GenericMemberIterator
|
||||||
template <typename Encoding, typename Allocator>
|
template <typename Encoding, typename Allocator>
|
||||||
struct GenericMemberIterator<true,Encoding,Allocator> {
|
class GenericMemberIterator<true,Encoding,Allocator> {
|
||||||
|
public:
|
||||||
//! use plain const pointer as iterator type
|
//! use plain const pointer as iterator type
|
||||||
typedef const GenericMember<Encoding,Allocator>* Iterator;
|
typedef const GenericMember<Encoding,Allocator>* Iterator;
|
||||||
};
|
};
|
||||||
|
@ -450,6 +533,26 @@ struct TypeHelper<ValueType, unsigned> {
|
||||||
static ValueType& Set(ValueType& v, unsigned data, typename ValueType::AllocatorType&) { return v.SetUint(data); }
|
static ValueType& Set(ValueType& v, unsigned data, typename ValueType::AllocatorType&) { return v.SetUint(data); }
|
||||||
};
|
};
|
||||||
|
|
||||||
|
#ifdef _MSC_VER
|
||||||
|
RAPIDJSON_STATIC_ASSERT(sizeof(long) == sizeof(int));
|
||||||
|
template<typename ValueType>
|
||||||
|
struct TypeHelper<ValueType, long> {
|
||||||
|
static bool Is(const ValueType& v) { return v.IsInt(); }
|
||||||
|
static long Get(const ValueType& v) { return v.GetInt(); }
|
||||||
|
static ValueType& Set(ValueType& v, long data) { return v.SetInt(data); }
|
||||||
|
static ValueType& Set(ValueType& v, long data, typename ValueType::AllocatorType&) { return v.SetInt(data); }
|
||||||
|
};
|
||||||
|
|
||||||
|
RAPIDJSON_STATIC_ASSERT(sizeof(unsigned long) == sizeof(unsigned));
|
||||||
|
template<typename ValueType>
|
||||||
|
struct TypeHelper<ValueType, unsigned long> {
|
||||||
|
static bool Is(const ValueType& v) { return v.IsUint(); }
|
||||||
|
static unsigned long Get(const ValueType& v) { return v.GetUint(); }
|
||||||
|
static ValueType& Set(ValueType& v, unsigned long data) { return v.SetUint(data); }
|
||||||
|
static ValueType& Set(ValueType& v, unsigned long data, typename ValueType::AllocatorType&) { return v.SetUint(data); }
|
||||||
|
};
|
||||||
|
#endif
|
||||||
|
|
||||||
template<typename ValueType>
|
template<typename ValueType>
|
||||||
struct TypeHelper<ValueType, int64_t> {
|
struct TypeHelper<ValueType, int64_t> {
|
||||||
static bool Is(const ValueType& v) { return v.IsInt64(); }
|
static bool Is(const ValueType& v) { return v.IsInt64(); }
|
||||||
|
@ -552,7 +655,7 @@ template <bool, typename> class GenericObject;
|
||||||
\tparam Encoding Encoding of the value. (Even non-string values need to have the same encoding in a document)
|
\tparam Encoding Encoding of the value. (Even non-string values need to have the same encoding in a document)
|
||||||
\tparam Allocator Allocator type for allocating memory of object, array and string.
|
\tparam Allocator Allocator type for allocating memory of object, array and string.
|
||||||
*/
|
*/
|
||||||
template <typename Encoding, typename Allocator = MemoryPoolAllocator<> >
|
template <typename Encoding, typename Allocator = RAPIDJSON_DEFAULT_ALLOCATOR >
|
||||||
class GenericValue {
|
class GenericValue {
|
||||||
public:
|
public:
|
||||||
//! Name-value pair in an object.
|
//! Name-value pair in an object.
|
||||||
|
@ -606,11 +709,11 @@ public:
|
||||||
\note Default content for number is zero.
|
\note Default content for number is zero.
|
||||||
*/
|
*/
|
||||||
explicit GenericValue(Type type) RAPIDJSON_NOEXCEPT : data_() {
|
explicit GenericValue(Type type) RAPIDJSON_NOEXCEPT : data_() {
|
||||||
static const uint16_t defaultFlags[7] = {
|
static const uint16_t defaultFlags[] = {
|
||||||
kNullFlag, kFalseFlag, kTrueFlag, kObjectFlag, kArrayFlag, kShortStringFlag,
|
kNullFlag, kFalseFlag, kTrueFlag, kObjectFlag, kArrayFlag, kShortStringFlag,
|
||||||
kNumberAnyFlag
|
kNumberAnyFlag
|
||||||
};
|
};
|
||||||
RAPIDJSON_ASSERT(type >= kNullType && type <= kNumberType);
|
RAPIDJSON_NOEXCEPT_ASSERT(type >= kNullType && type <= kNumberType);
|
||||||
data_.f.flags = defaultFlags[type];
|
data_.f.flags = defaultFlags[type];
|
||||||
|
|
||||||
// Use ShortString to store empty string.
|
// Use ShortString to store empty string.
|
||||||
|
@ -812,9 +915,10 @@ public:
|
||||||
/*! \param rhs Source of the assignment. It will become a null value after assignment.
|
/*! \param rhs Source of the assignment. It will become a null value after assignment.
|
||||||
*/
|
*/
|
||||||
GenericValue& operator=(GenericValue& rhs) RAPIDJSON_NOEXCEPT {
|
GenericValue& operator=(GenericValue& rhs) RAPIDJSON_NOEXCEPT {
|
||||||
RAPIDJSON_ASSERT(this != &rhs);
|
if (RAPIDJSON_LIKELY(this != &rhs)) {
|
||||||
this->~GenericValue();
|
this->~GenericValue();
|
||||||
RawAssign(rhs);
|
RawAssign(rhs);
|
||||||
|
}
|
||||||
return *this;
|
return *this;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -906,7 +1010,7 @@ public:
|
||||||
//! Equal-to operator
|
//! Equal-to operator
|
||||||
/*!
|
/*!
|
||||||
\note If an object contains duplicated named member, comparing equality with any object is always \c false.
|
\note If an object contains duplicated named member, comparing equality with any object is always \c false.
|
||||||
\note Linear time complexity (number of all values in the subtree and total lengths of all strings).
|
\note Complexity is quadratic in Object's member number and linear for the rest (number of all values in the subtree and total lengths of all strings).
|
||||||
*/
|
*/
|
||||||
template <typename SourceAllocator>
|
template <typename SourceAllocator>
|
||||||
bool operator==(const GenericValue<Encoding, SourceAllocator>& rhs) const {
|
bool operator==(const GenericValue<Encoding, SourceAllocator>& rhs) const {
|
||||||
|
@ -1075,6 +1179,9 @@ public:
|
||||||
//! Get the number of members in the object.
|
//! Get the number of members in the object.
|
||||||
SizeType MemberCount() const { RAPIDJSON_ASSERT(IsObject()); return data_.o.size; }
|
SizeType MemberCount() const { RAPIDJSON_ASSERT(IsObject()); return data_.o.size; }
|
||||||
|
|
||||||
|
//! Get the capacity of object.
|
||||||
|
SizeType MemberCapacity() const { RAPIDJSON_ASSERT(IsObject()); return data_.o.capacity; }
|
||||||
|
|
||||||
//! Check whether the object is empty.
|
//! Check whether the object is empty.
|
||||||
bool ObjectEmpty() const { RAPIDJSON_ASSERT(IsObject()); return data_.o.size == 0; }
|
bool ObjectEmpty() const { RAPIDJSON_ASSERT(IsObject()); return data_.o.size == 0; }
|
||||||
|
|
||||||
|
@ -1143,6 +1250,21 @@ public:
|
||||||
/*! \pre IsObject() == true */
|
/*! \pre IsObject() == true */
|
||||||
MemberIterator MemberEnd() { RAPIDJSON_ASSERT(IsObject()); return MemberIterator(GetMembersPointer() + data_.o.size); }
|
MemberIterator MemberEnd() { RAPIDJSON_ASSERT(IsObject()); return MemberIterator(GetMembersPointer() + data_.o.size); }
|
||||||
|
|
||||||
|
//! Request the object to have enough capacity to store members.
|
||||||
|
/*! \param newCapacity The capacity that the object at least need to have.
|
||||||
|
\param allocator Allocator for reallocating memory. It must be the same one as used before. Commonly use GenericDocument::GetAllocator().
|
||||||
|
\return The value itself for fluent API.
|
||||||
|
\note Linear time complexity.
|
||||||
|
*/
|
||||||
|
GenericValue& MemberReserve(SizeType newCapacity, Allocator &allocator) {
|
||||||
|
RAPIDJSON_ASSERT(IsObject());
|
||||||
|
if (newCapacity > data_.o.capacity) {
|
||||||
|
SetMembersPointer(reinterpret_cast<Member*>(allocator.Realloc(GetMembersPointer(), data_.o.capacity * sizeof(Member), newCapacity * sizeof(Member))));
|
||||||
|
data_.o.capacity = newCapacity;
|
||||||
|
}
|
||||||
|
return *this;
|
||||||
|
}
|
||||||
|
|
||||||
//! Check whether a member exists in the object.
|
//! Check whether a member exists in the object.
|
||||||
/*!
|
/*!
|
||||||
\param name Member name to be searched.
|
\param name Member name to be searched.
|
||||||
|
@ -1248,17 +1370,8 @@ public:
|
||||||
RAPIDJSON_ASSERT(name.IsString());
|
RAPIDJSON_ASSERT(name.IsString());
|
||||||
|
|
||||||
ObjectData& o = data_.o;
|
ObjectData& o = data_.o;
|
||||||
if (o.size >= o.capacity) {
|
if (o.size >= o.capacity)
|
||||||
if (o.capacity == 0) {
|
MemberReserve(o.capacity == 0 ? kDefaultObjectCapacity : (o.capacity + (o.capacity + 1) / 2), allocator);
|
||||||
o.capacity = kDefaultObjectCapacity;
|
|
||||||
SetMembersPointer(reinterpret_cast<Member*>(allocator.Malloc(o.capacity * sizeof(Member))));
|
|
||||||
}
|
|
||||||
else {
|
|
||||||
SizeType oldCapacity = o.capacity;
|
|
||||||
o.capacity += (oldCapacity + 1) / 2; // grow by factor 1.5
|
|
||||||
SetMembersPointer(reinterpret_cast<Member*>(allocator.Realloc(GetMembersPointer(), oldCapacity * sizeof(Member), o.capacity * sizeof(Member))));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
Member* members = GetMembersPointer();
|
Member* members = GetMembersPointer();
|
||||||
members[o.size].name.RawAssign(name);
|
members[o.size].name.RawAssign(name);
|
||||||
members[o.size].value.RawAssign(value);
|
members[o.size].value.RawAssign(value);
|
||||||
|
@ -1485,7 +1598,7 @@ public:
|
||||||
MemberIterator pos = MemberBegin() + (first - MemberBegin());
|
MemberIterator pos = MemberBegin() + (first - MemberBegin());
|
||||||
for (MemberIterator itr = pos; itr != last; ++itr)
|
for (MemberIterator itr = pos; itr != last; ++itr)
|
||||||
itr->~Member();
|
itr->~Member();
|
||||||
std::memmove(&*pos, &*last, static_cast<size_t>(MemberEnd() - last) * sizeof(Member));
|
std::memmove(static_cast<void*>(&*pos), &*last, static_cast<size_t>(MemberEnd() - last) * sizeof(Member));
|
||||||
data_.o.size -= static_cast<SizeType>(last - first);
|
data_.o.size -= static_cast<SizeType>(last - first);
|
||||||
return pos;
|
return pos;
|
||||||
}
|
}
|
||||||
|
@ -1689,7 +1802,7 @@ public:
|
||||||
ValueIterator pos = Begin() + (first - Begin());
|
ValueIterator pos = Begin() + (first - Begin());
|
||||||
for (ValueIterator itr = pos; itr != last; ++itr)
|
for (ValueIterator itr = pos; itr != last; ++itr)
|
||||||
itr->~GenericValue();
|
itr->~GenericValue();
|
||||||
std::memmove(pos, last, static_cast<size_t>(End() - last) * sizeof(GenericValue));
|
std::memmove(static_cast<void*>(pos), last, static_cast<size_t>(End() - last) * sizeof(GenericValue));
|
||||||
data_.a.size -= static_cast<SizeType>(last - first);
|
data_.a.size -= static_cast<SizeType>(last - first);
|
||||||
return pos;
|
return pos;
|
||||||
}
|
}
|
||||||
|
@ -1890,25 +2003,26 @@ private:
|
||||||
|
|
||||||
// Initial flags of different types.
|
// Initial flags of different types.
|
||||||
kNullFlag = kNullType,
|
kNullFlag = kNullType,
|
||||||
kTrueFlag = kTrueType | kBoolFlag,
|
// These casts are added to suppress the warning on MSVC about bitwise operations between enums of different types.
|
||||||
kFalseFlag = kFalseType | kBoolFlag,
|
kTrueFlag = static_cast<int>(kTrueType) | static_cast<int>(kBoolFlag),
|
||||||
kNumberIntFlag = kNumberType | kNumberFlag | kIntFlag | kInt64Flag,
|
kFalseFlag = static_cast<int>(kFalseType) | static_cast<int>(kBoolFlag),
|
||||||
kNumberUintFlag = kNumberType | kNumberFlag | kUintFlag | kUint64Flag | kInt64Flag,
|
kNumberIntFlag = static_cast<int>(kNumberType) | static_cast<int>(kNumberFlag | kIntFlag | kInt64Flag),
|
||||||
kNumberInt64Flag = kNumberType | kNumberFlag | kInt64Flag,
|
kNumberUintFlag = static_cast<int>(kNumberType) | static_cast<int>(kNumberFlag | kUintFlag | kUint64Flag | kInt64Flag),
|
||||||
kNumberUint64Flag = kNumberType | kNumberFlag | kUint64Flag,
|
kNumberInt64Flag = static_cast<int>(kNumberType) | static_cast<int>(kNumberFlag | kInt64Flag),
|
||||||
kNumberDoubleFlag = kNumberType | kNumberFlag | kDoubleFlag,
|
kNumberUint64Flag = static_cast<int>(kNumberType) | static_cast<int>(kNumberFlag | kUint64Flag),
|
||||||
kNumberAnyFlag = kNumberType | kNumberFlag | kIntFlag | kInt64Flag | kUintFlag | kUint64Flag | kDoubleFlag,
|
kNumberDoubleFlag = static_cast<int>(kNumberType) | static_cast<int>(kNumberFlag | kDoubleFlag),
|
||||||
kConstStringFlag = kStringType | kStringFlag,
|
kNumberAnyFlag = static_cast<int>(kNumberType) | static_cast<int>(kNumberFlag | kIntFlag | kInt64Flag | kUintFlag | kUint64Flag | kDoubleFlag),
|
||||||
kCopyStringFlag = kStringType | kStringFlag | kCopyFlag,
|
kConstStringFlag = static_cast<int>(kStringType) | static_cast<int>(kStringFlag),
|
||||||
kShortStringFlag = kStringType | kStringFlag | kCopyFlag | kInlineStrFlag,
|
kCopyStringFlag = static_cast<int>(kStringType) | static_cast<int>(kStringFlag | kCopyFlag),
|
||||||
|
kShortStringFlag = static_cast<int>(kStringType) | static_cast<int>(kStringFlag | kCopyFlag | kInlineStrFlag),
|
||||||
kObjectFlag = kObjectType,
|
kObjectFlag = kObjectType,
|
||||||
kArrayFlag = kArrayType,
|
kArrayFlag = kArrayType,
|
||||||
|
|
||||||
kTypeMask = 0x07
|
kTypeMask = 0x07
|
||||||
};
|
};
|
||||||
|
|
||||||
static const SizeType kDefaultArrayCapacity = 16;
|
static const SizeType kDefaultArrayCapacity = RAPIDJSON_VALUE_DEFAULT_ARRAY_CAPACITY;
|
||||||
static const SizeType kDefaultObjectCapacity = 16;
|
static const SizeType kDefaultObjectCapacity = RAPIDJSON_VALUE_DEFAULT_OBJECT_CAPACITY;
|
||||||
|
|
||||||
struct Flag {
|
struct Flag {
|
||||||
#if RAPIDJSON_48BITPOINTER_OPTIMIZATION
|
#if RAPIDJSON_48BITPOINTER_OPTIMIZATION
|
||||||
|
@ -2004,7 +2118,7 @@ private:
|
||||||
if (count) {
|
if (count) {
|
||||||
GenericValue* e = static_cast<GenericValue*>(allocator.Malloc(count * sizeof(GenericValue)));
|
GenericValue* e = static_cast<GenericValue*>(allocator.Malloc(count * sizeof(GenericValue)));
|
||||||
SetElementsPointer(e);
|
SetElementsPointer(e);
|
||||||
std::memcpy(e, values, count * sizeof(GenericValue));
|
std::memcpy(static_cast<void*>(e), values, count * sizeof(GenericValue));
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
SetElementsPointer(0);
|
SetElementsPointer(0);
|
||||||
|
@ -2017,7 +2131,7 @@ private:
|
||||||
if (count) {
|
if (count) {
|
||||||
Member* m = static_cast<Member*>(allocator.Malloc(count * sizeof(Member)));
|
Member* m = static_cast<Member*>(allocator.Malloc(count * sizeof(Member)));
|
||||||
SetMembersPointer(m);
|
SetMembersPointer(m);
|
||||||
std::memcpy(m, members, count * sizeof(Member));
|
std::memcpy(static_cast<void*>(m), members, count * sizeof(Member));
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
SetMembersPointer(0);
|
SetMembersPointer(0);
|
||||||
|
@ -2088,7 +2202,7 @@ typedef GenericValue<UTF8<> > Value;
|
||||||
\tparam StackAllocator Allocator for allocating memory for stack during parsing.
|
\tparam StackAllocator Allocator for allocating memory for stack during parsing.
|
||||||
\warning Although GenericDocument inherits from GenericValue, the API does \b not provide any virtual functions, especially no virtual destructor. To avoid memory leaks, do not \c delete a GenericDocument object via a pointer to a GenericValue.
|
\warning Although GenericDocument inherits from GenericValue, the API does \b not provide any virtual functions, especially no virtual destructor. To avoid memory leaks, do not \c delete a GenericDocument object via a pointer to a GenericValue.
|
||||||
*/
|
*/
|
||||||
template <typename Encoding, typename Allocator = MemoryPoolAllocator<>, typename StackAllocator = CrtAllocator>
|
template <typename Encoding, typename Allocator = RAPIDJSON_DEFAULT_ALLOCATOR, typename StackAllocator = RAPIDJSON_DEFAULT_STACK_ALLOCATOR >
|
||||||
class GenericDocument : public GenericValue<Encoding, Allocator> {
|
class GenericDocument : public GenericValue<Encoding, Allocator> {
|
||||||
public:
|
public:
|
||||||
typedef typename Encoding::Ch Ch; //!< Character type derived from Encoding.
|
typedef typename Encoding::Ch Ch; //!< Character type derived from Encoding.
|
||||||
|
@ -2352,7 +2466,7 @@ public:
|
||||||
//!@name Handling parse errors
|
//!@name Handling parse errors
|
||||||
//!@{
|
//!@{
|
||||||
|
|
||||||
//! Whether a parse error has occured in the last parsing.
|
//! Whether a parse error has occurred in the last parsing.
|
||||||
bool HasParseError() const { return parseResult_.IsError(); }
|
bool HasParseError() const { return parseResult_.IsError(); }
|
||||||
|
|
||||||
//! Get the \ref ParseErrorCode of last parsing.
|
//! Get the \ref ParseErrorCode of last parsing.
|
||||||
|
@ -2473,6 +2587,7 @@ private:
|
||||||
//! GenericDocument with UTF8 encoding
|
//! GenericDocument with UTF8 encoding
|
||||||
typedef GenericDocument<UTF8<> > Document;
|
typedef GenericDocument<UTF8<> > Document;
|
||||||
|
|
||||||
|
|
||||||
//! Helper class for accessing Value of array type.
|
//! Helper class for accessing Value of array type.
|
||||||
/*!
|
/*!
|
||||||
Instance of this helper class is obtained by \c GenericValue::GetArray().
|
Instance of this helper class is obtained by \c GenericValue::GetArray().
|
||||||
|
@ -2497,6 +2612,7 @@ public:
|
||||||
GenericArray& operator=(const GenericArray& rhs) { value_ = rhs.value_; return *this; }
|
GenericArray& operator=(const GenericArray& rhs) { value_ = rhs.value_; return *this; }
|
||||||
~GenericArray() {}
|
~GenericArray() {}
|
||||||
|
|
||||||
|
operator ValueType&() const { return value_; }
|
||||||
SizeType Size() const { return value_.Size(); }
|
SizeType Size() const { return value_.Size(); }
|
||||||
SizeType Capacity() const { return value_.Capacity(); }
|
SizeType Capacity() const { return value_.Capacity(); }
|
||||||
bool Empty() const { return value_.Empty(); }
|
bool Empty() const { return value_.Empty(); }
|
||||||
|
@ -2552,7 +2668,9 @@ public:
|
||||||
GenericObject& operator=(const GenericObject& rhs) { value_ = rhs.value_; return *this; }
|
GenericObject& operator=(const GenericObject& rhs) { value_ = rhs.value_; return *this; }
|
||||||
~GenericObject() {}
|
~GenericObject() {}
|
||||||
|
|
||||||
|
operator ValueType&() const { return value_; }
|
||||||
SizeType MemberCount() const { return value_.MemberCount(); }
|
SizeType MemberCount() const { return value_.MemberCount(); }
|
||||||
|
SizeType MemberCapacity() const { return value_.MemberCapacity(); }
|
||||||
bool ObjectEmpty() const { return value_.ObjectEmpty(); }
|
bool ObjectEmpty() const { return value_.ObjectEmpty(); }
|
||||||
template <typename T> ValueType& operator[](T* name) const { return value_[name]; }
|
template <typename T> ValueType& operator[](T* name) const { return value_[name]; }
|
||||||
template <typename SourceAllocator> ValueType& operator[](const GenericValue<EncodingType, SourceAllocator>& name) const { return value_[name]; }
|
template <typename SourceAllocator> ValueType& operator[](const GenericValue<EncodingType, SourceAllocator>& name) const { return value_[name]; }
|
||||||
|
@ -2561,6 +2679,7 @@ public:
|
||||||
#endif
|
#endif
|
||||||
MemberIterator MemberBegin() const { return value_.MemberBegin(); }
|
MemberIterator MemberBegin() const { return value_.MemberBegin(); }
|
||||||
MemberIterator MemberEnd() const { return value_.MemberEnd(); }
|
MemberIterator MemberEnd() const { return value_.MemberEnd(); }
|
||||||
|
GenericObject MemberReserve(SizeType newCapacity, AllocatorType &allocator) const { value_.MemberReserve(newCapacity, allocator); return *this; }
|
||||||
bool HasMember(const Ch* name) const { return value_.HasMember(name); }
|
bool HasMember(const Ch* name) const { return value_.HasMember(name); }
|
||||||
#if RAPIDJSON_HAS_STDSTRING
|
#if RAPIDJSON_HAS_STDSTRING
|
||||||
bool HasMember(const std::basic_string<Ch>& name) const { return value_.HasMember(name); }
|
bool HasMember(const std::basic_string<Ch>& name) const { return value_.HasMember(name); }
|
||||||
|
@ -2615,8 +2734,4 @@ private:
|
||||||
RAPIDJSON_NAMESPACE_END
|
RAPIDJSON_NAMESPACE_END
|
||||||
RAPIDJSON_DIAG_POP
|
RAPIDJSON_DIAG_POP
|
||||||
|
|
||||||
#if (__GNUC__ == 8 && __GNUC_MINOR__ >= 0)
|
|
||||||
#pragma GCC diagnostic pop
|
|
||||||
#endif
|
|
||||||
|
|
||||||
#endif // RAPIDJSON_DOCUMENT_H_
|
#endif // RAPIDJSON_DOCUMENT_H_
|
||||||
|
|
|
@ -1,6 +1,6 @@
|
||||||
// Tencent is pleased to support the open source community by making RapidJSON available.
|
// 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.
|
// Copyright (C) 2015 THL A29 Limited, a Tencent company, and Milo Yip.
|
||||||
//
|
//
|
||||||
// Licensed under the MIT License (the "License"); you may not use this file except
|
// 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
|
// in compliance with the License. You may obtain a copy of the License at
|
||||||
|
|
|
@ -1,6 +1,6 @@
|
||||||
// Tencent is pleased to support the open source community by making RapidJSON available.
|
// 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.
|
// Copyright (C) 2015 THL A29 Limited, a Tencent company, and Milo Yip.
|
||||||
//
|
//
|
||||||
// Licensed under the MIT License (the "License"); you may not use this file except
|
// 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
|
// in compliance with the License. You may obtain a copy of the License at
|
||||||
|
@ -144,9 +144,9 @@ struct UTF8 {
|
||||||
|
|
||||||
template <typename InputStream>
|
template <typename InputStream>
|
||||||
static bool Decode(InputStream& is, unsigned* codepoint) {
|
static bool Decode(InputStream& is, unsigned* codepoint) {
|
||||||
#define COPY() c = is.Take(); *codepoint = (*codepoint << 6) | (static_cast<unsigned char>(c) & 0x3Fu)
|
#define RAPIDJSON_COPY() c = is.Take(); *codepoint = (*codepoint << 6) | (static_cast<unsigned char>(c) & 0x3Fu)
|
||||||
#define TRANS(mask) result &= ((GetRange(static_cast<unsigned char>(c)) & mask) != 0)
|
#define RAPIDJSON_TRANS(mask) result &= ((GetRange(static_cast<unsigned char>(c)) & mask) != 0)
|
||||||
#define TAIL() COPY(); TRANS(0x70)
|
#define RAPIDJSON_TAIL() RAPIDJSON_COPY(); RAPIDJSON_TRANS(0x70)
|
||||||
typename InputStream::Ch c = is.Take();
|
typename InputStream::Ch c = is.Take();
|
||||||
if (!(c & 0x80)) {
|
if (!(c & 0x80)) {
|
||||||
*codepoint = static_cast<unsigned char>(c);
|
*codepoint = static_cast<unsigned char>(c);
|
||||||
|
@ -161,44 +161,44 @@ struct UTF8 {
|
||||||
}
|
}
|
||||||
bool result = true;
|
bool result = true;
|
||||||
switch (type) {
|
switch (type) {
|
||||||
case 2: TAIL(); return result;
|
case 2: RAPIDJSON_TAIL(); return result;
|
||||||
case 3: TAIL(); TAIL(); return result;
|
case 3: RAPIDJSON_TAIL(); RAPIDJSON_TAIL(); return result;
|
||||||
case 4: COPY(); TRANS(0x50); TAIL(); return result;
|
case 4: RAPIDJSON_COPY(); RAPIDJSON_TRANS(0x50); RAPIDJSON_TAIL(); return result;
|
||||||
case 5: COPY(); TRANS(0x10); TAIL(); TAIL(); return result;
|
case 5: RAPIDJSON_COPY(); RAPIDJSON_TRANS(0x10); RAPIDJSON_TAIL(); RAPIDJSON_TAIL(); return result;
|
||||||
case 6: TAIL(); TAIL(); TAIL(); return result;
|
case 6: RAPIDJSON_TAIL(); RAPIDJSON_TAIL(); RAPIDJSON_TAIL(); return result;
|
||||||
case 10: COPY(); TRANS(0x20); TAIL(); return result;
|
case 10: RAPIDJSON_COPY(); RAPIDJSON_TRANS(0x20); RAPIDJSON_TAIL(); return result;
|
||||||
case 11: COPY(); TRANS(0x60); TAIL(); TAIL(); return result;
|
case 11: RAPIDJSON_COPY(); RAPIDJSON_TRANS(0x60); RAPIDJSON_TAIL(); RAPIDJSON_TAIL(); return result;
|
||||||
default: return false;
|
default: return false;
|
||||||
}
|
}
|
||||||
#undef COPY
|
#undef RAPIDJSON_COPY
|
||||||
#undef TRANS
|
#undef RAPIDJSON_TRANS
|
||||||
#undef TAIL
|
#undef RAPIDJSON_TAIL
|
||||||
}
|
}
|
||||||
|
|
||||||
template <typename InputStream, typename OutputStream>
|
template <typename InputStream, typename OutputStream>
|
||||||
static bool Validate(InputStream& is, OutputStream& os) {
|
static bool Validate(InputStream& is, OutputStream& os) {
|
||||||
#define COPY() os.Put(c = is.Take())
|
#define RAPIDJSON_COPY() os.Put(c = is.Take())
|
||||||
#define TRANS(mask) result &= ((GetRange(static_cast<unsigned char>(c)) & mask) != 0)
|
#define RAPIDJSON_TRANS(mask) result &= ((GetRange(static_cast<unsigned char>(c)) & mask) != 0)
|
||||||
#define TAIL() COPY(); TRANS(0x70)
|
#define RAPIDJSON_TAIL() RAPIDJSON_COPY(); RAPIDJSON_TRANS(0x70)
|
||||||
Ch c;
|
Ch c;
|
||||||
COPY();
|
RAPIDJSON_COPY();
|
||||||
if (!(c & 0x80))
|
if (!(c & 0x80))
|
||||||
return true;
|
return true;
|
||||||
|
|
||||||
bool result = true;
|
bool result = true;
|
||||||
switch (GetRange(static_cast<unsigned char>(c))) {
|
switch (GetRange(static_cast<unsigned char>(c))) {
|
||||||
case 2: TAIL(); return result;
|
case 2: RAPIDJSON_TAIL(); return result;
|
||||||
case 3: TAIL(); TAIL(); return result;
|
case 3: RAPIDJSON_TAIL(); RAPIDJSON_TAIL(); return result;
|
||||||
case 4: COPY(); TRANS(0x50); TAIL(); return result;
|
case 4: RAPIDJSON_COPY(); RAPIDJSON_TRANS(0x50); RAPIDJSON_TAIL(); return result;
|
||||||
case 5: COPY(); TRANS(0x10); TAIL(); TAIL(); return result;
|
case 5: RAPIDJSON_COPY(); RAPIDJSON_TRANS(0x10); RAPIDJSON_TAIL(); RAPIDJSON_TAIL(); return result;
|
||||||
case 6: TAIL(); TAIL(); TAIL(); return result;
|
case 6: RAPIDJSON_TAIL(); RAPIDJSON_TAIL(); RAPIDJSON_TAIL(); return result;
|
||||||
case 10: COPY(); TRANS(0x20); TAIL(); return result;
|
case 10: RAPIDJSON_COPY(); RAPIDJSON_TRANS(0x20); RAPIDJSON_TAIL(); return result;
|
||||||
case 11: COPY(); TRANS(0x60); TAIL(); TAIL(); return result;
|
case 11: RAPIDJSON_COPY(); RAPIDJSON_TRANS(0x60); RAPIDJSON_TAIL(); RAPIDJSON_TAIL(); return result;
|
||||||
default: return false;
|
default: return false;
|
||||||
}
|
}
|
||||||
#undef COPY
|
#undef RAPIDJSON_COPY
|
||||||
#undef TRANS
|
#undef RAPIDJSON_TRANS
|
||||||
#undef TAIL
|
#undef RAPIDJSON_TAIL
|
||||||
}
|
}
|
||||||
|
|
||||||
static unsigned char GetRange(unsigned char c) {
|
static unsigned char GetRange(unsigned char c) {
|
||||||
|
@ -384,7 +384,7 @@ struct UTF16BE : UTF16<CharType> {
|
||||||
static CharType Take(InputByteStream& is) {
|
static CharType Take(InputByteStream& is) {
|
||||||
RAPIDJSON_STATIC_ASSERT(sizeof(typename InputByteStream::Ch) == 1);
|
RAPIDJSON_STATIC_ASSERT(sizeof(typename InputByteStream::Ch) == 1);
|
||||||
unsigned c = static_cast<unsigned>(static_cast<uint8_t>(is.Take())) << 8;
|
unsigned c = static_cast<unsigned>(static_cast<uint8_t>(is.Take())) << 8;
|
||||||
c |= static_cast<uint8_t>(is.Take());
|
c |= static_cast<unsigned>(static_cast<uint8_t>(is.Take()));
|
||||||
return static_cast<CharType>(c);
|
return static_cast<CharType>(c);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -1,6 +1,6 @@
|
||||||
// Tencent is pleased to support the open source community by making RapidJSON available.
|
// 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.
|
// Copyright (C) 2015 THL A29 Limited, a Tencent company, and Milo Yip.
|
||||||
//
|
//
|
||||||
// Licensed under the MIT License (the "License"); you may not use this file except
|
// 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
|
// in compliance with the License. You may obtain a copy of the License at
|
||||||
|
@ -65,6 +65,54 @@ inline const RAPIDJSON_ERROR_CHARTYPE* GetParseError_En(ParseErrorCode parseErro
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
//! Maps error code of validation into error message.
|
||||||
|
/*!
|
||||||
|
\ingroup RAPIDJSON_ERRORS
|
||||||
|
\param validateErrorCode Error code obtained from validator.
|
||||||
|
\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* GetValidateError_En(ValidateErrorCode validateErrorCode) {
|
||||||
|
switch (validateErrorCode) {
|
||||||
|
case kValidateErrors: return RAPIDJSON_ERROR_STRING("One or more validation errors have occurred");
|
||||||
|
case kValidateErrorNone: return RAPIDJSON_ERROR_STRING("No error.");
|
||||||
|
|
||||||
|
case kValidateErrorMultipleOf: return RAPIDJSON_ERROR_STRING("Number '%actual' is not a multiple of the 'multipleOf' value '%expected'.");
|
||||||
|
case kValidateErrorMaximum: return RAPIDJSON_ERROR_STRING("Number '%actual' is greater than the 'maximum' value '%expected'.");
|
||||||
|
case kValidateErrorExclusiveMaximum: return RAPIDJSON_ERROR_STRING("Number '%actual' is greater than or equal to the 'exclusiveMaximum' value '%expected'.");
|
||||||
|
case kValidateErrorMinimum: return RAPIDJSON_ERROR_STRING("Number '%actual' is less than the 'minimum' value '%expected'.");
|
||||||
|
case kValidateErrorExclusiveMinimum: return RAPIDJSON_ERROR_STRING("Number '%actual' is less than or equal to the 'exclusiveMinimum' value '%expected'.");
|
||||||
|
|
||||||
|
case kValidateErrorMaxLength: return RAPIDJSON_ERROR_STRING("String '%actual' is longer than the 'maxLength' value '%expected'.");
|
||||||
|
case kValidateErrorMinLength: return RAPIDJSON_ERROR_STRING("String '%actual' is shorter than the 'minLength' value '%expected'.");
|
||||||
|
case kValidateErrorPattern: return RAPIDJSON_ERROR_STRING("String '%actual' does not match the 'pattern' regular expression.");
|
||||||
|
|
||||||
|
case kValidateErrorMaxItems: return RAPIDJSON_ERROR_STRING("Array of length '%actual' is longer than the 'maxItems' value '%expected'.");
|
||||||
|
case kValidateErrorMinItems: return RAPIDJSON_ERROR_STRING("Array of length '%actual' is shorter than the 'minItems' value '%expected'.");
|
||||||
|
case kValidateErrorUniqueItems: return RAPIDJSON_ERROR_STRING("Array has duplicate items at indices '%duplicates' but 'uniqueItems' is true.");
|
||||||
|
case kValidateErrorAdditionalItems: return RAPIDJSON_ERROR_STRING("Array has an additional item at index '%disallowed' that is not allowed by the schema.");
|
||||||
|
|
||||||
|
case kValidateErrorMaxProperties: return RAPIDJSON_ERROR_STRING("Object has '%actual' members which is more than 'maxProperties' value '%expected'.");
|
||||||
|
case kValidateErrorMinProperties: return RAPIDJSON_ERROR_STRING("Object has '%actual' members which is less than 'minProperties' value '%expected'.");
|
||||||
|
case kValidateErrorRequired: return RAPIDJSON_ERROR_STRING("Object is missing the following members required by the schema: '%missing'.");
|
||||||
|
case kValidateErrorAdditionalProperties: return RAPIDJSON_ERROR_STRING("Object has an additional member '%disallowed' that is not allowed by the schema.");
|
||||||
|
case kValidateErrorPatternProperties: return RAPIDJSON_ERROR_STRING("Object has 'patternProperties' that are not allowed by the schema.");
|
||||||
|
case kValidateErrorDependencies: return RAPIDJSON_ERROR_STRING("Object has missing property or schema dependencies, refer to following errors.");
|
||||||
|
|
||||||
|
case kValidateErrorEnum: return RAPIDJSON_ERROR_STRING("Property has a value that is not one of its allowed enumerated values.");
|
||||||
|
case kValidateErrorType: return RAPIDJSON_ERROR_STRING("Property has a type '%actual' that is not in the following list: '%expected'.");
|
||||||
|
|
||||||
|
case kValidateErrorOneOf: return RAPIDJSON_ERROR_STRING("Property did not match any of the sub-schemas specified by 'oneOf', refer to following errors.");
|
||||||
|
case kValidateErrorOneOfMatch: return RAPIDJSON_ERROR_STRING("Property matched more than one of the sub-schemas specified by 'oneOf'.");
|
||||||
|
case kValidateErrorAllOf: return RAPIDJSON_ERROR_STRING("Property did not match all of the sub-schemas specified by 'allOf', refer to following errors.");
|
||||||
|
case kValidateErrorAnyOf: return RAPIDJSON_ERROR_STRING("Property did not match any of the sub-schemas specified by 'anyOf', refer to following errors.");
|
||||||
|
case kValidateErrorNot: return RAPIDJSON_ERROR_STRING("Property matched the sub-schema specified by 'not'.");
|
||||||
|
|
||||||
|
default: return RAPIDJSON_ERROR_STRING("Unknown error.");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
RAPIDJSON_NAMESPACE_END
|
RAPIDJSON_NAMESPACE_END
|
||||||
|
|
||||||
#ifdef __clang__
|
#ifdef __clang__
|
||||||
|
|
|
@ -1,6 +1,6 @@
|
||||||
// Tencent is pleased to support the open source community by making RapidJSON available.
|
// 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.
|
// Copyright (C) 2015 THL A29 Limited, a Tencent company, and Milo Yip.
|
||||||
//
|
//
|
||||||
// Licensed under the MIT License (the "License"); you may not use this file except
|
// 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
|
// in compliance with the License. You may obtain a copy of the License at
|
||||||
|
@ -152,6 +152,61 @@ private:
|
||||||
*/
|
*/
|
||||||
typedef const RAPIDJSON_ERROR_CHARTYPE* (*GetParseErrorFunc)(ParseErrorCode);
|
typedef const RAPIDJSON_ERROR_CHARTYPE* (*GetParseErrorFunc)(ParseErrorCode);
|
||||||
|
|
||||||
|
///////////////////////////////////////////////////////////////////////////////
|
||||||
|
// ValidateErrorCode
|
||||||
|
|
||||||
|
//! Error codes when validating.
|
||||||
|
/*! \ingroup RAPIDJSON_ERRORS
|
||||||
|
\see GenericSchemaValidator
|
||||||
|
*/
|
||||||
|
enum ValidateErrorCode {
|
||||||
|
kValidateErrors = -1, //!< Top level error code when kValidateContinueOnErrorsFlag set.
|
||||||
|
kValidateErrorNone = 0, //!< No error.
|
||||||
|
|
||||||
|
kValidateErrorMultipleOf, //!< Number is not a multiple of the 'multipleOf' value.
|
||||||
|
kValidateErrorMaximum, //!< Number is greater than the 'maximum' value.
|
||||||
|
kValidateErrorExclusiveMaximum, //!< Number is greater than or equal to the 'maximum' value.
|
||||||
|
kValidateErrorMinimum, //!< Number is less than the 'minimum' value.
|
||||||
|
kValidateErrorExclusiveMinimum, //!< Number is less than or equal to the 'minimum' value.
|
||||||
|
|
||||||
|
kValidateErrorMaxLength, //!< String is longer than the 'maxLength' value.
|
||||||
|
kValidateErrorMinLength, //!< String is longer than the 'maxLength' value.
|
||||||
|
kValidateErrorPattern, //!< String does not match the 'pattern' regular expression.
|
||||||
|
|
||||||
|
kValidateErrorMaxItems, //!< Array is longer than the 'maxItems' value.
|
||||||
|
kValidateErrorMinItems, //!< Array is shorter than the 'minItems' value.
|
||||||
|
kValidateErrorUniqueItems, //!< Array has duplicate items but 'uniqueItems' is true.
|
||||||
|
kValidateErrorAdditionalItems, //!< Array has additional items that are not allowed by the schema.
|
||||||
|
|
||||||
|
kValidateErrorMaxProperties, //!< Object has more members than 'maxProperties' value.
|
||||||
|
kValidateErrorMinProperties, //!< Object has less members than 'minProperties' value.
|
||||||
|
kValidateErrorRequired, //!< Object is missing one or more members required by the schema.
|
||||||
|
kValidateErrorAdditionalProperties, //!< Object has additional members that are not allowed by the schema.
|
||||||
|
kValidateErrorPatternProperties, //!< See other errors.
|
||||||
|
kValidateErrorDependencies, //!< Object has missing property or schema dependencies.
|
||||||
|
|
||||||
|
kValidateErrorEnum, //!< Property has a value that is not one of its allowed enumerated values
|
||||||
|
kValidateErrorType, //!< Property has a type that is not allowed by the schema..
|
||||||
|
|
||||||
|
kValidateErrorOneOf, //!< Property did not match any of the sub-schemas specified by 'oneOf'.
|
||||||
|
kValidateErrorOneOfMatch, //!< Property matched more than one of the sub-schemas specified by 'oneOf'.
|
||||||
|
kValidateErrorAllOf, //!< Property did not match all of the sub-schemas specified by 'allOf'.
|
||||||
|
kValidateErrorAnyOf, //!< Property did not match any of the sub-schemas specified by 'anyOf'.
|
||||||
|
kValidateErrorNot //!< Property matched the sub-schema specified by 'not'.
|
||||||
|
};
|
||||||
|
|
||||||
|
//! Function pointer type of GetValidateError().
|
||||||
|
/*! \ingroup RAPIDJSON_ERRORS
|
||||||
|
|
||||||
|
This is the prototype for \c GetValidateError_X(), where \c X is a locale.
|
||||||
|
User can dynamically change locale in runtime, e.g.:
|
||||||
|
\code
|
||||||
|
GetValidateErrorFunc GetValidateError = GetValidateError_En; // or whatever
|
||||||
|
const RAPIDJSON_ERROR_CHARTYPE* s = GetValidateError(validator.GetInvalidSchemaCode());
|
||||||
|
\endcode
|
||||||
|
*/
|
||||||
|
typedef const RAPIDJSON_ERROR_CHARTYPE* (*GetValidateErrorFunc)(ValidateErrorCode);
|
||||||
|
|
||||||
RAPIDJSON_NAMESPACE_END
|
RAPIDJSON_NAMESPACE_END
|
||||||
|
|
||||||
#ifdef __clang__
|
#ifdef __clang__
|
||||||
|
|
|
@ -1,6 +1,6 @@
|
||||||
// Tencent is pleased to support the open source community by making RapidJSON available.
|
// 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.
|
// Copyright (C) 2015 THL A29 Limited, a Tencent company, and Milo Yip.
|
||||||
//
|
//
|
||||||
// Licensed under the MIT License (the "License"); you may not use this file except
|
// 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
|
// in compliance with the License. You may obtain a copy of the License at
|
||||||
|
@ -59,7 +59,7 @@ public:
|
||||||
|
|
||||||
// For encoding detection only.
|
// For encoding detection only.
|
||||||
const Ch* Peek4() const {
|
const Ch* Peek4() const {
|
||||||
return (current_ + 4 <= bufferLast_) ? current_ : 0;
|
return (current_ + 4 - !eof_ <= bufferLast_) ? current_ : 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
private:
|
private:
|
||||||
|
@ -68,7 +68,7 @@ private:
|
||||||
++current_;
|
++current_;
|
||||||
else if (!eof_) {
|
else if (!eof_) {
|
||||||
count_ += readCount_;
|
count_ += readCount_;
|
||||||
readCount_ = fread(buffer_, 1, bufferSize_, fp_);
|
readCount_ = std::fread(buffer_, 1, bufferSize_, fp_);
|
||||||
bufferLast_ = buffer_ + readCount_ - 1;
|
bufferLast_ = buffer_ + readCount_ - 1;
|
||||||
current_ = buffer_;
|
current_ = buffer_;
|
||||||
|
|
||||||
|
|
|
@ -1,6 +1,6 @@
|
||||||
// Tencent is pleased to support the open source community by making RapidJSON available.
|
// 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.
|
// Copyright (C) 2015 THL A29 Limited, a Tencent company, and Milo Yip.
|
||||||
//
|
//
|
||||||
// Licensed under the MIT License (the "License"); you may not use this file except
|
// 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
|
// in compliance with the License. You may obtain a copy of the License at
|
||||||
|
@ -25,7 +25,7 @@ RAPIDJSON_DIAG_OFF(unreachable-code)
|
||||||
|
|
||||||
RAPIDJSON_NAMESPACE_BEGIN
|
RAPIDJSON_NAMESPACE_BEGIN
|
||||||
|
|
||||||
//! Wrapper of C file stream for input using fread().
|
//! Wrapper of C file stream for output using fwrite().
|
||||||
/*!
|
/*!
|
||||||
\note implements Stream concept
|
\note implements Stream concept
|
||||||
*/
|
*/
|
||||||
|
@ -62,7 +62,7 @@ public:
|
||||||
|
|
||||||
void Flush() {
|
void Flush() {
|
||||||
if (current_ != buffer_) {
|
if (current_ != buffer_) {
|
||||||
size_t result = fwrite(buffer_, 1, static_cast<size_t>(current_ - buffer_), fp_);
|
size_t result = std::fwrite(buffer_, 1, static_cast<size_t>(current_ - buffer_), fp_);
|
||||||
if (result < static_cast<size_t>(current_ - buffer_)) {
|
if (result < static_cast<size_t>(current_ - buffer_)) {
|
||||||
// failure deliberately ignored at this time
|
// failure deliberately ignored at this time
|
||||||
// added to avoid warn_unused_result build errors
|
// added to avoid warn_unused_result build errors
|
||||||
|
|
|
@ -1,6 +1,6 @@
|
||||||
// Tencent is pleased to support the open source community by making RapidJSON available.
|
// 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.
|
// Copyright (C) 2015 THL A29 Limited, a Tencent company, and Milo Yip.
|
||||||
//
|
//
|
||||||
// Licensed under the MIT License (the "License"); you may not use this file except
|
// 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
|
// in compliance with the License. You may obtain a copy of the License at
|
||||||
|
@ -102,7 +102,7 @@ class PrettyWriter;
|
||||||
// document.h
|
// document.h
|
||||||
|
|
||||||
template <typename Encoding, typename Allocator>
|
template <typename Encoding, typename Allocator>
|
||||||
struct GenericMember;
|
class GenericMember;
|
||||||
|
|
||||||
template <bool Const, typename Encoding, typename Allocator>
|
template <bool Const, typename Encoding, typename Allocator>
|
||||||
class GenericMemberIterator;
|
class GenericMemberIterator;
|
||||||
|
|
|
@ -1,6 +1,6 @@
|
||||||
// Tencent is pleased to support the open source community by making RapidJSON available.
|
// 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.
|
// Copyright (C) 2015 THL A29 Limited, a Tencent company, and Milo Yip.
|
||||||
//
|
//
|
||||||
// Licensed under the MIT License (the "License"); you may not use this file except
|
// 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
|
// in compliance with the License. You may obtain a copy of the License at
|
||||||
|
@ -17,7 +17,7 @@
|
||||||
|
|
||||||
#include "../rapidjson.h"
|
#include "../rapidjson.h"
|
||||||
|
|
||||||
#if defined(_MSC_VER) && defined(_M_AMD64)
|
#if defined(_MSC_VER) && !defined(__INTEL_COMPILER) && defined(_M_AMD64)
|
||||||
#include <intrin.h> // for _umul128
|
#include <intrin.h> // for _umul128
|
||||||
#pragma intrinsic(_umul128)
|
#pragma intrinsic(_umul128)
|
||||||
#endif
|
#endif
|
||||||
|
@ -133,7 +133,7 @@ public:
|
||||||
RAPIDJSON_ASSERT(count_ + offset <= kCapacity);
|
RAPIDJSON_ASSERT(count_ + offset <= kCapacity);
|
||||||
|
|
||||||
if (interShift == 0) {
|
if (interShift == 0) {
|
||||||
std::memmove(&digits_[count_ - 1 + offset], &digits_[count_ - 1], count_ * sizeof(Type));
|
std::memmove(digits_ + offset, digits_, count_ * sizeof(Type));
|
||||||
count_ += offset;
|
count_ += offset;
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
|
|
|
@ -0,0 +1,71 @@
|
||||||
|
// 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.
|
||||||
|
//
|
||||||
|
// 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_CLZLL_H_
|
||||||
|
#define RAPIDJSON_CLZLL_H_
|
||||||
|
|
||||||
|
#include "../rapidjson.h"
|
||||||
|
|
||||||
|
#if defined(_MSC_VER) && !defined(UNDER_CE)
|
||||||
|
#include <intrin.h>
|
||||||
|
#if defined(_WIN64)
|
||||||
|
#pragma intrinsic(_BitScanReverse64)
|
||||||
|
#else
|
||||||
|
#pragma intrinsic(_BitScanReverse)
|
||||||
|
#endif
|
||||||
|
#endif
|
||||||
|
|
||||||
|
RAPIDJSON_NAMESPACE_BEGIN
|
||||||
|
namespace internal {
|
||||||
|
|
||||||
|
inline uint32_t clzll(uint64_t x) {
|
||||||
|
// Passing 0 to __builtin_clzll is UB in GCC and results in an
|
||||||
|
// infinite loop in the software implementation.
|
||||||
|
RAPIDJSON_ASSERT(x != 0);
|
||||||
|
|
||||||
|
#if defined(_MSC_VER) && !defined(UNDER_CE)
|
||||||
|
unsigned long r = 0;
|
||||||
|
#if defined(_WIN64)
|
||||||
|
_BitScanReverse64(&r, x);
|
||||||
|
#else
|
||||||
|
// Scan the high 32 bits.
|
||||||
|
if (_BitScanReverse(&r, static_cast<uint32_t>(x >> 32)))
|
||||||
|
return 63 - (r + 32);
|
||||||
|
|
||||||
|
// Scan the low 32 bits.
|
||||||
|
_BitScanReverse(&r, static_cast<uint32_t>(x & 0xFFFFFFFF));
|
||||||
|
#endif // _WIN64
|
||||||
|
|
||||||
|
return 63 - r;
|
||||||
|
#elif (defined(__GNUC__) && __GNUC__ >= 4) || RAPIDJSON_HAS_BUILTIN(__builtin_clzll)
|
||||||
|
// __builtin_clzll wrapper
|
||||||
|
return static_cast<uint32_t>(__builtin_clzll(x));
|
||||||
|
#else
|
||||||
|
// naive version
|
||||||
|
uint32_t r = 0;
|
||||||
|
while (!(x & (static_cast<uint64_t>(1) << 63))) {
|
||||||
|
x <<= 1;
|
||||||
|
++r;
|
||||||
|
}
|
||||||
|
|
||||||
|
return r;
|
||||||
|
#endif // _MSC_VER
|
||||||
|
}
|
||||||
|
|
||||||
|
#define RAPIDJSON_CLZLL RAPIDJSON_NAMESPACE::internal::clzll
|
||||||
|
|
||||||
|
} // namespace internal
|
||||||
|
RAPIDJSON_NAMESPACE_END
|
||||||
|
|
||||||
|
#endif // RAPIDJSON_CLZLL_H_
|
|
@ -1,6 +1,6 @@
|
||||||
// Tencent is pleased to support the open source community by making RapidJSON available.
|
// 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.
|
// Copyright (C) 2015 THL A29 Limited, a Tencent company, and Milo Yip.
|
||||||
//
|
//
|
||||||
// Licensed under the MIT License (the "License"); you may not use this file except
|
// 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
|
// in compliance with the License. You may obtain a copy of the License at
|
||||||
|
@ -20,10 +20,11 @@
|
||||||
#define RAPIDJSON_DIYFP_H_
|
#define RAPIDJSON_DIYFP_H_
|
||||||
|
|
||||||
#include "../rapidjson.h"
|
#include "../rapidjson.h"
|
||||||
|
#include "clzll.h"
|
||||||
|
#include <limits>
|
||||||
|
|
||||||
#if defined(_MSC_VER) && defined(_M_AMD64) && !defined(__INTEL_COMPILER)
|
#if defined(_MSC_VER) && defined(_M_AMD64) && !defined(__INTEL_COMPILER)
|
||||||
#include <intrin.h>
|
#include <intrin.h>
|
||||||
#pragma intrinsic(_BitScanReverse64)
|
|
||||||
#pragma intrinsic(_umul128)
|
#pragma intrinsic(_umul128)
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
@ -99,21 +100,8 @@ struct DiyFp {
|
||||||
}
|
}
|
||||||
|
|
||||||
DiyFp Normalize() const {
|
DiyFp Normalize() const {
|
||||||
#if defined(_MSC_VER) && defined(_M_AMD64)
|
int s = static_cast<int>(clzll(f));
|
||||||
unsigned long index;
|
|
||||||
_BitScanReverse64(&index, f);
|
|
||||||
return DiyFp(f << (63 - index), e - (63 - index));
|
|
||||||
#elif defined(__GNUC__) && __GNUC__ >= 4
|
|
||||||
int s = __builtin_clzll(f);
|
|
||||||
return DiyFp(f << s, e - s);
|
return DiyFp(f << s, e - s);
|
||||||
#else
|
|
||||||
DiyFp res = *this;
|
|
||||||
while (!(res.f & (static_cast<uint64_t>(1) << 63))) {
|
|
||||||
res.f <<= 1;
|
|
||||||
res.e--;
|
|
||||||
}
|
|
||||||
return res;
|
|
||||||
#endif
|
|
||||||
}
|
}
|
||||||
|
|
||||||
DiyFp NormalizeBoundary() const {
|
DiyFp NormalizeBoundary() const {
|
||||||
|
@ -141,6 +129,15 @@ struct DiyFp {
|
||||||
double d;
|
double d;
|
||||||
uint64_t u64;
|
uint64_t u64;
|
||||||
}u;
|
}u;
|
||||||
|
RAPIDJSON_ASSERT(f <= kDpHiddenBit + kDpSignificandMask);
|
||||||
|
if (e < kDpDenormalExponent) {
|
||||||
|
// Underflow.
|
||||||
|
return 0.0;
|
||||||
|
}
|
||||||
|
if (e >= kDpMaxExponent) {
|
||||||
|
// Overflow.
|
||||||
|
return std::numeric_limits<double>::infinity();
|
||||||
|
}
|
||||||
const uint64_t be = (e == kDpDenormalExponent && (f & kDpHiddenBit) == 0) ? 0 :
|
const uint64_t be = (e == kDpDenormalExponent && (f & kDpHiddenBit) == 0) ? 0 :
|
||||||
static_cast<uint64_t>(e + kDpExponentBias);
|
static_cast<uint64_t>(e + kDpExponentBias);
|
||||||
u.u64 = (f & kDpSignificandMask) | (be << kDpSignificandSize);
|
u.u64 = (f & kDpSignificandMask) | (be << kDpSignificandSize);
|
||||||
|
@ -220,6 +217,7 @@ inline DiyFp GetCachedPowerByIndex(size_t index) {
|
||||||
641, 667, 694, 720, 747, 774, 800, 827, 853, 880,
|
641, 667, 694, 720, 747, 774, 800, 827, 853, 880,
|
||||||
907, 933, 960, 986, 1013, 1039, 1066
|
907, 933, 960, 986, 1013, 1039, 1066
|
||||||
};
|
};
|
||||||
|
RAPIDJSON_ASSERT(index < 87);
|
||||||
return DiyFp(kCachedPowers_F[index], kCachedPowers_E[index]);
|
return DiyFp(kCachedPowers_F[index], kCachedPowers_E[index]);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -238,10 +236,11 @@ inline DiyFp GetCachedPower(int e, int* K) {
|
||||||
}
|
}
|
||||||
|
|
||||||
inline DiyFp GetCachedPower10(int exp, int *outExp) {
|
inline DiyFp GetCachedPower10(int exp, int *outExp) {
|
||||||
unsigned index = (static_cast<unsigned>(exp) + 348u) / 8u;
|
RAPIDJSON_ASSERT(exp >= -348);
|
||||||
|
unsigned index = static_cast<unsigned>(exp + 348) / 8u;
|
||||||
*outExp = -348 + static_cast<int>(index) * 8;
|
*outExp = -348 + static_cast<int>(index) * 8;
|
||||||
return GetCachedPowerByIndex(index);
|
return GetCachedPowerByIndex(index);
|
||||||
}
|
}
|
||||||
|
|
||||||
#ifdef __GNUC__
|
#ifdef __GNUC__
|
||||||
RAPIDJSON_DIAG_POP
|
RAPIDJSON_DIAG_POP
|
||||||
|
|
|
@ -1,6 +1,6 @@
|
||||||
// Tencent is pleased to support the open source community by making RapidJSON available.
|
// 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.
|
// Copyright (C) 2015 THL A29 Limited, a Tencent company, and Milo Yip.
|
||||||
//
|
//
|
||||||
// Licensed under the MIT License (the "License"); you may not use this file except
|
// 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
|
// in compliance with the License. You may obtain a copy of the License at
|
||||||
|
|
|
@ -1,6 +1,6 @@
|
||||||
// Tencent is pleased to support the open source community by making RapidJSON available.
|
// 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.
|
// Copyright (C) 2015 THL A29 Limited, a Tencent company, and Milo Yip.
|
||||||
//
|
//
|
||||||
// Licensed under the MIT License (the "License"); you may not use this file except
|
// 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
|
// in compliance with the License. You may obtain a copy of the License at
|
||||||
|
|
|
@ -1,6 +1,6 @@
|
||||||
// Tencent is pleased to support the open source community by making RapidJSON available.
|
// 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.
|
// Copyright (C) 2015 THL A29 Limited, a Tencent company, and Milo Yip.
|
||||||
//
|
//
|
||||||
// Licensed under the MIT License (the "License"); you may not use this file except
|
// 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
|
// in compliance with the License. You may obtain a copy of the License at
|
||||||
|
@ -37,6 +37,8 @@ inline const char* GetDigitsLut() {
|
||||||
}
|
}
|
||||||
|
|
||||||
inline char* u32toa(uint32_t value, char* buffer) {
|
inline char* u32toa(uint32_t value, char* buffer) {
|
||||||
|
RAPIDJSON_ASSERT(buffer != 0);
|
||||||
|
|
||||||
const char* cDigitsLut = GetDigitsLut();
|
const char* cDigitsLut = GetDigitsLut();
|
||||||
|
|
||||||
if (value < 10000) {
|
if (value < 10000) {
|
||||||
|
@ -111,6 +113,7 @@ inline char* u32toa(uint32_t value, char* buffer) {
|
||||||
}
|
}
|
||||||
|
|
||||||
inline char* i32toa(int32_t value, char* buffer) {
|
inline char* i32toa(int32_t value, char* buffer) {
|
||||||
|
RAPIDJSON_ASSERT(buffer != 0);
|
||||||
uint32_t u = static_cast<uint32_t>(value);
|
uint32_t u = static_cast<uint32_t>(value);
|
||||||
if (value < 0) {
|
if (value < 0) {
|
||||||
*buffer++ = '-';
|
*buffer++ = '-';
|
||||||
|
@ -121,6 +124,7 @@ inline char* i32toa(int32_t value, char* buffer) {
|
||||||
}
|
}
|
||||||
|
|
||||||
inline char* u64toa(uint64_t value, char* buffer) {
|
inline char* u64toa(uint64_t value, char* buffer) {
|
||||||
|
RAPIDJSON_ASSERT(buffer != 0);
|
||||||
const char* cDigitsLut = GetDigitsLut();
|
const char* cDigitsLut = GetDigitsLut();
|
||||||
const uint64_t kTen8 = 100000000;
|
const uint64_t kTen8 = 100000000;
|
||||||
const uint64_t kTen9 = kTen8 * 10;
|
const uint64_t kTen9 = kTen8 * 10;
|
||||||
|
@ -207,9 +211,8 @@ inline char* u64toa(uint64_t value, char* buffer) {
|
||||||
*buffer++ = cDigitsLut[d3 + 1];
|
*buffer++ = cDigitsLut[d3 + 1];
|
||||||
if (value >= kTen9)
|
if (value >= kTen9)
|
||||||
*buffer++ = cDigitsLut[d4];
|
*buffer++ = cDigitsLut[d4];
|
||||||
if (value >= kTen8)
|
|
||||||
*buffer++ = cDigitsLut[d4 + 1];
|
|
||||||
|
|
||||||
|
*buffer++ = cDigitsLut[d4 + 1];
|
||||||
*buffer++ = cDigitsLut[d5];
|
*buffer++ = cDigitsLut[d5];
|
||||||
*buffer++ = cDigitsLut[d5 + 1];
|
*buffer++ = cDigitsLut[d5 + 1];
|
||||||
*buffer++ = cDigitsLut[d6];
|
*buffer++ = cDigitsLut[d6];
|
||||||
|
@ -289,6 +292,7 @@ inline char* u64toa(uint64_t value, char* buffer) {
|
||||||
}
|
}
|
||||||
|
|
||||||
inline char* i64toa(int64_t value, char* buffer) {
|
inline char* i64toa(int64_t value, char* buffer) {
|
||||||
|
RAPIDJSON_ASSERT(buffer != 0);
|
||||||
uint64_t u = static_cast<uint64_t>(value);
|
uint64_t u = static_cast<uint64_t>(value);
|
||||||
if (value < 0) {
|
if (value < 0) {
|
||||||
*buffer++ = '-';
|
*buffer++ = '-';
|
||||||
|
|
|
@ -1,6 +1,6 @@
|
||||||
// Tencent is pleased to support the open source community by making RapidJSON available.
|
// 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.
|
// Copyright (C) 2015 THL A29 Limited, a Tencent company, and Milo Yip.
|
||||||
//
|
//
|
||||||
// Licensed under the MIT License (the "License"); you may not use this file except
|
// 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
|
// in compliance with the License. You may obtain a copy of the License at
|
||||||
|
@ -21,6 +21,7 @@
|
||||||
RAPIDJSON_DIAG_PUSH
|
RAPIDJSON_DIAG_PUSH
|
||||||
RAPIDJSON_DIAG_OFF(effc++)
|
RAPIDJSON_DIAG_OFF(effc++)
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
#if defined(_MSC_VER) && !defined(__clang__)
|
#if defined(_MSC_VER) && !defined(__clang__)
|
||||||
RAPIDJSON_DIAG_PUSH
|
RAPIDJSON_DIAG_PUSH
|
||||||
RAPIDJSON_DIAG_OFF(6334)
|
RAPIDJSON_DIAG_OFF(6334)
|
||||||
|
@ -174,7 +175,11 @@ template <typename T> struct RemoveSfinaeTag<SfinaeTag&(*)(T)> { typedef T Type;
|
||||||
RAPIDJSON_NAMESPACE_END
|
RAPIDJSON_NAMESPACE_END
|
||||||
//@endcond
|
//@endcond
|
||||||
|
|
||||||
#if defined(__GNUC__) || (defined(_MSC_VER) && !defined(__clang__))
|
#if defined(_MSC_VER) && !defined(__clang__)
|
||||||
|
RAPIDJSON_DIAG_POP
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#ifdef __GNUC__
|
||||||
RAPIDJSON_DIAG_POP
|
RAPIDJSON_DIAG_POP
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
|
|
@ -1,6 +1,6 @@
|
||||||
// Tencent is pleased to support the open source community by making RapidJSON available.
|
// 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.
|
// Copyright (C) 2015 THL A29 Limited, a Tencent company, and Milo Yip.
|
||||||
//
|
//
|
||||||
// Licensed under the MIT License (the "License"); you may not use this file except
|
// 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
|
// in compliance with the License. You may obtain a copy of the License at
|
||||||
|
|
|
@ -1,6 +1,6 @@
|
||||||
// Tencent is pleased to support the open source community by making RapidJSON available.
|
// 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.
|
// Copyright (C) 2015 THL A29 Limited, a Tencent company, and Milo Yip.
|
||||||
//
|
//
|
||||||
// Licensed under the MIT License (the "License"); you may not use this file except
|
// 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
|
// in compliance with the License. You may obtain a copy of the License at
|
||||||
|
@ -23,20 +23,14 @@
|
||||||
RAPIDJSON_DIAG_PUSH
|
RAPIDJSON_DIAG_PUSH
|
||||||
RAPIDJSON_DIAG_OFF(padded)
|
RAPIDJSON_DIAG_OFF(padded)
|
||||||
RAPIDJSON_DIAG_OFF(switch-enum)
|
RAPIDJSON_DIAG_OFF(switch-enum)
|
||||||
RAPIDJSON_DIAG_OFF(implicit-fallthrough)
|
#elif defined(_MSC_VER)
|
||||||
|
RAPIDJSON_DIAG_PUSH
|
||||||
|
RAPIDJSON_DIAG_OFF(4512) // assignment operator could not be generated
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
#ifdef __GNUC__
|
#ifdef __GNUC__
|
||||||
RAPIDJSON_DIAG_PUSH
|
RAPIDJSON_DIAG_PUSH
|
||||||
RAPIDJSON_DIAG_OFF(effc++)
|
RAPIDJSON_DIAG_OFF(effc++)
|
||||||
#if __GNUC__ >= 7
|
|
||||||
RAPIDJSON_DIAG_OFF(implicit-fallthrough)
|
|
||||||
#endif
|
|
||||||
#endif
|
|
||||||
|
|
||||||
#ifdef _MSC_VER
|
|
||||||
RAPIDJSON_DIAG_PUSH
|
|
||||||
RAPIDJSON_DIAG_OFF(4512) // assignment operator could not be generated
|
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
#ifndef RAPIDJSON_REGEX_VERBOSE
|
#ifndef RAPIDJSON_REGEX_VERBOSE
|
||||||
|
@ -120,7 +114,8 @@ public:
|
||||||
template <typename, typename> friend class GenericRegexSearch;
|
template <typename, typename> friend class GenericRegexSearch;
|
||||||
|
|
||||||
GenericRegex(const Ch* source, Allocator* allocator = 0) :
|
GenericRegex(const Ch* source, Allocator* allocator = 0) :
|
||||||
states_(allocator, 256), ranges_(allocator, 256), root_(kRegexInvalidState), stateCount_(), rangeCount_(),
|
ownAllocator_(allocator ? 0 : RAPIDJSON_NEW(Allocator)()), allocator_(allocator ? allocator : ownAllocator_),
|
||||||
|
states_(allocator_, 256), ranges_(allocator_, 256), root_(kRegexInvalidState), stateCount_(), rangeCount_(),
|
||||||
anchorBegin_(), anchorEnd_()
|
anchorBegin_(), anchorEnd_()
|
||||||
{
|
{
|
||||||
GenericStringStream<Encoding> ss(source);
|
GenericStringStream<Encoding> ss(source);
|
||||||
|
@ -128,7 +123,10 @@ public:
|
||||||
Parse(ds);
|
Parse(ds);
|
||||||
}
|
}
|
||||||
|
|
||||||
~GenericRegex() {}
|
~GenericRegex()
|
||||||
|
{
|
||||||
|
RAPIDJSON_DELETE(ownAllocator_);
|
||||||
|
}
|
||||||
|
|
||||||
bool IsValid() const {
|
bool IsValid() const {
|
||||||
return root_ != kRegexInvalidState;
|
return root_ != kRegexInvalidState;
|
||||||
|
@ -190,10 +188,9 @@ private:
|
||||||
|
|
||||||
template <typename InputStream>
|
template <typename InputStream>
|
||||||
void Parse(DecodedStream<InputStream, Encoding>& ds) {
|
void Parse(DecodedStream<InputStream, Encoding>& ds) {
|
||||||
Allocator allocator;
|
Stack<Allocator> operandStack(allocator_, 256); // Frag
|
||||||
Stack<Allocator> operandStack(&allocator, 256); // Frag
|
Stack<Allocator> operatorStack(allocator_, 256); // Operator
|
||||||
Stack<Allocator> operatorStack(&allocator, 256); // Operator
|
Stack<Allocator> atomCountStack(allocator_, 256); // unsigned (Atom per parenthesis)
|
||||||
Stack<Allocator> atomCountStack(&allocator, 256); // unsigned (Atom per parenthesis)
|
|
||||||
|
|
||||||
*atomCountStack.template Push<unsigned>() = 0;
|
*atomCountStack.template Push<unsigned>() = 0;
|
||||||
|
|
||||||
|
@ -290,6 +287,7 @@ private:
|
||||||
if (!CharacterEscape(ds, &codepoint))
|
if (!CharacterEscape(ds, &codepoint))
|
||||||
return; // Unsupported escape character
|
return; // Unsupported escape character
|
||||||
// fall through to default
|
// fall through to default
|
||||||
|
RAPIDJSON_DELIBERATE_FALLTHROUGH;
|
||||||
|
|
||||||
default: // Pattern character
|
default: // Pattern character
|
||||||
PushOperand(operandStack, codepoint);
|
PushOperand(operandStack, codepoint);
|
||||||
|
@ -394,8 +392,7 @@ private:
|
||||||
}
|
}
|
||||||
return false;
|
return false;
|
||||||
|
|
||||||
default:
|
case kOneOrMore:
|
||||||
RAPIDJSON_ASSERT(op == kOneOrMore);
|
|
||||||
if (operandStack.GetSize() >= sizeof(Frag)) {
|
if (operandStack.GetSize() >= sizeof(Frag)) {
|
||||||
Frag e = *operandStack.template Pop<Frag>(1);
|
Frag e = *operandStack.template Pop<Frag>(1);
|
||||||
SizeType s = NewState(kRegexInvalidState, e.start, 0);
|
SizeType s = NewState(kRegexInvalidState, e.start, 0);
|
||||||
|
@ -404,6 +401,10 @@ private:
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
return false;
|
return false;
|
||||||
|
|
||||||
|
default:
|
||||||
|
// syntax error (e.g. unclosed kLeftParenthesis)
|
||||||
|
return false;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -516,6 +517,7 @@ private:
|
||||||
else if (!CharacterEscape(ds, &codepoint))
|
else if (!CharacterEscape(ds, &codepoint))
|
||||||
return false;
|
return false;
|
||||||
// fall through to default
|
// fall through to default
|
||||||
|
RAPIDJSON_DELIBERATE_FALLTHROUGH;
|
||||||
|
|
||||||
default:
|
default:
|
||||||
switch (step) {
|
switch (step) {
|
||||||
|
@ -525,6 +527,7 @@ private:
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
// fall through to step 0 for other characters
|
// fall through to step 0 for other characters
|
||||||
|
RAPIDJSON_DELIBERATE_FALLTHROUGH;
|
||||||
|
|
||||||
case 0:
|
case 0:
|
||||||
{
|
{
|
||||||
|
@ -584,6 +587,8 @@ private:
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Allocator* ownAllocator_;
|
||||||
|
Allocator* allocator_;
|
||||||
Stack<Allocator> states_;
|
Stack<Allocator> states_;
|
||||||
Stack<Allocator> ranges_;
|
Stack<Allocator> ranges_;
|
||||||
SizeType root_;
|
SizeType root_;
|
||||||
|
@ -723,11 +728,11 @@ typedef GenericRegexSearch<Regex> RegexSearch;
|
||||||
} // namespace internal
|
} // namespace internal
|
||||||
RAPIDJSON_NAMESPACE_END
|
RAPIDJSON_NAMESPACE_END
|
||||||
|
|
||||||
#ifdef __clang__
|
#ifdef __GNUC__
|
||||||
RAPIDJSON_DIAG_POP
|
RAPIDJSON_DIAG_POP
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
#ifdef _MSC_VER
|
#if defined(__clang__) || defined(_MSC_VER)
|
||||||
RAPIDJSON_DIAG_POP
|
RAPIDJSON_DIAG_POP
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
|
|
@ -1,6 +1,6 @@
|
||||||
// Tencent is pleased to support the open source community by making RapidJSON available.
|
// 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.
|
// Copyright (C) 2015 THL A29 Limited, a Tencent company, and Milo Yip.
|
||||||
//
|
//
|
||||||
// Licensed under the MIT License (the "License"); you may not use this file except
|
// 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
|
// in compliance with the License. You may obtain a copy of the License at
|
||||||
|
@ -17,6 +17,7 @@
|
||||||
|
|
||||||
#include "../allocators.h"
|
#include "../allocators.h"
|
||||||
#include "swap.h"
|
#include "swap.h"
|
||||||
|
#include <cstddef>
|
||||||
|
|
||||||
#if defined(__clang__)
|
#if defined(__clang__)
|
||||||
RAPIDJSON_DIAG_PUSH
|
RAPIDJSON_DIAG_PUSH
|
||||||
|
@ -100,7 +101,7 @@ public:
|
||||||
void ShrinkToFit() {
|
void ShrinkToFit() {
|
||||||
if (Empty()) {
|
if (Empty()) {
|
||||||
// If the stack is empty, completely deallocate the memory.
|
// If the stack is empty, completely deallocate the memory.
|
||||||
Allocator::Free(stack_);
|
Allocator::Free(stack_); // NOLINT (+clang-analyzer-unix.Malloc)
|
||||||
stack_ = 0;
|
stack_ = 0;
|
||||||
stackTop_ = 0;
|
stackTop_ = 0;
|
||||||
stackEnd_ = 0;
|
stackEnd_ = 0;
|
||||||
|
@ -114,7 +115,7 @@ public:
|
||||||
template<typename T>
|
template<typename T>
|
||||||
RAPIDJSON_FORCEINLINE void Reserve(size_t count = 1) {
|
RAPIDJSON_FORCEINLINE void Reserve(size_t count = 1) {
|
||||||
// Expand the stack if needed
|
// Expand the stack if needed
|
||||||
if (RAPIDJSON_UNLIKELY(stackTop_ + sizeof(T) * count > stackEnd_))
|
if (RAPIDJSON_UNLIKELY(static_cast<std::ptrdiff_t>(sizeof(T) * count) > (stackEnd_ - stackTop_)))
|
||||||
Expand<T>(count);
|
Expand<T>(count);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -127,7 +128,7 @@ public:
|
||||||
template<typename T>
|
template<typename T>
|
||||||
RAPIDJSON_FORCEINLINE T* PushUnsafe(size_t count = 1) {
|
RAPIDJSON_FORCEINLINE T* PushUnsafe(size_t count = 1) {
|
||||||
RAPIDJSON_ASSERT(stackTop_);
|
RAPIDJSON_ASSERT(stackTop_);
|
||||||
RAPIDJSON_ASSERT(stackTop_ + sizeof(T) * count <= stackEnd_);
|
RAPIDJSON_ASSERT(static_cast<std::ptrdiff_t>(sizeof(T) * count) <= (stackEnd_ - stackTop_));
|
||||||
T* ret = reinterpret_cast<T*>(stackTop_);
|
T* ret = reinterpret_cast<T*>(stackTop_);
|
||||||
stackTop_ += sizeof(T) * count;
|
stackTop_ += sizeof(T) * count;
|
||||||
return ret;
|
return ret;
|
||||||
|
|
|
@ -1,6 +1,6 @@
|
||||||
// Tencent is pleased to support the open source community by making RapidJSON available.
|
// 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.
|
// Copyright (C) 2015 THL A29 Limited, a Tencent company, and Milo Yip.
|
||||||
//
|
//
|
||||||
// Licensed under the MIT License (the "License"); you may not use this file except
|
// 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
|
// in compliance with the License. You may obtain a copy of the License at
|
||||||
|
|
|
@ -1,6 +1,6 @@
|
||||||
// Tencent is pleased to support the open source community by making RapidJSON available.
|
// 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.
|
// Copyright (C) 2015 THL A29 Limited, a Tencent company, and Milo Yip.
|
||||||
//
|
//
|
||||||
// Licensed under the MIT License (the "License"); you may not use this file except
|
// 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
|
// in compliance with the License. You may obtain a copy of the License at
|
||||||
|
@ -19,6 +19,8 @@
|
||||||
#include "biginteger.h"
|
#include "biginteger.h"
|
||||||
#include "diyfp.h"
|
#include "diyfp.h"
|
||||||
#include "pow10.h"
|
#include "pow10.h"
|
||||||
|
#include <climits>
|
||||||
|
#include <limits>
|
||||||
|
|
||||||
RAPIDJSON_NAMESPACE_BEGIN
|
RAPIDJSON_NAMESPACE_BEGIN
|
||||||
namespace internal {
|
namespace internal {
|
||||||
|
@ -126,20 +128,20 @@ inline bool StrtodFast(double d, int p, double* result) {
|
||||||
}
|
}
|
||||||
|
|
||||||
// Compute an approximation and see if it is within 1/2 ULP
|
// Compute an approximation and see if it is within 1/2 ULP
|
||||||
inline bool StrtodDiyFp(const char* decimals, size_t length, size_t decimalPosition, int exp, double* result) {
|
inline bool StrtodDiyFp(const char* decimals, int dLen, int dExp, double* result) {
|
||||||
uint64_t significand = 0;
|
uint64_t significand = 0;
|
||||||
size_t i = 0; // 2^64 - 1 = 18446744073709551615, 1844674407370955161 = 0x1999999999999999
|
int i = 0; // 2^64 - 1 = 18446744073709551615, 1844674407370955161 = 0x1999999999999999
|
||||||
for (; i < length; i++) {
|
for (; i < dLen; i++) {
|
||||||
if (significand > RAPIDJSON_UINT64_C2(0x19999999, 0x99999999) ||
|
if (significand > RAPIDJSON_UINT64_C2(0x19999999, 0x99999999) ||
|
||||||
(significand == RAPIDJSON_UINT64_C2(0x19999999, 0x99999999) && decimals[i] > '5'))
|
(significand == RAPIDJSON_UINT64_C2(0x19999999, 0x99999999) && decimals[i] > '5'))
|
||||||
break;
|
break;
|
||||||
significand = significand * 10u + static_cast<unsigned>(decimals[i] - '0');
|
significand = significand * 10u + static_cast<unsigned>(decimals[i] - '0');
|
||||||
}
|
}
|
||||||
|
|
||||||
if (i < length && decimals[i] >= '5') // Rounding
|
if (i < dLen && decimals[i] >= '5') // Rounding
|
||||||
significand++;
|
significand++;
|
||||||
|
|
||||||
size_t remaining = length - i;
|
int remaining = dLen - i;
|
||||||
const int kUlpShift = 3;
|
const int kUlpShift = 3;
|
||||||
const int kUlp = 1 << kUlpShift;
|
const int kUlp = 1 << kUlpShift;
|
||||||
int64_t error = (remaining == 0) ? 0 : kUlp / 2;
|
int64_t error = (remaining == 0) ? 0 : kUlp / 2;
|
||||||
|
@ -148,24 +150,24 @@ inline bool StrtodDiyFp(const char* decimals, size_t length, size_t decimalPosit
|
||||||
v = v.Normalize();
|
v = v.Normalize();
|
||||||
error <<= -v.e;
|
error <<= -v.e;
|
||||||
|
|
||||||
const int dExp = static_cast<int>(decimalPosition) - static_cast<int>(i) + exp;
|
dExp += remaining;
|
||||||
|
|
||||||
int actualExp;
|
int actualExp;
|
||||||
DiyFp cachedPower = GetCachedPower10(dExp, &actualExp);
|
DiyFp cachedPower = GetCachedPower10(dExp, &actualExp);
|
||||||
if (actualExp != dExp) {
|
if (actualExp != dExp) {
|
||||||
static const DiyFp kPow10[] = {
|
static const DiyFp kPow10[] = {
|
||||||
DiyFp(RAPIDJSON_UINT64_C2(0xa0000000, 00000000), -60), // 10^1
|
DiyFp(RAPIDJSON_UINT64_C2(0xa0000000, 0x00000000), -60), // 10^1
|
||||||
DiyFp(RAPIDJSON_UINT64_C2(0xc8000000, 00000000), -57), // 10^2
|
DiyFp(RAPIDJSON_UINT64_C2(0xc8000000, 0x00000000), -57), // 10^2
|
||||||
DiyFp(RAPIDJSON_UINT64_C2(0xfa000000, 00000000), -54), // 10^3
|
DiyFp(RAPIDJSON_UINT64_C2(0xfa000000, 0x00000000), -54), // 10^3
|
||||||
DiyFp(RAPIDJSON_UINT64_C2(0x9c400000, 00000000), -50), // 10^4
|
DiyFp(RAPIDJSON_UINT64_C2(0x9c400000, 0x00000000), -50), // 10^4
|
||||||
DiyFp(RAPIDJSON_UINT64_C2(0xc3500000, 00000000), -47), // 10^5
|
DiyFp(RAPIDJSON_UINT64_C2(0xc3500000, 0x00000000), -47), // 10^5
|
||||||
DiyFp(RAPIDJSON_UINT64_C2(0xf4240000, 00000000), -44), // 10^6
|
DiyFp(RAPIDJSON_UINT64_C2(0xf4240000, 0x00000000), -44), // 10^6
|
||||||
DiyFp(RAPIDJSON_UINT64_C2(0x98968000, 00000000), -40) // 10^7
|
DiyFp(RAPIDJSON_UINT64_C2(0x98968000, 0x00000000), -40) // 10^7
|
||||||
};
|
};
|
||||||
int adjustment = dExp - actualExp - 1;
|
int adjustment = dExp - actualExp;
|
||||||
RAPIDJSON_ASSERT(adjustment >= 0 && adjustment < 7);
|
RAPIDJSON_ASSERT(adjustment >= 1 && adjustment < 8);
|
||||||
v = v * kPow10[adjustment];
|
v = v * kPow10[adjustment - 1];
|
||||||
if (length + static_cast<unsigned>(adjustment)> 19u) // has more digits than decimal digits in 64-bit
|
if (dLen + adjustment > 19) // has more digits than decimal digits in 64-bit
|
||||||
error += kUlp / 2;
|
error += kUlp / 2;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -203,9 +205,9 @@ inline bool StrtodDiyFp(const char* decimals, size_t length, size_t decimalPosit
|
||||||
return halfWay - static_cast<unsigned>(error) >= precisionBits || precisionBits >= halfWay + static_cast<unsigned>(error);
|
return halfWay - static_cast<unsigned>(error) >= precisionBits || precisionBits >= halfWay + static_cast<unsigned>(error);
|
||||||
}
|
}
|
||||||
|
|
||||||
inline double StrtodBigInteger(double approx, const char* decimals, size_t length, size_t decimalPosition, int exp) {
|
inline double StrtodBigInteger(double approx, const char* decimals, int dLen, int dExp) {
|
||||||
const BigInteger dInt(decimals, length);
|
RAPIDJSON_ASSERT(dLen >= 0);
|
||||||
const int dExp = static_cast<int>(decimalPosition) - static_cast<int>(length) + exp;
|
const BigInteger dInt(decimals, static_cast<unsigned>(dLen));
|
||||||
Double a(approx);
|
Double a(approx);
|
||||||
int cmp = CheckWithinHalfULP(a.Value(), dInt, dExp);
|
int cmp = CheckWithinHalfULP(a.Value(), dInt, dExp);
|
||||||
if (cmp < 0)
|
if (cmp < 0)
|
||||||
|
@ -225,42 +227,61 @@ inline double StrtodFullPrecision(double d, int p, const char* decimals, size_t
|
||||||
RAPIDJSON_ASSERT(d >= 0.0);
|
RAPIDJSON_ASSERT(d >= 0.0);
|
||||||
RAPIDJSON_ASSERT(length >= 1);
|
RAPIDJSON_ASSERT(length >= 1);
|
||||||
|
|
||||||
double result;
|
double result = 0.0;
|
||||||
if (StrtodFast(d, p, &result))
|
if (StrtodFast(d, p, &result))
|
||||||
return result;
|
return result;
|
||||||
|
|
||||||
|
RAPIDJSON_ASSERT(length <= INT_MAX);
|
||||||
|
int dLen = static_cast<int>(length);
|
||||||
|
|
||||||
|
RAPIDJSON_ASSERT(length >= decimalPosition);
|
||||||
|
RAPIDJSON_ASSERT(length - decimalPosition <= INT_MAX);
|
||||||
|
int dExpAdjust = static_cast<int>(length - decimalPosition);
|
||||||
|
|
||||||
|
RAPIDJSON_ASSERT(exp >= INT_MIN + dExpAdjust);
|
||||||
|
int dExp = exp - dExpAdjust;
|
||||||
|
|
||||||
|
// Make sure length+dExp does not overflow
|
||||||
|
RAPIDJSON_ASSERT(dExp <= INT_MAX - dLen);
|
||||||
|
|
||||||
// Trim leading zeros
|
// Trim leading zeros
|
||||||
while (*decimals == '0' && length > 1) {
|
while (dLen > 0 && *decimals == '0') {
|
||||||
length--;
|
dLen--;
|
||||||
decimals++;
|
decimals++;
|
||||||
decimalPosition--;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// Trim trailing zeros
|
// Trim trailing zeros
|
||||||
while (decimals[length - 1] == '0' && length > 1) {
|
while (dLen > 0 && decimals[dLen - 1] == '0') {
|
||||||
length--;
|
dLen--;
|
||||||
decimalPosition--;
|
dExp++;
|
||||||
exp++;
|
}
|
||||||
|
|
||||||
|
if (dLen == 0) { // Buffer only contains zeros.
|
||||||
|
return 0.0;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Trim right-most digits
|
// Trim right-most digits
|
||||||
const int kMaxDecimalDigit = 780;
|
const int kMaxDecimalDigit = 767 + 1;
|
||||||
if (static_cast<int>(length) > kMaxDecimalDigit) {
|
if (dLen > kMaxDecimalDigit) {
|
||||||
int delta = (static_cast<int>(length) - kMaxDecimalDigit);
|
dExp += dLen - kMaxDecimalDigit;
|
||||||
exp += delta;
|
dLen = kMaxDecimalDigit;
|
||||||
decimalPosition -= static_cast<unsigned>(delta);
|
|
||||||
length = kMaxDecimalDigit;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// If too small, underflow to zero
|
// If too small, underflow to zero.
|
||||||
if (int(length) + exp < -324)
|
// Any x <= 10^-324 is interpreted as zero.
|
||||||
|
if (dLen + dExp <= -324)
|
||||||
return 0.0;
|
return 0.0;
|
||||||
|
|
||||||
if (StrtodDiyFp(decimals, length, decimalPosition, exp, &result))
|
// If too large, overflow to infinity.
|
||||||
|
// Any x >= 10^309 is interpreted as +infinity.
|
||||||
|
if (dLen + dExp > 309)
|
||||||
|
return std::numeric_limits<double>::infinity();
|
||||||
|
|
||||||
|
if (StrtodDiyFp(decimals, dLen, dExp, &result))
|
||||||
return result;
|
return result;
|
||||||
|
|
||||||
// Use approximation from StrtodDiyFp and make adjustment with BigInteger comparison
|
// Use approximation from StrtodDiyFp and make adjustment with BigInteger comparison
|
||||||
return StrtodBigInteger(result, decimals, length, decimalPosition, exp);
|
return StrtodBigInteger(result, decimals, dLen, dExp);
|
||||||
}
|
}
|
||||||
|
|
||||||
} // namespace internal
|
} // namespace internal
|
||||||
|
|
|
@ -1,6 +1,6 @@
|
||||||
// Tencent is pleased to support the open source community by making RapidJSON available.
|
// 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.
|
// Copyright (C) 2015 THL A29 Limited, a Tencent company, and Milo Yip.
|
||||||
//
|
//
|
||||||
// Licensed under the MIT License (the "License"); you may not use this file except
|
// 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
|
// in compliance with the License. You may obtain a copy of the License at
|
||||||
|
|
|
@ -1,6 +1,6 @@
|
||||||
// Tencent is pleased to support the open source community by making RapidJSON available.
|
// 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.
|
// Copyright (C) 2015 THL A29 Limited, a Tencent company, and Milo Yip.
|
||||||
//
|
//
|
||||||
// Licensed under the MIT License (the "License"); you may not use this file except
|
// 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
|
// in compliance with the License. You may obtain a copy of the License at
|
||||||
|
@ -17,13 +17,12 @@
|
||||||
|
|
||||||
#include "stream.h"
|
#include "stream.h"
|
||||||
#include <iosfwd>
|
#include <iosfwd>
|
||||||
|
#include <ios>
|
||||||
|
|
||||||
#ifdef __clang__
|
#ifdef __clang__
|
||||||
RAPIDJSON_DIAG_PUSH
|
RAPIDJSON_DIAG_PUSH
|
||||||
RAPIDJSON_DIAG_OFF(padded)
|
RAPIDJSON_DIAG_OFF(padded)
|
||||||
#endif
|
#elif defined(_MSC_VER)
|
||||||
|
|
||||||
#ifdef _MSC_VER
|
|
||||||
RAPIDJSON_DIAG_PUSH
|
RAPIDJSON_DIAG_PUSH
|
||||||
RAPIDJSON_DIAG_OFF(4351) // new behavior: elements of array 'array' will be default initialized
|
RAPIDJSON_DIAG_OFF(4351) // new behavior: elements of array 'array' will be default initialized
|
||||||
#endif
|
#endif
|
||||||
|
@ -50,57 +49,71 @@ template <typename StreamType>
|
||||||
class BasicIStreamWrapper {
|
class BasicIStreamWrapper {
|
||||||
public:
|
public:
|
||||||
typedef typename StreamType::char_type Ch;
|
typedef typename StreamType::char_type Ch;
|
||||||
BasicIStreamWrapper(StreamType& stream) : stream_(stream), count_(), peekBuffer_() {}
|
|
||||||
|
|
||||||
Ch Peek() const {
|
//! Constructor.
|
||||||
typename StreamType::int_type c = stream_.peek();
|
/*!
|
||||||
return RAPIDJSON_LIKELY(c != StreamType::traits_type::eof()) ? static_cast<Ch>(c) : static_cast<Ch>('\0');
|
\param stream stream opened for read.
|
||||||
|
*/
|
||||||
|
BasicIStreamWrapper(StreamType &stream) : stream_(stream), buffer_(peekBuffer_), bufferSize_(4), bufferLast_(0), current_(buffer_), readCount_(0), count_(0), eof_(false) {
|
||||||
|
Read();
|
||||||
}
|
}
|
||||||
|
|
||||||
Ch Take() {
|
//! Constructor.
|
||||||
typename StreamType::int_type c = stream_.get();
|
/*!
|
||||||
if (RAPIDJSON_LIKELY(c != StreamType::traits_type::eof())) {
|
\param stream stream opened for read.
|
||||||
count_++;
|
\param buffer user-supplied buffer.
|
||||||
return static_cast<Ch>(c);
|
\param bufferSize size of buffer in bytes. Must >=4 bytes.
|
||||||
}
|
*/
|
||||||
else
|
BasicIStreamWrapper(StreamType &stream, char* buffer, size_t bufferSize) : stream_(stream), buffer_(buffer), bufferSize_(bufferSize), bufferLast_(0), current_(buffer_), readCount_(0), count_(0), eof_(false) {
|
||||||
return '\0';
|
RAPIDJSON_ASSERT(bufferSize >= 4);
|
||||||
|
Read();
|
||||||
}
|
}
|
||||||
|
|
||||||
// tellg() may return -1 when failed. So we count by ourself.
|
Ch Peek() const { return *current_; }
|
||||||
size_t Tell() const { return count_; }
|
Ch Take() { Ch c = *current_; Read(); return c; }
|
||||||
|
size_t Tell() const { return count_ + static_cast<size_t>(current_ - buffer_); }
|
||||||
|
|
||||||
Ch* PutBegin() { RAPIDJSON_ASSERT(false); return 0; }
|
// Not implemented
|
||||||
void Put(Ch) { RAPIDJSON_ASSERT(false); }
|
void Put(Ch) { RAPIDJSON_ASSERT(false); }
|
||||||
void Flush() { RAPIDJSON_ASSERT(false); }
|
void Flush() { RAPIDJSON_ASSERT(false); }
|
||||||
|
Ch* PutBegin() { RAPIDJSON_ASSERT(false); return 0; }
|
||||||
size_t PutEnd(Ch*) { RAPIDJSON_ASSERT(false); return 0; }
|
size_t PutEnd(Ch*) { RAPIDJSON_ASSERT(false); return 0; }
|
||||||
|
|
||||||
// For encoding detection only.
|
// For encoding detection only.
|
||||||
const Ch* Peek4() const {
|
const Ch* Peek4() const {
|
||||||
RAPIDJSON_ASSERT(sizeof(Ch) == 1); // Only usable for byte stream.
|
return (current_ + 4 - !eof_ <= bufferLast_) ? current_ : 0;
|
||||||
int i;
|
|
||||||
bool hasError = false;
|
|
||||||
for (i = 0; i < 4; ++i) {
|
|
||||||
typename StreamType::int_type c = stream_.get();
|
|
||||||
if (c == StreamType::traits_type::eof()) {
|
|
||||||
hasError = true;
|
|
||||||
stream_.clear();
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
peekBuffer_[i] = static_cast<Ch>(c);
|
|
||||||
}
|
|
||||||
for (--i; i >= 0; --i)
|
|
||||||
stream_.putback(peekBuffer_[i]);
|
|
||||||
return !hasError ? peekBuffer_ : 0;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
private:
|
private:
|
||||||
|
BasicIStreamWrapper();
|
||||||
BasicIStreamWrapper(const BasicIStreamWrapper&);
|
BasicIStreamWrapper(const BasicIStreamWrapper&);
|
||||||
BasicIStreamWrapper& operator=(const BasicIStreamWrapper&);
|
BasicIStreamWrapper& operator=(const BasicIStreamWrapper&);
|
||||||
|
|
||||||
StreamType& stream_;
|
void Read() {
|
||||||
size_t count_; //!< Number of characters read. Note:
|
if (current_ < bufferLast_)
|
||||||
mutable Ch peekBuffer_[4];
|
++current_;
|
||||||
|
else if (!eof_) {
|
||||||
|
count_ += readCount_;
|
||||||
|
readCount_ = bufferSize_;
|
||||||
|
bufferLast_ = buffer_ + readCount_ - 1;
|
||||||
|
current_ = buffer_;
|
||||||
|
|
||||||
|
if (!stream_.read(buffer_, static_cast<std::streamsize>(bufferSize_))) {
|
||||||
|
readCount_ = static_cast<size_t>(stream_.gcount());
|
||||||
|
*(bufferLast_ = buffer_ + readCount_) = '\0';
|
||||||
|
eof_ = true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
StreamType &stream_;
|
||||||
|
Ch peekBuffer_[4], *buffer_;
|
||||||
|
size_t bufferSize_;
|
||||||
|
Ch *bufferLast_;
|
||||||
|
Ch *current_;
|
||||||
|
size_t readCount_;
|
||||||
|
size_t count_; //!< Number of characters read
|
||||||
|
bool eof_;
|
||||||
};
|
};
|
||||||
|
|
||||||
typedef BasicIStreamWrapper<std::istream> IStreamWrapper;
|
typedef BasicIStreamWrapper<std::istream> IStreamWrapper;
|
||||||
|
|
|
@ -1,6 +1,6 @@
|
||||||
// Tencent is pleased to support the open source community by making RapidJSON available.
|
// 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.
|
// Copyright (C) 2015 THL A29 Limited, a Tencent company, and Milo Yip.
|
||||||
//
|
//
|
||||||
// Licensed under the MIT License (the "License"); you may not use this file except
|
// 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
|
// in compliance with the License. You may obtain a copy of the License at
|
||||||
|
|
|
@ -1,6 +1,6 @@
|
||||||
// Tencent is pleased to support the open source community by making RapidJSON available.
|
// 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.
|
// Copyright (C) 2015 THL A29 Limited, a Tencent company, and Milo Yip.
|
||||||
//
|
//
|
||||||
// Licensed under the MIT License (the "License"); you may not use this file except
|
// 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
|
// in compliance with the License. You may obtain a copy of the License at
|
||||||
|
|
|
@ -1,6 +1,6 @@
|
||||||
// Tencent is pleased to support the open source community by making RapidJSON available.
|
// 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.
|
// Copyright (C) 2015 THL A29 Limited, a Tencent company, and Milo Yip.
|
||||||
//
|
//
|
||||||
// Licensed under the MIT License (the "License"); you may not use this file except
|
// 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
|
// in compliance with the License. You may obtain a copy of the License at
|
||||||
|
|
|
@ -1,6 +1,6 @@
|
||||||
// Tencent is pleased to support the open source community by making RapidJSON available.
|
// 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.
|
// Copyright (C) 2015 THL A29 Limited, a Tencent company, and Milo Yip.
|
||||||
//
|
//
|
||||||
// Licensed under the MIT License (the "License"); you may not use this file except
|
// 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
|
// in compliance with the License. You may obtain a copy of the License at
|
||||||
|
@ -21,9 +21,7 @@
|
||||||
#ifdef __clang__
|
#ifdef __clang__
|
||||||
RAPIDJSON_DIAG_PUSH
|
RAPIDJSON_DIAG_PUSH
|
||||||
RAPIDJSON_DIAG_OFF(switch-enum)
|
RAPIDJSON_DIAG_OFF(switch-enum)
|
||||||
#endif
|
#elif defined(_MSC_VER)
|
||||||
|
|
||||||
#ifdef _MSC_VER
|
|
||||||
RAPIDJSON_DIAG_PUSH
|
RAPIDJSON_DIAG_PUSH
|
||||||
RAPIDJSON_DIAG_OFF(4512) // assignment operator could not be generated
|
RAPIDJSON_DIAG_OFF(4512) // assignment operator could not be generated
|
||||||
#endif
|
#endif
|
||||||
|
@ -165,7 +163,12 @@ public:
|
||||||
GenericPointer(const Token* tokens, size_t tokenCount) : allocator_(), ownAllocator_(), nameBuffer_(), tokens_(const_cast<Token*>(tokens)), tokenCount_(tokenCount), parseErrorOffset_(), parseErrorCode_(kPointerParseErrorNone) {}
|
GenericPointer(const Token* tokens, size_t tokenCount) : allocator_(), ownAllocator_(), nameBuffer_(), tokens_(const_cast<Token*>(tokens)), tokenCount_(tokenCount), parseErrorOffset_(), parseErrorCode_(kPointerParseErrorNone) {}
|
||||||
|
|
||||||
//! Copy constructor.
|
//! Copy constructor.
|
||||||
GenericPointer(const GenericPointer& rhs, Allocator* allocator = 0) : allocator_(allocator), ownAllocator_(), nameBuffer_(), tokens_(), tokenCount_(), parseErrorOffset_(), parseErrorCode_(kPointerParseErrorNone) {
|
GenericPointer(const GenericPointer& rhs) : allocator_(rhs.allocator_), ownAllocator_(), nameBuffer_(), tokens_(), tokenCount_(), parseErrorOffset_(), parseErrorCode_(kPointerParseErrorNone) {
|
||||||
|
*this = rhs;
|
||||||
|
}
|
||||||
|
|
||||||
|
//! Copy constructor.
|
||||||
|
GenericPointer(const GenericPointer& rhs, Allocator* allocator) : allocator_(allocator), ownAllocator_(), nameBuffer_(), tokens_(), tokenCount_(), parseErrorOffset_(), parseErrorCode_(kPointerParseErrorNone) {
|
||||||
*this = rhs;
|
*this = rhs;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -197,6 +200,36 @@ public:
|
||||||
return *this;
|
return *this;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
//! Swap the content of this pointer with an other.
|
||||||
|
/*!
|
||||||
|
\param other The pointer to swap with.
|
||||||
|
\note Constant complexity.
|
||||||
|
*/
|
||||||
|
GenericPointer& Swap(GenericPointer& other) RAPIDJSON_NOEXCEPT {
|
||||||
|
internal::Swap(allocator_, other.allocator_);
|
||||||
|
internal::Swap(ownAllocator_, other.ownAllocator_);
|
||||||
|
internal::Swap(nameBuffer_, other.nameBuffer_);
|
||||||
|
internal::Swap(tokens_, other.tokens_);
|
||||||
|
internal::Swap(tokenCount_, other.tokenCount_);
|
||||||
|
internal::Swap(parseErrorOffset_, other.parseErrorOffset_);
|
||||||
|
internal::Swap(parseErrorCode_, other.parseErrorCode_);
|
||||||
|
return *this;
|
||||||
|
}
|
||||||
|
|
||||||
|
//! free-standing swap function helper
|
||||||
|
/*!
|
||||||
|
Helper function to enable support for common swap implementation pattern based on \c std::swap:
|
||||||
|
\code
|
||||||
|
void swap(MyClass& a, MyClass& b) {
|
||||||
|
using std::swap;
|
||||||
|
swap(a.pointer, b.pointer);
|
||||||
|
// ...
|
||||||
|
}
|
||||||
|
\endcode
|
||||||
|
\see Swap()
|
||||||
|
*/
|
||||||
|
friend inline void swap(GenericPointer& a, GenericPointer& b) RAPIDJSON_NOEXCEPT { a.Swap(b); }
|
||||||
|
|
||||||
//@}
|
//@}
|
||||||
|
|
||||||
//!@name Append token
|
//!@name Append token
|
||||||
|
@ -353,6 +386,33 @@ public:
|
||||||
*/
|
*/
|
||||||
bool operator!=(const GenericPointer& rhs) const { return !(*this == rhs); }
|
bool operator!=(const GenericPointer& rhs) const { return !(*this == rhs); }
|
||||||
|
|
||||||
|
//! Less than operator.
|
||||||
|
/*!
|
||||||
|
\note Invalid pointers are always greater than valid ones.
|
||||||
|
*/
|
||||||
|
bool operator<(const GenericPointer& rhs) const {
|
||||||
|
if (!IsValid())
|
||||||
|
return false;
|
||||||
|
if (!rhs.IsValid())
|
||||||
|
return true;
|
||||||
|
|
||||||
|
if (tokenCount_ != rhs.tokenCount_)
|
||||||
|
return tokenCount_ < rhs.tokenCount_;
|
||||||
|
|
||||||
|
for (size_t i = 0; i < tokenCount_; i++) {
|
||||||
|
if (tokens_[i].index != rhs.tokens_[i].index)
|
||||||
|
return tokens_[i].index < rhs.tokens_[i].index;
|
||||||
|
|
||||||
|
if (tokens_[i].length != rhs.tokens_[i].length)
|
||||||
|
return tokens_[i].length < rhs.tokens_[i].length;
|
||||||
|
|
||||||
|
if (int cmp = std::memcmp(tokens_[i].name, rhs.tokens_[i].name, sizeof(Ch) * tokens_[i].length))
|
||||||
|
return cmp < 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
//@}
|
//@}
|
||||||
|
|
||||||
//!@name Stringify
|
//!@name Stringify
|
||||||
|
@ -428,10 +488,11 @@ public:
|
||||||
v = &((*v)[t->index]);
|
v = &((*v)[t->index]);
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
typename ValueType::MemberIterator m = v->FindMember(GenericStringRef<Ch>(t->name, t->length));
|
typename ValueType::MemberIterator m = v->FindMember(GenericValue<EncodingType>(GenericStringRef<Ch>(t->name, t->length)));
|
||||||
if (m == v->MemberEnd()) {
|
if (m == v->MemberEnd()) {
|
||||||
v->AddMember(ValueType(t->name, t->length, allocator).Move(), ValueType().Move(), allocator);
|
v->AddMember(ValueType(t->name, t->length, allocator).Move(), ValueType().Move(), allocator);
|
||||||
v = &(--v->MemberEnd())->value; // Assumes AddMember() appends at the end
|
m = v->MemberEnd();
|
||||||
|
v = &(--m)->value; // Assumes AddMember() appends at the end
|
||||||
exist = false;
|
exist = false;
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
|
@ -483,7 +544,7 @@ public:
|
||||||
switch (v->GetType()) {
|
switch (v->GetType()) {
|
||||||
case kObjectType:
|
case kObjectType:
|
||||||
{
|
{
|
||||||
typename ValueType::MemberIterator m = v->FindMember(GenericStringRef<Ch>(t->name, t->length));
|
typename ValueType::MemberIterator m = v->FindMember(GenericValue<EncodingType>(GenericStringRef<Ch>(t->name, t->length)));
|
||||||
if (m == v->MemberEnd())
|
if (m == v->MemberEnd())
|
||||||
break;
|
break;
|
||||||
v = &m->value;
|
v = &m->value;
|
||||||
|
@ -532,14 +593,14 @@ public:
|
||||||
*/
|
*/
|
||||||
ValueType& GetWithDefault(ValueType& root, const ValueType& defaultValue, typename ValueType::AllocatorType& allocator) const {
|
ValueType& GetWithDefault(ValueType& root, const ValueType& defaultValue, typename ValueType::AllocatorType& allocator) const {
|
||||||
bool alreadyExist;
|
bool alreadyExist;
|
||||||
Value& v = Create(root, allocator, &alreadyExist);
|
ValueType& v = Create(root, allocator, &alreadyExist);
|
||||||
return alreadyExist ? v : v.CopyFrom(defaultValue, allocator);
|
return alreadyExist ? v : v.CopyFrom(defaultValue, allocator);
|
||||||
}
|
}
|
||||||
|
|
||||||
//! Query a value in a subtree with default null-terminated string.
|
//! Query a value in a subtree with default null-terminated string.
|
||||||
ValueType& GetWithDefault(ValueType& root, const Ch* defaultValue, typename ValueType::AllocatorType& allocator) const {
|
ValueType& GetWithDefault(ValueType& root, const Ch* defaultValue, typename ValueType::AllocatorType& allocator) const {
|
||||||
bool alreadyExist;
|
bool alreadyExist;
|
||||||
Value& v = Create(root, allocator, &alreadyExist);
|
ValueType& v = Create(root, allocator, &alreadyExist);
|
||||||
return alreadyExist ? v : v.SetString(defaultValue, allocator);
|
return alreadyExist ? v : v.SetString(defaultValue, allocator);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -547,7 +608,7 @@ public:
|
||||||
//! Query a value in a subtree with default std::basic_string.
|
//! Query a value in a subtree with default std::basic_string.
|
||||||
ValueType& GetWithDefault(ValueType& root, const std::basic_string<Ch>& defaultValue, typename ValueType::AllocatorType& allocator) const {
|
ValueType& GetWithDefault(ValueType& root, const std::basic_string<Ch>& defaultValue, typename ValueType::AllocatorType& allocator) const {
|
||||||
bool alreadyExist;
|
bool alreadyExist;
|
||||||
Value& v = Create(root, allocator, &alreadyExist);
|
ValueType& v = Create(root, allocator, &alreadyExist);
|
||||||
return alreadyExist ? v : v.SetString(defaultValue, allocator);
|
return alreadyExist ? v : v.SetString(defaultValue, allocator);
|
||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
|
@ -719,7 +780,7 @@ public:
|
||||||
switch (v->GetType()) {
|
switch (v->GetType()) {
|
||||||
case kObjectType:
|
case kObjectType:
|
||||||
{
|
{
|
||||||
typename ValueType::MemberIterator m = v->FindMember(GenericStringRef<Ch>(t->name, t->length));
|
typename ValueType::MemberIterator m = v->FindMember(GenericValue<EncodingType>(GenericStringRef<Ch>(t->name, t->length)));
|
||||||
if (m == v->MemberEnd())
|
if (m == v->MemberEnd())
|
||||||
return false;
|
return false;
|
||||||
v = &m->value;
|
v = &m->value;
|
||||||
|
@ -1347,11 +1408,7 @@ bool EraseValueByPointer(T& root, const CharType(&source)[N]) {
|
||||||
|
|
||||||
RAPIDJSON_NAMESPACE_END
|
RAPIDJSON_NAMESPACE_END
|
||||||
|
|
||||||
#ifdef __clang__
|
#if defined(__clang__) || defined(_MSC_VER)
|
||||||
RAPIDJSON_DIAG_POP
|
|
||||||
#endif
|
|
||||||
|
|
||||||
#ifdef _MSC_VER
|
|
||||||
RAPIDJSON_DIAG_POP
|
RAPIDJSON_DIAG_POP
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
|
|
@ -1,6 +1,6 @@
|
||||||
// Tencent is pleased to support the open source community by making RapidJSON available.
|
// 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.
|
// Copyright (C) 2015 THL A29 Limited, a Tencent company, and Milo Yip.
|
||||||
//
|
//
|
||||||
// Licensed under the MIT License (the "License"); you may not use this file except
|
// 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
|
// in compliance with the License. You may obtain a copy of the License at
|
||||||
|
@ -39,7 +39,7 @@ enum PrettyFormatOptions {
|
||||||
|
|
||||||
//! Writer with indentation and spacing.
|
//! Writer with indentation and spacing.
|
||||||
/*!
|
/*!
|
||||||
\tparam OutputStream Type of ouptut os.
|
\tparam OutputStream Type of output os.
|
||||||
\tparam SourceEncoding Encoding of source string.
|
\tparam SourceEncoding Encoding of source string.
|
||||||
\tparam TargetEncoding Encoding of output stream.
|
\tparam TargetEncoding Encoding of output stream.
|
||||||
\tparam StackAllocator Type of allocator for allocating memory of stack.
|
\tparam StackAllocator Type of allocator for allocating memory of stack.
|
||||||
|
@ -60,7 +60,7 @@ public:
|
||||||
|
|
||||||
|
|
||||||
explicit PrettyWriter(StackAllocator* allocator = 0, size_t levelDepth = Base::kDefaultLevelDepth) :
|
explicit PrettyWriter(StackAllocator* allocator = 0, size_t levelDepth = Base::kDefaultLevelDepth) :
|
||||||
Base(allocator, levelDepth), indentChar_(' '), indentCharCount_(4) {}
|
Base(allocator, levelDepth), indentChar_(' '), indentCharCount_(4), formatOptions_(kFormatDefault) {}
|
||||||
|
|
||||||
#if RAPIDJSON_HAS_CXX11_RVALUE_REFS
|
#if RAPIDJSON_HAS_CXX11_RVALUE_REFS
|
||||||
PrettyWriter(PrettyWriter&& rhs) :
|
PrettyWriter(PrettyWriter&& rhs) :
|
||||||
|
@ -92,26 +92,26 @@ public:
|
||||||
*/
|
*/
|
||||||
//@{
|
//@{
|
||||||
|
|
||||||
bool Null() { PrettyPrefix(kNullType); return Base::WriteNull(); }
|
bool Null() { PrettyPrefix(kNullType); return Base::EndValue(Base::WriteNull()); }
|
||||||
bool Bool(bool b) { PrettyPrefix(b ? kTrueType : kFalseType); return Base::WriteBool(b); }
|
bool Bool(bool b) { PrettyPrefix(b ? kTrueType : kFalseType); return Base::EndValue(Base::WriteBool(b)); }
|
||||||
bool Int(int i) { PrettyPrefix(kNumberType); return Base::WriteInt(i); }
|
bool Int(int i) { PrettyPrefix(kNumberType); return Base::EndValue(Base::WriteInt(i)); }
|
||||||
bool Uint(unsigned u) { PrettyPrefix(kNumberType); return Base::WriteUint(u); }
|
bool Uint(unsigned u) { PrettyPrefix(kNumberType); return Base::EndValue(Base::WriteUint(u)); }
|
||||||
bool Int64(int64_t i64) { PrettyPrefix(kNumberType); return Base::WriteInt64(i64); }
|
bool Int64(int64_t i64) { PrettyPrefix(kNumberType); return Base::EndValue(Base::WriteInt64(i64)); }
|
||||||
bool Uint64(uint64_t u64) { PrettyPrefix(kNumberType); return Base::WriteUint64(u64); }
|
bool Uint64(uint64_t u64) { PrettyPrefix(kNumberType); return Base::EndValue(Base::WriteUint64(u64)); }
|
||||||
bool Double(double d) { PrettyPrefix(kNumberType); return Base::WriteDouble(d); }
|
bool Double(double d) { PrettyPrefix(kNumberType); return Base::EndValue(Base::WriteDouble(d)); }
|
||||||
|
|
||||||
bool RawNumber(const Ch* str, SizeType length, bool copy = false) {
|
bool RawNumber(const Ch* str, SizeType length, bool copy = false) {
|
||||||
RAPIDJSON_ASSERT(str != 0);
|
RAPIDJSON_ASSERT(str != 0);
|
||||||
(void)copy;
|
(void)copy;
|
||||||
PrettyPrefix(kNumberType);
|
PrettyPrefix(kNumberType);
|
||||||
return Base::WriteString(str, length);
|
return Base::EndValue(Base::WriteString(str, length));
|
||||||
}
|
}
|
||||||
|
|
||||||
bool String(const Ch* str, SizeType length, bool copy = false) {
|
bool String(const Ch* str, SizeType length, bool copy = false) {
|
||||||
RAPIDJSON_ASSERT(str != 0);
|
RAPIDJSON_ASSERT(str != 0);
|
||||||
(void)copy;
|
(void)copy;
|
||||||
PrettyPrefix(kStringType);
|
PrettyPrefix(kStringType);
|
||||||
return Base::WriteString(str, length);
|
return Base::EndValue(Base::WriteString(str, length));
|
||||||
}
|
}
|
||||||
|
|
||||||
#if RAPIDJSON_HAS_STDSTRING
|
#if RAPIDJSON_HAS_STDSTRING
|
||||||
|
@ -146,7 +146,7 @@ public:
|
||||||
Base::os_->Put('\n');
|
Base::os_->Put('\n');
|
||||||
WriteIndent();
|
WriteIndent();
|
||||||
}
|
}
|
||||||
bool ret = Base::WriteEndObject();
|
bool ret = Base::EndValue(Base::WriteEndObject());
|
||||||
(void)ret;
|
(void)ret;
|
||||||
RAPIDJSON_ASSERT(ret == true);
|
RAPIDJSON_ASSERT(ret == true);
|
||||||
if (Base::level_stack_.Empty()) // end of json text
|
if (Base::level_stack_.Empty()) // end of json text
|
||||||
|
@ -170,7 +170,7 @@ public:
|
||||||
Base::os_->Put('\n');
|
Base::os_->Put('\n');
|
||||||
WriteIndent();
|
WriteIndent();
|
||||||
}
|
}
|
||||||
bool ret = Base::WriteEndArray();
|
bool ret = Base::EndValue(Base::WriteEndArray());
|
||||||
(void)ret;
|
(void)ret;
|
||||||
RAPIDJSON_ASSERT(ret == true);
|
RAPIDJSON_ASSERT(ret == true);
|
||||||
if (Base::level_stack_.Empty()) // end of json text
|
if (Base::level_stack_.Empty()) // end of json text
|
||||||
|
@ -201,7 +201,7 @@ public:
|
||||||
bool RawValue(const Ch* json, size_t length, Type type) {
|
bool RawValue(const Ch* json, size_t length, Type type) {
|
||||||
RAPIDJSON_ASSERT(json != 0);
|
RAPIDJSON_ASSERT(json != 0);
|
||||||
PrettyPrefix(type);
|
PrettyPrefix(type);
|
||||||
return Base::WriteRawValue(json, length);
|
return Base::EndValue(Base::WriteRawValue(json, length));
|
||||||
}
|
}
|
||||||
|
|
||||||
protected:
|
protected:
|
||||||
|
|
|
@ -1,6 +1,6 @@
|
||||||
// Tencent is pleased to support the open source community by making RapidJSON available.
|
// 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.
|
// Copyright (C) 2015 THL A29 Limited, a Tencent company, and Milo Yip.
|
||||||
//
|
//
|
||||||
// Licensed under the MIT License (the "License"); you may not use this file except
|
// 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
|
// in compliance with the License. You may obtain a copy of the License at
|
||||||
|
@ -26,7 +26,7 @@
|
||||||
|
|
||||||
Some RapidJSON features are configurable to adapt the library to a wide
|
Some RapidJSON features are configurable to adapt the library to a wide
|
||||||
variety of platforms, environments and usage scenarios. Most of the
|
variety of platforms, environments and usage scenarios. Most of the
|
||||||
features can be configured in terms of overriden or predefined
|
features can be configured in terms of overridden or predefined
|
||||||
preprocessor macros at compile-time.
|
preprocessor macros at compile-time.
|
||||||
|
|
||||||
Some additional customization is available in the \ref RAPIDJSON_ERRORS APIs.
|
Some additional customization is available in the \ref RAPIDJSON_ERRORS APIs.
|
||||||
|
@ -219,7 +219,7 @@
|
||||||
# elif __BYTE_ORDER__ == __ORDER_BIG_ENDIAN__
|
# elif __BYTE_ORDER__ == __ORDER_BIG_ENDIAN__
|
||||||
# define RAPIDJSON_ENDIAN RAPIDJSON_BIGENDIAN
|
# define RAPIDJSON_ENDIAN RAPIDJSON_BIGENDIAN
|
||||||
# else
|
# else
|
||||||
# error Unknown machine endianess detected. User needs to define RAPIDJSON_ENDIAN.
|
# error Unknown machine endianness detected. User needs to define RAPIDJSON_ENDIAN.
|
||||||
# endif // __BYTE_ORDER__
|
# endif // __BYTE_ORDER__
|
||||||
// Detect with GLIBC's endian.h
|
// Detect with GLIBC's endian.h
|
||||||
# elif defined(__GLIBC__)
|
# elif defined(__GLIBC__)
|
||||||
|
@ -229,7 +229,7 @@
|
||||||
# elif (__BYTE_ORDER == __BIG_ENDIAN)
|
# elif (__BYTE_ORDER == __BIG_ENDIAN)
|
||||||
# define RAPIDJSON_ENDIAN RAPIDJSON_BIGENDIAN
|
# define RAPIDJSON_ENDIAN RAPIDJSON_BIGENDIAN
|
||||||
# else
|
# else
|
||||||
# error Unknown machine endianess detected. User needs to define RAPIDJSON_ENDIAN.
|
# error Unknown machine endianness detected. User needs to define RAPIDJSON_ENDIAN.
|
||||||
# endif // __GLIBC__
|
# endif // __GLIBC__
|
||||||
// Detect with _LITTLE_ENDIAN and _BIG_ENDIAN macro
|
// Detect with _LITTLE_ENDIAN and _BIG_ENDIAN macro
|
||||||
# elif defined(_LITTLE_ENDIAN) && !defined(_BIG_ENDIAN)
|
# elif defined(_LITTLE_ENDIAN) && !defined(_BIG_ENDIAN)
|
||||||
|
@ -246,7 +246,7 @@
|
||||||
# elif defined(RAPIDJSON_DOXYGEN_RUNNING)
|
# elif defined(RAPIDJSON_DOXYGEN_RUNNING)
|
||||||
# define RAPIDJSON_ENDIAN
|
# define RAPIDJSON_ENDIAN
|
||||||
# else
|
# else
|
||||||
# error Unknown machine endianess detected. User needs to define RAPIDJSON_ENDIAN.
|
# error Unknown machine endianness detected. User needs to define RAPIDJSON_ENDIAN.
|
||||||
# endif
|
# endif
|
||||||
#endif // RAPIDJSON_ENDIAN
|
#endif // RAPIDJSON_ENDIAN
|
||||||
|
|
||||||
|
@ -269,16 +269,11 @@
|
||||||
/*! \ingroup RAPIDJSON_CONFIG
|
/*! \ingroup RAPIDJSON_CONFIG
|
||||||
\param x pointer to align
|
\param x pointer to align
|
||||||
|
|
||||||
Some machines require strict data alignment. Currently the default uses 4 bytes
|
Some machines require strict data alignment. The default is 8 bytes.
|
||||||
alignment on 32-bit platforms and 8 bytes alignment for 64-bit platforms.
|
|
||||||
User can customize by defining the RAPIDJSON_ALIGN function macro.
|
User can customize by defining the RAPIDJSON_ALIGN function macro.
|
||||||
*/
|
*/
|
||||||
#ifndef RAPIDJSON_ALIGN
|
#ifndef RAPIDJSON_ALIGN
|
||||||
#if RAPIDJSON_64BIT == 1
|
#define RAPIDJSON_ALIGN(x) (((x) + static_cast<size_t>(7u)) & ~static_cast<size_t>(7u))
|
||||||
#define RAPIDJSON_ALIGN(x) (((x) + static_cast<uint64_t>(7u)) & ~static_cast<uint64_t>(7u))
|
|
||||||
#else
|
|
||||||
#define RAPIDJSON_ALIGN(x) (((x) + 3u) & ~3u)
|
|
||||||
#endif
|
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
///////////////////////////////////////////////////////////////////////////////
|
///////////////////////////////////////////////////////////////////////////////
|
||||||
|
@ -433,7 +428,7 @@ template <> struct STATIC_ASSERTION_FAILURE<true> { enum { value = 1 }; };
|
||||||
template <size_t x> struct StaticAssertTest {};
|
template <size_t x> struct StaticAssertTest {};
|
||||||
RAPIDJSON_NAMESPACE_END
|
RAPIDJSON_NAMESPACE_END
|
||||||
|
|
||||||
#if defined(__GNUC__)
|
#if defined(__GNUC__) || defined(__clang__)
|
||||||
#define RAPIDJSON_STATIC_ASSERT_UNUSED_ATTRIBUTE __attribute__((unused))
|
#define RAPIDJSON_STATIC_ASSERT_UNUSED_ATTRIBUTE __attribute__((unused))
|
||||||
#else
|
#else
|
||||||
#define RAPIDJSON_STATIC_ASSERT_UNUSED_ATTRIBUTE
|
#define RAPIDJSON_STATIC_ASSERT_UNUSED_ATTRIBUTE
|
||||||
|
@ -495,6 +490,12 @@ RAPIDJSON_NAMESPACE_END
|
||||||
#define RAPIDJSON_VERSION_CODE(x,y,z) \
|
#define RAPIDJSON_VERSION_CODE(x,y,z) \
|
||||||
(((x)*100000) + ((y)*100) + (z))
|
(((x)*100000) + ((y)*100) + (z))
|
||||||
|
|
||||||
|
#if defined(__has_builtin)
|
||||||
|
#define RAPIDJSON_HAS_BUILTIN(x) __has_builtin(x)
|
||||||
|
#else
|
||||||
|
#define RAPIDJSON_HAS_BUILTIN(x) 0
|
||||||
|
#endif
|
||||||
|
|
||||||
///////////////////////////////////////////////////////////////////////////////
|
///////////////////////////////////////////////////////////////////////////////
|
||||||
// RAPIDJSON_DIAG_PUSH/POP, RAPIDJSON_DIAG_OFF
|
// RAPIDJSON_DIAG_PUSH/POP, RAPIDJSON_DIAG_OFF
|
||||||
|
|
||||||
|
@ -543,13 +544,14 @@ RAPIDJSON_NAMESPACE_END
|
||||||
#ifndef RAPIDJSON_HAS_CXX11_RVALUE_REFS
|
#ifndef RAPIDJSON_HAS_CXX11_RVALUE_REFS
|
||||||
#if defined(__clang__)
|
#if defined(__clang__)
|
||||||
#if __has_feature(cxx_rvalue_references) && \
|
#if __has_feature(cxx_rvalue_references) && \
|
||||||
(defined(_LIBCPP_VERSION) || defined(__GLIBCXX__) && __GLIBCXX__ >= 20080306)
|
(defined(_MSC_VER) || defined(_LIBCPP_VERSION) || defined(__GLIBCXX__) && __GLIBCXX__ >= 20080306)
|
||||||
#define RAPIDJSON_HAS_CXX11_RVALUE_REFS 1
|
#define RAPIDJSON_HAS_CXX11_RVALUE_REFS 1
|
||||||
#else
|
#else
|
||||||
#define RAPIDJSON_HAS_CXX11_RVALUE_REFS 0
|
#define RAPIDJSON_HAS_CXX11_RVALUE_REFS 0
|
||||||
#endif
|
#endif
|
||||||
#elif (defined(RAPIDJSON_GNUC) && (RAPIDJSON_GNUC >= RAPIDJSON_VERSION_CODE(4,3,0)) && defined(__GXX_EXPERIMENTAL_CXX0X__)) || \
|
#elif (defined(RAPIDJSON_GNUC) && (RAPIDJSON_GNUC >= RAPIDJSON_VERSION_CODE(4,3,0)) && defined(__GXX_EXPERIMENTAL_CXX0X__)) || \
|
||||||
(defined(_MSC_VER) && _MSC_VER >= 1600)
|
(defined(_MSC_VER) && _MSC_VER >= 1600) || \
|
||||||
|
(defined(__SUNPRO_CC) && __SUNPRO_CC >= 0x5140 && defined(__GXX_EXPERIMENTAL_CXX0X__))
|
||||||
|
|
||||||
#define RAPIDJSON_HAS_CXX11_RVALUE_REFS 1
|
#define RAPIDJSON_HAS_CXX11_RVALUE_REFS 1
|
||||||
#else
|
#else
|
||||||
|
@ -560,8 +562,9 @@ RAPIDJSON_NAMESPACE_END
|
||||||
#ifndef RAPIDJSON_HAS_CXX11_NOEXCEPT
|
#ifndef RAPIDJSON_HAS_CXX11_NOEXCEPT
|
||||||
#if defined(__clang__)
|
#if defined(__clang__)
|
||||||
#define RAPIDJSON_HAS_CXX11_NOEXCEPT __has_feature(cxx_noexcept)
|
#define RAPIDJSON_HAS_CXX11_NOEXCEPT __has_feature(cxx_noexcept)
|
||||||
#elif (defined(RAPIDJSON_GNUC) && (RAPIDJSON_GNUC >= RAPIDJSON_VERSION_CODE(4,6,0)) && defined(__GXX_EXPERIMENTAL_CXX0X__))
|
#elif (defined(RAPIDJSON_GNUC) && (RAPIDJSON_GNUC >= RAPIDJSON_VERSION_CODE(4,6,0)) && defined(__GXX_EXPERIMENTAL_CXX0X__)) || \
|
||||||
// (defined(_MSC_VER) && _MSC_VER >= ????) // not yet supported
|
(defined(_MSC_VER) && _MSC_VER >= 1900) || \
|
||||||
|
(defined(__SUNPRO_CC) && __SUNPRO_CC >= 0x5140 && defined(__GXX_EXPERIMENTAL_CXX0X__))
|
||||||
#define RAPIDJSON_HAS_CXX11_NOEXCEPT 1
|
#define RAPIDJSON_HAS_CXX11_NOEXCEPT 1
|
||||||
#else
|
#else
|
||||||
#define RAPIDJSON_HAS_CXX11_NOEXCEPT 0
|
#define RAPIDJSON_HAS_CXX11_NOEXCEPT 0
|
||||||
|
@ -575,22 +578,83 @@ RAPIDJSON_NAMESPACE_END
|
||||||
|
|
||||||
// no automatic detection, yet
|
// no automatic detection, yet
|
||||||
#ifndef RAPIDJSON_HAS_CXX11_TYPETRAITS
|
#ifndef RAPIDJSON_HAS_CXX11_TYPETRAITS
|
||||||
|
#if (defined(_MSC_VER) && _MSC_VER >= 1700)
|
||||||
|
#define RAPIDJSON_HAS_CXX11_TYPETRAITS 1
|
||||||
|
#else
|
||||||
#define RAPIDJSON_HAS_CXX11_TYPETRAITS 0
|
#define RAPIDJSON_HAS_CXX11_TYPETRAITS 0
|
||||||
#endif
|
#endif
|
||||||
|
#endif
|
||||||
|
|
||||||
#ifndef RAPIDJSON_HAS_CXX11_RANGE_FOR
|
#ifndef RAPIDJSON_HAS_CXX11_RANGE_FOR
|
||||||
#if defined(__clang__)
|
#if defined(__clang__)
|
||||||
#define RAPIDJSON_HAS_CXX11_RANGE_FOR __has_feature(cxx_range_for)
|
#define RAPIDJSON_HAS_CXX11_RANGE_FOR __has_feature(cxx_range_for)
|
||||||
#elif (defined(RAPIDJSON_GNUC) && (RAPIDJSON_GNUC >= RAPIDJSON_VERSION_CODE(4,6,0)) && defined(__GXX_EXPERIMENTAL_CXX0X__)) || \
|
#elif (defined(RAPIDJSON_GNUC) && (RAPIDJSON_GNUC >= RAPIDJSON_VERSION_CODE(4,6,0)) && defined(__GXX_EXPERIMENTAL_CXX0X__)) || \
|
||||||
(defined(_MSC_VER) && _MSC_VER >= 1700)
|
(defined(_MSC_VER) && _MSC_VER >= 1700) || \
|
||||||
|
(defined(__SUNPRO_CC) && __SUNPRO_CC >= 0x5140 && defined(__GXX_EXPERIMENTAL_CXX0X__))
|
||||||
#define RAPIDJSON_HAS_CXX11_RANGE_FOR 1
|
#define RAPIDJSON_HAS_CXX11_RANGE_FOR 1
|
||||||
#else
|
#else
|
||||||
#define RAPIDJSON_HAS_CXX11_RANGE_FOR 0
|
#define RAPIDJSON_HAS_CXX11_RANGE_FOR 0
|
||||||
#endif
|
#endif
|
||||||
#endif // RAPIDJSON_HAS_CXX11_RANGE_FOR
|
#endif // RAPIDJSON_HAS_CXX11_RANGE_FOR
|
||||||
|
|
||||||
|
///////////////////////////////////////////////////////////////////////////////
|
||||||
|
// C++17 features
|
||||||
|
|
||||||
|
#if defined(__has_cpp_attribute)
|
||||||
|
# if __has_cpp_attribute(fallthrough)
|
||||||
|
# define RAPIDJSON_DELIBERATE_FALLTHROUGH [[fallthrough]]
|
||||||
|
# else
|
||||||
|
# define RAPIDJSON_DELIBERATE_FALLTHROUGH
|
||||||
|
# endif
|
||||||
|
#else
|
||||||
|
# define RAPIDJSON_DELIBERATE_FALLTHROUGH
|
||||||
|
#endif
|
||||||
|
|
||||||
//!@endcond
|
//!@endcond
|
||||||
|
|
||||||
|
//! Assertion (in non-throwing contexts).
|
||||||
|
/*! \ingroup RAPIDJSON_CONFIG
|
||||||
|
Some functions provide a \c noexcept guarantee, if the compiler supports it.
|
||||||
|
In these cases, the \ref RAPIDJSON_ASSERT macro cannot be overridden to
|
||||||
|
throw an exception. This macro adds a separate customization point for
|
||||||
|
such cases.
|
||||||
|
|
||||||
|
Defaults to C \c assert() (as \ref RAPIDJSON_ASSERT), if \c noexcept is
|
||||||
|
supported, and to \ref RAPIDJSON_ASSERT otherwise.
|
||||||
|
*/
|
||||||
|
|
||||||
|
///////////////////////////////////////////////////////////////////////////////
|
||||||
|
// RAPIDJSON_NOEXCEPT_ASSERT
|
||||||
|
|
||||||
|
#ifndef RAPIDJSON_NOEXCEPT_ASSERT
|
||||||
|
#ifdef RAPIDJSON_ASSERT_THROWS
|
||||||
|
#if RAPIDJSON_HAS_CXX11_NOEXCEPT
|
||||||
|
#define RAPIDJSON_NOEXCEPT_ASSERT(x)
|
||||||
|
#else
|
||||||
|
#include <cassert>
|
||||||
|
#define RAPIDJSON_NOEXCEPT_ASSERT(x) assert(x)
|
||||||
|
#endif // RAPIDJSON_HAS_CXX11_NOEXCEPT
|
||||||
|
#else
|
||||||
|
#define RAPIDJSON_NOEXCEPT_ASSERT(x) RAPIDJSON_ASSERT(x)
|
||||||
|
#endif // RAPIDJSON_ASSERT_THROWS
|
||||||
|
#endif // RAPIDJSON_NOEXCEPT_ASSERT
|
||||||
|
|
||||||
|
///////////////////////////////////////////////////////////////////////////////
|
||||||
|
// malloc/realloc/free
|
||||||
|
|
||||||
|
#ifndef RAPIDJSON_MALLOC
|
||||||
|
///! customization point for global \c malloc
|
||||||
|
#define RAPIDJSON_MALLOC(size) std::malloc(size)
|
||||||
|
#endif
|
||||||
|
#ifndef RAPIDJSON_REALLOC
|
||||||
|
///! customization point for global \c realloc
|
||||||
|
#define RAPIDJSON_REALLOC(ptr, new_size) std::realloc(ptr, new_size)
|
||||||
|
#endif
|
||||||
|
#ifndef RAPIDJSON_FREE
|
||||||
|
///! customization point for global \c free
|
||||||
|
#define RAPIDJSON_FREE(ptr) std::free(ptr)
|
||||||
|
#endif
|
||||||
|
|
||||||
///////////////////////////////////////////////////////////////////////////////
|
///////////////////////////////////////////////////////////////////////////////
|
||||||
// new/delete
|
// new/delete
|
||||||
|
|
||||||
|
|
|
@ -1,6 +1,6 @@
|
||||||
// Tencent is pleased to support the open source community by making RapidJSON available.
|
// 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.
|
// Copyright (C) 2015 THL A29 Limited, a Tencent company, and Milo Yip.
|
||||||
//
|
//
|
||||||
// Licensed under the MIT License (the "License"); you may not use this file except
|
// 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
|
// in compliance with the License. You may obtain a copy of the License at
|
||||||
|
@ -20,6 +20,7 @@
|
||||||
#include "allocators.h"
|
#include "allocators.h"
|
||||||
#include "stream.h"
|
#include "stream.h"
|
||||||
#include "encodedstream.h"
|
#include "encodedstream.h"
|
||||||
|
#include "internal/clzll.h"
|
||||||
#include "internal/meta.h"
|
#include "internal/meta.h"
|
||||||
#include "internal/stack.h"
|
#include "internal/stack.h"
|
||||||
#include "internal/strtod.h"
|
#include "internal/strtod.h"
|
||||||
|
@ -37,17 +38,15 @@
|
||||||
#include <arm_neon.h>
|
#include <arm_neon.h>
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
#if defined(_MSC_VER) && !defined(__clang__)
|
|
||||||
RAPIDJSON_DIAG_PUSH
|
|
||||||
RAPIDJSON_DIAG_OFF(4127) // conditional expression is constant
|
|
||||||
RAPIDJSON_DIAG_OFF(4702) // unreachable code
|
|
||||||
#endif
|
|
||||||
|
|
||||||
#ifdef __clang__
|
#ifdef __clang__
|
||||||
RAPIDJSON_DIAG_PUSH
|
RAPIDJSON_DIAG_PUSH
|
||||||
RAPIDJSON_DIAG_OFF(old-style-cast)
|
RAPIDJSON_DIAG_OFF(old-style-cast)
|
||||||
RAPIDJSON_DIAG_OFF(padded)
|
RAPIDJSON_DIAG_OFF(padded)
|
||||||
RAPIDJSON_DIAG_OFF(switch-enum)
|
RAPIDJSON_DIAG_OFF(switch-enum)
|
||||||
|
#elif defined(_MSC_VER)
|
||||||
|
RAPIDJSON_DIAG_PUSH
|
||||||
|
RAPIDJSON_DIAG_OFF(4127) // conditional expression is constant
|
||||||
|
RAPIDJSON_DIAG_OFF(4702) // unreachable code
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
#ifdef __GNUC__
|
#ifdef __GNUC__
|
||||||
|
@ -155,6 +154,7 @@ enum ParseFlag {
|
||||||
kParseNumbersAsStringsFlag = 64, //!< Parse all numbers (ints/doubles) as strings.
|
kParseNumbersAsStringsFlag = 64, //!< Parse all numbers (ints/doubles) as strings.
|
||||||
kParseTrailingCommasFlag = 128, //!< Allow trailing commas at the end of objects and arrays.
|
kParseTrailingCommasFlag = 128, //!< Allow trailing commas at the end of objects and arrays.
|
||||||
kParseNanAndInfFlag = 256, //!< Allow parsing NaN, Inf, Infinity, -Inf and -Infinity as doubles.
|
kParseNanAndInfFlag = 256, //!< Allow parsing NaN, Inf, Infinity, -Inf and -Infinity as doubles.
|
||||||
|
kParseEscapedApostropheFlag = 512, //!< Allow escaped apostrophe in strings.
|
||||||
kParseDefaultFlags = RAPIDJSON_PARSE_DEFAULT_FLAGS //!< Default parse flags. Can be customized by defining RAPIDJSON_PARSE_DEFAULT_FLAGS
|
kParseDefaultFlags = RAPIDJSON_PARSE_DEFAULT_FLAGS //!< Default parse flags. Can be customized by defining RAPIDJSON_PARSE_DEFAULT_FLAGS
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -445,16 +445,16 @@ inline const char *SkipWhitespace_SIMD(const char* p) {
|
||||||
|
|
||||||
x = vmvnq_u8(x); // Negate
|
x = vmvnq_u8(x); // Negate
|
||||||
x = vrev64q_u8(x); // Rev in 64
|
x = vrev64q_u8(x); // Rev in 64
|
||||||
uint64_t low = vgetq_lane_u64(reinterpret_cast<uint64x2_t>(x), 0); // extract
|
uint64_t low = vgetq_lane_u64(vreinterpretq_u64_u8(x), 0); // extract
|
||||||
uint64_t high = vgetq_lane_u64(reinterpret_cast<uint64x2_t>(x), 1); // extract
|
uint64_t high = vgetq_lane_u64(vreinterpretq_u64_u8(x), 1); // extract
|
||||||
|
|
||||||
if (low == 0) {
|
if (low == 0) {
|
||||||
if (high != 0) {
|
if (high != 0) {
|
||||||
int lz =__builtin_clzll(high);;
|
uint32_t lz = internal::clzll(high);
|
||||||
return p + 8 + (lz >> 3);
|
return p + 8 + (lz >> 3);
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
int lz = __builtin_clzll(low);;
|
uint32_t lz = internal::clzll(low);
|
||||||
return p + (lz >> 3);
|
return p + (lz >> 3);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -481,16 +481,16 @@ inline const char *SkipWhitespace_SIMD(const char* p, const char* end) {
|
||||||
|
|
||||||
x = vmvnq_u8(x); // Negate
|
x = vmvnq_u8(x); // Negate
|
||||||
x = vrev64q_u8(x); // Rev in 64
|
x = vrev64q_u8(x); // Rev in 64
|
||||||
uint64_t low = vgetq_lane_u64(reinterpret_cast<uint64x2_t>(x), 0); // extract
|
uint64_t low = vgetq_lane_u64(vreinterpretq_u64_u8(x), 0); // extract
|
||||||
uint64_t high = vgetq_lane_u64(reinterpret_cast<uint64x2_t>(x), 1); // extract
|
uint64_t high = vgetq_lane_u64(vreinterpretq_u64_u8(x), 1); // extract
|
||||||
|
|
||||||
if (low == 0) {
|
if (low == 0) {
|
||||||
if (high != 0) {
|
if (high != 0) {
|
||||||
int lz = __builtin_clzll(high);
|
uint32_t lz = internal::clzll(high);
|
||||||
return p + 8 + (lz >> 3);
|
return p + 8 + (lz >> 3);
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
int lz = __builtin_clzll(low);
|
uint32_t lz = internal::clzll(low);
|
||||||
return p + (lz >> 3);
|
return p + (lz >> 3);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -544,7 +544,8 @@ public:
|
||||||
/*! \param stackAllocator Optional allocator for allocating stack memory. (Only use for non-destructive parsing)
|
/*! \param stackAllocator Optional allocator for allocating stack memory. (Only use for non-destructive parsing)
|
||||||
\param stackCapacity stack capacity in bytes for storing a single decoded string. (Only use for non-destructive parsing)
|
\param stackCapacity stack capacity in bytes for storing a single decoded string. (Only use for non-destructive parsing)
|
||||||
*/
|
*/
|
||||||
GenericReader(StackAllocator* stackAllocator = 0, size_t stackCapacity = kDefaultStackCapacity) : stack_(stackAllocator, stackCapacity), parseResult_() {}
|
GenericReader(StackAllocator* stackAllocator = 0, size_t stackCapacity = kDefaultStackCapacity) :
|
||||||
|
stack_(stackAllocator, stackCapacity), parseResult_(), state_(IterativeParsingStartState) {}
|
||||||
|
|
||||||
//! Parse JSON text.
|
//! Parse JSON text.
|
||||||
/*! \tparam parseFlags Combination of \ref ParseFlag.
|
/*! \tparam parseFlags Combination of \ref ParseFlag.
|
||||||
|
@ -673,11 +674,11 @@ public:
|
||||||
//! Check if token-by-token parsing JSON text is complete
|
//! Check if token-by-token parsing JSON text is complete
|
||||||
/*! \return Whether the JSON has been fully decoded.
|
/*! \return Whether the JSON has been fully decoded.
|
||||||
*/
|
*/
|
||||||
RAPIDJSON_FORCEINLINE bool IterativeParseComplete() {
|
RAPIDJSON_FORCEINLINE bool IterativeParseComplete() const {
|
||||||
return IsIterativeParsingCompleteState(state_);
|
return IsIterativeParsingCompleteState(state_);
|
||||||
}
|
}
|
||||||
|
|
||||||
//! Whether a parse error has occured in the last parsing.
|
//! Whether a parse error has occurred in the last parsing.
|
||||||
bool HasParseError() const { return parseResult_.IsError(); }
|
bool HasParseError() const { return parseResult_.IsError(); }
|
||||||
|
|
||||||
//! Get the \ref ParseErrorCode of last parsing.
|
//! Get the \ref ParseErrorCode of last parsing.
|
||||||
|
@ -900,7 +901,7 @@ private:
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Helper function to parse four hexidecimal digits in \uXXXX in ParseString().
|
// Helper function to parse four hexadecimal digits in \uXXXX in ParseString().
|
||||||
template<typename InputStream>
|
template<typename InputStream>
|
||||||
unsigned ParseHex4(InputStream& is, size_t escapeOffset) {
|
unsigned ParseHex4(InputStream& is, size_t escapeOffset) {
|
||||||
unsigned codepoint = 0;
|
unsigned codepoint = 0;
|
||||||
|
@ -991,7 +992,7 @@ private:
|
||||||
//!@cond RAPIDJSON_HIDDEN_FROM_DOXYGEN
|
//!@cond RAPIDJSON_HIDDEN_FROM_DOXYGEN
|
||||||
#define Z16 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0
|
#define Z16 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0
|
||||||
static const char escape[256] = {
|
static const char escape[256] = {
|
||||||
Z16, Z16, 0, 0,'\"', 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,'/',
|
Z16, Z16, 0, 0,'\"', 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, '/',
|
||||||
Z16, Z16, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,'\\', 0, 0, 0,
|
Z16, Z16, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,'\\', 0, 0, 0,
|
||||||
0, 0,'\b', 0, 0, 0,'\f', 0, 0, 0, 0, 0, 0, 0,'\n', 0,
|
0, 0,'\b', 0, 0, 0,'\f', 0, 0, 0, 0, 0, 0, 0,'\n', 0,
|
||||||
0, 0,'\r', 0,'\t', 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
|
0, 0,'\r', 0,'\t', 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
|
||||||
|
@ -1007,18 +1008,24 @@ private:
|
||||||
|
|
||||||
Ch c = is.Peek();
|
Ch c = is.Peek();
|
||||||
if (RAPIDJSON_UNLIKELY(c == '\\')) { // Escape
|
if (RAPIDJSON_UNLIKELY(c == '\\')) { // Escape
|
||||||
size_t escapeOffset = is.Tell(); // For invalid escaping, report the inital '\\' as error offset
|
size_t escapeOffset = is.Tell(); // For invalid escaping, report the initial '\\' as error offset
|
||||||
is.Take();
|
is.Take();
|
||||||
Ch e = is.Peek();
|
Ch e = is.Peek();
|
||||||
if ((sizeof(Ch) == 1 || unsigned(e) < 256) && RAPIDJSON_LIKELY(escape[static_cast<unsigned char>(e)])) {
|
if ((sizeof(Ch) == 1 || unsigned(e) < 256) && RAPIDJSON_LIKELY(escape[static_cast<unsigned char>(e)])) {
|
||||||
is.Take();
|
is.Take();
|
||||||
os.Put(static_cast<typename TEncoding::Ch>(escape[static_cast<unsigned char>(e)]));
|
os.Put(static_cast<typename TEncoding::Ch>(escape[static_cast<unsigned char>(e)]));
|
||||||
}
|
}
|
||||||
|
else if ((parseFlags & kParseEscapedApostropheFlag) && RAPIDJSON_LIKELY(e == '\'')) { // Allow escaped apostrophe
|
||||||
|
is.Take();
|
||||||
|
os.Put('\'');
|
||||||
|
}
|
||||||
else if (RAPIDJSON_LIKELY(e == 'u')) { // Unicode
|
else if (RAPIDJSON_LIKELY(e == 'u')) { // Unicode
|
||||||
is.Take();
|
is.Take();
|
||||||
unsigned codepoint = ParseHex4(is, escapeOffset);
|
unsigned codepoint = ParseHex4(is, escapeOffset);
|
||||||
RAPIDJSON_PARSE_ERROR_EARLY_RETURN_VOID;
|
RAPIDJSON_PARSE_ERROR_EARLY_RETURN_VOID;
|
||||||
if (RAPIDJSON_UNLIKELY(codepoint >= 0xD800 && codepoint <= 0xDBFF)) {
|
if (RAPIDJSON_UNLIKELY(codepoint >= 0xD800 && codepoint <= 0xDFFF)) {
|
||||||
|
// high surrogate, check if followed by valid low surrogate
|
||||||
|
if (RAPIDJSON_LIKELY(codepoint <= 0xDBFF)) {
|
||||||
// Handle UTF-16 surrogate pair
|
// Handle UTF-16 surrogate pair
|
||||||
if (RAPIDJSON_UNLIKELY(!Consume(is, '\\') || !Consume(is, 'u')))
|
if (RAPIDJSON_UNLIKELY(!Consume(is, '\\') || !Consume(is, 'u')))
|
||||||
RAPIDJSON_PARSE_ERROR(kParseErrorStringUnicodeSurrogateInvalid, escapeOffset);
|
RAPIDJSON_PARSE_ERROR(kParseErrorStringUnicodeSurrogateInvalid, escapeOffset);
|
||||||
|
@ -1028,6 +1035,12 @@ private:
|
||||||
RAPIDJSON_PARSE_ERROR(kParseErrorStringUnicodeSurrogateInvalid, escapeOffset);
|
RAPIDJSON_PARSE_ERROR(kParseErrorStringUnicodeSurrogateInvalid, escapeOffset);
|
||||||
codepoint = (((codepoint - 0xD800) << 10) | (codepoint2 - 0xDC00)) + 0x10000;
|
codepoint = (((codepoint - 0xD800) << 10) | (codepoint2 - 0xDC00)) + 0x10000;
|
||||||
}
|
}
|
||||||
|
// single low surrogate
|
||||||
|
else
|
||||||
|
{
|
||||||
|
RAPIDJSON_PARSE_ERROR(kParseErrorStringUnicodeSurrogateInvalid, escapeOffset);
|
||||||
|
}
|
||||||
|
}
|
||||||
TEncoding::Encode(os, codepoint);
|
TEncoding::Encode(os, codepoint);
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
|
@ -1245,19 +1258,19 @@ private:
|
||||||
x = vorrq_u8(x, vcltq_u8(s, s3));
|
x = vorrq_u8(x, vcltq_u8(s, s3));
|
||||||
|
|
||||||
x = vrev64q_u8(x); // Rev in 64
|
x = vrev64q_u8(x); // Rev in 64
|
||||||
uint64_t low = vgetq_lane_u64(reinterpret_cast<uint64x2_t>(x), 0); // extract
|
uint64_t low = vgetq_lane_u64(vreinterpretq_u64_u8(x), 0); // extract
|
||||||
uint64_t high = vgetq_lane_u64(reinterpret_cast<uint64x2_t>(x), 1); // extract
|
uint64_t high = vgetq_lane_u64(vreinterpretq_u64_u8(x), 1); // extract
|
||||||
|
|
||||||
SizeType length = 0;
|
SizeType length = 0;
|
||||||
bool escaped = false;
|
bool escaped = false;
|
||||||
if (low == 0) {
|
if (low == 0) {
|
||||||
if (high != 0) {
|
if (high != 0) {
|
||||||
unsigned lz = (unsigned)__builtin_clzll(high);;
|
uint32_t lz = internal::clzll(high);
|
||||||
length = 8 + (lz >> 3);
|
length = 8 + (lz >> 3);
|
||||||
escaped = true;
|
escaped = true;
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
unsigned lz = (unsigned)__builtin_clzll(low);;
|
uint32_t lz = internal::clzll(low);
|
||||||
length = lz >> 3;
|
length = lz >> 3;
|
||||||
escaped = true;
|
escaped = true;
|
||||||
}
|
}
|
||||||
|
@ -1315,19 +1328,19 @@ private:
|
||||||
x = vorrq_u8(x, vcltq_u8(s, s3));
|
x = vorrq_u8(x, vcltq_u8(s, s3));
|
||||||
|
|
||||||
x = vrev64q_u8(x); // Rev in 64
|
x = vrev64q_u8(x); // Rev in 64
|
||||||
uint64_t low = vgetq_lane_u64(reinterpret_cast<uint64x2_t>(x), 0); // extract
|
uint64_t low = vgetq_lane_u64(vreinterpretq_u64_u8(x), 0); // extract
|
||||||
uint64_t high = vgetq_lane_u64(reinterpret_cast<uint64x2_t>(x), 1); // extract
|
uint64_t high = vgetq_lane_u64(vreinterpretq_u64_u8(x), 1); // extract
|
||||||
|
|
||||||
SizeType length = 0;
|
SizeType length = 0;
|
||||||
bool escaped = false;
|
bool escaped = false;
|
||||||
if (low == 0) {
|
if (low == 0) {
|
||||||
if (high != 0) {
|
if (high != 0) {
|
||||||
unsigned lz = (unsigned)__builtin_clzll(high);
|
uint32_t lz = internal::clzll(high);
|
||||||
length = 8 + (lz >> 3);
|
length = 8 + (lz >> 3);
|
||||||
escaped = true;
|
escaped = true;
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
unsigned lz = (unsigned)__builtin_clzll(low);
|
uint32_t lz = internal::clzll(low);
|
||||||
length = lz >> 3;
|
length = lz >> 3;
|
||||||
escaped = true;
|
escaped = true;
|
||||||
}
|
}
|
||||||
|
@ -1371,17 +1384,17 @@ private:
|
||||||
x = vorrq_u8(x, vcltq_u8(s, s3));
|
x = vorrq_u8(x, vcltq_u8(s, s3));
|
||||||
|
|
||||||
x = vrev64q_u8(x); // Rev in 64
|
x = vrev64q_u8(x); // Rev in 64
|
||||||
uint64_t low = vgetq_lane_u64(reinterpret_cast<uint64x2_t>(x), 0); // extract
|
uint64_t low = vgetq_lane_u64(vreinterpretq_u64_u8(x), 0); // extract
|
||||||
uint64_t high = vgetq_lane_u64(reinterpret_cast<uint64x2_t>(x), 1); // extract
|
uint64_t high = vgetq_lane_u64(vreinterpretq_u64_u8(x), 1); // extract
|
||||||
|
|
||||||
if (low == 0) {
|
if (low == 0) {
|
||||||
if (high != 0) {
|
if (high != 0) {
|
||||||
int lz = __builtin_clzll(high);
|
uint32_t lz = internal::clzll(high);
|
||||||
p += 8 + (lz >> 3);
|
p += 8 + (lz >> 3);
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
int lz = __builtin_clzll(low);
|
uint32_t lz = internal::clzll(low);
|
||||||
p += lz >> 3;
|
p += lz >> 3;
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
@ -1562,8 +1575,6 @@ private:
|
||||||
// Force double for big integer
|
// Force double for big integer
|
||||||
if (useDouble) {
|
if (useDouble) {
|
||||||
while (RAPIDJSON_LIKELY(s.Peek() >= '0' && s.Peek() <= '9')) {
|
while (RAPIDJSON_LIKELY(s.Peek() >= '0' && s.Peek() <= '9')) {
|
||||||
if (RAPIDJSON_UNLIKELY(d >= 1.7976931348623157e307)) // DBL_MAX / 10.0
|
|
||||||
RAPIDJSON_PARSE_ERROR(kParseErrorNumberTooBig, startOffset);
|
|
||||||
d = d * 10 + (s.TakePush() - '0');
|
d = d * 10 + (s.TakePush() - '0');
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -1633,9 +1644,18 @@ private:
|
||||||
if (RAPIDJSON_LIKELY(s.Peek() >= '0' && s.Peek() <= '9')) {
|
if (RAPIDJSON_LIKELY(s.Peek() >= '0' && s.Peek() <= '9')) {
|
||||||
exp = static_cast<int>(s.Take() - '0');
|
exp = static_cast<int>(s.Take() - '0');
|
||||||
if (expMinus) {
|
if (expMinus) {
|
||||||
|
// (exp + expFrac) must not underflow int => we're detecting when -exp gets
|
||||||
|
// dangerously close to INT_MIN (a pessimistic next digit 9 would push it into
|
||||||
|
// underflow territory):
|
||||||
|
//
|
||||||
|
// -(exp * 10 + 9) + expFrac >= INT_MIN
|
||||||
|
// <=> exp <= (expFrac - INT_MIN - 9) / 10
|
||||||
|
RAPIDJSON_ASSERT(expFrac <= 0);
|
||||||
|
int maxExp = (expFrac + 2147483639) / 10;
|
||||||
|
|
||||||
while (RAPIDJSON_LIKELY(s.Peek() >= '0' && s.Peek() <= '9')) {
|
while (RAPIDJSON_LIKELY(s.Peek() >= '0' && s.Peek() <= '9')) {
|
||||||
exp = exp * 10 + static_cast<int>(s.Take() - '0');
|
exp = exp * 10 + static_cast<int>(s.Take() - '0');
|
||||||
if (exp >= 214748364) { // Issue #313: prevent overflow exponent
|
if (RAPIDJSON_UNLIKELY(exp > maxExp)) {
|
||||||
while (RAPIDJSON_UNLIKELY(s.Peek() >= '0' && s.Peek() <= '9')) // Consume the rest of exponent
|
while (RAPIDJSON_UNLIKELY(s.Peek() >= '0' && s.Peek() <= '9')) // Consume the rest of exponent
|
||||||
s.Take();
|
s.Take();
|
||||||
}
|
}
|
||||||
|
@ -1694,6 +1714,13 @@ private:
|
||||||
else
|
else
|
||||||
d = internal::StrtodNormalPrecision(d, p);
|
d = internal::StrtodNormalPrecision(d, p);
|
||||||
|
|
||||||
|
// Use > max, instead of == inf, to fix bogus warning -Wfloat-equal
|
||||||
|
if (d > (std::numeric_limits<double>::max)()) {
|
||||||
|
// Overflow
|
||||||
|
// TODO: internal::StrtodX should report overflow (or underflow)
|
||||||
|
RAPIDJSON_PARSE_ERROR(kParseErrorNumberTooBig, startOffset);
|
||||||
|
}
|
||||||
|
|
||||||
cont = handler.Double(minus ? -d : d);
|
cont = handler.Double(minus ? -d : d);
|
||||||
}
|
}
|
||||||
else if (useNanOrInf) {
|
else if (useNanOrInf) {
|
||||||
|
@ -1785,7 +1812,7 @@ private:
|
||||||
kTokenCount
|
kTokenCount
|
||||||
};
|
};
|
||||||
|
|
||||||
RAPIDJSON_FORCEINLINE Token Tokenize(Ch c) {
|
RAPIDJSON_FORCEINLINE Token Tokenize(Ch c) const {
|
||||||
|
|
||||||
//!@cond RAPIDJSON_HIDDEN_FROM_DOXYGEN
|
//!@cond RAPIDJSON_HIDDEN_FROM_DOXYGEN
|
||||||
#define N NumberToken
|
#define N NumberToken
|
||||||
|
@ -1812,7 +1839,7 @@ private:
|
||||||
return NumberToken;
|
return NumberToken;
|
||||||
}
|
}
|
||||||
|
|
||||||
RAPIDJSON_FORCEINLINE IterativeParsingState Predict(IterativeParsingState state, Token token) {
|
RAPIDJSON_FORCEINLINE IterativeParsingState Predict(IterativeParsingState state, Token token) const {
|
||||||
// current state x one lookahead token -> new state
|
// current state x one lookahead token -> new state
|
||||||
static const char G[cIterativeParsingStateCount][kTokenCount] = {
|
static const char G[cIterativeParsingStateCount][kTokenCount] = {
|
||||||
// Finish(sink state)
|
// Finish(sink state)
|
||||||
|
@ -2151,11 +2178,11 @@ private:
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
RAPIDJSON_FORCEINLINE bool IsIterativeParsingDelimiterState(IterativeParsingState s) {
|
RAPIDJSON_FORCEINLINE bool IsIterativeParsingDelimiterState(IterativeParsingState s) const {
|
||||||
return s >= IterativeParsingElementDelimiterState;
|
return s >= IterativeParsingElementDelimiterState;
|
||||||
}
|
}
|
||||||
|
|
||||||
RAPIDJSON_FORCEINLINE bool IsIterativeParsingCompleteState(IterativeParsingState s) {
|
RAPIDJSON_FORCEINLINE bool IsIterativeParsingCompleteState(IterativeParsingState s) const {
|
||||||
return s <= IterativeParsingErrorState;
|
return s <= IterativeParsingErrorState;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -2205,7 +2232,7 @@ typedef GenericReader<UTF8<>, UTF8<> > Reader;
|
||||||
|
|
||||||
RAPIDJSON_NAMESPACE_END
|
RAPIDJSON_NAMESPACE_END
|
||||||
|
|
||||||
#ifdef __clang__
|
#if defined(__clang__) || defined(_MSC_VER)
|
||||||
RAPIDJSON_DIAG_POP
|
RAPIDJSON_DIAG_POP
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
@ -2214,8 +2241,4 @@ RAPIDJSON_DIAG_POP
|
||||||
RAPIDJSON_DIAG_POP
|
RAPIDJSON_DIAG_POP
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
#if defined(_MSC_VER) && !defined(__clang__)
|
|
||||||
RAPIDJSON_DIAG_POP
|
|
||||||
#endif
|
|
||||||
|
|
||||||
#endif // RAPIDJSON_READER_H_
|
#endif // RAPIDJSON_READER_H_
|
||||||
|
|
File diff suppressed because it is too large
Load Diff
|
@ -1,6 +1,6 @@
|
||||||
// Tencent is pleased to support the open source community by making RapidJSON available.
|
// 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.
|
// Copyright (C) 2015 THL A29 Limited, a Tencent company, and Milo Yip.
|
||||||
//
|
//
|
||||||
// Licensed under the MIT License (the "License"); you may not use this file except
|
// 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
|
// in compliance with the License. You may obtain a copy of the License at
|
||||||
|
@ -100,6 +100,50 @@ inline void PutN(Stream& stream, Ch c, size_t n) {
|
||||||
PutUnsafe(stream, c);
|
PutUnsafe(stream, c);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
///////////////////////////////////////////////////////////////////////////////
|
||||||
|
// GenericStreamWrapper
|
||||||
|
|
||||||
|
//! A Stream Wrapper
|
||||||
|
/*! \tThis string stream is a wrapper for any stream by just forwarding any
|
||||||
|
\treceived message to the origin stream.
|
||||||
|
\note implements Stream concept
|
||||||
|
*/
|
||||||
|
|
||||||
|
#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
|
||||||
|
|
||||||
|
template <typename InputStream, typename Encoding = UTF8<> >
|
||||||
|
class GenericStreamWrapper {
|
||||||
|
public:
|
||||||
|
typedef typename Encoding::Ch Ch;
|
||||||
|
GenericStreamWrapper(InputStream& is): is_(is) {}
|
||||||
|
|
||||||
|
Ch Peek() const { return is_.Peek(); }
|
||||||
|
Ch Take() { return is_.Take(); }
|
||||||
|
size_t Tell() { return is_.Tell(); }
|
||||||
|
Ch* PutBegin() { return is_.PutBegin(); }
|
||||||
|
void Put(Ch ch) { is_.Put(ch); }
|
||||||
|
void Flush() { is_.Flush(); }
|
||||||
|
size_t PutEnd(Ch* ch) { return is_.PutEnd(ch); }
|
||||||
|
|
||||||
|
// wrapper for MemoryStream
|
||||||
|
const Ch* Peek4() const { return is_.Peek4(); }
|
||||||
|
|
||||||
|
// wrapper for AutoUTFInputStream
|
||||||
|
UTFType GetType() const { return is_.GetType(); }
|
||||||
|
bool HasBOM() const { return is_.HasBOM(); }
|
||||||
|
|
||||||
|
protected:
|
||||||
|
InputStream& is_;
|
||||||
|
};
|
||||||
|
|
||||||
|
#if defined(_MSC_VER) && _MSC_VER <= 1800
|
||||||
|
RAPIDJSON_DIAG_POP
|
||||||
|
#endif
|
||||||
|
|
||||||
///////////////////////////////////////////////////////////////////////////////
|
///////////////////////////////////////////////////////////////////////////////
|
||||||
// StringStream
|
// StringStream
|
||||||
|
|
||||||
|
|
|
@ -1,6 +1,6 @@
|
||||||
// Tencent is pleased to support the open source community by making RapidJSON available.
|
// 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.
|
// Copyright (C) 2015 THL A29 Limited, a Tencent company, and Milo Yip.
|
||||||
//
|
//
|
||||||
// Licensed under the MIT License (the "License"); you may not use this file except
|
// 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
|
// in compliance with the License. You may obtain a copy of the License at
|
||||||
|
|
|
@ -1,6 +1,6 @@
|
||||||
// Tencent is pleased to support the open source community by making RapidJSON available.
|
// 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.
|
// Copyright (C) 2015 THL A29 Limited, a Tencent company, and Milo Yip.
|
||||||
//
|
//
|
||||||
// Licensed under the MIT License (the "License"); you may not use this file except
|
// 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
|
// in compliance with the License. You may obtain a copy of the License at
|
||||||
|
@ -16,6 +16,7 @@
|
||||||
#define RAPIDJSON_WRITER_H_
|
#define RAPIDJSON_WRITER_H_
|
||||||
|
|
||||||
#include "stream.h"
|
#include "stream.h"
|
||||||
|
#include "internal/clzll.h"
|
||||||
#include "internal/meta.h"
|
#include "internal/meta.h"
|
||||||
#include "internal/stack.h"
|
#include "internal/stack.h"
|
||||||
#include "internal/strfunc.h"
|
#include "internal/strfunc.h"
|
||||||
|
@ -36,16 +37,14 @@
|
||||||
#include <arm_neon.h>
|
#include <arm_neon.h>
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
#if defined (_MSC_VER) && !defined(__clang__)
|
|
||||||
RAPIDJSON_DIAG_PUSH
|
|
||||||
RAPIDJSON_DIAG_OFF(4127) // conditional expression is constant
|
|
||||||
#endif
|
|
||||||
|
|
||||||
#ifdef __clang__
|
#ifdef __clang__
|
||||||
RAPIDJSON_DIAG_PUSH
|
RAPIDJSON_DIAG_PUSH
|
||||||
RAPIDJSON_DIAG_OFF(padded)
|
RAPIDJSON_DIAG_OFF(padded)
|
||||||
RAPIDJSON_DIAG_OFF(unreachable-code)
|
RAPIDJSON_DIAG_OFF(unreachable-code)
|
||||||
RAPIDJSON_DIAG_OFF(c++98-compat)
|
RAPIDJSON_DIAG_OFF(c++98-compat)
|
||||||
|
#elif defined(_MSC_VER)
|
||||||
|
RAPIDJSON_DIAG_PUSH
|
||||||
|
RAPIDJSON_DIAG_OFF(4127) // conditional expression is constant
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
RAPIDJSON_NAMESPACE_BEGIN
|
RAPIDJSON_NAMESPACE_BEGIN
|
||||||
|
@ -284,6 +283,8 @@ public:
|
||||||
os_->Flush();
|
os_->Flush();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static const size_t kDefaultLevelDepth = 32;
|
||||||
|
|
||||||
protected:
|
protected:
|
||||||
//! Information for each nested level
|
//! Information for each nested level
|
||||||
struct Level {
|
struct Level {
|
||||||
|
@ -292,8 +293,6 @@ protected:
|
||||||
bool inArray; //!< true if in array, otherwise in object
|
bool inArray; //!< true if in array, otherwise in object
|
||||||
};
|
};
|
||||||
|
|
||||||
static const size_t kDefaultLevelDepth = 32;
|
|
||||||
|
|
||||||
bool WriteNull() {
|
bool WriteNull() {
|
||||||
PutReserve(*os_, 4);
|
PutReserve(*os_, 4);
|
||||||
PutUnsafe(*os_, 'n'); PutUnsafe(*os_, 'u'); PutUnsafe(*os_, 'l'); PutUnsafe(*os_, 'l'); return true;
|
PutUnsafe(*os_, 'n'); PutUnsafe(*os_, 'u'); PutUnsafe(*os_, 'l'); PutUnsafe(*os_, 'l'); return true;
|
||||||
|
@ -460,9 +459,13 @@ protected:
|
||||||
|
|
||||||
bool WriteRawValue(const Ch* json, size_t length) {
|
bool WriteRawValue(const Ch* json, size_t length) {
|
||||||
PutReserve(*os_, length);
|
PutReserve(*os_, length);
|
||||||
for (size_t i = 0; i < length; i++) {
|
GenericStringStream<SourceEncoding> is(json);
|
||||||
RAPIDJSON_ASSERT(json[i] != '\0');
|
while (RAPIDJSON_LIKELY(is.Tell() < length)) {
|
||||||
PutUnsafe(*os_, json[i]);
|
RAPIDJSON_ASSERT(is.Peek() != '\0');
|
||||||
|
if (RAPIDJSON_UNLIKELY(!(writeFlags & kWriteValidateEncodingFlag ?
|
||||||
|
Transcoder<SourceEncoding, TargetEncoding>::Validate(is, *os_) :
|
||||||
|
Transcoder<SourceEncoding, TargetEncoding>::TranscodeUnsafe(is, *os_))))
|
||||||
|
return false;
|
||||||
}
|
}
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
@ -666,19 +669,19 @@ inline bool Writer<StringBuffer>::ScanWriteUnescapedString(StringStream& is, siz
|
||||||
x = vorrq_u8(x, vcltq_u8(s, s3));
|
x = vorrq_u8(x, vcltq_u8(s, s3));
|
||||||
|
|
||||||
x = vrev64q_u8(x); // Rev in 64
|
x = vrev64q_u8(x); // Rev in 64
|
||||||
uint64_t low = vgetq_lane_u64(reinterpret_cast<uint64x2_t>(x), 0); // extract
|
uint64_t low = vgetq_lane_u64(vreinterpretq_u64_u8(x), 0); // extract
|
||||||
uint64_t high = vgetq_lane_u64(reinterpret_cast<uint64x2_t>(x), 1); // extract
|
uint64_t high = vgetq_lane_u64(vreinterpretq_u64_u8(x), 1); // extract
|
||||||
|
|
||||||
SizeType len = 0;
|
SizeType len = 0;
|
||||||
bool escaped = false;
|
bool escaped = false;
|
||||||
if (low == 0) {
|
if (low == 0) {
|
||||||
if (high != 0) {
|
if (high != 0) {
|
||||||
unsigned lz = (unsigned)__builtin_clzll(high);
|
uint32_t lz = internal::clzll(high);
|
||||||
len = 8 + (lz >> 3);
|
len = 8 + (lz >> 3);
|
||||||
escaped = true;
|
escaped = true;
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
unsigned lz = (unsigned)__builtin_clzll(low);
|
uint32_t lz = internal::clzll(low);
|
||||||
len = lz >> 3;
|
len = lz >> 3;
|
||||||
escaped = true;
|
escaped = true;
|
||||||
}
|
}
|
||||||
|
@ -700,11 +703,7 @@ inline bool Writer<StringBuffer>::ScanWriteUnescapedString(StringStream& is, siz
|
||||||
|
|
||||||
RAPIDJSON_NAMESPACE_END
|
RAPIDJSON_NAMESPACE_END
|
||||||
|
|
||||||
#if defined(_MSC_VER) && !defined(__clang__)
|
#if defined(_MSC_VER) || defined(__clang__)
|
||||||
RAPIDJSON_DIAG_POP
|
|
||||||
#endif
|
|
||||||
|
|
||||||
#if defined(__clang__)
|
|
||||||
RAPIDJSON_DIAG_POP
|
RAPIDJSON_DIAG_POP
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
|
|
@ -63,8 +63,8 @@ class BlenderIntermediateTest : public ::testing::Test {
|
||||||
// The C++ standard defines and expects this behavior: true if lhs < rhs, false otherwise.
|
// The C++ standard defines and expects this behavior: true if lhs < rhs, false otherwise.
|
||||||
TEST_F(BlenderIntermediateTest, ConversionData_ObjectCompareTest) {
|
TEST_F(BlenderIntermediateTest, ConversionData_ObjectCompareTest) {
|
||||||
Object obj1, obj2;
|
Object obj1, obj2;
|
||||||
strncpy(obj1.id.name, NAME_1, sizeof(NAME_1));
|
strncpy(obj1.id.name, NAME_1, sizeof(obj1.id.name));
|
||||||
strncpy(obj2.id.name, NAME_2, sizeof(NAME_2));
|
strncpy(obj2.id.name, NAME_2, sizeof(obj2.id.name));
|
||||||
|
|
||||||
Blender::ObjectCompare cmp_true_because_first_is_smaller_than_second;
|
Blender::ObjectCompare cmp_true_because_first_is_smaller_than_second;
|
||||||
bool res(cmp_true_because_first_is_smaller_than_second(&obj1, &obj2));
|
bool res(cmp_true_because_first_is_smaller_than_second(&obj1, &obj2));
|
||||||
|
|
|
@ -72,6 +72,6 @@ TEST_F(utSMDImporter, importTest) {
|
||||||
|
|
||||||
TEST_F(utSMDImporter, issue_899_Texture_garbage_at_end_of_string_Test) {
|
TEST_F(utSMDImporter, issue_899_Texture_garbage_at_end_of_string_Test) {
|
||||||
Assimp::Importer importer;
|
Assimp::Importer importer;
|
||||||
const aiScene *scene = importer.ReadFile(ASSIMP_TEST_MODELS_DIR "/SMD/holy_grailref.smd", aiProcess_ValidateDataStructure);
|
const aiScene *scene = importer.ReadFile(ASSIMP_TEST_MODELS_DIR"/SMD/holy_grailref.smd", aiProcess_ValidateDataStructure);
|
||||||
EXPECT_NE(nullptr, scene);
|
EXPECT_NE(nullptr, scene);
|
||||||
}
|
}
|
||||||
|
|
|
@ -51,7 +51,7 @@ using namespace Assimp;
|
||||||
|
|
||||||
class utglTFImportExport : public AbstractImportExportBase {
|
class utglTFImportExport : public AbstractImportExportBase {
|
||||||
public:
|
public:
|
||||||
virtual bool importerTest() {
|
bool importerTest() override {
|
||||||
Assimp::Importer importer;
|
Assimp::Importer importer;
|
||||||
const aiScene *scene = importer.ReadFile(ASSIMP_TEST_MODELS_DIR "/glTF/TwoBoxes/TwoBoxes.gltf", aiProcess_ValidateDataStructure);
|
const aiScene *scene = importer.ReadFile(ASSIMP_TEST_MODELS_DIR "/glTF/TwoBoxes/TwoBoxes.gltf", aiProcess_ValidateDataStructure);
|
||||||
return nullptr != scene;
|
return nullptr != scene;
|
||||||
|
|
Loading…
Reference in New Issue