Add bounds checks to the parsing utilities. (#5421)

* Add bounds checks to the parsing utilities.

* Fix merge conflicts in ACLoader.

* Fix loaders

* Fix unittest of AC-Loader.

* Remove dead code.

* Md5Parser fixes

* Fix md5-parsing

* Fix Merge conflict

* Fix merge conflicts.

* Md5: Fix warning: missing return statement.
pull/5446/head
Kim Kulling 2024-01-30 14:32:41 +01:00 committed by GitHub
parent d5f35582d4
commit c08e3b4abb
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
39 changed files with 853 additions and 782 deletions

View File

@ -77,8 +77,8 @@ static constexpr aiImporterDesc desc = {
// ------------------------------------------------------------------------------------------------
// skip to the next token
inline const char *AcSkipToNextToken(const char *buffer) {
if (!SkipSpaces(&buffer)) {
inline const char *AcSkipToNextToken(const char *buffer, const char *end) {
if (!SkipSpaces(&buffer, end)) {
ASSIMP_LOG_ERROR("AC3D: Unexpected EOF/EOL");
}
return buffer;
@ -86,13 +86,13 @@ inline const char *AcSkipToNextToken(const char *buffer) {
// ------------------------------------------------------------------------------------------------
// read a string (may be enclosed in double quotation marks). buffer must point to "
inline const char *AcGetString(const char *buffer, std::string &out) {
inline const char *AcGetString(const char *buffer, const char *end, std::string &out) {
if (*buffer == '\0') {
throw DeadlyImportError("AC3D: Unexpected EOF in string");
}
++buffer;
const char *sz = buffer;
while ('\"' != *buffer) {
while ('\"' != *buffer && buffer != end) {
if (IsLineEnd(*buffer)) {
ASSIMP_LOG_ERROR("AC3D: Unexpected EOF/EOL in string");
out = "ERROR";
@ -112,8 +112,8 @@ inline const char *AcGetString(const char *buffer, std::string &out) {
// ------------------------------------------------------------------------------------------------
// read 1 to n floats prefixed with an optional predefined identifier
template <class T>
inline const char *TAcCheckedLoadFloatArray(const char *buffer, const char *name, size_t name_length, size_t num, T *out) {
buffer = AcSkipToNextToken(buffer);
inline const char *TAcCheckedLoadFloatArray(const char *buffer, const char *end, const char *name, size_t name_length, size_t num, T *out) {
buffer = AcSkipToNextToken(buffer, end);
if (0 != name_length) {
if (0 != strncmp(buffer, name, name_length) || !IsSpace(buffer[name_length])) {
ASSIMP_LOG_ERROR("AC3D: Unexpected token. ", name, " was expected.");
@ -122,7 +122,7 @@ inline const char *TAcCheckedLoadFloatArray(const char *buffer, const char *name
buffer += name_length + 1;
}
for (unsigned int _i = 0; _i < num; ++_i) {
buffer = AcSkipToNextToken(buffer);
buffer = AcSkipToNextToken(buffer, end);
buffer = fast_atoreal_move<float>(buffer, ((float *)out)[_i]);
}
@ -132,7 +132,7 @@ inline const char *TAcCheckedLoadFloatArray(const char *buffer, const char *name
// ------------------------------------------------------------------------------------------------
// Constructor to be privately used by Importer
AC3DImporter::AC3DImporter() :
buffer(),
mBuffer(),
configSplitBFCull(),
configEvalSubdivision(),
mNumMeshes(),
@ -164,17 +164,17 @@ const aiImporterDesc *AC3DImporter::GetInfo() const {
// ------------------------------------------------------------------------------------------------
// Get a pointer to the next line from the file
bool AC3DImporter::GetNextLine() {
SkipLine(&buffer);
return SkipSpaces(&buffer);
SkipLine(&mBuffer.data, mBuffer.end);
return SkipSpaces(&mBuffer.data, mBuffer.end);
}
// ------------------------------------------------------------------------------------------------
// Parse an object section in an AC file
bool AC3DImporter::LoadObjectSection(std::vector<Object> &objects) {
if (!TokenMatch(buffer, "OBJECT", 6))
if (!TokenMatch(mBuffer.data, "OBJECT", 6))
return false;
SkipSpaces(&buffer);
SkipSpaces(&mBuffer.data, mBuffer.end);
++mNumMeshes;
@ -182,7 +182,7 @@ bool AC3DImporter::LoadObjectSection(std::vector<Object> &objects) {
Object &obj = objects.back();
aiLight *light = nullptr;
if (!ASSIMP_strincmp(buffer, "light", 5)) {
if (!ASSIMP_strincmp(mBuffer.data, "light", 5)) {
// This is a light source. Add it to the list
mLights->push_back(light = new aiLight());
@ -198,16 +198,16 @@ bool AC3DImporter::LoadObjectSection(std::vector<Object> &objects) {
ASSIMP_LOG_VERBOSE_DEBUG("AC3D: Light source encountered");
obj.type = Object::Light;
} else if (!ASSIMP_strincmp(buffer, "group", 5)) {
} else if (!ASSIMP_strincmp(mBuffer.data, "group", 5)) {
obj.type = Object::Group;
} else if (!ASSIMP_strincmp(buffer, "world", 5)) {
} else if (!ASSIMP_strincmp(mBuffer.data, "world", 5)) {
obj.type = Object::World;
} else
obj.type = Object::Poly;
while (GetNextLine()) {
if (TokenMatch(buffer, "kids", 4)) {
SkipSpaces(&buffer);
unsigned int num = strtoul10(buffer, &buffer);
if (TokenMatch(mBuffer.data, "kids", 4)) {
SkipSpaces(&mBuffer.data, mBuffer.end);
unsigned int num = strtoul10(mBuffer.data, &mBuffer.data);
GetNextLine();
if (num) {
// load the children of this object recursively
@ -220,51 +220,44 @@ bool AC3DImporter::LoadObjectSection(std::vector<Object> &objects) {
}
}
return true;
} else if (TokenMatch(buffer, "name", 4)) {
SkipSpaces(&buffer);
buffer = AcGetString(buffer, obj.name);
} else if (TokenMatch(mBuffer.data, "name", 4)) {
SkipSpaces(&mBuffer.data, mBuffer.data);
mBuffer.data = AcGetString(mBuffer.data, mBuffer.end, obj.name);
// If this is a light source, we'll also need to store
// the name of the node in it.
if (light) {
light->mName.Set(obj.name);
}
} else if (TokenMatch(buffer, "texture", 7)) {
SkipSpaces(&buffer);
// skip empty acc texture
if (*buffer != '\"') {
if (!TokenMatch(buffer, "empty_texture_no_mapping", 24)) {
ASSIMP_LOG_ERROR("AC3D: Unquoted texture string");
}
} else {
std::string texture;
buffer = AcGetString(buffer, texture);
obj.textures.push_back(texture);
}
} else if (TokenMatch(buffer, "texrep", 6)) {
SkipSpaces(&buffer);
buffer = TAcCheckedLoadFloatArray(buffer, "", 0, 2, &obj.texRepeat);
} else if (TokenMatch(mBuffer.data, "texture", 7)) {
SkipSpaces(&mBuffer.data, mBuffer.end);
std::string texture;
mBuffer.data = AcGetString(mBuffer.data, mBuffer.end, texture);
obj.textures.push_back(texture);
} else if (TokenMatch(mBuffer.data, "texrep", 6)) {
SkipSpaces(&mBuffer.data, mBuffer.end);
mBuffer.data = TAcCheckedLoadFloatArray(mBuffer.data, mBuffer.end, "", 0, 2, &obj.texRepeat);
if (!obj.texRepeat.x || !obj.texRepeat.y)
obj.texRepeat = aiVector2D(1.f, 1.f);
} else if (TokenMatch(buffer, "texoff", 6)) {
SkipSpaces(&buffer);
buffer = TAcCheckedLoadFloatArray(buffer, "", 0, 2, &obj.texOffset);
} else if (TokenMatch(buffer, "rot", 3)) {
SkipSpaces(&buffer);
buffer = TAcCheckedLoadFloatArray(buffer, "", 0, 9, &obj.rotation);
} else if (TokenMatch(buffer, "loc", 3)) {
SkipSpaces(&buffer);
buffer = TAcCheckedLoadFloatArray(buffer, "", 0, 3, &obj.translation);
} else if (TokenMatch(buffer, "subdiv", 6)) {
SkipSpaces(&buffer);
obj.subDiv = strtoul10(buffer, &buffer);
} else if (TokenMatch(buffer, "crease", 6)) {
SkipSpaces(&buffer);
obj.crease = fast_atof(buffer);
} else if (TokenMatch(buffer, "numvert", 7)) {
SkipSpaces(&buffer);
} else if (TokenMatch(mBuffer.data, "texoff", 6)) {
SkipSpaces(&mBuffer.data, mBuffer.end);
mBuffer.data = TAcCheckedLoadFloatArray(mBuffer.data, mBuffer.end, "", 0, 2, &obj.texOffset);
} else if (TokenMatch(mBuffer.data, "rot", 3)) {
SkipSpaces(&mBuffer.data, mBuffer.end);
mBuffer.data = TAcCheckedLoadFloatArray(mBuffer.data, mBuffer.end, "", 0, 9, &obj.rotation);
} else if (TokenMatch(mBuffer.data, "loc", 3)) {
SkipSpaces(&mBuffer.data, mBuffer.end);
mBuffer.data = TAcCheckedLoadFloatArray(mBuffer.data, mBuffer.end, "", 0, 3, &obj.translation);
} else if (TokenMatch(mBuffer.data, "subdiv", 6)) {
SkipSpaces(&mBuffer.data, mBuffer.end);
obj.subDiv = strtoul10(mBuffer.data, &mBuffer.data);
} else if (TokenMatch(mBuffer.data, "crease", 6)) {
SkipSpaces(&mBuffer.data, mBuffer.end);
obj.crease = fast_atof(mBuffer.data);
} else if (TokenMatch(mBuffer.data, "numvert", 7)) {
SkipSpaces(&mBuffer.data, mBuffer.end);
unsigned int t = strtoul10(buffer, &buffer);
unsigned int t = strtoul10(mBuffer.data, &mBuffer.data);
if (t >= AI_MAX_ALLOC(aiVector3D)) {
throw DeadlyImportError("AC3D: Too many vertices, would run out of memory");
}
@ -273,59 +266,59 @@ bool AC3DImporter::LoadObjectSection(std::vector<Object> &objects) {
if (!GetNextLine()) {
ASSIMP_LOG_ERROR("AC3D: Unexpected EOF: not all vertices have been parsed yet");
break;
} else if (!IsNumeric(*buffer)) {
} else if (!IsNumeric(*mBuffer.data)) {
ASSIMP_LOG_ERROR("AC3D: Unexpected token: not all vertices have been parsed yet");
--buffer; // make sure the line is processed a second time
--mBuffer.data; // make sure the line is processed a second time
break;
}
obj.vertices.emplace_back();
aiVector3D &v = obj.vertices.back();
buffer = TAcCheckedLoadFloatArray(buffer, "", 0, 3, &v.x);
mBuffer.data = TAcCheckedLoadFloatArray(mBuffer.data, mBuffer.end, "", 0, 3, &v.x);
}
} else if (TokenMatch(buffer, "numsurf", 7)) {
SkipSpaces(&buffer);
} else if (TokenMatch(mBuffer.data, "numsurf", 7)) {
SkipSpaces(&mBuffer.data, mBuffer.end);
bool Q3DWorkAround = false;
const unsigned int t = strtoul10(buffer, &buffer);
const unsigned int t = strtoul10(mBuffer.data, &mBuffer.data);
obj.surfaces.reserve(t);
for (unsigned int i = 0; i < t; ++i) {
GetNextLine();
if (!TokenMatch(buffer, "SURF", 4)) {
if (!TokenMatch(mBuffer.data, "SURF", 4)) {
// FIX: this can occur for some files - Quick 3D for
// example writes no surf chunks
if (!Q3DWorkAround) {
ASSIMP_LOG_WARN("AC3D: SURF token was expected");
ASSIMP_LOG_VERBOSE_DEBUG("Continuing with Quick3D Workaround enabled");
}
--buffer; // make sure the line is processed a second time
--mBuffer.data; // make sure the line is processed a second time
// break; --- see fix notes above
Q3DWorkAround = true;
}
SkipSpaces(&buffer);
SkipSpaces(&mBuffer.data, mBuffer.end);
obj.surfaces.emplace_back();
Surface &surf = obj.surfaces.back();
surf.flags = strtoul_cppstyle(buffer);
surf.flags = strtoul_cppstyle(mBuffer.data);
while (true) {
if (!GetNextLine()) {
throw DeadlyImportError("AC3D: Unexpected EOF: surface is incomplete");
}
if (TokenMatch(buffer, "mat", 3)) {
SkipSpaces(&buffer);
surf.mat = strtoul10(buffer);
} else if (TokenMatch(buffer, "refs", 4)) {
if (TokenMatch(mBuffer.data, "mat", 3)) {
SkipSpaces(&mBuffer.data, mBuffer.end);
surf.mat = strtoul10(mBuffer.data);
} else if (TokenMatch(mBuffer.data, "refs", 4)) {
// --- see fix notes above
if (Q3DWorkAround) {
if (!surf.entries.empty()) {
buffer -= 6;
mBuffer.data -= 6;
break;
}
}
SkipSpaces(&buffer);
const unsigned int m = strtoul10(buffer);
SkipSpaces(&mBuffer.data, mBuffer.end);
const unsigned int m = strtoul10(mBuffer.data);
surf.entries.reserve(m);
obj.numRefs += m;
@ -338,12 +331,12 @@ bool AC3DImporter::LoadObjectSection(std::vector<Object> &objects) {
surf.entries.emplace_back();
Surface::SurfaceEntry &entry = surf.entries.back();
entry.first = strtoul10(buffer, &buffer);
SkipSpaces(&buffer);
buffer = TAcCheckedLoadFloatArray(buffer, "", 0, 2, &entry.second);
entry.first = strtoul10(mBuffer.data, &mBuffer.data);
SkipSpaces(&mBuffer.data, mBuffer.end);
mBuffer.data = TAcCheckedLoadFloatArray(mBuffer.data, mBuffer.end, "", 0, 2, &entry.second);
}
} else {
--buffer; // make sure the line is processed a second time
--mBuffer.data; // make sure the line is processed a second time
break;
}
}
@ -475,16 +468,15 @@ aiNode *AC3DImporter::ConvertObjectSection(Object &object,
}
switch ((*it).GetType()) {
// closed line
case Surface::ClosedLine:
needMat[idx].first += (unsigned int)(*it).entries.size();
needMat[idx].second += (unsigned int)(*it).entries.size() << 1u;
case Surface::ClosedLine: // closed line
needMat[idx].first += static_cast<unsigned int>((*it).entries.size());
needMat[idx].second += static_cast<unsigned int>((*it).entries.size() << 1u);
break;
// unclosed line
case Surface::OpenLine:
needMat[idx].first += (unsigned int)(*it).entries.size() - 1;
needMat[idx].second += ((unsigned int)(*it).entries.size() - 1) << 1u;
needMat[idx].first += static_cast<unsigned int>((*it).entries.size() - 1);
needMat[idx].second += static_cast<unsigned int>(((*it).entries.size() - 1) << 1u);
break;
// triangle strip
@ -763,17 +755,18 @@ void AC3DImporter::InternReadFile(const std::string &pFile,
std::vector<char> mBuffer2;
TextFileToBuffer(file.get(), mBuffer2);
buffer = &mBuffer2[0];
mBuffer.data = &mBuffer2[0];
mBuffer.end = &mBuffer2[0] + mBuffer2.size();
mNumMeshes = 0;
mLightsCounter = mPolysCounter = mWorldsCounter = mGroupsCounter = 0;
if (::strncmp(buffer, "AC3D", 4)) {
if (::strncmp(mBuffer.data, "AC3D", 4)) {
throw DeadlyImportError("AC3D: No valid AC3D file, magic sequence not found");
}
// print the file format version to the console
unsigned int version = HexDigitToDecimal(buffer[4]);
unsigned int version = HexDigitToDecimal(mBuffer.data[4]);
char msg[3];
ASSIMP_itoa10(msg, 3, version);
ASSIMP_LOG_INFO("AC3D file format version: ", msg);
@ -788,31 +781,31 @@ void AC3DImporter::InternReadFile(const std::string &pFile,
mLights = &lights;
while (GetNextLine()) {
if (TokenMatch(buffer, "MATERIAL", 8)) {
if (TokenMatch(mBuffer.data, "MATERIAL", 8)) {
materials.emplace_back();
Material &mat = materials.back();
// manually parse the material ... sscanf would use the buldin atof ...
// Format: (name) rgb %f %f %f amb %f %f %f emis %f %f %f spec %f %f %f shi %d trans %f
buffer = AcSkipToNextToken(buffer);
if ('\"' == *buffer) {
buffer = AcGetString(buffer, mat.name);
buffer = AcSkipToNextToken(buffer);
mBuffer.data = AcSkipToNextToken(mBuffer.data, mBuffer.end);
if ('\"' == *mBuffer.data) {
mBuffer.data = AcGetString(mBuffer.data, mBuffer.end, mat.name);
mBuffer.data = AcSkipToNextToken(mBuffer.data, mBuffer.end);
}
buffer = TAcCheckedLoadFloatArray(buffer, "rgb", 3, 3, &mat.rgb);
buffer = TAcCheckedLoadFloatArray(buffer, "amb", 3, 3, &mat.amb);
buffer = TAcCheckedLoadFloatArray(buffer, "emis", 4, 3, &mat.emis);
buffer = TAcCheckedLoadFloatArray(buffer, "spec", 4, 3, &mat.spec);
buffer = TAcCheckedLoadFloatArray(buffer, "shi", 3, 1, &mat.shin);
buffer = TAcCheckedLoadFloatArray(buffer, "trans", 5, 1, &mat.trans);
mBuffer.data = TAcCheckedLoadFloatArray(mBuffer.data, mBuffer.end, "rgb", 3, 3, &mat.rgb);
mBuffer.data = TAcCheckedLoadFloatArray(mBuffer.data, mBuffer.end, "amb", 3, 3, &mat.amb);
mBuffer.data = TAcCheckedLoadFloatArray(mBuffer.data, mBuffer.end, "emis", 4, 3, &mat.emis);
mBuffer.data = TAcCheckedLoadFloatArray(mBuffer.data, mBuffer.end, "spec", 4, 3, &mat.spec);
mBuffer.data = TAcCheckedLoadFloatArray(mBuffer.data, mBuffer.end, "shi", 3, 1, &mat.shin);
mBuffer.data = TAcCheckedLoadFloatArray(mBuffer.data, mBuffer.end, "trans", 5, 1, &mat.trans);
} else {
LoadObjectSection(rootObjects);
}
}
if (rootObjects.empty() || !mNumMeshes) {
if (rootObjects.empty() || mNumMeshes == 0u) {
throw DeadlyImportError("AC3D: No meshes have been loaded");
}
if (materials.empty()) {
@ -828,7 +821,7 @@ void AC3DImporter::InternReadFile(const std::string &pFile,
materials.reserve(mNumMeshes);
// generate a dummy root if there are multiple objects on the top layer
Object *root;
Object *root = nullptr;
if (1 == rootObjects.size())
root = &rootObjects[0];
else {
@ -841,7 +834,7 @@ void AC3DImporter::InternReadFile(const std::string &pFile,
delete root;
}
if (!::strncmp(pScene->mRootNode->mName.data, "Node", 4)) {
if (::strncmp(pScene->mRootNode->mName.data, "Node", 4) == 0) {
pScene->mRootNode->mName.Set("<AC3DWorld>");
}
@ -860,7 +853,7 @@ void AC3DImporter::InternReadFile(const std::string &pFile,
// copy lights
pScene->mNumLights = (unsigned int)lights.size();
if (lights.size()) {
if (!lights.empty()) {
pScene->mLights = new aiLight *[lights.size()];
::memcpy(pScene->mLights, &lights[0], lights.size() * sizeof(void *));
}

View File

@ -2,7 +2,7 @@
Open Asset Import Library (assimp)
----------------------------------------------------------------------
Copyright (c) 2006-2022, assimp team
Copyright (c) 2006-2024, assimp team
All rights reserved.
@ -242,7 +242,7 @@ private:
private:
// points to the next data line
const char *buffer;
aiBuffer mBuffer;
// Configuration option: if enabled, up to two meshes
// are generated per material: those faces who have

View File

@ -110,10 +110,12 @@ using namespace Assimp::ASE;
++filePtr;
// ------------------------------------------------------------------------------------------------
Parser::Parser(const char *szFile, unsigned int fileFormatDefault) {
Parser::Parser(const char *szFile, unsigned int fileFormatDefault) :
filePtr(nullptr), mEnd (nullptr) {
ai_assert(nullptr != szFile);
filePtr = szFile;
mEnd = filePtr + std::strlen(filePtr);
iFileFormat = fileFormatDefault;
// make sure that the color values are invalid
@ -179,14 +181,22 @@ bool Parser::SkipToNextToken() {
while (true) {
char me = *filePtr;
if (filePtr == mEnd) {
return false;
}
// increase the line number counter if necessary
if (IsLineEnd(me) && !bLastWasEndLine) {
++iLineNumber;
bLastWasEndLine = true;
} else
bLastWasEndLine = false;
if ('*' == me || '}' == me || '{' == me) return true;
if ('\0' == me) return false;
if ('*' == me || '}' == me || '{' == me) {
return true;
}
if ('\0' == me) {
return false;
}
++filePtr;
}
@ -344,8 +354,9 @@ void Parser::ParseLV1SoftSkinBlock() {
unsigned int numVerts = 0;
const char *sz = filePtr;
while (!IsSpaceOrNewLine(*filePtr))
while (!IsSpaceOrNewLine(*filePtr)) {
++filePtr;
}
const unsigned int diff = (unsigned int)(filePtr - sz);
if (diff) {
@ -363,24 +374,24 @@ void Parser::ParseLV1SoftSkinBlock() {
// Skip the mesh data - until we find a new mesh
// or the end of the *MESH_SOFTSKINVERTS section
while (true) {
SkipSpacesAndLineEnd(&filePtr);
SkipSpacesAndLineEnd(&filePtr, mEnd);
if (*filePtr == '}') {
++filePtr;
return;
} else if (!IsNumeric(*filePtr))
break;
SkipLine(&filePtr);
SkipLine(&filePtr, mEnd);
}
} else {
SkipSpacesAndLineEnd(&filePtr);
SkipSpacesAndLineEnd(&filePtr, mEnd);
ParseLV4MeshLong(numVerts);
// Reserve enough storage
curMesh->mBoneVertices.reserve(numVerts);
for (unsigned int i = 0; i < numVerts; ++i) {
SkipSpacesAndLineEnd(&filePtr);
SkipSpacesAndLineEnd(&filePtr, mEnd);
unsigned int numWeights;
ParseLV4MeshLong(numWeights);
@ -422,7 +433,7 @@ void Parser::ParseLV1SoftSkinBlock() {
if (*filePtr == '\0')
return;
++filePtr;
SkipSpacesAndLineEnd(&filePtr);
SkipSpacesAndLineEnd(&filePtr, mEnd);
}
}
@ -743,7 +754,7 @@ void Parser::ParseLV3MapBlock(Texture &map) {
// ------------------------------------------------------------------------------------------------
bool Parser::ParseString(std::string &out, const char *szName) {
char szBuffer[1024];
if (!SkipSpaces(&filePtr)) {
if (!SkipSpaces(&filePtr, mEnd)) {
ai_snprintf(szBuffer, 1024, "Unable to parse %s block: Unexpected EOL", szName);
LogWarning(szBuffer);
@ -1355,7 +1366,7 @@ void Parser::ParseLV4MeshBones(unsigned int iNumBones, ASE::Mesh &mesh) {
// Mesh bone with name ...
if (TokenMatch(filePtr, "MESH_BONE_NAME", 14)) {
// parse an index ...
if (SkipSpaces(&filePtr)) {
if (SkipSpaces(&filePtr, mEnd)) {
unsigned int iIndex = strtoul10(filePtr, &filePtr);
if (iIndex >= iNumBones) {
LogWarning("Bone index is out of bounds");
@ -1395,11 +1406,11 @@ void Parser::ParseLV4MeshBonesVertices(unsigned int iNumVertices, ASE::Mesh &mes
std::pair<int, float> pairOut;
while (true) {
// first parse the bone index ...
if (!SkipSpaces(&filePtr)) break;
if (!SkipSpaces(&filePtr, mEnd)) break;
pairOut.first = strtoul10(filePtr, &filePtr);
// then parse the vertex weight
if (!SkipSpaces(&filePtr)) break;
if (!SkipSpaces(&filePtr, mEnd)) break;
filePtr = fast_atoreal_move<float>(filePtr, pairOut.second);
// -1 marks unused entries
@ -1675,7 +1686,7 @@ void Parser::ParseLV3MeshNormalListBlock(ASE::Mesh &sMesh) {
// ------------------------------------------------------------------------------------------------
void Parser::ParseLV4MeshFace(ASE::Face &out) {
// skip spaces and tabs
if (!SkipSpaces(&filePtr)) {
if (!SkipSpaces(&filePtr, mEnd)) {
LogWarning("Unable to parse *MESH_FACE Element: Unexpected EOL [#1]");
SkipToNextToken();
return;
@ -1685,7 +1696,7 @@ void Parser::ParseLV4MeshFace(ASE::Face &out) {
out.iFace = strtoul10(filePtr, &filePtr);
// next character should be ':'
if (!SkipSpaces(&filePtr)) {
if (!SkipSpaces(&filePtr, mEnd)) {
// FIX: there are some ASE files which haven't got : here ....
LogWarning("Unable to parse *MESH_FACE Element: Unexpected EOL. \':\' expected [#2]");
SkipToNextToken();
@ -1697,7 +1708,7 @@ void Parser::ParseLV4MeshFace(ASE::Face &out) {
// Parse all mesh indices
for (unsigned int i = 0; i < 3; ++i) {
unsigned int iIndex = 0;
if (!SkipSpaces(&filePtr)) {
if (!SkipSpaces(&filePtr, mEnd)) {
LogWarning("Unable to parse *MESH_FACE Element: Unexpected EOL");
SkipToNextToken();
return;
@ -1723,7 +1734,7 @@ void Parser::ParseLV4MeshFace(ASE::Face &out) {
++filePtr;
// next character should be ':'
if (!SkipSpaces(&filePtr) || ':' != *filePtr) {
if (!SkipSpaces(&filePtr, mEnd) || ':' != *filePtr) {
LogWarning("Unable to parse *MESH_FACE Element: "
"Unexpected EOL. \':\' expected [#2]");
SkipToNextToken();
@ -1731,9 +1742,9 @@ void Parser::ParseLV4MeshFace(ASE::Face &out) {
}
++filePtr;
if (!SkipSpaces(&filePtr)) {
if (!SkipSpaces(&filePtr, mEnd)) {
LogWarning("Unable to parse *MESH_FACE Element: Unexpected EOL. "
"Vertex index ecpected [#4]");
"Vertex index expected [#4]");
SkipToNextToken();
return;
}
@ -1752,7 +1763,7 @@ void Parser::ParseLV4MeshFace(ASE::Face &out) {
// parse the smoothing group of the face
if (TokenMatch(filePtr, "*MESH_SMOOTHING", 15)) {
if (!SkipSpaces(&filePtr)) {
if (!SkipSpaces(&filePtr, mEnd)) {
LogWarning("Unable to parse *MESH_SMOOTHING Element: "
"Unexpected EOL. Smoothing group(s) expected [#5]");
SkipToNextToken();
@ -1771,12 +1782,12 @@ void Parser::ParseLV4MeshFace(ASE::Face &out) {
LogWarning(message.c_str());
}
}
SkipSpaces(&filePtr);
SkipSpaces(&filePtr, mEnd);
if (',' != *filePtr) {
break;
}
++filePtr;
SkipSpaces(&filePtr);
SkipSpaces(&filePtr, mEnd);
}
}
@ -1792,7 +1803,7 @@ void Parser::ParseLV4MeshFace(ASE::Face &out) {
}
if (TokenMatch(filePtr, "*MESH_MTLID", 11)) {
if (!SkipSpaces(&filePtr)) {
if (!SkipSpaces(&filePtr, mEnd)) {
LogWarning("Unable to parse *MESH_MTLID Element: Unexpected EOL. "
"Material index expected [#6]");
SkipToNextToken();
@ -1840,7 +1851,7 @@ void Parser::ParseLV4MeshFloatTriple(ai_real *apOut) {
// ------------------------------------------------------------------------------------------------
void Parser::ParseLV4MeshFloat(ai_real &fOut) {
// skip spaces and tabs
if (!SkipSpaces(&filePtr)) {
if (!SkipSpaces(&filePtr, mEnd)) {
// LOG
LogWarning("Unable to parse float: unexpected EOL [#1]");
fOut = 0.0;
@ -1853,7 +1864,7 @@ void Parser::ParseLV4MeshFloat(ai_real &fOut) {
// ------------------------------------------------------------------------------------------------
void Parser::ParseLV4MeshLong(unsigned int &iOut) {
// Skip spaces and tabs
if (!SkipSpaces(&filePtr)) {
if (!SkipSpaces(&filePtr, mEnd)) {
// LOG
LogWarning("Unable to parse long: unexpected EOL [#1]");
iOut = 0;

View File

@ -620,6 +620,9 @@ public:
//! Pointer to current data
const char *filePtr;
/// The end pointer of the file data
const char *mEnd;
//! background color to be passed to the viewer
//! QNAN if none was found
aiColor3D m_clrBackground;

View File

@ -473,8 +473,9 @@ void COBImporter::ReadBasicNodeInfo_Ascii(Node &msh, LineSplitter &splitter, con
} else if (splitter.match_start("Transform")) {
for (unsigned int y = 0; y < 4 && ++splitter; ++y) {
const char *s = splitter->c_str();
const char *end = s + splitter->size();
for (unsigned int x = 0; x < 4; ++x) {
SkipSpaces(&s);
SkipSpaces(&s, end);
msh.transform[y][x] = fast_atof(&s);
}
}
@ -486,12 +487,12 @@ void COBImporter::ReadBasicNodeInfo_Ascii(Node &msh, LineSplitter &splitter, con
// ------------------------------------------------------------------------------------------------
template <typename T>
void COBImporter::ReadFloat3Tuple_Ascii(T &fill, const char **in) {
void COBImporter::ReadFloat3Tuple_Ascii(T &fill, const char **in, const char *end) {
const char *rgb = *in;
for (unsigned int i = 0; i < 3; ++i) {
SkipSpaces(&rgb);
SkipSpaces(&rgb, end);
if (*rgb == ',') ++rgb;
SkipSpaces(&rgb);
SkipSpaces(&rgb, end);
fill[i] = fast_atof(&rgb);
}
@ -538,7 +539,7 @@ void COBImporter::ReadMat1_Ascii(Scene &out, LineSplitter &splitter, const Chunk
}
const char *rgb = splitter[1];
ReadFloat3Tuple_Ascii(mat.rgb, &rgb);
ReadFloat3Tuple_Ascii(mat.rgb, &rgb, splitter.getEnd());
++splitter;
if (!splitter.match_start("alpha ")) {
@ -617,20 +618,21 @@ void COBImporter::ReadLght_Ascii(Scene &out, LineSplitter &splitter, const Chunk
}
const char *rgb = splitter[1];
ReadFloat3Tuple_Ascii(msh.color, &rgb);
const char *end = splitter.getEnd();
ReadFloat3Tuple_Ascii(msh.color, &rgb, end);
SkipSpaces(&rgb);
SkipSpaces(&rgb, end);
if (strncmp(rgb, "cone angle", 10) != 0) {
ASSIMP_LOG_WARN("Expected `cone angle` entity in `color` line in `Lght` chunk ", nfo.id);
}
SkipSpaces(rgb + 10, &rgb);
SkipSpaces(rgb + 10, &rgb, end);
msh.angle = fast_atof(&rgb);
SkipSpaces(&rgb);
SkipSpaces(&rgb, end);
if (strncmp(rgb, "inner angle", 11) != 0) {
ASSIMP_LOG_WARN("Expected `inner angle` entity in `color` line in `Lght` chunk ", nfo.id);
}
SkipSpaces(rgb + 11, &rgb);
SkipSpaces(rgb + 11, &rgb, end);
msh.inner_angle = fast_atof(&rgb);
// skip the rest for we can't handle this kind of physically-based lighting information.
@ -703,14 +705,14 @@ void COBImporter::ReadPolH_Ascii(Scene &out, LineSplitter &splitter, const Chunk
for (unsigned int cur = 0; cur < cnt && ++splitter; ++cur) {
const char *s = splitter->c_str();
const char *end = splitter.getEnd();
aiVector3D &v = msh.vertex_positions[cur];
SkipSpaces(&s);
SkipSpaces(&s, end);
v.x = fast_atof(&s);
SkipSpaces(&s);
SkipSpaces(&s, end);
v.y = fast_atof(&s);
SkipSpaces(&s);
SkipSpaces(&s, end);
v.z = fast_atof(&s);
}
} else if (splitter.match_start("Texture Vertices")) {
@ -719,12 +721,13 @@ void COBImporter::ReadPolH_Ascii(Scene &out, LineSplitter &splitter, const Chunk
for (unsigned int cur = 0; cur < cnt && ++splitter; ++cur) {
const char *s = splitter->c_str();
const char *end = splitter.getEnd();
aiVector2D &v = msh.texture_coords[cur];
SkipSpaces(&s);
SkipSpaces(&s, end);
v.x = fast_atof(&s);
SkipSpaces(&s);
SkipSpaces(&s, end);
v.y = fast_atof(&s);
}
} else if (splitter.match_start("Faces")) {
@ -749,8 +752,9 @@ void COBImporter::ReadPolH_Ascii(Scene &out, LineSplitter &splitter, const Chunk
face.material = strtoul10(splitter[6]);
const char *s = (++splitter)->c_str();
const char *end = splitter.getEnd();
for (size_t i = 0; i < face.indices.size(); ++i) {
if (!SkipSpaces(&s)) {
if (!SkipSpaces(&s, end)) {
ThrowException("Expected EOL token in Face entry");
}
if ('<' != *s++) {

View File

@ -120,7 +120,7 @@ private:
void ReadChunkInfo_Ascii(COB::ChunkInfo &out, const LineSplitter &splitter);
void ReadBasicNodeInfo_Ascii(COB::Node &msh, LineSplitter &splitter, const COB::ChunkInfo &nfo);
template <typename T>
void ReadFloat3Tuple_Ascii(T &fill, const char **in);
void ReadFloat3Tuple_Ascii(T &fill, const char **in, const char *end);
void ReadPolH_Ascii(COB::Scene &out, LineSplitter &splitter, const COB::ChunkInfo &nfo);
void ReadBitM_Ascii(COB::Scene &out, LineSplitter &splitter, const COB::ChunkInfo &nfo);

View File

@ -82,23 +82,20 @@ CSMImporter::CSMImporter() : noSkeletonMesh(){
// ------------------------------------------------------------------------------------------------
// Returns whether the class can handle the format of the given file.
bool CSMImporter::CanRead( const std::string& pFile, IOSystem* pIOHandler, bool /*checkSig*/) const
{
bool CSMImporter::CanRead( const std::string& pFile, IOSystem* pIOHandler, bool /*checkSig*/) const {
static const char* tokens[] = {"$Filename"};
return SearchFileHeaderForToken(pIOHandler,pFile,tokens,AI_COUNT_OF(tokens));
}
// ------------------------------------------------------------------------------------------------
// Build a string of all file extensions supported
const aiImporterDesc* CSMImporter::GetInfo () const
{
const aiImporterDesc* CSMImporter::GetInfo () const {
return &desc;
}
// ------------------------------------------------------------------------------------------------
// Setup configuration properties for the loader
void CSMImporter::SetupProperties(const Importer* pImp)
{
void CSMImporter::SetupProperties(const Importer* pImp) {
noSkeletonMesh = pImp->GetPropertyInteger(AI_CONFIG_IMPORT_NO_SKELETON_MESHES,0) != 0;
}
@ -118,29 +115,29 @@ void CSMImporter::InternReadFile( const std::string& pFile,
std::vector<char> mBuffer2;
TextFileToBuffer(file.get(),mBuffer2);
const char* buffer = &mBuffer2[0];
const char *end = &mBuffer2[mBuffer2.size() - 1] + 1;
std::unique_ptr<aiAnimation> anim(new aiAnimation());
int first = 0, last = 0x00ffffff;
// now process the file and look out for '$' sections
while (true) {
SkipSpaces(&buffer);
SkipSpaces(&buffer, end);
if ('\0' == *buffer)
break;
if ('$' == *buffer) {
++buffer;
if (TokenMatchI(buffer,"firstframe",10)) {
SkipSpaces(&buffer);
SkipSpaces(&buffer, end);
first = strtol10(buffer,&buffer);
}
else if (TokenMatchI(buffer,"lastframe",9)) {
SkipSpaces(&buffer);
SkipSpaces(&buffer, end);
last = strtol10(buffer,&buffer);
}
else if (TokenMatchI(buffer,"rate",4)) {
SkipSpaces(&buffer);
float d;
SkipSpaces(&buffer, end);
float d = { 0.0f };
buffer = fast_atoreal_move<float>(buffer,d);
anim->mTicksPerSecond = d;
}
@ -148,8 +145,8 @@ void CSMImporter::InternReadFile( const std::string& pFile,
std::vector< aiNodeAnim* > anims_temp;
anims_temp.reserve(30);
while (true) {
SkipSpaces(&buffer);
if (IsLineEnd(*buffer) && SkipSpacesAndLineEnd(&buffer) && *buffer == '$')
SkipSpaces(&buffer, end);
if (IsLineEnd(*buffer) && SkipSpacesAndLineEnd(&buffer, end) && *buffer == '$')
break; // next section
// Construct a new node animation channel and setup its name
@ -157,41 +154,43 @@ void CSMImporter::InternReadFile( const std::string& pFile,
aiNodeAnim* nda = anims_temp.back();
char* ot = nda->mNodeName.data;
while (!IsSpaceOrNewLine(*buffer))
while (!IsSpaceOrNewLine(*buffer)) {
*ot++ = *buffer++;
}
*ot = '\0';
nda->mNodeName.length = static_cast<ai_uint32>(ot-nda->mNodeName.data);
}
anim->mNumChannels = static_cast<unsigned int>(anims_temp.size());
if (!anim->mNumChannels)
if (!anim->mNumChannels) {
throw DeadlyImportError("CSM: Empty $order section");
}
// copy over to the output animation
anim->mChannels = new aiNodeAnim*[anim->mNumChannels];
::memcpy(anim->mChannels,&anims_temp[0],sizeof(aiNodeAnim*)*anim->mNumChannels);
}
else if (TokenMatchI(buffer,"points",6)) {
if (!anim->mNumChannels)
} else if (TokenMatchI(buffer,"points",6)) {
if (!anim->mNumChannels) {
throw DeadlyImportError("CSM: \'$order\' section is required to appear prior to \'$points\'");
}
// If we know how many frames we'll read, we can preallocate some storage
unsigned int alloc = 100;
if (last != 0x00ffffff)
{
if (last != 0x00ffffff) {
alloc = last-first;
alloc += alloc>>2u; // + 25%
for (unsigned int i = 0; i < anim->mNumChannels;++i)
for (unsigned int i = 0; i < anim->mNumChannels; ++i) {
anim->mChannels[i]->mPositionKeys = new aiVectorKey[alloc];
}
}
unsigned int filled = 0;
// Now read all point data.
while (true) {
SkipSpaces(&buffer);
if (IsLineEnd(*buffer) && (!SkipSpacesAndLineEnd(&buffer) || *buffer == '$')) {
SkipSpaces(&buffer, end);
if (IsLineEnd(*buffer) && (!SkipSpacesAndLineEnd(&buffer, end) || *buffer == '$')) {
break; // next section
}
@ -202,8 +201,8 @@ void CSMImporter::InternReadFile( const std::string& pFile,
for (unsigned int i = 0; i < anim->mNumChannels;++i) {
aiNodeAnim* s = anim->mChannels[i];
if (s->mNumPositionKeys == alloc) { /* need to reallocate? */
if (s->mNumPositionKeys == alloc) {
// need to reallocate?
aiVectorKey* old = s->mPositionKeys;
s->mPositionKeys = new aiVectorKey[s->mNumPositionKeys = alloc*2];
::memcpy(s->mPositionKeys,old,sizeof(aiVectorKey)*alloc);
@ -211,24 +210,26 @@ void CSMImporter::InternReadFile( const std::string& pFile,
}
// read x,y,z
if(!SkipSpacesAndLineEnd(&buffer))
if (!SkipSpacesAndLineEnd(&buffer, end)) {
throw DeadlyImportError("CSM: Unexpected EOF occurred reading sample x coord");
}
if (TokenMatchI(buffer, "DROPOUT", 7)) {
// seems this is invalid marker data; at least the doc says it's possible
ASSIMP_LOG_WARN("CSM: Encountered invalid marker data (DROPOUT)");
}
else {
} else {
aiVectorKey* sub = s->mPositionKeys + s->mNumPositionKeys;
sub->mTime = (double)frame;
buffer = fast_atoreal_move<float>(buffer, (float&)sub->mValue.x);
if(!SkipSpacesAndLineEnd(&buffer))
if (!SkipSpacesAndLineEnd(&buffer, end)) {
throw DeadlyImportError("CSM: Unexpected EOF occurred reading sample y coord");
}
buffer = fast_atoreal_move<float>(buffer, (float&)sub->mValue.y);
if(!SkipSpacesAndLineEnd(&buffer))
if (!SkipSpacesAndLineEnd(&buffer, end)) {
throw DeadlyImportError("CSM: Unexpected EOF occurred reading sample z coord");
}
buffer = fast_atoreal_move<float>(buffer, (float&)sub->mValue.z);
++s->mNumPositionKeys;
@ -236,22 +237,22 @@ void CSMImporter::InternReadFile( const std::string& pFile,
}
// update allocation granularity
if (filled == alloc)
if (filled == alloc) {
alloc *= 2;
}
++filled;
}
// all channels must be complete in order to continue safely.
for (unsigned int i = 0; i < anim->mNumChannels;++i) {
if (!anim->mChannels[i]->mNumPositionKeys)
if (!anim->mChannels[i]->mNumPositionKeys) {
throw DeadlyImportError("CSM: Invalid marker track");
}
}
}
}
else {
} else {
// advance to the next line
SkipLine(&buffer);
SkipLine(&buffer, end);
}
}
@ -265,7 +266,7 @@ void CSMImporter::InternReadFile( const std::string& pFile,
pScene->mRootNode->mNumChildren = anim->mNumChannels;
pScene->mRootNode->mChildren = new aiNode* [anim->mNumChannels];
for (unsigned int i = 0; i < anim->mNumChannels;++i) {
for (unsigned int i = 0; i < anim->mNumChannels;++i) {
aiNodeAnim* na = anim->mChannels[i];
aiNode* nd = pScene->mRootNode->mChildren[i] = new aiNode();

View File

@ -654,12 +654,13 @@ void ColladaParser::ReadController(XmlNode &node, Collada::Controller &controlle
std::string v;
XmlParser::getValueAsString(currentNode, v);
const char *content = v.c_str();
const char *end = content + v.size();
for (unsigned int a = 0; a < 16; a++) {
SkipSpacesAndLineEnd(&content);
SkipSpacesAndLineEnd(&content, end);
// read a number
content = fast_atoreal_move<ai_real>(content, controller.mBindShapeMatrix[a]);
// skip whitespace after it
SkipSpacesAndLineEnd(&content);
SkipSpacesAndLineEnd(&content, end);
}
} else if (currentName == "source") {
ReadSource(currentNode);
@ -740,7 +741,9 @@ void ColladaParser::ReadControllerWeights(XmlNode &node, Collada::Controller &pC
throw DeadlyImportError("Unknown semantic \"", attrSemantic, "\" in <vertex_weights> data <input> element");
}
} else if (currentName == "vcount" && vertexCount > 0) {
const char *text = currentNode.text().as_string();
const std::string stdText = currentNode.text().as_string();
const char *text = stdText.c_str();
const char *end = text + stdText.size();
size_t numWeights = 0;
for (std::vector<size_t>::iterator it = pController.mWeightCounts.begin(); it != pController.mWeightCounts.end(); ++it) {
if (*text == 0) {
@ -749,7 +752,7 @@ void ColladaParser::ReadControllerWeights(XmlNode &node, Collada::Controller &pC
*it = strtoul10(text, &text);
numWeights += *it;
SkipSpacesAndLineEnd(&text);
SkipSpacesAndLineEnd(&text, end);
}
// reserve weight count
pController.mWeights.resize(numWeights);
@ -758,18 +761,19 @@ void ColladaParser::ReadControllerWeights(XmlNode &node, Collada::Controller &pC
std::string stdText;
XmlParser::getValueAsString(currentNode, stdText);
const char *text = stdText.c_str();
const char *end = text + stdText.size();
for (std::vector<std::pair<size_t, size_t>>::iterator it = pController.mWeights.begin(); it != pController.mWeights.end(); ++it) {
if (text == nullptr) {
throw DeadlyImportError("Out of data while reading <vertex_weights>");
}
SkipSpacesAndLineEnd(&text);
SkipSpacesAndLineEnd(&text, end);
it->first = strtoul10(text, &text);
SkipSpacesAndLineEnd(&text);
SkipSpacesAndLineEnd(&text, end);
if (*text == 0) {
throw DeadlyImportError("Out of data while reading <vertex_weights>");
}
it->second = strtoul10(text, &text);
SkipSpacesAndLineEnd(&text);
SkipSpacesAndLineEnd(&text, end);
}
}
}
@ -952,15 +956,16 @@ void ColladaParser::ReadLight(XmlNode &node, Collada::Light &pLight) {
std::string v;
XmlParser::getValueAsString(currentNode, v);
const char *content = v.c_str();
const char *end = content + v.size();
content = fast_atoreal_move<ai_real>(content, (ai_real &)pLight.mColor.r);
SkipSpacesAndLineEnd(&content);
SkipSpacesAndLineEnd(&content, end);
content = fast_atoreal_move<ai_real>(content, (ai_real &)pLight.mColor.g);
SkipSpacesAndLineEnd(&content);
SkipSpacesAndLineEnd(&content, end);
content = fast_atoreal_move<ai_real>(content, (ai_real &)pLight.mColor.b);
SkipSpacesAndLineEnd(&content);
SkipSpacesAndLineEnd(&content, end);
} else if (currentName == "constant_attenuation") {
XmlParser::getValueAsFloat(currentNode, pLight.mAttConstant);
} else if (currentName == "linear_attenuation") {
@ -1220,18 +1225,19 @@ void ColladaParser::ReadEffectColor(XmlNode &node, aiColor4D &pColor, Sampler &p
std::string v;
XmlParser::getValueAsString(currentNode, v);
const char *content = v.c_str();
const char *end = v.c_str() + v.size() + 1;
content = fast_atoreal_move<ai_real>(content, (ai_real &)pColor.r);
SkipSpacesAndLineEnd(&content);
SkipSpacesAndLineEnd(&content, end);
content = fast_atoreal_move<ai_real>(content, (ai_real &)pColor.g);
SkipSpacesAndLineEnd(&content);
SkipSpacesAndLineEnd(&content, end);
content = fast_atoreal_move<ai_real>(content, (ai_real &)pColor.b);
SkipSpacesAndLineEnd(&content);
SkipSpacesAndLineEnd(&content, end);
content = fast_atoreal_move<ai_real>(content, (ai_real &)pColor.a);
SkipSpacesAndLineEnd(&content);
SkipSpacesAndLineEnd(&content, end);
} else if (currentName == "texture") {
// get name of source texture/sampler
XmlParser::getStdStrAttribute(currentNode, "texture", pSampler.mName);
@ -1345,6 +1351,7 @@ void ColladaParser::ReadGeometry(XmlNode &node, Collada::Mesh &pMesh) {
if (node.empty()) {
return;
}
for (XmlNode &currentNode : node.children()) {
const std::string &currentName = currentNode.name();
if (currentName == "mesh") {
@ -1415,6 +1422,7 @@ void ColladaParser::ReadDataArray(XmlNode &node) {
XmlParser::getValueAsString(node, v);
v = ai_trim(v);
const char *content = v.c_str();
const char *end = content + v.size();
// read values and store inside an array in the data library
mDataLibrary[id] = Data();
@ -1433,11 +1441,13 @@ void ColladaParser::ReadDataArray(XmlNode &node) {
}
s.clear();
while (!IsSpaceOrNewLine(*content))
s += *content++;
while (!IsSpaceOrNewLine(*content)) {
s += *content;
content++;
}
data.mStrings.push_back(s);
SkipSpacesAndLineEnd(&content);
SkipSpacesAndLineEnd(&content, end);
}
} else {
data.mValues.reserve(count);
@ -1452,7 +1462,7 @@ void ColladaParser::ReadDataArray(XmlNode &node) {
content = fast_atoreal_move<ai_real>(content, value);
data.mValues.push_back(value);
// skip whitespace after it
SkipSpacesAndLineEnd(&content);
SkipSpacesAndLineEnd(&content, end);
}
}
}
@ -1617,8 +1627,10 @@ void ColladaParser::ReadIndexData(XmlNode &node, Mesh &pMesh) {
std::string v;
XmlParser::getValueAsString(currentNode, v);
const char *content = v.c_str();
const char *end = content + v.size();
vcount.reserve(numPrimitives);
SkipSpacesAndLineEnd(&content);
SkipSpacesAndLineEnd(&content, end);
for (unsigned int a = 0; a < numPrimitives; a++) {
if (*content == 0) {
throw DeadlyImportError("Expected more values while reading <vcount> contents.");
@ -1626,7 +1638,7 @@ void ColladaParser::ReadIndexData(XmlNode &node, Mesh &pMesh) {
// read a number
vcount.push_back((size_t)strtoul10(content, &content));
// skip whitespace after it
SkipSpacesAndLineEnd(&content);
SkipSpacesAndLineEnd(&content, end);
}
}
}
@ -1735,14 +1747,16 @@ size_t ColladaParser::ReadPrimitives(XmlNode &node, Mesh &pMesh, std::vector<Inp
std::string v;
XmlParser::getValueAsString(node, v);
const char *content = v.c_str();
SkipSpacesAndLineEnd(&content);
const char *end = content + v.size();
SkipSpacesAndLineEnd(&content, end);
while (*content != 0) {
// read a value.
// Hack: (thom) Some exporters put negative indices sometimes. We just try to carry on anyways.
int value = std::max(0, strtol10(content, &content));
indices.push_back(size_t(value));
// skip whitespace after it
SkipSpacesAndLineEnd(&content);
SkipSpacesAndLineEnd(&content, end);
}
}
@ -1801,8 +1815,10 @@ size_t ColladaParser::ReadPrimitives(XmlNode &node, Mesh &pMesh, std::vector<Inp
// For continued primitives, the given count does not come all in one <p>, but only one primitive per <p>
size_t numPrimitives = pNumPrimitives;
if (pPrimType == Prim_TriFans || pPrimType == Prim_Polygon)
if (pPrimType == Prim_TriFans || pPrimType == Prim_Polygon) {
numPrimitives = 1;
}
// For continued primitives, the given count is actually the number of <p>'s inside the parent tag
if (pPrimType == Prim_TriStrips) {
size_t numberOfVertices = indices.size() / numOffsets;
@ -2166,15 +2182,15 @@ void ColladaParser::ReadNodeTransformation(XmlNode &node, Node *pNode, Transform
}
// how many parameters to read per transformation type
static const unsigned int sNumParameters[] = { 9, 4, 3, 3, 7, 16 };
static constexpr unsigned int sNumParameters[] = { 9, 4, 3, 3, 7, 16 };
std::string value;
XmlParser::getValueAsString(node, value);
const char *content = value.c_str();
const char *end = value.c_str() + value.size();
// read as many parameters and store in the transformation
for (unsigned int a = 0; a < sNumParameters[pType]; a++) {
// skip whitespace before the number
SkipSpacesAndLineEnd(&content);
SkipSpacesAndLineEnd(&content, end);
// read a number
content = fast_atoreal_move<ai_real>(content, tf.f[a]);
}

View File

@ -250,7 +250,9 @@ void IRRMeshImporter::InternReadFile(const std::string &pFile,
};
// We know what format buffer is, collect numbers
ParseBufferVertices(verticesNode.text().get(), vertexFormat,
std::string v = verticesNode.text().get();
const char *end = v.c_str() + v.size();
ParseBufferVertices(v.c_str(), end, vertexFormat,
curVertices, curNormals,
curTangents, curBitangents,
curUVs, curUV2s, curColors, useColors);
@ -329,8 +331,9 @@ void IRRMeshImporter::InternReadFile(const std::string &pFile,
// NOTE this might explode for UTF-16 and wchars
const char *sz = indicesNode.text().get();
const char *end = sz + std::strlen(sz) + 1;
// For each index loop over aiMesh faces
while (SkipSpacesAndLineEnd(&sz)) {
while (SkipSpacesAndLineEnd(&sz, end)) {
if (curFace >= faceEnd) {
ASSIMP_LOG_ERROR("IRRMESH: Too many indices");
break;
@ -354,12 +357,18 @@ void IRRMeshImporter::InternReadFile(const std::string &pFile,
// Copy over data to aiMesh
*pcV++ = curVertices[idx];
if (pcN) *pcN++ = curNormals[idx];
if (pcT) *pcT++ = curTangents[idx];
if (pcB) *pcB++ = curBitangents[idx];
if (pcC0) *pcC0++ = curColors[idx];
if (pcT0) *pcT0++ = curUVs[idx];
if (pcT1) *pcT1++ = curUV2s[idx];
if (pcN)
*pcN++ = curNormals[idx];
if (pcT)
*pcT++ = curTangents[idx];
if (pcB)
*pcB++ = curBitangents[idx];
if (pcC0)
*pcC0++ = curColors[idx];
if (pcT0)
*pcT0++ = curUVs[idx];
if (pcT1)
*pcT1++ = curUV2s[idx];
// start new face
if (++curIdx == 3) {
@ -421,37 +430,37 @@ void IRRMeshImporter::InternReadFile(const std::string &pFile,
};
}
void IRRMeshImporter::ParseBufferVertices(const char *sz, VertexFormat vertexFormat,
void IRRMeshImporter::ParseBufferVertices(const char *sz, const char *end, VertexFormat vertexFormat,
std::vector<aiVector3D> &vertices, std::vector<aiVector3D> &normals,
std::vector<aiVector3D> &tangents, std::vector<aiVector3D> &bitangents,
std::vector<aiVector3D> &UVs, std::vector<aiVector3D> &UV2s,
std::vector<aiColor4D> &colors, bool &useColors) {
// read vertices
do {
SkipSpacesAndLineEnd(&sz);
SkipSpacesAndLineEnd(&sz, end);
aiVector3D temp;
aiColor4D c;
// Read the vertex position
sz = fast_atoreal_move<float>(sz, (float &)temp.x);
SkipSpaces(&sz);
SkipSpaces(&sz, end);
sz = fast_atoreal_move<float>(sz, (float &)temp.y);
SkipSpaces(&sz);
SkipSpaces(&sz, end);
sz = fast_atoreal_move<float>(sz, (float &)temp.z);
SkipSpaces(&sz);
SkipSpaces(&sz, end);
vertices.push_back(temp);
// Read the vertex normals
sz = fast_atoreal_move<float>(sz, (float &)temp.x);
SkipSpaces(&sz);
SkipSpaces(&sz, end);
sz = fast_atoreal_move<float>(sz, (float &)temp.y);
SkipSpaces(&sz);
SkipSpaces(&sz, end);
sz = fast_atoreal_move<float>(sz, (float &)temp.z);
SkipSpaces(&sz);
SkipSpaces(&sz, end);
normals.push_back(temp);
// read the vertex colors
@ -463,14 +472,14 @@ void IRRMeshImporter::ParseBufferVertices(const char *sz, VertexFormat vertexFor
useColors = true;
colors.push_back(c);
SkipSpaces(&sz);
SkipSpaces(&sz, end);
// read the first UV coordinate set
sz = fast_atoreal_move<float>(sz, (float &)temp.x);
SkipSpaces(&sz);
SkipSpaces(&sz, end);
sz = fast_atoreal_move<float>(sz, (float &)temp.y);
SkipSpaces(&sz);
SkipSpaces(&sz, end);
temp.z = 0.f;
temp.y = 1.f - temp.y; // DX to OGL
UVs.push_back(temp);
@ -480,7 +489,7 @@ void IRRMeshImporter::ParseBufferVertices(const char *sz, VertexFormat vertexFor
// read the (optional) second UV coordinate set
if (vertexFormat == VertexFormat::t2coord) {
sz = fast_atoreal_move<float>(sz, (float &)temp.x);
SkipSpaces(&sz);
SkipSpaces(&sz, end);
sz = fast_atoreal_move<float>(sz, (float &)temp.y);
temp.y = 1.f - temp.y; // DX to OGL
@ -490,33 +499,32 @@ void IRRMeshImporter::ParseBufferVertices(const char *sz, VertexFormat vertexFor
else if (vertexFormat == VertexFormat::tangent) {
// tangents
sz = fast_atoreal_move<float>(sz, (float &)temp.x);
SkipSpaces(&sz);
SkipSpaces(&sz, end);
sz = fast_atoreal_move<float>(sz, (float &)temp.z);
SkipSpaces(&sz);
SkipSpaces(&sz, end);
sz = fast_atoreal_move<float>(sz, (float &)temp.y);
SkipSpaces(&sz);
SkipSpaces(&sz, end);
temp.y *= -1.0f;
tangents.push_back(temp);
// bitangents
sz = fast_atoreal_move<float>(sz, (float &)temp.x);
SkipSpaces(&sz);
SkipSpaces(&sz, end);
sz = fast_atoreal_move<float>(sz, (float &)temp.z);
SkipSpaces(&sz);
SkipSpaces(&sz, end);
sz = fast_atoreal_move<float>(sz, (float &)temp.y);
SkipSpaces(&sz);
SkipSpaces(&sz, end);
temp.y *= -1.0f;
bitangents.push_back(temp);
}
} while (SkipLine(&sz));
/* IMPORTANT: We assume that each vertex is specified in one
line. So we can skip the rest of the line - unknown vertex
elements are ignored.
*/
} while (SkipLine(&sz, end));
// IMPORTANT: We assume that each vertex is specified in one
// line. So we can skip the rest of the line - unknown vertex
// elements are ignored.
}
#endif // !! ASSIMP_BUILD_NO_IRRMESH_IMPORTER

View File

@ -93,7 +93,7 @@ private:
tangent = 2, // "tangents" - standard + tangents and bitangents
};
void ParseBufferVertices(const char *sz, VertexFormat vertexFormat,
void ParseBufferVertices(const char *sz, const char *end, VertexFormat vertexFormat,
std::vector<aiVector3D> &vertices, std::vector<aiVector3D> &normals,
std::vector<aiVector3D> &tangents, std::vector<aiVector3D> &bitangents,
std::vector<aiVector3D> &UVs, std::vector<aiVector3D> &UV2s,

View File

@ -135,21 +135,23 @@ void IrrlichtBase::ReadVectorProperty(VectorProperty &out, pugi::xml_node& vecto
} else if (!ASSIMP_stricmp(attrib.name(), "value")) {
// three floats, separated with commas
const char *ptr = attrib.value();
size_t len = std::strlen(ptr);
const char *end = ptr + len;
SkipSpaces(&ptr);
SkipSpaces(&ptr, end);
ptr = fast_atoreal_move<float>(ptr, (float &)out.value.x);
SkipSpaces(&ptr);
SkipSpaces(&ptr, end);
if (',' != *ptr) {
ASSIMP_LOG_ERROR("IRR(MESH): Expected comma in vector definition");
} else {
SkipSpaces(ptr + 1, &ptr);
SkipSpaces(ptr + 1, &ptr, end);
}
ptr = fast_atoreal_move<float>(ptr, (float &)out.value.y);
SkipSpaces(&ptr);
SkipSpaces(&ptr, end);
if (',' != *ptr) {
ASSIMP_LOG_ERROR("IRR(MESH): Expected comma in vector definition");
} else {
SkipSpaces(ptr + 1, &ptr);
SkipSpaces(ptr + 1, &ptr, end);
}
ptr = fast_atoreal_move<float>(ptr, (float &)out.value.z);
}

View File

@ -152,7 +152,7 @@ void LWOImporter::CountVertsAndFacesLWOB(unsigned int& verts, unsigned int& face
}
// ------------------------------------------------------------------------------------------------
void LWOImporter::CopyFaceIndicesLWOB(FaceList::iterator& it,
void LWOImporter::CopyFaceIndicesLWOB(FaceList::iterator &it,
LE_NCONST uint16_t*& cursor,
const uint16_t* const end,
unsigned int max) {

View File

@ -78,14 +78,14 @@ static constexpr aiImporterDesc desc = {
// ------------------------------------------------------------------------------------------------
// Recursive parsing of LWS files
void LWS::Element::Parse(const char *&buffer) {
for (; SkipSpacesAndLineEnd(&buffer); SkipLine(&buffer)) {
void LWS::Element::Parse(const char *&buffer, const char *end) {
for (; SkipSpacesAndLineEnd(&buffer, end); SkipLine(&buffer, end)) {
// begin of a new element with children
bool sub = false;
if (*buffer == '{') {
++buffer;
SkipSpaces(&buffer);
SkipSpaces(&buffer, end);
sub = true;
} else if (*buffer == '}')
return;
@ -98,16 +98,15 @@ void LWS::Element::Parse(const char *&buffer) {
while (!IsSpaceOrNewLine(*buffer))
++buffer;
children.back().tokens[0] = std::string(cur, (size_t)(buffer - cur));
SkipSpaces(&buffer);
SkipSpaces(&buffer, end);
if (children.back().tokens[0] == "Plugin") {
ASSIMP_LOG_VERBOSE_DEBUG("LWS: Skipping over plugin-specific data");
// strange stuff inside Plugin/Endplugin blocks. Needn't
// follow LWS syntax, so we skip over it
for (; SkipSpacesAndLineEnd(&buffer); SkipLine(&buffer)) {
for (; SkipSpacesAndLineEnd(&buffer, end); SkipLine(&buffer, end)) {
if (!::strncmp(buffer, "EndPlugin", 9)) {
//SkipLine(&buffer);
break;
}
}
@ -122,7 +121,7 @@ void LWS::Element::Parse(const char *&buffer) {
// parse more elements recursively
if (sub) {
children.back().Parse(buffer);
children.back().Parse(buffer, end);
}
}
}
@ -155,7 +154,8 @@ const aiImporterDesc *LWSImporter::GetInfo() const {
return &desc;
}
// ------------------------------------------------------------------------------------------------
static constexpr int MagicHackNo = 150392;
// ------------------------------------------------------------------------------------------------
// Setup configuration properties
void LWSImporter::SetupProperties(const Importer *pImp) {
// AI_CONFIG_FAVOUR_SPEED
@ -163,11 +163,11 @@ void LWSImporter::SetupProperties(const Importer *pImp) {
// AI_CONFIG_IMPORT_LWS_ANIM_START
first = pImp->GetPropertyInteger(AI_CONFIG_IMPORT_LWS_ANIM_START,
150392 /* magic hack */);
MagicHackNo /* magic hack */);
// AI_CONFIG_IMPORT_LWS_ANIM_END
last = pImp->GetPropertyInteger(AI_CONFIG_IMPORT_LWS_ANIM_END,
150392 /* magic hack */);
MagicHackNo /* magic hack */);
if (last < first) {
std::swap(last, first);
@ -191,15 +191,16 @@ void LWSImporter::ReadEnvelope(const LWS::Element &dad, LWO::Envelope &fill) {
for (++it; it != dad.children.end(); ++it) {
const char *c = (*it).tokens[1].c_str();
const char *end = c + (*it).tokens[1].size();
if ((*it).tokens[0] == "Key") {
fill.keys.emplace_back();
LWO::Key &key = fill.keys.back();
float f;
SkipSpaces(&c);
SkipSpaces(&c, end);
c = fast_atoreal_move<float>(c, key.value);
SkipSpaces(&c);
SkipSpaces(&c, end);
c = fast_atoreal_move<float>(c, f);
key.time = f;
@ -231,13 +232,13 @@ void LWSImporter::ReadEnvelope(const LWS::Element &dad, LWO::Envelope &fill) {
ASSIMP_LOG_ERROR("LWS: Unknown span type");
}
for (unsigned int i = 0; i < num; ++i) {
SkipSpaces(&c);
SkipSpaces(&c, end);
c = fast_atoreal_move<float>(c, key.params[i]);
}
} else if ((*it).tokens[0] == "Behaviors") {
SkipSpaces(&c);
SkipSpaces(&c, end);
fill.pre = (LWO::PrePostBehaviour)strtoul10(c, &c);
SkipSpaces(&c);
SkipSpaces(&c, end);
fill.post = (LWO::PrePostBehaviour)strtoul10(c, &c);
}
}
@ -245,36 +246,39 @@ void LWSImporter::ReadEnvelope(const LWS::Element &dad, LWO::Envelope &fill) {
// ------------------------------------------------------------------------------------------------
// Read animation channels in the old LightWave animation format
void LWSImporter::ReadEnvelope_Old(
std::list<LWS::Element>::const_iterator &it,
const std::list<LWS::Element>::const_iterator &end,
LWS::NodeDesc &nodes,
unsigned int /*version*/) {
unsigned int num, sub_num;
if (++it == end) goto unexpected_end;
void LWSImporter::ReadEnvelope_Old(std::list<LWS::Element>::const_iterator &it,const std::list<LWS::Element>::const_iterator &endIt,
LWS::NodeDesc &nodes, unsigned int) {
unsigned int num=0, sub_num=0;
if (++it == endIt) {
ASSIMP_LOG_ERROR("LWS: Encountered unexpected end of file while parsing object motion");
return;
}
num = strtoul10((*it).tokens[0].c_str());
for (unsigned int i = 0; i < num; ++i) {
nodes.channels.emplace_back();
LWO::Envelope &envl = nodes.channels.back();
envl.index = i;
envl.type = (LWO::EnvelopeType)(i + 1);
if (++it == end) {
goto unexpected_end;
if (++it == endIt) {
ASSIMP_LOG_ERROR("LWS: Encountered unexpected end of file while parsing object motion");
return;
}
sub_num = strtoul10((*it).tokens[0].c_str());
for (unsigned int n = 0; n < sub_num; ++n) {
if (++it == end) goto unexpected_end;
if (++it == endIt) {
ASSIMP_LOG_ERROR("LWS: Encountered unexpected end of file while parsing object motion");
return;
}
// parse value and time, skip the rest for the moment.
LWO::Key key;
const char *c = fast_atoreal_move<float>((*it).tokens[0].c_str(), key.value);
SkipSpaces(&c);
const char *end = c + (*it).tokens[0].size();
SkipSpaces(&c, end);
float f;
fast_atoreal_move<float>((*it).tokens[0].c_str(), f);
key.time = f;
@ -282,10 +286,6 @@ void LWSImporter::ReadEnvelope_Old(
envl.keys.push_back(key);
}
}
return;
unexpected_end:
ASSIMP_LOG_ERROR("LWS: Encountered unexpected end of file while parsing object motion");
}
// ------------------------------------------------------------------------------------------------
@ -296,7 +296,6 @@ void LWSImporter::SetupNodeName(aiNode *nd, LWS::NodeDesc &src) {
// the name depends on the type. We break LWS's strange naming convention
// and return human-readable, but still machine-parsable and unique, strings.
if (src.type == LWS::NodeDesc::OBJECT) {
if (src.path.length()) {
std::string::size_type s = src.path.find_last_of("\\/");
if (s == std::string::npos) {
@ -501,7 +500,8 @@ void LWSImporter::InternReadFile(const std::string &pFile, aiScene *pScene, IOSy
// Parse the file structure
LWS::Element root;
const char *dummy = &mBuffer[0];
root.Parse(dummy);
const char *dummyEnd = dummy + mBuffer.size();
root.Parse(dummy, dummyEnd);
// Construct a Batch-importer to read more files recursively
BatchLoader batch(pIOHandler);
@ -540,6 +540,7 @@ void LWSImporter::InternReadFile(const std::string &pFile, aiScene *pScene, IOSy
// Now read all elements in a very straightforward manner
for (; it != root.children.end(); ++it) {
const char *c = (*it).tokens[1].c_str();
const char *end = c + (*it).tokens[1].size();
// 'FirstFrame': begin of animation slice
if ((*it).tokens[0] == "FirstFrame") {
@ -567,14 +568,14 @@ void LWSImporter::InternReadFile(const std::string &pFile, aiScene *pScene, IOSy
LWS::NodeDesc d;
d.type = LWS::NodeDesc::OBJECT;
if (version >= 4) { // handle LWSC 4 explicit ID
SkipSpaces(&c);
SkipSpaces(&c, end);
d.number = strtoul16(c, &c) & AI_LWS_MASK;
} else {
d.number = cur_object++;
}
// and add the file to the import list
SkipSpaces(&c);
SkipSpaces(&c, end);
std::string path = FindLWOFile(c);
d.path = path;
d.id = batch.AddLoadRequest(path, 0, &props);
@ -588,7 +589,7 @@ void LWSImporter::InternReadFile(const std::string &pFile, aiScene *pScene, IOSy
if (version >= 4) { // handle LWSC 4 explicit ID
d.number = strtoul16(c, &c) & AI_LWS_MASK;
SkipSpaces(&c);
SkipSpaces(&c, end);
} else {
d.number = cur_object++;
}
@ -604,7 +605,7 @@ void LWSImporter::InternReadFile(const std::string &pFile, aiScene *pScene, IOSy
d.type = LWS::NodeDesc::OBJECT;
if (version >= 4) { // handle LWSC 4 explicit ID
d.number = strtoul16(c, &c) & AI_LWS_MASK;
SkipSpaces(&c);
SkipSpaces(&c, end);
} else {
d.number = cur_object++;
}
@ -668,26 +669,25 @@ void LWSImporter::InternReadFile(const std::string &pFile, aiScene *pScene, IOSy
// two ints per envelope
LWO::Envelope &env = *envelopeIt;
env.pre = (LWO::PrePostBehaviour)strtoul10(c, &c);
SkipSpaces(&c);
SkipSpaces(&c, end);
env.post = (LWO::PrePostBehaviour)strtoul10(c, &c);
SkipSpaces(&c);
SkipSpaces(&c, end);
}
}
}
// 'ParentItem': specifies the parent of the current element
else if ((*it).tokens[0] == "ParentItem") {
if (nodes.empty())
if (nodes.empty()) {
ASSIMP_LOG_ERROR("LWS: Unexpected keyword: \'ParentItem\'");
else
} else {
nodes.back().parent = strtoul16(c, &c);
}
}
// 'ParentObject': deprecated one for older formats
else if (version < 3 && (*it).tokens[0] == "ParentObject") {
if (nodes.empty())
if (nodes.empty()) {
ASSIMP_LOG_ERROR("LWS: Unexpected keyword: \'ParentObject\'");
else {
} else {
nodes.back().parent = strtoul10(c, &c) | (1u << 28u);
}
}
@ -700,19 +700,20 @@ void LWSImporter::InternReadFile(const std::string &pFile, aiScene *pScene, IOSy
if (version >= 4) { // handle LWSC 4 explicit ID
d.number = strtoul16(c, &c) & AI_LWS_MASK;
} else
} else {
d.number = cur_camera++;
}
nodes.push_back(d);
num_camera++;
}
// 'CameraName': set name of currently active camera
else if ((*it).tokens[0] == "CameraName") {
if (nodes.empty() || nodes.back().type != LWS::NodeDesc::CAMERA)
if (nodes.empty() || nodes.back().type != LWS::NodeDesc::CAMERA) {
ASSIMP_LOG_ERROR("LWS: Unexpected keyword: \'CameraName\'");
else
} else {
nodes.back().name = c;
}
}
// 'AddLight': add a light to the scenegraph
else if ((*it).tokens[0] == "AddLight") {
@ -723,19 +724,20 @@ void LWSImporter::InternReadFile(const std::string &pFile, aiScene *pScene, IOSy
if (version >= 4) { // handle LWSC 4 explicit ID
d.number = strtoul16(c, &c) & AI_LWS_MASK;
} else
} else {
d.number = cur_light++;
}
nodes.push_back(d);
num_light++;
}
// 'LightName': set name of currently active light
else if ((*it).tokens[0] == "LightName") {
if (nodes.empty() || nodes.back().type != LWS::NodeDesc::LIGHT)
if (nodes.empty() || nodes.back().type != LWS::NodeDesc::LIGHT) {
ASSIMP_LOG_ERROR("LWS: Unexpected keyword: \'LightName\'");
else
} else {
nodes.back().name = c;
}
}
// 'LightIntensity': set intensity of currently active light
else if ((*it).tokens[0] == "LightIntensity" || (*it).tokens[0] == "LgtIntensity") {
@ -753,62 +755,58 @@ void LWSImporter::InternReadFile(const std::string &pFile, aiScene *pScene, IOSy
}
// 'LightType': set type of currently active light
else if ((*it).tokens[0] == "LightType") {
if (nodes.empty() || nodes.back().type != LWS::NodeDesc::LIGHT)
if (nodes.empty() || nodes.back().type != LWS::NodeDesc::LIGHT) {
ASSIMP_LOG_ERROR("LWS: Unexpected keyword: \'LightType\'");
else
} else {
nodes.back().lightType = strtoul10(c);
}
}
// 'LightFalloffType': set falloff type of currently active light
else if ((*it).tokens[0] == "LightFalloffType") {
if (nodes.empty() || nodes.back().type != LWS::NodeDesc::LIGHT)
if (nodes.empty() || nodes.back().type != LWS::NodeDesc::LIGHT) {
ASSIMP_LOG_ERROR("LWS: Unexpected keyword: \'LightFalloffType\'");
else
} else {
nodes.back().lightFalloffType = strtoul10(c);
}
}
// 'LightConeAngle': set cone angle of currently active light
else if ((*it).tokens[0] == "LightConeAngle") {
if (nodes.empty() || nodes.back().type != LWS::NodeDesc::LIGHT)
if (nodes.empty() || nodes.back().type != LWS::NodeDesc::LIGHT) {
ASSIMP_LOG_ERROR("LWS: Unexpected keyword: \'LightConeAngle\'");
else
} else {
nodes.back().lightConeAngle = fast_atof(c);
}
}
// 'LightEdgeAngle': set area where we're smoothing from min to max intensity
else if ((*it).tokens[0] == "LightEdgeAngle") {
if (nodes.empty() || nodes.back().type != LWS::NodeDesc::LIGHT)
if (nodes.empty() || nodes.back().type != LWS::NodeDesc::LIGHT) {
ASSIMP_LOG_ERROR("LWS: Unexpected keyword: \'LightEdgeAngle\'");
else
} else {
nodes.back().lightEdgeAngle = fast_atof(c);
}
}
// 'LightColor': set color of currently active light
else if ((*it).tokens[0] == "LightColor") {
if (nodes.empty() || nodes.back().type != LWS::NodeDesc::LIGHT)
if (nodes.empty() || nodes.back().type != LWS::NodeDesc::LIGHT) {
ASSIMP_LOG_ERROR("LWS: Unexpected keyword: \'LightColor\'");
else {
} else {
c = fast_atoreal_move<float>(c, (float &)nodes.back().lightColor.r);
SkipSpaces(&c);
SkipSpaces(&c, end);
c = fast_atoreal_move<float>(c, (float &)nodes.back().lightColor.g);
SkipSpaces(&c);
SkipSpaces(&c, end);
c = fast_atoreal_move<float>(c, (float &)nodes.back().lightColor.b);
}
}
// 'PivotPosition': position of local transformation origin
else if ((*it).tokens[0] == "PivotPosition" || (*it).tokens[0] == "PivotPoint") {
if (nodes.empty())
if (nodes.empty()) {
ASSIMP_LOG_ERROR("LWS: Unexpected keyword: \'PivotPosition\'");
else {
} else {
c = fast_atoreal_move<float>(c, (float &)nodes.back().pivotPos.x);
SkipSpaces(&c);
SkipSpaces(&c, end);
c = fast_atoreal_move<float>(c, (float &)nodes.back().pivotPos.y);
SkipSpaces(&c);
SkipSpaces(&c, end);
c = fast_atoreal_move<float>(c, (float &)nodes.back().pivotPos.z);
// Mark pivotPos as set
nodes.back().isPivotSet = true;
@ -818,7 +816,6 @@ void LWSImporter::InternReadFile(const std::string &pFile, aiScene *pScene, IOSy
// resolve parenting
for (std::list<LWS::NodeDesc>::iterator ndIt = nodes.begin(); ndIt != nodes.end(); ++ndIt) {
// check whether there is another node which calls us a parent
for (std::list<LWS::NodeDesc>::iterator dit = nodes.begin(); dit != nodes.end(); ++dit) {
if (dit != ndIt && *ndIt == (*dit).parent) {
@ -854,7 +851,7 @@ void LWSImporter::InternReadFile(const std::string &pFile, aiScene *pScene, IOSy
aiNode *nd = master->mRootNode = new aiNode();
// allocate storage for cameras&lights
if (num_camera) {
if (num_camera > 0u) {
master->mCameras = new aiCamera *[master->mNumCameras = num_camera];
}
aiCamera **cams = master->mCameras;

View File

@ -76,7 +76,7 @@ public:
std::list<Element> children;
//! Recursive parsing function
void Parse(const char *&buffer);
void Parse(const char *&buffer, const char *end);
};
#define AI_LWS_MASK (0xffffffff >> 4u)

View File

@ -123,12 +123,12 @@ bool Q3Shader::LoadShader(ShaderData &fill, const std::string &pFile, IOSystem *
// remove comments from it (C++ style)
CommentRemover::RemoveLineComments("//", &_buff[0]);
const char *buff = &_buff[0];
const char *end = buff + _buff.size();
Q3Shader::ShaderDataBlock *curData = nullptr;
Q3Shader::ShaderMapBlock *curMap = nullptr;
// read line per line
for (; SkipSpacesAndLineEnd(&buff); SkipLine(&buff)) {
for (; SkipSpacesAndLineEnd(&buff, end); SkipLine(&buff, end)) {
if (*buff == '{') {
++buff;
@ -140,21 +140,21 @@ bool Q3Shader::LoadShader(ShaderData &fill, const std::string &pFile, IOSystem *
}
// read this data section
for (; SkipSpacesAndLineEnd(&buff); SkipLine(&buff)) {
for (; SkipSpacesAndLineEnd(&buff, end); SkipLine(&buff, end)) {
if (*buff == '{') {
++buff;
// add new map section
curData->maps.emplace_back();
curMap = &curData->maps.back();
for (; SkipSpacesAndLineEnd(&buff); SkipLine(&buff)) {
for (; SkipSpacesAndLineEnd(&buff, end); SkipLine(&buff, end)) {
// 'map' - Specifies texture file name
if (TokenMatchI(buff, "map", 3) || TokenMatchI(buff, "clampmap", 8)) {
curMap->name = GetNextToken(buff);
curMap->name = GetNextToken(buff, end);
}
// 'blendfunc' - Alpha blending mode
else if (TokenMatchI(buff, "blendfunc", 9)) {
const std::string blend_src = GetNextToken(buff);
const std::string blend_src = GetNextToken(buff, end);
if (blend_src == "add") {
curMap->blend_src = Q3Shader::BLEND_GL_ONE;
curMap->blend_dest = Q3Shader::BLEND_GL_ONE;
@ -166,12 +166,12 @@ bool Q3Shader::LoadShader(ShaderData &fill, const std::string &pFile, IOSystem *
curMap->blend_dest = Q3Shader::BLEND_GL_ONE_MINUS_SRC_ALPHA;
} else {
curMap->blend_src = StringToBlendFunc(blend_src);
curMap->blend_dest = StringToBlendFunc(GetNextToken(buff));
curMap->blend_dest = StringToBlendFunc(GetNextToken(buff, end));
}
}
// 'alphafunc' - Alpha testing mode
else if (TokenMatchI(buff, "alphafunc", 9)) {
const std::string at = GetNextToken(buff);
const std::string at = GetNextToken(buff, end);
if (at == "GT0") {
curMap->alpha_test = Q3Shader::AT_GT0;
} else if (at == "LT128") {
@ -186,7 +186,6 @@ bool Q3Shader::LoadShader(ShaderData &fill, const std::string &pFile, IOSystem *
break;
}
}
} else if (*buff == '}') {
++buff;
curData = nullptr;
@ -195,7 +194,7 @@ bool Q3Shader::LoadShader(ShaderData &fill, const std::string &pFile, IOSystem *
// 'cull' specifies culling behaviour for the model
else if (TokenMatchI(buff, "cull", 4)) {
SkipSpaces(&buff);
SkipSpaces(&buff, end);
if (!ASSIMP_strincmp(buff, "back", 4)) { // render face's backside, does not function in Q3 engine (bug)
curData->cull = Q3Shader::CULL_CCW;
} else if (!ASSIMP_strincmp(buff, "front", 5)) { // is not valid keyword in Q3, but occurs in shaders
@ -213,9 +212,10 @@ bool Q3Shader::LoadShader(ShaderData &fill, const std::string &pFile, IOSystem *
curData = &fill.blocks.back();
// get the name of this section
curData->name = GetNextToken(buff);
curData->name = GetNextToken(buff, end);
}
}
return true;
}
@ -232,6 +232,7 @@ bool Q3Shader::LoadSkin(SkinData &fill, const std::string &pFile, IOSystem *io)
const size_t s = file->FileSize();
std::vector<char> _buff(s + 1);
const char *buff = &_buff[0];
const char *end = buff + _buff.size();
file->Read(&_buff[0], s, 1);
_buff[s] = 0;
@ -240,10 +241,10 @@ bool Q3Shader::LoadSkin(SkinData &fill, const std::string &pFile, IOSystem *io)
// read token by token and fill output table
for (; *buff;) {
SkipSpacesAndLineEnd(&buff);
SkipSpacesAndLineEnd(&buff, end);
// get first identifier
std::string ss = GetNextToken(buff);
std::string ss = GetNextToken(buff, end);
// ignore tokens starting with tag_
if (!::strncmp(&ss[0], "tag_", std::min((size_t)4, ss.length())))
@ -253,8 +254,9 @@ bool Q3Shader::LoadSkin(SkinData &fill, const std::string &pFile, IOSystem *io)
SkinData::TextureEntry &entry = fill.textures.back();
entry.first = ss;
entry.second = GetNextToken(buff);
entry.second = GetNextToken(buff, end);
}
return true;
}
@ -293,7 +295,7 @@ void Q3Shader::ConvertShaderToMaterial(aiMaterial *out, const ShaderDataBlock &s
// - in any case: set it as diffuse texture
//
// If the texture is using 'filter' blending
// - take as lightmap
// - take as light-map
//
// Textures with alpha funcs
// - aiTextureFlags_UseAlpha is set (otherwise aiTextureFlags_NoAlpha is explicitly set)

View File

@ -210,7 +210,7 @@ void MD5Importer::MakeDataUnique(MD5::MeshDesc &meshSrc) {
const unsigned int guess = (unsigned int)(fWeightsPerVert * iNewNum);
meshSrc.mWeights.reserve(guess + (guess >> 3)); // + 12.5% as buffer
for (FaceList::const_iterator iter = meshSrc.mFaces.begin(), iterEnd = meshSrc.mFaces.end(); iter != iterEnd; ++iter) {
for (FaceArray::const_iterator iter = meshSrc.mFaces.begin(), iterEnd = meshSrc.mFaces.end(); iter != iterEnd; ++iter) {
const aiFace &face = *iter;
for (unsigned int i = 0; i < 3; ++i) {
if (face.mIndices[0] >= meshSrc.mVertices.size()) {
@ -231,7 +231,7 @@ void MD5Importer::MakeDataUnique(MD5::MeshDesc &meshSrc) {
// ------------------------------------------------------------------------------------------------
// Recursive node graph construction from a MD5MESH
void MD5Importer::AttachChilds_Mesh(int iParentID, aiNode *piParent, BoneList &bones) {
void MD5Importer::AttachChilds_Mesh(int iParentID, aiNode *piParent, BoneArray &bones) {
ai_assert(nullptr != piParent);
ai_assert(!piParent->mNumChildren);
@ -282,7 +282,7 @@ void MD5Importer::AttachChilds_Mesh(int iParentID, aiNode *piParent, BoneList &b
// ------------------------------------------------------------------------------------------------
// Recursive node graph construction from a MD5ANIM
void MD5Importer::AttachChilds_Anim(int iParentID, aiNode *piParent, AnimBoneList &bones, const aiNodeAnim **node_anims) {
void MD5Importer::AttachChilds_Anim(int iParentID, aiNode *piParent, AnimBoneArray &bones, const aiNodeAnim **node_anims) {
ai_assert(nullptr != piParent);
ai_assert(!piParent->mNumChildren);
@ -402,7 +402,7 @@ void MD5Importer::LoadMD5MeshFile() {
// copy texture coordinates
aiVector3D *pv = mesh->mTextureCoords[0];
for (MD5::VertexList::const_iterator iter = meshSrc.mVertices.begin(); iter != meshSrc.mVertices.end(); ++iter, ++pv) {
for (MD5::VertexArray::const_iterator iter = meshSrc.mVertices.begin(); iter != meshSrc.mVertices.end(); ++iter, ++pv) {
pv->x = (*iter).mUV.x;
pv->y = 1.0f - (*iter).mUV.y; // D3D to OpenGL
pv->z = 0.0f;
@ -412,7 +412,7 @@ void MD5Importer::LoadMD5MeshFile() {
unsigned int *piCount = new unsigned int[meshParser.mJoints.size()];
::memset(piCount, 0, sizeof(unsigned int) * meshParser.mJoints.size());
for (MD5::VertexList::const_iterator iter = meshSrc.mVertices.begin(); iter != meshSrc.mVertices.end(); ++iter, ++pv) {
for (MD5::VertexArray::const_iterator iter = meshSrc.mVertices.begin(); iter != meshSrc.mVertices.end(); ++iter, ++pv) {
for (unsigned int jub = (*iter).mFirstWeight, w = jub; w < jub + (*iter).mNumWeights; ++w) {
MD5::WeightDesc &weightDesc = meshSrc.mWeights[w];
/* FIX for some invalid exporters */
@ -447,7 +447,7 @@ void MD5Importer::LoadMD5MeshFile() {
}
pv = mesh->mVertices;
for (MD5::VertexList::const_iterator iter = meshSrc.mVertices.begin(); iter != meshSrc.mVertices.end(); ++iter, ++pv) {
for (MD5::VertexArray::const_iterator iter = meshSrc.mVertices.begin(); iter != meshSrc.mVertices.end(); ++iter, ++pv) {
// compute the final vertex position from all single weights
*pv = aiVector3D();
@ -585,14 +585,14 @@ void MD5Importer::LoadMD5AnimFile() {
// 1 tick == 1 frame
anim->mTicksPerSecond = animParser.fFrameRate;
for (FrameList::const_iterator iter = animParser.mFrames.begin(), iterEnd = animParser.mFrames.end(); iter != iterEnd; ++iter) {
for (FrameArray::const_iterator iter = animParser.mFrames.begin(), iterEnd = animParser.mFrames.end(); iter != iterEnd; ++iter) {
double dTime = (double)(*iter).iIndex;
aiNodeAnim **pcAnimNode = anim->mChannels;
if (!(*iter).mValues.empty() || iter == animParser.mFrames.begin()) /* be sure we have at least one frame */
{
// now process all values in there ... read all joints
MD5::BaseFrameDesc *pcBaseFrame = &animParser.mBaseFrames[0];
for (AnimBoneList::const_iterator iter2 = animParser.mAnimatedBones.begin(); iter2 != animParser.mAnimatedBones.end(); ++iter2,
for (AnimBoneArray::const_iterator iter2 = animParser.mAnimatedBones.begin(); iter2 != animParser.mAnimatedBones.end(); ++iter2,
++pcAnimNode, ++pcBaseFrame) {
if ((*iter2).iFirstKeyIndex >= (*iter).mValues.size()) {

View File

@ -2,7 +2,7 @@
Open Asset Import Library (assimp)
----------------------------------------------------------------------
Copyright (c) 2006-2022, assimp team
Copyright (c) 2006-2024, assimp team
All rights reserved.
@ -118,7 +118,7 @@ protected:
* @param node_anims Generated node animations
*/
void AttachChilds_Anim(int iParentID, aiNode *piParent,
AnimBoneList &bones, const aiNodeAnim **node_anims);
AnimBoneArray &bones, const aiNodeAnim **node_anims);
// -------------------------------------------------------------------
/** Construct node hierarchy from a given MD5MESH
@ -126,7 +126,7 @@ protected:
* @param piParent Parent node to attach to
* @param bones Input bones
*/
void AttachChilds_Mesh(int iParentID, aiNode *piParent, BoneList &bones);
void AttachChilds_Mesh(int iParentID, aiNode *piParent, BoneArray &bones);
// -------------------------------------------------------------------
/** Build unique vertex buffers from a given MD5ANIM

View File

@ -3,7 +3,7 @@
Open Asset Import Library (assimp)
---------------------------------------------------------------------------
Copyright (c) 2006-2023, assimp team
Copyright (c) 2006-2024, assimp team
All rights reserved.
@ -138,14 +138,16 @@ bool MD5Parser::ParseSection(Section &out) {
char *sz = buffer;
while (!IsSpaceOrNewLine(*buffer)) {
++buffer;
if (buffer == bufferEnd)
if (buffer == bufferEnd) {
return false;
}
}
out.mName = std::string(sz, (uintptr_t)(buffer - sz));
while (IsSpace(*buffer)) {
++buffer;
if (buffer == bufferEnd)
if (buffer == bufferEnd) {
return false;
}
}
bool running = true;
@ -153,14 +155,16 @@ bool MD5Parser::ParseSection(Section &out) {
if ('{' == *buffer) {
// it is a normal section so read all lines
++buffer;
if (buffer == bufferEnd)
if (buffer == bufferEnd) {
return false;
}
bool run = true;
while (run) {
while (IsSpaceOrNewLine(*buffer)) {
++buffer;
if (buffer == bufferEnd)
if (buffer == bufferEnd) {
return false;
}
}
if ('\0' == *buffer) {
return false; // seems this was the last section
@ -175,18 +179,21 @@ bool MD5Parser::ParseSection(Section &out) {
elem.iLineNumber = lineNumber;
elem.szStart = buffer;
elem.end = bufferEnd;
// terminate the line with zero
while (!IsLineEnd(*buffer)) {
++buffer;
if (buffer == bufferEnd)
if (buffer == bufferEnd) {
return false;
}
}
if (*buffer) {
++lineNumber;
*buffer++ = '\0';
if (buffer == bufferEnd)
if (buffer == bufferEnd) {
return false;
}
}
}
break;
@ -194,89 +201,107 @@ bool MD5Parser::ParseSection(Section &out) {
// it is an element at global scope. Parse its value and go on
sz = buffer;
while (!IsSpaceOrNewLine(*buffer++)) {
if (buffer == bufferEnd)
if (buffer == bufferEnd) {
return false;
}
}
out.mGlobalValue = std::string(sz, (uintptr_t)(buffer - sz));
continue;
}
break;
}
if (buffer == bufferEnd)
if (buffer == bufferEnd) {
return false;
}
while (IsSpaceOrNewLine(*buffer)) {
if (buffer == bufferEnd) {
break;
}
++buffer;
if (buffer == bufferEnd)
return false;
}
return '\0' != *buffer;
}
// ------------------------------------------------------------------------------------------------
// Some dirty macros just because they're so funny and easy to debug
// skip all spaces ... handle EOL correctly
#define AI_MD5_SKIP_SPACES() \
if (!SkipSpaces(&sz)) \
MD5Parser::ReportWarning("Unexpected end of line", elem.iLineNumber);
inline void AI_MD5_SKIP_SPACES(const char **sz, const char *bufferEnd, int linenumber) {
if (!SkipSpaces(sz, bufferEnd)) {
MD5Parser::ReportWarning("Unexpected end of line", linenumber);
}
}
// read a triple float in brackets: (1.0 1.0 1.0)
#define AI_MD5_READ_TRIPLE(vec) \
AI_MD5_SKIP_SPACES(); \
if ('(' != *sz++) \
MD5Parser::ReportWarning("Unexpected token: ( was expected", elem.iLineNumber); \
AI_MD5_SKIP_SPACES(); \
sz = fast_atoreal_move<float>(sz, (float &)vec.x); \
AI_MD5_SKIP_SPACES(); \
sz = fast_atoreal_move<float>(sz, (float &)vec.y); \
AI_MD5_SKIP_SPACES(); \
sz = fast_atoreal_move<float>(sz, (float &)vec.z); \
AI_MD5_SKIP_SPACES(); \
if (')' != *sz++) \
MD5Parser::ReportWarning("Unexpected token: ) was expected", elem.iLineNumber);
inline void AI_MD5_READ_TRIPLE(aiVector3D &vec, const char **sz, const char *bufferEnd, int linenumber) {
AI_MD5_SKIP_SPACES(sz, bufferEnd, linenumber);
if ('(' != **sz) {
MD5Parser::ReportWarning("Unexpected token: ( was expected", linenumber);
++*sz;
}
++*sz;
AI_MD5_SKIP_SPACES(sz, bufferEnd, linenumber);
*sz = fast_atoreal_move<float>(*sz, (float &)vec.x);
AI_MD5_SKIP_SPACES(sz, bufferEnd, linenumber);
*sz = fast_atoreal_move<float>(*sz, (float &)vec.y);
AI_MD5_SKIP_SPACES(sz, bufferEnd, linenumber);
*sz = fast_atoreal_move<float>(*sz, (float &)vec.z);
AI_MD5_SKIP_SPACES(sz, bufferEnd, linenumber);
if (')' != **sz) {
MD5Parser::ReportWarning("Unexpected token: ) was expected", linenumber);
}
++*sz;
}
// parse a string, enclosed in quotation marks or not
#define AI_MD5_PARSE_STRING(out) \
bool bQuota = (*sz == '\"'); \
const char *szStart = sz; \
while (!IsSpaceOrNewLine(*sz)) \
++sz; \
const char *szEnd = sz; \
if (bQuota) { \
szStart++; \
if ('\"' != *(szEnd -= 1)) { \
MD5Parser::ReportWarning("Expected closing quotation marks in string", \
elem.iLineNumber); \
continue; \
} \
} \
out.length = (size_t)(szEnd - szStart); \
::memcpy(out.data, szStart, out.length); \
inline bool AI_MD5_PARSE_STRING(const char **sz, const char *bufferEnd, aiString &out, int linenumber) {
bool bQuota = (**sz == '\"');
const char *szStart = *sz;
while (!IsSpaceOrNewLine(**sz)) {
++*sz;
if (*sz == bufferEnd) break;
}
const char *szEnd = *sz;
if (bQuota) {
szStart++;
if ('\"' != *(szEnd -= 1)) {
MD5Parser::ReportWarning("Expected closing quotation marks in string", linenumber);
++*sz;
}
}
out.length = (ai_uint32)(szEnd - szStart);
::memcpy(out.data, szStart, out.length);
out.data[out.length] = '\0';
return true;
}
// parse a string, enclosed in quotation marks
#define AI_MD5_PARSE_STRING_IN_QUOTATION(out) \
out.length = 0; \
while ('\"' != *sz && '\0' != *sz) \
++sz; \
if ('\0' != *sz) { \
const char *szStart = ++sz; \
while ('\"' != *sz && '\0' != *sz) \
++sz; \
if ('\0' != *sz) { \
const char *szEnd = (sz++); \
out.length = (ai_uint32)(szEnd - szStart); \
::memcpy(out.data, szStart, out.length); \
} \
} \
inline void AI_MD5_PARSE_STRING_IN_QUOTATION(const char **sz, const char *bufferEnd, aiString &out) {
out.length = 0u;
while (('\"' != **sz && '\0' != **sz) && *sz != bufferEnd) {
++*sz;
}
if ('\0' != **sz) {
const char *szStart = ++(*sz);
while (('\"' != **sz && '\0' != **sz) && *sz != bufferEnd) {
++*sz;
}
if ('\0' != **sz) {
const char *szEnd = *sz;
++*sz;
out.length = (ai_uint32)(szEnd - szStart);
::memcpy(out.data, szStart, out.length);
}
}
out.data[out.length] = '\0';
}
// ------------------------------------------------------------------------------------------------
// .MD5MESH parsing function
MD5MeshParser::MD5MeshParser(SectionList &mSections) {
MD5MeshParser::MD5MeshParser(SectionArray &mSections) {
ASSIMP_LOG_DEBUG("MD5MeshParser begin");
// now parse all sections
for (SectionList::const_iterator iter = mSections.begin(), iterEnd = mSections.end(); iter != iterEnd; ++iter) {
for (SectionArray::const_iterator iter = mSections.begin(), iterEnd = mSections.end(); iter != iterEnd; ++iter) {
if ((*iter).mName == "numMeshes") {
mMeshes.reserve(::strtoul10((*iter).mGlobalValue.c_str()));
} else if ((*iter).mName == "numJoints") {
@ -288,14 +313,15 @@ MD5MeshParser::MD5MeshParser(SectionList &mSections) {
BoneDesc &desc = mJoints.back();
const char *sz = elem.szStart;
AI_MD5_PARSE_STRING_IN_QUOTATION(desc.mName);
AI_MD5_SKIP_SPACES();
AI_MD5_PARSE_STRING_IN_QUOTATION(&sz, elem.end, desc.mName);
AI_MD5_SKIP_SPACES(&sz, elem.end, elem.iLineNumber);
// negative values, at least -1, is allowed here
desc.mParentIndex = (int)strtol10(sz, &sz);
AI_MD5_READ_TRIPLE(desc.mPositionXYZ);
AI_MD5_READ_TRIPLE(desc.mRotationQuat); // normalized quaternion, so w is not there
AI_MD5_READ_TRIPLE(desc.mPositionXYZ, &sz, elem.end, elem.iLineNumber);
AI_MD5_READ_TRIPLE(desc.mRotationQuat, &sz, elem.end, elem.iLineNumber); // normalized quaternion, so w is not there
}
} else if ((*iter).mName == "mesh") {
mMeshes.emplace_back();
@ -306,52 +332,52 @@ MD5MeshParser::MD5MeshParser(SectionList &mSections) {
// shader attribute
if (TokenMatch(sz, "shader", 6)) {
AI_MD5_SKIP_SPACES();
AI_MD5_PARSE_STRING_IN_QUOTATION(desc.mShader);
AI_MD5_SKIP_SPACES(&sz, elem.end, elem.iLineNumber);
AI_MD5_PARSE_STRING_IN_QUOTATION(&sz, elem.end, desc.mShader);
}
// numverts attribute
else if (TokenMatch(sz, "numverts", 8)) {
AI_MD5_SKIP_SPACES();
AI_MD5_SKIP_SPACES(&sz, elem.end, elem.iLineNumber);
desc.mVertices.resize(strtoul10(sz));
}
// numtris attribute
else if (TokenMatch(sz, "numtris", 7)) {
AI_MD5_SKIP_SPACES();
AI_MD5_SKIP_SPACES(&sz, elem.end, elem.iLineNumber);
desc.mFaces.resize(strtoul10(sz));
}
// numweights attribute
else if (TokenMatch(sz, "numweights", 10)) {
AI_MD5_SKIP_SPACES();
AI_MD5_SKIP_SPACES(&sz, elem.end, elem.iLineNumber);
desc.mWeights.resize(strtoul10(sz));
}
// vert attribute
// "vert 0 ( 0.394531 0.513672 ) 0 1"
else if (TokenMatch(sz, "vert", 4)) {
AI_MD5_SKIP_SPACES();
AI_MD5_SKIP_SPACES(&sz, elem.end, elem.iLineNumber);
const unsigned int idx = ::strtoul10(sz, &sz);
AI_MD5_SKIP_SPACES();
AI_MD5_SKIP_SPACES(&sz, elem.end, elem.iLineNumber);
if (idx >= desc.mVertices.size())
desc.mVertices.resize(idx + 1);
VertexDesc &vert = desc.mVertices[idx];
if ('(' != *sz++)
MD5Parser::ReportWarning("Unexpected token: ( was expected", elem.iLineNumber);
AI_MD5_SKIP_SPACES();
AI_MD5_SKIP_SPACES(&sz, elem.end, elem.iLineNumber);
sz = fast_atoreal_move<float>(sz, (float &)vert.mUV.x);
AI_MD5_SKIP_SPACES();
AI_MD5_SKIP_SPACES(&sz, elem.end, elem.iLineNumber);
sz = fast_atoreal_move<float>(sz, (float &)vert.mUV.y);
AI_MD5_SKIP_SPACES();
AI_MD5_SKIP_SPACES(&sz, elem.end, elem.iLineNumber);
if (')' != *sz++)
MD5Parser::ReportWarning("Unexpected token: ) was expected", elem.iLineNumber);
AI_MD5_SKIP_SPACES();
AI_MD5_SKIP_SPACES(&sz, elem.end, elem.iLineNumber);
vert.mFirstWeight = ::strtoul10(sz, &sz);
AI_MD5_SKIP_SPACES();
AI_MD5_SKIP_SPACES(&sz, elem.end, elem.iLineNumber);
vert.mNumWeights = ::strtoul10(sz, &sz);
}
// tri attribute
// "tri 0 15 13 12"
else if (TokenMatch(sz, "tri", 3)) {
AI_MD5_SKIP_SPACES();
AI_MD5_SKIP_SPACES(&sz, elem.end, elem.iLineNumber);
const unsigned int idx = strtoul10(sz, &sz);
if (idx >= desc.mFaces.size())
desc.mFaces.resize(idx + 1);
@ -359,24 +385,24 @@ MD5MeshParser::MD5MeshParser(SectionList &mSections) {
aiFace &face = desc.mFaces[idx];
face.mIndices = new unsigned int[face.mNumIndices = 3];
for (unsigned int i = 0; i < 3; ++i) {
AI_MD5_SKIP_SPACES();
AI_MD5_SKIP_SPACES(&sz, elem.end, elem.iLineNumber);
face.mIndices[i] = strtoul10(sz, &sz);
}
}
// weight attribute
// "weight 362 5 0.500000 ( -3.553583 11.893474 9.719339 )"
else if (TokenMatch(sz, "weight", 6)) {
AI_MD5_SKIP_SPACES();
AI_MD5_SKIP_SPACES(&sz, elem.end, elem.iLineNumber);
const unsigned int idx = strtoul10(sz, &sz);
AI_MD5_SKIP_SPACES();
AI_MD5_SKIP_SPACES(&sz, elem.end, elem.iLineNumber);
if (idx >= desc.mWeights.size())
desc.mWeights.resize(idx + 1);
WeightDesc &weight = desc.mWeights[idx];
weight.mBone = strtoul10(sz, &sz);
AI_MD5_SKIP_SPACES();
AI_MD5_SKIP_SPACES(&sz, elem.end, elem.iLineNumber);
sz = fast_atoreal_move<float>(sz, weight.mWeight);
AI_MD5_READ_TRIPLE(weight.vOffsetPosition);
AI_MD5_READ_TRIPLE(weight.vOffsetPosition, &sz, elem.end, elem.iLineNumber);
}
}
}
@ -386,12 +412,12 @@ MD5MeshParser::MD5MeshParser(SectionList &mSections) {
// ------------------------------------------------------------------------------------------------
// .MD5ANIM parsing function
MD5AnimParser::MD5AnimParser(SectionList &mSections) {
MD5AnimParser::MD5AnimParser(SectionArray &mSections) {
ASSIMP_LOG_DEBUG("MD5AnimParser begin");
fFrameRate = 24.0f;
mNumAnimatedComponents = UINT_MAX;
for (SectionList::const_iterator iter = mSections.begin(), iterEnd = mSections.end(); iter != iterEnd; ++iter) {
for (SectionArray::const_iterator iter = mSections.begin(), iterEnd = mSections.end(); iter != iterEnd; ++iter) {
if ((*iter).mName == "hierarchy") {
// "sheath" 0 63 6
for (const auto &elem : (*iter).mElements) {
@ -399,18 +425,18 @@ MD5AnimParser::MD5AnimParser(SectionList &mSections) {
AnimBoneDesc &desc = mAnimatedBones.back();
const char *sz = elem.szStart;
AI_MD5_PARSE_STRING_IN_QUOTATION(desc.mName);
AI_MD5_SKIP_SPACES();
AI_MD5_PARSE_STRING_IN_QUOTATION(&sz, elem.end, desc.mName);
AI_MD5_SKIP_SPACES(&sz, elem.end, elem.iLineNumber);
// parent index - negative values are allowed (at least -1)
desc.mParentIndex = ::strtol10(sz, &sz);
// flags (highest is 2^6-1)
AI_MD5_SKIP_SPACES();
AI_MD5_SKIP_SPACES(&sz, elem.end, elem.iLineNumber);
if (63 < (desc.iFlags = ::strtoul10(sz, &sz))) {
MD5Parser::ReportWarning("Invalid flag combination in hierarchy section", elem.iLineNumber);
}
AI_MD5_SKIP_SPACES();
AI_MD5_SKIP_SPACES(& sz, elem.end, elem.iLineNumber);
// index of the first animation keyframe component for this joint
desc.iFirstKeyIndex = ::strtoul10(sz, &sz);
@ -423,8 +449,8 @@ MD5AnimParser::MD5AnimParser(SectionList &mSections) {
mBaseFrames.emplace_back();
BaseFrameDesc &desc = mBaseFrames.back();
AI_MD5_READ_TRIPLE(desc.vPositionXYZ);
AI_MD5_READ_TRIPLE(desc.vRotationQuat);
AI_MD5_READ_TRIPLE(desc.vPositionXYZ, &sz, elem.end, elem.iLineNumber);
AI_MD5_READ_TRIPLE(desc.vRotationQuat, &sz, elem.end, elem.iLineNumber);
}
} else if ((*iter).mName == "frame") {
if (!(*iter).mGlobalValue.length()) {
@ -444,7 +470,7 @@ MD5AnimParser::MD5AnimParser(SectionList &mSections) {
// now read all elements (continuous list of floats)
for (const auto &elem : (*iter).mElements) {
const char *sz = elem.szStart;
while (SkipSpacesAndLineEnd(&sz)) {
while (SkipSpacesAndLineEnd(&sz, elem.end)) {
float f;
sz = fast_atoreal_move<float>(sz, f);
desc.mValues.push_back(f);
@ -471,11 +497,11 @@ MD5AnimParser::MD5AnimParser(SectionList &mSections) {
// ------------------------------------------------------------------------------------------------
// .MD5CAMERA parsing function
MD5CameraParser::MD5CameraParser(SectionList &mSections) {
MD5CameraParser::MD5CameraParser(SectionArray &mSections) {
ASSIMP_LOG_DEBUG("MD5CameraParser begin");
fFrameRate = 24.0f;
for (SectionList::const_iterator iter = mSections.begin(), iterEnd = mSections.end(); iter != iterEnd; ++iter) {
for (SectionArray::const_iterator iter = mSections.begin(), iterEnd = mSections.end(); iter != iterEnd; ++iter) {
if ((*iter).mName == "numFrames") {
frames.reserve(strtoul10((*iter).mGlobalValue.c_str()));
} else if ((*iter).mName == "frameRate") {
@ -492,9 +518,9 @@ MD5CameraParser::MD5CameraParser(SectionList &mSections) {
frames.emplace_back();
CameraAnimFrameDesc &cur = frames.back();
AI_MD5_READ_TRIPLE(cur.vPositionXYZ);
AI_MD5_READ_TRIPLE(cur.vRotationQuat);
AI_MD5_SKIP_SPACES();
AI_MD5_READ_TRIPLE(cur.vPositionXYZ, &sz, elem.end, elem.iLineNumber);
AI_MD5_READ_TRIPLE(cur.vRotationQuat, &sz, elem.end, elem.iLineNumber);
AI_MD5_SKIP_SPACES(&sz, elem.end, elem.iLineNumber);
cur.fFOV = fast_atof(sz);
}
}

View File

@ -2,7 +2,7 @@
Open Asset Import Library (assimp)
----------------------------------------------------------------------
Copyright (c) 2006-2023, assimp team
Copyright (c) 2006-2024, assimp team
All rights reserved.
@ -68,12 +68,14 @@ struct Element {
//! Elements are terminated with \0
char* szStart;
const char *end;
//! Original line number (can be used in error messages
//! if a parsing error occurs)
unsigned int iLineNumber;
};
using ElementList = std::vector<Element>;
using ElementArray = std::vector<Element>;
// ---------------------------------------------------------------------------
/** Represents a section of a MD5 file (such as the mesh or the joints section)
@ -86,7 +88,7 @@ struct Section {
unsigned int iLineNumber;
//! List of all elements which have been parsed in this section.
ElementList mElements;
ElementArray mElements;
//! Name of the section
std::string mName;
@ -96,7 +98,7 @@ struct Section {
std::string mGlobalValue;
};
using SectionList = std::vector<Section>;
using SectionArray = std::vector<Section>;
// ---------------------------------------------------------------------------
/** Basic information about a joint
@ -132,7 +134,7 @@ struct BoneDesc : BaseJointDescription {
unsigned int mMap;
};
using BoneList = std::vector<BoneDesc>;
using BoneArray = std::vector<BoneDesc>;
// ---------------------------------------------------------------------------
/** Represents a bone (joint) descriptor in a MD5Anim file
@ -145,7 +147,7 @@ struct AnimBoneDesc : BaseJointDescription {
unsigned int iFirstKeyIndex;
};
using AnimBoneList = std::vector< AnimBoneDesc >;
using AnimBoneArray = std::vector< AnimBoneDesc >;
// ---------------------------------------------------------------------------
/** Represents a base frame descriptor in a MD5Anim file
@ -155,7 +157,7 @@ struct BaseFrameDesc {
aiVector3D vRotationQuat;
};
using BaseFrameList = std::vector<BaseFrameDesc>;
using BaseFrameArray = std::vector<BaseFrameDesc>;
// ---------------------------------------------------------------------------
/** Represents a camera animation frame in a MDCamera file
@ -164,7 +166,7 @@ struct CameraAnimFrameDesc : BaseFrameDesc {
float fFOV;
};
using CameraFrameList = std::vector<CameraAnimFrameDesc>;
using CameraFrameArray = std::vector<CameraAnimFrameDesc>;
// ---------------------------------------------------------------------------
/** Represents a frame descriptor in a MD5Anim file
@ -177,7 +179,7 @@ struct FrameDesc {
std::vector< float > mValues;
};
using FrameList = std::vector<FrameDesc>;
using FrameArray = std::vector<FrameDesc>;
// ---------------------------------------------------------------------------
/** Represents a vertex descriptor in a MD5 file
@ -199,7 +201,7 @@ struct VertexDesc {
unsigned int mNumWeights;
};
using VertexList = std::vector<VertexDesc>;
using VertexArray = std::vector<VertexDesc>;
// ---------------------------------------------------------------------------
/** Represents a vertex weight descriptor in a MD5 file
@ -216,27 +218,27 @@ struct WeightDesc {
aiVector3D vOffsetPosition;
};
using WeightList = std::vector<WeightDesc>;
using FaceList = std::vector<aiFace>;
using WeightArray = std::vector<WeightDesc>;
using FaceArray = std::vector<aiFace>;
// ---------------------------------------------------------------------------
/** Represents a mesh in a MD5 file
*/
struct MeshDesc {
//! Weights of the mesh
WeightList mWeights;
WeightArray mWeights;
//! Vertices of the mesh
VertexList mVertices;
VertexArray mVertices;
//! Faces of the mesh
FaceList mFaces;
FaceArray mFaces;
//! Name of the shader (=texture) to be assigned to the mesh
aiString mShader;
};
using MeshList = std::vector<MeshDesc>;
using MeshArray = std::vector<MeshDesc>;
// ---------------------------------------------------------------------------
// Convert a quaternion to its usual representation
@ -269,13 +271,13 @@ public:
*
* @param mSections List of file sections (output of MD5Parser)
*/
explicit MD5MeshParser(SectionList& mSections);
explicit MD5MeshParser(SectionArray& mSections);
//! List of all meshes
MeshList mMeshes;
MeshArray mMeshes;
//! List of all joints
BoneList mJoints;
BoneArray mJoints;
};
// remove this flag if you need to the bounding box data
@ -292,20 +294,20 @@ public:
*
* @param mSections List of file sections (output of MD5Parser)
*/
explicit MD5AnimParser(SectionList& mSections);
explicit MD5AnimParser(SectionArray& mSections);
//! Output frame rate
float fFrameRate;
//! List of animation bones
AnimBoneList mAnimatedBones;
AnimBoneArray mAnimatedBones;
//! List of base frames
BaseFrameList mBaseFrames;
BaseFrameArray mBaseFrames;
//! List of animation frames
FrameList mFrames;
FrameArray mFrames;
//! Number of animated components
unsigned int mNumAnimatedComponents;
@ -322,7 +324,7 @@ public:
*
* @param mSections List of file sections (output of MD5Parser)
*/
explicit MD5CameraParser(SectionList& mSections);
explicit MD5CameraParser(SectionArray& mSections);
//! Output frame rate
float fFrameRate;
@ -331,7 +333,7 @@ public:
std::vector<unsigned int> cuts;
//! Frames
CameraFrameList frames;
CameraFrameArray frames;
};
// ---------------------------------------------------------------------------
@ -375,7 +377,7 @@ public:
void ReportWarning (const char* warn);
//! List of all sections which have been read
SectionList mSections;
SectionArray mSections;
private:
bool ParseSection(Section& out);
@ -388,7 +390,7 @@ private:
private:
char* buffer;
char* bufferEnd;
const char* bufferEnd;
unsigned int fileSize;
unsigned int lineNumber;
};
@ -406,7 +408,7 @@ inline void MD5Parser::ReportError(const char* error) {
// -------------------------------------------------------------------
inline bool MD5Parser::SkipLine(const char* in, const char** out) {
++lineNumber;
return Assimp::SkipLine(in ,out);
return Assimp::SkipLine(in, out, bufferEnd);
}
// -------------------------------------------------------------------
@ -450,7 +452,7 @@ inline bool MD5Parser::SkipSpacesAndLineEnd() {
// -------------------------------------------------------------------
inline bool MD5Parser::SkipSpaces() {
return Assimp::SkipSpaces((const char**)&buffer);
return Assimp::SkipSpaces((const char**)&buffer, bufferEnd);
}
} // namespace Assimp

View File

@ -85,7 +85,7 @@ const aiImporterDesc *NFFImporter::GetInfo() const {
// ------------------------------------------------------------------------------------------------
#define AI_NFF_PARSE_FLOAT(f) \
SkipSpaces(&sz); \
SkipSpaces(&sz, lineEnd); \
if (!IsLineEnd(*sz)) sz = fast_atoreal_move<ai_real>(sz, (ai_real &)f);
// ------------------------------------------------------------------------------------------------
@ -111,7 +111,7 @@ const aiImporterDesc *NFFImporter::GetInfo() const {
ASSIMP_LOG_WARN("NFF2: Unexpected EOF, can't read next token"); \
break; \
} \
SkipSpaces(line, &sz); \
SkipSpaces(line, &sz, lineEnd); \
} while (IsLineEnd(*sz))
// ------------------------------------------------------------------------------------------------
@ -148,9 +148,9 @@ void NFFImporter::LoadNFF2MaterialTable(std::vector<ShadingInfo> &output,
// No read the file line per line
char line[4096];
const char *sz;
const char *sz, *lineEnd = &line[2095]+1;
while (GetNextLine(buffer, line)) {
SkipSpaces(line, &sz);
SkipSpaces(line, &sz, lineEnd);
// 'version' defines the version of the file format
if (TokenMatch(sz, "version", 7)) {
@ -198,18 +198,16 @@ void NFFImporter::LoadNFF2MaterialTable(std::vector<ShadingInfo> &output,
// ------------------------------------------------------------------------------------------------
// Imports the given file into the given scene structure.
void NFFImporter::InternReadFile(const std::string &pFile,
aiScene *pScene, IOSystem *pIOHandler) {
std::unique_ptr<IOStream> file(pIOHandler->Open(pFile, "rb"));
// Check whether we can read from the file
if (!file)
throw DeadlyImportError("Failed to open NFF file ", pFile, ".");
void NFFImporter::InternReadFile(const std::string &file, aiScene *pScene, IOSystem *pIOHandler) {
std::unique_ptr<IOStream> stream(pIOHandler->Open(file, "rb"));
if (!stream) {
throw DeadlyImportError("Failed to open NFF file ", file, ".");
}
// allocate storage and copy the contents of the file to a memory buffer
// (terminate it with zero)
std::vector<char> mBuffer2;
TextFileToBuffer(file.get(), mBuffer2);
TextFileToBuffer(stream.get(), mBuffer2);
const char *buffer = &mBuffer2[0];
// mesh arrays - separate here to make the handling of the pointers below easier.
@ -219,8 +217,10 @@ void NFFImporter::InternReadFile(const std::string &pFile,
std::vector<MeshInfo> meshesLocked;
char line[4096];
const char *lineEnd = &line[4096];
const char *sz;
// camera parameters
aiVector3D camPos, camUp(0.f, 1.f, 0.f), camLookAt(0.f, 0.f, 1.f);
ai_real angle = 45.f;
@ -265,7 +265,7 @@ void NFFImporter::InternReadFile(const std::string &pFile,
CommentRemover::RemoveLineComments("//", &mBuffer2[0]);
while (GetNextLine(buffer, line)) {
SkipSpaces(line, &sz);
SkipSpaces(line, &sz, lineEnd);
if (TokenMatch(sz, "version", 7)) {
ASSIMP_LOG_INFO("NFF (Sense8) file format: ", sz);
} else if (TokenMatch(sz, "viewpos", 7)) {
@ -295,7 +295,7 @@ void NFFImporter::InternReadFile(const std::string &pFile,
// material table - an external file
if (TokenMatch(sz, "mtable", 6)) {
SkipSpaces(&sz);
SkipSpaces(&sz, lineEnd);
sz3 = sz;
while (!IsSpaceOrNewLine(*sz))
++sz;
@ -316,12 +316,12 @@ void NFFImporter::InternReadFile(const std::string &pFile,
std::string::size_type sepPos;
if ((std::string::npos == (sepPos = path.find_last_of('\\')) || !sepPos) &&
(std::string::npos == (sepPos = path.find_last_of('/')) || !sepPos)) {
sepPos = pFile.find_last_of('\\');
sepPos = file.find_last_of('\\');
if (std::string::npos == sepPos) {
sepPos = pFile.find_last_of('/');
sepPos = file.find_last_of('/');
}
if (std::string::npos != sepPos) {
path = pFile.substr(0, sepPos + 1) + path;
path = file.substr(0, sepPos + 1) + path;
}
}
LoadNFF2MaterialTable(materialTable, path, pIOHandler);
@ -351,7 +351,7 @@ void NFFImporter::InternReadFile(const std::string &pFile,
// parse all other attributes in the line
while (true) {
SkipSpaces(&sz);
SkipSpaces(&sz, lineEnd);
if (IsLineEnd(*sz)) break;
// color definition
@ -403,23 +403,20 @@ void NFFImporter::InternReadFile(const std::string &pFile,
tempIdx.reserve(10);
for (unsigned int i = 0; i < num; ++i) {
AI_NFF2_GET_NEXT_TOKEN();
SkipSpaces(line, &sz);
SkipSpaces(line, &sz, lineEnd);
unsigned int numIdx = strtoul10(sz, &sz);
// read all faces indices
if (numIdx) {
// mesh.faces.push_back(numIdx);
// tempIdx.erase(tempIdx.begin(),tempIdx.end());
tempIdx.resize(numIdx);
for (unsigned int a = 0; a < numIdx; ++a) {
SkipSpaces(sz, &sz);
SkipSpaces(sz, &sz, lineEnd);
unsigned int m = strtoul10(sz, &sz);
if (m >= (unsigned int)tempPositions.size()) {
ASSIMP_LOG_ERROR("NFF2: Vertex index overflow");
m = 0;
}
// mesh.vertices.push_back (tempPositions[idx]);
tempIdx[a] = m;
}
}
@ -432,7 +429,7 @@ void NFFImporter::InternReadFile(const std::string &pFile,
shader.color = aiColor3D(1.f, 1.f, 1.f);
aiColor4D c = aiColor4D(1.f, 1.f, 1.f, 1.f);
while (true) {
SkipSpaces(sz, &sz);
SkipSpaces(sz, &sz, lineEnd);
if (IsLineEnd(*sz)) break;
// per-polygon colors
@ -510,7 +507,7 @@ void NFFImporter::InternReadFile(const std::string &pFile,
// Material ID?
else if (!materialTable.empty() && TokenMatch(sz, "matid", 5)) {
SkipSpaces(&sz);
SkipSpaces(&sz, lineEnd);
matIdx = strtoul10(sz, &sz);
if (matIdx >= materialTable.size()) {
ASSIMP_LOG_ERROR("NFF2: Material index overflow.");
@ -527,7 +524,7 @@ void NFFImporter::InternReadFile(const std::string &pFile,
shader.specular = mat.specular;
shader.shininess = mat.shininess;
} else
SkipToken(sz);
SkipToken(sz, lineEnd);
}
// search the list of all shaders we have for this object whether
@ -649,7 +646,7 @@ void NFFImporter::InternReadFile(const std::string &pFile,
sz = &line[1];
out = currentMesh;
}
SkipSpaces(sz, &sz);
SkipSpaces(sz, &sz, lineEnd);
unsigned int m = strtoul10(sz);
// ---- flip the face order
@ -677,13 +674,13 @@ void NFFImporter::InternReadFile(const std::string &pFile,
}
if (out == currentMeshWithUVCoords) {
// FIX: in one test file this wraps over multiple lines
SkipSpaces(&sz);
SkipSpaces(&sz, lineEnd);
if (IsLineEnd(*sz)) {
GetNextLine(buffer, line);
sz = line;
}
AI_NFF_PARSE_FLOAT(v.x);
SkipSpaces(&sz);
SkipSpaces(&sz, lineEnd);
if (IsLineEnd(*sz)) {
GetNextLine(buffer, line);
sz = line;
@ -717,7 +714,7 @@ void NFFImporter::InternReadFile(const std::string &pFile,
// if the next one is NOT a number we assume it is a texture file name
// this feature is used by some NFF files on the internet and it has
// been implemented as it can be really useful
SkipSpaces(&sz);
SkipSpaces(&sz, lineEnd);
if (!IsNumeric(*sz)) {
// TODO: Support full file names with spaces and quotation marks ...
const char *p = sz;
@ -731,10 +728,8 @@ void NFFImporter::InternReadFile(const std::string &pFile,
} else {
AI_NFF_PARSE_FLOAT(s.ambient); // optional
}
}
// 'shader' - other way to specify a texture
else if (TokenMatch(sz, "shader", 6)) {
SkipSpaces(&sz);
} else if (TokenMatch(sz, "shader", 6)) { // 'shader' - other way to specify a texture
SkipSpaces(&sz, lineEnd);
const char *old = sz;
while (!IsSpaceOrNewLine(*sz))
++sz;
@ -889,7 +884,7 @@ void NFFImporter::InternReadFile(const std::string &pFile,
}
// 'tess' - tessellation
else if (TokenMatch(sz, "tess", 4)) {
SkipSpaces(&sz);
SkipSpaces(&sz, lineEnd);
iTesselation = strtoul10(sz);
}
// 'from' - camera position
@ -929,7 +924,7 @@ void NFFImporter::InternReadFile(const std::string &pFile,
// '' - comment
else if ('#' == line[0]) {
const char *space;
SkipSpaces(&line[1], &space);
SkipSpaces(&line[1], &space, lineEnd);
if (!IsLineEnd(*space)) {
ASSIMP_LOG_INFO(space);
}

View File

@ -84,10 +84,10 @@ const aiImporterDesc *OFFImporter::GetInfo() const {
// skip blank space, lines and comments
static void NextToken(const char **car, const char *end) {
SkipSpacesAndLineEnd(car);
SkipSpacesAndLineEnd(car, end);
while (*car < end && (**car == '#' || **car == '\n' || **car == '\r')) {
SkipLine(car);
SkipSpacesAndLineEnd(car);
SkipLine(car, end);
SkipSpacesAndLineEnd(car, end);
}
}
@ -195,6 +195,7 @@ void OFFImporter::InternReadFile(const std::string &pFile, aiScene *pScene, IOSy
char line[4096];
buffer = car;
const char *sz = car;
const char *lineEnd = &line[4096];
// now read all vertex lines
for (unsigned int i = 0; i < numVertices; ++i) {
@ -210,13 +211,13 @@ void OFFImporter::InternReadFile(const std::string &pFile, aiScene *pScene, IOSy
// stop at dimensions: this allows loading 1D or 2D coordinate vertices
for (unsigned int dim = 0; dim < dimensions; ++dim) {
SkipSpaces(&sz);
SkipSpaces(&sz, lineEnd);
sz = fast_atoreal_move<ai_real>(sz, *vec[dim]);
}
// if has homogeneous coordinate, divide others by this one
if (hasHomogenous) {
SkipSpaces(&sz);
SkipSpaces(&sz, lineEnd);
ai_real w = 1.;
sz = fast_atoreal_move<ai_real>(sz, w);
for (unsigned int dim = 0; dim < dimensions; ++dim) {
@ -227,11 +228,11 @@ void OFFImporter::InternReadFile(const std::string &pFile, aiScene *pScene, IOSy
// read optional normals
if (hasNormals) {
aiVector3D &n = mesh->mNormals[i];
SkipSpaces(&sz);
SkipSpaces(&sz, lineEnd);
sz = fast_atoreal_move<ai_real>(sz, (ai_real &)n.x);
SkipSpaces(&sz);
SkipSpaces(&sz, lineEnd);
sz = fast_atoreal_move<ai_real>(sz, (ai_real &)n.y);
SkipSpaces(&sz);
SkipSpaces(&sz, lineEnd);
fast_atoreal_move<ai_real>(sz, (ai_real &)n.z);
}
@ -241,22 +242,22 @@ void OFFImporter::InternReadFile(const std::string &pFile, aiScene *pScene, IOSy
// in theory should be testing type !
if (hasColors) {
aiColor4D &c = mesh->mColors[0][i];
SkipSpaces(&sz);
SkipSpaces(&sz, lineEnd);
sz = fast_atoreal_move<ai_real>(sz, (ai_real &)c.r);
if (*sz != '#' && *sz != '\n' && *sz != '\r') {
SkipSpaces(&sz);
SkipSpaces(&sz, lineEnd);
sz = fast_atoreal_move<ai_real>(sz, (ai_real &)c.g);
} else {
c.g = 0.;
}
if (*sz != '#' && *sz != '\n' && *sz != '\r') {
SkipSpaces(&sz);
SkipSpaces(&sz, lineEnd);
sz = fast_atoreal_move<ai_real>(sz, (ai_real &)c.b);
} else {
c.b = 0.;
}
if (*sz != '#' && *sz != '\n' && *sz != '\r') {
SkipSpaces(&sz);
SkipSpaces(&sz, lineEnd);
sz = fast_atoreal_move<ai_real>(sz, (ai_real &)c.a);
} else {
c.a = 1.;
@ -264,9 +265,9 @@ void OFFImporter::InternReadFile(const std::string &pFile, aiScene *pScene, IOSy
}
if (hasTexCoord) {
aiVector3D &t = mesh->mTextureCoords[0][i];
SkipSpaces(&sz);
SkipSpaces(&sz, lineEnd);
sz = fast_atoreal_move<ai_real>(sz, (ai_real &)t.x);
SkipSpaces(&sz);
SkipSpaces(&sz, lineEnd);
fast_atoreal_move<ai_real>(sz, (ai_real &)t.y);
}
}
@ -280,7 +281,7 @@ void OFFImporter::InternReadFile(const std::string &pFile, aiScene *pScene, IOSy
}
unsigned int idx;
sz = line;
SkipSpaces(&sz);
SkipSpaces(&sz, lineEnd);
idx = strtoul10(sz, &sz);
if (!idx || idx > 9) {
ASSIMP_LOG_ERROR("OFF: Faces with zero indices aren't allowed");
@ -291,7 +292,7 @@ void OFFImporter::InternReadFile(const std::string &pFile, aiScene *pScene, IOSy
faces->mNumIndices = idx;
faces->mIndices = new unsigned int[faces->mNumIndices];
for (unsigned int m = 0; m < faces->mNumIndices; ++m) {
SkipSpaces(&sz);
SkipSpaces(&sz, lineEnd);
idx = strtoul10(sz, &sz);
if (idx >= numVertices) {
ASSIMP_LOG_ERROR("OFF: Vertex index is out of range");

View File

@ -64,6 +64,7 @@ ObjFileParser::ObjFileParser() :
m_pModel(nullptr),
m_uiLine(0),
m_buffer(),
mEnd(&m_buffer[Buffersize]),
m_pIO(nullptr),
m_progress(nullptr),
m_originalObjFileName() {
@ -97,8 +98,6 @@ ObjFileParser::ObjFileParser(IOStreamBuffer<char> &streamBuffer, const std::stri
parseFile(streamBuffer);
}
ObjFileParser::~ObjFileParser() = default;
void ObjFileParser::setBuffer(std::vector<char> &buffer) {
m_DataIt = buffer.begin();
m_DataItEnd = buffer.end();
@ -121,6 +120,7 @@ void ObjFileParser::parseFile(IOStreamBuffer<char> &streamBuffer) {
while (streamBuffer.getNextDataLine(buffer, '\\')) {
m_DataIt = buffer.begin();
m_DataItEnd = buffer.end();
mEnd = &buffer[buffer.size() - 1] + 1;
// Handle progress reporting
const size_t filePos(streamBuffer.getFilePos());
@ -130,7 +130,7 @@ void ObjFileParser::parseFile(IOStreamBuffer<char> &streamBuffer) {
m_progress->UpdateFileRead(processed, progressTotal);
}
// handle cstype section end (http://paulbourke.net/dataformats/obj/)
// handle c-stype section end (http://paulbourke.net/dataformats/obj/)
if (insideCstype) {
switch (*m_DataIt) {
case 'e': {
@ -301,18 +301,19 @@ size_t ObjFileParser::getNumComponentsInDataDefinition() {
} else if (IsLineEnd(*tmp)) {
end_of_definition = true;
}
if (!SkipSpaces(&tmp)) {
if (!SkipSpaces(&tmp, mEnd)) {
break;
}
const bool isNum(IsNumeric(*tmp) || isNanOrInf(tmp));
SkipToken(tmp);
SkipToken(tmp, mEnd);
if (isNum) {
++numComponents;
}
if (!SkipSpaces(&tmp)) {
if (!SkipSpaces(&tmp, mEnd)) {
break;
}
}
return numComponents;
}
@ -487,8 +488,9 @@ void ObjFileParser::getFace(aiPrimitiveType type) {
++iStep;
}
if (iPos == 1 && !vt && vn)
if (iPos == 1 && !vt && vn) {
iPos = 2; // skip texture coords for normals if there are no tex coords
}
if (iVal > 0) {
// Store parsed index
@ -577,8 +579,9 @@ void ObjFileParser::getMaterialDesc() {
// Get name
std::string strName(pStart, &(*m_DataIt));
strName = trim_whitespaces(strName);
if (strName.empty())
if (strName.empty()) {
skip = true;
}
// If the current mesh has the same material, we simply ignore that 'usemtl' command
// There is no need to create another object or even mesh here

View File

@ -41,6 +41,8 @@ OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
#ifndef OBJ_FILEPARSER_H_INC
#define OBJ_FILEPARSER_H_INC
#include "ObjFileData.h"
#include <assimp/IOStreamBuffer.h>
#include <assimp/material.h>
#include <assimp/mesh.h>
@ -53,14 +55,6 @@ OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
namespace Assimp {
namespace ObjFile {
struct Model;
struct Object;
struct Material;
struct Point3;
struct Point2;
} // namespace ObjFile
class ObjFileImporter;
class IOSystem;
class ProgressHandler;
@ -79,7 +73,7 @@ public:
/// @brief Constructor with data array.
ObjFileParser(IOStreamBuffer<char> &streamBuffer, const std::string &modelName, IOSystem *io, ProgressHandler *progress, const std::string &originalObjFileName);
/// @brief Destructor
~ObjFileParser();
~ObjFileParser() = default;
/// @brief If you want to load in-core data.
void setBuffer(std::vector<char> &buffer);
/// @brief Model getter.
@ -149,6 +143,7 @@ private:
unsigned int m_uiLine;
//! Helper buffer
char m_buffer[Buffersize];
const char *mEnd;
/// Pointer to IO system instance.
IOSystem *m_pIO;
//! Pointer to progress handler

View File

@ -159,7 +159,8 @@ void PLYImporter::InternReadFile(const std::string &pFile, aiScene *pScene, IOSy
mBuffer = (unsigned char *)&mBuffer2[0];
char *szMe = (char *)&this->mBuffer[0];
SkipSpacesAndLineEnd(szMe, (const char **)&szMe);
const char *end = &mBuffer2[0] + mBuffer2.size();
SkipSpacesAndLineEnd(szMe, (const char **)&szMe, end);
// determine the format of the file data and construct the aiMesh
PLY::DOM sPlyDom;
@ -167,7 +168,7 @@ void PLYImporter::InternReadFile(const std::string &pFile, aiScene *pScene, IOSy
if (TokenMatch(szMe, "format", 6)) {
if (TokenMatch(szMe, "ascii", 5)) {
SkipLine(szMe, (const char **)&szMe);
SkipLine(szMe, (const char **)&szMe, end);
if (!PLY::DOM::ParseInstance(streamedBuffer, &sPlyDom, this)) {
if (mGeneratedMesh != nullptr) {
delete (mGeneratedMesh);

View File

@ -50,7 +50,7 @@ OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
#include <assimp/DefaultLogger.hpp>
#include <utility>
using namespace Assimp;
namespace Assimp {
// ------------------------------------------------------------------------------------------------
PLY::EDataType PLY::Property::ParseDataType(std::vector<char> &buffer) {
@ -296,7 +296,7 @@ bool PLY::Element::ParseElement(IOStreamBuffer<char> &streamBuffer, std::vector<
return true;
}
//parse the number of occurrences of this element
// parse the number of occurrences of this element
const char *pCur = (char *)&buffer[0];
pOut->NumOccur = strtoul10(pCur, &pCur);
@ -321,13 +321,13 @@ bool PLY::Element::ParseElement(IOStreamBuffer<char> &streamBuffer, std::vector<
return true;
}
// ------------------------------------------------------------------------------------------------
bool PLY::DOM::SkipSpaces(std::vector<char> &buffer) {
const char *pCur = buffer.empty() ? nullptr : (char *)&buffer[0];
const char *end = pCur + buffer.size();
bool ret = false;
if (pCur) {
const char *szCur = pCur;
ret = Assimp::SkipSpaces(pCur, &pCur);
ret = Assimp::SkipSpaces(pCur, &pCur, end);
uintptr_t iDiff = (uintptr_t)pCur - (uintptr_t)szCur;
buffer.erase(buffer.begin(), buffer.begin() + iDiff);
@ -339,10 +339,11 @@ bool PLY::DOM::SkipSpaces(std::vector<char> &buffer) {
bool PLY::DOM::SkipLine(std::vector<char> &buffer) {
const char *pCur = buffer.empty() ? nullptr : (char *)&buffer[0];
const char *end = pCur + buffer.size();
bool ret = false;
if (pCur) {
const char *szCur = pCur;
ret = Assimp::SkipLine(pCur, &pCur);
ret = Assimp::SkipLine(pCur, &pCur, end);
uintptr_t iDiff = (uintptr_t)pCur - (uintptr_t)szCur;
buffer.erase(buffer.begin(), buffer.begin() + iDiff);
@ -369,10 +370,11 @@ bool PLY::DOM::TokenMatch(std::vector<char> &buffer, const char *token, unsigned
bool PLY::DOM::SkipSpacesAndLineEnd(std::vector<char> &buffer) {
const char *pCur = buffer.empty() ? nullptr : (char *)&buffer[0];
const char *end = pCur + buffer.size();
bool ret = false;
if (pCur) {
const char *szCur = pCur;
ret = Assimp::SkipSpacesAndLineEnd(pCur, &pCur);
ret = Assimp::SkipSpacesAndLineEnd(pCur, &pCur, end);
uintptr_t iDiff = (uintptr_t)pCur - (uintptr_t)szCur;
buffer.erase(buffer.begin(), buffer.begin() + iDiff);
@ -426,7 +428,7 @@ bool PLY::DOM::ParseHeader(IOStreamBuffer<char> &streamBuffer, std::vector<char>
} else {
// ignore unknown header elements
if (!streamBuffer.getNextLine(buffer))
return false;
return false;
}
}
@ -446,7 +448,7 @@ bool PLY::DOM::ParseElementInstanceLists(IOStreamBuffer<char> &streamBuffer, std
std::vector<PLY::ElementInstanceList>::iterator a = alElementData.begin();
// parse all element instances
//construct vertices and faces
// construct vertices and faces
for (; i != alElements.end(); ++i, ++a) {
if ((*i).eSemantic == EEST_Vertex || (*i).eSemantic == EEST_Face || (*i).eSemantic == EEST_TriStrip) {
PLY::ElementInstanceList::ParseInstanceList(streamBuffer, buffer, &(*i), nullptr, loader);
@ -528,7 +530,7 @@ bool PLY::DOM::ParseInstance(IOStreamBuffer<char> &streamBuffer, DOM *p_pcOut, P
return false;
}
//get next line after header
// get next line after header
streamBuffer.getNextLine(buffer);
if (!p_pcOut->ParseElementInstanceLists(streamBuffer, buffer, loader)) {
ASSIMP_LOG_VERBOSE_DEBUG("PLY::DOM::ParseInstance() failure");
@ -558,23 +560,24 @@ bool PLY::ElementInstanceList::ParseInstanceList(
}
} else {
const char *pCur = (const char *)&buffer[0];
const char *end = pCur + buffer.size();
// be sure to have enough storage
for (unsigned int i = 0; i < pcElement->NumOccur; ++i) {
if (p_pcOut)
PLY::ElementInstance::ParseInstance(pCur, pcElement, &p_pcOut->alInstances[i]);
PLY::ElementInstance::ParseInstance(pCur, end, pcElement, &p_pcOut->alInstances[i]);
else {
ElementInstance elt;
PLY::ElementInstance::ParseInstance(pCur, pcElement, &elt);
PLY::ElementInstance::ParseInstance(pCur, end, pcElement, &elt);
// Create vertex or face
if (pcElement->eSemantic == EEST_Vertex) {
//call loader instance from here
// call loader instance from here
loader->LoadVertex(pcElement, &elt, i);
} else if (pcElement->eSemantic == EEST_Face) {
//call loader instance from here
// call loader instance from here
loader->LoadFace(pcElement, &elt, i);
} else if (pcElement->eSemantic == EEST_TriStrip) {
//call loader instance from here
// call loader instance from here
loader->LoadFace(pcElement, &elt, i);
}
}
@ -611,13 +614,13 @@ bool PLY::ElementInstanceList::ParseInstanceListBinary(
// Create vertex or face
if (pcElement->eSemantic == EEST_Vertex) {
//call loader instance from here
// call loader instance from here
loader->LoadVertex(pcElement, &elt, i);
} else if (pcElement->eSemantic == EEST_Face) {
//call loader instance from here
// call loader instance from here
loader->LoadFace(pcElement, &elt, i);
} else if (pcElement->eSemantic == EEST_TriStrip) {
//call loader instance from here
// call loader instance from here
loader->LoadFace(pcElement, &elt, i);
}
}
@ -626,7 +629,7 @@ bool PLY::ElementInstanceList::ParseInstanceListBinary(
}
// ------------------------------------------------------------------------------------------------
bool PLY::ElementInstance::ParseInstance(const char *&pCur,
bool PLY::ElementInstance::ParseInstance(const char *&pCur, const char *end,
const PLY::Element *pcElement,
PLY::ElementInstance *p_pcOut) {
ai_assert(nullptr != pcElement);
@ -638,7 +641,7 @@ bool PLY::ElementInstance::ParseInstance(const char *&pCur,
std::vector<PLY::PropertyInstance>::iterator i = p_pcOut->alProperties.begin();
std::vector<PLY::Property>::const_iterator a = pcElement->alProperties.begin();
for (; i != p_pcOut->alProperties.end(); ++i, ++a) {
if (!(PLY::PropertyInstance::ParseInstance(pCur, &(*a), &(*i)))) {
if (!(PLY::PropertyInstance::ParseInstance(pCur, end, &(*a), &(*i)))) {
ASSIMP_LOG_WARN("Unable to parse property instance. "
"Skipping this element instance");
@ -678,13 +681,13 @@ bool PLY::ElementInstance::ParseInstanceBinary(
}
// ------------------------------------------------------------------------------------------------
bool PLY::PropertyInstance::ParseInstance(const char *&pCur,
const PLY::Property *prop, PLY::PropertyInstance *p_pcOut) {
bool PLY::PropertyInstance::ParseInstance(const char *&pCur, const char *end, const PLY::Property *prop,
PLY::PropertyInstance *p_pcOut) {
ai_assert(nullptr != prop);
ai_assert(nullptr != p_pcOut);
// skip spaces at the beginning
if (!SkipSpaces(&pCur)) {
if (!SkipSpaces(&pCur, end)) {
return false;
}
@ -699,7 +702,7 @@ bool PLY::PropertyInstance::ParseInstance(const char *&pCur,
// parse all list elements
p_pcOut->avList.resize(iNum);
for (unsigned int i = 0; i < iNum; ++i) {
if (!SkipSpaces(&pCur))
if (!SkipSpaces(&pCur, end))
return false;
PLY::PropertyInstance::ParseValue(pCur, prop->eType, &p_pcOut->avList[i]);
@ -711,7 +714,7 @@ bool PLY::PropertyInstance::ParseInstance(const char *&pCur,
PLY::PropertyInstance::ParseValue(pCur, prop->eType, &v);
p_pcOut->avList.push_back(v);
}
SkipSpacesAndLineEnd(&pCur);
SkipSpacesAndLineEnd(&pCur, end);
return true;
}
@ -774,7 +777,7 @@ bool PLY::PropertyInstance::ParseValue(const char *&pCur,
ai_assert(nullptr != pCur);
ai_assert(nullptr != out);
//calc element size
// calc element size
bool ret = true;
switch (eType) {
case EDT_UInt:
@ -824,7 +827,7 @@ bool PLY::PropertyInstance::ParseValueBinary(IOStreamBuffer<char> &streamBuffer,
bool p_bBE) {
ai_assert(nullptr != out);
//calc element size
// calc element size
unsigned int lsize = 0;
switch (eType) {
case EDT_Char:
@ -852,11 +855,11 @@ bool PLY::PropertyInstance::ParseValueBinary(IOStreamBuffer<char> &streamBuffer,
break;
}
//read the next file block if needed
// read the next file block if needed
if (bufferSize < lsize) {
std::vector<char> nbuffer;
if (streamBuffer.getNextBlock(nbuffer)) {
//concat buffer contents
// concat buffer contents
buffer = std::vector<char>(buffer.end() - bufferSize, buffer.end());
buffer.insert(buffer.end(), nbuffer.begin(), nbuffer.end());
nbuffer.clear();
@ -958,4 +961,6 @@ bool PLY::PropertyInstance::ParseValueBinary(IOStreamBuffer<char> &streamBuffer,
return ret;
}
} // namespace Assimp
#endif // !! ASSIMP_BUILD_NO_PLY_IMPORTER

View File

@ -324,7 +324,7 @@ public:
// -------------------------------------------------------------------
//! Parse a property instance
static bool ParseInstance(const char* &pCur,
static bool ParseInstance(const char* &pCur, const char *end,
const Property* prop, PropertyInstance* p_pcOut);
// -------------------------------------------------------------------
@ -364,7 +364,7 @@ public:
// -------------------------------------------------------------------
//! Parse an element instance
static bool ParseInstance(const char* &pCur,
static bool ParseInstance(const char *&pCur, const char *end,
const Element* pcElement, ElementInstance* p_pcOut);
// -------------------------------------------------------------------

View File

@ -104,11 +104,12 @@ void RAWImporter::InternReadFile(const std::string &pFile,
// now read all lines
char line[4096];
const char *end = &line[4096];
while (GetNextLine(buffer, line)) {
// if the line starts with a non-numeric identifier, it marks
// the beginning of a new group
const char *sz = line;
SkipSpaces(&sz);
SkipSpaces(&sz, end);
if (IsLineEnd(*sz)) continue;
if (!IsNumeric(*sz)) {
const char *sz2 = sz;
@ -117,8 +118,8 @@ void RAWImporter::InternReadFile(const std::string &pFile,
const unsigned int length = (unsigned int)(sz2 - sz);
// find an existing group with this name
for (std::vector<GroupInformation>::iterator it = outGroups.begin(), end = outGroups.end();
it != end; ++it) {
for (std::vector<GroupInformation>::iterator it = outGroups.begin(), endIt = outGroups.end();
it != endIt; ++it) {
if (length == (*it).name.length() && !::strcmp(sz, (*it).name.c_str())) {
curGroup = it;
sz2 = nullptr;
@ -134,7 +135,7 @@ void RAWImporter::InternReadFile(const std::string &pFile,
float data[12];
unsigned int num;
for (num = 0; num < 12; ++num) {
if (!SkipSpaces(&sz) || !IsNumeric(*sz)) break;
if (!SkipSpaces(&sz, end) || !IsNumeric(*sz)) break;
sz = fast_atoreal_move<float>(sz, data[num]);
}
if (num != 12 && num != 9) {

View File

@ -83,7 +83,9 @@ static constexpr aiImporterDesc desc = {
// Constructor to be privately used by Importer
SMDImporter::SMDImporter() :
configFrameID(),
pScene( nullptr ),
mBuffer(),
mEnd(nullptr),
pScene(nullptr),
iFileSize( 0 ),
iSmallestFrame( INT_MAX ),
dLengthOfAnim( 0.0 ),
@ -92,9 +94,6 @@ SMDImporter::SMDImporter() :
// empty
}
// ------------------------------------------------------------------------------------------------
// Destructor, private as well
SMDImporter::~SMDImporter() = default;
// ------------------------------------------------------------------------------------------------
// Returns whether the class can handle the format of the given file.
@ -632,13 +631,13 @@ void SMDImporter::ParseFile() {
// read line per line ...
for ( ;; ) {
if(!SkipSpacesAndLineEnd(szCurrent,&szCurrent)) {
if(!SkipSpacesAndLineEnd(szCurrent,&szCurrent, mEnd)) {
break;
}
// "version <n> \n", <n> should be 1 for hl and hl2 SMD files
if (TokenMatch(szCurrent,"version",7)) {
if(!SkipSpaces(szCurrent,&szCurrent)) break;
if(!SkipSpaces(szCurrent,&szCurrent, mEnd)) break;
if (1 != strtoul10(szCurrent,&szCurrent)) {
ASSIMP_LOG_WARN("SMD.version is not 1. This "
"file format is not known. Continuing happily ...");
@ -647,26 +646,26 @@ void SMDImporter::ParseFile() {
}
// "nodes\n" - Starts the node section
if (TokenMatch(szCurrent,"nodes",5)) {
ParseNodesSection(szCurrent,&szCurrent);
ParseNodesSection(szCurrent, &szCurrent, mEnd);
continue;
}
// "triangles\n" - Starts the triangle section
if (TokenMatch(szCurrent,"triangles",9)) {
ParseTrianglesSection(szCurrent,&szCurrent);
ParseTrianglesSection(szCurrent, &szCurrent, mEnd);
continue;
}
// "vertexanimation\n" - Starts the vertex animation section
if (TokenMatch(szCurrent,"vertexanimation",15)) {
bHasUVs = false;
ParseVASection(szCurrent,&szCurrent);
ParseVASection(szCurrent, &szCurrent, mEnd);
continue;
}
// "skeleton\n" - Starts the skeleton section
if (TokenMatch(szCurrent,"skeleton",8)) {
ParseSkeletonSection(szCurrent,&szCurrent);
ParseSkeletonSection(szCurrent, &szCurrent, mEnd);
continue;
}
SkipLine(szCurrent,&szCurrent);
SkipLine(szCurrent, &szCurrent, mEnd);
}
}
@ -683,6 +682,7 @@ void SMDImporter::ReadSmd(const std::string &pFile, IOSystem* pIOHandler) {
// Allocate storage and copy the contents of the file to a memory buffer
mBuffer.resize(iFileSize + 1);
TextFileToBuffer(file.get(), mBuffer);
mEnd = &mBuffer[mBuffer.size() - 1] + 1;
iSmallestFrame = INT_MAX;
bHasUVs = true;
@ -723,26 +723,26 @@ unsigned int SMDImporter::GetTextureIndex(const std::string& filename) {
// ------------------------------------------------------------------------------------------------
// Parse the nodes section of the file
void SMDImporter::ParseNodesSection(const char* szCurrent, const char** szCurrentOut) {
void SMDImporter::ParseNodesSection(const char* szCurrent, const char** szCurrentOut, const char *end) {
for ( ;; ) {
// "end\n" - Ends the nodes section
if (0 == ASSIMP_strincmp(szCurrent,"end",3) && IsSpaceOrNewLine(*(szCurrent+3))) {
if (0 == ASSIMP_strincmp(szCurrent, "end", 3) && IsSpaceOrNewLine(*(szCurrent+3))) {
szCurrent += 4;
break;
}
ParseNodeInfo(szCurrent,&szCurrent);
ParseNodeInfo(szCurrent,&szCurrent, end);
}
SkipSpacesAndLineEnd(szCurrent,&szCurrent);
SkipSpacesAndLineEnd(szCurrent, &szCurrent, end);
*szCurrentOut = szCurrent;
}
// ------------------------------------------------------------------------------------------------
// Parse the triangles section of the file
void SMDImporter::ParseTrianglesSection(const char* szCurrent, const char** szCurrentOut) {
void SMDImporter::ParseTrianglesSection(const char *szCurrent, const char **szCurrentOut, const char *end) {
// Parse a triangle, parse another triangle, parse the next triangle ...
// and so on until we reach a token that looks quite similar to "end"
for ( ;; ) {
if(!SkipSpacesAndLineEnd(szCurrent,&szCurrent)) {
if(!SkipSpacesAndLineEnd(szCurrent,&szCurrent, end)) {
break;
}
@ -750,17 +750,17 @@ void SMDImporter::ParseTrianglesSection(const char* szCurrent, const char** szCu
if (TokenMatch(szCurrent,"end",3)) {
break;
}
ParseTriangle(szCurrent,&szCurrent);
ParseTriangle(szCurrent,&szCurrent, end);
}
SkipSpacesAndLineEnd(szCurrent,&szCurrent);
SkipSpacesAndLineEnd(szCurrent,&szCurrent, end);
*szCurrentOut = szCurrent;
}
// ------------------------------------------------------------------------------------------------
// Parse the vertex animation section of the file
void SMDImporter::ParseVASection(const char* szCurrent, const char** szCurrentOut) {
void SMDImporter::ParseVASection(const char *szCurrent, const char **szCurrentOut, const char *end) {
unsigned int iCurIndex = 0;
for ( ;; ) {
if (!SkipSpacesAndLineEnd(szCurrent,&szCurrent)) {
if (!SkipSpacesAndLineEnd(szCurrent,&szCurrent, end)) {
break;
}
@ -774,10 +774,10 @@ void SMDImporter::ParseVASection(const char* szCurrent, const char** szCurrentOu
// NOTE: The doc says that time values COULD be negative ...
// NOTE2: this is the shape key -> valve docs
int iTime = 0;
if(!ParseSignedInt(szCurrent,&szCurrent,iTime) || configFrameID != (unsigned int)iTime) {
if (!ParseSignedInt(szCurrent, &szCurrent, end, iTime) || configFrameID != (unsigned int)iTime) {
break;
}
SkipLine(szCurrent,&szCurrent);
SkipLine(szCurrent,&szCurrent, end);
} else {
if(0 == iCurIndex) {
asTriangles.emplace_back();
@ -785,7 +785,7 @@ void SMDImporter::ParseVASection(const char* szCurrent, const char** szCurrentOu
if (++iCurIndex == 3) {
iCurIndex = 0;
}
ParseVertex(szCurrent,&szCurrent,asTriangles.back().avVertices[iCurIndex],true);
ParseVertex(szCurrent,&szCurrent, end, asTriangles.back().avVertices[iCurIndex],true);
}
}
@ -794,16 +794,16 @@ void SMDImporter::ParseVASection(const char* szCurrent, const char** szCurrentOu
asTriangles.pop_back();
}
SkipSpacesAndLineEnd(szCurrent,&szCurrent);
SkipSpacesAndLineEnd(szCurrent,&szCurrent, end);
*szCurrentOut = szCurrent;
}
// ------------------------------------------------------------------------------------------------
// Parse the skeleton section of the file
void SMDImporter::ParseSkeletonSection(const char* szCurrent, const char** szCurrentOut) {
void SMDImporter::ParseSkeletonSection(const char *szCurrent, const char **szCurrentOut, const char *end) {
int iTime = 0;
for ( ;; ) {
if (!SkipSpacesAndLineEnd(szCurrent,&szCurrent)) {
if (!SkipSpacesAndLineEnd(szCurrent,&szCurrent, end)) {
break;
}
@ -811,15 +811,15 @@ void SMDImporter::ParseSkeletonSection(const char* szCurrent, const char** szCur
if (TokenMatch(szCurrent,"end",3)) {
break;
} else if (TokenMatch(szCurrent,"time",4)) {
// "time <n>\n" - Specifies the current animation frame
if(!ParseSignedInt(szCurrent,&szCurrent,iTime)) {
// "time <n>\n" - Specifies the current animation frame
if (!ParseSignedInt(szCurrent, &szCurrent, end, iTime)) {
break;
}
iSmallestFrame = std::min(iSmallestFrame,iTime);
SkipLine(szCurrent,&szCurrent);
SkipLine(szCurrent, &szCurrent, end);
} else {
ParseSkeletonElement(szCurrent,&szCurrent,iTime);
ParseSkeletonElement(szCurrent, &szCurrent, end, iTime);
}
}
*szCurrentOut = szCurrent;
@ -827,16 +827,16 @@ void SMDImporter::ParseSkeletonSection(const char* szCurrent, const char** szCur
// ------------------------------------------------------------------------------------------------
#define SMDI_PARSE_RETURN { \
SkipLine(szCurrent,&szCurrent); \
SkipLine(szCurrent,&szCurrent, end); \
*szCurrentOut = szCurrent; \
return; \
}
// ------------------------------------------------------------------------------------------------
// Parse a node line
void SMDImporter::ParseNodeInfo(const char* szCurrent, const char** szCurrentOut) {
void SMDImporter::ParseNodeInfo(const char *szCurrent, const char **szCurrentOut, const char *end) {
unsigned int iBone = 0;
SkipSpacesAndLineEnd(szCurrent,&szCurrent);
if ( !ParseUnsignedInt(szCurrent,&szCurrent,iBone) || !SkipSpaces(szCurrent,&szCurrent)) {
SkipSpacesAndLineEnd(szCurrent, &szCurrent, end);
if ( !ParseUnsignedInt(szCurrent, &szCurrent, end, iBone) || !SkipSpaces(szCurrent,&szCurrent, end)) {
throw DeadlyImportError("Unexpected EOF/EOL while parsing bone index");
}
if (iBone == UINT_MAX) {
@ -877,7 +877,7 @@ void SMDImporter::ParseNodeInfo(const char* szCurrent, const char** szCurrentOut
szCurrent = szEnd;
// the only negative bone parent index that could occur is -1 AFAIK
if(!ParseSignedInt(szCurrent,&szCurrent,(int&)bone.iParent)) {
if(!ParseSignedInt(szCurrent, &szCurrent, end, (int&)bone.iParent)) {
LogErrorNoThrow("Unexpected EOF/EOL while parsing bone parent index. Assuming -1");
SMDI_PARSE_RETURN;
}
@ -888,12 +888,12 @@ void SMDImporter::ParseNodeInfo(const char* szCurrent, const char** szCurrentOut
// ------------------------------------------------------------------------------------------------
// Parse a skeleton element
void SMDImporter::ParseSkeletonElement(const char* szCurrent, const char** szCurrentOut,int iTime) {
void SMDImporter::ParseSkeletonElement(const char *szCurrent, const char **szCurrentOut, const char *end, int iTime) {
aiVector3D vPos;
aiVector3D vRot;
unsigned int iBone = 0;
if(!ParseUnsignedInt(szCurrent,&szCurrent,iBone)) {
if (!ParseUnsignedInt(szCurrent, &szCurrent, end, iBone)) {
ASSIMP_LOG_ERROR("Unexpected EOF/EOL while parsing bone index");
SMDI_PARSE_RETURN;
}
@ -907,27 +907,27 @@ void SMDImporter::ParseSkeletonElement(const char* szCurrent, const char** szCur
SMD::Bone::Animation::MatrixKey& key = bone.sAnim.asKeys.back();
key.dTime = (double)iTime;
if(!ParseFloat(szCurrent,&szCurrent,(float&)vPos.x)) {
if(!ParseFloat(szCurrent, &szCurrent, end, (float&)vPos.x)) {
LogErrorNoThrow("Unexpected EOF/EOL while parsing bone.pos.x");
SMDI_PARSE_RETURN;
}
if(!ParseFloat(szCurrent,&szCurrent,(float&)vPos.y)) {
if(!ParseFloat(szCurrent, &szCurrent, end, (float&)vPos.y)) {
LogErrorNoThrow("Unexpected EOF/EOL while parsing bone.pos.y");
SMDI_PARSE_RETURN;
}
if(!ParseFloat(szCurrent,&szCurrent,(float&)vPos.z)) {
if(!ParseFloat(szCurrent, &szCurrent, end, (float&)vPos.z)) {
LogErrorNoThrow("Unexpected EOF/EOL while parsing bone.pos.z");
SMDI_PARSE_RETURN;
}
if(!ParseFloat(szCurrent,&szCurrent,(float&)vRot.x)) {
if(!ParseFloat(szCurrent, &szCurrent, end, (float&)vRot.x)) {
LogErrorNoThrow("Unexpected EOF/EOL while parsing bone.rot.x");
SMDI_PARSE_RETURN;
}
if(!ParseFloat(szCurrent,&szCurrent,(float&)vRot.y)) {
if(!ParseFloat(szCurrent, &szCurrent, end, (float&)vRot.y)) {
LogErrorNoThrow("Unexpected EOF/EOL while parsing bone.rot.y");
SMDI_PARSE_RETURN;
}
if(!ParseFloat(szCurrent,&szCurrent,(float&)vRot.z)) {
if(!ParseFloat(szCurrent, &szCurrent, end, (float&)vRot.z)) {
LogErrorNoThrow("Unexpected EOF/EOL while parsing bone.rot.z");
SMDI_PARSE_RETURN;
}
@ -947,11 +947,11 @@ void SMDImporter::ParseSkeletonElement(const char* szCurrent, const char** szCur
// ------------------------------------------------------------------------------------------------
// Parse a triangle
void SMDImporter::ParseTriangle(const char* szCurrent, const char** szCurrentOut) {
void SMDImporter::ParseTriangle(const char *szCurrent, const char **szCurrentOut, const char *end) {
asTriangles.emplace_back();
SMD::Face& face = asTriangles.back();
if(!SkipSpaces(szCurrent,&szCurrent)) {
if(!SkipSpaces(szCurrent, &szCurrent, end)) {
LogErrorNoThrow("Unexpected EOF/EOL while parsing a triangle");
return;
}
@ -963,19 +963,19 @@ void SMDImporter::ParseTriangle(const char* szCurrent, const char** szCurrentOut
// ... and get the index that belongs to this file name
face.iTexture = GetTextureIndex(std::string(szLast,(uintptr_t)szCurrent-(uintptr_t)szLast));
SkipSpacesAndLineEnd(szCurrent,&szCurrent);
SkipSpacesAndLineEnd(szCurrent, &szCurrent, end);
// load three vertices
for (auto &avVertex : face.avVertices) {
ParseVertex(szCurrent,&szCurrent, avVertex);
ParseVertex(szCurrent, &szCurrent, end, avVertex);
}
*szCurrentOut = szCurrent;
}
// ------------------------------------------------------------------------------------------------
// Parse a float
bool SMDImporter::ParseFloat(const char* szCurrent, const char** szCurrentOut, float& out) {
if(!SkipSpaces(&szCurrent)) {
bool SMDImporter::ParseFloat(const char *szCurrent, const char **szCurrentOut, const char *end, float &out) {
if (!SkipSpaces(&szCurrent, end)) {
return false;
}
@ -985,8 +985,8 @@ bool SMDImporter::ParseFloat(const char* szCurrent, const char** szCurrentOut, f
// ------------------------------------------------------------------------------------------------
// Parse an unsigned int
bool SMDImporter::ParseUnsignedInt(const char* szCurrent, const char** szCurrentOut, unsigned int& out) {
if(!SkipSpaces(&szCurrent)) {
bool SMDImporter::ParseUnsignedInt(const char *szCurrent, const char **szCurrentOut, const char *end, unsigned int &out) {
if(!SkipSpaces(&szCurrent, end)) {
return false;
}
@ -996,8 +996,8 @@ bool SMDImporter::ParseUnsignedInt(const char* szCurrent, const char** szCurrent
// ------------------------------------------------------------------------------------------------
// Parse a signed int
bool SMDImporter::ParseSignedInt(const char* szCurrent, const char** szCurrentOut, int& out) {
if(!SkipSpaces(&szCurrent)) {
bool SMDImporter::ParseSignedInt(const char *szCurrent, const char **szCurrentOut, const char *end, int &out) {
if(!SkipSpaces(&szCurrent, end)) {
return false;
}
@ -1008,37 +1008,37 @@ bool SMDImporter::ParseSignedInt(const char* szCurrent, const char** szCurrentOu
// ------------------------------------------------------------------------------------------------
// Parse a vertex
void SMDImporter::ParseVertex(const char* szCurrent,
const char** szCurrentOut, SMD::Vertex& vertex,
const char **szCurrentOut, const char *end, SMD::Vertex &vertex,
bool bVASection /*= false*/) {
if (SkipSpaces(&szCurrent) && IsLineEnd(*szCurrent)) {
SkipSpacesAndLineEnd(szCurrent,&szCurrent);
return ParseVertex(szCurrent,szCurrentOut,vertex,bVASection);
if (SkipSpaces(&szCurrent, end) && IsLineEnd(*szCurrent)) {
SkipSpacesAndLineEnd(szCurrent,&szCurrent, end);
return ParseVertex(szCurrent, szCurrentOut, end, vertex, bVASection);
}
if(!ParseSignedInt(szCurrent,&szCurrent,(int&)vertex.iParentNode)) {
if(!ParseSignedInt(szCurrent, &szCurrent, end, (int&)vertex.iParentNode)) {
LogErrorNoThrow("Unexpected EOF/EOL while parsing vertex.parent");
SMDI_PARSE_RETURN;
}
if(!ParseFloat(szCurrent,&szCurrent,(float&)vertex.pos.x)) {
if(!ParseFloat(szCurrent, &szCurrent, end, (float&)vertex.pos.x)) {
LogErrorNoThrow("Unexpected EOF/EOL while parsing vertex.pos.x");
SMDI_PARSE_RETURN;
}
if(!ParseFloat(szCurrent,&szCurrent,(float&)vertex.pos.y)) {
if(!ParseFloat(szCurrent, &szCurrent, end, (float&)vertex.pos.y)) {
LogErrorNoThrow("Unexpected EOF/EOL while parsing vertex.pos.y");
SMDI_PARSE_RETURN;
}
if(!ParseFloat(szCurrent,&szCurrent,(float&)vertex.pos.z)) {
if(!ParseFloat(szCurrent, &szCurrent, end, (float&)vertex.pos.z)) {
LogErrorNoThrow("Unexpected EOF/EOL while parsing vertex.pos.z");
SMDI_PARSE_RETURN;
}
if(!ParseFloat(szCurrent,&szCurrent,(float&)vertex.nor.x)) {
if(!ParseFloat(szCurrent,&szCurrent,end, (float&)vertex.nor.x)) {
LogErrorNoThrow("Unexpected EOF/EOL while parsing vertex.nor.x");
SMDI_PARSE_RETURN;
}
if(!ParseFloat(szCurrent,&szCurrent,(float&)vertex.nor.y)) {
if(!ParseFloat(szCurrent,&szCurrent, end, (float&)vertex.nor.y)) {
LogErrorNoThrow("Unexpected EOF/EOL while parsing vertex.nor.y");
SMDI_PARSE_RETURN;
}
if(!ParseFloat(szCurrent,&szCurrent,(float&)vertex.nor.z)) {
if(!ParseFloat(szCurrent, &szCurrent, end, (float&)vertex.nor.z)) {
LogErrorNoThrow("Unexpected EOF/EOL while parsing vertex.nor.z");
SMDI_PARSE_RETURN;
}
@ -1047,11 +1047,11 @@ void SMDImporter::ParseVertex(const char* szCurrent,
SMDI_PARSE_RETURN;
}
if(!ParseFloat(szCurrent,&szCurrent,(float&)vertex.uv.x)) {
if(!ParseFloat(szCurrent, &szCurrent, end, (float&)vertex.uv.x)) {
LogErrorNoThrow("Unexpected EOF/EOL while parsing vertex.uv.x");
SMDI_PARSE_RETURN;
}
if(!ParseFloat(szCurrent,&szCurrent,(float&)vertex.uv.y)) {
if(!ParseFloat(szCurrent, &szCurrent, end, (float&)vertex.uv.y)) {
LogErrorNoThrow("Unexpected EOF/EOL while parsing vertex.uv.y");
SMDI_PARSE_RETURN;
}
@ -1059,16 +1059,16 @@ void SMDImporter::ParseVertex(const char* szCurrent,
// now read the number of bones affecting this vertex
// all elements from now are fully optional, we don't need them
unsigned int iSize = 0;
if(!ParseUnsignedInt(szCurrent,&szCurrent,iSize)) {
if(!ParseUnsignedInt(szCurrent, &szCurrent, end, iSize)) {
SMDI_PARSE_RETURN;
}
vertex.aiBoneLinks.resize(iSize,std::pair<unsigned int, float>(0,0.0f));
for (auto &aiBoneLink : vertex.aiBoneLinks) {
if(!ParseUnsignedInt(szCurrent,&szCurrent,aiBoneLink.first)) {
if(!ParseUnsignedInt(szCurrent, &szCurrent, end, aiBoneLink.first)) {
SMDI_PARSE_RETURN;
}
if(!ParseFloat(szCurrent,&szCurrent,aiBoneLink.second)) {
if(!ParseFloat(szCurrent, &szCurrent, end, aiBoneLink.second)) {
SMDI_PARSE_RETURN;
}
}
@ -1077,6 +1077,6 @@ void SMDImporter::ParseVertex(const char* szCurrent,
SMDI_PARSE_RETURN;
}
}
} // namespace Assimp
#endif // !! ASSIMP_BUILD_NO_SMD_IMPORTER

View File

@ -162,7 +162,7 @@ struct Bone {
class ASSIMP_API SMDImporter : public BaseImporter {
public:
SMDImporter();
~SMDImporter() override;
~SMDImporter() override = default;
// -------------------------------------------------------------------
/** Returns whether the class can handle the format of the given file.
@ -206,7 +206,7 @@ protected:
* the next section (or to EOF)
*/
void ParseTrianglesSection(const char* szCurrent,
const char** szCurrentOut);
const char **szCurrentOut, const char *end);
// -------------------------------------------------------------------
/** Parse the vertex animation section in VTA files
@ -216,7 +216,7 @@ protected:
* the next section (or to EOF)
*/
void ParseVASection(const char* szCurrent,
const char** szCurrentOut);
const char **szCurrentOu, const char *end);
// -------------------------------------------------------------------
/** Parse the nodes section of the SMD file
@ -226,7 +226,7 @@ protected:
* the next section (or to EOF)
*/
void ParseNodesSection(const char* szCurrent,
const char** szCurrentOut);
const char **szCurrentOut, const char *end);
// -------------------------------------------------------------------
/** Parse the skeleton section of the SMD file
@ -236,7 +236,7 @@ protected:
* the next section (or to EOF)
*/
void ParseSkeletonSection(const char* szCurrent,
const char** szCurrentOut);
const char **szCurrentOut, const char *end);
// -------------------------------------------------------------------
/** Parse a single triangle in the SMD file
@ -245,8 +245,7 @@ protected:
* \param szCurrentOut Receives the output cursor position
*/
void ParseTriangle(const char* szCurrent,
const char** szCurrentOut);
const char **szCurrentOut, const char *end);
// -------------------------------------------------------------------
/** Parse a single vertex in the SMD file
@ -256,7 +255,7 @@ protected:
* \param vertex Vertex to be filled
*/
void ParseVertex(const char* szCurrent,
const char** szCurrentOut, SMD::Vertex& vertex,
const char **szCurrentOut, const char *end, SMD::Vertex &vertex,
bool bVASection = false);
// -------------------------------------------------------------------
@ -271,32 +270,31 @@ protected:
/** Parse a line in the skeleton section
*/
void ParseSkeletonElement(const char* szCurrent,
const char** szCurrentOut,int iTime);
const char **szCurrentOut, const char *end, int iTime);
// -------------------------------------------------------------------
/** Parse a line in the nodes section
*/
void ParseNodeInfo(const char* szCurrent,
const char** szCurrentOut);
const char **szCurrentOut, const char *end);
// -------------------------------------------------------------------
/** Parse a floating-point value
*/
bool ParseFloat(const char* szCurrent,
const char** szCurrentOut, float& out);
const char **szCurrentOut, const char *end, float &out);
// -------------------------------------------------------------------
/** Parse an unsigned integer. There may be no sign!
*/
bool ParseUnsignedInt(const char* szCurrent,
const char** szCurrentOut, unsigned int& out);
const char **szCurrentOut, const char *end, unsigned int &out);
// -------------------------------------------------------------------
/** Parse a signed integer. Signs (+,-) are handled.
*/
bool ParseSignedInt(const char* szCurrent,
const char** szCurrentOut, int& out);
const char **szCurrentOut, const char *end, int &out);
// -------------------------------------------------------------------
/** Fix invalid time values in the file
@ -304,7 +302,7 @@ protected:
void FixTimeValues();
// -------------------------------------------------------------------
/** Add all children of a bone as subnodes to a node
/** Add all children of a bone as sub-nodes to a node
* \param pcNode Parent node
* \param iParent Parent bone index
*/
@ -329,17 +327,15 @@ protected:
// -------------------------------------------------------------------
inline bool SkipLine( const char* in, const char** out)
{
Assimp::SkipLine(in,out);
inline bool SkipLine( const char* in, const char** out, const char *end) {
Assimp::SkipLine(in, out, end);
++iLineNumber;
return true;
}
// -------------------------------------------------------------------
inline bool SkipSpacesAndLineEnd( const char* in, const char** out)
{
inline bool SkipSpacesAndLineEnd(const char *in, const char **out, const char *end) {
++iLineNumber;
return Assimp::SkipSpacesAndLineEnd(in,out);
return Assimp::SkipSpacesAndLineEnd(in, out, end);
}
private:
@ -349,6 +345,7 @@ private:
/** Buffer to hold the loaded file */
std::vector<char> mBuffer;
char *mEnd;
/** Output scene to be filled
*/

View File

@ -4,7 +4,6 @@ Open Asset Import Library (assimp)
Copyright (c) 2006-2022, assimp team
All rights reserved.
Redistribution and use of this software in source and binary forms,
@ -40,9 +39,10 @@ OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
----------------------------------------------------------------------
*/
/** @file STEPFileReader.cpp
/**
* @file STEPFileReader.cpp
* @brief Implementation of the STEP file parser, which fills a
* STEP::DB with data read from a file.
* STEP::DB with data read from a file.
*/
#include "STEPFileReader.h"
@ -58,34 +58,28 @@ using namespace Assimp;
namespace EXPRESS = STEP::EXPRESS;
// ------------------------------------------------------------------------------------------------
std::string AddLineNumber(const std::string& s,uint64_t line /*= LINE_NOT_SPECIFIED*/, const std::string& prefix = std::string())
{
std::string AddLineNumber(const std::string& s,uint64_t line /*= LINE_NOT_SPECIFIED*/, const std::string& prefix = std::string()) {
return line == STEP::SyntaxError::LINE_NOT_SPECIFIED ? prefix+s : static_cast<std::string>( (Formatter::format(),prefix,"(line ",line,") ",s) );
}
// ------------------------------------------------------------------------------------------------
std::string AddEntityID(const std::string& s,uint64_t entity /*= ENTITY_NOT_SPECIFIED*/, const std::string& prefix = std::string())
{
std::string AddEntityID(const std::string& s,uint64_t entity /*= ENTITY_NOT_SPECIFIED*/, const std::string& prefix = std::string()) {
return entity == STEP::TypeError::ENTITY_NOT_SPECIFIED ? prefix+s : static_cast<std::string>( (Formatter::format(),prefix,"(entity #",entity,") ",s));
}
// ------------------------------------------------------------------------------------------------
STEP::SyntaxError::SyntaxError (const std::string& s,uint64_t line /* = LINE_NOT_SPECIFIED */)
: DeadlyImportError(AddLineNumber(s,line))
{
STEP::SyntaxError::SyntaxError (const std::string& s,uint64_t line) : DeadlyImportError(AddLineNumber(s,line)) {
// empty
}
// ------------------------------------------------------------------------------------------------
STEP::TypeError::TypeError (const std::string& s,uint64_t entity /* = ENTITY_NOT_SPECIFIED */,uint64_t line /*= LINE_NOT_SPECIFIED*/)
: DeadlyImportError(AddLineNumber(AddEntityID(s,entity),line))
{
STEP::TypeError::TypeError (const std::string& s,uint64_t entity, uint64_t line) : DeadlyImportError(AddLineNumber(AddEntityID(s,entity),line)) {
// empty
}
static const char *ISO_Token = "ISO-10303-21;";
static const char *FILE_SCHEMA_Token = "FILE_SCHEMA";
static constexpr char ISO_Token[] = "ISO-10303-21;";
static constexpr char FILE_SCHEMA_Token[] = "FILE_SCHEMA";
// ------------------------------------------------------------------------------------------------
STEP::DB* STEP::ReadFileHeader(std::shared_ptr<IOStream> stream) {
std::shared_ptr<StreamReaderLE> reader = std::shared_ptr<StreamReaderLE>(new StreamReaderLE(std::move(stream)));
@ -110,8 +104,9 @@ STEP::DB* STEP::ReadFileHeader(std::shared_ptr<IOStream> stream) {
if (s.substr(0,11) == FILE_SCHEMA_Token) {
const char* sz = s.c_str()+11;
SkipSpaces(sz,&sz);
std::shared_ptr< const EXPRESS::DataType > schema = EXPRESS::DataType::Parse(sz);
const char *end = s.c_str() + s.size();
SkipSpaces(sz,&sz, end);
std::shared_ptr< const EXPRESS::DataType > schema = EXPRESS::DataType::Parse(sz, end);
// the file schema should be a regular list entity, although it usually contains exactly one entry
// since the list itself is contained in a regular parameter list, we actually have
@ -304,10 +299,10 @@ void STEP::ReadFile(DB& db,const EXPRESS::ConversionSchema& scheme,
}
// ------------------------------------------------------------------------------------------------
std::shared_ptr<const EXPRESS::DataType> EXPRESS::DataType::Parse(const char*& inout,uint64_t line, const EXPRESS::ConversionSchema* schema /*= nullptr*/)
std::shared_ptr<const EXPRESS::DataType> EXPRESS::DataType::Parse(const char*& inout, const char *end, uint64_t line, const EXPRESS::ConversionSchema* schema /*= nullptr*/)
{
const char* cur = inout;
SkipSpaces(&cur);
SkipSpaces(&cur, end);
if (*cur == ',' || IsSpaceOrNewLine(*cur)) {
throw STEP::SyntaxError("unexpected token, expected parameter",line);
}
@ -325,7 +320,7 @@ std::shared_ptr<const EXPRESS::DataType> EXPRESS::DataType::Parse(const char*& i
std::transform(s.begin(),s.end(),s.begin(),&ai_tolower<char> );
if (schema->IsKnownToken(s)) {
for(cur = t+1;*cur++ != '(';);
std::shared_ptr<const EXPRESS::DataType> dt = Parse(cur);
std::shared_ptr<const EXPRESS::DataType> dt = Parse(cur, end);
inout = *cur ? cur+1 : cur;
return dt;
}
@ -348,7 +343,7 @@ std::shared_ptr<const EXPRESS::DataType> EXPRESS::DataType::Parse(const char*& i
else if (*cur == '(' ) {
// start of an aggregate, further parsing is done by the LIST factory constructor
inout = cur;
return EXPRESS::LIST::Parse(inout,line,schema);
return EXPRESS::LIST::Parse(inout, end, line, schema);
}
else if (*cur == '.' ) {
// enum (includes boolean)
@ -427,9 +422,10 @@ std::shared_ptr<const EXPRESS::DataType> EXPRESS::DataType::Parse(const char*& i
}
// ------------------------------------------------------------------------------------------------
std::shared_ptr<const EXPRESS::LIST> EXPRESS::LIST::Parse(const char*& inout,uint64_t line, const EXPRESS::ConversionSchema* schema /*= nullptr*/) {
std::shared_ptr<const EXPRESS::LIST> EXPRESS::LIST::Parse(const char*& inout, const char *end,
uint64_t line, const EXPRESS::ConversionSchema* schema) {
const std::shared_ptr<EXPRESS::LIST> list = std::make_shared<EXPRESS::LIST>();
EXPRESS::LIST::MemberList& members = list->members;
EXPRESS::LIST::MemberList& cur_members = list->members;
const char* cur = inout;
if (*cur++ != '(') {
@ -442,19 +438,19 @@ std::shared_ptr<const EXPRESS::LIST> EXPRESS::LIST::Parse(const char*& inout,uin
count += (*c == ',' ? 1 : 0);
}
members.reserve(count);
cur_members.reserve(count);
for(;;++cur) {
if (!*cur) {
throw STEP::SyntaxError("unexpected end of line while reading list");
}
SkipSpaces(cur,&cur);
SkipSpaces(cur,&cur, end);
if (*cur == ')') {
break;
}
members.push_back( EXPRESS::DataType::Parse(cur,line,schema));
SkipSpaces(cur,&cur);
cur_members.push_back(EXPRESS::DataType::Parse(cur, end, line, schema));
SkipSpaces(cur, &cur, end);
if (*cur != ',') {
if (*cur == ')') {
@ -464,7 +460,7 @@ std::shared_ptr<const EXPRESS::LIST> EXPRESS::LIST::Parse(const char*& inout,uin
}
}
inout = cur+1;
inout = cur + 1;
return list;
}
@ -543,7 +539,8 @@ void STEP::LazyObject::LazyInit() const {
}
const char* acopy = args;
std::shared_ptr<const EXPRESS::LIST> conv_args = EXPRESS::LIST::Parse(acopy,(uint64_t)STEP::SyntaxError::LINE_NOT_SPECIFIED,&db.GetSchema());
const char *end = acopy + std::strlen(args);
std::shared_ptr<const EXPRESS::LIST> conv_args = EXPRESS::LIST::Parse(acopy, end, (uint64_t)STEP::SyntaxError::LINE_NOT_SPECIFIED,&db.GetSchema());
delete[] args;
args = nullptr;

View File

@ -60,8 +60,7 @@ void ReadFile(DB& db,const EXPRESS::ConversionSchema& scheme, const char* const*
/// @brief Helper to read a file.
template <size_t N, size_t N2>
inline
void ReadFile(DB& db,const EXPRESS::ConversionSchema& scheme, const char* const (&arr)[N], const char* const (&arr2)[N2]) {
inline void ReadFile(DB& db,const EXPRESS::ConversionSchema& scheme, const char* const (&arr)[N], const char* const (&arr2)[N2]) {
return ReadFile(db,scheme,arr,N,arr2,N2);
}

View File

@ -98,7 +98,7 @@ static bool IsAsciiSTL(const char *buffer, size_t fileSize) {
const char *bufferEnd = buffer + fileSize;
if (!SkipSpaces(&buffer)) {
if (!SkipSpaces(&buffer, bufferEnd)) {
return false;
}
@ -244,11 +244,11 @@ void STLImporter::LoadASCIIFile(aiNode *root) {
aiNode *node = new aiNode;
node->mParent = root;
nodes.push_back(node);
SkipSpaces(&sz);
SkipSpaces(&sz, bufferEnd);
ai_assert(!IsLineEnd(sz));
sz += 5; // skip the "solid"
SkipSpaces(&sz);
SkipSpaces(&sz, bufferEnd);
const char *szMe = sz;
while (!IsSpaceOrNewLine(*sz)) {
sz++;
@ -270,7 +270,7 @@ void STLImporter::LoadASCIIFile(aiNode *root) {
unsigned int faceVertexCounter = 3;
for (;;) {
// go to the next token
if (!SkipSpacesAndLineEnd(&sz)) {
if (!SkipSpacesAndLineEnd(&sz, bufferEnd)) {
// seems we're finished although there was no end marker
ASSIMP_LOG_WARN("STL: unexpected EOF. \'endsolid\' keyword was expected");
break;
@ -284,7 +284,7 @@ void STLImporter::LoadASCIIFile(aiNode *root) {
faceVertexCounter = 0;
sz += 6;
SkipSpaces(&sz);
SkipSpaces(&sz, bufferEnd);
if (strncmp(sz, "normal", 6)) {
ASSIMP_LOG_WARN("STL: a facet normal vector was expected but not found");
} else {
@ -293,11 +293,11 @@ void STLImporter::LoadASCIIFile(aiNode *root) {
}
aiVector3D vn;
sz += 7;
SkipSpaces(&sz);
SkipSpaces(&sz, bufferEnd);
sz = fast_atoreal_move<ai_real>(sz, (ai_real &)vn.x);
SkipSpaces(&sz);
SkipSpaces(&sz, bufferEnd);
sz = fast_atoreal_move<ai_real>(sz, (ai_real &)vn.y);
SkipSpaces(&sz);
SkipSpaces(&sz, bufferEnd);
sz = fast_atoreal_move<ai_real>(sz, (ai_real &)vn.z);
normalBuffer.emplace_back(vn);
normalBuffer.emplace_back(vn);
@ -312,13 +312,13 @@ void STLImporter::LoadASCIIFile(aiNode *root) {
throw DeadlyImportError("STL: unexpected EOF while parsing facet");
}
sz += 7;
SkipSpaces(&sz);
SkipSpaces(&sz, bufferEnd);
positionBuffer.emplace_back();
aiVector3D *vn = &positionBuffer.back();
sz = fast_atoreal_move<ai_real>(sz, (ai_real &)vn->x);
SkipSpaces(&sz);
SkipSpaces(&sz, bufferEnd);
sz = fast_atoreal_move<ai_real>(sz, (ai_real &)vn->y);
SkipSpaces(&sz);
SkipSpaces(&sz, bufferEnd);
sz = fast_atoreal_move<ai_real>(sz, (ai_real &)vn->z);
faceVertexCounter++;
}
@ -326,7 +326,7 @@ void STLImporter::LoadASCIIFile(aiNode *root) {
do {
++sz;
} while (!IsLineEnd(*sz));
SkipSpacesAndLineEnd(&sz);
SkipSpacesAndLineEnd(&sz, bufferEnd);
// finished!
break;
} else { // else skip the whole identifier

View File

@ -199,35 +199,27 @@ public:
}
public:
/** parse a variable from a string and set 'inout' to the character
* behind the last consumed character. An optional schema enables,
* if specified, automatic conversion of custom data types.
*
* @throw SyntaxError
*/
static std::shared_ptr<const EXPRESS::DataType> Parse(const char *&inout,
uint64_t line = SyntaxError::LINE_NOT_SPECIFIED,
const EXPRESS::ConversionSchema *schema = nullptr);
/// @brief Parse a variable from a string and set 'inout' to the character behind the last consumed character.
///
/// An optional schema enables, if specified, automatic conversion of custom data types.
///
/// @throw SyntaxError
static std::shared_ptr<const EXPRESS::DataType> Parse(const char *&inout, const char *end,
uint64_t line = SyntaxError::LINE_NOT_SPECIFIED, const EXPRESS::ConversionSchema *schema = nullptr);
};
typedef DataType SELECT;
typedef DataType LOGICAL;
// -------------------------------------------------------------------------------
/** Sentinel class to represent explicitly unset (optional) fields ($) */
/// Sentinel class to represent explicitly unset (optional) fields ($)
// -------------------------------------------------------------------------------
class UNSET : public DataType {
public:
private:
};
class UNSET : public DataType {};
// -------------------------------------------------------------------------------
/** Sentinel class to represent explicitly derived fields (*) */
/// Sentinel class to represent explicitly derived fields (*)
// -------------------------------------------------------------------------------
class ISDERIVED : public DataType {
public:
private:
};
class ISDERIVED : public DataType {};
// -------------------------------------------------------------------------------
/** Shared implementation for some of the primitive data type, i.e. int, float
@ -304,7 +296,7 @@ public:
public:
/** @see DaraType::Parse
*/
static std::shared_ptr<const EXPRESS::LIST> Parse(const char *&inout,
static std::shared_ptr<const EXPRESS::LIST> Parse(const char *&inout, const char *end,
uint64_t line = SyntaxError::LINE_NOT_SPECIFIED,
const EXPRESS::ConversionSchema *schema = nullptr);

View File

@ -320,17 +320,18 @@ void UnrealImporter::InternReadFile(const std::string &pFile,
std::vector<char> _data;
TextFileToBuffer(pb.get(), _data);
const char *data = &_data[0];
const char *end = &_data[_data.size() - 1] + 1;
std::vector<std::pair<std::string, std::string>> tempTextures;
// do a quick search in the UC file for some known, usually texture-related, tags
for (; *data; ++data) {
if (TokenMatchI(data, "#exec", 5)) {
SkipSpacesAndLineEnd(&data);
SkipSpacesAndLineEnd(&data, end);
// #exec TEXTURE IMPORT [...] NAME=jjjjj [...] FILE=jjjj.pcx [...]
if (TokenMatchI(data, "TEXTURE", 7)) {
SkipSpacesAndLineEnd(&data);
SkipSpacesAndLineEnd(&data, end);
if (TokenMatchI(data, "IMPORT", 6)) {
tempTextures.emplace_back();
@ -348,14 +349,15 @@ void UnrealImporter::InternReadFile(const std::string &pFile,
me.second = std::string(d, (size_t)(data - d));
}
}
if (!me.first.length() || !me.second.length())
if (!me.first.length() || !me.second.length()) {
tempTextures.pop_back();
}
}
}
// #exec MESHMAP SETTEXTURE MESHMAP=box NUM=1 TEXTURE=Jtex1
// #exec MESHMAP SCALE MESHMAP=box X=0.1 Y=0.1 Z=0.2
else if (TokenMatchI(data, "MESHMAP", 7)) {
SkipSpacesAndLineEnd(&data);
SkipSpacesAndLineEnd(&data, end);
if (TokenMatchI(data, "SETTEXTURE", 10)) {
@ -369,8 +371,7 @@ void UnrealImporter::InternReadFile(const std::string &pFile,
} else if (!ASSIMP_strincmp(data, "TEXTURE=", 8)) {
data += 8;
const char *d = data;
for (; !IsSpaceOrNewLine(*data); ++data)
;
for (; !IsSpaceOrNewLine(*data); ++data);
me.second = std::string(d, (size_t)(data - d));
// try to find matching path names, doesn't care if we don't find them
@ -408,7 +409,7 @@ void UnrealImporter::InternReadFile(const std::string &pFile,
// find out how many output meshes and materials we'll have and build material indices
for (Unreal::Triangle &tri : triangles) {
Unreal::TempMat mat(tri);
std::vector<Unreal::TempMat>::iterator nt = std::find(materials.begin(), materials.end(), mat);
auto nt = std::find(materials.begin(), materials.end(), mat);
if (nt == materials.end()) {
// add material
tri.matIndex = static_cast<unsigned int>(materials.size());

View File

@ -700,13 +700,14 @@ unsigned int XGLImporter::ReadIDAttr(XmlNode &node) {
float XGLImporter::ReadFloat(XmlNode &node) {
std::string v;
XmlParser::getValueAsString(node, v);
const char *s = v.c_str(), *se;
if (!SkipSpaces(&s)) {
const char *s = v.c_str();
const char *end = v.c_str() + v.size();
if (!SkipSpaces(&s, end)) {
LogError("unexpected EOL, failed to parse index element");
return 0.f;
}
float t;
se = fast_atoreal_move(s, t);
float t{ 0.0f };
const char *se = fast_atoreal_move(s, t);
if (se == s) {
LogError("failed to read float text");
return 0.f;
@ -720,7 +721,8 @@ unsigned int XGLImporter::ReadIndexFromText(XmlNode &node) {
std::string v;
XmlParser::getValueAsString(node, v);
const char *s = v.c_str();
if (!SkipSpaces(&s)) {
const char *end = v.c_str() + v.size();
if (!SkipSpaces(&s, end)) {
LogError("unexpected EOL, failed to parse index element");
return ErrorId;
}
@ -741,16 +743,17 @@ aiVector2D XGLImporter::ReadVec2(XmlNode &node) {
std::string val;
XmlParser::getValueAsString(node, val);
const char *s = val.c_str();
const char *end = val.c_str() + val.size();
ai_real v[2] = {};
for (int i = 0; i < 2; ++i) {
if (!SkipSpaces(&s)) {
if (!SkipSpaces(&s, end)) {
LogError("unexpected EOL, failed to parse vec2");
return vec;
}
v[i] = fast_atof(&s);
SkipSpaces(&s);
SkipSpaces(&s, end);
if (i != 1 && *s != ',') {
LogError("expected comma, failed to parse vec2");
return vec;
@ -769,14 +772,15 @@ aiVector3D XGLImporter::ReadVec3(XmlNode &node) {
std::string v;
XmlParser::getValueAsString(node, v);
const char *s = v.c_str();
const char *end = v.c_str() + v.size();
for (int i = 0; i < 3; ++i) {
if (!SkipSpaces(&s)) {
if (!SkipSpaces(&s, end)) {
LogError("unexpected EOL, failed to parse vec3");
return vec;
}
vec[i] = fast_atof(&s);
SkipSpaces(&s);
SkipSpaces(&s, end);
if (i != 2 && *s != ',') {
LogError("expected comma, failed to parse vec3");
return vec;

View File

@ -1193,6 +1193,10 @@ ENDIF ()
TARGET_USE_COMMON_OUTPUT_DIRECTORY(assimp)
add_compile_options(
"$<$<CONFIG:DEBUG>:-O0;-g3;-ggdb>"
)
IF (ASSIMP_WARNINGS_AS_ERRORS)
MESSAGE(STATUS "Treating all warnings as errors (for assimp library only)")
IF (MSVC)

View File

@ -52,8 +52,9 @@ namespace Assimp {
// -------------------------------------------------------------------------------
void ConvertListToStrings(const std::string &in, std::list<std::string> &out) {
const char *s = in.c_str();
const char *end = in.c_str() + in.size();
while (*s) {
SkipSpacesAndLineEnd(&s);
SkipSpacesAndLineEnd(&s, end);
if (*s == '\'') {
const char *base = ++s;
while (*s != '\'') {
@ -66,7 +67,7 @@ void ConvertListToStrings(const std::string &in, std::list<std::string> &out) {
out.emplace_back(base, (size_t)(s - base));
++s;
} else {
out.push_back(GetNextToken(s));
out.push_back(GetNextToken(s, end));
}
}
}

View File

@ -110,6 +110,8 @@ public:
std::string operator* () const;
const char *getEnd() const;
// -----------------------------------------
/** boolean context */
operator bool() const;
@ -139,17 +141,21 @@ public:
private:
line_idx mIdx;
std::string mCur;
const char *mEnd;
StreamReaderLE& mStream;
bool mSwallow, mSkip_empty_lines, mTrim;
};
AI_FORCE_INLINE LineSplitter::LineSplitter(StreamReaderLE& stream, bool skip_empty_lines, bool trim ) :
mIdx(0),
mCur(),
mEnd(nullptr),
mStream(stream),
mSwallow(),
mSkip_empty_lines(skip_empty_lines),
mTrim(trim) {
mCur.reserve(1024);
mEnd = mCur.c_str() + 1024;
operator++();
mIdx = 0;
}
@ -203,14 +209,14 @@ AI_FORCE_INLINE LineSplitter &LineSplitter::operator++(int) {
AI_FORCE_INLINE const char *LineSplitter::operator[] (size_t idx) const {
const char* s = operator->()->c_str();
SkipSpaces(&s);
SkipSpaces(&s, mEnd);
for (size_t i = 0; i < idx; ++i) {
for (; !IsSpace(*s); ++s) {
if (IsLineEnd(*s)) {
throw std::range_error("Token index out of range, EOL reached");
}
}
SkipSpaces(&s);
SkipSpaces(&s, mEnd);
}
return s;
}
@ -219,7 +225,7 @@ template <size_t N>
AI_FORCE_INLINE void LineSplitter::get_tokens(const char* (&tokens)[N]) const {
const char* s = operator->()->c_str();
SkipSpaces(&s);
SkipSpaces(&s, mEnd);
for (size_t i = 0; i < N; ++i) {
if (IsLineEnd(*s)) {
throw std::range_error("Token count out of range, EOL reached");
@ -227,7 +233,7 @@ AI_FORCE_INLINE void LineSplitter::get_tokens(const char* (&tokens)[N]) const {
tokens[i] = s;
for (; *s && !IsSpace(*s); ++s);
SkipSpaces(&s);
SkipSpaces(&s, mEnd);
}
}
@ -239,6 +245,10 @@ AI_FORCE_INLINE std::string LineSplitter::operator* () const {
return mCur;
}
AI_FORCE_INLINE const char* LineSplitter::getEnd() const {
return mEnd;
}
AI_FORCE_INLINE LineSplitter::operator bool() const {
return mStream.GetRemainingSize() > 0;
}

View File

@ -102,8 +102,8 @@ AI_FORCE_INLINE bool IsSpaceOrNewLine(char_t in) {
// ---------------------------------------------------------------------------------
template <class char_t>
AI_FORCE_INLINE bool SkipSpaces(const char_t *in, const char_t **out) {
while (*in == (char_t)' ' || *in == (char_t)'\t') {
AI_FORCE_INLINE bool SkipSpaces(const char_t *in, const char_t **out, const char_t *end) {
while ((*in == (char_t)' ' || *in == (char_t)'\t') && in != end) {
++in;
}
*out = in;
@ -112,19 +112,19 @@ AI_FORCE_INLINE bool SkipSpaces(const char_t *in, const char_t **out) {
// ---------------------------------------------------------------------------------
template <class char_t>
AI_FORCE_INLINE bool SkipSpaces(const char_t **inout) {
return SkipSpaces<char_t>(*inout, inout);
AI_FORCE_INLINE bool SkipSpaces(const char_t **inout, const char_t *end) {
return SkipSpaces<char_t>(*inout, inout, end);
}
// ---------------------------------------------------------------------------------
template <class char_t>
AI_FORCE_INLINE bool SkipLine(const char_t *in, const char_t **out) {
while (*in != (char_t)'\r' && *in != (char_t)'\n' && *in != (char_t)'\0') {
AI_FORCE_INLINE bool SkipLine(const char_t *in, const char_t **out, const char_t *end) {
while ((*in != (char_t)'\r' && *in != (char_t)'\n' && *in != (char_t)'\0') && in != end) {
++in;
}
// files are opened in binary mode. Ergo there are both NL and CR
while (*in == (char_t)'\r' || *in == (char_t)'\n') {
while ((*in == (char_t)'\r' || *in == (char_t)'\n') && in != end) {
++in;
}
*out = in;
@ -133,14 +133,14 @@ AI_FORCE_INLINE bool SkipLine(const char_t *in, const char_t **out) {
// ---------------------------------------------------------------------------------
template <class char_t>
AI_FORCE_INLINE bool SkipLine(const char_t **inout) {
return SkipLine<char_t>(*inout, inout);
AI_FORCE_INLINE bool SkipLine(const char_t **inout, const char_t *end) {
return SkipLine<char_t>(*inout, inout, end);
}
// ---------------------------------------------------------------------------------
template <class char_t>
AI_FORCE_INLINE bool SkipSpacesAndLineEnd(const char_t *in, const char_t **out) {
while (*in == (char_t)' ' || *in == (char_t)'\t' || *in == (char_t)'\r' || *in == (char_t)'\n') {
AI_FORCE_INLINE bool SkipSpacesAndLineEnd(const char_t *in, const char_t **out, const char_t *end) {
while ((*in == (char_t)' ' || *in == (char_t)'\t' || *in == (char_t)'\r' || *in == (char_t)'\n') && in != end) {
++in;
}
*out = in;
@ -149,8 +149,8 @@ AI_FORCE_INLINE bool SkipSpacesAndLineEnd(const char_t *in, const char_t **out)
// ---------------------------------------------------------------------------------
template <class char_t>
AI_FORCE_INLINE bool SkipSpacesAndLineEnd(const char_t **inout) {
return SkipSpacesAndLineEnd<char_t>(*inout, inout);
AI_FORCE_INLINE bool SkipSpacesAndLineEnd(const char_t **inout, const char_t *end) {
return SkipSpacesAndLineEnd<char_t>(*inout, inout, end);
}
// ---------------------------------------------------------------------------------
@ -210,16 +210,16 @@ AI_FORCE_INLINE bool TokenMatchI(const char *&in, const char *token, unsigned in
}
// ---------------------------------------------------------------------------------
AI_FORCE_INLINE void SkipToken(const char *&in) {
SkipSpaces(&in);
AI_FORCE_INLINE void SkipToken(const char *&in, const char *end) {
SkipSpaces(&in, end);
while (!IsSpaceOrNewLine(*in)) {
++in;
}
}
// ---------------------------------------------------------------------------------
AI_FORCE_INLINE std::string GetNextToken(const char *&in) {
SkipSpacesAndLineEnd(&in);
AI_FORCE_INLINE std::string GetNextToken(const char *&in, const char *end) {
SkipSpacesAndLineEnd(&in, end);
const char *cur = in;
while (!IsSpaceOrNewLine(*in)) {
++in;