Merge branch 'master' into master

pull/3636/head
Kim Kulling 2021-02-06 09:54:51 +01:00 committed by GitHub
commit 6c3593eda0
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
42 changed files with 2127 additions and 887 deletions

View File

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

View File

@ -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()) {

View File

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

View File

@ -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 &currentNode : node.children()) { for (XmlNode &currentNode : node.children()) {
const std::string &currentName = std::string(currentNode.name()); const std::string &currentName = 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 &currentName = currentNode.name(); const std::string &currentName = 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 &currentNode : node.children()) {
XmlNodeIterator xmlIt(node);
xmlIt.collectChildrenPreOrder(node);
XmlNode currentNode;
while (xmlIt.getNext(currentNode)) {
//for (XmlNode &currentNode : node.children()) {
const std::string &currentName = currentNode.name(); const std::string &currentName = 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 &currentChildName = currentChildNode.name(); const std::string &currentChildName = 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 &currentNode : node.children()) { for (XmlNode &currentNode : node.children()) {
const std::string &currentName = currentNode.name(); const std::string &currentName = 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 &currentNode : node.children()) { for (XmlNode &currentNode : node.children()) {
const std::string &currentName = currentNode.name(); const std::string &currentName = 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 &currentNode : node.children()) { for (XmlNode &currentNode : 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 &currentNode : node.children()) { for (XmlNode &currentNode : node.children()) {
const std::string &currentName = currentNode.name(); const std::string &currentName = 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 &currentNode : node.children()) { for (XmlNode &currentNode : node.children()) {
const std::string &currentName = currentNode.name(); const std::string &currentName = currentNode.name();
if (currentName == "camera") { if (currentName == "camera") {

View File

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

View File

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

View File

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

View File

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

View File

@ -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);
} }

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

@ -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++ = '-';

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

@ -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);
} }

View File

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