From 7b54b0f40623b7c5e3a657f03dfe1fa06926ed79 Mon Sep 17 00:00:00 2001 From: Kim Kulling Date: Thu, 21 Dec 2023 20:54:49 +0100 Subject: [PATCH 01/77] Fix leak - closes https://github.com/assimp/assimp/issues/5390 --- code/AssetLib/Irr/IRRLoader.cpp | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/code/AssetLib/Irr/IRRLoader.cpp b/code/AssetLib/Irr/IRRLoader.cpp index 99e053892..2a481a6d8 100644 --- a/code/AssetLib/Irr/IRRLoader.cpp +++ b/code/AssetLib/Irr/IRRLoader.cpp @@ -1234,7 +1234,10 @@ void IRRImporter::InternReadFile(const std::string &pFile, aiScene *pScene, IOSy // Parse the XML // Find the scene root from document root. const pugi::xml_node &sceneRoot = documentRoot.child("irr_scene"); - if (!sceneRoot) throw new DeadlyImportError("IRR: not found in file"); + if (!sceneRoot) { + delete root; + throw new DeadlyImportError("IRR: not found in file"); + } for (pugi::xml_node &child : sceneRoot.children()) { // XML elements are either nodes, animators, attributes, or materials if (!ASSIMP_stricmp(child.name(), "node")) { From 274f64cbf1942328b74d22dcc246d568670a8b68 Mon Sep 17 00:00:00 2001 From: Kim Kulling Date: Fri, 22 Dec 2023 09:45:37 +0100 Subject: [PATCH 02/77] Check validity of archive without parsing - closes https://github.com/assimp/assimp/issues/5392 --- code/AssetLib/3MF/D3MFImporter.cpp | 11 ++++++++--- 1 file changed, 8 insertions(+), 3 deletions(-) diff --git a/code/AssetLib/3MF/D3MFImporter.cpp b/code/AssetLib/3MF/D3MFImporter.cpp index e8529064c..2633bacf4 100644 --- a/code/AssetLib/3MF/D3MFImporter.cpp +++ b/code/AssetLib/3MF/D3MFImporter.cpp @@ -81,12 +81,17 @@ static constexpr aiImporterDesc desc = { "3mf" }; -bool D3MFImporter::CanRead(const std::string &filename, IOSystem *pIOHandler, bool /*checkSig*/) const { +bool D3MFImporter::CanRead(const std::string &filename, IOSystem *pIOHandler, bool ) const { if (!ZipArchiveIOSystem::isZipArchive(pIOHandler, filename)) { return false; } - D3MF::D3MFOpcPackage opcPackage(pIOHandler, filename); - return opcPackage.validate(); + + ZipArchiveIOSystem archive(pIOHandler, rFile); + if (!mZipArchive->archive()) { + return false; + } + + return true; } void D3MFImporter::SetupProperties(const Importer*) { From b9576e6992ba2ec7b3468d6f51a53d2258ccdc0f Mon Sep 17 00:00:00 2001 From: Kim Kulling Date: Fri, 22 Dec 2023 10:32:54 +0100 Subject: [PATCH 03/77] Update D3MFImporter.cpp --- code/AssetLib/3MF/D3MFImporter.cpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/code/AssetLib/3MF/D3MFImporter.cpp b/code/AssetLib/3MF/D3MFImporter.cpp index 2633bacf4..5508c2505 100644 --- a/code/AssetLib/3MF/D3MFImporter.cpp +++ b/code/AssetLib/3MF/D3MFImporter.cpp @@ -85,9 +85,9 @@ bool D3MFImporter::CanRead(const std::string &filename, IOSystem *pIOHandler, bo if (!ZipArchiveIOSystem::isZipArchive(pIOHandler, filename)) { return false; } - + static const char *const ModelRef = "3D/3dmodel.model"; ZipArchiveIOSystem archive(pIOHandler, rFile); - if (!mZipArchive->archive()) { + if (!archive.Exists(ModelRef)) { return false; } From 9dddef9b9dff03f341a7a22b0e8d5178f8b1f2d3 Mon Sep 17 00:00:00 2001 From: Kim Kulling Date: Fri, 22 Dec 2023 10:37:34 +0100 Subject: [PATCH 04/77] Update D3MFImporter.cpp --- code/AssetLib/3MF/D3MFImporter.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/code/AssetLib/3MF/D3MFImporter.cpp b/code/AssetLib/3MF/D3MFImporter.cpp index 5508c2505..9a5081db9 100644 --- a/code/AssetLib/3MF/D3MFImporter.cpp +++ b/code/AssetLib/3MF/D3MFImporter.cpp @@ -86,7 +86,7 @@ bool D3MFImporter::CanRead(const std::string &filename, IOSystem *pIOHandler, bo return false; } static const char *const ModelRef = "3D/3dmodel.model"; - ZipArchiveIOSystem archive(pIOHandler, rFile); + ZipArchiveIOSystem archive(pIOHandler, filename); if (!archive.Exists(ModelRef)) { return false; } From 69dae9599a4bf7c7ce50a6ed672ef3d017cb1f90 Mon Sep 17 00:00:00 2001 From: Kim Kulling Date: Fri, 22 Dec 2023 11:57:43 +0100 Subject: [PATCH 05/77] Fix integer overflow - closes https://github.com/assimp/assimp/issues/4930 --- code/AssetLib/MDL/MDLMaterialLoader.cpp | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/code/AssetLib/MDL/MDLMaterialLoader.cpp b/code/AssetLib/MDL/MDLMaterialLoader.cpp index 3d39fa645..57ed6c7b9 100644 --- a/code/AssetLib/MDL/MDLMaterialLoader.cpp +++ b/code/AssetLib/MDL/MDLMaterialLoader.cpp @@ -123,9 +123,8 @@ aiColor4D MDLImporter::ReplaceTextureWithColor(const aiTexture *pcTexture) { // Read a texture from a MDL3 file void MDLImporter::CreateTextureARGB8_3DGS_MDL3(const unsigned char *szData) { const MDL::Header *pcHeader = (const MDL::Header *)mBuffer; //the endianness is already corrected in the InternReadFile_3DGS_MDL345 function - - VALIDATE_FILE_SIZE(szData + pcHeader->skinwidth * - pcHeader->skinheight); + const size_t len = pcHeader->skinwidth * pcHeader->skinheight); + VALIDATE_FILE_SIZE(szData + len); // allocate a new texture object aiTexture *pcNew = new aiTexture(); From 5d5496f1ad895297cede723b3c96b513263f82ed Mon Sep 17 00:00:00 2001 From: Kim Kulling Date: Fri, 22 Dec 2023 13:06:10 +0100 Subject: [PATCH 06/77] Update MDLMaterialLoader.cpp --- code/AssetLib/MDL/MDLMaterialLoader.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/code/AssetLib/MDL/MDLMaterialLoader.cpp b/code/AssetLib/MDL/MDLMaterialLoader.cpp index 57ed6c7b9..f8dafdb3e 100644 --- a/code/AssetLib/MDL/MDLMaterialLoader.cpp +++ b/code/AssetLib/MDL/MDLMaterialLoader.cpp @@ -123,7 +123,7 @@ aiColor4D MDLImporter::ReplaceTextureWithColor(const aiTexture *pcTexture) { // Read a texture from a MDL3 file void MDLImporter::CreateTextureARGB8_3DGS_MDL3(const unsigned char *szData) { const MDL::Header *pcHeader = (const MDL::Header *)mBuffer; //the endianness is already corrected in the InternReadFile_3DGS_MDL345 function - const size_t len = pcHeader->skinwidth * pcHeader->skinheight); + const size_t len = pcHeader->skinwidth * pcHeader->skinheight; VALIDATE_FILE_SIZE(szData + len); // allocate a new texture object From 263bebb5baace5d7869aa348015257279ebfc5e9 Mon Sep 17 00:00:00 2001 From: Kim Kulling Date: Fri, 29 Dec 2023 16:30:42 +0100 Subject: [PATCH 07/77] Add a test before generating the txture folder --- code/Pbrt/PbrtExporter.cpp | 18 +++-- test/CMakeLists.txt | 1 + .../ImportExport/Pbrt/utPbrtImportExport.cpp | 70 +++++++++++++++++++ 3 files changed, 85 insertions(+), 4 deletions(-) create mode 100644 test/unit/ImportExport/Pbrt/utPbrtImportExport.cpp diff --git a/code/Pbrt/PbrtExporter.cpp b/code/Pbrt/PbrtExporter.cpp index 67937019f..6191b6ba1 100644 --- a/code/Pbrt/PbrtExporter.cpp +++ b/code/Pbrt/PbrtExporter.cpp @@ -97,13 +97,23 @@ void ExportScenePbrt ( ){ std::string path = DefaultIOSystem::absolutePath(std::string(pFile)); std::string file = DefaultIOSystem::completeBaseName(std::string(pFile)); - + path = path + file + ".brt"; // initialize the exporter PbrtExporter exporter(pScene, pIOSystem, path, file); } } // end of namespace Assimp +static void create_embedded_textures_folder(const aiScene *scene, IOSystem *pIOSystem) { + if (scene->mNumTextures > 0) { + if (!pIOSystem->Exists("textures")) { + if (!pIOSystem->CreateDirectory("textures")) { + throw DeadlyExportError("Could not create textures/ directory."); + } + } + } +} + // Constructor PbrtExporter::PbrtExporter( const aiScene *pScene, IOSystem *pIOSystem, @@ -127,10 +137,10 @@ PbrtExporter::PbrtExporter( 0.f, 0.f, 1.f, 0.f, // 0.f, 0.f, 0.f, 1.f // ) * mRootTransform; + // Export embedded textures. - if (mScene->mNumTextures > 0) - if (!mIOSystem->CreateDirectory("textures")) - throw DeadlyExportError("Could not create textures/ directory."); + create_embedded_textures_folder(mScene, mIOSystem); + for (unsigned int i = 0; i < mScene->mNumTextures; ++i) { aiTexture* tex = mScene->mTextures[i]; std::string fn = CleanTextureFilename(tex->mFilename, false); diff --git a/test/CMakeLists.txt b/test/CMakeLists.txt index afe487411..da6a5b00b 100644 --- a/test/CMakeLists.txt +++ b/test/CMakeLists.txt @@ -165,6 +165,7 @@ SET( IMPORTERS unit/ImportExport/MDL/utMDLImporter_HL1_Nodes.cpp unit/ImportExport/RAW/utRAWImportExport.cpp unit/ImportExport/Terragen/utTerragenImportExport.cpp + unit/ImportExport/Pbrt/utPbrtImportExport.cpp ) SET( MATERIAL diff --git a/test/unit/ImportExport/Pbrt/utPbrtImportExport.cpp b/test/unit/ImportExport/Pbrt/utPbrtImportExport.cpp new file mode 100644 index 000000000..c7807205a --- /dev/null +++ b/test/unit/ImportExport/Pbrt/utPbrtImportExport.cpp @@ -0,0 +1,70 @@ +/* +--------------------------------------------------------------------------- +Open Asset Import Library (assimp) +--------------------------------------------------------------------------- + +Copyright (c) 2006-2020, assimp team + +All rights reserved. + +Redistribution and use of this software in source and binary forms, +with or without modification, are permitted provided that the following +conditions are met: + +* Redistributions of source code must retain the above +copyright notice, this list of conditions and the +following disclaimer. + +* Redistributions in binary form must reproduce the above +copyright notice, this list of conditions and the +following disclaimer in the documentation and/or other +materials provided with the distribution. + +* Neither the name of the assimp team, nor the names of its +contributors may be used to endorse or promote products +derived from this software without specific prior +written permission of the assimp team. + +THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +--------------------------------------------------------------------------- +*/ +#include "AbstractImportExportBase.h" +#include "UnitTestPCH.h" +#include +#include +#include +#include + +using namespace Assimp; + +class utPbrtImportExport : public AbstractImportExportBase { +public: +#ifndef ASSIMP_BUILD_NO_EXPORT + bool exporterTest() override { + Assimp::Importer importer; + const aiScene *scene = importer.ReadFile(ASSIMP_TEST_MODELS_DIR "/OBJ/spider.obj", aiProcess_ValidateDataStructure); + EXPECT_NE(scene, nullptr ); + + ::Assimp::Exporter exporter; + return AI_SUCCESS == exporter.Export(scene, "pbrt", ASSIMP_TEST_MODELS_DIR "/OBJ/spider_out.pbrt"); + } +#endif +}; + +#ifndef ASSIMP_BUILD_NO_EXPORT + +TEST_F(utPbrtImportExport, exportTest_Success) { + EXPECT_TRUE(exporterTest()); +} + +#endif // ASSIMP_BUILD_NO_EXPORT From 636fbd65b3ff1e4f4ae11cec6380b86d07efc682 Mon Sep 17 00:00:00 2001 From: Kim Kulling Date: Fri, 29 Dec 2023 16:47:21 +0100 Subject: [PATCH 08/77] Refactorings: come code cleanups --- code/Pbrt/PbrtExporter.cpp | 14 +++------- code/Pbrt/PbrtExporter.h | 52 +++++++++++++++---------------------- include/assimp/IOSystem.hpp | 10 ++----- 3 files changed, 26 insertions(+), 50 deletions(-) diff --git a/code/Pbrt/PbrtExporter.cpp b/code/Pbrt/PbrtExporter.cpp index 6191b6ba1..9e4ca293d 100644 --- a/code/Pbrt/PbrtExporter.cpp +++ b/code/Pbrt/PbrtExporter.cpp @@ -89,15 +89,11 @@ using namespace Assimp; namespace Assimp { -void ExportScenePbrt ( - const char* pFile, - IOSystem* pIOSystem, - const aiScene* pScene, - const ExportProperties* /*pProperties*/ -){ +void ExportScenePbrt(const char *pFile, IOSystem *pIOSystem, const aiScene *pScene, + const ExportProperties *) { std::string path = DefaultIOSystem::absolutePath(std::string(pFile)); std::string file = DefaultIOSystem::completeBaseName(std::string(pFile)); - path = path + file + ".brt"; + path = path + file + ".pbrt"; // initialize the exporter PbrtExporter exporter(pScene, pIOSystem, path, file); } @@ -114,7 +110,6 @@ static void create_embedded_textures_folder(const aiScene *scene, IOSystem *pIOS } } -// Constructor PbrtExporter::PbrtExporter( const aiScene *pScene, IOSystem *pIOSystem, const std::string &path, const std::string &file) : @@ -186,9 +181,6 @@ PbrtExporter::PbrtExporter( outfile->Write(mOutput.str().c_str(), mOutput.str().length(), 1); } -// Destructor -PbrtExporter::~PbrtExporter() = default; - void PbrtExporter::WriteMetaData() { mOutput << "#############################\n"; mOutput << "# Scene metadata:\n"; diff --git a/code/Pbrt/PbrtExporter.h b/code/Pbrt/PbrtExporter.h index c7e8180e2..a4b1a608a 100644 --- a/code/Pbrt/PbrtExporter.h +++ b/code/Pbrt/PbrtExporter.h @@ -70,15 +70,33 @@ class ExportProperties; // --------------------------------------------------------------------- /** Helper class to export a given scene to a Pbrt file. */ // --------------------------------------------------------------------- -class PbrtExporter -{ +class PbrtExporter { public: /// Constructor for a specific scene to export PbrtExporter(const aiScene *pScene, IOSystem *pIOSystem, const std::string &path, const std::string &file); /// Destructor - virtual ~PbrtExporter(); + virtual ~PbrtExporter() = default; + +private: + aiMatrix4x4 GetNodeTransform(const aiString &name) const; + static std::string TransformAsString(const aiMatrix4x4 &m); + static std::string RemoveSuffix(std::string filename); + std::string CleanTextureFilename(const aiString &f, bool rewriteExtension = true) const; + void WriteMetaData(); + void WriteWorldDefinition(); + void WriteCameras(); + void WriteCamera(int i); + void WriteLights(); + void WriteTextures(); + static bool TextureHasAlphaMask(const std::string &filename); + void WriteMaterials(); + void WriteMaterial(int i); + void WriteMesh(aiMesh *mesh); + void WriteInstanceDefinition(int i); + void WriteGeometricObjects(aiNode *node, aiMatrix4x4 parentTransform, + std::map &meshUses); private: // the scene to export @@ -96,39 +114,11 @@ private: /// Name of the file (without extension) where the scene will be exported const std::string mFile; -private: // A private set to keep track of which textures have been declared std::set mTextureSet; // Transform to apply to the root node and all root objects such as cameras, lights, etc. aiMatrix4x4 mRootTransform; - - aiMatrix4x4 GetNodeTransform(const aiString& name) const; - static std::string TransformAsString(const aiMatrix4x4& m); - - static std::string RemoveSuffix(std::string filename); - std::string CleanTextureFilename(const aiString &f, bool rewriteExtension = true) const; - - void WriteMetaData(); - - void WriteWorldDefinition(); - - void WriteCameras(); - void WriteCamera(int i); - - void WriteLights(); - - void WriteTextures(); - static bool TextureHasAlphaMask(const std::string &filename); - - void WriteMaterials(); - void WriteMaterial(int i); - - void WriteMesh(aiMesh* mesh); - - void WriteInstanceDefinition(int i); - void WriteGeometricObjects(aiNode* node, aiMatrix4x4 parentTransform, - std::map &meshUses); }; } // namespace Assimp diff --git a/include/assimp/IOSystem.hpp b/include/assimp/IOSystem.hpp index 30f48b81c..acb1f8eae 100644 --- a/include/assimp/IOSystem.hpp +++ b/include/assimp/IOSystem.hpp @@ -97,7 +97,7 @@ public: * Create an instance of your derived class and assign it to an * #Assimp::Importer instance by calling Importer::SetIOHandler(). */ - IOSystem() AI_NO_EXCEPT; + IOSystem() AI_NO_EXCEPT = default; // ------------------------------------------------------------------- /** @brief Virtual destructor. @@ -105,7 +105,7 @@ public: * It is safe to be called from within DLL Assimp, we're constructed * on Assimp's heap. */ - virtual ~IOSystem(); + virtual ~IOSystem() = default; // ------------------------------------------------------------------- /** @brief For backward compatibility @@ -236,12 +236,6 @@ private: std::vector m_pathStack; }; -// ---------------------------------------------------------------------------- -AI_FORCE_INLINE IOSystem::IOSystem() AI_NO_EXCEPT = default; - -// ---------------------------------------------------------------------------- -AI_FORCE_INLINE IOSystem::~IOSystem() = default; - // ---------------------------------------------------------------------------- // For compatibility, the interface of some functions taking a std::string was // changed to const char* to avoid crashes between binary incompatible STL From 5cbdb6c63b8229d1a41a99857112cc3811d82076 Mon Sep 17 00:00:00 2001 From: Kim Kulling Date: Fri, 29 Dec 2023 17:31:11 +0100 Subject: [PATCH 09/77] Build: Disable building zlib for non-windows - closes https://github.com/assimp/assimp/issues/5340 --- CMakeLists.txt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/CMakeLists.txt b/CMakeLists.txt index 88f69174a..4eca71955 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -137,7 +137,7 @@ IF (WIN32) ELSE() OPTION( ASSIMP_BUILD_ZLIB "Build your own zlib" - ON + OFF ) ENDIF() From 6bcdf989fb7331aab8fa3b1afe6a0740b1a4ec9b Mon Sep 17 00:00:00 2001 From: copycd Date: Sat, 30 Dec 2023 16:46:08 +0900 Subject: [PATCH 10/77] Triangle value is null-error, I don't know why it happened. --- contrib/poly2tri/poly2tri/sweep/sweep.cc | 3 +++ 1 file changed, 3 insertions(+) diff --git a/contrib/poly2tri/poly2tri/sweep/sweep.cc b/contrib/poly2tri/poly2tri/sweep/sweep.cc index 565a198d8..e1f23f11b 100644 --- a/contrib/poly2tri/poly2tri/sweep/sweep.cc +++ b/contrib/poly2tri/poly2tri/sweep/sweep.cc @@ -111,6 +111,9 @@ void Sweep::EdgeEvent(SweepContext& tcx, Edge* edge, Node* node) void Sweep::EdgeEvent(SweepContext& tcx, Point& ep, Point& eq, Triangle* triangle, Point& point) { + if (triangle == nullptr) + return; + if (IsEdgeSideOfTriangle(*triangle, ep, eq)) { return; } From ec122eb348ba5da816ba2466f6f4622c51ef4b06 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Wed, 20 Dec 2023 19:14:40 +0000 Subject: [PATCH 11/77] Bump actions/upload-artifact from 3 to 4 Bumps [actions/upload-artifact](https://github.com/actions/upload-artifact) from 3 to 4. - [Release notes](https://github.com/actions/upload-artifact/releases) - [Commits](https://github.com/actions/upload-artifact/compare/v3...v4) --- updated-dependencies: - dependency-name: actions/upload-artifact dependency-type: direct:production update-type: version-update:semver-major ... Signed-off-by: dependabot[bot] --- .github/workflows/ccpp.yml | 2 +- .github/workflows/cifuzz.yml | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/.github/workflows/ccpp.yml b/.github/workflows/ccpp.yml index 3859c04db..1c533aa80 100644 --- a/.github/workflows/ccpp.yml +++ b/.github/workflows/ccpp.yml @@ -98,7 +98,7 @@ jobs: run: cd build/bin && ./unit ${{ steps.hunter_extra_test_args.outputs.args }} shell: bash - - uses: actions/upload-artifact@v3 + - uses: actions/upload-artifact@v4 if: matrix.name == 'windows-msvc' with: name: 'assimp-bins-${{ matrix.name }}-${{ github.sha }}' diff --git a/.github/workflows/cifuzz.yml b/.github/workflows/cifuzz.yml index a84be8cbc..38f54ce06 100644 --- a/.github/workflows/cifuzz.yml +++ b/.github/workflows/cifuzz.yml @@ -19,7 +19,7 @@ jobs: dry-run: false language: c++ - name: Upload Crash - uses: actions/upload-artifact@v3 + uses: actions/upload-artifact@v4 if: failure() && steps.build.outcome == 'success' with: name: artifacts From 9776d47ccad48cbd4ea7869e93df9e8e8244615c Mon Sep 17 00:00:00 2001 From: tangxin Date: Fri, 5 Jan 2024 10:02:26 +0800 Subject: [PATCH 12/77] fix: KHR_materials_pbrSpecularGlossiness/diffuseFactor convert to pbrMetallicRoughness/baseColorFactor --- code/AssetLib/glTF2/glTF2Exporter.cpp | 1 + 1 file changed, 1 insertion(+) diff --git a/code/AssetLib/glTF2/glTF2Exporter.cpp b/code/AssetLib/glTF2/glTF2Exporter.cpp index 836e15f9f..17d162466 100644 --- a/code/AssetLib/glTF2/glTF2Exporter.cpp +++ b/code/AssetLib/glTF2/glTF2Exporter.cpp @@ -912,6 +912,7 @@ void glTF2Exporter::ExportMaterials() { if (GetMatSpecular(mat, specular)) { mAsset->extensionsUsed.KHR_materials_specular = true; m->materialSpecular = Nullable(specular); + GetMatColor(mat, m->pbrMetallicRoughness.baseColorFactor, AI_MATKEY_COLOR_DIFFUSE); } MaterialSheen sheen; From 6a0e1d5467af409cf40deb31046d27942d7ff7f0 Mon Sep 17 00:00:00 2001 From: Hamza <98172837+0xf0ad@users.noreply.github.com> Date: Sun, 10 Dec 2023 15:12:12 +0100 Subject: [PATCH 13/77] fix building errors for MinGW --- CMakeLists.txt | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/CMakeLists.txt b/CMakeLists.txt index 4eca71955..868282ef2 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -311,9 +311,9 @@ ELSEIF( MINGW ) SET(CMAKE_C_FLAGS "-fPIC ${CMAKE_C_FLAGS}") ENDIF() IF (CMAKE_BUILD_TYPE STREQUAL "Debug") - SET(CMAKE_CXX_FLAGS "-fvisibility=hidden -fno-strict-aliasing -Wall -Wno-long-long -Wa,-mbig-obj -g ${CMAKE_CXX_FLAGS}") + SET(CMAKE_CXX_FLAGS "-fvisibility=hidden -fno-strict-aliasing -Wno-dangling-reference -Wall -Wno-long-long -Wa,-mbig-obj -g ${CMAKE_CXX_FLAGS}") ELSE() - SET(CMAKE_CXX_FLAGS "-fvisibility=hidden -fno-strict-aliasing -Wall -Wno-long-long -Wa,-mbig-obj -O3 ${CMAKE_CXX_FLAGS}") + SET(CMAKE_CXX_FLAGS "-fvisibility=hidden -fno-strict-aliasing -Wno-dangling-reference -Wall -Wno-long-long -Wa,-mbig-obj -O3 ${CMAKE_CXX_FLAGS}") ENDIF() SET(CMAKE_C_FLAGS "-fno-strict-aliasing ${CMAKE_C_FLAGS}") ENDIF() From b571501559fc3b4d5af174349a9654a48fb41cd2 Mon Sep 17 00:00:00 2001 From: copycd Date: Wed, 3 Jan 2024 13:57:49 +0900 Subject: [PATCH 14/77] @ error Cause a TypeError when arg is UNSET --- code/AssetLib/IFC/IFCReaderGen1_2x3.cpp | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/code/AssetLib/IFC/IFCReaderGen1_2x3.cpp b/code/AssetLib/IFC/IFCReaderGen1_2x3.cpp index 73e3c91d8..c625f1daf 100644 --- a/code/AssetLib/IFC/IFCReaderGen1_2x3.cpp +++ b/code/AssetLib/IFC/IFCReaderGen1_2x3.cpp @@ -2725,6 +2725,10 @@ template <> size_t GenericFill(const DB& db, const L do { // convert the 'CompositionType' argument std::shared_ptr arg = params[base++]; if (dynamic_cast(&*arg)) { in->ObjectHelper::aux_is_derived[1]=true; break; } + if (dynamic_cast(&*arg)) { + // Consider assigning the default value as in->CompositionType = "ELEMENT". + break; + } try { GenericConvert( in->CompositionType, arg, db ); break; } catch (const TypeError& t) { throw TypeError(t.what() + std::string(" - expected argument 8 to IfcSpatialStructureElement to be a `IfcElementCompositionEnum`")); } } while (false); From cb8150b3e87165bad1ca0914bde306e366b11036 Mon Sep 17 00:00:00 2001 From: Steve M Date: Sat, 9 Dec 2023 13:04:10 -0800 Subject: [PATCH 15/77] Add missing textures and reduce texture sprawl --- .../IRR/EpisodeII_TheDwarfesStrikeBack.irr | 44 +++++++++--------- ...EpisodeII_TheDwarfesStrikeBack_UTF16LE.irr | Bin 95826 -> 95934 bytes test/models/IRR/EpisodeI_ANewDwarf.irr | 38 +++++++-------- .../models/IRR/EpisodeI_ANewDwarf_UTF16LE.irr | Bin 72352 -> 72618 bytes test/models/IRR/animMesh.irr | 6 +-- test/models/IRR/animMesh_UTF16LE.irr | Bin 12908 -> 12950 bytes test/models/IRR/{ => assets}/1.png | Bin test/models/IRR/{ => assets}/SpiderTex.jpg | Bin .../IRR/{ => assets}/UVTransformTestImg.png | Bin test/models/IRR/{ => assets}/axe.jpg | Bin .../IRR/{ => assets}/brownground_1-1.jpg | Bin .../IRR/{ => assets}/crackedground_1-6.jpg | Bin test/models/IRR/assets/default.png | Bin 0 -> 50279 bytes test/models/IRR/assets/default_texture.png | Bin 0 -> 264673 bytes test/models/IRR/{ => assets}/drkwood2.jpg | Bin test/models/IRR/{ => assets}/dwarf.jpg | Bin test/models/IRR/{ => assets}/dwarf.x | 0 .../IRR/{ => assets}/earthSpherical.jpg | Bin test/models/IRR/{ => assets}/engineflare1.jpg | Bin test/models/IRR/assets/skybox/credits.txt | 11 +++++ .../IRR/assets/skybox/default_skybox0.jpg | Bin 0 -> 51271 bytes .../IRR/assets/skybox/default_skybox1.jpg | Bin 0 -> 21534 bytes .../IRR/assets/skybox/default_skybox2.jpg | Bin 0 -> 30183 bytes .../IRR/assets/skybox/default_skybox3.jpg | Bin 0 -> 36117 bytes .../IRR/assets/skybox/default_skyboxdn.jpg | Bin 0 -> 11149 bytes .../IRR/assets/skybox/default_skyboxup.jpg | Bin 0 -> 9452 bytes test/models/IRR/{ => assets}/spider.mtl | 0 .../models/IRR/{ => assets}/wal67ar_small.jpg | Bin .../models/IRR/{ => assets}/wal69ar_small.jpg | Bin test/models/IRR/box.irr | 2 +- test/models/IRR/box_UTF16LE.irr | Bin 5368 -> 5382 bytes test/models/IRR/cellar.irrmesh | 8 ++-- .../models/IRR/dawfInCellar_ChildOfCellar.irr | 14 +++--- .../dawfInCellar_ChildOfCellar_UTF16LE.irr | Bin 21752 -> 21850 bytes .../models/IRR/dawfInCellar_SameHierarchy.irr | 14 +++--- .../dawfInCellar_SameHierarchy_UTF16LE.irr | Bin 21490 -> 21588 bytes test/models/IRR/instancing.irr | 34 +++++++------- test/models/IRR/scenegraphAnim.irr | 20 ++++---- test/models/IRR/scenegraphAnimMod.irr | 20 ++++---- test/models/IRR/scenegraphAnimMod_UTF16LE.irr | Bin 47672 -> 47812 bytes test/models/IRR/scenegraphAnim_UTF16LE.irr | Bin 47404 -> 47544 bytes test/models/IRR/sphere.irr | 2 +- test/models/IRR/sphere_UTF16LE.irr | Bin 5538 -> 5552 bytes test/models/IRRMesh/{ => assets}/1.png | Bin .../models/IRRMesh/{ => assets}/SpiderTex.jpg | Bin .../IRRMesh/assets/UVTransformTestImg.png | Bin 0 -> 34368 bytes .../IRRMesh/{ => assets}/brownground_1-1.jpg | Bin .../{ => assets}/crackedground_1-6.jpg | Bin test/models/IRRMesh/{ => assets}/drkwood2.jpg | Bin .../IRRMesh/{ => assets}/engineflare1.jpg | Bin .../IRRMesh/{ => assets}/wal67ar_small.jpg | Bin .../IRRMesh/{ => assets}/wal69ar_small.jpg | Bin test/models/IRRMesh/cellar.irrmesh | 8 ++-- test/models/IRRMesh/cellar_UTF16LE.irrmesh | Bin 188818 -> 188874 bytes test/models/IRRMesh/spider.irrmesh | 8 ++-- test/models/IRRMesh/spider_UTF16LE.irrmesh | Bin 293134 -> 293176 bytes test/models/IRRMesh/testFormatDetection.xml | 10 ++-- .../IRRMesh/testFormatDetection_UTF16LE.xml | Bin 53842 -> 54132 bytes 58 files changed, 125 insertions(+), 114 deletions(-) rename test/models/IRR/{ => assets}/1.png (100%) rename test/models/IRR/{ => assets}/SpiderTex.jpg (100%) rename test/models/IRR/{ => assets}/UVTransformTestImg.png (100%) rename test/models/IRR/{ => assets}/axe.jpg (100%) rename test/models/IRR/{ => assets}/brownground_1-1.jpg (100%) rename test/models/IRR/{ => assets}/crackedground_1-6.jpg (100%) create mode 100644 test/models/IRR/assets/default.png create mode 100644 test/models/IRR/assets/default_texture.png rename test/models/IRR/{ => assets}/drkwood2.jpg (100%) rename test/models/IRR/{ => assets}/dwarf.jpg (100%) rename test/models/IRR/{ => assets}/dwarf.x (100%) rename test/models/IRR/{ => assets}/earthSpherical.jpg (100%) rename test/models/IRR/{ => assets}/engineflare1.jpg (100%) create mode 100644 test/models/IRR/assets/skybox/credits.txt create mode 100644 test/models/IRR/assets/skybox/default_skybox0.jpg create mode 100644 test/models/IRR/assets/skybox/default_skybox1.jpg create mode 100644 test/models/IRR/assets/skybox/default_skybox2.jpg create mode 100644 test/models/IRR/assets/skybox/default_skybox3.jpg create mode 100644 test/models/IRR/assets/skybox/default_skyboxdn.jpg create mode 100644 test/models/IRR/assets/skybox/default_skyboxup.jpg rename test/models/IRR/{ => assets}/spider.mtl (100%) rename test/models/IRR/{ => assets}/wal67ar_small.jpg (100%) rename test/models/IRR/{ => assets}/wal69ar_small.jpg (100%) rename test/models/IRRMesh/{ => assets}/1.png (100%) rename test/models/IRRMesh/{ => assets}/SpiderTex.jpg (100%) create mode 100644 test/models/IRRMesh/assets/UVTransformTestImg.png rename test/models/IRRMesh/{ => assets}/brownground_1-1.jpg (100%) rename test/models/IRRMesh/{ => assets}/crackedground_1-6.jpg (100%) rename test/models/IRRMesh/{ => assets}/drkwood2.jpg (100%) rename test/models/IRRMesh/{ => assets}/engineflare1.jpg (100%) rename test/models/IRRMesh/{ => assets}/wal67ar_small.jpg (100%) rename test/models/IRRMesh/{ => assets}/wal69ar_small.jpg (100%) diff --git a/test/models/IRR/EpisodeII_TheDwarfesStrikeBack.irr b/test/models/IRR/EpisodeII_TheDwarfesStrikeBack.irr index a317ac61e..761ea0ad4 100644 --- a/test/models/IRR/EpisodeII_TheDwarfesStrikeBack.irr +++ b/test/models/IRR/EpisodeII_TheDwarfesStrikeBack.irr @@ -32,7 +32,7 @@ - + @@ -89,7 +89,7 @@ - + @@ -128,7 +128,7 @@ - + @@ -167,7 +167,7 @@ - + @@ -206,7 +206,7 @@ - + @@ -245,7 +245,7 @@ - + @@ -284,7 +284,7 @@ - + @@ -329,7 +329,7 @@ - + @@ -345,7 +345,7 @@ - + @@ -384,7 +384,7 @@ - + @@ -468,7 +468,7 @@ - + @@ -484,7 +484,7 @@ - + @@ -523,7 +523,7 @@ - + @@ -620,7 +620,7 @@ - + @@ -678,7 +678,7 @@ - + @@ -723,7 +723,7 @@ - + @@ -739,7 +739,7 @@ - + @@ -778,7 +778,7 @@ - + @@ -875,7 +875,7 @@ - + @@ -920,7 +920,7 @@ - + @@ -936,7 +936,7 @@ - + @@ -975,7 +975,7 @@ - + diff --git a/test/models/IRR/EpisodeII_TheDwarfesStrikeBack_UTF16LE.irr b/test/models/IRR/EpisodeII_TheDwarfesStrikeBack_UTF16LE.irr index 9321cf93f828f5b6f28b5d216b4851838324d0c6..d109c67cc302fb09ebbe5d81aa383d2eca9ba6d0 100644 GIT binary patch delta 466 zcmccghIQXt)(tB-*%KLxfiQJ5p0}P&7|KwOGu)u|J`z1rh9%LK9hB`5BpXJJUhlxC+t)-?L Il`$#+00e-H8UO$Q delta 329 zcmdn@mi5vb)(tB-Cp)O~$rdx{Go&)4Fk~{6Fyu27F~kGesSIfhi43I-IhzyjpXc6O zC)&b3`IENRW-HlMe49UMU*QAu{#mVpFdle98HXa)Ktz_MpW@%n#LRe&Wph%^8ouod z#27=QHWw_FVL=nklHR=N#tt^3TryvnC}ltg7c3QHoW8-8QD^gpWp|j+tW;4V#hC3t RV>p=6jIffLKCg^X0RS2qZMgsd diff --git a/test/models/IRR/EpisodeI_ANewDwarf.irr b/test/models/IRR/EpisodeI_ANewDwarf.irr index 65f65ad4b..c84073553 100644 --- a/test/models/IRR/EpisodeI_ANewDwarf.irr +++ b/test/models/IRR/EpisodeI_ANewDwarf.irr @@ -33,8 +33,8 @@ - - + + @@ -72,8 +72,8 @@ - - + + @@ -117,7 +117,7 @@ - + @@ -131,7 +131,7 @@ - + @@ -170,7 +170,7 @@ - + @@ -254,7 +254,7 @@ - + @@ -268,7 +268,7 @@ - + @@ -307,7 +307,7 @@ - + @@ -391,7 +391,7 @@ - + @@ -405,7 +405,7 @@ - + @@ -444,7 +444,7 @@ - + @@ -528,7 +528,7 @@ - + @@ -542,7 +542,7 @@ - + @@ -581,7 +581,7 @@ - + @@ -665,7 +665,7 @@ - + @@ -679,7 +679,7 @@ - + @@ -718,7 +718,7 @@ - + diff --git a/test/models/IRR/EpisodeI_ANewDwarf_UTF16LE.irr b/test/models/IRR/EpisodeI_ANewDwarf_UTF16LE.irr index 5e5a68f2d4a3423f2815f96ef391101763080857..551a5ac9a47a4b8e3f85e7979dacb6135cab2602 100644 GIT binary patch delta 382 zcmZ3mm1Wg-mJK3Yyon6OK$yx<0wnb(3v*SYifr!XO6Efqn*3g(9#v#>u4F1dn$SfJ zNfvG-qc`)%tw%Fx^WL0j>CGR)xR}Y(n=D6`wrJ_e1+R=Y7wmk*M5g}D1+Rq2bF#J6 J^ad$L1ppAAWx@ae delta 147 zcmZ3ron^sRmJK3Yla;utHm~AJ;+rfbSqEfrac|zB62-E);GG1^<_U3Y__hZyGFnM( mHh87PxH%-8gBgpA0^{Z-9av?87&oi!dc=f9j}e*`QBnZLJ~pNR diff --git a/test/models/IRR/animMesh.irr b/test/models/IRR/animMesh.irr index 0e246bacf..5cd109d77 100644 --- a/test/models/IRR/animMesh.irr +++ b/test/models/IRR/animMesh.irr @@ -19,7 +19,7 @@ - + @@ -35,7 +35,7 @@ - + @@ -73,7 +73,7 @@ - + diff --git a/test/models/IRR/animMesh_UTF16LE.irr b/test/models/IRR/animMesh_UTF16LE.irr index c041565ea04e980dd967ddf0e5d1293d6bc215cb..70f6374fa45aa27eac5a52562da9115e526a52c3 100644 GIT binary patch delta 62 scmaEpGA(t(30B@jhGHO0WheoX`kRllUT5J(7MRWD&WEPvp+vVN0Al_UDgXcg delta 22 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 literal 0 HcmV?d00001 diff --git a/test/models/IRR/assets/default_texture.png b/test/models/IRR/assets/default_texture.png new file mode 100644 index 0000000000000000000000000000000000000000..a1ad5979bb322fe6bf75f9fc441294d1379d45a9 GIT binary patch literal 264673 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�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 VKtDs@>I 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�#piCxMVSg9X4~-ja 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 Myqa9Kj9JM40oEHm5C8xG literal 0 HcmV?d00001 diff --git a/test/models/IRR/drkwood2.jpg b/test/models/IRR/assets/drkwood2.jpg similarity index 100% rename from test/models/IRR/drkwood2.jpg rename to test/models/IRR/assets/drkwood2.jpg diff --git a/test/models/IRR/dwarf.jpg b/test/models/IRR/assets/dwarf.jpg similarity index 100% rename from test/models/IRR/dwarf.jpg rename to test/models/IRR/assets/dwarf.jpg diff --git a/test/models/IRR/dwarf.x b/test/models/IRR/assets/dwarf.x similarity index 100% rename from test/models/IRR/dwarf.x rename to test/models/IRR/assets/dwarf.x diff --git a/test/models/IRR/earthSpherical.jpg b/test/models/IRR/assets/earthSpherical.jpg similarity index 100% rename from test/models/IRR/earthSpherical.jpg rename to test/models/IRR/assets/earthSpherical.jpg diff --git a/test/models/IRR/engineflare1.jpg b/test/models/IRR/assets/engineflare1.jpg similarity index 100% rename from test/models/IRR/engineflare1.jpg rename to test/models/IRR/assets/engineflare1.jpg diff --git a/test/models/IRR/assets/skybox/credits.txt b/test/models/IRR/assets/skybox/credits.txt new file mode 100644 index 000000000..b2b601392 --- /dev/null +++ b/test/models/IRR/assets/skybox/credits.txt @@ -0,0 +1,11 @@ +This skybox is basing on a skydome texture from + +http://mikepan.homeip.net/earth + +Downloaded November 22th, 08 +Distribution note: +"These royalty-free skydome textures work best when applied to a sphere or hemisphere" + + + +Thanks for your great work! diff --git a/test/models/IRR/assets/skybox/default_skybox0.jpg b/test/models/IRR/assets/skybox/default_skybox0.jpg new file mode 100644 index 0000000000000000000000000000000000000000..0fe4d0890567859c852734a155b9f3f6b0d8ca1c GIT binary patch literal 51271 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 literal 0 HcmV?d00001 diff --git a/test/models/IRR/assets/skybox/default_skybox1.jpg b/test/models/IRR/assets/skybox/default_skybox1.jpg new file mode 100644 index 0000000000000000000000000000000000000000..c4c286bff28c2563a5724c7d1b72fd5d60588838 GIT binary patch literal 21534 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 Gf&bY+H|r+= literal 0 HcmV?d00001 diff --git a/test/models/IRR/assets/skybox/default_skybox2.jpg b/test/models/IRR/assets/skybox/default_skybox2.jpg new file mode 100644 index 0000000000000000000000000000000000000000..935f72579ba1542fd6903b58603c3e0680ba8378 GIT binary patch literal 30183 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

H7~b7L1Hh=$(Zb0?oGw0T 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 literal 0 HcmV?d00001 diff --git a/test/models/IRR/assets/skybox/default_skyboxdn.jpg b/test/models/IRR/assets/skybox/default_skyboxdn.jpg new file mode 100644 index 0000000000000000000000000000000000000000..af66a6176b2ff92a472b656017bce0c9cf6c24ee GIT binary patch literal 11149 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

4i$O*jzgJ{-@${_=n<(Ntrww zw5Ndj##Hau2$O4GcZ5bwxz3#R@9ty5gD{ zd^|h6Fr5n!-u@A8pE#W9HUf#eV%$3jj&;ashDoWvll#fb3%Uc7Rn68)!SOfL7)B)N zr)cMW@PsJv?(Q@~y*Yj;*NS`bg)8O|4l%UX~p$`o{e#0L=LnKFQZZHPiJ_XeHG-rH;$`~0wM802>g!f8Ci=`mK zsgVSw`(g=2!I2=blivj6evqcHXNyN-w&|_x)=(eO6enLB(x%#zKC=6xwJbDMJ1Y;@ zN$3wy{y1zv5Ua}{1nOeft{_x9B-gO+!)+qS(ol>`1<$ZBNaMnw)~BE+ek{ldN29vb zD!D?}0rTxn^tD2#kewS}t)d)a%*?i=-~&VTT;K5?_LNb+CqB! z(~WxFVQCckBpEGqka?4{6jYNO5CzHqM@Xpnrt#&2amrO0x3XX)tt$v4daR++$0z(aDUt)Z3^GfiBM~ zln)N(dz*wuls~;$TLIp-bQy=$3VxNEYvQK+3->+$*JQ{2&wGil?BnyNt)FAW=57?H z|B|%WFbTibie2JgO^+Q@B}VvL^4dr5h#1o2U@bu^W4epaW-y*zd!_h}3pWrr+EoO!-M~6kptwc1Yk?qWM5c;CcHzn_MB04%Zr@**A{yT=~*mHl_B~eih^r*i*&$nFeg7o~258 zs<0vYyQv25@*~9sII_>Rpa?gLfp7GK`uczW@#sUOVv!}E2Ta(i z4ade-8g*uGMgepO>7u>t?{;y^!ICz^q6;(jsuF_VX+!F%yJoBF&Po{TN#8Ew>xRZP z%%{Z_IbpHFq;T+Tjo8b(3bw-?pZG}Yu}F@JDz^1cYY&xyq&dp6l2N&FRhd_Sc9m(j z26omvOb(c56b+^eRTRtvqu=@zSug~+==|EIH_YkMfj@m*Hu*R+1H7n;NR{4-HYTqi``8m~uE0=1{(8yfY3R^AtmFo78sxX? znWPS0rEMY7K+hVhd+Pqv)wZUK*INBcSpkI4!)r=OV95s~z z4(u5$56w!;bQ)QG@UXG#jtw>c;X+c+dd!6r52LYA;W&)f(nMsz=ELPm7aOqCP?+}A zl>zu?cth?o8qto*qPh<~jKUWQ3cgwt&pqgkFv5Dj;)$9`!?%7F6FcFl{ME&yiJHhP8$(mfX7SD7hmYT?Jr^^0zt^4=& zm>wgFUMdy|$0#bW@%-7zY>L`i+h_Ba_SunFj#5Yp`cM*`T76V`;8xZua|MSN7BrMF z8}JV%b^k-GRxpdnc*oh%z*FAEXIihXIJO9P`H&&q88HTsI?{Jl#u6PVVA9zP7r*P& zFI0;z4z4wWXq#=ZuGs{#p9pKV1+lJt4%(`SZBF=7F7vkOA=T}uVa$jq;&H|EI$%~#(0Ad}~vLssDT5~+>e@7jaq)ELVwf)dc2bj@% z^#Ywn)4!#t*oJoPl{w4H(u3r0M~n1Y^7p;7pZ22SvE81&!r&iKQF*Uw_N8Ws%}`mE zhuCiU5TJ02Z%A6jZg9*jfwC&&FF6|nZHq%A)8fX~+Zur|wV4${XKBIWI^ZwV^PSIc zv+jGIv%n64XWctIZ}V3<N-k>l9De#vfS52) zUXVY03YcBWv_~W=+ssIQ4WJ)gaTx5D@6QjhtWlU1n4>gq*-5HrHzCrq>^saL9qbJS zS-QVUWX7yZI-`(F>i~cV0!L2-PjPiAPA315J~2dOwN*Jii$9~XK6CT{agqIdu3Td! zt~4qxzC;nx4OTRKHx13$P4v4mfPN-k_RjgPi$k@|l|>yUG^*6Oq*Q-g(E3S9x;TiV z+*dNV!FIAi0;jko_Rm8A&ftJpsO%+>yfpu?><(9rc$r6AouA>AZgUI6*Qzl;&1G1Y z(SVYLFUjz)I3+eS&8|rlr)&RI4Ycl$*G1?qWTQ}f|C)9Fj{O^fzY+M45fD5b`7ew% Bx8wi- literal 0 HcmV?d00001 diff --git a/test/models/IRR/assets/skybox/default_skyboxup.jpg b/test/models/IRR/assets/skybox/default_skyboxup.jpg new file mode 100644 index 0000000000000000000000000000000000000000..7959709fa3707a33010a76b4ec8acf815375e390 GIT binary patch literal 9452 zcmeHsc|2R&+wWFwrD~|7)u5^I+U#XLAbY@q!o z{_hH-9^e5T0uBMJEI$K>cvx6@SQsAwp?&?C7O*nUzsoUpHW2HPqlXVM|F%8BtUkhW znC;ME9?($`8}kvCL#&679AyKs^Bnt$S5z&e?BcH{PhEHB7x-Dhz{cJ0e)Pj<$=LFy zUcS>{UGrO6WHIqe{=X+kD(OLA7MC^zJcxRpm|eu|`sBYy{66x2Ezb`Bo-TkLUd2S!#{JK7C9965TQfMYQ@vPdqyJW zwBvHsZg6cJo;Q7{v$9`+RVAbpcbt8jQ{~ThO%7HSsi%`NJT6&gX+G~Tz0`wMyp0Tn zD3aqZ_`kOxvc=gq5H4@yo~$A3&;CQ%v;Q_wU6+bTnkbn8JaVs&vbgII zUW0{*NG%<1t*PJl9WF zd)fBfY~++SpWSZ9&G;PW_fC;abB+eyt=b$VK^DWs(dUkoq!)VYU3R{(;prUVB$B&s zxgp(O_F?F1{&OpI5__?sl0mC!T2Y4lG}r=lX50Ai+kfh-#Q>TMzNEgm_qrvl*7@xJ z$uA)c;AInDha_9WHp?xy_v=3`y#oj_fSDp+vkihT%Z?s_0h|culbxjxd4JY12#xr1 z24H(3F?)L~!!Qf%D_cRovmG3rjMQ1@u4oQy_jUUNZ9^Q>^X6@K+zK8p->9R9J)2s+ z%`0kW5-F_FQbs?XXYVVuG=ulXT6oCxhesu4}{W9*Sj<<1ST8 z!#0g&c|nf~okKLWVT<#IMm8lhQ@0{ApCOw^cKdQu2{xIJ$1> zE!|-M_!?!S%alW@mZ0yc+1$B)<%zEux%jS3ze4``p|2M=Erv(!Zp0La1&Jdi6Ws5; zMgGjW&e0xdvl6m+DWpC6Nz#~P^i-dslbSo>mF!ond6do>)05|8d&!*mqTRmAKgQi~^4`w=Dj-8yTUwXxJ1Ist5%)Uqm`I&X_J0 zZImuCfE~>b5nLRTVD$l)cl_HOM!Ba|%r}O482}=Q;teLyhR!{oLY_@@5KWV?f4>xmtnIZ| zD|9QTNx=H^6jMB51ttA!6XX5p2KSEP-K@4TjP2yOaL(CdH?-~N1qKPj{R4^~q!Ifr zCF#=Ft^DUOnnh%O*C_Y|7{U|fECT()GE0vYPFlGtlV*P6+6K@`3W9ca(<35 zzwO<-ArM}@+LQCfpk~E+T^_Un1Mo2D5+C~)%RBsskguP#eukHR4$dw~Lk^^9wijU? zhf76e$0X-W9SSfXo+87NZX=z$YUR;31jQn>Ee5R>{nSxdIQcvsDMVe6DcLqE-Owr3 zcx*Fj?QQPf{6yQm1*az=qk~gAmb+8gIG+c}QG>V}_6^|6Iy6WgL9cof3IvK9LeC|* zo5)a`&oJ!}>W*@zuerPQB3}USi)n7_2NQCji*)@7M-{Qz-7)8d5`ER_D%*En82D zlE3z|m?Mb&=KS|3tyWAvX9o8@~$|188?%V%G@ zZHb}%+&5mo-=3Ej3y<-HtUY(HdGkp*AijB4t9tMn8n1y?Ao#*?Rd1)4;bYgLG~64` zV_@&J=Y&IKU zt|)n=wv9?>R|x-U2qy~tah5it_(VOu=F;htrAy@)-OOKZ6!yl~Q>Mriw5^zKXf_2k zKCTEo@p~lDUwHfi11MAJnQ8q18|fGsP;Z1<<`9!tZ=|Lh$4cFvx3P}z7>vl87T)Uc z)C^xpIv;VAzGf{bJ}ckuHC2XqbKcX==Sx&+*hrSvdX!{!woX@H*6~4q22itI-FW@Q zzV+YBAz-C5Jhm<=;@!0)5tY;0P2+8KBd-ntzyRfV{C!BHjtKqJ*D(fgmo>VjKHE7n zo&mV~`$k0m-ToLeM@+c9xYySb261*uIQY`NbO_))=rz|P*d_MN4TRuK>C(C!yXwEP z+(ft}ypTl6tUNlP>}D5r;ewJWx(XAIQdqA_Ui-S3KTW30jr3%z>|K~)1^i-ud6HV2 z`#Yu>PgO3%%oxig29A}q-?{OmxB%KU$%N8wGvM=cY=>?TykBnqgD%9mkx(bl?^@hHE3k zIH&P$D*9TK)J<;<^WKCL8@e`RA1L>7Y;>J|xzG#C;m-bb)7OPE#DU%+cuj$UiEx0f z$2t}V)}Nl%SdG*vWOcESNH4CyfC*OkP^nfh+!@>f(qjPg+d|xd4o56JQU?|qjfqjN zxI87F^QXl{7m=Q0<{0k1`q7X7nDI!>fXrJIveVKH7N;e(uA&fX;ifbY2`KG0On$!p zwyT8!l&Y!JjR6yW%fAe|O)`MtGpXaB|L)_^M`c>B2j*$ zM57k9EnyJ`Wg(luKeE*~4KzhQ#MWYJ$u!>TD+NZB&pXfE%U8N>3?)*N4CfqMH7j@< z$GJL*r+FLP;gTqW5QscHRU^HaxMkd)VM-kkifg%+F*i3im0$XbWS(Htp=CIYmPgsT zpm>n3NN12P57PG3mkYCj$(Zx^?%L1VzwYr$b^TNj+ar&J%DgjrZo(aPJ6i@mL4p`c zB=At8rEg4vjTL+9c}D=@frJncCljy?R_Dx?3i@rYJ_Y)>@jKn3(#(J?G`~>QPMX+hR$q}|9WVfEqa6(;vJoT;91aNLL z4e1hZ9WJCm2tS>!Z-4Ea>vCbqopV~CSby&PfQC0uSrZ>;Z2=-F)}^=6mn}y_?ODEkoP1^ z99&a5!oaJovrf(RVRC~p`^xjLi*KeYGi(?@SlaFQR>EM0y#vXyh(s@c*IPAzV@?SA zN=}D#J3x)SV!%?gtBNPj9F|Mw3jZ|SCj8mFHjOS3Zb{U4izv}bCVgE~Zkp6F-z?Ag z$tB3m%E!NX8V7EOt5emL&ywk$hn$&4`^<_by#Rn+2hNuYyI1=ws{h>a&2 zLQwB>j%DN~*o0}ilqiLXC!<8UQL=9W&6du&bT?LNca>W}>|xYFIM~5$>D49yo>(Z{ zKbIr9(IF#k!Y_`5@2Uq*EEx*(`b5R1IgDw96}-Cjn$#r_(CC(uTIFDyiwcE`Z+j#( z3x6c=W3swPpbo1O0d`K&C)0LMM@TaO{};?RmQ&3Eq(l2(?`y@G zi6I(wf7M!OmOmPC5CsA4AV87!-eSU~u%_?h4n!!0FSAnmo=n*$`kjbDi#6c8v_M3Xl3!QcmQyfOp@qF9}Eu?N6&rTQ(ceaheV`KlATtFF$ zN4cVP6wkh_j=RI$`{Ac_n>Wp2ui=73>oZtfLf_lC^Gn#ek`{tU6a?Y;(K4DJN~=8N zYj1y}rV-@R+Yn{Jz0K-fRy^h=b`zETX;2J#pFQ~ zR=AOTRa?t^UjN5dk&PRoqhR}%xjDGBuAwu(w1sJGtOiNC89(}LAt^-+Lymi!(Z~U@Q>tQ%F`kjA9wS@LUQ=ttAXCNY$n4|nZf`T+(rPF z!p_sjvQ&OGZFB~$lF#gktws#TQRZ{zfqp?>BO3r7O?NBXZ}FW+w95~uI% zuT{+*%74Fc@6NZ#W#J;aKRDCufiA!pUi0n-MW+ z*}RS@U;rJbn1sPWoOPC)c#+oYgo{|!n+4P7<~!GLkM3j2LL7e_p|vDy`$W{3t8s8EoPoK%eCDDc0P8<;=ANJ{6O?m zW_pewt$d3%pOp%S;{u-+?}WvRq@xm{<89R8FkTZ-#F|2b&I9uAxl10{wH~N6HB>e;mrWDdVEvV1I7IOpt;zt zZj^0kSAUBoHey|y?iXF^Ji0gyh7UIR)>*&^vQVr77@3aOX!o%i#-xw3Kb@8cvy?zS zZxul+G|TVFNKyRW9$)NJ$sQK&@V|yz#vgxG`1ZM(`I&4-yHnFx37dO8tuiGI+FK@| z2N?i6;eA(4w9vD)?5}|)i!Cm&GOhC=Ps*`iYSd`=Z?ZR#nj z5-O=@Hdo_P4iyZLE5?^KNqG=6ms=IZK8n2fdqR$?ZN*nS%dQ!?8a!C6tRezxg28v} zOgrV{RSj3d`DN!Dcs3hU%tuVPoQ6GGa`fOMJ`<_W7sWhnRlCswDx6kRZP7MV6m{P2JnZUmXrqmDf;53JS9)*)W+Lh>+O5#9ro=g^C`^eXp_Ne2Hx&DBy<|BBjbvM ziqvv{0YsLDhcVNVuQA`UUQoWp5WT_P>Z+ye5-k?-gr0|g z5G&hHI&&}D+nHx8BJMUTKrY7DUW9JG$PSvJgc6&I9M0L1CTyy2(lqJjwwP&C<&-T5 zHRt(WLhpjJF{Lj`Ycczq_5U@|q`cd$G2v2emSpEdly#uhtDn0kQvsvmjCZc!{&ycV zINDZ{d^D6>Li&iio*#xF8N8mVA8pCft>=0TQAH>tKV)}IU{Ri@AR=FET+!V!J|aR^ zNwcYkt$Wp(=u&y1d??N+m^vp=s;$&>+A>s^&(`y-;RLQ19OKn^ zL3os@7nlN*v5Fo@zPl(`VXqMivwn+HEcGh8N^DH@k%5A#i(-TVr5eN=M?YkGs3@3l z_3}5DKpf9kwI&vl9r>+o9(SDqtrs(LfB~Hnxgi0?nOc&puE|wG~mG$r4UE#<9 zQsXedQZe?&_;K0cd#{P~XC9O#mV@#9gAMyO?FTL=#9~#l)Hl__;dlt)Edu~8ERr8~ zUql5m0HUtlov31$oCM)PT?1XCJ^a%Iqh~P}`tQ2U*1>n#`HcnoD{jDUl5X~(lk6;S zM^P;k-2IuXATv6^5P787qHFvk{fC(nRq1qJZ}_1Pqb}u6b~&5x7B6|5D*2Sgt2V=M z*HA+1GS1_jLaWzeD$-RUutN#}cS0w%Tze_032&Ep{!_*&sa~w2OGetKcvTZnV=d1< z-6m5wW_HscXpAkknyfezNTr;}HTe|Lj`C`MTy-HsN zLDIqtpsl@0=ei&@qWm!1xoUx=iLOy4?Vdsz1S|{mwx2aTrNH)aX9G`B>m)@~rC9NT zcwW~kL@xHyo408HwAHVdRB^|o8q<1iI`m+UIj^o~b6w>CMuhuz%tO2f!_z&6u|B)! zK6L2K7fki>1^Hyt7mrDsSh+KRY8gk-FyLsNPMrf;}SEHmtJ!xtGqNfka` zx@_MwXuCTY)4TeKy`lxha@MYpH%7gCA@80M# zvdu{yH!I-Bx;?np8Bco~7~%a>_@%M}&OeFPB_@ipKAskfUJB-oI~$t{0T?@{O-ZEl z0{TR}s*1vnR`x=R$zqJYBW%sj{hp6R%`iaxnqHUWP$-$GLKzM$42qf>2EAmzLi#p`(&!Qn7j9t8KZ zcH60Qvo~lq>?%UR(Umvjoa!L?CD)S~z{f{o%j;wPRfj{G2g}Gt{NZC8G2sF?x4Z6_ zBx{L(+ICh-?8`b0>L+D+ySXM!8edV zmBK?v*By*aUM(Wx zr4vh3g41szjz;*N7i2;giw3Q6P-eOTbtlC<$`z#;U^?55c=~?$%Zf6eO^tV)>hZ};RRAl7O3?N)gWc12T1p`pj zeipy - + diff --git a/test/models/IRR/box_UTF16LE.irr b/test/models/IRR/box_UTF16LE.irr index efc165d934a0dfede0a168772740e9c8cc57f088..6555171958dfcc38f41eb4571ea10d6683a8dbbc 100644 GIT binary patch delta 26 ecmeyN*`~E&5hrgVLopDhGL!&G{mlzG!?^);&j-5z delta 12 TcmZqE`k}dD5$EO&oMGGmBzOe+ diff --git a/test/models/IRR/cellar.irrmesh b/test/models/IRR/cellar.irrmesh index 0278c9239..ee787463a 100644 --- a/test/models/IRR/cellar.irrmesh +++ b/test/models/IRR/cellar.irrmesh @@ -13,8 +13,8 @@ - - + + @@ -870,8 +870,8 @@ - - + + diff --git a/test/models/IRR/dawfInCellar_ChildOfCellar.irr b/test/models/IRR/dawfInCellar_ChildOfCellar.irr index b9fa20c6a..0b57fc158 100644 --- a/test/models/IRR/dawfInCellar_ChildOfCellar.irr +++ b/test/models/IRR/dawfInCellar_ChildOfCellar.irr @@ -33,8 +33,8 @@ - - + + @@ -71,8 +71,8 @@ - - + + @@ -113,7 +113,7 @@ - + @@ -127,7 +127,7 @@ - + @@ -165,7 +165,7 @@ - + diff --git a/test/models/IRR/dawfInCellar_ChildOfCellar_UTF16LE.irr b/test/models/IRR/dawfInCellar_ChildOfCellar_UTF16LE.irr index aba42e94ded98bf46ee6e502a12083bd34211ee0..cd7ba9752105c886a6ec11270470689b5c8cff6c 100644 GIT binary patch delta 143 zcmeydlJV9m#tkA|yon6OK$yx<0wnb(3v*SYifr!X`pt_fG`U@(9#sUWXffC370M|r ZXyV)&#w^@O=5Myvnaqc#=B$;r6adSgB_03( delta 47 zcmcb$it)!v#tkA|la;utHrq)q;@a#Z8o@kylSCbm$Hu=oNW+L_^CX=Ke47odwWI*1 C3J@Xy diff --git a/test/models/IRR/dawfInCellar_SameHierarchy.irr b/test/models/IRR/dawfInCellar_SameHierarchy.irr index 424b42df8..5f6d01fe5 100644 --- a/test/models/IRR/dawfInCellar_SameHierarchy.irr +++ b/test/models/IRR/dawfInCellar_SameHierarchy.irr @@ -33,8 +33,8 @@ - - + + @@ -71,8 +71,8 @@ - - + + @@ -115,7 +115,7 @@ - + @@ -129,7 +129,7 @@ - + @@ -167,7 +167,7 @@ - + diff --git a/test/models/IRR/dawfInCellar_SameHierarchy_UTF16LE.irr b/test/models/IRR/dawfInCellar_SameHierarchy_UTF16LE.irr index a4e7cc951533a80a69b7ba566102245d0527ebb4..5cc3dda877e3a0aefb3732b62e76122bfe33ecc1 100644 GIT binary patch delta 147 zcmeygobk#E#tkA|yon6OK$yx<0wnb(3v*SYifr!X`pt_fG`U@(9#sUWXffC1dBG-| d? - + @@ -71,7 +71,7 @@ - + @@ -153,7 +153,7 @@ - + @@ -167,7 +167,7 @@ - + @@ -205,7 +205,7 @@ - + @@ -287,7 +287,7 @@ - + @@ -301,7 +301,7 @@ - + @@ -339,7 +339,7 @@ - + @@ -421,7 +421,7 @@ - + @@ -435,7 +435,7 @@ - + @@ -473,7 +473,7 @@ - + @@ -555,7 +555,7 @@ - + @@ -569,7 +569,7 @@ - + @@ -607,7 +607,7 @@ - + @@ -689,7 +689,7 @@ - + @@ -703,7 +703,7 @@ - + @@ -741,7 +741,7 @@ - + diff --git a/test/models/IRR/scenegraphAnim.irr b/test/models/IRR/scenegraphAnim.irr index 2300ea18f..dedc1c2cf 100644 --- a/test/models/IRR/scenegraphAnim.irr +++ b/test/models/IRR/scenegraphAnim.irr @@ -126,7 +126,7 @@ - + @@ -197,7 +197,7 @@ - + @@ -213,7 +213,7 @@ - + @@ -251,7 +251,7 @@ - + @@ -347,8 +347,8 @@ - - + + @@ -385,8 +385,8 @@ - - + + @@ -442,7 +442,7 @@ - + @@ -512,7 +512,7 @@ - + diff --git a/test/models/IRR/scenegraphAnimMod.irr b/test/models/IRR/scenegraphAnimMod.irr index 21408b245..9f82efcb0 100644 --- a/test/models/IRR/scenegraphAnimMod.irr +++ b/test/models/IRR/scenegraphAnimMod.irr @@ -126,7 +126,7 @@ - + @@ -197,7 +197,7 @@ - + @@ -213,7 +213,7 @@ - + @@ -251,7 +251,7 @@ - + @@ -347,8 +347,8 @@ - - + + @@ -385,8 +385,8 @@ - - + + @@ -442,7 +442,7 @@ - + @@ -512,7 +512,7 @@ - + diff --git a/test/models/IRR/scenegraphAnimMod_UTF16LE.irr b/test/models/IRR/scenegraphAnimMod_UTF16LE.irr index 7384ae29ada86ec6b7aaa1952ca7138f0280983f..a8cab1a12f05a4e86d952c29f50faf5fbbfe9515 100644 GIT binary patch delta 215 zcmdn-h3UvwrVSI+c@r6mfiRV!1W4*ncAVCF)u`W*zlYVyIG^zuI1B5kykUkjPNM zkUIHeQS9UfXNS!KO%Ys^Kh#D{PFT5X@&t#3&1U|$7}1R24?L=fDm3|WQ8lW_X5Zr9 yyr@Ex-5cvsMSzMHb4||KE;qSL$YArfo-6EV@|{yoi(?3F=AJxDFl%zbjy(WK`BFOo delta 113 zcmdn-nQ6@@rVTIDCO=r?FnNPA%j5~_T9X@!MJAPqfVi6{sF#Rs7P7m>!d$_Sx;Zc~ zoo91`|1HMN9)U*`CrcGqO=4l$ysY>e@8ngDbrAMEuE`1u - + diff --git a/test/models/IRR/sphere_UTF16LE.irr b/test/models/IRR/sphere_UTF16LE.irr index d0f99a0186c7ad650da623e6487299a8dade9066..7974a4c70b5a7ee3b6f9650e5bdc00f27a777363 100644 GIT binary patch delta 26 ecmZ3ay+M0}9T#sRLopDhGL!&G{mr&qsoVf&y9U|- delta 12 Tcmdm>y-0h59oJ?bt`u$n9|{B+ diff --git a/test/models/IRRMesh/1.png b/test/models/IRRMesh/assets/1.png similarity index 100% rename from test/models/IRRMesh/1.png rename to test/models/IRRMesh/assets/1.png diff --git a/test/models/IRRMesh/SpiderTex.jpg b/test/models/IRRMesh/assets/SpiderTex.jpg similarity index 100% rename from test/models/IRRMesh/SpiderTex.jpg rename to test/models/IRRMesh/assets/SpiderTex.jpg diff --git a/test/models/IRRMesh/assets/UVTransformTestImg.png b/test/models/IRRMesh/assets/UVTransformTestImg.png new file mode 100644 index 0000000000000000000000000000000000000000..b8f6f54f1f5e2e3014307c83195238ec5f0a36b1 GIT binary patch literal 34368 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 literal 0 HcmV?d00001 diff --git a/test/models/IRRMesh/brownground_1-1.jpg b/test/models/IRRMesh/assets/brownground_1-1.jpg similarity index 100% rename from test/models/IRRMesh/brownground_1-1.jpg rename to test/models/IRRMesh/assets/brownground_1-1.jpg diff --git a/test/models/IRRMesh/crackedground_1-6.jpg b/test/models/IRRMesh/assets/crackedground_1-6.jpg similarity index 100% rename from test/models/IRRMesh/crackedground_1-6.jpg rename to test/models/IRRMesh/assets/crackedground_1-6.jpg diff --git a/test/models/IRRMesh/drkwood2.jpg b/test/models/IRRMesh/assets/drkwood2.jpg similarity index 100% rename from test/models/IRRMesh/drkwood2.jpg rename to test/models/IRRMesh/assets/drkwood2.jpg diff --git a/test/models/IRRMesh/engineflare1.jpg b/test/models/IRRMesh/assets/engineflare1.jpg similarity index 100% rename from test/models/IRRMesh/engineflare1.jpg rename to test/models/IRRMesh/assets/engineflare1.jpg diff --git a/test/models/IRRMesh/wal67ar_small.jpg b/test/models/IRRMesh/assets/wal67ar_small.jpg similarity index 100% rename from test/models/IRRMesh/wal67ar_small.jpg rename to test/models/IRRMesh/assets/wal67ar_small.jpg diff --git a/test/models/IRRMesh/wal69ar_small.jpg b/test/models/IRRMesh/assets/wal69ar_small.jpg similarity index 100% rename from test/models/IRRMesh/wal69ar_small.jpg rename to test/models/IRRMesh/assets/wal69ar_small.jpg diff --git a/test/models/IRRMesh/cellar.irrmesh b/test/models/IRRMesh/cellar.irrmesh index 0278c9239..ee787463a 100644 --- a/test/models/IRRMesh/cellar.irrmesh +++ b/test/models/IRRMesh/cellar.irrmesh @@ -13,8 +13,8 @@ - - + + @@ -870,8 +870,8 @@ - - + + diff --git a/test/models/IRRMesh/cellar_UTF16LE.irrmesh b/test/models/IRRMesh/cellar_UTF16LE.irrmesh index d8d3a661bd05d9c37e5c8ffc2f281e3a7061eb68..38ef1847c4f27a15d279e9b836ad44665ad3f013 100644 GIT binary patch delta 104 zcmbPqnETXW?hQ3;yon6OK$yx<0wnb(SF=^3ifq^3&a|Ctdc!OxzUCc*?K=b+x9<>S U`mqF6)%5k-m}*glKpNAv0Gj(Ba{vGU delta 42 zcmV+_0M-A>!wZtb3$T0!lZpm-gAfOY5C;Lb5C;Ohub0}k0(`R&2et~g8o~mwA6|10 A%>V!Z diff --git a/test/models/IRRMesh/spider.irrmesh b/test/models/IRRMesh/spider.irrmesh index e446a9ec2..e94901156 100644 --- a/test/models/IRRMesh/spider.irrmesh +++ b/test/models/IRRMesh/spider.irrmesh @@ -13,7 +13,7 @@ - + @@ -354,7 +354,7 @@ - + @@ -485,7 +485,7 @@ - + @@ -1609,7 +1609,7 @@ - + diff --git a/test/models/IRRMesh/spider_UTF16LE.irrmesh b/test/models/IRRMesh/spider_UTF16LE.irrmesh index 25fda7c276c171a9359e62a4ce372c5030efe5ae..4a3509d5b9c1760000589729e3c674e549fec2d4 100644 GIT binary patch delta 79 zcmeDCB)H>~;D!V?-b99CAWUT_0h0Qg - + @@ -96,7 +96,7 @@ - + @@ -179,7 +179,7 @@ - + @@ -262,7 +262,7 @@ - + @@ -345,7 +345,7 @@ - + diff --git a/test/models/IRRMesh/testFormatDetection_UTF16LE.xml b/test/models/IRRMesh/testFormatDetection_UTF16LE.xml index aa73560d4cf064032536838245ab23fa27cdf2f0..e38a1ef896ee2797386d893c7dc01706b40c5bb2 100644 GIT binary patch delta 363 zcmcb#g!#)d<_&plmWd3-K$yx<0wnbrLK(ssLKun|5*hM<{4|DqAUhW*k_zONFn9vl z=?r=d1wh&K$%5?mo6qT=;o4jwC?Q9&Ia!(%8*zqf@{bg~%>^kFD0Plqa{@J-vw6k# GRZ;+2=~oi~ delta 105 zcmeyejQP?M<_&plljpIEOg3QC+Wc?r8Lr7UumlYcuN*VVl$uhJULX64=MXl SMJBK4*W0YnpN1@2rV0R9zbxYb From ea9aa863ffe4002c97b0267b7a4a98d2ff8a0f88 Mon Sep 17 00:00:00 2001 From: Steve M Date: Sat, 9 Dec 2023 13:13:32 -0800 Subject: [PATCH 16/77] Increase texture variety --- .../UVTransform_OffsetUV0.5-mirrorUV.png | Bin 0 -> 48965 bytes ...orm_ScaleUV1-2_OffsetUV0-0.9_Rotate-72.png | Bin 0 -> 105643 bytes ...eUV1-2_OffsetUV0-0.9_Rotate-72_mirrorU.png | Bin 0 -> 130740 bytes .../assets/UVTransform_ScaleUV2x_Rotate45.png | Bin 0 -> 111075 bytes test/models/IRRMesh/testFormatDetection.xml | 8 ++++---- .../IRRMesh/testFormatDetection_UTF16LE.xml | Bin 54132 -> 54312 bytes 6 files changed, 4 insertions(+), 4 deletions(-) create mode 100644 test/models/IRRMesh/assets/UVTransform_OffsetUV0.5-mirrorUV.png create mode 100644 test/models/IRRMesh/assets/UVTransform_ScaleUV1-2_OffsetUV0-0.9_Rotate-72.png create mode 100644 test/models/IRRMesh/assets/UVTransform_ScaleUV1-2_OffsetUV0-0.9_Rotate-72_mirrorU.png create mode 100644 test/models/IRRMesh/assets/UVTransform_ScaleUV2x_Rotate45.png diff --git a/test/models/IRRMesh/assets/UVTransform_OffsetUV0.5-mirrorUV.png b/test/models/IRRMesh/assets/UVTransform_OffsetUV0.5-mirrorUV.png new file mode 100644 index 0000000000000000000000000000000000000000..447d30c32624c829d9efc3622d74bc6d2847c6d8 GIT binary patch literal 48965 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

ulNi_-}@w((jgY2 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 Yj@!)DU^T`g9^x?!^h_y5x(;Fg0lt@@vH$=8 literal 0 HcmV?d00001 diff --git a/test/models/IRRMesh/assets/UVTransform_ScaleUV1-2_OffsetUV0-0.9_Rotate-72_mirrorU.png b/test/models/IRRMesh/assets/UVTransform_ScaleUV1-2_OffsetUV0-0.9_Rotate-72_mirrorU.png new file mode 100644 index 0000000000000000000000000000000000000000..9fdc6daabee2827b31880cf00f22a8d15b320091 GIT binary patch literal 130740 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ℑMQ>5#n2IE2O5J}g5zj~>=K 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 z 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 literal 0 HcmV?d00001 diff --git a/test/models/IRRMesh/assets/UVTransform_ScaleUV2x_Rotate45.png b/test/models/IRRMesh/assets/UVTransform_ScaleUV2x_Rotate45.png new file mode 100644 index 0000000000000000000000000000000000000000..ac15908c365454077f041431e06079c5150c5191 GIT binary patch literal 111075 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 literal 0 HcmV?d00001 diff --git a/test/models/IRRMesh/testFormatDetection.xml b/test/models/IRRMesh/testFormatDetection.xml index 22ceeb007..fd2e34f65 100644 --- a/test/models/IRRMesh/testFormatDetection.xml +++ b/test/models/IRRMesh/testFormatDetection.xml @@ -96,7 +96,7 @@ - + @@ -179,7 +179,7 @@ - + @@ -262,7 +262,7 @@ - + @@ -345,7 +345,7 @@ - + diff --git a/test/models/IRRMesh/testFormatDetection_UTF16LE.xml b/test/models/IRRMesh/testFormatDetection_UTF16LE.xml index e38a1ef896ee2797386d893c7dc01706b40c5bb2..64891be9f7e4a2e577597a3502f48bd24065bd4d 100644 GIT binary patch delta 280 zcmeyejCsWh<_+)kHRBol8Pb5Tm?4#+gdvn6jKP3GkHM5dmm!xSlc5L*^MM#BzIi^I zF!yFY>qBy`@eIKX$qb1MIY2!i9fm;FMhw_Y(gmAl36u*0no|PQQv%eZ%V5r61TpVJ n$|Jc@s+b3~1I5Lg?>C>;R7E%1h@k?_F(wSA5T~5lu}TU6iI_bc delta 53 xcmZ3ng89ob<_+)kH&0?y;NGldeMk<>ntUVU%w~Z!F$iySU;hp$t8V8iDF9%n72W^< From c8ca1a48ecd673c3cc8b6132354251ceb0855ca8 Mon Sep 17 00:00:00 2001 From: Kim Kulling Date: Fri, 5 Jan 2024 21:59:52 +0100 Subject: [PATCH 17/77] Update Dockerfile - closes https://github.com/assimp/assimp/issues/5403 --- Dockerfile | 1 + 1 file changed, 1 insertion(+) diff --git a/Dockerfile b/Dockerfile index 5da5458f8..eb5715d0f 100644 --- a/Dockerfile +++ b/Dockerfile @@ -6,6 +6,7 @@ RUN apt-get update && apt-get install -y ninja-build \ RUN add-apt-repository ppa:ubuntu-toolchain-r/test && apt-get update WORKDIR /opt +RUN apt install zlib1g-dev # Build Assimp RUN git clone https://github.com/assimp/assimp.git /opt/assimp From 9d71a275c3ce84617f1c57625cf658e1be884eb5 Mon Sep 17 00:00:00 2001 From: Andre Schulz Date: Sun, 3 Dec 2023 13:05:10 +0100 Subject: [PATCH 18/77] X3D: Don't convert IndexedLineSet polylines with > 2 indices to triangles/polygons Currently, when the coordIndex attribute of an IndexedLineSet contains a polyline with > 2 indices, X3DGeoHelper::coordIdx_str2faces_arr() will incorrectly determine the primitive type to be aiPrimitiveType_TRIANGLE or aiPrimitiveType_POLYGON instead of aiPrimitiveType_LINE. To fix this, this commit adds functions to explicitly handle an IndexedLineSet. Fixes #3101 --- code/AssetLib/X3D/X3DGeoHelper.cpp | 81 +++++++++++++++++++ code/AssetLib/X3D/X3DGeoHelper.h | 2 + code/AssetLib/X3D/X3DImporter_Postprocess.cpp | 2 +- 3 files changed, 84 insertions(+), 1 deletion(-) diff --git a/code/AssetLib/X3D/X3DGeoHelper.cpp b/code/AssetLib/X3D/X3DGeoHelper.cpp index 0a62ff9b0..1c962a460 100644 --- a/code/AssetLib/X3D/X3DGeoHelper.cpp +++ b/code/AssetLib/X3D/X3DGeoHelper.cpp @@ -188,6 +188,51 @@ mg_m_err: pFaces.clear(); } +void X3DGeoHelper::coordIdx_str2lines_arr(const std::vector &pCoordIdx, std::vector &pFaces) { + std::vector f_data(pCoordIdx); + + if (f_data.back() != (-1)) { + f_data.push_back(-1); + } + + // reserve average size. + pFaces.reserve(f_data.size() / 2); + for (std::vector::const_iterator startIt = f_data.cbegin(), endIt = f_data.cbegin(); endIt != f_data.cend(); ++endIt) { + // check for end of current polyline + if (*endIt != -1) + continue; + + // found end of polyline, check if this is a valid polyline + std::size_t numIndices = std::distance(startIt, endIt); + if (numIndices <= 1) + goto mg_m_err; + + // create line faces out of polyline indices + for (int32_t idx0 = *startIt++; startIt != endIt; ++startIt) { + int32_t idx1 = *startIt; + + aiFace tface; + tface.mNumIndices = 2; + tface.mIndices = new unsigned int[2]; + tface.mIndices[0] = idx0; + tface.mIndices[1] = idx1; + pFaces.push_back(tface); + + idx0 = idx1; + } + + ++startIt; + } + + return; + +mg_m_err: + for (size_t i = 0, i_e = pFaces.size(); i < i_e; i++) + delete[] pFaces[i].mIndices; + + pFaces.clear(); +} + void X3DGeoHelper::add_color(aiMesh &pMesh, const std::list &pColors, const bool pColorPerVertex) { std::list tcol; @@ -528,4 +573,40 @@ aiMesh *X3DGeoHelper::make_mesh(const std::vector &pCoordIdx, const std return tmesh; } +aiMesh *X3DGeoHelper::make_line_mesh(const std::vector &pCoordIdx, const std::list &pVertices) { + std::vector faces; + + // create faces array from input string with vertices indices. + X3DGeoHelper::coordIdx_str2lines_arr(pCoordIdx, faces); + if (!faces.size()) { + throw DeadlyImportError("Failed to create mesh, faces list is empty."); + } + + // + // Create new mesh and copy geometry data. + // + aiMesh *tmesh = new aiMesh; + size_t ts = faces.size(); + // faces + tmesh->mFaces = new aiFace[ts]; + tmesh->mNumFaces = static_cast(ts); + for (size_t i = 0; i < ts; i++) + tmesh->mFaces[i] = faces[i]; + + // vertices + std::list::const_iterator vit = pVertices.begin(); + + ts = pVertices.size(); + tmesh->mVertices = new aiVector3D[ts]; + tmesh->mNumVertices = static_cast(ts); + for (size_t i = 0; i < ts; i++) { + tmesh->mVertices[i] = *vit++; + } + + // set primitive type and return result. + tmesh->mPrimitiveTypes = aiPrimitiveType_LINE; + + return tmesh; +} + } // namespace Assimp diff --git a/code/AssetLib/X3D/X3DGeoHelper.h b/code/AssetLib/X3D/X3DGeoHelper.h index 78e57f9da..c740b4288 100644 --- a/code/AssetLib/X3D/X3DGeoHelper.h +++ b/code/AssetLib/X3D/X3DGeoHelper.h @@ -21,6 +21,7 @@ public: static void polylineIdx_to_lineIdx(const std::list &pPolylineCoordIdx, std::list &pLineCoordIdx); static void rect_parallel_epiped(const aiVector3D &pSize, std::list &pVertices); static void coordIdx_str2faces_arr(const std::vector &pCoordIdx, std::vector &pFaces, unsigned int &pPrimitiveTypes); + static void coordIdx_str2lines_arr(const std::vector &pCoordIdx, std::vector &pFaces); static void add_color(aiMesh &pMesh, const std::list &pColors, const bool pColorPerVertex); static void add_color(aiMesh &pMesh, const std::list &pColors, const bool pColorPerVertex); static void add_color(aiMesh &pMesh, const std::vector &pCoordIdx, const std::vector &pColorIdx, @@ -34,6 +35,7 @@ public: const std::list &pTexCoords); static void add_tex_coord(aiMesh &pMesh, const std::list &pTexCoords); static aiMesh *make_mesh(const std::vector &pCoordIdx, const std::list &pVertices); + static aiMesh *make_line_mesh(const std::vector &pCoordIdx, const std::list &pVertices); }; } // namespace Assimp diff --git a/code/AssetLib/X3D/X3DImporter_Postprocess.cpp b/code/AssetLib/X3D/X3DImporter_Postprocess.cpp index 87121ef5f..216929076 100644 --- a/code/AssetLib/X3D/X3DImporter_Postprocess.cpp +++ b/code/AssetLib/X3D/X3DImporter_Postprocess.cpp @@ -320,7 +320,7 @@ void X3DImporter::Postprocess_BuildMesh(const X3DNodeElementBase &pNodeElement, // at first search for node and create mesh. for (std::list::iterator ch_it = tnemesh.Children.begin(); ch_it != tnemesh.Children.end(); ++ch_it) { if ((*ch_it)->Type == X3DElemType::ENET_Coordinate) { - *pMesh = X3DGeoHelper::make_mesh(tnemesh.CoordIndex, ((X3DNodeElementCoordinate *)*ch_it)->Value); + *pMesh = X3DGeoHelper::make_line_mesh(tnemesh.CoordIndex, ((X3DNodeElementCoordinate *)*ch_it)->Value); } } From 74af43f6559af645c9f79c7e6e9cc149bdbb57cc Mon Sep 17 00:00:00 2001 From: Andre Schulz Date: Sun, 3 Dec 2023 13:06:45 +0100 Subject: [PATCH 19/77] Add unit test for X3D IndexedLineSet Unit test for issue #3101 Thanks to @mvidiassov for the X3D test file! --- test/models/X3D/IndexedLineSet.x3d | 19 +++++++++++++++++++ test/unit/utX3DImportExport.cpp | 14 ++++++++++++++ 2 files changed, 33 insertions(+) create mode 100644 test/models/X3D/IndexedLineSet.x3d diff --git a/test/models/X3D/IndexedLineSet.x3d b/test/models/X3D/IndexedLineSet.x3d new file mode 100644 index 000000000..ed865ebb7 --- /dev/null +++ b/test/models/X3D/IndexedLineSet.x3d @@ -0,0 +1,19 @@ + + + + + + + + + + + + + + + + + + + diff --git a/test/unit/utX3DImportExport.cpp b/test/unit/utX3DImportExport.cpp index f2df81ac2..a654765de 100644 --- a/test/unit/utX3DImportExport.cpp +++ b/test/unit/utX3DImportExport.cpp @@ -44,6 +44,7 @@ OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. #include #include +#include using namespace Assimp; @@ -59,3 +60,16 @@ public: TEST_F(utX3DImportExport, importX3DFromFileTest) { EXPECT_TRUE(importerTest()); } + +TEST_F(utX3DImportExport, importX3DIndexedLineSet) { + Assimp::Importer importer; + const aiScene *scene = importer.ReadFile(ASSIMP_TEST_MODELS_DIR "/X3D/IndexedLineSet.x3d", aiProcess_ValidateDataStructure); + ASSERT_NE(nullptr, scene); + ASSERT_EQ(scene->mNumMeshes, 1u); + ASSERT_EQ(scene->mMeshes[0]->mNumFaces, 4u); + ASSERT_EQ(scene->mMeshes[0]->mPrimitiveTypes, aiPrimitiveType_LINE); + ASSERT_EQ(scene->mMeshes[0]->mNumVertices, 4u); + for (unsigned int i = 0; i < scene->mMeshes[0]->mNumFaces; i++) { + ASSERT_EQ(scene->mMeshes[0]->mFaces[i].mNumIndices, 2u); + } +} From 81c20a5c6155ab906b58f655685ad0481e13b650 Mon Sep 17 00:00:00 2001 From: Robert Reif Date: Thu, 30 Nov 2023 04:12:28 -0500 Subject: [PATCH 20/77] Improve acc file loading Add warning and support for tolerating a common problem where objects have wrong kid count. Add support for empty texture layers. --- code/AssetLib/AC/ACLoader.cpp | 42 ++- code/AssetLib/AC/ACLoader.h | 2 +- test/models/AC/SphereWithLight.acc | 535 +++++++++++++++++++++++++++++ test/unit/utACImportExport.cpp | 6 + 4 files changed, 565 insertions(+), 20 deletions(-) create mode 100644 test/models/AC/SphereWithLight.acc diff --git a/code/AssetLib/AC/ACLoader.cpp b/code/AssetLib/AC/ACLoader.cpp index 1bb77c441..f98a4d105 100644 --- a/code/AssetLib/AC/ACLoader.cpp +++ b/code/AssetLib/AC/ACLoader.cpp @@ -170,9 +170,9 @@ bool AC3DImporter::GetNextLine() { // ------------------------------------------------------------------------------------------------ // Parse an object section in an AC file -void AC3DImporter::LoadObjectSection(std::vector &objects) { +bool AC3DImporter::LoadObjectSection(std::vector &objects) { if (!TokenMatch(buffer, "OBJECT", 6)) - return; + return false; SkipSpaces(&buffer); @@ -212,10 +212,14 @@ void AC3DImporter::LoadObjectSection(std::vector &objects) { if (num) { // load the children of this object recursively obj.children.reserve(num); - for (unsigned int i = 0; i < num; ++i) - LoadObjectSection(obj.children); + for (unsigned int i = 0; i < num; ++i) { + if (!LoadObjectSection(obj.children)) { + ASSIMP_LOG_WARN("AC3D: wrong number of kids"); + break; + } + } } - return; + return true; } else if (TokenMatch(buffer, "name", 4)) { SkipSpaces(&buffer); buffer = AcGetString(buffer, obj.name); @@ -227,9 +231,16 @@ void AC3DImporter::LoadObjectSection(std::vector &objects) { } } else if (TokenMatch(buffer, "texture", 7)) { SkipSpaces(&buffer); - std::string texture; - buffer = AcGetString(buffer, texture); - obj.textures.push_back(texture); + // 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); @@ -340,6 +351,7 @@ void AC3DImporter::LoadObjectSection(std::vector &objects) { } } ASSIMP_LOG_ERROR("AC3D: Unexpected EOF: \'kids\' line was expected"); + return false; } // ------------------------------------------------------------------------------------------------ @@ -445,7 +457,7 @@ aiNode *AC3DImporter::ConvertObjectSection(Object &object, idx = 0; } if ((*it).entries.empty()) { - ASSIMP_LOG_WARN("AC3D: surface her zero vertex references"); + ASSIMP_LOG_WARN("AC3D: surface has zero vertex references"); } // validate all vertex indices to make sure we won't crash here @@ -574,15 +586,6 @@ aiNode *AC3DImporter::ConvertObjectSection(Object &object, const Surface::SurfaceEntry &entry2 = src.entries[i + 1]; const Surface::SurfaceEntry &entry3 = src.entries[i + 2]; - // skip degenerate triangles - if (object.vertices[entry1.first] == object.vertices[entry2.first] || - object.vertices[entry1.first] == object.vertices[entry3.first] || - object.vertices[entry2.first] == object.vertices[entry3.first]) { - mesh->mNumFaces--; - mesh->mNumVertices -= 3; - continue; - } - aiFace &face = *faces++; face.mNumIndices = 3; face.mIndices = new unsigned int[face.mNumIndices]; @@ -804,8 +807,9 @@ void AC3DImporter::InternReadFile(const std::string &pFile, buffer = TAcCheckedLoadFloatArray(buffer, "spec", 4, 3, &mat.spec); buffer = TAcCheckedLoadFloatArray(buffer, "shi", 3, 1, &mat.shin); buffer = TAcCheckedLoadFloatArray(buffer, "trans", 5, 1, &mat.trans); + } else { + LoadObjectSection(rootObjects); } - LoadObjectSection(rootObjects); } if (rootObjects.empty() || !mNumMeshes) { diff --git a/code/AssetLib/AC/ACLoader.h b/code/AssetLib/AC/ACLoader.h index 7f8dfd03c..3b5be4b6e 100644 --- a/code/AssetLib/AC/ACLoader.h +++ b/code/AssetLib/AC/ACLoader.h @@ -216,7 +216,7 @@ private: * load subobjects, the method returns after a 'kids 0' was * encountered. * @objects List of output objects*/ - void LoadObjectSection(std::vector &objects); + bool LoadObjectSection(std::vector &objects); // ------------------------------------------------------------------- /** Convert all objects into meshes and nodes. diff --git a/test/models/AC/SphereWithLight.acc b/test/models/AC/SphereWithLight.acc new file mode 100644 index 000000000..42096672a --- /dev/null +++ b/test/models/AC/SphereWithLight.acc @@ -0,0 +1,535 @@ +AC3Db +MATERIAL "ac3dmat1" rgb 1.00 1.00 1.00 amb 0.20 0.20 0.20 emis 0.00 0.00 0.00 spec 0.20 0.20 0.20 shi 128 trans 0 +OBJECT world +kids 2 +OBJECT light +name "light" +loc 0.000424567 -0.0127304 0 +kids 0 +OBJECT poly +name "sphere" +texture "earthSpherical.jpg" base +texture empty_texture_no_mapping tiled +texture empty_texture_no_mapping skids +texture empty_texture_no_mapping shad +numvert 167 +-0.051576 -0.062833 0.063067 0.224114 -0.961969 0.156168 +-0.064432 -0.064684 0.055841 0.000000 -1.000000 -0.000000 +-0.049587 -0.062833 0.055841 0.270337 -0.962554 0.020215 +-0.057009 -0.062833 0.068357 0.117917 -0.961035 0.250013 +-0.064432 -0.064684 0.055841 0.000000 -1.000000 -0.000000 +-0.064432 -0.062833 0.070294 -0.019618 -0.960685 0.276946 +-0.064432 -0.064684 0.055841 0.000000 -1.000000 -0.000000 +-0.071854 -0.062833 0.068357 -0.151973 -0.961267 0.229935 +-0.064432 -0.064684 0.055841 0.000000 -1.000000 -0.000000 +-0.077288 -0.062833 0.063067 -0.243865 -0.962202 0.121235 +-0.064432 -0.064684 0.055841 0.000000 -1.000000 -0.000000 +-0.079277 -0.062833 0.055841 -0.270337 -0.962554 -0.020215 +-0.064432 -0.064684 0.055841 0.000000 -1.000000 -0.000000 +-0.077288 -0.062833 0.048614 -0.224114 -0.961969 -0.156168 +-0.064432 -0.064684 0.055841 0.000000 -1.000000 -0.000000 +-0.071854 -0.062833 0.043324 -0.117917 -0.961035 -0.250013 +-0.064432 -0.064684 0.055841 0.000000 -1.000000 -0.000000 +-0.064432 -0.062833 0.041388 0.019618 -0.960685 -0.276946 +-0.064432 -0.064684 0.055841 0.000000 -1.000000 -0.000000 +-0.057009 -0.062833 0.043324 0.151973 -0.961267 -0.229935 +-0.064432 -0.064684 0.055841 0.000000 -1.000000 -0.000000 +-0.049587 0.042114 0.055841 0.270334 0.962554 -0.020215 +-0.064432 0.043965 0.055841 0.000000 1.000000 -0.000000 +-0.051576 0.042114 0.063067 0.243863 0.962202 0.121233 +-0.064432 0.043965 0.055841 0.000000 1.000000 -0.000000 +-0.057009 0.042114 0.068357 0.151972 0.961268 0.229933 +-0.064432 0.043965 0.055841 0.000000 1.000000 -0.000000 +-0.064432 0.042114 0.070294 0.019618 0.960686 0.276944 +-0.064432 0.043965 0.055841 0.000000 1.000000 -0.000000 +-0.071854 0.042114 0.068357 -0.117915 0.961036 0.250011 +-0.064432 0.043965 0.055841 0.000000 1.000000 -0.000000 +-0.077288 0.042114 0.063067 -0.224112 0.961970 0.156167 +-0.064432 0.043965 0.055841 0.000000 1.000000 -0.000000 +-0.079277 0.042114 0.055841 -0.270334 0.962554 0.020215 +-0.064432 0.043965 0.055841 0.000000 1.000000 -0.000000 +-0.077288 0.042114 0.048614 -0.243863 0.962202 -0.121233 +-0.064432 0.043965 0.055841 0.000000 1.000000 -0.000000 +-0.071854 0.042114 0.043324 -0.151972 0.961268 -0.229933 +-0.064432 0.043965 0.055841 0.000000 1.000000 -0.000000 +-0.064432 0.042114 0.041388 -0.019618 0.960686 -0.276944 +-0.064432 0.043965 0.055841 0.000000 1.000000 -0.000000 +-0.057009 0.042114 0.043324 0.117916 0.961036 -0.250011 +-0.035753 -0.057406 0.055841 0.479979 -0.877222 0.010123 +-0.049587 -0.062833 0.055841 0.270337 -0.962554 0.020215 +-0.051576 -0.062833 0.048614 0.243865 -0.962202 -0.121234 +-0.039596 -0.057406 0.041881 0.420061 -0.875943 -0.237219 +-0.023874 -0.048773 0.055841 0.687850 -0.725803 0.008451 +-0.029308 -0.048773 0.036098 0.598218 -0.723534 -0.344433 +-0.014759 -0.037522 0.055841 0.853991 -0.520251 0.006112 +-0.021414 -0.037522 0.031661 0.739473 -0.517639 -0.430382 +-0.009029 -0.024420 0.055841 0.962274 -0.272063 0.003217 +-0.016452 -0.024420 0.028872 0.830450 -0.270187 -0.487187 +-0.007075 -0.010360 0.055841 1.000000 -0.000000 0.000000 +-0.014759 -0.010360 0.027920 0.860926 0.000265 -0.508731 +-0.009029 0.003701 0.055841 0.962274 0.272063 -0.003217 +-0.016452 0.003701 0.028872 0.827147 0.270625 -0.492534 +-0.014759 0.016803 0.055841 0.853991 0.520251 -0.006112 +-0.021414 0.016803 0.031661 0.733264 0.517855 -0.440625 +-0.023874 0.028054 0.055841 0.687850 0.725803 -0.008451 +-0.029308 0.028054 0.036098 0.589753 0.723523 -0.358756 +-0.035753 0.036687 0.055841 0.479979 0.877222 -0.010123 +-0.039596 0.036687 0.041881 0.410061 0.875812 -0.254565 +-0.049587 0.042114 0.055841 0.270334 0.962554 -0.020215 +-0.051576 0.042114 0.048614 0.224112 0.961970 -0.156167 +-0.064432 0.043965 0.055841 0.000000 1.000000 -0.000000 +-0.064432 -0.064684 0.055841 0.000000 -1.000000 -0.000000 +-0.039596 -0.057406 0.069801 0.410061 -0.875812 0.254565 +-0.035753 -0.057406 0.055841 0.479979 -0.877222 0.010123 +-0.050092 -0.057406 0.080021 0.230454 -0.873143 0.429549 +-0.064432 -0.057406 0.083761 -0.009683 -0.871880 0.489625 +-0.078771 -0.057406 0.080021 -0.247407 -0.873270 0.419748 +-0.089268 -0.057406 0.069801 -0.420061 -0.875942 0.237220 +-0.093110 -0.057406 0.055841 -0.479980 -0.877221 -0.010124 +-0.089268 -0.057406 0.041881 -0.410062 -0.875812 -0.254565 +-0.078771 -0.057406 0.031661 -0.230453 -0.873143 -0.429549 +-0.064432 -0.057406 0.027920 0.009684 -0.871880 -0.489625 +-0.050092 -0.057406 0.031661 0.247407 -0.873271 -0.419748 +-0.029308 -0.048773 0.075583 0.589753 -0.723523 0.358757 +-0.023874 -0.048773 0.055841 0.687850 -0.725803 0.008451 +-0.044153 -0.048773 0.090036 0.333957 -0.719029 0.609483 +-0.064432 -0.048773 0.095326 -0.007940 -0.716811 0.697222 +-0.084710 -0.048773 0.090036 -0.348006 -0.719035 0.601564 +-0.099555 -0.048773 0.075583 -0.598218 -0.723534 0.344434 +-0.104989 -0.048773 0.055841 -0.687850 -0.725804 -0.008451 +-0.099555 -0.048773 0.036098 -0.589753 -0.723523 -0.358757 +-0.084710 -0.048773 0.021645 -0.333958 -0.719029 -0.609483 +-0.064432 -0.048773 0.016355 0.007940 -0.716811 -0.697222 +-0.044153 -0.048773 0.021645 0.348006 -0.719035 -0.601565 +-0.021414 -0.037522 0.080021 0.733263 -0.517855 0.440625 +-0.014759 -0.037522 0.055841 0.853991 -0.520251 0.006112 +-0.039596 -0.037522 0.097721 0.416448 -0.512938 0.750643 +-0.064432 -0.037522 0.104200 -0.005639 -0.510417 0.859908 +-0.089268 -0.037522 0.097721 -0.426533 -0.512723 0.745107 +-0.107449 -0.037522 0.080021 -0.739473 -0.517640 0.430382 +-0.114104 -0.037522 0.055841 -0.853991 -0.520252 -0.006112 +-0.107449 -0.037522 0.031661 -0.733262 -0.517857 -0.440626 +-0.089268 -0.037522 0.013960 -0.416448 -0.512938 -0.750643 +-0.064432 -0.037522 0.007481 0.005639 -0.510417 -0.859908 +-0.039595 -0.037522 0.013960 0.426534 -0.512723 -0.745107 +-0.016452 -0.024420 0.082810 0.827147 -0.270625 0.492534 +-0.009029 -0.024420 0.055841 0.962274 -0.272063 0.003217 +-0.036730 -0.024420 0.102553 0.470709 -0.267377 0.840799 +-0.064432 -0.024420 0.109779 -0.002929 -0.265584 0.964083 +-0.092133 -0.024420 0.102553 -0.475987 -0.266955 0.837957 +-0.112412 -0.024420 0.082810 -0.830450 -0.270188 0.487187 +-0.119834 -0.024420 0.055841 -0.962274 -0.272062 -0.003217 +-0.112412 -0.024420 0.028872 -0.827148 -0.270623 -0.492534 +-0.092133 -0.024420 0.009129 -0.470709 -0.267377 -0.840799 +-0.064432 -0.024420 0.001903 0.002929 -0.265584 -0.964083 +-0.036730 -0.024420 0.009129 0.475987 -0.266954 -0.837957 +-0.014759 -0.010360 0.083761 0.860926 -0.000266 0.508731 +-0.007075 -0.010360 0.055841 1.000000 -0.000000 0.000000 +-0.035753 -0.010360 0.104200 0.491288 -0.000257 0.870997 +-0.064432 -0.010360 0.111682 0.000000 -0.000000 1.000000 +-0.093110 -0.010360 0.104200 -0.491288 0.000257 0.870997 +-0.114104 -0.010360 0.083761 -0.860926 0.000265 0.508731 +-0.121788 -0.010360 0.055841 -1.000000 -0.000001 -0.000001 +-0.114104 -0.010360 0.027920 -0.860925 -0.000266 -0.508731 +-0.093110 -0.010360 0.007481 -0.491288 -0.000256 -0.870997 +-0.064432 -0.010360 0.000000 0.000000 -0.000000 -1.000000 +-0.035753 -0.010360 0.007481 0.491288 0.000257 -0.870997 +-0.016452 0.003701 0.082810 0.830450 0.270188 0.487187 +-0.009029 0.003701 0.055841 0.962274 0.272063 -0.003217 +-0.036730 0.003701 0.102553 0.475987 0.266955 0.837957 +-0.064432 0.003701 0.109779 0.002929 0.265584 0.964083 +-0.092133 0.003701 0.102553 -0.470709 0.267377 0.840799 +-0.112412 0.003701 0.082810 -0.827147 0.270625 0.492534 +-0.119834 0.003701 0.055841 -0.962274 0.272063 0.003217 +-0.112412 0.003701 0.028872 -0.830450 0.270186 -0.487188 +-0.092133 0.003701 0.009129 -0.475987 0.266954 -0.837957 +-0.064432 0.003701 0.001903 -0.002929 0.265583 -0.964083 +-0.036730 0.003701 0.009129 0.470710 0.267376 -0.840799 +-0.021414 0.016803 0.080021 0.739473 0.517639 0.430383 +-0.014759 0.016803 0.055841 0.853991 0.520251 -0.006112 +-0.039596 0.016803 0.097721 0.426533 0.512723 0.745107 +-0.064432 0.016803 0.104200 0.005639 0.510417 0.859908 +-0.089268 0.016803 0.097721 -0.416448 0.512938 0.750643 +-0.107449 0.016803 0.080021 -0.733262 0.517857 0.440626 +-0.114104 0.016803 0.055841 -0.853991 0.520252 0.006112 +-0.107449 0.016803 0.031661 -0.739473 0.517640 -0.430382 +-0.089268 0.016803 0.013960 -0.426533 0.512723 -0.745107 +-0.064432 0.016803 0.007481 -0.005640 0.510418 -0.859908 +-0.039595 0.016803 0.013960 0.416449 0.512938 -0.750643 +-0.029308 0.028054 0.075583 0.598218 0.723534 0.344433 +-0.023874 0.028054 0.055841 0.687850 0.725803 -0.008451 +-0.044153 0.028054 0.090036 0.348006 0.719035 0.601565 +-0.064432 0.028054 0.095326 0.007940 0.716811 0.697222 +-0.084710 0.028054 0.090036 -0.333958 0.719029 0.609483 +-0.099555 0.028054 0.075583 -0.589753 0.723523 0.358757 +-0.104989 0.028054 0.055841 -0.687850 0.725804 0.008451 +-0.099555 0.028054 0.036098 -0.598218 0.723534 -0.344434 +-0.084710 0.028054 0.021645 -0.348006 0.719035 -0.601564 +-0.064432 0.028054 0.016355 -0.007940 0.716811 -0.697222 +-0.044153 0.028054 0.021645 0.333956 0.719030 -0.609483 +-0.039596 0.036687 0.069801 0.420061 0.875943 0.237219 +-0.035753 0.036687 0.055841 0.479979 0.877222 -0.010123 +-0.050092 0.036687 0.080021 0.247407 0.873271 0.419748 +-0.064432 0.036687 0.083761 0.009684 0.871880 0.489625 +-0.078771 0.036687 0.080021 -0.230453 0.873143 0.429549 +-0.089268 0.036687 0.069801 -0.410062 0.875812 0.254565 +-0.093110 0.036687 0.055841 -0.479980 0.877221 0.010124 +-0.089268 0.036687 0.041881 -0.420061 0.875942 -0.237220 +-0.078771 0.036687 0.031661 -0.247407 0.873270 -0.419748 +-0.064432 0.036687 0.027920 -0.009683 0.871880 -0.489625 +-0.050092 0.036687 0.031661 0.230454 0.873143 -0.429549 +-0.064432 0.043965 0.055841 0.000000 1.000000 -0.000000 +-0.064432 -0.064684 0.055841 0.000000 -1.000000 -0.000000 +numsurf 13 +SURF 0x14 +mat 0 +refs 25 +166 0.12500 0.00000 0.19898 0.00100 0.23912 -0.60440 0.00000 0.00000 +19 0.16667 0.08333 0.20078 0.00100 0.27261 -0.65958 0.06470 0.11207 +44 0.08333 0.08333 0.22774 0.00100 0.24337 -0.66338 0.11207 0.06470 +45 0.08333 0.16667 0.25662 0.00100 0.24258 -0.70570 0.21651 0.12500 +42 -0.00000 0.16667 0.29617 0.00100 0.18165 -0.65455 0.25000 0.00000 +45 0.08333 0.16667 0.25662 0.00100 0.24258 -0.70570 0.21651 0.12500 +46 -0.00000 0.25000 0.34675 0.00100 0.14154 -0.62617 0.35355 0.00000 +47 0.08333 0.25000 0.28254 0.00100 0.23215 -0.72379 0.30619 0.17678 +48 -0.00000 0.33333 0.39286 0.00100 0.09463 -0.54477 0.43301 0.00000 +49 0.08333 0.33333 0.30010 0.00100 0.20445 -0.70053 0.37500 0.21651 +50 -0.00000 0.41667 0.42672 0.00100 0.04684 -0.39635 0.48296 0.00000 +51 0.08333 0.41667 0.30053 0.00100 0.14994 -0.59217 0.41826 0.24148 +52 -0.00000 0.50000 0.43819 0.27990 0.01216 -0.18101 0.50000 0.00000 +53 0.08333 0.50000 0.27797 0.11146 0.07998 -0.31169 0.43301 0.25000 +54 -0.00000 0.58333 0.42036 0.71453 0.00746 0.06528 0.48296 0.00000 +55 0.08333 0.58333 0.25398 0.77247 0.06825 0.11068 0.41826 0.24148 +56 -0.00000 0.66667 0.37732 0.99900 0.03584 0.27934 0.43301 0.00000 +57 0.08333 0.66667 0.24356 0.99900 0.12085 0.40243 0.37500 0.21651 +58 -0.00000 0.75000 0.32156 0.99900 0.08264 0.41936 0.35355 0.00000 +59 0.08333 0.75000 0.23016 0.99900 0.16764 0.51660 0.30619 0.17678 +60 -0.00000 0.83333 0.26409 0.99900 0.13155 0.48413 0.25000 0.00000 +61 0.08333 0.83333 0.21022 0.99900 0.19350 0.53698 0.21651 0.12500 +62 -0.00000 0.91667 0.21082 0.99900 0.17434 0.49121 0.12941 0.00000 +63 0.08333 0.91667 0.18721 0.99900 0.20517 0.51082 0.11207 0.06470 +64 0.04167 1.00000 0.16417 0.99900 0.20895 0.45830 0.00000 0.00000 +SURF 0x14 +mat 0 +refs 4 +42 -0.00000 0.16667 0.29617 0.00100 0.18165 -0.65455 0.25000 0.00000 +43 -0.00000 0.08333 0.24596 0.00100 0.21392 -0.64381 0.12941 0.00000 +44 0.08333 0.08333 0.22774 0.00100 0.24337 -0.66338 0.11207 0.06470 +65 0.04167 0.00000 0.19898 0.00100 0.23912 -0.60440 0.00000 0.00000 +SURF 0x14 +mat 0 +refs 26 +41 0.16667 0.91667 0.15686 0.99900 0.23923 0.50697 0.06470 0.11207 +165 0.12500 1.00000 0.16417 0.99900 0.20895 0.45830 0.00000 0.00000 +41 0.16667 0.91667 0.15686 0.99900 0.23923 0.50697 0.06470 0.11207 +63 0.08333 0.91667 0.18721 0.99900 0.20517 0.51082 0.11207 0.06470 +164 0.16667 0.83333 0.14064 0.99900 0.27287 0.52638 0.12500 0.21651 +61 0.08333 0.83333 0.21022 0.99900 0.19350 0.53698 0.21651 0.12500 +153 0.16667 0.75000 0.11005 0.99900 0.30883 0.49554 0.17678 0.30619 +59 0.08333 0.75000 0.23016 0.99900 0.16764 0.51660 0.30619 0.17678 +142 0.16667 0.66667 0.06221 0.99900 0.34565 0.37156 0.21651 0.37500 +57 0.08333 0.66667 0.24356 0.99900 0.12085 0.40243 0.37500 0.21651 +131 0.16667 0.58333 0.01707 0.75383 0.37997 0.09731 0.24148 0.41826 +55 0.08333 0.58333 0.25398 0.77247 0.06825 0.11068 0.41826 0.24148 +120 0.16667 0.50000 0.02917 0.16155 0.40148 -0.27285 0.25000 0.43301 +53 0.08333 0.50000 0.27797 0.11146 0.07998 -0.31169 0.43301 0.25000 +109 0.16667 0.41667 0.09227 0.00100 0.39866 -0.54216 0.24148 0.41826 +51 0.08333 0.41667 0.30053 0.00100 0.14994 -0.59217 0.41826 0.24148 +98 0.16667 0.33333 0.14840 0.00100 0.37604 -0.66637 0.21651 0.37500 +49 0.08333 0.33333 0.30010 0.00100 0.20445 -0.70053 0.37500 0.21651 +87 0.16667 0.25000 0.18125 0.00100 0.34374 -0.70421 0.17678 0.30619 +47 0.08333 0.25000 0.28254 0.00100 0.23215 -0.72379 0.30619 0.17678 +76 0.16667 0.16667 0.19643 0.00100 0.30813 -0.69579 0.12500 0.21651 +45 0.08333 0.16667 0.25662 0.00100 0.24258 -0.70570 0.21651 0.12500 +76 0.16667 0.16667 0.19643 0.00100 0.30813 -0.69579 0.12500 0.21651 +19 0.16667 0.08333 0.20078 0.00100 0.27261 -0.65958 0.06470 0.11207 +17 0.25000 0.08333 0.17478 0.00100 0.29109 -0.63431 0.00000 0.12941 +20 0.20833 0.00000 0.19898 0.00100 0.23912 -0.60440 0.00000 0.00000 +SURF 0x14 +mat 0 +refs 26 +39 0.25000 0.91667 0.13138 0.99900 0.26321 0.48188 0.00000 0.12941 +40 0.20833 1.00000 0.16417 0.99900 0.20895 0.45830 0.00000 0.00000 +39 0.25000 0.91667 0.13138 0.99900 0.26321 0.48188 0.00000 0.12941 +41 0.16667 0.91667 0.15686 0.99900 0.23923 0.50697 0.06470 0.11207 +163 0.25000 0.83333 0.09337 0.99900 0.32380 0.46306 0.00000 0.25000 +164 0.16667 0.83333 0.14064 0.99900 0.27287 0.52638 0.12500 0.21651 +152 0.25000 0.75000 0.05350 0.99900 0.38666 0.38881 0.00000 0.35355 +153 0.16667 0.75000 0.11005 0.99900 0.30883 0.49554 0.17678 0.30619 +141 0.25000 0.66667 0.01921 0.99900 0.44417 0.25077 0.00000 0.43301 +142 0.16667 0.66667 0.06221 0.99900 0.34565 0.37156 0.21651 0.37500 +130 0.25000 0.58333 0.00104 0.70147 0.48527 0.05732 0.00000 0.48296 +131 0.16667 0.58333 0.01707 0.75383 0.37997 0.09731 0.24148 0.41826 +119 0.25000 0.50000 0.00634 0.30861 0.50000 -0.15875 0.00000 0.50000 +120 0.16667 0.50000 0.02917 0.16155 0.40148 -0.27285 0.25000 0.43301 +108 0.25000 0.41667 0.03263 0.00100 0.48620 -0.35427 0.00000 0.48296 +109 0.16667 0.41667 0.09227 0.00100 0.39866 -0.54216 0.24148 0.41826 +97 0.25000 0.33333 0.07009 0.00100 0.45008 -0.50072 0.00000 0.43301 +98 0.16667 0.33333 0.14840 0.00100 0.37604 -0.66637 0.21651 0.37500 +86 0.25000 0.25000 0.10926 0.00100 0.40081 -0.59156 0.00000 0.35355 +87 0.16667 0.25000 0.18125 0.00100 0.34374 -0.70421 0.17678 0.30619 +75 0.25000 0.16667 0.14481 0.00100 0.34608 -0.63293 0.00000 0.25000 +76 0.16667 0.16667 0.19643 0.00100 0.30813 -0.69579 0.12500 0.21651 +75 0.25000 0.16667 0.14481 0.00100 0.34608 -0.63293 0.00000 0.25000 +17 0.25000 0.08333 0.17478 0.00100 0.29109 -0.63431 0.00000 0.12941 +15 0.33333 0.08333 0.15726 0.00100 0.29335 -0.59942 -0.06470 0.11207 +18 0.29167 0.00000 0.19898 0.00100 0.23912 -0.60440 0.00000 0.00000 +SURF 0x14 +mat 0 +refs 26 +37 0.33333 0.91667 0.11731 0.99900 0.26926 0.44859 -0.06470 0.11207 +38 0.29167 1.00000 0.16417 0.99900 0.20895 0.45830 0.00000 0.00000 +37 0.33333 0.91667 0.11731 0.99900 0.26926 0.44859 -0.06470 0.11207 +39 0.25000 0.91667 0.13138 0.99900 0.26321 0.48188 0.00000 0.12941 +162 0.33333 0.83333 0.07414 0.99900 0.32883 0.39669 -0.12500 0.21651 +163 0.25000 0.83333 0.09337 0.99900 0.32380 0.46306 0.00000 0.25000 +151 0.33333 0.75000 0.03873 0.99900 0.38213 0.30552 -0.17678 0.30619 +152 0.25000 0.75000 0.05350 0.99900 0.38666 0.38881 0.00000 0.35355 +140 0.33333 0.66667 0.01433 0.96962 0.42405 0.18283 -0.21651 0.37500 +141 0.25000 0.66667 0.01921 0.99900 0.44417 0.25077 0.00000 0.43301 +129 0.33333 0.58333 0.00283 0.67965 0.45074 0.03994 -0.24148 0.41826 +130 0.25000 0.58333 0.00104 0.70147 0.48527 0.05732 0.00000 0.48296 +118 0.33333 0.50000 0.00464 0.37108 0.46020 -0.11023 -0.25000 0.43301 +119 0.25000 0.50000 0.00634 0.30861 0.50000 -0.15875 0.00000 0.50000 +107 0.33333 0.41667 0.01889 0.06946 0.45233 -0.25504 -0.24148 0.41826 +108 0.25000 0.41667 0.03263 0.00100 0.48620 -0.35427 0.00000 0.48296 +96 0.33333 0.33333 0.04378 0.00100 0.42865 -0.38353 -0.21651 0.37500 +97 0.25000 0.33333 0.07009 0.00100 0.45008 -0.50072 0.00000 0.43301 +85 0.33333 0.25000 0.07694 0.00100 0.39190 -0.48717 -0.17678 0.30619 +86 0.25000 0.25000 0.10926 0.00100 0.40081 -0.59156 0.00000 0.35355 +74 0.33333 0.16667 0.11569 0.00100 0.34553 -0.56015 -0.12500 0.21651 +75 0.25000 0.16667 0.14481 0.00100 0.34608 -0.63293 0.00000 0.25000 +74 0.33333 0.16667 0.11569 0.00100 0.34553 -0.56015 -0.12500 0.21651 +15 0.33333 0.08333 0.15726 0.00100 0.29335 -0.59942 -0.06470 0.11207 +13 0.41667 0.08333 0.15134 0.00100 0.28069 -0.56690 -0.11207 0.06470 +16 0.37500 0.00000 0.19898 0.00100 0.23912 -0.60440 0.00000 0.00000 +SURF 0x14 +mat 0 +refs 26 +35 0.41667 0.91667 0.11568 0.99900 0.25826 0.41884 -0.11207 0.06470 +36 0.37500 1.00000 0.16417 0.99900 0.20895 0.45830 0.00000 0.00000 +35 0.41667 0.91667 0.11568 0.99900 0.25826 0.41884 -0.11207 0.06470 +37 0.33333 0.91667 0.11731 0.99900 0.26926 0.44859 -0.06470 0.11207 +161 0.41667 0.83333 0.07575 0.99900 0.30096 0.34871 -0.21651 0.12500 +162 0.33333 0.83333 0.07414 0.99900 0.32883 0.39669 -0.12500 0.21651 +150 0.41667 0.75000 0.04562 0.99900 0.33524 0.25608 -0.30619 0.17678 +151 0.33333 0.75000 0.03873 0.99900 0.38213 0.30552 -0.17678 0.30619 +139 0.41667 0.66667 0.02569 0.92724 0.36024 0.14834 -0.37500 0.21651 +140 0.33333 0.66667 0.01433 0.96962 0.42405 0.18283 -0.21651 0.37500 +128 0.41667 0.58333 0.01596 0.67063 0.37568 0.03187 -0.41826 0.24148 +129 0.33333 0.58333 0.00283 0.67965 0.45074 0.03994 -0.24148 0.41826 +117 0.41667 0.50000 0.01621 0.39994 0.38162 -0.08785 -0.43301 0.25000 +118 0.33333 0.50000 0.00464 0.37108 0.46020 -0.11023 -0.25000 0.43301 +106 0.41667 0.41667 0.02609 0.13144 0.37828 -0.20590 -0.41826 0.24148 +107 0.33333 0.41667 0.01889 0.06946 0.45233 -0.25504 -0.24148 0.41826 +95 0.41667 0.33333 0.04522 0.00100 0.36600 -0.31762 -0.37500 0.21651 +96 0.33333 0.33333 0.04378 0.00100 0.42865 -0.38353 -0.21651 0.37500 +84 0.41667 0.25000 0.07305 0.00100 0.34519 -0.41833 -0.30619 0.17678 +85 0.33333 0.25000 0.07694 0.00100 0.39190 -0.48717 -0.17678 0.30619 +73 0.41667 0.16667 0.10881 0.00100 0.31647 -0.50313 -0.21651 0.12500 +74 0.33333 0.16667 0.11569 0.00100 0.34553 -0.56015 -0.12500 0.21651 +73 0.41667 0.16667 0.10881 0.00100 0.31647 -0.50313 -0.21651 0.12500 +13 0.41667 0.08333 0.15134 0.00100 0.28069 -0.56690 -0.11207 0.06470 +11 0.50000 0.08333 0.15695 0.00100 0.25836 -0.54379 -0.12941 0.00000 +14 0.45833 0.00000 0.19898 0.00100 0.23912 -0.60440 0.00000 0.00000 +SURF 0x14 +mat 0 +refs 26 +33 0.50000 0.91667 0.12506 0.99900 0.23590 0.39836 -0.12941 0.00000 +34 0.45833 1.00000 0.16417 0.99900 0.20895 0.45830 0.00000 0.00000 +33 0.50000 0.91667 0.12506 0.99900 0.23590 0.39836 -0.12941 0.00000 +35 0.41667 0.91667 0.11568 0.99900 0.25826 0.41884 -0.11207 0.06470 +160 0.50000 0.83333 0.09377 0.99900 0.25637 0.32013 -0.25000 0.00000 +161 0.41667 0.83333 0.07575 0.99900 0.30096 0.34871 -0.21651 0.12500 +149 0.50000 0.75000 0.07035 0.99900 0.27148 0.22961 -0.35355 0.00000 +150 0.41667 0.75000 0.04562 0.99900 0.33524 0.25608 -0.30619 0.17678 +138 0.50000 0.66667 0.05477 0.90616 0.28211 0.13113 -0.43301 0.00000 +139 0.41667 0.66667 0.02569 0.92724 0.36024 0.14834 -0.37500 0.21651 +127 0.50000 0.58333 0.04697 0.66642 0.28889 0.02798 -0.48296 0.00000 +128 0.41667 0.58333 0.01596 0.67063 0.37568 0.03187 -0.41826 0.24148 +116 0.50000 0.50000 0.04685 0.41393 0.29223 -0.07709 -0.50000 0.00000 +117 0.41667 0.50000 0.01621 0.39994 0.38162 -0.08785 -0.43301 0.25000 +105 0.50000 0.41667 0.05433 0.16212 0.29232 -0.18164 -0.48296 0.00000 +106 0.41667 0.41667 0.02609 0.13144 0.37828 -0.20590 -0.41826 0.24148 +94 0.50000 0.33333 0.06929 0.00100 0.28922 -0.28327 -0.43301 0.00000 +95 0.41667 0.33333 0.04522 0.00100 0.36600 -0.31762 -0.37500 0.21651 +83 0.50000 0.25000 0.09157 0.00100 0.28277 -0.37947 -0.35355 0.00000 +84 0.41667 0.25000 0.07305 0.00100 0.34519 -0.41833 -0.30619 0.17678 +72 0.50000 0.16667 0.12093 0.00100 0.27266 -0.46743 -0.25000 0.00000 +73 0.41667 0.16667 0.10881 0.00100 0.31647 -0.50313 -0.21651 0.12500 +72 0.50000 0.16667 0.12093 0.00100 0.27266 -0.46743 -0.25000 0.00000 +11 0.50000 0.08333 0.15695 0.00100 0.25836 -0.54379 -0.12941 0.00000 +9 0.58333 0.08333 0.17221 0.00100 0.23253 -0.53297 -0.11207 -0.06470 +12 0.54167 0.00000 0.19898 0.00100 0.23912 -0.60440 0.00000 0.00000 +SURF 0x14 +mat 0 +refs 26 +31 0.58333 0.91667 0.14311 0.99900 0.20878 0.38894 -0.11207 -0.06470 +32 0.54167 1.00000 0.16417 0.99900 0.20895 0.45830 0.00000 0.00000 +31 0.58333 0.91667 0.14311 0.99900 0.20878 0.38894 -0.11207 -0.06470 +33 0.50000 0.91667 0.12506 0.99900 0.23590 0.39836 -0.12941 0.00000 +159 0.58333 0.83333 0.12527 0.99900 0.20699 0.30801 -0.21651 -0.12500 +160 0.50000 0.83333 0.09377 0.99900 0.25637 0.32013 -0.25000 0.00000 +148 0.58333 0.75000 0.11143 0.99900 0.20500 0.21899 -0.30619 -0.17678 +149 0.50000 0.75000 0.07035 0.99900 0.27148 0.22961 -0.35355 0.00000 +137 0.58333 0.66667 0.10210 0.89651 0.20368 0.12444 -0.37500 -0.21651 +138 0.50000 0.66667 0.05477 0.90616 0.28211 0.13113 -0.43301 0.00000 +126 0.58333 0.58333 0.09758 0.66389 0.20355 0.02650 -0.41826 -0.24148 +127 0.50000 0.58333 0.04697 0.66642 0.28889 0.02798 -0.48296 0.00000 +115 0.58333 0.50000 0.09802 0.41933 0.20491 -0.07299 -0.43301 -0.25000 +116 0.50000 0.50000 0.04685 0.41393 0.29223 -0.07709 -0.50000 0.00000 +104 0.58333 0.41667 0.10346 0.17498 0.20788 -0.17229 -0.41826 -0.24148 +105 0.50000 0.41667 0.05433 0.16212 0.29232 -0.18164 -0.48296 0.00000 +93 0.58333 0.33333 0.11385 0.00100 0.21242 -0.26969 -0.37500 -0.21651 +94 0.50000 0.33333 0.06929 0.00100 0.28922 -0.28327 -0.43301 0.00000 +82 0.58333 0.25000 0.12901 0.00100 0.21834 -0.36350 -0.30619 -0.17678 +83 0.50000 0.25000 0.09157 0.00100 0.28277 -0.37947 -0.35355 0.00000 +71 0.58333 0.16667 0.14863 0.00100 0.22526 -0.45191 -0.21651 -0.12500 +72 0.50000 0.16667 0.12093 0.00100 0.27266 -0.46743 -0.25000 0.00000 +71 0.58333 0.16667 0.14863 0.00100 0.22526 -0.45191 -0.21651 -0.12500 +9 0.58333 0.08333 0.17221 0.00100 0.23253 -0.53297 -0.11207 -0.06470 +7 0.66667 0.08333 0.19399 0.00100 0.20888 -0.53519 -0.06470 -0.11207 +10 0.62500 0.00000 0.19898 0.00100 0.23912 -0.60440 0.00000 0.00000 +SURF 0x14 +mat 0 +refs 26 +29 0.66667 0.91667 0.16656 0.99900 0.18279 0.39086 -0.06470 -0.11207 +30 0.62500 1.00000 0.16417 0.99900 0.20895 0.45830 0.00000 0.00000 +29 0.66667 0.91667 0.16656 0.99900 0.18279 0.39086 -0.06470 -0.11207 +31 0.58333 0.91667 0.14311 0.99900 0.20878 0.38894 -0.11207 -0.06470 +158 0.66667 0.83333 0.16659 0.99900 0.16130 0.31057 -0.12500 -0.21651 +159 0.58333 0.83333 0.12527 0.99900 0.20699 0.30801 -0.21651 -0.12500 +147 0.66667 0.75000 0.16588 0.99900 0.14487 0.22131 -0.17678 -0.30619 +148 0.58333 0.75000 0.11143 0.99900 0.20500 0.21899 -0.30619 -0.17678 +136 0.66667 0.66667 0.16546 0.89633 0.13378 0.12594 -0.21651 -0.37500 +137 0.58333 0.66667 0.10210 0.89651 0.20368 0.12444 -0.37500 -0.21651 +125 0.66667 0.58333 0.16597 0.66293 0.12819 0.02683 -0.24148 -0.41826 +126 0.58333 0.58333 0.09758 0.66389 0.20355 0.02650 -0.41826 -0.24148 +114 0.66667 0.50000 0.16776 0.41811 0.12818 -0.07393 -0.25000 -0.43301 +115 0.58333 0.50000 0.09802 0.41933 0.20491 -0.07299 -0.43301 -0.25000 +103 0.66667 0.41667 0.17097 0.17362 0.13376 -0.17442 -0.24148 -0.41826 +104 0.58333 0.41667 0.10346 0.17498 0.20788 -0.17229 -0.41826 -0.24148 +92 0.66667 0.33333 0.17556 0.00100 0.14484 -0.27274 -0.21651 -0.37500 +93 0.58333 0.33333 0.11385 0.00100 0.21242 -0.26969 -0.37500 -0.21651 +81 0.66667 0.25000 0.18129 0.00100 0.16125 -0.36700 -0.17678 -0.30619 +82 0.58333 0.25000 0.12901 0.00100 0.21834 -0.36350 -0.30619 -0.17678 +70 0.66667 0.16667 0.18769 0.00100 0.18273 -0.45521 -0.12500 -0.21651 +71 0.58333 0.16667 0.14863 0.00100 0.22526 -0.45191 -0.21651 -0.12500 +70 0.66667 0.16667 0.18769 0.00100 0.18273 -0.45521 -0.12500 -0.21651 +7 0.66667 0.08333 0.19399 0.00100 0.20888 -0.53519 -0.06470 -0.11207 +5 0.75000 0.08333 0.21789 0.00100 0.19222 -0.55023 0.00000 -0.12941 +8 0.70833 0.00000 0.19898 0.00100 0.23912 -0.60440 0.00000 0.00000 +SURF 0x14 +mat 0 +refs 26 +27 0.75000 0.91667 0.19095 0.99900 0.16283 0.40401 0.00000 -0.12941 +28 0.70833 1.00000 0.16417 0.99900 0.20895 0.45830 0.00000 0.00000 +27 0.75000 0.91667 0.19095 0.99900 0.16283 0.40401 0.00000 -0.12941 +29 0.66667 0.91667 0.16656 0.99900 0.18279 0.39086 -0.06470 -0.11207 +157 0.75000 0.83333 0.21201 0.99900 0.12561 0.32796 0.00000 -0.25000 +158 0.66667 0.83333 0.16659 0.99900 0.16130 0.31057 -0.12500 -0.21651 +146 0.75000 0.75000 0.22797 0.99900 0.09754 0.23688 0.00000 -0.35355 +147 0.66667 0.75000 0.16588 0.99900 0.14487 0.22131 -0.17678 -0.30619 +135 0.75000 0.66667 0.23948 0.90806 0.07868 0.13588 0.00000 -0.43301 +136 0.66667 0.66667 0.16546 0.89633 0.13378 0.12594 -0.21651 -0.37500 +124 0.75000 0.58333 0.24702 0.66503 0.06897 0.02906 0.00000 -0.48296 +125 0.66667 0.58333 0.16597 0.66293 0.12819 0.02683 -0.24148 -0.41826 +113 0.75000 0.50000 0.25094 0.41006 0.06830 -0.08009 0.00000 -0.50000 +114 0.66667 0.50000 0.16776 0.41811 0.12818 -0.07393 -0.25000 -0.43301 +102 0.75000 0.41667 0.25144 0.15617 0.07651 -0.18841 0.00000 -0.48296 +103 0.66667 0.41667 0.17097 0.17362 0.13376 -0.17442 -0.24148 -0.41826 +91 0.75000 0.33333 0.24857 0.00100 0.09338 -0.29285 0.00000 -0.43301 +92 0.66667 0.33333 0.17556 0.00100 0.14484 -0.27274 -0.21651 -0.37500 +80 0.75000 0.25000 0.24221 0.00100 0.11860 -0.39028 0.00000 -0.35355 +81 0.66667 0.25000 0.18129 0.00100 0.16125 -0.36700 -0.17678 -0.30619 +69 0.75000 0.16667 0.23212 0.00100 0.15175 -0.47734 0.00000 -0.25000 +70 0.66667 0.16667 0.18769 0.00100 0.18273 -0.45521 -0.12500 -0.21651 +69 0.75000 0.16667 0.23212 0.00100 0.15175 -0.47734 0.00000 -0.25000 +5 0.75000 0.08333 0.21789 0.00100 0.19222 -0.55023 0.00000 -0.12941 +3 0.83333 0.08333 0.23838 0.00100 0.18630 -0.57670 0.06470 -0.11207 +6 0.79167 0.00000 0.19898 0.00100 0.23912 -0.60440 0.00000 0.00000 +SURF 0x14 +mat 0 +refs 26 +25 0.83333 0.91667 0.21053 0.99900 0.15290 0.42768 0.06470 -0.11207 +26 0.79167 1.00000 0.16417 0.99900 0.20895 0.45830 0.00000 0.00000 +25 0.83333 0.91667 0.21053 0.99900 0.15290 0.42768 0.06470 -0.11207 +27 0.75000 0.91667 0.19095 0.99900 0.16283 0.40401 0.00000 -0.12941 +156 0.83333 0.83333 0.25271 0.99900 0.10497 0.36222 0.12500 -0.21651 +157 0.75000 0.83333 0.21201 0.99900 0.12561 0.32796 0.00000 -0.25000 +145 0.83333 0.75000 0.28799 0.99900 0.06767 0.26941 0.17678 -0.30619 +146 0.75000 0.75000 0.22797 0.99900 0.09754 0.23688 0.00000 -0.35355 +134 0.83333 0.66667 0.31457 0.93678 0.04237 0.15738 0.21651 -0.37500 +135 0.75000 0.66667 0.23948 0.90806 0.07868 0.13588 0.00000 -0.43301 +123 0.83333 0.58333 0.33150 0.67193 0.02955 0.03395 0.24148 -0.41826 +124 0.75000 0.58333 0.24702 0.66503 0.06897 0.02906 0.00000 -0.48296 +112 0.83333 0.50000 0.33844 0.39249 0.02914 -0.09363 0.25000 -0.43301 +113 0.75000 0.50000 0.25094 0.41006 0.06830 -0.08009 0.00000 -0.50000 +101 0.83333 0.41667 0.33549 0.11627 0.04068 -0.21875 0.24148 -0.41826 +102 0.75000 0.41667 0.25144 0.15617 0.07651 -0.18841 0.00000 -0.48296 +90 0.83333 0.33333 0.32310 0.00100 0.06342 -0.33527 0.21651 -0.37500 +91 0.75000 0.33333 0.24857 0.00100 0.09338 -0.29285 0.00000 -0.43301 +79 0.83333 0.25000 0.30202 0.00100 0.09629 -0.43738 0.17678 -0.30619 +80 0.75000 0.25000 0.24221 0.00100 0.11860 -0.39028 0.00000 -0.35355 +68 0.83333 0.16667 0.27332 0.00100 0.13788 -0.51956 0.12500 -0.21651 +69 0.75000 0.16667 0.23212 0.00100 0.15175 -0.47734 0.00000 -0.25000 +68 0.83333 0.16667 0.27332 0.00100 0.13788 -0.51956 0.12500 -0.21651 +3 0.83333 0.08333 0.23838 0.00100 0.18630 -0.57670 0.06470 -0.11207 +0 0.91667 0.08333 0.24936 0.00100 0.19351 -0.61071 0.11207 -0.06470 +4 0.87500 0.00000 0.19898 0.00100 0.23912 -0.60440 0.00000 0.00000 +SURF 0x14 +mat 0 +refs 26 +23 0.91667 0.91667 0.21882 0.99900 0.15617 0.45920 0.11207 -0.06470 +24 0.87500 1.00000 0.16417 0.99900 0.20895 0.45830 0.00000 0.00000 +23 0.91667 0.91667 0.21882 0.99900 0.15617 0.45920 0.11207 -0.06470 +25 0.83333 0.91667 0.21053 0.99900 0.15290 0.42768 0.06470 -0.11207 +154 0.91667 0.83333 0.27563 0.99900 0.10447 0.41577 0.21651 -0.12500 +156 0.83333 0.83333 0.25271 0.99900 0.10497 0.36222 0.12500 -0.21651 +143 0.91667 0.75000 0.32918 0.99900 0.05945 0.32703 0.30619 -0.17678 +145 0.83333 0.75000 0.28799 0.99900 0.06767 0.26941 0.17678 -0.30619 +132 0.91667 0.66667 0.37332 0.99232 0.02664 0.19879 0.37500 -0.21651 +134 0.83333 0.66667 0.31457 0.93678 0.04237 0.15738 0.21651 -0.37500 +121 0.91667 0.58333 0.40266 0.68601 0.01006 0.04379 0.41826 -0.24148 +123 0.83333 0.58333 0.33150 0.67193 0.02955 0.03395 0.24148 -0.41826 +110 0.91667 0.50000 0.41387 0.35730 0.01120 -0.12091 0.43301 -0.25000 +112 0.83333 0.50000 0.33844 0.39249 0.02914 -0.09363 0.25000 -0.43301 +99 0.91667 0.41667 0.40641 0.03864 0.02889 -0.27785 0.41826 -0.24148 +101 0.83333 0.41667 0.33549 0.11627 0.04068 -0.21875 0.24148 -0.41826 +88 0.91667 0.33333 0.38226 0.00100 0.06003 -0.41261 0.37500 -0.21651 +90 0.83333 0.33333 0.32310 0.00100 0.06342 -0.33527 0.21651 -0.37500 +77 0.91667 0.25000 0.34511 0.00100 0.10054 -0.51553 0.30619 -0.17678 +79 0.83333 0.25000 0.30202 0.00100 0.09629 -0.43738 0.17678 -0.30619 +66 0.91667 0.16667 0.29935 0.00100 0.14628 -0.58181 0.21651 -0.12500 +68 0.83333 0.16667 0.27332 0.00100 0.13788 -0.51956 0.12500 -0.21651 +66 0.91667 0.16667 0.29935 0.00100 0.14628 -0.58181 0.21651 -0.12500 +0 0.91667 0.08333 0.24936 0.00100 0.19351 -0.61071 0.11207 -0.06470 +2 1.00000 0.08333 0.24596 0.00100 0.21392 -0.64381 0.12941 0.00000 +1 0.95833 0.00000 0.19898 0.00100 0.23912 -0.60440 0.00000 0.00000 +SURF 0x14 +mat 0 +refs 23 +66 0.91667 0.16667 0.29935 0.00100 0.14628 -0.58181 0.21651 -0.12500 +2 1.00000 0.08333 0.24596 0.00100 0.21392 -0.64381 0.12941 0.00000 +66 0.91667 0.16667 0.29935 0.00100 0.14628 -0.58181 0.21651 -0.12500 +67 1.00000 0.16667 0.29617 0.00100 0.18165 -0.65455 0.25000 0.00000 +77 0.91667 0.25000 0.34511 0.00100 0.10054 -0.51553 0.30619 -0.17678 +78 1.00000 0.25000 0.34675 0.00100 0.14154 -0.62617 0.35355 0.00000 +88 0.91667 0.33333 0.38226 0.00100 0.06003 -0.41261 0.37500 -0.21651 +89 1.00000 0.33333 0.39286 0.00100 0.09463 -0.54477 0.43301 0.00000 +99 0.91667 0.41667 0.40641 0.03864 0.02889 -0.27785 0.41826 -0.24148 +100 1.00000 0.41667 0.42672 0.00100 0.04684 -0.39635 0.48296 0.00000 +110 0.91667 0.50000 0.41387 0.35730 0.01120 -0.12091 0.43301 -0.25000 +111 1.00000 0.50000 0.43819 0.27990 0.01216 -0.18101 0.50000 0.00000 +121 0.91667 0.58333 0.40266 0.68601 0.01006 0.04379 0.41826 -0.24148 +122 1.00000 0.58333 0.42036 0.71453 0.00746 0.06528 0.48296 0.00000 +132 0.91667 0.66667 0.37332 0.99232 0.02664 0.19879 0.37500 -0.21651 +133 1.00000 0.66667 0.37732 0.99900 0.03584 0.27934 0.43301 0.00000 +143 0.91667 0.75000 0.32918 0.99900 0.05945 0.32703 0.30619 -0.17678 +144 1.00000 0.75000 0.32156 0.99900 0.08264 0.41936 0.35355 0.00000 +154 0.91667 0.83333 0.27563 0.99900 0.10447 0.41577 0.21651 -0.12500 +155 1.00000 0.83333 0.26409 0.99900 0.13155 0.48413 0.25000 0.00000 +23 0.91667 0.91667 0.21882 0.99900 0.15617 0.45920 0.11207 -0.06470 +21 1.00000 0.91667 0.21082 0.99900 0.17434 0.49121 0.12941 0.00000 +22 0.95833 1.00000 0.16417 0.99900 0.20895 0.45830 0.00000 0.00000 +kids 0 diff --git a/test/unit/utACImportExport.cpp b/test/unit/utACImportExport.cpp index c844603cf..ee22f44f8 100644 --- a/test/unit/utACImportExport.cpp +++ b/test/unit/utACImportExport.cpp @@ -99,6 +99,12 @@ TEST(utACImportExport, importSphereWithLight) { ASSERT_NE(nullptr, scene); } +TEST(utACImportExport, importSphereWithLightACC) { + Assimp::Importer importer; + const aiScene *scene = importer.ReadFile(ASSIMP_TEST_MODELS_DIR "/AC/SphereWithLight.acc", aiProcess_ValidateDataStructure); + ASSERT_NE(nullptr, scene); +} + TEST(utACImportExport, importSphereWithLightUTF16) { Assimp::Importer importer; const aiScene *scene = importer.ReadFile(ASSIMP_TEST_MODELS_DIR "/AC/SphereWithLight_UTF16LE.ac", aiProcess_ValidateDataStructure); From ac29847d5679c243d7649fe8a5d5e48f0f57c297 Mon Sep 17 00:00:00 2001 From: Stephen Gold Date: Sun, 3 Dec 2023 16:11:54 -0800 Subject: [PATCH 21/77] Readme.md: present the web links in a more uniform style --- Readme.md | 15 ++++++++------- 1 file changed, 8 insertions(+), 7 deletions(-) diff --git a/Readme.md b/Readme.md index a1f707a95..eae0cf00a 100644 --- a/Readme.md +++ b/Readme.md @@ -16,26 +16,27 @@ APIs are provided for C and C++. There are various bindings to other languages ( Additionally, assimp features various __mesh post-processing tools__: normals and tangent space generation, triangulation, vertex cache locality optimization, removal of degenerate primitives and duplicate vertices, sorting by primitive type, merging of redundant materials and many more. ### Documentation ### -Please check the latest documents at [Asset-Importer-Lib-Doc](https://assimp-docs.readthedocs.io/en/latest/). +Read [our latest documentation](https://assimp-docs.readthedocs.io/en/latest/). ### Pre-built binaries ### -Please check our [Itchi Projectspace](https://kimkulling.itch.io/the-asset-importer-lib) +Download binaries from [our Itchi Projectspace](https://kimkulling.itch.io/the-asset-importer-lib). -If you want to check our Model-Database, use the following repo: https://github.com/assimp/assimp-mdb +### Test data ### +Clone [our model database](https://github.com/assimp/assimp-mdb). ### Communities ### -- Ask a question at [The Assimp-Discussion Board](https://github.com/assimp/assimp/discussions) -- Ask on [Assimp-Community on Reddit](https://www.reddit.com/r/Assimp/) +- Ask questions at [the Assimp Discussion Board](https://github.com/assimp/assimp/discussions). +- Ask [the Assimp community on Reddit](https://www.reddit.com/r/Assimp/). - Ask on [StackOverflow with the assimp-tag](http://stackoverflow.com/questions/tagged/assimp?sort=newest). - Nothing has worked? File a question or an issue-report at [The Assimp-Issue Tracker](https://github.com/assimp/assimp/issues) And we also have a Gitter-channel:Gitter [![Join the chat at https://gitter.im/assimp/assimp](https://badges.gitter.im/assimp/assimp.svg)](https://gitter.im/assimp/assimp?utm_source=badge&utm_medium=badge&utm_campaign=pr-badge&utm_content=badge)
    #### Supported file formats #### -You can find the complete list of supported file-formats [here](https://github.com/assimp/assimp/blob/master/doc/Fileformats.md) +See [the complete list of supported formats](https://github.com/assimp/assimp/blob/master/doc/Fileformats.md). ### Building ### -Take a look [here](https://github.com/assimp/assimp/blob/master/Build.md) to get started. We are available in vcpkg, and our build system is CMake; if you used CMake before there is a good chance you know what to do. +Start by reading [our build instructions](https://github.com/assimp/assimp/blob/master/Build.md). We are available in vcpkg, and our build system is CMake; if you used CMake before there is a good chance you know what to do. ### Ports ### * [Android](port/AndroidJNI/README.md) From bdc08dd4a9031f75034f2c7db225b8ea34d90b43 Mon Sep 17 00:00:00 2001 From: julianknodt Date: Thu, 25 Jan 2024 15:50:03 -0800 Subject: [PATCH 22/77] Encode full weight as double --- code/AssetLib/FBX/FBXExporter.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/code/AssetLib/FBX/FBXExporter.cpp b/code/AssetLib/FBX/FBXExporter.cpp index 28299544a..873179f4c 100644 --- a/code/AssetLib/FBX/FBXExporter.cpp +++ b/code/AssetLib/FBX/FBXExporter.cpp @@ -1807,7 +1807,7 @@ void FBXExporter::WriteObjects () p.AddP70numberA("DeformPercent", 0.0); sdnode.AddChild(p); // TODO: Normally just one weight per channel, adding stub for later development - std::vectorfFullWeights; + std::vectorfFullWeights; fFullWeights.push_back(100.); sdnode.AddChild("FullWeights", fFullWeights); sdnode.Dump(outstream, binary, indent); From 727001b0cab8b2d06ed6b6bfa99a3a19a450d0c8 Mon Sep 17 00:00:00 2001 From: seanth Date: Tue, 16 Jan 2024 21:43:12 -0600 Subject: [PATCH 23/77] Update DXFLoader.cpp Edited out line suspected to be causing changes in position when changes in scale are made to inserted BLOCKS --- code/AssetLib/DXF/DXFLoader.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/code/AssetLib/DXF/DXFLoader.cpp b/code/AssetLib/DXF/DXFLoader.cpp index f69cdfce2..161a91826 100644 --- a/code/AssetLib/DXF/DXFLoader.cpp +++ b/code/AssetLib/DXF/DXFLoader.cpp @@ -373,7 +373,7 @@ void DXFImporter::ExpandBlockReferences(DXF::Block& bl,const DXF::BlockMap& bloc aiMatrix4x4 trafo, tmp; aiMatrix4x4::Translation(-bl_src.base,trafo); trafo *= aiMatrix4x4::Scaling(insert.scale,tmp); - trafo *= aiMatrix4x4::Translation(insert.pos,tmp); + //trafo *= aiMatrix4x4::Translation(insert.pos,tmp); // XXX rotation currently ignored - I didn't find an appropriate sample model. if (insert.angle != 0.f) { From 240fa97fed0247cd778dcbf0ad161cc16f1728f9 Mon Sep 17 00:00:00 2001 From: seanth Date: Wed, 17 Jan 2024 07:38:48 -0600 Subject: [PATCH 24/77] Update DXFLoader.cpp Changed order of operations for insert positioning and scaling. Need to position the inserts before scaling it, otherwise the position ends up up being position*scale --- code/AssetLib/DXF/DXFLoader.cpp | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/code/AssetLib/DXF/DXFLoader.cpp b/code/AssetLib/DXF/DXFLoader.cpp index 161a91826..0979b44a6 100644 --- a/code/AssetLib/DXF/DXFLoader.cpp +++ b/code/AssetLib/DXF/DXFLoader.cpp @@ -372,6 +372,10 @@ void DXFImporter::ExpandBlockReferences(DXF::Block& bl,const DXF::BlockMap& bloc // XXX order aiMatrix4x4 trafo, tmp; aiMatrix4x4::Translation(-bl_src.base,trafo); + //Need to translate position before scaling the insert + //otherwise the position ends up being the position*scaling + //STH 2024.01.17 + trafo *= aiMatrix4x4::Translation(insert.pos,tmp); trafo *= aiMatrix4x4::Scaling(insert.scale,tmp); //trafo *= aiMatrix4x4::Translation(insert.pos,tmp); From 8cde65bfe8934240ed398be03c23d82222c6b3f5 Mon Sep 17 00:00:00 2001 From: seanth Date: Fri, 26 Jan 2024 15:53:45 -0600 Subject: [PATCH 25/77] Updated AIC table The previous table was in an incorrect order, leading to index references in DXF producing the wrong colours when converted. Also added other entries to bring the total number of ACI colours up to the number that can be used in DXF files --- code/AssetLib/DXF/DXFLoader.cpp | 278 +++++++++++++++++++++++++++++--- 1 file changed, 260 insertions(+), 18 deletions(-) diff --git a/code/AssetLib/DXF/DXFLoader.cpp b/code/AssetLib/DXF/DXFLoader.cpp index 0979b44a6..833fdf6cb 100644 --- a/code/AssetLib/DXF/DXFLoader.cpp +++ b/code/AssetLib/DXF/DXFLoader.cpp @@ -68,25 +68,267 @@ static constexpr size_t AI_DXF_BINARY_IDENT_LEN = sizeof AI_DXF_BINARY_IDENT; // default vertex color that all uncolored vertices will receive static const aiColor4D AI_DXF_DEFAULT_COLOR(aiColor4D(0.6f, 0.6f, 0.6f, 0.6f)); -// color indices for DXF - 16 are supported, the table is -// taken directly from the DXF spec. +// color indices for DXF - 256 are supported, the table is +// taken directly from the AutoCad Index (ACI) table +// https://gohtx.com/acadcolors.php +//STH 2024-0126 static const aiColor4D g_aclrDxfIndexColors[] = { - aiColor4D(0.6f, 0.6f, 0.6f, 1.0f), - aiColor4D (1.0f, 0.0f, 0.0f, 1.0f), // red - aiColor4D (0.0f, 1.0f, 0.0f, 1.0f), // green - aiColor4D (0.0f, 0.0f, 1.0f, 1.0f), // blue - aiColor4D (0.3f, 1.0f, 0.3f, 1.0f), // light green - aiColor4D (0.3f, 0.3f, 1.0f, 1.0f), // light blue - aiColor4D (1.0f, 0.3f, 0.3f, 1.0f), // light red - aiColor4D (1.0f, 0.0f, 1.0f, 1.0f), // pink - aiColor4D (1.0f, 0.6f, 0.0f, 1.0f), // orange - aiColor4D (0.6f, 0.3f, 0.0f, 1.0f), // dark orange - aiColor4D (1.0f, 1.0f, 0.0f, 1.0f), // yellow - aiColor4D (0.3f, 0.3f, 0.3f, 1.0f), // dark gray - aiColor4D (0.8f, 0.8f, 0.8f, 1.0f), // light gray - aiColor4D (0.0f, 00.f, 0.0f, 1.0f), // black - aiColor4D (1.0f, 1.0f, 1.0f, 1.0f), // white - aiColor4D (0.6f, 0.0f, 1.0f, 1.0f) // violet + aiColor4D (0.0f, 0.0f ,0.0f, 1.0f), //dxf color code 0 + aiColor4D (1.0f, 0.0f ,0.0f, 1.0f), //dxf color code 1 + aiColor4D (1.0f, 1.0f ,0.0f, 1.0f), //dxf color code 2 + aiColor4D (0.0f, 1.0f ,0.0f, 1.0f), //dxf color code 3 + aiColor4D (0.0f, 1.0f ,1.0f, 1.0f), //dxf color code 4 + aiColor4D (0.0f, 0.0f ,1.0f, 1.0f), //dxf color code 5 + aiColor4D (1.0f, 0.0f ,1.0f, 1.0f), //dxf color code 6 + aiColor4D (1.0f, 1.0f ,1.0f, 1.0f), //dxf color code 7 + aiColor4D (0.3f, 0.3f ,0.3f, 1.0f), //dxf color code 8 + aiColor4D (0.5f, 0.5f ,0.5f, 1.0f), //dxf color code 9 + aiColor4D (1.0f, 0.0f ,0.0f, 1.0f), //dxf color code 10 + aiColor4D (1.0f, 0.7f ,0.7f, 1.0f), //dxf color code 11 + aiColor4D (0.7f, 0.0f ,0.0f, 1.0f), //dxf color code 12 + aiColor4D (0.7f, 0.5f ,0.5f, 1.0f), //dxf color code 13 + aiColor4D (0.5f, 0.0f ,0.0f, 1.0f), //dxf color code 14 + aiColor4D (0.5f, 0.3f ,0.3f, 1.0f), //dxf color code 15 + aiColor4D (0.4f, 0.0f ,0.0f, 1.0f), //dxf color code 16 + aiColor4D (0.4f, 0.3f ,0.3f, 1.0f), //dxf color code 17 + aiColor4D (0.3f, 0.0f ,0.0f, 1.0f), //dxf color code 18 + aiColor4D (0.3f, 0.2f ,0.2f, 1.0f), //dxf color code 19 + aiColor4D (1.0f, 0.2f ,0.0f, 1.0f), //dxf color code 20 + aiColor4D (1.0f, 0.7f ,0.7f, 1.0f), //dxf color code 21 + aiColor4D (0.7f, 0.2f ,0.0f, 1.0f), //dxf color code 22 + aiColor4D (0.7f, 0.6f ,0.5f, 1.0f), //dxf color code 23 + aiColor4D (0.5f, 0.1f ,0.0f, 1.0f), //dxf color code 24 + aiColor4D (0.5f, 0.4f ,0.3f, 1.0f), //dxf color code 25 + aiColor4D (0.4f, 0.1f ,0.0f, 1.0f), //dxf color code 26 + aiColor4D (0.4f, 0.3f ,0.3f, 1.0f), //dxf color code 27 + aiColor4D (0.3f, 0.1f ,0.0f, 1.0f), //dxf color code 28 + aiColor4D (0.3f, 0.2f ,0.2f, 1.0f), //dxf color code 29 + aiColor4D (1.0f, 0.5f ,0.0f, 1.0f), //dxf color code 30 + aiColor4D (1.0f, 0.8f ,0.7f, 1.0f), //dxf color code 31 + aiColor4D (0.7f, 0.4f ,0.0f, 1.0f), //dxf color code 32 + aiColor4D (0.7f, 0.6f ,0.5f, 1.0f), //dxf color code 33 + aiColor4D (0.5f, 0.3f ,0.0f, 1.0f), //dxf color code 34 + aiColor4D (0.5f, 0.4f ,0.3f, 1.0f), //dxf color code 35 + aiColor4D (0.4f, 0.2f ,0.0f, 1.0f), //dxf color code 36 + aiColor4D (0.4f, 0.3f ,0.3f, 1.0f), //dxf color code 37 + aiColor4D (0.3f, 0.2f ,0.0f, 1.0f), //dxf color code 38 + aiColor4D (0.3f, 0.3f ,0.2f, 1.0f), //dxf color code 39 + aiColor4D (1.0f, 0.7f ,0.0f, 1.0f), //dxf color code 40 + aiColor4D (1.0f, 0.9f ,0.7f, 1.0f), //dxf color code 41 + aiColor4D (0.7f, 0.6f ,0.0f, 1.0f), //dxf color code 42 + aiColor4D (0.7f, 0.7f ,0.5f, 1.0f), //dxf color code 43 + aiColor4D (0.5f, 0.4f ,0.0f, 1.0f), //dxf color code 44 + aiColor4D (0.5f, 0.5f ,0.3f, 1.0f), //dxf color code 45 + aiColor4D (0.4f, 0.3f ,0.0f, 1.0f), //dxf color code 46 + aiColor4D (0.4f, 0.4f ,0.3f, 1.0f), //dxf color code 47 + aiColor4D (0.3f, 0.2f ,0.0f, 1.0f), //dxf color code 48 + aiColor4D (0.3f, 0.3f ,0.2f, 1.0f), //dxf color code 49 + aiColor4D (1.0f, 1.0f ,0.0f, 1.0f), //dxf color code 50 + aiColor4D (1.0f, 1.0f ,0.7f, 1.0f), //dxf color code 51 + aiColor4D (0.7f, 0.7f ,0.0f, 1.0f), //dxf color code 52 + aiColor4D (0.7f, 0.7f ,0.5f, 1.0f), //dxf color code 53 + aiColor4D (0.5f, 0.5f ,0.0f, 1.0f), //dxf color code 54 + aiColor4D (0.5f, 0.5f ,0.3f, 1.0f), //dxf color code 55 + aiColor4D (0.4f, 0.4f ,0.0f, 1.0f), //dxf color code 56 + aiColor4D (0.4f, 0.4f ,0.3f, 1.0f), //dxf color code 57 + aiColor4D (0.3f, 0.3f ,0.0f, 1.0f), //dxf color code 58 + aiColor4D (0.3f, 0.3f ,0.2f, 1.0f), //dxf color code 59 + aiColor4D (0.7f, 1.0f ,0.0f, 1.0f), //dxf color code 60 + aiColor4D (0.9f, 1.0f ,0.7f, 1.0f), //dxf color code 61 + aiColor4D (0.6f, 0.7f ,0.0f, 1.0f), //dxf color code 62 + aiColor4D (0.7f, 0.7f ,0.5f, 1.0f), //dxf color code 63 + aiColor4D (0.4f, 0.5f ,0.0f, 1.0f), //dxf color code 64 + aiColor4D (0.5f, 0.5f ,0.3f, 1.0f), //dxf color code 65 + aiColor4D (0.3f, 0.4f ,0.0f, 1.0f), //dxf color code 66 + aiColor4D (0.4f, 0.4f ,0.3f, 1.0f), //dxf color code 67 + aiColor4D (0.2f, 0.3f ,0.0f, 1.0f), //dxf color code 68 + aiColor4D (0.3f, 0.3f ,0.2f, 1.0f), //dxf color code 69 + aiColor4D (0.5f, 1.0f ,0.0f, 1.0f), //dxf color code 70 + aiColor4D (0.8f, 1.0f ,0.7f, 1.0f), //dxf color code 71 + aiColor4D (0.4f, 0.7f ,0.0f, 1.0f), //dxf color code 72 + aiColor4D (0.6f, 0.7f ,0.5f, 1.0f), //dxf color code 73 + aiColor4D (0.3f, 0.5f ,0.0f, 1.0f), //dxf color code 74 + aiColor4D (0.4f, 0.5f ,0.3f, 1.0f), //dxf color code 75 + aiColor4D (0.2f, 0.4f ,0.0f, 1.0f), //dxf color code 76 + aiColor4D (0.3f, 0.4f ,0.3f, 1.0f), //dxf color code 77 + aiColor4D (0.2f, 0.3f ,0.0f, 1.0f), //dxf color code 78 + aiColor4D (0.3f, 0.3f ,0.2f, 1.0f), //dxf color code 79 + aiColor4D (0.2f, 1.0f ,0.0f, 1.0f), //dxf color code 80 + aiColor4D (0.7f, 1.0f ,0.7f, 1.0f), //dxf color code 81 + aiColor4D (0.2f, 0.7f ,0.0f, 1.0f), //dxf color code 82 + aiColor4D (0.6f, 0.7f ,0.5f, 1.0f), //dxf color code 83 + aiColor4D (0.1f, 0.5f ,0.0f, 1.0f), //dxf color code 84 + aiColor4D (0.4f, 0.5f ,0.3f, 1.0f), //dxf color code 85 + aiColor4D (0.1f, 0.4f ,0.0f, 1.0f), //dxf color code 86 + aiColor4D (0.3f, 0.4f ,0.3f, 1.0f), //dxf color code 87 + aiColor4D (0.1f, 0.3f ,0.0f, 1.0f), //dxf color code 88 + aiColor4D (0.2f, 0.3f ,0.2f, 1.0f), //dxf color code 89 + aiColor4D (0.0f, 1.0f ,0.0f, 1.0f), //dxf color code 90 + aiColor4D (0.7f, 1.0f ,0.7f, 1.0f), //dxf color code 91 + aiColor4D (0.0f, 0.7f ,0.0f, 1.0f), //dxf color code 92 + aiColor4D (0.5f, 0.7f ,0.5f, 1.0f), //dxf color code 93 + aiColor4D (0.0f, 0.5f ,0.0f, 1.0f), //dxf color code 94 + aiColor4D (0.3f, 0.5f ,0.3f, 1.0f), //dxf color code 95 + aiColor4D (0.0f, 0.4f ,0.0f, 1.0f), //dxf color code 96 + aiColor4D (0.3f, 0.4f ,0.3f, 1.0f), //dxf color code 97 + aiColor4D (0.0f, 0.3f ,0.0f, 1.0f), //dxf color code 98 + aiColor4D (0.2f, 0.3f ,0.2f, 1.0f), //dxf color code 99 + aiColor4D (0.0f, 1.0f ,0.2f, 1.0f), //dxf color code 100 + aiColor4D (0.7f, 1.0f ,0.7f, 1.0f), //dxf color code 101 + aiColor4D (0.0f, 0.7f ,0.2f, 1.0f), //dxf color code 102 + aiColor4D (0.5f, 0.7f ,0.6f, 1.0f), //dxf color code 103 + aiColor4D (0.0f, 0.5f ,0.1f, 1.0f), //dxf color code 104 + aiColor4D (0.3f, 0.5f ,0.4f, 1.0f), //dxf color code 105 + aiColor4D (0.0f, 0.4f ,0.1f, 1.0f), //dxf color code 106 + aiColor4D (0.3f, 0.4f ,0.3f, 1.0f), //dxf color code 107 + aiColor4D (0.0f, 0.3f ,0.1f, 1.0f), //dxf color code 108 + aiColor4D (0.2f, 0.3f ,0.2f, 1.0f), //dxf color code 109 + aiColor4D (0.0f, 1.0f ,0.5f, 1.0f), //dxf color code 110 + aiColor4D (0.7f, 1.0f ,0.8f, 1.0f), //dxf color code 111 + aiColor4D (0.0f, 0.7f ,0.4f, 1.0f), //dxf color code 112 + aiColor4D (0.5f, 0.7f ,0.6f, 1.0f), //dxf color code 113 + aiColor4D (0.0f, 0.5f ,0.3f, 1.0f), //dxf color code 114 + aiColor4D (0.3f, 0.5f ,0.4f, 1.0f), //dxf color code 115 + aiColor4D (0.0f, 0.4f ,0.2f, 1.0f), //dxf color code 116 + aiColor4D (0.3f, 0.4f ,0.3f, 1.0f), //dxf color code 117 + aiColor4D (0.0f, 0.3f ,0.2f, 1.0f), //dxf color code 118 + aiColor4D (0.2f, 0.3f ,0.3f, 1.0f), //dxf color code 119 + aiColor4D (0.0f, 1.0f ,0.7f, 1.0f), //dxf color code 120 + aiColor4D (0.7f, 1.0f ,0.9f, 1.0f), //dxf color code 121 + aiColor4D (0.0f, 0.7f ,0.6f, 1.0f), //dxf color code 122 + aiColor4D (0.5f, 0.7f ,0.7f, 1.0f), //dxf color code 123 + aiColor4D (0.0f, 0.5f ,0.4f, 1.0f), //dxf color code 124 + aiColor4D (0.3f, 0.5f ,0.5f, 1.0f), //dxf color code 125 + aiColor4D (0.0f, 0.4f ,0.3f, 1.0f), //dxf color code 126 + aiColor4D (0.3f, 0.4f ,0.4f, 1.0f), //dxf color code 127 + aiColor4D (0.0f, 0.3f ,0.2f, 1.0f), //dxf color code 128 + aiColor4D (0.2f, 0.3f ,0.3f, 1.0f), //dxf color code 129 + aiColor4D (0.0f, 1.0f ,1.0f, 1.0f), //dxf color code 130 + aiColor4D (0.7f, 1.0f ,1.0f, 1.0f), //dxf color code 131 + aiColor4D (0.0f, 0.7f ,0.7f, 1.0f), //dxf color code 132 + aiColor4D (0.5f, 0.7f ,0.7f, 1.0f), //dxf color code 133 + aiColor4D (0.0f, 0.5f ,0.5f, 1.0f), //dxf color code 134 + aiColor4D (0.3f, 0.5f ,0.5f, 1.0f), //dxf color code 135 + aiColor4D (0.0f, 0.4f ,0.4f, 1.0f), //dxf color code 136 + aiColor4D (0.3f, 0.4f ,0.4f, 1.0f), //dxf color code 137 + aiColor4D (0.0f, 0.3f ,0.3f, 1.0f), //dxf color code 138 + aiColor4D (0.2f, 0.3f ,0.3f, 1.0f), //dxf color code 139 + aiColor4D (0.0f, 0.7f ,1.0f, 1.0f), //dxf color code 140 + aiColor4D (0.7f, 0.9f ,1.0f, 1.0f), //dxf color code 141 + aiColor4D (0.0f, 0.6f ,0.7f, 1.0f), //dxf color code 142 + aiColor4D (0.5f, 0.7f ,0.7f, 1.0f), //dxf color code 143 + aiColor4D (0.0f, 0.4f ,0.5f, 1.0f), //dxf color code 144 + aiColor4D (0.3f, 0.5f ,0.5f, 1.0f), //dxf color code 145 + aiColor4D (0.0f, 0.3f ,0.4f, 1.0f), //dxf color code 146 + aiColor4D (0.3f, 0.4f ,0.4f, 1.0f), //dxf color code 147 + aiColor4D (0.0f, 0.2f ,0.3f, 1.0f), //dxf color code 148 + aiColor4D (0.2f, 0.3f ,0.3f, 1.0f), //dxf color code 149 + aiColor4D (0.0f, 0.5f ,1.0f, 1.0f), //dxf color code 150 + aiColor4D (0.7f, 0.8f ,1.0f, 1.0f), //dxf color code 151 + aiColor4D (0.0f, 0.4f ,0.7f, 1.0f), //dxf color code 152 + aiColor4D (0.5f, 0.6f ,0.7f, 1.0f), //dxf color code 153 + aiColor4D (0.0f, 0.3f ,0.5f, 1.0f), //dxf color code 154 + aiColor4D (0.3f, 0.4f ,0.5f, 1.0f), //dxf color code 155 + aiColor4D (0.0f, 0.2f ,0.4f, 1.0f), //dxf color code 156 + aiColor4D (0.3f, 0.3f ,0.4f, 1.0f), //dxf color code 157 + aiColor4D (0.0f, 0.2f ,0.3f, 1.0f), //dxf color code 158 + aiColor4D (0.2f, 0.3f ,0.3f, 1.0f), //dxf color code 159 + aiColor4D (0.0f, 0.2f ,1.0f, 1.0f), //dxf color code 160 + aiColor4D (0.7f, 0.7f ,1.0f, 1.0f), //dxf color code 161 + aiColor4D (0.0f, 0.2f ,0.7f, 1.0f), //dxf color code 162 + aiColor4D (0.5f, 0.6f ,0.7f, 1.0f), //dxf color code 163 + aiColor4D (0.0f, 0.1f ,0.5f, 1.0f), //dxf color code 164 + aiColor4D (0.3f, 0.4f ,0.5f, 1.0f), //dxf color code 165 + aiColor4D (0.0f, 0.1f ,0.4f, 1.0f), //dxf color code 166 + aiColor4D (0.3f, 0.3f ,0.4f, 1.0f), //dxf color code 167 + aiColor4D (0.0f, 0.1f ,0.3f, 1.0f), //dxf color code 168 + aiColor4D (0.2f, 0.2f ,0.3f, 1.0f), //dxf color code 169 + aiColor4D (0.0f, 0.0f ,1.0f, 1.0f), //dxf color code 170 + aiColor4D (0.7f, 0.7f ,1.0f, 1.0f), //dxf color code 171 + aiColor4D (0.0f, 0.0f ,0.7f, 1.0f), //dxf color code 172 + aiColor4D (0.5f, 0.5f ,0.7f, 1.0f), //dxf color code 173 + aiColor4D (0.0f, 0.0f ,0.5f, 1.0f), //dxf color code 174 + aiColor4D (0.3f, 0.3f ,0.5f, 1.0f), //dxf color code 175 + aiColor4D (0.0f, 0.0f ,0.4f, 1.0f), //dxf color code 176 + aiColor4D (0.3f, 0.3f ,0.4f, 1.0f), //dxf color code 177 + aiColor4D (0.0f, 0.0f ,0.3f, 1.0f), //dxf color code 178 + aiColor4D (0.2f, 0.2f ,0.3f, 1.0f), //dxf color code 179 + aiColor4D (0.2f, 0.0f ,1.0f, 1.0f), //dxf color code 180 + aiColor4D (0.7f, 0.7f ,1.0f, 1.0f), //dxf color code 181 + aiColor4D (0.2f, 0.0f ,0.7f, 1.0f), //dxf color code 182 + aiColor4D (0.6f, 0.5f ,0.7f, 1.0f), //dxf color code 183 + aiColor4D (0.1f, 0.0f ,0.5f, 1.0f), //dxf color code 184 + aiColor4D (0.4f, 0.3f ,0.5f, 1.0f), //dxf color code 185 + aiColor4D (0.1f, 0.0f ,0.4f, 1.0f), //dxf color code 186 + aiColor4D (0.3f, 0.3f ,0.4f, 1.0f), //dxf color code 187 + aiColor4D (0.1f, 0.0f ,0.3f, 1.0f), //dxf color code 188 + aiColor4D (0.2f, 0.2f ,0.3f, 1.0f), //dxf color code 189 + aiColor4D (0.5f, 0.0f ,1.0f, 1.0f), //dxf color code 190 + aiColor4D (0.8f, 0.7f ,1.0f, 1.0f), //dxf color code 191 + aiColor4D (0.4f, 0.0f ,0.7f, 1.0f), //dxf color code 192 + aiColor4D (0.6f, 0.5f ,0.7f, 1.0f), //dxf color code 193 + aiColor4D (0.3f, 0.0f ,0.5f, 1.0f), //dxf color code 194 + aiColor4D (0.4f, 0.3f ,0.5f, 1.0f), //dxf color code 195 + aiColor4D (0.2f, 0.0f ,0.4f, 1.0f), //dxf color code 196 + aiColor4D (0.3f, 0.3f ,0.4f, 1.0f), //dxf color code 197 + aiColor4D (0.2f, 0.0f ,0.3f, 1.0f), //dxf color code 198 + aiColor4D (0.3f, 0.2f ,0.3f, 1.0f), //dxf color code 199 + aiColor4D (0.7f, 0.0f ,1.0f, 1.0f), //dxf color code 200 + aiColor4D (0.9f, 0.7f ,1.0f, 1.0f), //dxf color code 201 + aiColor4D (0.6f, 0.0f ,0.7f, 1.0f), //dxf color code 202 + aiColor4D (0.7f, 0.5f ,0.7f, 1.0f), //dxf color code 203 + aiColor4D (0.4f, 0.0f ,0.5f, 1.0f), //dxf color code 204 + aiColor4D (0.5f, 0.3f ,0.5f, 1.0f), //dxf color code 205 + aiColor4D (0.3f, 0.0f ,0.4f, 1.0f), //dxf color code 206 + aiColor4D (0.4f, 0.3f ,0.4f, 1.0f), //dxf color code 207 + aiColor4D (0.2f, 0.0f ,0.3f, 1.0f), //dxf color code 208 + aiColor4D (0.3f, 0.2f ,0.3f, 1.0f), //dxf color code 209 + aiColor4D (1.0f, 0.0f ,1.0f, 1.0f), //dxf color code 210 + aiColor4D (1.0f, 0.7f ,1.0f, 1.0f), //dxf color code 211 + aiColor4D (0.7f, 0.0f ,0.7f, 1.0f), //dxf color code 212 + aiColor4D (0.7f, 0.5f ,0.7f, 1.0f), //dxf color code 213 + aiColor4D (0.5f, 0.0f ,0.5f, 1.0f), //dxf color code 214 + aiColor4D (0.5f, 0.3f ,0.5f, 1.0f), //dxf color code 215 + aiColor4D (0.4f, 0.0f ,0.4f, 1.0f), //dxf color code 216 + aiColor4D (0.4f, 0.3f ,0.4f, 1.0f), //dxf color code 217 + aiColor4D (0.3f, 0.0f ,0.3f, 1.0f), //dxf color code 218 + aiColor4D (0.3f, 0.2f ,0.3f, 1.0f), //dxf color code 219 + aiColor4D (1.0f, 0.0f ,0.7f, 1.0f), //dxf color code 220 + aiColor4D (1.0f, 0.7f ,0.9f, 1.0f), //dxf color code 221 + aiColor4D (0.7f, 0.0f ,0.6f, 1.0f), //dxf color code 222 + aiColor4D (0.7f, 0.5f ,0.7f, 1.0f), //dxf color code 223 + aiColor4D (0.5f, 0.0f ,0.4f, 1.0f), //dxf color code 224 + aiColor4D (0.5f, 0.3f ,0.5f, 1.0f), //dxf color code 225 + aiColor4D (0.4f, 0.0f ,0.3f, 1.0f), //dxf color code 226 + aiColor4D (0.4f, 0.3f ,0.4f, 1.0f), //dxf color code 227 + aiColor4D (0.3f, 0.0f ,0.2f, 1.0f), //dxf color code 228 + aiColor4D (0.3f, 0.2f ,0.3f, 1.0f), //dxf color code 229 + aiColor4D (1.0f, 0.0f ,0.5f, 1.0f), //dxf color code 230 + aiColor4D (1.0f, 0.7f ,0.8f, 1.0f), //dxf color code 231 + aiColor4D (0.7f, 0.0f ,0.4f, 1.0f), //dxf color code 232 + aiColor4D (0.7f, 0.5f ,0.6f, 1.0f), //dxf color code 233 + aiColor4D (0.5f, 0.0f ,0.3f, 1.0f), //dxf color code 234 + aiColor4D (0.5f, 0.3f ,0.4f, 1.0f), //dxf color code 235 + aiColor4D (0.4f, 0.0f ,0.2f, 1.0f), //dxf color code 236 + aiColor4D (0.4f, 0.3f ,0.3f, 1.0f), //dxf color code 237 + aiColor4D (0.3f, 0.0f ,0.2f, 1.0f), //dxf color code 238 + aiColor4D (0.3f, 0.2f ,0.3f, 1.0f), //dxf color code 239 + aiColor4D (1.0f, 0.0f ,0.2f, 1.0f), //dxf color code 240 + aiColor4D (1.0f, 0.7f ,0.7f, 1.0f), //dxf color code 241 + aiColor4D (0.7f, 0.0f ,0.2f, 1.0f), //dxf color code 242 + aiColor4D (0.7f, 0.5f ,0.6f, 1.0f), //dxf color code 243 + aiColor4D (0.5f, 0.0f ,0.1f, 1.0f), //dxf color code 244 + aiColor4D (0.5f, 0.3f ,0.4f, 1.0f), //dxf color code 245 + aiColor4D (0.4f, 0.0f ,0.1f, 1.0f), //dxf color code 246 + aiColor4D (0.4f, 0.3f ,0.3f, 1.0f), //dxf color code 247 + aiColor4D (0.3f, 0.0f ,0.1f, 1.0f), //dxf color code 248 + aiColor4D (0.3f, 0.2f ,0.2f, 1.0f), //dxf color code 249 + aiColor4D (0.2f, 0.2f ,0.2f, 1.0f), //dxf color code 250 + aiColor4D (0.3f, 0.3f ,0.3f, 1.0f), //dxf color code 251 + aiColor4D (0.4f, 0.4f ,0.4f, 1.0f), //dxf color code 252 + aiColor4D (0.5f, 0.5f ,0.5f, 1.0f), //dxf color code 253 + aiColor4D (0.7f, 0.7f ,0.7f, 1.0f), //dxf color code 254 + aiColor4D (1.0f, 1.0f ,1.0f, 1.0f) //dxf color code 255 }; #define AI_DXF_NUM_INDEX_COLORS (sizeof(g_aclrDxfIndexColors)/sizeof(g_aclrDxfIndexColors[0])) From c6fe03f7a5ff53ac050ba1fd979bc106b6eb54bb Mon Sep 17 00:00:00 2001 From: Kim Kulling Date: Sat, 27 Jan 2024 11:13:48 +0100 Subject: [PATCH 26/77] Update DXFLoader.cpp - Use constexpr instead of const. --- code/AssetLib/DXF/DXFLoader.cpp | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/code/AssetLib/DXF/DXFLoader.cpp b/code/AssetLib/DXF/DXFLoader.cpp index 833fdf6cb..db9dfdf96 100644 --- a/code/AssetLib/DXF/DXFLoader.cpp +++ b/code/AssetLib/DXF/DXFLoader.cpp @@ -3,7 +3,7 @@ Open Asset Import Library (assimp) --------------------------------------------------------------------------- -Copyright (c) 2006-2022, assimp team +Copyright (c) 2006-2024, assimp team All rights reserved. @@ -43,7 +43,6 @@ OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. * @brief Implementation of the DXF importer class */ - #ifndef ASSIMP_BUILD_NO_DXF_IMPORTER #include "AssetLib/DXF/DXFLoader.h" @@ -72,7 +71,7 @@ static const aiColor4D AI_DXF_DEFAULT_COLOR(aiColor4D(0.6f, 0.6f, 0.6f, 0.6f)); // taken directly from the AutoCad Index (ACI) table // https://gohtx.com/acadcolors.php //STH 2024-0126 -static const aiColor4D g_aclrDxfIndexColors[] = { +static constexpr aiColor4D g_aclrDxfIndexColors[256] = { aiColor4D (0.0f, 0.0f ,0.0f, 1.0f), //dxf color code 0 aiColor4D (1.0f, 0.0f ,0.0f, 1.0f), //dxf color code 1 aiColor4D (1.0f, 1.0f ,0.0f, 1.0f), //dxf color code 2 From a8d30f7e91503fe4d230446c48f75c3636011a42 Mon Sep 17 00:00:00 2001 From: Kim Kulling Date: Sat, 27 Jan 2024 11:18:42 +0100 Subject: [PATCH 27/77] Update DXFLoader.cpp revert it --- code/AssetLib/DXF/DXFLoader.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/code/AssetLib/DXF/DXFLoader.cpp b/code/AssetLib/DXF/DXFLoader.cpp index db9dfdf96..0f3da2626 100644 --- a/code/AssetLib/DXF/DXFLoader.cpp +++ b/code/AssetLib/DXF/DXFLoader.cpp @@ -71,7 +71,7 @@ static const aiColor4D AI_DXF_DEFAULT_COLOR(aiColor4D(0.6f, 0.6f, 0.6f, 0.6f)); // taken directly from the AutoCad Index (ACI) table // https://gohtx.com/acadcolors.php //STH 2024-0126 -static constexpr aiColor4D g_aclrDxfIndexColors[256] = { +static const aiColor4D g_aclrDxfIndexColors[256] = { aiColor4D (0.0f, 0.0f ,0.0f, 1.0f), //dxf color code 0 aiColor4D (1.0f, 0.0f ,0.0f, 1.0f), //dxf color code 1 aiColor4D (1.0f, 1.0f ,0.0f, 1.0f), //dxf color code 2 From a02085ea9836c2ac151c44675c4c96646a35802c Mon Sep 17 00:00:00 2001 From: tigertang Date: Fri, 26 Jan 2024 00:24:21 +0800 Subject: [PATCH 28/77] Update StbCommon.h to stay up-to-date with stb_image.h. This enables C++ API users to statically link Assimp into their projects along with stb_image. --- code/Common/StbCommon.h | 18 ++++++++++-------- 1 file changed, 10 insertions(+), 8 deletions(-) diff --git a/code/Common/StbCommon.h b/code/Common/StbCommon.h index 5de2e176d..91f8e424a 100644 --- a/code/Common/StbCommon.h +++ b/code/Common/StbCommon.h @@ -64,10 +64,11 @@ OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. The list can be regenerated using the following: - cat | fgrep STBIDEF | fgrep '(' | sed -E 's/\*|\(.+//g' | \ - awk '{print "#define " $(NF) " assimp_" $(NF) }' | sort | uniq" + cat "path/to/stb/stb_image.h" | fgrep STBIDEF | fgrep '(' | sed -E 's/\*|\(.+//g' | \ + awk '{print "#define " $(NF) " assimp_" $(NF) }' | sort | uniq */ #define stbi_convert_iphone_png_to_rgb assimp_stbi_convert_iphone_png_to_rgb +#define stbi_convert_iphone_png_to_rgb_thread assimp_stbi_convert_iphone_png_to_rgb_thread #define stbi_convert_wchar_to_utf8 assimp_stbi_convert_wchar_to_utf8 #define stbi_failure_reason assimp_stbi_failure_reason #define stbi_hdr_to_ldr_gamma assimp_stbi_hdr_to_ldr_gamma @@ -87,22 +88,23 @@ OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. #define stbi_is_hdr_from_memory assimp_stbi_is_hdr_from_memory #define stbi_ldr_to_hdr_gamma assimp_stbi_ldr_to_hdr_gamma #define stbi_ldr_to_hdr_scale assimp_stbi_ldr_to_hdr_scale +#define stbi_load assimp_stbi_load #define stbi_load_16 assimp_stbi_load_16 #define stbi_load_16_from_callbacks assimp_stbi_load_16_from_callbacks #define stbi_load_16_from_memory assimp_stbi_load_16_from_memory -#define stbi_load assimp_stbi_load +#define stbi_load_from_callbacks assimp_stbi_load_from_callbacks +#define stbi_load_from_file assimp_stbi_load_from_file +#define stbi_load_from_file_16 assimp_stbi_load_from_file_16 +#define stbi_load_from_memory assimp_stbi_load_from_memory +#define stbi_load_gif_from_memory assimp_stbi_load_gif_from_memory #define stbi_loadf assimp_stbi_loadf #define stbi_loadf_from_callbacks assimp_stbi_loadf_from_callbacks #define stbi_loadf_from_file assimp_stbi_loadf_from_file #define stbi_loadf_from_memory assimp_stbi_loadf_from_memory -#define stbi_load_from_callbacks assimp_stbi_load_from_callbacks -#define stbi_load_from_file_16 assimp_stbi_load_from_file_16 -#define stbi_load_from_file assimp_stbi_load_from_file -#define stbi_load_from_memory assimp_stbi_load_from_memory -#define stbi_load_gif_from_memory assimp_stbi_load_gif_from_memory #define stbi_set_flip_vertically_on_load assimp_stbi_set_flip_vertically_on_load #define stbi_set_flip_vertically_on_load_thread assimp_stbi_set_flip_vertically_on_load_thread #define stbi_set_unpremultiply_on_load assimp_stbi_set_unpremultiply_on_load +#define stbi_set_unpremultiply_on_load_thread assimp_stbi_set_unpremultiply_on_load_thread #define stbi_zlib_decode_buffer assimp_stbi_zlib_decode_buffer #define stbi_zlib_decode_malloc assimp_stbi_zlib_decode_malloc #define stbi_zlib_decode_malloc_guesssize assimp_stbi_zlib_decode_malloc_guesssize From d5f35582d4044362be507b83b76ed0b7822c071a Mon Sep 17 00:00:00 2001 From: Kim Kulling Date: Tue, 30 Jan 2024 10:35:22 +0100 Subject: [PATCH 29/77] Introduce aiBuffer We have a lot of parsing tools which are not doing any kind of bound checking. This is the first approach to solve these issues. --- include/assimp/types.h | 19 ++++++++++++++++++- 1 file changed, 18 insertions(+), 1 deletion(-) diff --git a/include/assimp/types.h b/include/assimp/types.h index 42aa0f9eb..ea72dd996 100644 --- a/include/assimp/types.h +++ b/include/assimp/types.h @@ -3,7 +3,7 @@ Open Asset Import Library (assimp) --------------------------------------------------------------------------- -Copyright (c) 2006-2022, assimp team +Copyright (c) 2006-2024, assimp team All rights reserved. @@ -523,6 +523,23 @@ struct aiMemoryInfo { unsigned int total; }; // !struct aiMemoryInfo +/** + * @brief Type to store a in-memory data buffer. + */ +struct aiBuffer { + const char *data; ///< Begin poiner + const char *end; ///< End pointer + +#ifdef __cplusplus + /// @brief The class constructor. + aiBuffer() : + data(nullptr), end(nullptr) {} + + /// @brief The class destructor. + ~aiBuffer() = default; +#endif //! __cplusplus +}; + #ifdef __cplusplus } #endif //! __cplusplus From c08e3b4abbc2707bd22096fffeec35325e33aafa Mon Sep 17 00:00:00 2001 From: Kim Kulling Date: Tue, 30 Jan 2024 14:32:41 +0100 Subject: [PATCH 30/77] 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. --- code/AssetLib/AC/ACLoader.cpp | 191 ++++++++--------- code/AssetLib/AC/ACLoader.h | 4 +- code/AssetLib/ASE/ASEParser.cpp | 61 +++--- code/AssetLib/ASE/ASEParser.h | 3 + code/AssetLib/COB/COBLoader.cpp | 38 ++-- code/AssetLib/COB/COBLoader.h | 2 +- code/AssetLib/CSM/CSMLoader.cpp | 77 +++---- code/AssetLib/Collada/ColladaParser.cpp | 68 +++--- code/AssetLib/Irr/IRRMeshLoader.cpp | 70 +++--- code/AssetLib/Irr/IRRMeshLoader.h | 2 +- code/AssetLib/Irr/IRRShared.cpp | 12 +- code/AssetLib/LWO/LWOBLoader.cpp | 2 +- code/AssetLib/LWS/LWSLoader.cpp | 157 +++++++------- code/AssetLib/LWS/LWSLoader.h | 2 +- code/AssetLib/MD3/MD3Loader.cpp | 32 +-- code/AssetLib/MD5/MD5Loader.cpp | 16 +- code/AssetLib/MD5/MD5Loader.h | 6 +- code/AssetLib/MD5/MD5Parser.cpp | 222 +++++++++++--------- code/AssetLib/MD5/MD5Parser.h | 60 +++--- code/AssetLib/NFF/NFFLoader.cpp | 67 +++--- code/AssetLib/OFF/OFFLoader.cpp | 33 +-- code/AssetLib/Obj/ObjFileParser.cpp | 19 +- code/AssetLib/Obj/ObjFileParser.h | 13 +- code/AssetLib/Ply/PlyLoader.cpp | 5 +- code/AssetLib/Ply/PlyParser.cpp | 61 +++--- code/AssetLib/Ply/PlyParser.h | 4 +- code/AssetLib/Raw/RawLoader.cpp | 9 +- code/AssetLib/SMD/SMDLoader.cpp | 144 ++++++------- code/AssetLib/SMD/SMDLoader.h | 39 ++-- code/AssetLib/STEPParser/STEPFileReader.cpp | 59 +++--- code/AssetLib/STEPParser/STEPFileReader.h | 3 +- code/AssetLib/STL/STLLoader.cpp | 24 +-- code/AssetLib/Step/STEPFile.h | 32 ++- code/AssetLib/Unreal/UnrealLoader.cpp | 15 +- code/AssetLib/XGL/XGLLoader.cpp | 22 +- code/CMakeLists.txt | 4 + code/PostProcessing/ProcessHelper.cpp | 5 +- include/assimp/LineSplitter.h | 18 +- include/assimp/ParsingUtils.h | 34 +-- 39 files changed, 853 insertions(+), 782 deletions(-) diff --git a/code/AssetLib/AC/ACLoader.cpp b/code/AssetLib/AC/ACLoader.cpp index f98a4d105..cd3fe8c3a 100644 --- a/code/AssetLib/AC/ACLoader.cpp +++ b/code/AssetLib/AC/ACLoader.cpp @@ -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 -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(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 &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 &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 &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 &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 &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 &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((*it).entries.size()); + needMat[idx].second += static_cast((*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((*it).entries.size() - 1); + needMat[idx].second += static_cast(((*it).entries.size() - 1) << 1u); break; // triangle strip @@ -763,17 +755,18 @@ void AC3DImporter::InternReadFile(const std::string &pFile, std::vector 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(""); } @@ -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 *)); } diff --git a/code/AssetLib/AC/ACLoader.h b/code/AssetLib/AC/ACLoader.h index 3b5be4b6e..22f7d0d09 100644 --- a/code/AssetLib/AC/ACLoader.h +++ b/code/AssetLib/AC/ACLoader.h @@ -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 diff --git a/code/AssetLib/ASE/ASEParser.cpp b/code/AssetLib/ASE/ASEParser.cpp index 90f462598..3b515def7 100644 --- a/code/AssetLib/ASE/ASEParser.cpp +++ b/code/AssetLib/ASE/ASEParser.cpp @@ -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 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(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; diff --git a/code/AssetLib/ASE/ASEParser.h b/code/AssetLib/ASE/ASEParser.h index c41cd59d3..fa7c6d3c5 100644 --- a/code/AssetLib/ASE/ASEParser.h +++ b/code/AssetLib/ASE/ASEParser.h @@ -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; diff --git a/code/AssetLib/COB/COBLoader.cpp b/code/AssetLib/COB/COBLoader.cpp index 9a6e32f6d..3b7ae5525 100644 --- a/code/AssetLib/COB/COBLoader.cpp +++ b/code/AssetLib/COB/COBLoader.cpp @@ -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 -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++) { diff --git a/code/AssetLib/COB/COBLoader.h b/code/AssetLib/COB/COBLoader.h index a9755f5d7..cc124f533 100644 --- a/code/AssetLib/COB/COBLoader.h +++ b/code/AssetLib/COB/COBLoader.h @@ -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 - 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); diff --git a/code/AssetLib/CSM/CSMLoader.cpp b/code/AssetLib/CSM/CSMLoader.cpp index 20f2343f5..a8513cb3d 100644 --- a/code/AssetLib/CSM/CSMLoader.cpp +++ b/code/AssetLib/CSM/CSMLoader.cpp @@ -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 mBuffer2; TextFileToBuffer(file.get(),mBuffer2); const char* buffer = &mBuffer2[0]; - + const char *end = &mBuffer2[mBuffer2.size() - 1] + 1; std::unique_ptr 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(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(ot-nda->mNodeName.data); } anim->mNumChannels = static_cast(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(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(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(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(); diff --git a/code/AssetLib/Collada/ColladaParser.cpp b/code/AssetLib/Collada/ColladaParser.cpp index 42a8d6052..ee7a395d9 100644 --- a/code/AssetLib/Collada/ColladaParser.cpp +++ b/code/AssetLib/Collada/ColladaParser.cpp @@ -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(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 data 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::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>::iterator it = pController.mWeights.begin(); it != pController.mWeights.end(); ++it) { if (text == nullptr) { throw DeadlyImportError("Out of data while reading "); } - 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 "); } 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(content, (ai_real &)pLight.mColor.r); - SkipSpacesAndLineEnd(&content); + SkipSpacesAndLineEnd(&content, end); content = fast_atoreal_move(content, (ai_real &)pLight.mColor.g); - SkipSpacesAndLineEnd(&content); + SkipSpacesAndLineEnd(&content, end); content = fast_atoreal_move(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(content, (ai_real &)pColor.r); - SkipSpacesAndLineEnd(&content); + SkipSpacesAndLineEnd(&content, end); content = fast_atoreal_move(content, (ai_real &)pColor.g); - SkipSpacesAndLineEnd(&content); + SkipSpacesAndLineEnd(&content, end); content = fast_atoreal_move(content, (ai_real &)pColor.b); - SkipSpacesAndLineEnd(&content); + SkipSpacesAndLineEnd(&content, end); content = fast_atoreal_move(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 ¤tNode : node.children()) { const std::string ¤tName = 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(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 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, but only one primitive per

    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

    '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(content, tf.f[a]); } diff --git a/code/AssetLib/Irr/IRRMeshLoader.cpp b/code/AssetLib/Irr/IRRMeshLoader.cpp index b35a95c12..639b4fff9 100644 --- a/code/AssetLib/Irr/IRRMeshLoader.cpp +++ b/code/AssetLib/Irr/IRRMeshLoader.cpp @@ -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 &vertices, std::vector &normals, std::vector &tangents, std::vector &bitangents, std::vector &UVs, std::vector &UV2s, std::vector &colors, bool &useColors) { // read vertices do { - SkipSpacesAndLineEnd(&sz); + SkipSpacesAndLineEnd(&sz, end); aiVector3D temp; aiColor4D c; // Read the vertex position sz = fast_atoreal_move(sz, (float &)temp.x); - SkipSpaces(&sz); + SkipSpaces(&sz, end); sz = fast_atoreal_move(sz, (float &)temp.y); - SkipSpaces(&sz); + SkipSpaces(&sz, end); sz = fast_atoreal_move(sz, (float &)temp.z); - SkipSpaces(&sz); + SkipSpaces(&sz, end); vertices.push_back(temp); // Read the vertex normals sz = fast_atoreal_move(sz, (float &)temp.x); - SkipSpaces(&sz); + SkipSpaces(&sz, end); sz = fast_atoreal_move(sz, (float &)temp.y); - SkipSpaces(&sz); + SkipSpaces(&sz, end); sz = fast_atoreal_move(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(sz, (float &)temp.x); - SkipSpaces(&sz); + SkipSpaces(&sz, end); sz = fast_atoreal_move(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(sz, (float &)temp.x); - SkipSpaces(&sz); + SkipSpaces(&sz, end); sz = fast_atoreal_move(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(sz, (float &)temp.x); - SkipSpaces(&sz); + SkipSpaces(&sz, end); sz = fast_atoreal_move(sz, (float &)temp.z); - SkipSpaces(&sz); + SkipSpaces(&sz, end); sz = fast_atoreal_move(sz, (float &)temp.y); - SkipSpaces(&sz); + SkipSpaces(&sz, end); temp.y *= -1.0f; tangents.push_back(temp); // bitangents sz = fast_atoreal_move(sz, (float &)temp.x); - SkipSpaces(&sz); + SkipSpaces(&sz, end); sz = fast_atoreal_move(sz, (float &)temp.z); - SkipSpaces(&sz); + SkipSpaces(&sz, end); sz = fast_atoreal_move(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 diff --git a/code/AssetLib/Irr/IRRMeshLoader.h b/code/AssetLib/Irr/IRRMeshLoader.h index 620e40dba..9ec5c983d 100644 --- a/code/AssetLib/Irr/IRRMeshLoader.h +++ b/code/AssetLib/Irr/IRRMeshLoader.h @@ -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 &vertices, std::vector &normals, std::vector &tangents, std::vector &bitangents, std::vector &UVs, std::vector &UV2s, diff --git a/code/AssetLib/Irr/IRRShared.cpp b/code/AssetLib/Irr/IRRShared.cpp index a47aeccba..9ab8d0899 100644 --- a/code/AssetLib/Irr/IRRShared.cpp +++ b/code/AssetLib/Irr/IRRShared.cpp @@ -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(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(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(ptr, (float &)out.value.z); } diff --git a/code/AssetLib/LWO/LWOBLoader.cpp b/code/AssetLib/LWO/LWOBLoader.cpp index 4a9792b79..fc9132d88 100644 --- a/code/AssetLib/LWO/LWOBLoader.cpp +++ b/code/AssetLib/LWO/LWOBLoader.cpp @@ -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) { diff --git a/code/AssetLib/LWS/LWSLoader.cpp b/code/AssetLib/LWS/LWSLoader.cpp index dec834495..bf6e9ee31 100644 --- a/code/AssetLib/LWS/LWSLoader.cpp +++ b/code/AssetLib/LWS/LWSLoader.cpp @@ -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(c, key.value); - SkipSpaces(&c); + SkipSpaces(&c, end); c = fast_atoreal_move(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(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::const_iterator &it, - const std::list::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::const_iterator &it,const std::list::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((*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((*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(c, (float &)nodes.back().lightColor.r); - SkipSpaces(&c); + SkipSpaces(&c, end); c = fast_atoreal_move(c, (float &)nodes.back().lightColor.g); - SkipSpaces(&c); + SkipSpaces(&c, end); c = fast_atoreal_move(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(c, (float &)nodes.back().pivotPos.x); - SkipSpaces(&c); + SkipSpaces(&c, end); c = fast_atoreal_move(c, (float &)nodes.back().pivotPos.y); - SkipSpaces(&c); + SkipSpaces(&c, end); c = fast_atoreal_move(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::iterator ndIt = nodes.begin(); ndIt != nodes.end(); ++ndIt) { - // check whether there is another node which calls us a parent for (std::list::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; diff --git a/code/AssetLib/LWS/LWSLoader.h b/code/AssetLib/LWS/LWSLoader.h index 4e92ef0d5..5db6852c1 100644 --- a/code/AssetLib/LWS/LWSLoader.h +++ b/code/AssetLib/LWS/LWSLoader.h @@ -76,7 +76,7 @@ public: std::list children; //! Recursive parsing function - void Parse(const char *&buffer); + void Parse(const char *&buffer, const char *end); }; #define AI_LWS_MASK (0xffffffff >> 4u) diff --git a/code/AssetLib/MD3/MD3Loader.cpp b/code/AssetLib/MD3/MD3Loader.cpp index e743889e3..e4179d05d 100644 --- a/code/AssetLib/MD3/MD3Loader.cpp +++ b/code/AssetLib/MD3/MD3Loader.cpp @@ -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 _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) diff --git a/code/AssetLib/MD5/MD5Loader.cpp b/code/AssetLib/MD5/MD5Loader.cpp index 697e758fb..d4cdc0c44 100644 --- a/code/AssetLib/MD5/MD5Loader.cpp +++ b/code/AssetLib/MD5/MD5Loader.cpp @@ -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()) { diff --git a/code/AssetLib/MD5/MD5Loader.h b/code/AssetLib/MD5/MD5Loader.h index c213c04e6..d64d6f5b8 100644 --- a/code/AssetLib/MD5/MD5Loader.h +++ b/code/AssetLib/MD5/MD5Loader.h @@ -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 diff --git a/code/AssetLib/MD5/MD5Parser.cpp b/code/AssetLib/MD5/MD5Parser.cpp index 8da30e28f..24882af7e 100644 --- a/code/AssetLib/MD5/MD5Parser.cpp +++ b/code/AssetLib/MD5/MD5Parser.cpp @@ -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(sz, (float &)vec.x); \ - AI_MD5_SKIP_SPACES(); \ - sz = fast_atoreal_move(sz, (float &)vec.y); \ - AI_MD5_SKIP_SPACES(); \ - sz = fast_atoreal_move(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(*sz, (float &)vec.x); + AI_MD5_SKIP_SPACES(sz, bufferEnd, linenumber); + *sz = fast_atoreal_move(*sz, (float &)vec.y); + AI_MD5_SKIP_SPACES(sz, bufferEnd, linenumber); + *sz = fast_atoreal_move(*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(sz, (float &)vert.mUV.x); - AI_MD5_SKIP_SPACES(); + AI_MD5_SKIP_SPACES(&sz, elem.end, elem.iLineNumber); sz = fast_atoreal_move(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(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(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); } } diff --git a/code/AssetLib/MD5/MD5Parser.h b/code/AssetLib/MD5/MD5Parser.h index 9b29fbe85..75e3c22f2 100644 --- a/code/AssetLib/MD5/MD5Parser.h +++ b/code/AssetLib/MD5/MD5Parser.h @@ -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; +using ElementArray = std::vector; // --------------------------------------------------------------------------- /** 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

    ; +using SectionArray = std::vector
    ; // --------------------------------------------------------------------------- /** Basic information about a joint @@ -132,7 +134,7 @@ struct BoneDesc : BaseJointDescription { unsigned int mMap; }; -using BoneList = std::vector; +using BoneArray = std::vector; // --------------------------------------------------------------------------- /** 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; +using BaseFrameArray = std::vector; // --------------------------------------------------------------------------- /** Represents a camera animation frame in a MDCamera file @@ -164,7 +166,7 @@ struct CameraAnimFrameDesc : BaseFrameDesc { float fFOV; }; -using CameraFrameList = std::vector; +using CameraFrameArray = std::vector; // --------------------------------------------------------------------------- /** Represents a frame descriptor in a MD5Anim file @@ -177,7 +179,7 @@ struct FrameDesc { std::vector< float > mValues; }; -using FrameList = std::vector; +using FrameArray = std::vector; // --------------------------------------------------------------------------- /** Represents a vertex descriptor in a MD5 file @@ -199,7 +201,7 @@ struct VertexDesc { unsigned int mNumWeights; }; -using VertexList = std::vector; +using VertexArray = std::vector; // --------------------------------------------------------------------------- /** Represents a vertex weight descriptor in a MD5 file @@ -216,27 +218,27 @@ struct WeightDesc { aiVector3D vOffsetPosition; }; -using WeightList = std::vector; -using FaceList = std::vector; +using WeightArray = std::vector; +using FaceArray = std::vector; // --------------------------------------------------------------------------- /** 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; +using MeshArray = std::vector; // --------------------------------------------------------------------------- // 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 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 diff --git a/code/AssetLib/NFF/NFFLoader.cpp b/code/AssetLib/NFF/NFFLoader.cpp index 78adc27bd..6191d6def 100644 --- a/code/AssetLib/NFF/NFFLoader.cpp +++ b/code/AssetLib/NFF/NFFLoader.cpp @@ -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(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 &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 &output, // ------------------------------------------------------------------------------------------------ // Imports the given file into the given scene structure. -void NFFImporter::InternReadFile(const std::string &pFile, - aiScene *pScene, IOSystem *pIOHandler) { - std::unique_ptr 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 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 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 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); } diff --git a/code/AssetLib/OFF/OFFLoader.cpp b/code/AssetLib/OFF/OFFLoader.cpp index ce8dfc2d4..37fc2d31a 100644 --- a/code/AssetLib/OFF/OFFLoader.cpp +++ b/code/AssetLib/OFF/OFFLoader.cpp @@ -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(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(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(sz, (ai_real &)n.x); - SkipSpaces(&sz); + SkipSpaces(&sz, lineEnd); sz = fast_atoreal_move(sz, (ai_real &)n.y); - SkipSpaces(&sz); + SkipSpaces(&sz, lineEnd); fast_atoreal_move(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(sz, (ai_real &)c.r); if (*sz != '#' && *sz != '\n' && *sz != '\r') { - SkipSpaces(&sz); + SkipSpaces(&sz, lineEnd); sz = fast_atoreal_move(sz, (ai_real &)c.g); } else { c.g = 0.; } if (*sz != '#' && *sz != '\n' && *sz != '\r') { - SkipSpaces(&sz); + SkipSpaces(&sz, lineEnd); sz = fast_atoreal_move(sz, (ai_real &)c.b); } else { c.b = 0.; } if (*sz != '#' && *sz != '\n' && *sz != '\r') { - SkipSpaces(&sz); + SkipSpaces(&sz, lineEnd); sz = fast_atoreal_move(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(sz, (ai_real &)t.x); - SkipSpaces(&sz); + SkipSpaces(&sz, lineEnd); fast_atoreal_move(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"); diff --git a/code/AssetLib/Obj/ObjFileParser.cpp b/code/AssetLib/Obj/ObjFileParser.cpp index acb3f074c..9f5522ed2 100644 --- a/code/AssetLib/Obj/ObjFileParser.cpp +++ b/code/AssetLib/Obj/ObjFileParser.cpp @@ -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 &streamBuffer, const std::stri parseFile(streamBuffer); } -ObjFileParser::~ObjFileParser() = default; - void ObjFileParser::setBuffer(std::vector &buffer) { m_DataIt = buffer.begin(); m_DataItEnd = buffer.end(); @@ -121,6 +120,7 @@ void ObjFileParser::parseFile(IOStreamBuffer &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 &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 diff --git a/code/AssetLib/Obj/ObjFileParser.h b/code/AssetLib/Obj/ObjFileParser.h index 0ed724461..f3e149838 100644 --- a/code/AssetLib/Obj/ObjFileParser.h +++ b/code/AssetLib/Obj/ObjFileParser.h @@ -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 #include #include @@ -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 &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 &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 diff --git a/code/AssetLib/Ply/PlyLoader.cpp b/code/AssetLib/Ply/PlyLoader.cpp index a747ba5cd..f524e3a73 100644 --- a/code/AssetLib/Ply/PlyLoader.cpp +++ b/code/AssetLib/Ply/PlyLoader.cpp @@ -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); diff --git a/code/AssetLib/Ply/PlyParser.cpp b/code/AssetLib/Ply/PlyParser.cpp index 662da805e..7dcc4d239 100644 --- a/code/AssetLib/Ply/PlyParser.cpp +++ b/code/AssetLib/Ply/PlyParser.cpp @@ -50,7 +50,7 @@ OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. #include #include -using namespace Assimp; +namespace Assimp { // ------------------------------------------------------------------------------------------------ PLY::EDataType PLY::Property::ParseDataType(std::vector &buffer) { @@ -296,7 +296,7 @@ bool PLY::Element::ParseElement(IOStreamBuffer &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 &streamBuffer, std::vector< return true; } -// ------------------------------------------------------------------------------------------------ bool PLY::DOM::SkipSpaces(std::vector &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 &buffer) { bool PLY::DOM::SkipLine(std::vector &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 &buffer, const char *token, unsigned bool PLY::DOM::SkipSpacesAndLineEnd(std::vector &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 &streamBuffer, std::vector } else { // ignore unknown header elements if (!streamBuffer.getNextLine(buffer)) - return false; + return false; } } @@ -446,7 +448,7 @@ bool PLY::DOM::ParseElementInstanceLists(IOStreamBuffer &streamBuffer, std std::vector::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 &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::iterator i = p_pcOut->alProperties.begin(); std::vector::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 &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 &streamBuffer, break; } - //read the next file block if needed + // read the next file block if needed if (bufferSize < lsize) { std::vector nbuffer; if (streamBuffer.getNextBlock(nbuffer)) { - //concat buffer contents + // concat buffer contents buffer = std::vector(buffer.end() - bufferSize, buffer.end()); buffer.insert(buffer.end(), nbuffer.begin(), nbuffer.end()); nbuffer.clear(); @@ -958,4 +961,6 @@ bool PLY::PropertyInstance::ParseValueBinary(IOStreamBuffer &streamBuffer, return ret; } +} // namespace Assimp + #endif // !! ASSIMP_BUILD_NO_PLY_IMPORTER diff --git a/code/AssetLib/Ply/PlyParser.h b/code/AssetLib/Ply/PlyParser.h index 593791e92..0e362926e 100644 --- a/code/AssetLib/Ply/PlyParser.h +++ b/code/AssetLib/Ply/PlyParser.h @@ -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); // ------------------------------------------------------------------- diff --git a/code/AssetLib/Raw/RawLoader.cpp b/code/AssetLib/Raw/RawLoader.cpp index 4c5f852b0..338ca9efa 100644 --- a/code/AssetLib/Raw/RawLoader.cpp +++ b/code/AssetLib/Raw/RawLoader.cpp @@ -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::iterator it = outGroups.begin(), end = outGroups.end(); - it != end; ++it) { + for (std::vector::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(sz, data[num]); } if (num != 12 && num != 9) { diff --git a/code/AssetLib/SMD/SMDLoader.cpp b/code/AssetLib/SMD/SMDLoader.cpp index 4b63dd9d0..1d02847c8 100644 --- a/code/AssetLib/SMD/SMDLoader.cpp +++ b/code/AssetLib/SMD/SMDLoader.cpp @@ -82,8 +82,10 @@ static constexpr aiImporterDesc desc = { // ------------------------------------------------------------------------------------------------ // Constructor to be privately used by Importer SMDImporter::SMDImporter() : - configFrameID(), - pScene( nullptr ), + configFrameID(), + 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", 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" - Specifies the current animation frame - if(!ParseSignedInt(szCurrent,&szCurrent,iTime)) { + // "time \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(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 diff --git a/code/AssetLib/SMD/SMDLoader.h b/code/AssetLib/SMD/SMDLoader.h index adf80ba14..8286aa5eb 100644 --- a/code/AssetLib/SMD/SMDLoader.h +++ b/code/AssetLib/SMD/SMDLoader.h @@ -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 mBuffer; + char *mEnd; /** Output scene to be filled */ diff --git a/code/AssetLib/STEPParser/STEPFileReader.cpp b/code/AssetLib/STEPParser/STEPFileReader.cpp index 2bcfa1755..58d9cacc4 100644 --- a/code/AssetLib/STEPParser/STEPFileReader.cpp +++ b/code/AssetLib/STEPParser/STEPFileReader.cpp @@ -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( (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( (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 stream) { std::shared_ptr reader = std::shared_ptr(new StreamReaderLE(std::move(stream))); @@ -110,8 +104,9 @@ STEP::DB* STEP::ReadFileHeader(std::shared_ptr 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 EXPRESS::DataType::Parse(const char*& inout,uint64_t line, const EXPRESS::ConversionSchema* schema /*= nullptr*/) +std::shared_ptr 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 EXPRESS::DataType::Parse(const char*& i std::transform(s.begin(),s.end(),s.begin(),&ai_tolower ); if (schema->IsKnownToken(s)) { for(cur = t+1;*cur++ != '(';); - std::shared_ptr dt = Parse(cur); + std::shared_ptr dt = Parse(cur, end); inout = *cur ? cur+1 : cur; return dt; } @@ -348,7 +343,7 @@ std::shared_ptr 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 EXPRESS::DataType::Parse(const char*& i } // ------------------------------------------------------------------------------------------------ -std::shared_ptr EXPRESS::LIST::Parse(const char*& inout,uint64_t line, const EXPRESS::ConversionSchema* schema /*= nullptr*/) { +std::shared_ptr EXPRESS::LIST::Parse(const char*& inout, const char *end, + uint64_t line, const EXPRESS::ConversionSchema* schema) { const std::shared_ptr list = std::make_shared(); - 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 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 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 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 conv_args = EXPRESS::LIST::Parse(acopy, end, (uint64_t)STEP::SyntaxError::LINE_NOT_SPECIFIED,&db.GetSchema()); delete[] args; args = nullptr; diff --git a/code/AssetLib/STEPParser/STEPFileReader.h b/code/AssetLib/STEPParser/STEPFileReader.h index 8a57937c0..5a8eb7a6e 100644 --- a/code/AssetLib/STEPParser/STEPFileReader.h +++ b/code/AssetLib/STEPParser/STEPFileReader.h @@ -60,8 +60,7 @@ void ReadFile(DB& db,const EXPRESS::ConversionSchema& scheme, const char* const* /// @brief Helper to read a file. template -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); } diff --git a/code/AssetLib/STL/STLLoader.cpp b/code/AssetLib/STL/STLLoader.cpp index 269ee1467..397aa59b1 100644 --- a/code/AssetLib/STL/STLLoader.cpp +++ b/code/AssetLib/STL/STLLoader.cpp @@ -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(sz, (ai_real &)vn.x); - SkipSpaces(&sz); + SkipSpaces(&sz, bufferEnd); sz = fast_atoreal_move(sz, (ai_real &)vn.y); - SkipSpaces(&sz); + SkipSpaces(&sz, bufferEnd); sz = fast_atoreal_move(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(sz, (ai_real &)vn->x); - SkipSpaces(&sz); + SkipSpaces(&sz, bufferEnd); sz = fast_atoreal_move(sz, (ai_real &)vn->y); - SkipSpaces(&sz); + SkipSpaces(&sz, bufferEnd); sz = fast_atoreal_move(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 diff --git a/code/AssetLib/Step/STEPFile.h b/code/AssetLib/Step/STEPFile.h index 76a9370f5..e5da75b61 100644 --- a/code/AssetLib/Step/STEPFile.h +++ b/code/AssetLib/Step/STEPFile.h @@ -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 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 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 Parse(const char *&inout, + static std::shared_ptr Parse(const char *&inout, const char *end, uint64_t line = SyntaxError::LINE_NOT_SPECIFIED, const EXPRESS::ConversionSchema *schema = nullptr); diff --git a/code/AssetLib/Unreal/UnrealLoader.cpp b/code/AssetLib/Unreal/UnrealLoader.cpp index 5f622da42..ab3f7c3be 100644 --- a/code/AssetLib/Unreal/UnrealLoader.cpp +++ b/code/AssetLib/Unreal/UnrealLoader.cpp @@ -320,17 +320,18 @@ void UnrealImporter::InternReadFile(const std::string &pFile, std::vector _data; TextFileToBuffer(pb.get(), _data); const char *data = &_data[0]; + const char *end = &_data[_data.size() - 1] + 1; std::vector> 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::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(materials.size()); diff --git a/code/AssetLib/XGL/XGLLoader.cpp b/code/AssetLib/XGL/XGLLoader.cpp index 9efd5d628..cb5237dc8 100644 --- a/code/AssetLib/XGL/XGLLoader.cpp +++ b/code/AssetLib/XGL/XGLLoader.cpp @@ -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; diff --git a/code/CMakeLists.txt b/code/CMakeLists.txt index 9b0b964c0..bc5b7b16f 100644 --- a/code/CMakeLists.txt +++ b/code/CMakeLists.txt @@ -1193,6 +1193,10 @@ ENDIF () TARGET_USE_COMMON_OUTPUT_DIRECTORY(assimp) +add_compile_options( + "$<$:-O0;-g3;-ggdb>" +) + IF (ASSIMP_WARNINGS_AS_ERRORS) MESSAGE(STATUS "Treating all warnings as errors (for assimp library only)") IF (MSVC) diff --git a/code/PostProcessing/ProcessHelper.cpp b/code/PostProcessing/ProcessHelper.cpp index e55c17648..36ffd6fe0 100644 --- a/code/PostProcessing/ProcessHelper.cpp +++ b/code/PostProcessing/ProcessHelper.cpp @@ -52,8 +52,9 @@ namespace Assimp { // ------------------------------------------------------------------------------- void ConvertListToStrings(const std::string &in, std::list &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 &out) { out.emplace_back(base, (size_t)(s - base)); ++s; } else { - out.push_back(GetNextToken(s)); + out.push_back(GetNextToken(s, end)); } } } diff --git a/include/assimp/LineSplitter.h b/include/assimp/LineSplitter.h index 379821f03..0504e03d6 100644 --- a/include/assimp/LineSplitter.h +++ b/include/assimp/LineSplitter.h @@ -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 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; } diff --git a/include/assimp/ParsingUtils.h b/include/assimp/ParsingUtils.h index 7e7fb161c..570f10aac 100644 --- a/include/assimp/ParsingUtils.h +++ b/include/assimp/ParsingUtils.h @@ -102,8 +102,8 @@ AI_FORCE_INLINE bool IsSpaceOrNewLine(char_t in) { // --------------------------------------------------------------------------------- template -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 -AI_FORCE_INLINE bool SkipSpaces(const char_t **inout) { - return SkipSpaces(*inout, inout); +AI_FORCE_INLINE bool SkipSpaces(const char_t **inout, const char_t *end) { + return SkipSpaces(*inout, inout, end); } // --------------------------------------------------------------------------------- template -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 -AI_FORCE_INLINE bool SkipLine(const char_t **inout) { - return SkipLine(*inout, inout); +AI_FORCE_INLINE bool SkipLine(const char_t **inout, const char_t *end) { + return SkipLine(*inout, inout, end); } // --------------------------------------------------------------------------------- template -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 -AI_FORCE_INLINE bool SkipSpacesAndLineEnd(const char_t **inout) { - return SkipSpacesAndLineEnd(*inout, inout); +AI_FORCE_INLINE bool SkipSpacesAndLineEnd(const char_t **inout, const char_t *end) { + return SkipSpacesAndLineEnd(*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; From f9563519428797a3a34b4a84cd8305cf479d7dda Mon Sep 17 00:00:00 2001 From: Kim Kulling Date: Tue, 30 Jan 2024 22:14:18 +0100 Subject: [PATCH 31/77] Fix crash in viewer (#5446) --- tools/assimp_view/Display.cpp | 73 ++++++++++++++--------------------- 1 file changed, 30 insertions(+), 43 deletions(-) diff --git a/tools/assimp_view/Display.cpp b/tools/assimp_view/Display.cpp index 95ed41615..5c2ee8ff5 100644 --- a/tools/assimp_view/Display.cpp +++ b/tools/assimp_view/Display.cpp @@ -518,20 +518,19 @@ int CDisplay::AddTextureToDisplayList(unsigned int iType, return 1; } //------------------------------------------------------------------------------- -int CDisplay::AddMaterialToDisplayList(HTREEITEM hRoot, - unsigned int iIndex) -{ +int CDisplay::AddMaterialToDisplayList(HTREEITEM hRoot, unsigned int iIndex) { ai_assert(nullptr != hRoot); aiMaterial* pcMat = g_pcAsset->pcScene->mMaterials[iIndex]; + if (g_pcAsset->pcScene->mNumMeshes == 0) { + return -1; + } // find the first mesh using this material index unsigned int iMesh = 0; - for (unsigned int i = 0; i < g_pcAsset->pcScene->mNumMeshes;++i) - { - if (iIndex == g_pcAsset->pcScene->mMeshes[i]->mMaterialIndex) - { + for (unsigned int i = 0; i < g_pcAsset->pcScene->mNumMeshes;++i) { + if (iIndex == g_pcAsset->pcScene->mMeshes[i]->mMaterialIndex) { iMesh = i; break; } @@ -540,12 +539,9 @@ int CDisplay::AddMaterialToDisplayList(HTREEITEM hRoot, // use the name of the material, if possible char chTemp[512]; aiString szOut; - if (AI_SUCCESS != aiGetMaterialString(pcMat,AI_MATKEY_NAME,&szOut)) - { + if (AI_SUCCESS != aiGetMaterialString(pcMat,AI_MATKEY_NAME,&szOut)) { ai_snprintf(chTemp,512,"Material %i",iIndex+1); - } - else - { + } else { ai_snprintf(chTemp,512,"%s (%i)",szOut.data,iIndex+1); } TVITEMEXW tvi; @@ -577,17 +573,15 @@ int CDisplay::AddMaterialToDisplayList(HTREEITEM hRoot, aiTextureOp eOp; aiString szPath; bool bNoOpacity = true; - for (unsigned int i = 0; i <= AI_TEXTURE_TYPE_MAX;++i) - { + for (unsigned int i = 0; i <= AI_TEXTURE_TYPE_MAX;++i) { unsigned int iNum = 0; - while (true) - { - if (AI_SUCCESS != aiGetMaterialTexture(pcMat,(aiTextureType)i,iNum, - &szPath,nullptr, &iUV,&fBlend,&eOp)) - { + while (true) { + if (AI_SUCCESS != aiGetMaterialTexture(pcMat,(aiTextureType)i,iNum, &szPath,nullptr, &iUV,&fBlend,&eOp)) { break; } - if (aiTextureType_OPACITY == i)bNoOpacity = false; + if (aiTextureType_OPACITY == i) { + bNoOpacity = false; + } AddTextureToDisplayList(i,iNum,&szPath,hTexture,iUV,fBlend,eOp,iMesh); ++iNum; } @@ -595,8 +589,7 @@ int CDisplay::AddMaterialToDisplayList(HTREEITEM hRoot, AssetHelper::MeshHelper* pcMesh = g_pcAsset->apcMeshes[iMesh]; - if (pcMesh->piDiffuseTexture && pcMesh->piDiffuseTexture == pcMesh->piOpacityTexture && bNoOpacity) - { + if (pcMesh->piDiffuseTexture && pcMesh->piDiffuseTexture == pcMesh->piOpacityTexture && bNoOpacity) { // check whether the diffuse texture is not a default texture // {9785DA94-1D96-426b-B3CB-BADC36347F5E} @@ -606,9 +599,7 @@ int CDisplay::AddMaterialToDisplayList(HTREEITEM hRoot, uint32_t iData = 0; DWORD dwSize = 4; - if(FAILED( pcMesh->piDiffuseTexture->GetPrivateData(guidPrivateData,&iData,&dwSize) || - 0xffffffff == iData)) - { + if(FAILED( pcMesh->piDiffuseTexture->GetPrivateData(guidPrivateData,&iData,&dwSize) || 0xffffffff == iData)) { // seems the diffuse texture contains alpha, therefore it has been // added to the opacity channel, too. Add a special value ... AddTextureToDisplayList(aiTextureType_OPACITY | 0x40000000, @@ -625,33 +616,26 @@ int CDisplay::AddMaterialToDisplayList(HTREEITEM hRoot, this->AddMaterial(info); return 1; } + //------------------------------------------------------------------------------- // Expand all elements in the tree-view -int CDisplay::ExpandTree() -{ +int CDisplay::ExpandTree() { // expand all materials - for (std::vector< MaterialInfo >::iterator - i = m_asMaterials.begin(); - i != m_asMaterials.end();++i) - { + for (std::vector< MaterialInfo >::iterator i = m_asMaterials.begin(); i != m_asMaterials.end();++i) { TreeView_Expand(GetDlgItem(g_hDlg,IDC_TREE1),(*i).hTreeItem,TVE_EXPAND); } // expand all nodes - for (std::vector< NodeInfo >::iterator - i = m_asNodes.begin(); - i != m_asNodes.end();++i) - { + for (std::vector< NodeInfo >::iterator i = m_asNodes.begin(); i != m_asNodes.end();++i) { TreeView_Expand(GetDlgItem(g_hDlg,IDC_TREE1),(*i).hTreeItem,TVE_EXPAND); } TreeView_Expand(GetDlgItem(g_hDlg,IDC_TREE1),m_hRoot,TVE_EXPAND); return 1; } + //------------------------------------------------------------------------------- // Get image list for tree view -int CDisplay::LoadImageList(void) -{ - if (!m_hImageList) - { +int CDisplay::LoadImageList() { + if (!m_hImageList) { // First, create the image list we will need. // FIX: Need RGB888 color space to display all colors correctly HIMAGELIST hIml = ImageList_Create( 16,16,ILC_COLOR24, 5, 0 ); @@ -682,12 +666,13 @@ int CDisplay::LoadImageList(void) m_hImageList = hIml; } + return 1; } + //------------------------------------------------------------------------------- // Fill tree view -int CDisplay::FillDisplayList(void) -{ +int CDisplay::FillDisplayList(void) { LoadImageList(); // Initialize the tree view window. @@ -713,11 +698,11 @@ int CDisplay::FillDisplayList(void) (LPARAM)(LPTVINSERTSTRUCT)&sNew); // add each loaded material to the tree - for (unsigned int i = 0; i < g_pcAsset->pcScene->mNumMaterials;++i) + for (unsigned int i = 0; i < g_pcAsset->pcScene->mNumMaterials; ++i) AddMaterialToDisplayList(m_hRoot,i); // add each mesh to the tree - for (unsigned int i = 0; i < g_pcAsset->pcScene->mNumMeshes;++i) + for (unsigned int i = 0; i < g_pcAsset->pcScene->mNumMeshes; ++i) AddMeshToDisplayList(i,m_hRoot); // now add all loaded nodes recursively @@ -729,8 +714,10 @@ int CDisplay::FillDisplayList(void) // everything reacts a little bit slowly if D3D is rendering, // so give GDI a small hint to leave the couch and work ;-) UpdateWindow(g_hDlg); + return 1; } + //------------------------------------------------------------------------------- // Main render loop int CDisplay::OnRender() From 3476c798016d6db6dce6682ea05f87f4683651aa Mon Sep 17 00:00:00 2001 From: Kim Kulling Date: Wed, 31 Jan 2024 09:30:54 +0100 Subject: [PATCH 32/77] Static code analysis fixes (#5447) * Static code analysis fixes - Fix warning in LOW * Fix possible out of bound access. * Add default to class declaration --- code/AssetLib/Irr/IRRMeshLoader.cpp | 35 +++++++++++------------------ code/AssetLib/Irr/IRRMeshLoader.h | 9 +++++--- code/AssetLib/LWS/LWSLoader.cpp | 14 ++++++------ 3 files changed, 26 insertions(+), 32 deletions(-) diff --git a/code/AssetLib/Irr/IRRMeshLoader.cpp b/code/AssetLib/Irr/IRRMeshLoader.cpp index 639b4fff9..4a2f70882 100644 --- a/code/AssetLib/Irr/IRRMeshLoader.cpp +++ b/code/AssetLib/Irr/IRRMeshLoader.cpp @@ -3,7 +3,7 @@ Open Asset Import Library (assimp) --------------------------------------------------------------------------- -Copyright (c) 2006-2022, assimp team +Copyright (c) 2006-2024, assimp team All rights reserved. @@ -69,14 +69,6 @@ static constexpr aiImporterDesc desc = { "xml irrmesh" }; -// ------------------------------------------------------------------------------------------------ -// Constructor to be privately used by Importer -IRRMeshImporter::IRRMeshImporter() = default; - -// ------------------------------------------------------------------------------------------------ -// Destructor, private as well -IRRMeshImporter::~IRRMeshImporter() = default; - // ------------------------------------------------------------------------------------------------ // Returns whether the class can handle the format of the given file. bool IRRMeshImporter::CanRead(const std::string &pFile, IOSystem *pIOHandler, bool /*checkSig*/) const { @@ -116,8 +108,9 @@ void IRRMeshImporter::InternReadFile(const std::string &pFile, std::unique_ptr file(pIOHandler->Open(pFile)); // Check whether we can read from the file - if (file == nullptr) + if (file == nullptr) { throw DeadlyImportError("Failed to open IRRMESH file ", pFile); + } // Construct the irrXML parser XmlParser parser; @@ -148,13 +141,11 @@ void IRRMeshImporter::InternReadFile(const std::string &pFile, // int vertexFormat = 0; // 0 = normal; 1 = 2 tcoords, 2 = tangents bool useColors = false; - /* - ** irrmesh files have a top level owning multiple nodes. - ** Each contains , , and - ** tags here directly owns the material data specs - ** are a vertex per line, contains position, UV1 coords, maybe UV2, normal, tangent, bitangent - ** is ignored, I think assimp recalculates those? - */ + // irrmesh files have a top level owning multiple nodes. + // Each contains , , and + // tags here directly owns the material data specs + // are a vertex per line, contains position, UV1 coords, maybe UV2, normal, tangent, bitangent + // is ignored, I think assimp recalculates those? // Parse the XML file pugi::xml_node const &meshNode = root.child("mesh"); @@ -201,7 +192,6 @@ void IRRMeshImporter::InternReadFile(const std::string &pFile, // This is possible ... remove the mesh from the list and skip further reading ASSIMP_LOG_WARN("IRRMESH: Found mesh with zero vertices"); releaseMaterial(&curMat); - // releaseMesh(&curMesh); continue; // Bail out early }; @@ -331,7 +321,8 @@ 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; + const char *end = sz + std::strlen(sz); + // For each index loop over aiMesh faces while (SkipSpacesAndLineEnd(&sz, end)) { if (curFace >= faceEnd) { @@ -377,8 +368,9 @@ void IRRMeshImporter::InternReadFile(const std::string &pFile, } } // We should be at the end of mFaces - if (curFace != faceEnd) + if (curFace != faceEnd) { ASSIMP_LOG_ERROR("IRRMESH: Not enough indices"); + } } // Finish processing the mesh - do some small material workarounds @@ -388,8 +380,7 @@ void IRRMeshImporter::InternReadFile(const std::string &pFile, aiMaterial *mat = (aiMaterial *)curMat; mat->AddProperty(&curColors[0].a, 1, AI_MATKEY_OPACITY); } - // textMeaning = 2; - + // end of previous buffer. A material and a mesh should be there if (!curMat || !curMesh) { ASSIMP_LOG_ERROR("IRRMESH: A buffer must contain a mesh and a material"); diff --git a/code/AssetLib/Irr/IRRMeshLoader.h b/code/AssetLib/Irr/IRRMeshLoader.h index 9ec5c983d..4ab3615ee 100644 --- a/code/AssetLib/Irr/IRRMeshLoader.h +++ b/code/AssetLib/Irr/IRRMeshLoader.h @@ -2,7 +2,7 @@ Open Asset Import Library (assimp) ---------------------------------------------------------------------- -Copyright (c) 2006-2022, assimp team +Copyright (c) 2006-2024, assimp team All rights reserved. @@ -62,8 +62,11 @@ namespace Assimp { */ class IRRMeshImporter : public BaseImporter, public IrrlichtBase { public: - IRRMeshImporter(); - ~IRRMeshImporter() override; + /// @brief The class constructor. + IRRMeshImporter() = default; + + /// @brief The class destructor. + ~IRRMeshImporter() override = default; // ------------------------------------------------------------------- /** Returns whether the class can handle the format of the given file. diff --git a/code/AssetLib/LWS/LWSLoader.cpp b/code/AssetLib/LWS/LWSLoader.cpp index bf6e9ee31..4c3a44785 100644 --- a/code/AssetLib/LWS/LWSLoader.cpp +++ b/code/AssetLib/LWS/LWSLoader.cpp @@ -3,7 +3,7 @@ Open Asset Import Library (assimp) --------------------------------------------------------------------------- -Copyright (c) 2006-2022, assimp team +Copyright (c) 2006-2024, assimp team All rights reserved. @@ -155,7 +155,8 @@ const aiImporterDesc *LWSImporter::GetInfo() const { } static constexpr int MagicHackNo = 150392; - // ------------------------------------------------------------------------------------------------ + +// ------------------------------------------------------------------------------------------------ // Setup configuration properties void LWSImporter::SetupProperties(const Importer *pImp) { // AI_CONFIG_FAVOUR_SPEED @@ -248,13 +249,12 @@ 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::const_iterator &it,const std::list::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()); + const unsigned int 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(); @@ -266,8 +266,8 @@ void LWSImporter::ReadEnvelope_Old(std::list::const_iterator &it,c ASSIMP_LOG_ERROR("LWS: Encountered unexpected end of file while parsing object motion"); return; } - sub_num = strtoul10((*it).tokens[0].c_str()); - + + const unsigned int sub_num = strtoul10((*it).tokens[0].c_str()); for (unsigned int n = 0; n < sub_num; ++n) { if (++it == endIt) { ASSIMP_LOG_ERROR("LWS: Encountered unexpected end of file while parsing object motion"); @@ -283,7 +283,7 @@ void LWSImporter::ReadEnvelope_Old(std::list::const_iterator &it,c fast_atoreal_move((*it).tokens[0].c_str(), f); key.time = f; - envl.keys.push_back(key); + envl.keys.emplace_back(key); } } } From 3990ec80a1ba00e27e2ac825192dba4d3b07bb82 Mon Sep 17 00:00:00 2001 From: Kim Kulling Date: Thu, 1 Feb 2024 21:27:04 +0100 Subject: [PATCH 33/77] Kimkulling/fix bahavior of remove redundat mats issue 5438 (#5451) * Fix crash in viewer * Fix bevavior when material was not referenced --- .../RemoveRedundantMaterials.cpp | 195 +++++++++--------- 1 file changed, 100 insertions(+), 95 deletions(-) diff --git a/code/PostProcessing/RemoveRedundantMaterials.cpp b/code/PostProcessing/RemoveRedundantMaterials.cpp index ea8d154dc..b5fa7e732 100644 --- a/code/PostProcessing/RemoveRedundantMaterials.cpp +++ b/code/PostProcessing/RemoveRedundantMaterials.cpp @@ -75,124 +75,129 @@ void RemoveRedundantMatsProcess::Execute( aiScene* pScene) { ASSIMP_LOG_DEBUG("RemoveRedundantMatsProcess begin"); unsigned int redundantRemoved = 0, unreferencedRemoved = 0; - if (pScene->mNumMaterials) { - // Find out which materials are referenced by meshes - std::vector abReferenced(pScene->mNumMaterials,false); - for (unsigned int i = 0;i < pScene->mNumMeshes;++i) - abReferenced[pScene->mMeshes[i]->mMaterialIndex] = true; + if (pScene->mNumMaterials == 0) { + return; + } + + // Find out which materials are referenced by meshes + std::vector abReferenced(pScene->mNumMaterials,false); + for (unsigned int i = 0;i < pScene->mNumMeshes;++i) + abReferenced[pScene->mMeshes[i]->mMaterialIndex] = true; - // If a list of materials to be excluded was given, match the list with - // our imported materials and 'salt' all positive matches to ensure that - // we get unique hashes later. - if (mConfigFixedMaterials.length()) { + // If a list of materials to be excluded was given, match the list with + // our imported materials and 'salt' all positive matches to ensure that + // we get unique hashes later. + if (mConfigFixedMaterials.length()) { - std::list strings; - ConvertListToStrings(mConfigFixedMaterials,strings); + std::list strings; + ConvertListToStrings(mConfigFixedMaterials,strings); - for (unsigned int i = 0; i < pScene->mNumMaterials;++i) { - aiMaterial* mat = pScene->mMaterials[i]; + for (unsigned int i = 0; i < pScene->mNumMaterials;++i) { + aiMaterial* mat = pScene->mMaterials[i]; - aiString name; - mat->Get(AI_MATKEY_NAME,name); + aiString name; + mat->Get(AI_MATKEY_NAME,name); - if (name.length) { - std::list::const_iterator it = std::find(strings.begin(), strings.end(), name.data); - if (it != strings.end()) { + if (name.length) { + std::list::const_iterator it = std::find(strings.begin(), strings.end(), name.data); + if (it != strings.end()) { - // Our brilliant 'salt': A single material property with ~ as first - // character to mark it as internal and temporary. - const int dummy = 1; - ((aiMaterial*)mat)->AddProperty(&dummy,1,"~RRM.UniqueMaterial",0,0); + // Our brilliant 'salt': A single material property with ~ as first + // character to mark it as internal and temporary. + const int dummy = 1; + ((aiMaterial*)mat)->AddProperty(&dummy,1,"~RRM.UniqueMaterial",0,0); - // Keep this material even if no mesh references it - abReferenced[i] = true; - ASSIMP_LOG_VERBOSE_DEBUG( "Found positive match in exclusion list: \'", name.data, "\'"); - } + // Keep this material even if no mesh references it + abReferenced[i] = true; + ASSIMP_LOG_VERBOSE_DEBUG( "Found positive match in exclusion list: \'", name.data, "\'"); } } } + } - // TODO: re-implement this algorithm to work in-place - unsigned int *aiMappingTable = new unsigned int[pScene->mNumMaterials]; - for ( unsigned int i=0; imNumMaterials; i++ ) { - aiMappingTable[ i ] = 0; + // TODO: re-implement this algorithm to work in-place + unsigned int *aiMappingTable = new unsigned int[pScene->mNumMaterials]; + for ( unsigned int i=0; imNumMaterials; i++ ) { + aiMappingTable[ i ] = 0; + } + unsigned int iNewNum = 0; + + // Iterate through all materials and calculate a hash for them + // store all hashes in a list and so a quick search whether + // we do already have a specific hash. This allows us to + // determine which materials are identical. + uint32_t *aiHashes = new uint32_t[ pScene->mNumMaterials ];; + for (unsigned int i = 0; i < pScene->mNumMaterials;++i) { + // No mesh is referencing this material, remove it. + if (!abReferenced[i]) { + ++unreferencedRemoved; + delete pScene->mMaterials[i]; + pScene->mMaterials[i] = nullptr; + continue; } - unsigned int iNewNum = 0; - // Iterate through all materials and calculate a hash for them - // store all hashes in a list and so a quick search whether - // we do already have a specific hash. This allows us to - // determine which materials are identical. - uint32_t *aiHashes = new uint32_t[ pScene->mNumMaterials ];; - for (unsigned int i = 0; i < pScene->mNumMaterials;++i) { - // No mesh is referencing this material, remove it. - if (!abReferenced[i]) { - ++unreferencedRemoved; + // Check all previously mapped materials for a matching hash. + // On a match we can delete this material and just make it ref to the same index. + uint32_t me = aiHashes[i] = ComputeMaterialHash(pScene->mMaterials[i]); + for (unsigned int a = 0; a < i;++a) { + if (abReferenced[a] && me == aiHashes[a]) { + ++redundantRemoved; + me = 0; + aiMappingTable[i] = aiMappingTable[a]; delete pScene->mMaterials[i]; pScene->mMaterials[i] = nullptr; + break; + } + } + // This is a new material that is referenced, add to the map. + if (me) { + aiMappingTable[i] = iNewNum++; + } + } + // If the new material count differs from the original, + // we need to rebuild the material list and remap mesh material indexes. + if (iNewNum < 1) { + //throw DeadlyImportError("No materials remaining"); + return; + } + if (iNewNum != pScene->mNumMaterials) { + ai_assert(iNewNum > 0); + aiMaterial** ppcMaterials = new aiMaterial*[iNewNum]; + ::memset(ppcMaterials,0,sizeof(void*)*iNewNum); + for (unsigned int p = 0; p < pScene->mNumMaterials;++p) + { + // if the material is not referenced ... remove it + if (!abReferenced[p]) { continue; } - // Check all previously mapped materials for a matching hash. - // On a match we can delete this material and just make it ref to the same index. - uint32_t me = aiHashes[i] = ComputeMaterialHash(pScene->mMaterials[i]); - for (unsigned int a = 0; a < i;++a) { - if (abReferenced[a] && me == aiHashes[a]) { - ++redundantRemoved; - me = 0; - aiMappingTable[i] = aiMappingTable[a]; - delete pScene->mMaterials[i]; - pScene->mMaterials[i] = nullptr; - break; + // generate new names for modified materials that had no names + const unsigned int idx = aiMappingTable[p]; + if (ppcMaterials[idx]) { + aiString sz; + if( ppcMaterials[idx]->Get(AI_MATKEY_NAME, sz) != AI_SUCCESS ) { + sz.length = ::ai_snprintf(sz.data,MAXLEN,"JoinedMaterial_#%u",p); + ((aiMaterial*)ppcMaterials[idx])->AddProperty(&sz,AI_MATKEY_NAME); } - } - // This is a new material that is referenced, add to the map. - if (me) { - aiMappingTable[i] = iNewNum++; + } else { + ppcMaterials[idx] = pScene->mMaterials[p]; } } - // If the new material count differs from the original, - // we need to rebuild the material list and remap mesh material indexes. - if(iNewNum < 1) - throw DeadlyImportError("No materials remaining"); - if (iNewNum != pScene->mNumMaterials) { - ai_assert(iNewNum > 0); - aiMaterial** ppcMaterials = new aiMaterial*[iNewNum]; - ::memset(ppcMaterials,0,sizeof(void*)*iNewNum); - for (unsigned int p = 0; p < pScene->mNumMaterials;++p) - { - // if the material is not referenced ... remove it - if (!abReferenced[p]) { - continue; - } - - // generate new names for modified materials that had no names - const unsigned int idx = aiMappingTable[p]; - if (ppcMaterials[idx]) { - aiString sz; - if( ppcMaterials[idx]->Get(AI_MATKEY_NAME, sz) != AI_SUCCESS ) { - sz.length = ::ai_snprintf(sz.data,MAXLEN,"JoinedMaterial_#%u",p); - ((aiMaterial*)ppcMaterials[idx])->AddProperty(&sz,AI_MATKEY_NAME); - } - } else { - ppcMaterials[idx] = pScene->mMaterials[p]; - } - } - // update all material indices - for (unsigned int p = 0; p < pScene->mNumMeshes;++p) { - aiMesh* mesh = pScene->mMeshes[p]; - ai_assert(nullptr != mesh); - mesh->mMaterialIndex = aiMappingTable[mesh->mMaterialIndex]; - } - // delete the old material list - delete[] pScene->mMaterials; - pScene->mMaterials = ppcMaterials; - pScene->mNumMaterials = iNewNum; + // update all material indices + for (unsigned int p = 0; p < pScene->mNumMeshes;++p) { + aiMesh* mesh = pScene->mMeshes[p]; + ai_assert(nullptr != mesh); + mesh->mMaterialIndex = aiMappingTable[mesh->mMaterialIndex]; } - // delete temporary storage - delete[] aiHashes; - delete[] aiMappingTable; + // delete the old material list + delete[] pScene->mMaterials; + pScene->mMaterials = ppcMaterials; + pScene->mNumMaterials = iNewNum; } + // delete temporary storage + delete[] aiHashes; + delete[] aiMappingTable; + if (redundantRemoved == 0 && unreferencedRemoved == 0) { ASSIMP_LOG_DEBUG("RemoveRedundantMatsProcess finished "); } else { From 005399a67189df2d7666fedff5db3a6da028c051 Mon Sep 17 00:00:00 2001 From: Steve M Date: Sun, 4 Feb 2024 01:38:07 -0800 Subject: [PATCH 34/77] Fix X importer breakage introduced in commit f844c33 (#5372) * Update XFileImporter.cpp Comment out boneIdx conditional which caused massive breakage * Update XFileImporter.cpp Fix typo * Update XFileImporter.cpp Dummy whitespace change to attempt to re-trigger failing CI tests --------- Co-authored-by: Steve M Co-authored-by: Kim Kulling --- code/AssetLib/X/XFileImporter.cpp | 14 +++++++++++--- 1 file changed, 11 insertions(+), 3 deletions(-) diff --git a/code/AssetLib/X/XFileImporter.cpp b/code/AssetLib/X/XFileImporter.cpp index 00f44b34b..22697d679 100644 --- a/code/AssetLib/X/XFileImporter.cpp +++ b/code/AssetLib/X/XFileImporter.cpp @@ -359,10 +359,18 @@ void XFileImporter::CreateMeshes(aiScene *pScene, aiNode *pNode, const std::vect // set up a vertex-linear array of the weights for quick searching if a bone influences a vertex std::vector oldWeights(sourceMesh->mPositions.size(), 0.0); for (unsigned int d = 0; d < obone.mWeights.size(); ++d) { - const unsigned int boneIdx = obone.mWeights[d].mVertex; - if (boneIdx < obone.mWeights.size()) { + // TODO The conditional against boneIdx which was added in commit f844c33 + // TODO (https://github.com/assimp/assimp/commit/f844c3397d7726477ab0fdca8efd3df56c18366b) + // TODO causes massive breakage as detailed in: + // TODO https://github.com/assimp/assimp/issues/5332 + // TODO In cases like this unit tests are less useful, since the model still has + // TODO meshes, textures, animations etc. and asserts against these values may pass; + // TODO when touching importer code, it is crucial that developers also run manual, visual + // TODO checks to ensure there's no obvious breakage _before_ commiting to main branch + //const unsigned int boneIdx = obone.mWeights[d].mVertex; + //if (boneIdx < obone.mWeights.size()) { oldWeights[obone.mWeights[d].mVertex] = obone.mWeights[d].mWeight; - } + //} } // collect all vertex weights that influence a vertex in the new mesh From bc6673b4b2884903139b78639ce81762ca710bc8 Mon Sep 17 00:00:00 2001 From: Stephen Gold Date: Sun, 4 Feb 2024 10:06:07 -0800 Subject: [PATCH 35/77] Fileformats.md: clarify that import of .blend files is deprecated (#5350) Co-authored-by: Kim Kulling --- doc/Fileformats.md | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/doc/Fileformats.md b/doc/Fileformats.md index 118d798f2..5e7983812 100644 --- a/doc/Fileformats.md +++ b/doc/Fileformats.md @@ -12,7 +12,6 @@ __Importers__: - ASE - ASK - B3D -- [BLEND](https://en.wikipedia.org/wiki/.blend_(file_format)) - [BVH](https://en.wikipedia.org/wiki/Biovision_Hierarchy) - CSM - COB @@ -66,6 +65,9 @@ __Importers__: - XGL - ZGL +Note: support for [BLEND](https://en.wikipedia.org/wiki/.blend_(file_format)) is deprecated. +It is too time-consuming to maintain an undocumented format which contains so much more than we need. + Additionally, some formats are supported by dependency on non-free code or external SDKs (not built by default): - [C4D](https://en.wikipedia.org/wiki/Cinema_4D) (https://github.com/assimp/assimp/wiki/Cinema4D-&-Melange) IMporting geometry + node hierarchy are currently supported From b7b6601a759fe724219d8eda93e5ed158adc045c Mon Sep 17 00:00:00 2001 From: Galen Xiao <35212039+GalenXiao@users.noreply.github.com> Date: Mon, 5 Feb 2024 03:23:07 +0800 Subject: [PATCH 36/77] feat:1.add 3mf vertex color read 2.fix 3mf read texture bug (#5361) * feat:1.add 3mf vertex color read 2.fix 3mf read texture bug * fix checks failed * Trigger CI --------- Co-authored-by: Kim Kulling --- code/AssetLib/3MF/3MFTypes.h | 16 +++ code/AssetLib/3MF/3MFXmlTags.h | 5 + code/AssetLib/3MF/D3MFOpcPackage.cpp | 4 +- code/AssetLib/3MF/XmlSerializer.cpp | 150 +++++++++++++++++++++++---- code/AssetLib/3MF/XmlSerializer.h | 3 + 5 files changed, 154 insertions(+), 24 deletions(-) diff --git a/code/AssetLib/3MF/3MFTypes.h b/code/AssetLib/3MF/3MFTypes.h index 8207b568b..8b7cce652 100644 --- a/code/AssetLib/3MF/3MFTypes.h +++ b/code/AssetLib/3MF/3MFTypes.h @@ -57,6 +57,7 @@ enum class ResourceType { RT_BaseMaterials, RT_EmbeddedTexture2D, RT_Texture2DGroup, + RT_ColorGroup, RT_Unknown }; // To be extended with other resource types (eg. material extension resources like Texture2d, Texture2dGroup...) @@ -117,6 +118,21 @@ public: } }; +class ColorGroup : public Resource { +public: + std::vector mColors; + ColorGroup(int id) : + Resource(id){ + // empty + } + + ~ColorGroup() override = default; + + ResourceType getType() const override { + return ResourceType::RT_ColorGroup; + } +}; + class BaseMaterials : public Resource { public: std::vector mMaterialIndex; diff --git a/code/AssetLib/3MF/3MFXmlTags.h b/code/AssetLib/3MF/3MFXmlTags.h index 333d169aa..f94135187 100644 --- a/code/AssetLib/3MF/3MFXmlTags.h +++ b/code/AssetLib/3MF/3MFXmlTags.h @@ -98,6 +98,11 @@ namespace XmlTag { const char *const texture_cuurd_u = "u"; const char *const texture_cuurd_v = "v"; + // vertex color definitions + const char *const colorgroup = "m:colorgroup"; + const char *const color_item = "m:color"; + const char *const color_vaule = "color"; + // Meta info tags const char* const CONTENT_TYPES_ARCHIVE = "[Content_Types].xml"; const char* const ROOT_RELATIONSHIPS_ARCHIVE = "_rels/.rels"; diff --git a/code/AssetLib/3MF/D3MFOpcPackage.cpp b/code/AssetLib/3MF/D3MFOpcPackage.cpp index e772d8b7e..6284ce017 100644 --- a/code/AssetLib/3MF/D3MFOpcPackage.cpp +++ b/code/AssetLib/3MF/D3MFOpcPackage.cpp @@ -119,9 +119,9 @@ public: static bool IsEmbeddedTexture( const std::string &filename ) { const std::string extension = BaseImporter::GetExtension(filename); - if (extension == "jpg" || extension == "png") { + if (extension == "jpg" || extension == "png" || extension == "jpeg") { std::string::size_type pos = filename.find("thumbnail"); - if (pos == std::string::npos) { + if (pos != std::string::npos) { return false; } return true; diff --git a/code/AssetLib/3MF/XmlSerializer.cpp b/code/AssetLib/3MF/XmlSerializer.cpp index 5fcdc0ccc..cdaf3f432 100644 --- a/code/AssetLib/3MF/XmlSerializer.cpp +++ b/code/AssetLib/3MF/XmlSerializer.cpp @@ -75,7 +75,7 @@ aiFace ReadTriangle(XmlNode &node, int &texId0, int &texId1, int &texId2) { face.mIndices[1] = static_cast(std::atoi(node.attribute(XmlTag::v2).as_string())); face.mIndices[2] = static_cast(std::atoi(node.attribute(XmlTag::v3).as_string())); - texId0 = texId1 = texId2 = -1; + texId0 = texId1 = texId2 = IdNotSet; XmlParser::getIntAttribute(node, XmlTag::p1, texId0); XmlParser::getIntAttribute(node, XmlTag::p2, texId1); XmlParser::getIntAttribute(node, XmlTag::p3, texId2); @@ -236,6 +236,8 @@ void XmlSerializer::ImportXml(aiScene *scene) { ReadBaseMaterials(currentNode); } else if (currentNodeName == XmlTag::meta) { ReadMetadata(currentNode); + } else if (currentNodeName == XmlTag::colorgroup) { + ReadColorGroup(currentNode); } } StoreMaterialsInScene(scene); @@ -331,9 +333,49 @@ void XmlSerializer::ReadObject(XmlNode &node) { if (hasPid) { auto it = mResourcesDictionnary.find(pid); - if (hasPindex && it != mResourcesDictionnary.end() && it->second->getType() == ResourceType::RT_BaseMaterials) { - BaseMaterials *materials = static_cast(it->second); - mesh->mMaterialIndex = materials->mMaterialIndex[pindex]; + if (hasPindex && it != mResourcesDictionnary.end()) { + if (it->second->getType() == ResourceType::RT_BaseMaterials) { + BaseMaterials *materials = static_cast(it->second); + mesh->mMaterialIndex = materials->mMaterialIndex[pindex]; + } else if (it->second->getType() == ResourceType::RT_Texture2DGroup) { + Texture2DGroup *group = static_cast(it->second); + if (mesh->mTextureCoords[0] == nullptr) { + mesh->mNumUVComponents[0] = 2; + for (unsigned int i = 1; i < AI_MAX_NUMBER_OF_TEXTURECOORDS; ++i) { + mesh->mNumUVComponents[i] = 0; + } + + const std::string name = ai_to_string(group->mTexId); + for (size_t i = 0; i < mMaterials.size(); ++i) { + if (name == mMaterials[i]->GetName().C_Str()) { + mesh->mMaterialIndex = static_cast(i); + } + } + + mesh->mTextureCoords[0] = new aiVector3D[mesh->mNumVertices]; + for (unsigned int vertex_idx = 0; vertex_idx < mesh->mNumVertices; vertex_idx++) { + mesh->mTextureCoords[0][vertex_idx] = + aiVector3D(group->mTex2dCoords[pindex].x, group->mTex2dCoords[pindex].y, 0.0f); + } + } else { + for (unsigned int vertex_idx = 0; vertex_idx < mesh->mNumVertices; vertex_idx++) { + if (mesh->mTextureCoords[0][vertex_idx].z < 0) { + // use default + mesh->mTextureCoords[0][vertex_idx] = + aiVector3D(group->mTex2dCoords[pindex].x, group->mTex2dCoords[pindex].y, 0.0f); + } + } + } + }else if (it->second->getType() == ResourceType::RT_ColorGroup) { + if (mesh->mColors[0] == nullptr) { + mesh->mColors[0] = new aiColor4D[mesh->mNumVertices]; + + ColorGroup *group = static_cast(it->second); + for (unsigned int vertex_idx = 0; vertex_idx < mesh->mNumVertices; vertex_idx++) { + mesh->mColors[0][vertex_idx] = group->mColors[pindex]; + } + } + } } } @@ -415,27 +457,36 @@ void XmlSerializer::ImportTriangles(XmlNode &node, aiMesh *mesh) { for (XmlNode ¤tNode : node.children()) { const std::string currentName = currentNode.name(); if (currentName == XmlTag::triangle) { - int pid = IdNotSet, p1 = IdNotSet; + int pid = IdNotSet; bool hasPid = getNodeAttribute(currentNode, D3MF::XmlTag::pid, pid); - bool hasP1 = getNodeAttribute(currentNode, D3MF::XmlTag::p1, p1); - int texId[3]; - Texture2DGroup *group = nullptr; - aiFace face = ReadTriangle(currentNode, texId[0], texId[1], texId[2]); - if (hasPid && hasP1) { + int pindex[3]; + aiFace face = ReadTriangle(currentNode, pindex[0], pindex[1], pindex[2]); + if (hasPid && (pindex[0] != IdNotSet || pindex[1] != IdNotSet || pindex[2] != IdNotSet)) { auto it = mResourcesDictionnary.find(pid); if (it != mResourcesDictionnary.end()) { if (it->second->getType() == ResourceType::RT_BaseMaterials) { BaseMaterials *baseMaterials = static_cast(it->second); - mesh->mMaterialIndex = baseMaterials->mMaterialIndex[p1]; + + auto update_material = [&](int idx) { + if (pindex[idx] != IdNotSet) { + mesh->mMaterialIndex = baseMaterials->mMaterialIndex[pindex[idx]]; + } + }; + + update_material(0); + update_material(1); + update_material(2); + } else if (it->second->getType() == ResourceType::RT_Texture2DGroup) { + // Load texture coordinates into mesh, when any + Texture2DGroup *group = static_cast(it->second); // fix bug if (mesh->mTextureCoords[0] == nullptr) { mesh->mNumUVComponents[0] = 2; for (unsigned int i = 1; i < AI_MAX_NUMBER_OF_TEXTURECOORDS; ++i) { mesh->mNumUVComponents[i] = 0; } - group = static_cast(it->second); const std::string name = ai_to_string(group->mTexId); for (size_t i = 0; i < mMaterials.size(); ++i) { if (name == mMaterials[i]->GetName().C_Str()) { @@ -443,21 +494,44 @@ void XmlSerializer::ImportTriangles(XmlNode &node, aiMesh *mesh) { } } mesh->mTextureCoords[0] = new aiVector3D[mesh->mNumVertices]; + for (unsigned int vertex_index = 0; vertex_index < mesh->mNumVertices; vertex_index++) { + mesh->mTextureCoords[0][vertex_index].z = IdNotSet;//mark not set + } } + + auto update_texture = [&](int idx) { + if (pindex[idx] != IdNotSet) { + size_t vertex_index = face.mIndices[idx]; + mesh->mTextureCoords[0][vertex_index] = + aiVector3D(group->mTex2dCoords[pindex[idx]].x, group->mTex2dCoords[pindex[idx]].y, 0.0f); + } + }; + + update_texture(0); + update_texture(1); + update_texture(2); + + } else if (it->second->getType() == ResourceType::RT_ColorGroup) { + // Load vertex color into mesh, when any + ColorGroup *group = static_cast(it->second); + if (mesh->mColors[0] == nullptr) { + mesh->mColors[0] = new aiColor4D[mesh->mNumVertices]; + } + + auto update_color = [&](int idx) { + if (pindex[idx] != IdNotSet) { + size_t vertex_index = face.mIndices[idx]; + mesh->mColors[0][vertex_index] = group->mColors[pindex[idx]]; + } + }; + + update_color(0); + update_color(1); + update_color(2); } } } - // Load texture coordinates into mesh, when any - if (group != nullptr) { - size_t i0 = face.mIndices[0]; - size_t i1 = face.mIndices[1]; - size_t i2 = face.mIndices[2]; - mesh->mTextureCoords[0][i0] = aiVector3D(group->mTex2dCoords[texId[0]].x, group->mTex2dCoords[texId[0]].y, 0.0f); - mesh->mTextureCoords[0][i1] = aiVector3D(group->mTex2dCoords[texId[1]].x, group->mTex2dCoords[texId[1]].y, 0.0f); - mesh->mTextureCoords[0][i2] = aiVector3D(group->mTex2dCoords[texId[2]].x, group->mTex2dCoords[texId[2]].y, 0.0f); - } - faces.push_back(face); } } @@ -598,6 +672,38 @@ aiMaterial *XmlSerializer::readMaterialDef(XmlNode &node, unsigned int basemater return material; } +void XmlSerializer::ReadColor(XmlNode &node, ColorGroup *colorGroup) { + if (node.empty() || nullptr == colorGroup) { + return; + } + + for (XmlNode currentNode : node.children()) { + const std::string currentName = currentNode.name(); + if (currentName == XmlTag::color_item) { + const char *color = currentNode.attribute(XmlTag::color_vaule).as_string(); + aiColor4D color_value; + if (parseColor(color, color_value)) { + colorGroup->mColors.push_back(color_value); + } + } + } +} + +void XmlSerializer::ReadColorGroup(XmlNode &node) { + if (node.empty()) { + return; + } + + int id = IdNotSet; + if (!XmlParser::getIntAttribute(node, XmlTag::id, id)) { + return; + } + + ColorGroup *group = new ColorGroup(id); + ReadColor(node, group); + mResourcesDictionnary.insert(std::make_pair(id, group)); +} + void XmlSerializer::StoreMaterialsInScene(aiScene *scene) { if (nullptr == scene) { return; diff --git a/code/AssetLib/3MF/XmlSerializer.h b/code/AssetLib/3MF/XmlSerializer.h index 6cf6a70a9..39eb2ddf9 100644 --- a/code/AssetLib/3MF/XmlSerializer.h +++ b/code/AssetLib/3MF/XmlSerializer.h @@ -57,6 +57,7 @@ class D3MFOpcPackage; class Object; class Texture2DGroup; class EmbeddedTexture; +class ColorGroup; class XmlSerializer { public: @@ -78,6 +79,8 @@ private: void ReadTextureGroup(XmlNode &node); aiMaterial *readMaterialDef(XmlNode &node, unsigned int basematerialsId); void StoreMaterialsInScene(aiScene *scene); + void ReadColorGroup(XmlNode &node); + void ReadColor(XmlNode &node, ColorGroup *colorGroup); private: struct MetaEntry { From f59a5fab1aac3adbefe001317b9e4a3bae6cae32 Mon Sep 17 00:00:00 2001 From: Florian Born <44984048+FlorianBorn71@users.noreply.github.com> Date: Sun, 4 Feb 2024 21:23:31 +0100 Subject: [PATCH 37/77] More GLTF loading hardening (#5415) Co-authored-by: Kim Kulling --- code/AssetLib/glTF2/glTF2Asset.h | 4 +-- code/AssetLib/glTF2/glTF2Asset.inl | 50 +++++++++++++++++++++++++----- 2 files changed, 45 insertions(+), 9 deletions(-) diff --git a/code/AssetLib/glTF2/glTF2Asset.h b/code/AssetLib/glTF2/glTF2Asset.h index 8d500b156..4cfaca4da 100644 --- a/code/AssetLib/glTF2/glTF2Asset.h +++ b/code/AssetLib/glTF2/glTF2Asset.h @@ -547,7 +547,7 @@ struct BufferView : public Object { BufferViewTarget target; //! The target that the WebGL buffer should be bound to. void Read(Value &obj, Asset &r); - uint8_t *GetPointer(size_t accOffset); + uint8_t *GetPointerAndTailSize(size_t accOffset, size_t& outTailSize); }; //! A typed view into a BufferView. A BufferView contains raw binary data. @@ -629,7 +629,7 @@ struct Accessor : public Object { std::vector data; //!< Actual data, which may be defaulted to an array of zeros or the original data, with the sparse buffer view applied on top of it. - void PopulateData(size_t numBytes, uint8_t *bytes); + void PopulateData(size_t numBytes, const uint8_t *bytes); void PatchData(unsigned int elementSize); }; }; diff --git a/code/AssetLib/glTF2/glTF2Asset.inl b/code/AssetLib/glTF2/glTF2Asset.inl index 61964d1b4..09a58da54 100644 --- a/code/AssetLib/glTF2/glTF2Asset.inl +++ b/code/AssetLib/glTF2/glTF2Asset.inl @@ -785,12 +785,14 @@ inline void BufferView::Read(Value &obj, Asset &r) { } } -inline uint8_t *BufferView::GetPointer(size_t accOffset) { +inline uint8_t *BufferView::GetPointerAndTailSize(size_t accOffset, size_t& outTailSize) { if (!buffer) { + outTailSize = 0; return nullptr; } - uint8_t *basePtr = buffer->GetPointer(); + uint8_t * const basePtr = buffer->GetPointer(); if (!basePtr) { + outTailSize = 0; return nullptr; } @@ -799,17 +801,25 @@ inline uint8_t *BufferView::GetPointer(size_t accOffset) { const size_t begin = buffer->EncodedRegion_Current->Offset; const size_t end = begin + buffer->EncodedRegion_Current->DecodedData_Length; if ((offset >= begin) && (offset < end)) { + outTailSize = end - offset; return &buffer->EncodedRegion_Current->DecodedData[offset - begin]; } } + if (offset >= buffer->byteLength) + { + outTailSize = 0; + return nullptr; + } + + outTailSize = buffer->byteLength - offset; return basePtr + offset; } // // struct Accessor // -inline void Accessor::Sparse::PopulateData(size_t numBytes, uint8_t *bytes) { +inline void Accessor::Sparse::PopulateData(size_t numBytes, const uint8_t *bytes) { if (bytes) { data.assign(bytes, bytes + numBytes); } else { @@ -818,11 +828,21 @@ inline void Accessor::Sparse::PopulateData(size_t numBytes, uint8_t *bytes) { } inline void Accessor::Sparse::PatchData(unsigned int elementSize) { - uint8_t *pIndices = indices->GetPointer(indicesByteOffset); + size_t indicesTailDataSize; + uint8_t *pIndices = indices->GetPointerAndTailSize(indicesByteOffset, indicesTailDataSize); const unsigned int indexSize = int(ComponentTypeSize(indicesType)); uint8_t *indicesEnd = pIndices + count * indexSize; - uint8_t *pValues = values->GetPointer(valuesByteOffset); + if ((uint64_t)indicesEnd > (uint64_t)pIndices + indicesTailDataSize) { + throw DeadlyImportError("Invalid sparse accessor. Indices outside allocated memory."); + } + + size_t valuesTailDataSize; + uint8_t* pValues = values->GetPointerAndTailSize(valuesByteOffset, valuesTailDataSize); + + if (elementSize * count > valuesTailDataSize) { + throw DeadlyImportError("Invalid sparse accessor. Indices outside allocated memory."); + } while (pIndices != indicesEnd) { size_t offset; switch (indicesType) { @@ -894,6 +914,9 @@ inline void Accessor::Read(Value &obj, Asset &r) { if (Value *indicesValue = FindObject(*sparseValue, "indices")) { //indices bufferView Value *indiceViewID = FindUInt(*indicesValue, "bufferView"); + if (!indiceViewID) { + throw DeadlyImportError("A bufferView value is required, when reading ", id.c_str(), name.empty() ? "" : " (" + name + ")"); + } sparse->indices = r.bufferViews.Retrieve(indiceViewID->GetUint()); //indices byteOffset sparse->indicesByteOffset = MemberOrDefault(*indicesValue, "byteOffset", size_t(0)); @@ -909,6 +932,9 @@ inline void Accessor::Read(Value &obj, Asset &r) { if (Value *valuesValue = FindObject(*sparseValue, "values")) { //value bufferView Value *valueViewID = FindUInt(*valuesValue, "bufferView"); + if (!valueViewID) { + throw DeadlyImportError("A bufferView value is required, when reading ", id.c_str(), name.empty() ? "" : " (" + name + ")"); + } sparse->values = r.bufferViews.Retrieve(valueViewID->GetUint()); //value byteOffset sparse->valuesByteOffset = MemberOrDefault(*valuesValue, "byteOffset", size_t(0)); @@ -918,8 +944,18 @@ inline void Accessor::Read(Value &obj, Asset &r) { const unsigned int elementSize = GetElementSize(); const size_t dataSize = count * elementSize; - sparse->PopulateData(dataSize, bufferView ? bufferView->GetPointer(byteOffset) : nullptr); - sparse->PatchData(elementSize); + if (bufferView) { + size_t bufferViewTailSize; + const uint8_t* bufferViewPointer = bufferView->GetPointerAndTailSize(byteOffset, bufferViewTailSize); + if (dataSize > bufferViewTailSize) { + throw DeadlyImportError("Invalid buffer when reading ", id.c_str(), name.empty() ? "" : " (" + name + ")"); + } + sparse->PopulateData(dataSize, bufferViewPointer); + } + else { + sparse->PopulateData(dataSize, nullptr); + } + sparse->PatchData(elementSize); } } From a8c8e75a17856c65bb3fe66e1b432c10985491bb Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Mon, 5 Feb 2024 15:10:36 +0100 Subject: [PATCH 38/77] Bump actions/cache from 3 to 4 (#5431) Bumps [actions/cache](https://github.com/actions/cache) from 3 to 4. - [Release notes](https://github.com/actions/cache/releases) - [Changelog](https://github.com/actions/cache/blob/main/RELEASES.md) - [Commits](https://github.com/actions/cache/compare/v3...v4) --- updated-dependencies: - dependency-name: actions/cache dependency-type: direct:production update-type: version-update:semver-major ... Signed-off-by: dependabot[bot] Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> Co-authored-by: Kim Kulling --- .github/workflows/ccpp.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/ccpp.yml b/.github/workflows/ccpp.yml index 1c533aa80..db152b813 100644 --- a/.github/workflows/ccpp.yml +++ b/.github/workflows/ccpp.yml @@ -54,7 +54,7 @@ jobs: - name: Cache DX SDK id: dxcache if: contains(matrix.name, 'windows') - uses: actions/cache@v3 + uses: actions/cache@v4 with: path: '${{ github.workspace }}/DX_SDK' key: ${{ runner.os }}-DX_SDK From 1164844ce4ada5f0d57fca31c2b5c2035b914055 Mon Sep 17 00:00:00 2001 From: mosfet80 Date: Mon, 5 Feb 2024 15:40:52 +0100 Subject: [PATCH 39/77] Update CMakeLists.txt (#5379) * Update CMakeLists.txt Silence warnings when building with CMake 3.27 by @hjmallon in #717 update gate submodule with fixed CMake 3.27 deprecation warnings as well glog: add version 0.6.0 and disable new dependencies by @NeroBurner in #719 ceres-solver: update to v2.2.0-p1 by @NeroBurner in #720 Update 'GTest' to v1.14.0 by @hjmallon in #705 Update 'pybind11' to v2.11.1 by @hjmallon in #706 ceres-solver: update to v2.2.0-p0 and fix examples by @NeroBurner in #703 Eigen: explicitly disable Fortran usage by @NeroBurner in #704 OpenSSL: Fix v3 version parsing by @hjmallon in #707 Update 'Boost' to 1.83 by @hjmallon in #708 Update 'OpenSSL' to v3.0.12 and v3.1.4 by @hjmallon in #710 Update 'abseil' to 20230802.1 by @hjmallon in #711 Update 'benchmark' to v1.8.3 by @hjmallon in #712 Update 'sqlite3' to v3.43.2 by @hjmallon in #716 Update 'CURL' to v8.4.0 by @hjmallon in #663 CI: remove macos-10.15 jobs as the macos-10.15 runners are removed by @NeroBurner in #695 ZLIB: update to version v1.3.0-p0 by @NeroBurner in #693 miniz: update to v3.0.2 by @NeroBurner in #692 Update fmt package to 10.1.1 by @JamesEggleton in #697 Update spdlog package to 1.12.0-p0 by @JamesEggleton in #699 Update zstd package to 1.5.5 by @JamesEggleton in #700 SuiteSparse: update to 1.8.0 / 5.4.0-2 by @NeroBurner in #702 OpenCV, Extra, ippicv: update to v4.8.1-p0 by @NeroBurner in #696 hunter_setup_msvc: tolower to fix arm64 vs ARM64 confusion by @NeroBurner in #681 Add various recent LLVM versions by @mrexodia in #517 Update fmt package to 9.1.0 by @apivovarov in #683 Update asio-grpc to v2.6.0 by @Tradias in #686 #685 Minimum cmake version required now 3.5 by @john-forrest in #689 * Update CMakeLists.txt * Update CMakeLists.txt --------- Co-authored-by: Kim Kulling --- CMakeLists.txt | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/CMakeLists.txt b/CMakeLists.txt index 868282ef2..0133b47a4 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -49,8 +49,8 @@ option(ASSIMP_HUNTER_ENABLED "Enable Hunter package manager support" OFF) IF(ASSIMP_HUNTER_ENABLED) include("cmake-modules/HunterGate.cmake") HunterGate( - URL "https://github.com/cpp-pm/hunter/archive/v0.24.18.tar.gz" - SHA1 "1292e4d661e1770d6d6ca08c12c07cf34a0bf718" + URL "https://github.com/cpp-pm/hunter/archive/v0.25.3.tar.gz" + SHA1 "3319fe6a3b08090df7df98dee75134d68e2ef5a3" ) add_definitions(-DASSIMP_USE_HUNTER) ENDIF() From c877a151401afded0dca65fae3974a093dbd4e06 Mon Sep 17 00:00:00 2001 From: Julian Knodt Date: Mon, 5 Feb 2024 07:55:00 -0800 Subject: [PATCH 40/77] `Blendshape`->`Geometry` in FBX Export (#5419) When loading a mesh exported from assimp into Blender, it warns that it has an incorrect class. While debugging, I traced it back to this being `Blendshape` where `Geometry` was expected. This is likely because this node describes a `Geometry`, which is used as a blendshape. I'm not sure if any other DCC tools or places to import it expect `Blendshape` instead (i.e. was this code ever tested?), but it fixes its use in Blender. Co-authored-by: Kim Kulling --- code/AssetLib/FBX/FBXExporter.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/code/AssetLib/FBX/FBXExporter.cpp b/code/AssetLib/FBX/FBXExporter.cpp index 873179f4c..7527d3fc7 100644 --- a/code/AssetLib/FBX/FBXExporter.cpp +++ b/code/AssetLib/FBX/FBXExporter.cpp @@ -1748,7 +1748,7 @@ void FBXExporter::WriteObjects () int64_t blendshape_uid = generate_uid(); mesh_uids.push_back(blendshape_uid); bsnode.AddProperty(blendshape_uid); - bsnode.AddProperty(blendshape_name + FBX::SEPARATOR + "Blendshape"); + bsnode.AddProperty(blendshape_name + FBX::SEPARATOR + "Geometry"); bsnode.AddProperty("Shape"); bsnode.AddChild("Version", int32_t(100)); bsnode.Begin(outstream, binary, indent); From 2d98f6a880a6d10b7bab9874feb60e9834cf4b86 Mon Sep 17 00:00:00 2001 From: fvbj Date: Tue, 6 Feb 2024 21:24:41 +0100 Subject: [PATCH 41/77] Fix identity matrix check (#5445) * Fix identity matrix check Adds an extra epsilon value to check the matrix4x4 identity. The method is also used to export to GLTF/GLTF2 format to check node transformation matrices. The epsilon value can be set using AI_CONFIG_CHECK_IDENTITY_MATRIX_EPSILON with the default value set to 10e-3f for backward compatibility of legacy code. * Fix type of float values in the unit test * Update matrix4x4.inl Fix typo * Update matrix4x4.inl Remove dead code. * Add isIdentity-Test * Update AssimpAPITest_aiMatrix4x4.cpp --------- Co-authored-by: Kim Kulling --- code/AssetLib/glTF/glTFExporter.cpp | 9 +++++++-- code/AssetLib/glTF/glTFExporter.h | 3 +++ code/AssetLib/glTF2/glTF2Exporter.cpp | 9 +++++++-- code/AssetLib/glTF2/glTF2Exporter.h | 2 ++ include/assimp/config.h.in | 15 +++++++++++++++ include/assimp/matrix4x4.h | 6 +++++- include/assimp/matrix4x4.inl | 11 ++++------- test/unit/AssimpAPITest_aiMatrix4x4.cpp | 11 +++++++---- test/unit/utMatrix4x4.cpp | 14 ++++++++++++++ test/unit/utglTF2ImportExport.cpp | 24 ++++++++++++++++++++++++ 10 files changed, 88 insertions(+), 16 deletions(-) diff --git a/code/AssetLib/glTF/glTFExporter.cpp b/code/AssetLib/glTF/glTFExporter.cpp index 91d88f1ae..9b44578c0 100644 --- a/code/AssetLib/glTF/glTFExporter.cpp +++ b/code/AssetLib/glTF/glTFExporter.cpp @@ -56,6 +56,7 @@ OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. #include #include #include +#include // Header files, standard library. #include @@ -113,6 +114,10 @@ glTFExporter::glTFExporter(const char* filename, IOSystem* pIOSystem, const aiSc mAsset = std::make_shared(pIOSystem); + configEpsilon = mProperties->GetPropertyFloat( + AI_CONFIG_CHECK_IDENTITY_MATRIX_EPSILON, + (ai_real)AI_CONFIG_CHECK_IDENTITY_MATRIX_EPSILON_DEFAULT); + if (isBinary) { mAsset->SetAsBinary(); } @@ -824,7 +829,7 @@ unsigned int glTFExporter::ExportNodeHierarchy(const aiNode* n) { Ref node = mAsset->nodes.Create(mAsset->FindUniqueID(n->mName.C_Str(), "node")); - if (!n->mTransformation.IsIdentity()) { + if (!n->mTransformation.IsIdentity(configEpsilon)) { node->matrix.isPresent = true; CopyValue(n->mTransformation, node->matrix.value); } @@ -851,7 +856,7 @@ unsigned int glTFExporter::ExportNode(const aiNode* n, Ref& parent) node->parent = parent; - if (!n->mTransformation.IsIdentity()) { + if (!n->mTransformation.IsIdentity(configEpsilon)) { node->matrix.isPresent = true; CopyValue(n->mTransformation, node->matrix.value); } diff --git a/code/AssetLib/glTF/glTFExporter.h b/code/AssetLib/glTF/glTFExporter.h index a52695402..1d036509c 100644 --- a/code/AssetLib/glTF/glTFExporter.h +++ b/code/AssetLib/glTF/glTFExporter.h @@ -50,6 +50,7 @@ OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. #include #include +#include #include #include @@ -98,6 +99,8 @@ private: std::vector mBodyData; + ai_real configEpsilon; + void WriteBinaryData(IOStream *outfile, std::size_t sceneLength); void GetTexSampler(const aiMaterial *mat, glTF::TexProperty &prop); diff --git a/code/AssetLib/glTF2/glTF2Exporter.cpp b/code/AssetLib/glTF2/glTF2Exporter.cpp index 17d162466..20a1f7ae9 100644 --- a/code/AssetLib/glTF2/glTF2Exporter.cpp +++ b/code/AssetLib/glTF2/glTF2Exporter.cpp @@ -55,6 +55,7 @@ OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. #include #include #include +#include // Header files, standard library. #include @@ -90,6 +91,10 @@ glTF2Exporter::glTF2Exporter(const char *filename, IOSystem *pIOSystem, const ai // Always on as our triangulation process is aware of this type of encoding mAsset->extensionsUsed.FB_ngon_encoding = true; + configEpsilon = mProperties->GetPropertyFloat( + AI_CONFIG_CHECK_IDENTITY_MATRIX_EPSILON, + (ai_real)AI_CONFIG_CHECK_IDENTITY_MATRIX_EPSILON_DEFAULT); + if (isBinary) { mAsset->SetAsBinary(); } @@ -1455,7 +1460,7 @@ unsigned int glTF2Exporter::ExportNodeHierarchy(const aiNode *n) { node->name = n->mName.C_Str(); - if (!n->mTransformation.IsIdentity()) { + if (!n->mTransformation.IsIdentity(configEpsilon)) { node->matrix.isPresent = true; CopyValue(n->mTransformation, node->matrix.value); } @@ -1485,7 +1490,7 @@ unsigned int glTF2Exporter::ExportNode(const aiNode *n, Ref &parent) { ExportNodeExtras(n->mMetaData, node->extras); - if (!n->mTransformation.IsIdentity()) { + if (!n->mTransformation.IsIdentity(configEpsilon)) { if (mScene->mNumAnimations > 0 || (mProperties && mProperties->HasPropertyBool("GLTF2_NODE_IN_TRS"))) { aiQuaternion quaternion; n->mTransformation.Decompose(*reinterpret_cast(&node->scale.value), quaternion, *reinterpret_cast(&node->translation.value)); diff --git a/code/AssetLib/glTF2/glTF2Exporter.h b/code/AssetLib/glTF2/glTF2Exporter.h index 7bf57b567..47b668de7 100644 --- a/code/AssetLib/glTF2/glTF2Exporter.h +++ b/code/AssetLib/glTF2/glTF2Exporter.h @@ -49,6 +49,7 @@ OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. #include #include +#include #include #include @@ -142,6 +143,7 @@ private: std::map mTexturesByPath; std::shared_ptr mAsset; std::vector mBodyData; + ai_real configEpsilon; }; } // namespace Assimp diff --git a/include/assimp/config.h.in b/include/assimp/config.h.in index cb46d8057..403ddb32a 100644 --- a/include/assimp/config.h.in +++ b/include/assimp/config.h.in @@ -225,6 +225,21 @@ OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. #define AI_CONFIG_PP_PTV_ROOT_TRANSFORMATION \ "PP_PTV_ROOT_TRANSFORMATION" +// --------------------------------------------------------------------------- +/** @brief Set epsilon to check the identity of the matrix 4x4. + * + * This is used by aiMatrix4x4t::IsIdentity(const TReal epsilon). + * @note The default value is 10e-3f for backward compatibility of legacy code. + * Property type: Float. + */ +#define AI_CONFIG_CHECK_IDENTITY_MATRIX_EPSILON \ + "CHECK_IDENTITY_MATRIX_EPSILON" + +// default value for AI_CONFIG_CHECK_IDENTITY_MATRIX_EPSILON +#if (!defined AI_CONFIG_CHECK_IDENTITY_MATRIX_EPSILON_DEFAULT) +# define AI_CONFIG_CHECK_IDENTITY_MATRIX_EPSILON_DEFAULT 10e-3f +#endif + // --------------------------------------------------------------------------- /** @brief Configures the #aiProcess_FindDegenerates step to * remove degenerated primitives from the import - immediately. diff --git a/include/assimp/matrix4x4.h b/include/assimp/matrix4x4.h index 67e0e356e..7de59c706 100644 --- a/include/assimp/matrix4x4.h +++ b/include/assimp/matrix4x4.h @@ -136,9 +136,13 @@ public: // ------------------------------------------------------------------- /** @brief Returns true of the matrix is the identity matrix. + * @param epsilon Value of epsilon. Default value is 10e-3 for backward + * compatibility with legacy code. + * @return Returns true of the matrix is the identity matrix. * The check is performed against a not so small epsilon. */ - inline bool IsIdentity() const; + inline bool IsIdentity(const TReal + epsilon = AI_CONFIG_CHECK_IDENTITY_MATRIX_EPSILON_DEFAULT) const; // ------------------------------------------------------------------- /** @brief Decompose a trafo matrix into its original components diff --git a/include/assimp/matrix4x4.inl b/include/assimp/matrix4x4.inl index 54d176d18..56f7296e5 100644 --- a/include/assimp/matrix4x4.inl +++ b/include/assimp/matrix4x4.inl @@ -3,7 +3,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 @@ aiMatrix4x4t& aiMatrix4x4t::Inverse() { const TReal det = Determinant(); if(det == static_cast(0.0)) { - // Matrix not invertible. Setting all elements to nan is not really + // Matrix is not invertible. Setting all elements to nan is not really // correct in a mathematical sense but it is easy to debug for the // programmer. const TReal nan = std::numeric_limits::quiet_NaN(); @@ -545,10 +545,7 @@ aiMatrix4x4t& aiMatrix4x4t::FromEulerAnglesXYZ(TReal x, TReal y, T // ---------------------------------------------------------------------------------------- template AI_FORCE_INLINE -bool aiMatrix4x4t::IsIdentity() const { - // Use a small epsilon to solve floating-point inaccuracies - const static TReal epsilon = 10e-3f; - +bool aiMatrix4x4t::IsIdentity(const TReal epsilon) const { return (a2 <= epsilon && a2 >= -epsilon && a3 <= epsilon && a3 >= -epsilon && a4 <= epsilon && a4 >= -epsilon && @@ -657,7 +654,7 @@ aiMatrix4x4t& aiMatrix4x4t::Scaling( const aiVector3t& v, a /** A function for creating a rotation matrix that rotates a vector called * "from" into another vector called "to". * Input : from[3], to[3] which both must be *normalized* non-zero vectors - * Output: mtx[3][3] -- a 3x3 matrix in colum-major form + * Output: mtx[3][3] -- a 3x3 matrix in column-major form * Authors: Tomas Möller, John Hughes * "Efficiently Building a Matrix to Rotate One Vector to Another" * Journal of Graphics Tools, 4(4):1-4, 1999 diff --git a/test/unit/AssimpAPITest_aiMatrix4x4.cpp b/test/unit/AssimpAPITest_aiMatrix4x4.cpp index 9372bd9c4..2f17ea2ad 100644 --- a/test/unit/AssimpAPITest_aiMatrix4x4.cpp +++ b/test/unit/AssimpAPITest_aiMatrix4x4.cpp @@ -3,9 +3,7 @@ Open Asset Import Library (assimp) --------------------------------------------------------------------------- -Copyright (c) 2006-2022, assimp team - - +Copyright (c) 2006-2024, assimp team All rights reserved. @@ -47,7 +45,7 @@ using namespace Assimp; class AssimpAPITest_aiMatrix4x4 : public AssimpMathTest { protected: - virtual void SetUp() { + void SetUp() override { result_c = result_cpp = aiMatrix4x4(); } @@ -64,6 +62,11 @@ protected: aiMatrix4x4 result_c, result_cpp; }; +TEST_F(AssimpAPITest_aiMatrix4x4, isIdendityTest) { + aiMatrix4x4 m = aiMatrix4x4(1.001f, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1); + EXPECT_TRUE(m.IsIdentity(1e-3f)); +} + TEST_F(AssimpAPITest_aiMatrix4x4, aiIdentityMatrix4Test) { // Force a non-identity matrix. result_c = aiMatrix4x4(0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0); diff --git a/test/unit/utMatrix4x4.cpp b/test/unit/utMatrix4x4.cpp index 795971afc..86a70bfe4 100644 --- a/test/unit/utMatrix4x4.cpp +++ b/test/unit/utMatrix4x4.cpp @@ -90,3 +90,17 @@ TEST_F(utMatrix4x4, indexOperatorTest) { ai_real *a15 = a12 + 3; EXPECT_FLOAT_EQ(1.0, *a15); } + +TEST_F(utMatrix4x4, identityMatrixTest) { + aiMatrix4x4 m1 = aiMatrix4x4(1.f,0,0,0, 0,1,0,0, 0,0,1,0, 0,0,0, 1); + EXPECT_TRUE(m1.IsIdentity()); + aiMatrix4x4 m2 = aiMatrix4x4(1.02f,0,0,0, 0,1,0,0, 0,0,1,0, 0,0,0, 1); + EXPECT_FALSE(m2.IsIdentity()); + aiMatrix4x4 m3 = aiMatrix4x4(1.009f,0,0,0, 0,1,0,0, 0,0,1,0, 0,0,0, 1); + EXPECT_TRUE(m3.IsIdentity()); + + EXPECT_TRUE(m1.IsIdentity(1e-3f)); + EXPECT_FALSE(m2.IsIdentity(1e-3f)); + EXPECT_TRUE(m2.IsIdentity(1e-1f)); + EXPECT_FALSE(m3.IsIdentity(1e-3f)); +} diff --git a/test/unit/utglTF2ImportExport.cpp b/test/unit/utglTF2ImportExport.cpp index 6778e2679..478f75666 100644 --- a/test/unit/utglTF2ImportExport.cpp +++ b/test/unit/utglTF2ImportExport.cpp @@ -988,3 +988,27 @@ TEST_F(utglTF2ImportExport, noSchemaFound) { EXPECT_NE(scene, nullptr); EXPECT_STREQ(importer.GetErrorString(), ""); } + +// ------------------------------------------------------------------------------------------------ +TEST_F(utglTF2ImportExport, testSetIdentityMatrixEpsilon) { +// Assimp::Exporter exporter; + Assimp::ExportProperties properties = Assimp::ExportProperties(); + EXPECT_EQ(AI_CONFIG_CHECK_IDENTITY_MATRIX_EPSILON_DEFAULT, + properties.GetPropertyFloat("CHECK_IDENTITY_MATRIX_EPSILON", + AI_CONFIG_CHECK_IDENTITY_MATRIX_EPSILON_DEFAULT)); + aiMatrix4x4 m; + m = aiMatrix4x4(1.02f, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1); + EXPECT_FALSE(m.IsIdentity()); + m = aiMatrix4x4(1.001f, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1); + EXPECT_TRUE(m.IsIdentity()); + + bool b = properties.SetPropertyFloat("CHECK_IDENTITY_MATRIX_EPSILON", 0.0001f); + EXPECT_TRUE(!b); + ai_real epsilon = properties.GetPropertyFloat("CHECK_IDENTITY_MATRIX_EPSILON", 0.01f); + EXPECT_EQ(0.0001f, epsilon); + m = aiMatrix4x4(1.0002f, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1); + EXPECT_FALSE(m.IsIdentity(epsilon)); + m = aiMatrix4x4(1.00009f, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1); + EXPECT_TRUE(m.IsIdentity(epsilon)); +} + From ff5b0ae575082fcd10b9c887390c321a110d2051 Mon Sep 17 00:00:00 2001 From: Emily Banerjee Date: Thu, 8 Feb 2024 19:46:36 +0000 Subject: [PATCH 42/77] Fix PyAssimp under Python >= 3.12 and macOS library search support (#5397) * Fix PyAssimp under Python >= 3.12 * Make PyAssimp search DYLD_LIBRARY_PATH under macOS --------- Co-authored-by: Kim Kulling --- port/PyAssimp/pyassimp/helper.py | 12 ++++++++++-- 1 file changed, 10 insertions(+), 2 deletions(-) diff --git a/port/PyAssimp/pyassimp/helper.py b/port/PyAssimp/pyassimp/helper.py index 7c14f6097..0ae7cbdff 100644 --- a/port/PyAssimp/pyassimp/helper.py +++ b/port/PyAssimp/pyassimp/helper.py @@ -5,13 +5,17 @@ Some fancy helper functions. """ import os +import platform import ctypes import operator -from distutils.sysconfig import get_python_lib import re import sys +have_distutils = sys.version_info[0] < 3 and sys.version_info[1] < 12 +if have_distutils: + from distutils.sysconfig import get_python_lib + try: import numpy except ImportError: numpy = None @@ -32,10 +36,14 @@ if os.name=='posix': if 'LD_LIBRARY_PATH' in os.environ: additional_dirs.extend([item for item in os.environ['LD_LIBRARY_PATH'].split(':') if item]) + + if platform.system() == 'Darwin': + if 'DYLD_LIBRARY_PATH' in os.environ: + additional_dirs.extend([item for item in os.environ['DYLD_LIBRARY_PATH'].split(':') if item]) # check if running from anaconda. anaconda_keywords = ("conda", "continuum") - if any(k in sys.version.lower() for k in anaconda_keywords): + if have_distutils and any(k in sys.version.lower() for k in anaconda_keywords): cur_path = get_python_lib() pattern = re.compile('.*\/lib\/') conda_lib = pattern.match(cur_path).group() From a3708e3464a156b188cbd4ee1e38a7a21d5acd7c Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?S=C3=A9verin=20Lemaignan?= Date: Wed, 14 Feb 2024 08:32:32 +0100 Subject: [PATCH 43/77] Add ISC LICENSE file (#5465) --- port/PyAssimp/LICENSE | 17 +++++++++++++++++ 1 file changed, 17 insertions(+) create mode 100644 port/PyAssimp/LICENSE diff --git a/port/PyAssimp/LICENSE b/port/PyAssimp/LICENSE new file mode 100644 index 000000000..91cf88d72 --- /dev/null +++ b/port/PyAssimp/LICENSE @@ -0,0 +1,17 @@ +ISC License + +Copyright 2024, pyassimp contributors + +Permission to use, copy, modify, and/or distribute this software +for any purpose with or without fee is hereby granted, provided +that the above copyright notice and this permission notice appear +in all copies. + +THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL +WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED +WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE +AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL +DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA +OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER +TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR +PERFORMANCE OF THIS SOFTWARE. From 4b9f46dbda5128d6d538d185eb69ad6a7b4b99ff Mon Sep 17 00:00:00 2001 From: Adam Mizerski Date: Thu, 15 Feb 2024 13:07:00 +0100 Subject: [PATCH 44/77] ColladaParser: check values length (#5462) * ColladaParser: check values length fixes: #4286 * Refactor calculation of size for data --------- Co-authored-by: Kim Kulling --- code/AssetLib/Collada/ColladaParser.cpp | 10 +- .../invalid/box_nested_animation_4286.dae | 196 ++++++++++++++++++ test/models/invalid/readme.txt | 3 + test/unit/utColladaImportExport.cpp | 8 + 4 files changed, 216 insertions(+), 1 deletion(-) create mode 100644 test/models/invalid/box_nested_animation_4286.dae diff --git a/code/AssetLib/Collada/ColladaParser.cpp b/code/AssetLib/Collada/ColladaParser.cpp index ee7a395d9..c5163fe39 100644 --- a/code/AssetLib/Collada/ColladaParser.cpp +++ b/code/AssetLib/Collada/ColladaParser.cpp @@ -3,7 +3,7 @@ Open Asset Import Library (assimp) --------------------------------------------------------------------------- -Copyright (c) 2006-2022, assimp team +Copyright (c) 2006-2024, assimp team All rights reserved. @@ -1786,6 +1786,10 @@ size_t ColladaParser::ReadPrimitives(XmlNode &node, Mesh &pMesh, std::vectormData) { acc->mData = &ResolveLibraryReference(mDataLibrary, acc->mSource); + const size_t dataSize = acc->mOffset + acc->mCount * acc->mStride; + if (dataSize > acc->mData->mValues.size()) { + throw DeadlyImportError("Not enough data for accessor"); + } } } // and the same for the per-index channels @@ -1810,6 +1814,10 @@ size_t ColladaParser::ReadPrimitives(XmlNode &node, Mesh &pMesh, std::vectormData) { acc->mData = &ResolveLibraryReference(mDataLibrary, acc->mSource); + const size_t dataSize = acc->mOffset + acc->mCount * acc->mStride; + if (dataSize > acc->mData->mValues.size()) { + throw DeadlyImportError("Not enough data for accessor"); + } } } diff --git a/test/models/invalid/box_nested_animation_4286.dae b/test/models/invalid/box_nested_animation_4286.dae new file mode 100644 index 000000000..2def61d20 --- /dev/null +++ b/test/models/invalid/box_nested_animation_4286.dae @@ -0,0 +1,196 @@ + + + + + Blender User + Blender 2.80.40 commit date:2019-01-07, commit time:23:37, hash:91a155833e59 + + 2019-01-08T17:44:11 + 2019-01-08T17:44:11 + + Z_UP + + + + + + + + 0.8 0.8 0.8 1 + + + 0 0.5 0 1 + + + + + + + + + + + + + + + + + 1 1 1 1 1 -1 1 -1 1 1 -1 -1 -1 1 1 -1 1 -1 -1 -1 1 -1 -1 -1 + + + + + + + + + + 0 0 1 0 -1 0 -1 0 0 0 0 -1 1 0 0 0 1 0 + + + + + + + + + + 0.625 0 0.375 0.25 0.375 0 0.625 0.25 0.375 0.5 0.375 0.25 0.625 0.5 0.375 0.75 0.375 0.5 0.625 0.75 0.375 1 0.375 0.75 0.375 0.5 0.125 0.75 0.125 0.5 0.875 0.5 0.625 0.75 0.625 0.5 0.625 0 0.625 0.25 0.375 0.25 0.625 0.25 0.625 0.5 0.375 0.5 0.625 0.5 0.625 0.75 0.375 0.75 0.625 0.75 0.625 1 0.375 1 0.375 0.5 0.375 0.75 0.125 0.75 0.875 0.5 0.875 0.75 0.625 0.75 + + + + + + + + + + + + + + + 3 3 3 3 3 3 3 3 3 3 3 3 +

    4 0 0 2 0 1 0 0 2 2 1 3 7 1 4 3 1 5 6 2 6 5 2 7 7 2 8 1 3 9 7 3 10 5 3 11 0 4 12 3 4 13 1 4 14 4 5 15 1 5 16 5 5 17 4 0 18 6 0 19 2 0 20 2 1 21 6 1 22 7 1 23 6 2 24 4 2 25 5 2 26 1 3 27 3 3 28 7 3 29 0 4 30 2 4 31 3 4 32 4 5 33 0 5 34 1 5 35

    +
    +
    +
    +
    + + + + 1 0 0 -1 0 1 0 1 0 0 1 1 0 0 0 1 + + Bone + + + + + + + + 0.7886752 0.2113248 0.5773504 -0.5773504 -0.5773503 0.5773503 0.5773503 1.154701 -0.2113249 -0.7886752 0.5773503 -0.5773502 0 0 0 1 + + + + + + + + 1 1 1 1 1 1 1 1 + + + + + + + + + + + + + + 1 1 1 1 1 1 1 1 + 0 0 0 1 0 2 0 3 0 4 0 5 0 6 0 7 + + + + + + + + + 0.04166662 0.08333331 0.125 0.1666666 0.2083333 0.25 0.2916666 0.3333333 0.375 0.4166666 0.4583333 0.5 0.5416667 0.5833333 0.625 0.6666667 0.7083333 0.75 0.7916667 0.8333333 0.875 0.9166667 0.9583333 1 1.041667 1.083333 1.125 1.166667 1.208333 1.25 1.291667 1.333333 1.375 1.416667 1.458333 1.5 1.541667 1.583333 1.625 1.666667 + + + + + + + + 1 0 0 1 0 1 0 -1 0 0 1 0 0 0 0 1 0.9999878 3.10816e-5 0.004935208 1 0 0.9999802 -0.006297799 -1 -0.004935306 0.006297722 0.999968 0 0 0 0 1 0.999819 4.61727e-4 0.01901668 1 0 0.9997054 -0.02427293 -1 -0.01902229 0.02426853 0.9995245 0 0 0 0 1 0.9991519 0.002163141 0.04111904 1 0 0.9986191 -0.05253414 -1 -0.04117589 0.05248959 0.9977722 0 0 0 0 1 0.9975264 0.006301912 0.07000974 1 0 0.9959731 -0.08965231 -1 -0.0702928 0.08943056 0.9935095 0 0 0 0 1 0.9944467 0.01411698 0.1042901 1 0 0.9909625 -0.1341392 -1 -0.1052413 0.1333943 0.9854594 0 0 0 0 1 0.9894527 0.02671701 0.1423712 1 0 0.9828442 -0.184438 -1 -0.1448563 0.1824927 0.9724778 0 0 0 0 1 0.9821799 0.04490547 0.1825 1 0 0.9710366 -0.2389307 -1 -0.1879434 0.234673 0.9537326 0 0 0 0 1 0.9724072 0.06904543 0.2228386 1 0 0.9551992 -0.2959637 -1 -0.2332902 0.2877972 0.9288425 0 0 0 0 1 0.9600915 0.09897761 0.261587 1 0 0.9352878 -0.3538882 -1 -0.2796861 0.339765 0.8979618 0 0 0 0 1 0.9453882 0.1340003 0.2971281 1 0 0.9115852 -0.4111113 -1 -0.3259466 0.3886598 0.8618018 0 0 0 0 1 0.9286572 0.1729132 0.328172 1 0 0.8847058 -0.4661497 -1 -0.3709391 0.4328933 0.8215885 0 0 0 0 1 0.9104556 0.2141147 0.3538722 1 0 0.8555763 -0.5176768 -1 -0.4136069 0.4713217 0.7789642 0 0 0 0 1 0.8915175 0.2557371 0.3738919 1 0 0.8253933 -0.5645581 -1 -0.4529863 0.5033134 0.7358525 0 0 0 0 1 0.8727233 0.2957927 0.388408 1 0 0.7955672 -0.6058654 -1 -0.4882152 0.5287529 0.6943099 0 0 0 0 1 0.8550603 0.332307 0.3980502 1 0 0.7676533 -0.6408653 -1 -0.5185286 0.5479785 0.6563899 0 0 0 0 1 0.8395769 0.3634188 0.4037789 1 0 0.7432778 -0.6689829 -1 -0.5432408 0.5616626 0.6240388 0 0 0 0 1 0.8273312 0.3874339 0.4067161 1 0 0.7240622 -0.6897347 -1 -0.5617144 0.5706391 0.5990393 0 0 0 0 1 0.8193359 0.4028329 0.4079393 1 0 0.7115462 -0.7026393 -1 -0.5733138 0.5756976 0.5829953 0 0 0 0 1 0.8164964 0.4082482 0.4082486 1 7.75722e-8 0.707107 -0.7071065 -1 -0.5773504 0.57735 0.5773503 0 0 0 0 1 0.8190646 0.4033515 0.4079717 1 7.78161e-8 0.7111219 -0.7030687 -1 -0.5737014 0.5758587 0.5824547 0 0 0 0 1 0.8263245 0.3893851 0.4068995 1 7.85059e-8 0.7224849 -0.6913868 -1 -0.5631944 0.5713098 0.5970069 0 0 0 0 1 0.8375081 0.3675125 0.4043696 1 7.95684e-8 0.7400277 -0.6725764 -1 -0.5464249 0.5632883 0.6197791 0 0 0 0 1 0.8517552 0.3390183 0.3994742 1 8.0922e-8 0.7624427 -0.6470557 -1 -0.5239399 0.5511332 0.6494145 0 0 0 0 1 0.8681612 0.3053284 0.3912425 1 8.24806e-8 0.7883466 -0.6152314 -1 -0.4962822 0.5341201 0.6844119 0 0 0 0 1 0.8858209 0.2680094 0.3788038 1 8.41584e-8 0.8163394 -0.5775725 -1 -0.4640273 0.5116258 0.7231305 0 0 0 0 1 0.9038687 0.2287352 0.3615268 1 8.58731e-8 0.8450637 -0.5346656 -1 -0.42781 0.4832675 0.7638266 0 0 0 0 1 0.9215156 0.1892192 0.339124 1 8.75496e-8 0.8732626 -0.4872499 -1 -0.3883413 0.4490085 0.8047251 0 0 0 0 1 0.9380813 0.1511175 0.3117163 1 8.91235e-8 0.899834 -0.4362323 -1 -0.3464153 0.4092214 0.8441175 0 0 0 0 1 0.9530206 0.1159168 0.2798482 1 9.05428e-8 0.9238796 -0.3826832 -1 -0.3029055 0.3647051 0.8804763 0 0 0 0 1 0.965943 0.08482374 0.2444564 1 9.17705e-8 0.9447417 -0.3278156 -1 -0.2587547 0.3166512 0.9125667 0 0 0 0 1 0.9766233 0.05867312 0.2067956 1 9.27852e-8 0.9620277 -0.2729518 -1 -0.2149581 0.2665711 0.9395387 0 0 0 0 1 0.9850019 0.03787052 0.1683363 1 9.35812e-8 0.975616 -0.2194843 -1 -0.1725436 0.2161924 0.9609836 0 0 0 0 1 0.991176 0.02237916 0.1306496 1 9.41678e-8 0.9856446 -0.1688333 -1 -0.1325524 0.1673435 0.9769473 0 0 0 0 1 0.9953793 0.01175384 0.09529842 1 9.45671e-8 0.9924796 -0.1224106 -1 -0.09602053 0.121845 0.9878936 0 0 0 0 1 0.997952 0.005218936 0.06375288 1 9.48115e-8 0.996666 -0.08159051 -1 -0.06396614 0.08142342 0.9946249 0 0 0 0 1 0.9993011 0.001782816 0.03733916 1 9.49397e-8 0.998862 -0.04769476 -1 -0.0373817 0.04766143 0.9981638 0 0 0 0 1 0.9998515 3.78837e-4 0.01722835 1 9.4992e-8 0.9997582 -0.02198936 -1 -0.01723252 0.0219861 0.9996098 0 0 0 0 1 0.99999 2.53135e-5 0.004462156 1 9.50052e-8 0.9999838 -0.00569412 -1 -0.004462227 0.005694063 0.9999738 0 0 0 0 1 1 0 0 2 0 1 0 -1 0 0 1 0 0 0 0 1 + + + + + + + + LINEAR LINEAR LINEAR LINEAR LINEAR LINEAR LINEAR LINEAR LINEAR LINEAR LINEAR LINEAR LINEAR LINEAR LINEAR LINEAR LINEAR LINEAR LINEAR LINEAR LINEAR LINEAR LINEAR LINEAR LINEAR LINEAR LINEAR LINEAR LINEAR LINEAR LINEAR LINEAR LINEAR LINEAR LINEAR LINEAR LINEAR LINEAR LINEAR LINEAR + + + + + + + + + + + + + + + + + + + 1 0 0 1 0 1 0 -1 0 0 1 0 0 0 0 1 + + 0.7886751 -0.5773503 -0.211325 0 0.2113248 0.5773503 -0.7886751 0 0.5773503 0.5773503 0.5773502 0 0 0 0 1 + + + 0 + -0.5235989 + -2 + 2 + 2 + + + + + 0 0 0 + 0 0 1 0 + 0 1 0 0 + 1 0 0 0 + 1 1 1 + + #Armature_Bone + + + + + + + + + + + + + + + +
    diff --git a/test/models/invalid/readme.txt b/test/models/invalid/readme.txt index 6ad8b4380..ad144ca36 100644 --- a/test/models/invalid/readme.txt +++ b/test/models/invalid/readme.txt @@ -18,6 +18,9 @@ crash. FILES ********************************************************* +box_nested_animation_4286.dae - This was reported as GH#4286. + The "count" parameter in "Cube-mesh-positions-array" is too small. + OutOfMemory.off - the number of faces is invalid. There won't be enough memory so std::vector::reserve() will most likely fail. The exception should be caught in Importer.cpp. diff --git a/test/unit/utColladaImportExport.cpp b/test/unit/utColladaImportExport.cpp index e2842732e..52a927b12 100644 --- a/test/unit/utColladaImportExport.cpp +++ b/test/unit/utColladaImportExport.cpp @@ -357,6 +357,14 @@ TEST_F(utColladaImportExport, exporterUniqueIdsTest) { ImportAsNames(outFileNamed, scene); } +// This file is invalid, we just want to ensure that the importer is not crashing +// This was reported as GH#4286. The "count" parameter in "Cube-mesh-positions-array" is too small. +TEST_F(utColladaImportExport, parseInvalid4286) { + Assimp::Importer importer; + const aiScene *scene = importer.ReadFile(ASSIMP_TEST_MODELS_DIR "/invalid/box_nested_animation_4286.dae", 0); + EXPECT_EQ(nullptr, scene); +} + #endif class utColladaZaeImportExport : public AbstractImportExportBase { From 94bc568d139880ba110ca8d438767ed0357d5491 Mon Sep 17 00:00:00 2001 From: Kim Kulling Date: Fri, 16 Feb 2024 15:21:49 +0100 Subject: [PATCH 45/77] Include defs in not cpp-section (#5466) - closes https://github.com/assimp/assimp/issues/5428 --- include/assimp/quaternion.h | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/include/assimp/quaternion.h b/include/assimp/quaternion.h index 7ab3ad6f8..457c650aa 100644 --- a/include/assimp/quaternion.h +++ b/include/assimp/quaternion.h @@ -2,7 +2,7 @@ Open Asset Import Library (assimp) ---------------------------------------------------------------------- -Copyright (c) 2006-2022, assimp team +Copyright (c) 2006-2024, assimp team All rights reserved. @@ -45,14 +45,14 @@ OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. #ifndef AI_QUATERNION_H_INC #define AI_QUATERNION_H_INC +#include + #ifdef __cplusplus #ifdef __GNUC__ # pragma GCC system_header #endif -#include - // Forward declarations template class aiVector3t; template class aiMatrix3x3t; From 4d6dd80257037921ba9dfe2b01c0fa0dadb98806 Mon Sep 17 00:00:00 2001 From: Kim Kulling Date: Thu, 22 Feb 2024 13:58:25 +0100 Subject: [PATCH 46/77] Add correct double zero check (#5471) * Add correct double zero check * Use std::fpclassify --- code/AssetLib/FBX/FBXExporter.cpp | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/code/AssetLib/FBX/FBXExporter.cpp b/code/AssetLib/FBX/FBXExporter.cpp index 7527d3fc7..50daf7996 100644 --- a/code/AssetLib/FBX/FBXExporter.cpp +++ b/code/AssetLib/FBX/FBXExporter.cpp @@ -69,6 +69,7 @@ OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. #include #include #include +#include // RESOURCES: // https://code.blender.org/2013/08/fbx-binary-file-format-specification/ @@ -1062,7 +1063,7 @@ aiMatrix4x4 get_world_transform(const aiNode* node, const aiScene* scene) } inline int64_t to_ktime(double ticks, const aiAnimation* anim) { - if (anim->mTicksPerSecond <= 0) { + if (FP_ZERO == std::fpclassify(anim->mTicksPerSecond)) { return static_cast(ticks) * FBX::SECOND; } return (static_cast(ticks / anim->mTicksPerSecond)) * FBX::SECOND; From 06648827635cbf52fe93eb153975913cd568e746 Mon Sep 17 00:00:00 2001 From: Kim Kulling Date: Fri, 23 Feb 2024 11:30:37 +0100 Subject: [PATCH 47/77] Add zlib-header to ZipArchiveIOSystem.h (#5473) - closes https://github.com/assimp/assimp/issues/5430 --- include/assimp/ZipArchiveIOSystem.h | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/include/assimp/ZipArchiveIOSystem.h b/include/assimp/ZipArchiveIOSystem.h index 9f3a4783b..8145e98f8 100644 --- a/include/assimp/ZipArchiveIOSystem.h +++ b/include/assimp/ZipArchiveIOSystem.h @@ -3,9 +3,7 @@ Open Asset Import Library (assimp) --------------------------------------------------------------------------- -Copyright (c) 2006-2022, assimp team - - +Copyright (c) 2006-2024, assimp team All rights reserved. @@ -55,6 +53,7 @@ OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. #include #include +#include namespace Assimp { From 01231d0e6001f555c81dcfcc6c581fa5797ccac9 Mon Sep 17 00:00:00 2001 From: Kim Kulling Date: Fri, 23 Feb 2024 22:30:05 +0100 Subject: [PATCH 48/77] Add 2024 to copyright infos (#5475) --- CMakeLists.txt | 2 +- code/AssetLib/3DS/3DSConverter.cpp | 2 +- code/AssetLib/3DS/3DSExporter.cpp | 2 +- code/AssetLib/3DS/3DSExporter.h | 2 +- code/AssetLib/3DS/3DSHelper.h | 2 +- code/AssetLib/3DS/3DSLoader.cpp | 2 +- code/AssetLib/3DS/3DSLoader.h | 2 +- code/AssetLib/3MF/3MFTypes.h | 2 +- code/AssetLib/3MF/3MFXmlTags.h | 2 +- code/AssetLib/3MF/D3MFExporter.cpp | 2 +- code/AssetLib/3MF/D3MFExporter.h | 2 +- code/AssetLib/3MF/D3MFImporter.cpp | 2 +- code/AssetLib/3MF/D3MFImporter.h | 2 +- code/AssetLib/3MF/D3MFOpcPackage.cpp | 2 +- code/AssetLib/3MF/D3MFOpcPackage.h | 2 +- code/AssetLib/3MF/XmlSerializer.cpp | 2 +- code/AssetLib/3MF/XmlSerializer.h | 2 +- code/AssetLib/AC/ACLoader.cpp | 2 +- code/AssetLib/AMF/AMFImporter.cpp | 2 +- code/AssetLib/AMF/AMFImporter.hpp | 2 +- code/AssetLib/AMF/AMFImporter_Geometry.cpp | 2 +- code/AssetLib/AMF/AMFImporter_Material.cpp | 2 +- code/AssetLib/AMF/AMFImporter_Node.hpp | 2 +- code/AssetLib/AMF/AMFImporter_Postprocess.cpp | 2 +- code/AssetLib/ASE/ASELoader.cpp | 2 +- code/AssetLib/ASE/ASELoader.h | 2 +- code/AssetLib/ASE/ASEParser.cpp | 2 +- code/AssetLib/ASE/ASEParser.h | 2 +- code/AssetLib/Assbin/AssbinExporter.cpp | 2 +- code/AssetLib/Assbin/AssbinExporter.h | 2 +- code/AssetLib/Assbin/AssbinFileWriter.cpp | 2 +- code/AssetLib/Assbin/AssbinFileWriter.h | 2 +- code/AssetLib/Assbin/AssbinLoader.cpp | 2 +- code/AssetLib/Assbin/AssbinLoader.h | 2 +- code/AssetLib/Assxml/AssxmlExporter.cpp | 2 +- code/AssetLib/Assxml/AssxmlExporter.h | 2 +- code/AssetLib/Assxml/AssxmlFileWriter.cpp | 2 +- code/AssetLib/Assxml/AssxmlFileWriter.h | 2 +- code/AssetLib/B3D/B3DImporter.cpp | 2 +- code/AssetLib/B3D/B3DImporter.h | 2 +- code/AssetLib/BVH/BVHLoader.cpp | 2 +- code/AssetLib/BVH/BVHLoader.h | 2 +- code/AssetLib/Blender/BlenderBMesh.cpp | 2 +- code/AssetLib/Blender/BlenderBMesh.h | 2 +- code/AssetLib/Blender/BlenderDNA.cpp | 2 +- code/AssetLib/Blender/BlenderDNA.h | 2 +- code/AssetLib/Blender/BlenderDNA.inl | 2 +- code/AssetLib/Blender/BlenderIntermediate.h | 2 +- code/AssetLib/Blender/BlenderLoader.cpp | 2 +- code/AssetLib/Blender/BlenderLoader.h | 2 +- code/AssetLib/Blender/BlenderModifier.cpp | 2 +- code/AssetLib/Blender/BlenderModifier.h | 2 +- code/AssetLib/Blender/BlenderScene.h | 2 +- code/AssetLib/Blender/BlenderTessellator.cpp | 2 +- code/AssetLib/Blender/BlenderTessellator.h | 2 +- code/AssetLib/COB/COBLoader.cpp | 2 +- code/AssetLib/COB/COBLoader.h | 2 +- code/AssetLib/COB/COBScene.h | 2 +- code/AssetLib/CSM/CSMLoader.cpp | 2 +- code/AssetLib/CSM/CSMLoader.h | 2 +- code/AssetLib/Collada/ColladaExporter.cpp | 2 +- code/AssetLib/Collada/ColladaExporter.h | 2 +- code/AssetLib/Collada/ColladaHelper.cpp | 2 +- code/AssetLib/Collada/ColladaHelper.h | 2 +- code/AssetLib/Collada/ColladaLoader.cpp | 2 +- code/AssetLib/Collada/ColladaLoader.h | 2 +- code/AssetLib/Collada/ColladaParser.h | 2 +- code/AssetLib/DXF/DXFHelper.h | 2 +- code/AssetLib/DXF/DXFLoader.h | 2 +- code/AssetLib/FBX/FBXAnimation.cpp | 2 +- code/AssetLib/FBX/FBXBinaryTokenizer.cpp | 2 +- code/AssetLib/FBX/FBXCommon.h | 2 +- code/AssetLib/FBX/FBXCompileConfig.h | 2 +- code/AssetLib/FBX/FBXConverter.cpp | 2 +- code/AssetLib/FBX/FBXConverter.h | 2 +- code/AssetLib/FBX/FBXDeformer.cpp | 2 +- code/AssetLib/FBX/FBXDocument.cpp | 2 +- code/AssetLib/FBX/FBXDocument.h | 2 +- code/AssetLib/FBX/FBXDocumentUtil.cpp | 2 +- code/AssetLib/FBX/FBXExportNode.cpp | 2 +- code/AssetLib/FBX/FBXExportNode.h | 2 +- code/AssetLib/FBX/FBXExportProperty.cpp | 2 +- code/AssetLib/FBX/FBXExportProperty.h | 2 +- code/AssetLib/FBX/FBXExporter.cpp | 2 +- code/AssetLib/FBX/FBXExporter.h | 2 +- code/AssetLib/FBX/FBXImportSettings.h | 2 +- code/AssetLib/FBX/FBXImporter.cpp | 2 +- code/AssetLib/FBX/FBXImporter.h | 2 +- code/AssetLib/FBX/FBXMaterial.cpp | 2 +- code/AssetLib/FBX/FBXMeshGeometry.cpp | 2 +- code/AssetLib/FBX/FBXMeshGeometry.h | 2 +- code/AssetLib/FBX/FBXModel.cpp | 2 +- code/AssetLib/FBX/FBXNodeAttribute.cpp | 2 +- code/AssetLib/FBX/FBXParser.cpp | 2 +- code/AssetLib/FBX/FBXParser.h | 2 +- code/AssetLib/FBX/FBXProperties.cpp | 2 +- code/AssetLib/FBX/FBXProperties.h | 2 +- code/AssetLib/FBX/FBXTokenizer.cpp | 2 +- code/AssetLib/FBX/FBXTokenizer.h | 2 +- code/AssetLib/FBX/FBXUtil.cpp | 2 +- code/AssetLib/FBX/FBXUtil.h | 2 +- code/AssetLib/HMP/HMPFileData.h | 2 +- code/AssetLib/HMP/HMPLoader.cpp | 2 +- code/AssetLib/HMP/HMPLoader.h | 2 +- code/AssetLib/HMP/HalfLifeFileData.h | 2 +- code/AssetLib/IFC/IFCBoolean.cpp | 2 +- code/AssetLib/IFC/IFCCurve.cpp | 2 +- code/AssetLib/IFC/IFCGeometry.cpp | 2 +- code/AssetLib/IFC/IFCLoader.cpp | 2 +- code/AssetLib/IFC/IFCLoader.h | 2 +- code/AssetLib/IFC/IFCMaterial.cpp | 2 +- code/AssetLib/IFC/IFCOpenings.cpp | 2 +- code/AssetLib/IFC/IFCProfile.cpp | 2 +- code/AssetLib/IFC/IFCUtil.cpp | 2 +- code/AssetLib/IFC/IFCUtil.h | 2 +- code/AssetLib/Irr/IRRLoader.cpp | 2 +- code/AssetLib/Irr/IRRLoader.h | 2 +- code/AssetLib/Irr/IRRShared.cpp | 2 +- code/AssetLib/LWO/LWOAnimation.cpp | 2 +- code/AssetLib/LWO/LWOAnimation.h | 2 +- code/AssetLib/LWO/LWOBLoader.cpp | 2 +- code/AssetLib/LWO/LWOFileData.h | 2 +- code/AssetLib/LWO/LWOLoader.cpp | 2 +- code/AssetLib/LWO/LWOLoader.h | 2 +- code/AssetLib/LWO/LWOMaterial.cpp | 2 +- code/AssetLib/LWS/LWSLoader.h | 2 +- code/AssetLib/M3D/M3DExporter.cpp | 2 +- code/AssetLib/M3D/M3DExporter.h | 2 +- code/AssetLib/M3D/M3DImporter.cpp | 2 +- code/AssetLib/M3D/M3DImporter.h | 2 +- code/AssetLib/M3D/M3DMaterials.h | 2 +- code/AssetLib/M3D/M3DWrapper.cpp | 2 +- code/AssetLib/M3D/M3DWrapper.h | 2 +- code/AssetLib/MD2/MD2FileData.h | 2 +- code/AssetLib/MD2/MD2Loader.cpp | 2 +- code/AssetLib/MD2/MD2Loader.h | 2 +- code/AssetLib/MD2/MD2NormalTable.h | 2 +- code/AssetLib/MD3/MD3FileData.h | 2 +- code/AssetLib/MD3/MD3Loader.cpp | 2 +- code/AssetLib/MD3/MD3Loader.h | 2 +- code/AssetLib/MD5/MD5Loader.cpp | 2 +- code/AssetLib/MDC/MDCFileData.h | 2 +- code/AssetLib/MDC/MDCLoader.cpp | 2 +- code/AssetLib/MDC/MDCLoader.h | 2 +- code/AssetLib/MDL/HalfLife/HL1FileData.h | 2 +- code/AssetLib/MDL/HalfLife/HL1ImportDefinitions.h | 2 +- code/AssetLib/MDL/HalfLife/HL1ImportSettings.h | 2 +- code/AssetLib/MDL/HalfLife/HL1MDLLoader.cpp | 2 +- code/AssetLib/MDL/HalfLife/HL1MDLLoader.h | 2 +- code/AssetLib/MDL/HalfLife/HL1MeshTrivert.h | 2 +- code/AssetLib/MDL/HalfLife/HalfLifeMDLBaseHeader.h | 2 +- code/AssetLib/MDL/HalfLife/LogFunctions.h | 2 +- code/AssetLib/MDL/HalfLife/UniqueNameGenerator.cpp | 2 +- code/AssetLib/MDL/HalfLife/UniqueNameGenerator.h | 2 +- code/AssetLib/MDL/MDLDefaultColorMap.h | 2 +- code/AssetLib/MDL/MDLFileData.h | 2 +- code/AssetLib/MDL/MDLLoader.cpp | 2 +- code/AssetLib/MDL/MDLLoader.h | 2 +- code/AssetLib/MDL/MDLMaterialLoader.cpp | 2 +- code/AssetLib/MMD/MMDCpp14.h | 2 +- code/AssetLib/MMD/MMDImporter.cpp | 2 +- code/AssetLib/MMD/MMDImporter.h | 2 +- code/AssetLib/MMD/MMDPmdParser.h | 2 +- code/AssetLib/MMD/MMDPmxParser.cpp | 2 +- code/AssetLib/MMD/MMDPmxParser.h | 2 +- code/AssetLib/MMD/MMDVmdParser.h | 2 +- code/AssetLib/MS3D/MS3DLoader.cpp | 2 +- code/AssetLib/MS3D/MS3DLoader.h | 2 +- code/AssetLib/NDO/NDOLoader.cpp | 2 +- code/AssetLib/NDO/NDOLoader.h | 2 +- code/AssetLib/NFF/NFFLoader.cpp | 2 +- code/AssetLib/NFF/NFFLoader.h | 2 +- code/AssetLib/OFF/OFFLoader.cpp | 2 +- code/AssetLib/OFF/OFFLoader.h | 2 +- code/AssetLib/Obj/ObjFileData.h | 2 +- code/AssetLib/Obj/ObjFileImporter.cpp | 2 +- code/AssetLib/Obj/ObjFileParser.cpp | 2 +- code/AssetLib/Obj/ObjTools.h | 2 +- code/AssetLib/Ogre/OgreBinarySerializer.cpp | 2 +- code/AssetLib/Ogre/OgreBinarySerializer.h | 2 +- code/AssetLib/Ogre/OgreImporter.cpp | 2 +- code/AssetLib/Ogre/OgreImporter.h | 2 +- code/AssetLib/Ogre/OgreMaterial.cpp | 2 +- code/AssetLib/Ogre/OgreParsingUtils.h | 2 +- code/AssetLib/Ogre/OgreStructs.cpp | 2 +- code/AssetLib/Ogre/OgreStructs.h | 2 +- code/AssetLib/Ogre/OgreXmlSerializer.cpp | 2 +- code/AssetLib/Ogre/OgreXmlSerializer.h | 2 +- code/AssetLib/OpenGEX/OpenGEXExporter.cpp | 2 +- code/AssetLib/OpenGEX/OpenGEXExporter.h | 2 +- code/AssetLib/OpenGEX/OpenGEXImporter.cpp | 2 +- code/AssetLib/OpenGEX/OpenGEXImporter.h | 2 +- code/AssetLib/OpenGEX/OpenGEXStructs.h | 2 +- code/AssetLib/Ply/PlyExporter.cpp | 2 +- code/AssetLib/Ply/PlyExporter.h | 2 +- code/AssetLib/Ply/PlyLoader.cpp | 2 +- code/AssetLib/Ply/PlyLoader.h | 2 +- code/AssetLib/Ply/PlyParser.cpp | 2 +- code/AssetLib/Ply/PlyParser.h | 2 +- code/AssetLib/Q3BSP/Q3BSPFileData.h | 2 +- code/AssetLib/Q3BSP/Q3BSPFileImporter.cpp | 2 +- code/AssetLib/Q3BSP/Q3BSPFileImporter.h | 2 +- code/AssetLib/Q3BSP/Q3BSPFileParser.cpp | 2 +- code/AssetLib/Q3BSP/Q3BSPFileParser.h | 2 +- code/AssetLib/Q3D/Q3DLoader.cpp | 2 +- code/AssetLib/Q3D/Q3DLoader.h | 2 +- code/AssetLib/Raw/RawLoader.cpp | 2 +- code/AssetLib/Raw/RawLoader.h | 2 +- code/AssetLib/SIB/SIBImporter.cpp | 2 +- code/AssetLib/SIB/SIBImporter.h | 2 +- code/AssetLib/SMD/SMDLoader.cpp | 2 +- code/AssetLib/SMD/SMDLoader.h | 2 +- code/AssetLib/STEPParser/STEPFileEncoding.cpp | 2 +- code/AssetLib/STEPParser/STEPFileEncoding.h | 2 +- code/AssetLib/STEPParser/STEPFileReader.cpp | 2 +- code/AssetLib/STEPParser/STEPFileReader.h | 2 +- code/AssetLib/STL/STLExporter.cpp | 2 +- code/AssetLib/STL/STLExporter.h | 2 +- code/AssetLib/STL/STLLoader.cpp | 2 +- code/AssetLib/STL/STLLoader.h | 2 +- code/AssetLib/Step/STEPFile.h | 2 +- code/AssetLib/Step/StepExporter.cpp | 2 +- code/AssetLib/Step/StepExporter.h | 2 +- code/AssetLib/Terragen/TerragenLoader.cpp | 2 +- code/AssetLib/Terragen/TerragenLoader.h | 2 +- code/AssetLib/Unreal/UnrealLoader.cpp | 2 +- code/AssetLib/Unreal/UnrealLoader.h | 2 +- code/AssetLib/X/XFileExporter.cpp | 2 +- code/AssetLib/X/XFileExporter.h | 2 +- code/AssetLib/X/XFileHelper.h | 2 +- code/AssetLib/X/XFileImporter.cpp | 2 +- code/AssetLib/X/XFileImporter.h | 2 +- code/AssetLib/X/XFileParser.cpp | 2 +- code/AssetLib/X/XFileParser.h | 2 +- code/AssetLib/X3D/X3DImporter.cpp | 2 +- code/AssetLib/X3D/X3DImporter.hpp | 2 +- code/AssetLib/X3D/X3DImporter_Geometry2D.cpp | 2 +- code/AssetLib/XGL/XGLLoader.cpp | 2 +- code/AssetLib/XGL/XGLLoader.h | 2 +- code/AssetLib/glTF/glTFAsset.h | 2 +- code/AssetLib/glTF/glTFAsset.inl | 2 +- code/AssetLib/glTF/glTFAssetWriter.h | 2 +- code/AssetLib/glTF/glTFAssetWriter.inl | 2 +- code/AssetLib/glTF/glTFCommon.cpp | 2 +- code/AssetLib/glTF/glTFCommon.h | 2 +- code/AssetLib/glTF/glTFExporter.cpp | 2 +- code/AssetLib/glTF/glTFExporter.h | 2 +- code/AssetLib/glTF/glTFImporter.cpp | 2 +- code/AssetLib/glTF/glTFImporter.h | 2 +- code/AssetLib/glTF2/glTF2Asset.h | 2 +- code/AssetLib/glTF2/glTF2Asset.inl | 2 +- code/AssetLib/glTF2/glTF2AssetWriter.h | 2 +- code/AssetLib/glTF2/glTF2AssetWriter.inl | 2 +- code/AssetLib/glTF2/glTF2Exporter.cpp | 2 +- code/AssetLib/glTF2/glTF2Exporter.h | 2 +- code/AssetLib/glTF2/glTF2Importer.cpp | 2 +- code/AssetLib/glTF2/glTF2Importer.h | 2 +- code/CApi/AssimpCExport.cpp | 2 +- code/CApi/CInterfaceIOWrapper.cpp | 2 +- code/CApi/CInterfaceIOWrapper.h | 2 +- code/CMakeLists.txt | 2 +- code/Common/AssertHandler.cpp | 2 +- code/Common/Assimp.cpp | 2 +- code/Common/Base64.cpp | 2 +- code/Common/BaseImporter.cpp | 2 +- code/Common/BaseProcess.cpp | 2 +- code/Common/BaseProcess.h | 2 +- code/Common/Bitmap.cpp | 2 +- code/Common/Compression.cpp | 2 +- code/Common/Compression.h | 2 +- code/Common/CreateAnimMesh.cpp | 2 +- code/Common/DefaultIOStream.cpp | 2 +- code/Common/DefaultIOSystem.cpp | 2 +- code/Common/DefaultLogger.cpp | 2 +- code/Common/DefaultProgressHandler.h | 2 +- code/Common/Exceptional.cpp | 2 +- code/Common/Exporter.cpp | 2 +- code/Common/FileLogStream.h | 2 +- code/Common/IOSystem.cpp | 2 +- code/Common/Importer.cpp | 2 +- code/Common/Importer.h | 2 +- code/Common/ImporterRegistry.cpp | 2 +- code/Common/Maybe.h | 2 +- code/Common/PolyTools.h | 2 +- code/Common/PostStepRegistry.cpp | 2 +- code/Common/RemoveComments.cpp | 2 +- code/Common/SGSpatialSort.cpp | 2 +- code/Common/SceneCombiner.cpp | 2 +- code/Common/ScenePreprocessor.cpp | 2 +- code/Common/ScenePreprocessor.h | 2 +- code/Common/ScenePrivate.h | 2 +- code/Common/SkeletonMeshBuilder.cpp | 2 +- code/Common/SpatialSort.cpp | 2 +- code/Common/StackAllocator.h | 2 +- code/Common/StackAllocator.inl | 2 +- code/Common/StandardShapes.cpp | 2 +- code/Common/StbCommon.h | 2 +- code/Common/StdOStreamLogStream.h | 2 +- code/Common/Subdivision.cpp | 2 +- code/Common/TargetAnimation.cpp | 2 +- code/Common/TargetAnimation.h | 2 +- code/Common/Version.cpp | 2 +- code/Common/VertexTriangleAdjacency.cpp | 2 +- code/Common/VertexTriangleAdjacency.h | 2 +- code/Common/Win32DebugLogStream.h | 2 +- code/Common/ZipArchiveIOSystem.cpp | 2 +- code/Common/material.cpp | 2 +- code/Common/scene.cpp | 2 +- code/Common/simd.cpp | 2 +- code/Common/simd.h | 2 +- code/Geometry/GeometryUtils.cpp | 2 +- code/Geometry/GeometryUtils.h | 2 +- code/Material/MaterialSystem.cpp | 2 +- code/Material/MaterialSystem.h | 2 +- code/Pbrt/PbrtExporter.cpp | 2 +- code/Pbrt/PbrtExporter.h | 2 +- code/PostProcessing/ArmaturePopulate.cpp | 2 +- code/PostProcessing/ArmaturePopulate.h | 2 +- code/PostProcessing/CalcTangentsProcess.cpp | 2 +- code/PostProcessing/CalcTangentsProcess.h | 2 +- code/PostProcessing/ComputeUVMappingProcess.cpp | 2 +- code/PostProcessing/ComputeUVMappingProcess.h | 2 +- code/PostProcessing/ConvertToLHProcess.cpp | 2 +- code/PostProcessing/ConvertToLHProcess.h | 2 +- code/PostProcessing/DeboneProcess.cpp | 2 +- code/PostProcessing/DeboneProcess.h | 2 +- code/PostProcessing/DropFaceNormalsProcess.cpp | 2 +- code/PostProcessing/DropFaceNormalsProcess.h | 2 +- code/PostProcessing/EmbedTexturesProcess.cpp | 2 +- code/PostProcessing/EmbedTexturesProcess.h | 2 +- code/PostProcessing/FindDegenerates.cpp | 2 +- code/PostProcessing/FindDegenerates.h | 2 +- code/PostProcessing/FindInstancesProcess.cpp | 2 +- code/PostProcessing/FindInstancesProcess.h | 2 +- code/PostProcessing/FindInvalidDataProcess.cpp | 2 +- code/PostProcessing/FindInvalidDataProcess.h | 2 +- code/PostProcessing/FixNormalsStep.cpp | 2 +- code/PostProcessing/FixNormalsStep.h | 2 +- code/PostProcessing/GenBoundingBoxesProcess.cpp | 2 +- code/PostProcessing/GenBoundingBoxesProcess.h | 2 +- code/PostProcessing/GenFaceNormalsProcess.cpp | 2 +- code/PostProcessing/GenFaceNormalsProcess.h | 2 +- code/PostProcessing/GenVertexNormalsProcess.cpp | 2 +- code/PostProcessing/GenVertexNormalsProcess.h | 2 +- code/PostProcessing/ImproveCacheLocality.cpp | 2 +- code/PostProcessing/ImproveCacheLocality.h | 2 +- code/PostProcessing/JoinVerticesProcess.cpp | 2 +- code/PostProcessing/JoinVerticesProcess.h | 2 +- code/PostProcessing/LimitBoneWeightsProcess.cpp | 2 +- code/PostProcessing/LimitBoneWeightsProcess.h | 2 +- code/PostProcessing/MakeVerboseFormat.cpp | 2 +- code/PostProcessing/MakeVerboseFormat.h | 2 +- code/PostProcessing/OptimizeGraph.cpp | 2 +- code/PostProcessing/OptimizeGraph.h | 2 +- code/PostProcessing/OptimizeMeshes.cpp | 2 +- code/PostProcessing/OptimizeMeshes.h | 2 +- code/PostProcessing/PretransformVertices.cpp | 2 +- code/PostProcessing/PretransformVertices.h | 2 +- code/PostProcessing/ProcessHelper.cpp | 2 +- code/PostProcessing/ProcessHelper.h | 2 +- code/PostProcessing/RemoveRedundantMaterials.cpp | 2 +- code/PostProcessing/RemoveRedundantMaterials.h | 2 +- code/PostProcessing/RemoveVCProcess.cpp | 2 +- code/PostProcessing/RemoveVCProcess.h | 2 +- code/PostProcessing/ScaleProcess.cpp | 2 +- code/PostProcessing/ScaleProcess.h | 2 +- code/PostProcessing/SortByPTypeProcess.cpp | 2 +- code/PostProcessing/SortByPTypeProcess.h | 2 +- code/PostProcessing/SplitByBoneCountProcess.cpp | 2 +- code/PostProcessing/SplitByBoneCountProcess.h | 2 +- code/PostProcessing/SplitLargeMeshes.cpp | 2 +- code/PostProcessing/SplitLargeMeshes.h | 2 +- code/PostProcessing/TextureTransform.cpp | 2 +- code/PostProcessing/TextureTransform.h | 2 +- code/PostProcessing/TriangulateProcess.cpp | 2 +- code/PostProcessing/TriangulateProcess.h | 2 +- code/PostProcessing/ValidateDataStructure.cpp | 2 +- code/PostProcessing/ValidateDataStructure.h | 2 +- contrib/pugixml/readme.txt | 4 ++-- contrib/pugixml/src/pugiconfig.hpp | 4 ++-- contrib/pugixml/src/pugixml.cpp | 4 ++-- contrib/pugixml/src/pugixml.hpp | 4 ++-- fuzz/assimp_fuzzer.cc | 2 +- include/assimp/Base64.hpp | 2 +- include/assimp/BaseImporter.h | 2 +- include/assimp/Bitmap.h | 2 +- include/assimp/BlobIOSystem.h | 2 +- include/assimp/ByteSwapper.h | 2 +- include/assimp/ColladaMetaData.h | 2 +- include/assimp/CreateAnimMesh.h | 2 +- include/assimp/DefaultIOStream.h | 2 +- include/assimp/DefaultIOSystem.h | 2 +- include/assimp/DefaultLogger.hpp | 2 +- include/assimp/Exceptional.h | 2 +- include/assimp/Exporter.hpp | 2 +- include/assimp/GenericProperty.h | 2 +- include/assimp/GltfMaterial.h | 2 +- include/assimp/Hash.h | 2 +- include/assimp/IOStream.hpp | 2 +- include/assimp/IOStreamBuffer.h | 2 +- include/assimp/IOSystem.hpp | 2 +- include/assimp/Importer.hpp | 2 +- include/assimp/LineSplitter.h | 2 +- include/assimp/LogAux.h | 2 +- include/assimp/LogStream.hpp | 2 +- include/assimp/Logger.hpp | 2 +- include/assimp/MathFunctions.h | 2 +- include/assimp/MemoryIOWrapper.h | 2 +- include/assimp/NullLogger.hpp | 2 +- include/assimp/ObjMaterial.h | 2 +- include/assimp/ParsingUtils.h | 2 +- include/assimp/Profiler.h | 2 +- include/assimp/ProgressHandler.hpp | 2 +- include/assimp/RemoveComments.h | 2 +- include/assimp/SGSpatialSort.h | 2 +- include/assimp/SceneCombiner.h | 2 +- include/assimp/SkeletonMeshBuilder.h | 2 +- include/assimp/SmallVector.h | 2 +- include/assimp/SmoothingGroups.h | 2 +- include/assimp/SmoothingGroups.inl | 2 +- include/assimp/SpatialSort.h | 2 +- include/assimp/StandardShapes.h | 2 +- include/assimp/StreamReader.h | 2 +- include/assimp/StreamWriter.h | 2 +- include/assimp/StringComparison.h | 2 +- include/assimp/StringUtils.h | 2 +- include/assimp/Subdivision.h | 2 +- include/assimp/TinyFormatter.h | 2 +- include/assimp/Vertex.h | 2 +- include/assimp/XMLTools.h | 2 +- include/assimp/XmlParser.h | 2 +- include/assimp/aabb.h | 2 +- include/assimp/ai_assert.h | 2 +- include/assimp/anim.h | 2 +- include/assimp/camera.h | 2 +- include/assimp/cexport.h | 2 +- include/assimp/cfileio.h | 2 +- include/assimp/cimport.h | 2 +- include/assimp/color4.h | 2 +- include/assimp/color4.inl | 2 +- include/assimp/commonMetaData.h | 2 +- include/assimp/config.h.in | 2 +- include/assimp/defs.h | 2 +- include/assimp/importerdesc.h | 2 +- include/assimp/light.h | 2 +- include/assimp/material.h | 2 +- include/assimp/material.inl | 2 +- include/assimp/matrix3x3.h | 2 +- include/assimp/matrix3x3.inl | 2 +- include/assimp/matrix4x4.h | 2 +- include/assimp/mesh.h | 2 +- include/assimp/metadata.h | 2 +- include/assimp/pbrmaterial.h | 2 +- include/assimp/postprocess.h | 2 +- include/assimp/qnan.h | 2 +- include/assimp/quaternion.inl | 2 +- include/assimp/scene.h | 2 +- include/assimp/texture.h | 2 +- include/assimp/vector2.h | 2 +- include/assimp/vector2.inl | 2 +- include/assimp/vector3.h | 2 +- include/assimp/vector3.inl | 2 +- include/assimp/version.h | 2 +- test/CMakeLists.txt | 2 +- test/unit/AbstractImportExportBase.cpp | 2 +- test/unit/AssimpAPITest.cpp | 2 +- test/unit/AssimpAPITest_aiMatrix3x3.cpp | 2 +- test/unit/AssimpAPITest_aiQuaternion.cpp | 2 +- test/unit/AssimpAPITest_aiVector2D.cpp | 2 +- test/unit/AssimpAPITest_aiVector3D.cpp | 2 +- test/unit/Common/uiScene.cpp | 2 +- test/unit/Common/utAssertHandler.cpp | 2 +- test/unit/Common/utBase64.cpp | 2 +- test/unit/Common/utBaseProcess.cpp | 2 +- test/unit/Common/utHash.cpp | 2 +- test/unit/Common/utLineSplitter.cpp | 2 +- test/unit/Common/utMaybe.cpp | 2 +- test/unit/Common/utMesh.cpp | 2 +- test/unit/Common/utSpatialSort.cpp | 2 +- test/unit/Common/utStandardShapes.cpp | 2 +- test/unit/Common/utXmlParser.cpp | 2 +- test/unit/Geometry/utGeometryUtils.cpp | 2 +- test/unit/ImportExport/MDL/MDLHL1TestFiles.h | 2 +- .../ImportExport/MDL/utMDLImporter_HL1_ImportSettings.cpp | 2 +- test/unit/ImportExport/MDL/utMDLImporter_HL1_Materials.cpp | 2 +- test/unit/ImportExport/MDL/utMDLImporter_HL1_Nodes.cpp | 2 +- test/unit/ImportExport/RAW/utRAWImportExport.cpp | 2 +- test/unit/ImportExport/Terragen/utTerragenImportExport.cpp | 2 +- test/unit/ImportExport/utAssjsonImportExport.cpp | 2 +- test/unit/ImportExport/utCOBImportExport.cpp | 2 +- test/unit/ImportExport/utExporter.cpp | 2 +- test/unit/ImportExport/utMD2Importer.cpp | 2 +- test/unit/ImportExport/utMD5Importer.cpp | 2 +- test/unit/ImportExport/utMDLImporter.cpp | 2 +- test/unit/ImportExport/utNFFImportExport.cpp | 2 +- test/unit/ImportExport/utOFFImportExport.cpp | 2 +- test/unit/ImportExport/utOgreImportExport.cpp | 2 +- test/unit/ImportExport/utQ3BSPFileImportExport.cpp | 2 +- test/unit/ImportExport/utXGLImportExport.cpp | 2 +- test/unit/MathTest.cpp | 2 +- test/unit/MathTest.h | 2 +- test/unit/RandomNumberGeneration.h | 2 +- test/unit/SceneDiffer.cpp | 2 +- test/unit/SceneDiffer.h | 2 +- test/unit/TestIOSystem.h | 2 +- test/unit/TestModelFactory.h | 2 +- test/unit/UTLogStream.h | 2 +- test/unit/ut3DImportExport.cpp | 2 +- test/unit/ut3DSImportExport.cpp | 2 +- test/unit/utACImportExport.cpp | 2 +- test/unit/utAMFImportExport.cpp | 2 +- test/unit/utASEImportExport.cpp | 2 +- test/unit/utAnim.cpp | 2 +- test/unit/utArmaturePopulate.cpp | 2 +- test/unit/utAssbinImportExport.cpp | 2 +- test/unit/utB3DImportExport.cpp | 2 +- test/unit/utBVHImportExport.cpp | 2 +- test/unit/utBatchLoader.cpp | 2 +- test/unit/utBlendImportAreaLight.cpp | 2 +- test/unit/utBlendImportMaterials.cpp | 2 +- test/unit/utBlenderImportExport.cpp | 2 +- test/unit/utBlenderIntermediate.cpp | 2 +- test/unit/utBlenderWork.cpp | 2 +- test/unit/utCSMImportExport.cpp | 2 +- test/unit/utColladaExport.cpp | 2 +- test/unit/utColladaImportExport.cpp | 2 +- test/unit/utD3MFImportExport.cpp | 2 +- test/unit/utDXFImporterExporter.cpp | 2 +- test/unit/utDefaultIOStream.cpp | 2 +- test/unit/utExport.cpp | 2 +- test/unit/utFBXImporterExporter.cpp | 2 +- test/unit/utFastAtof.cpp | 2 +- test/unit/utFindDegenerates.cpp | 2 +- test/unit/utFindInvalidData.cpp | 2 +- test/unit/utFixInfacingNormals.cpp | 2 +- test/unit/utGenBoundingBoxesProcess.cpp | 2 +- test/unit/utGenNormals.cpp | 2 +- test/unit/utHMPImportExport.cpp | 2 +- test/unit/utIFCImportExport.cpp | 2 +- test/unit/utIOStreamBuffer.cpp | 2 +- test/unit/utIOSystem.cpp | 2 +- test/unit/utImporter.cpp | 2 +- test/unit/utImproveCacheLocality.cpp | 2 +- test/unit/utIssues.cpp | 2 +- test/unit/utJoinVertices.cpp | 2 +- test/unit/utLWOImportExport.cpp | 2 +- test/unit/utLWSImportExport.cpp | 2 +- test/unit/utLimitBoneWeights.cpp | 2 +- test/unit/utMDCImportExport.cpp | 2 +- test/unit/utMaterialSystem.cpp | 2 +- test/unit/utMatrix3x3.cpp | 2 +- test/unit/utMatrix4x4.cpp | 2 +- test/unit/utMetadata.cpp | 2 +- test/unit/utObjImportExport.cpp | 2 +- test/unit/utObjTools.cpp | 2 +- test/unit/utOpenGEXImportExport.cpp | 2 +- test/unit/utPLYImportExport.cpp | 2 +- test/unit/utPMXImporter.cpp | 2 +- test/unit/utPretransformVertices.cpp | 2 +- test/unit/utProfiler.cpp | 2 +- test/unit/utQ3DImportExport.cpp | 2 +- test/unit/utRemoveComments.cpp | 2 +- test/unit/utRemoveComponent.cpp | 2 +- test/unit/utRemoveRedundantMaterials.cpp | 2 +- test/unit/utRemoveVCProcess.cpp | 2 +- test/unit/utSIBImporter.cpp | 2 +- test/unit/utSMDImportExport.cpp | 2 +- test/unit/utSTLImportExport.cpp | 2 +- test/unit/utScaleProcess.cpp | 2 +- test/unit/utSceneCombiner.cpp | 2 +- test/unit/utScenePreprocessor.cpp | 2 +- test/unit/utSharedPPData.cpp | 2 +- test/unit/utSimd.cpp | 2 +- test/unit/utSortByPType.cpp | 2 +- test/unit/utSplitLargeMeshes.cpp | 2 +- test/unit/utStringUtils.cpp | 2 +- test/unit/utTargetAnimation.cpp | 2 +- test/unit/utTextureTransform.cpp | 2 +- test/unit/utTriangulate.cpp | 2 +- test/unit/utTypes.cpp | 2 +- test/unit/utVector3.cpp | 2 +- test/unit/utVersion.cpp | 2 +- test/unit/utVertexTriangleAdjacency.cpp | 2 +- test/unit/utX3DImportExport.cpp | 2 +- test/unit/utXImporterExporter.cpp | 2 +- test/unit/utglTF2ImportExport.cpp | 2 +- test/unit/utglTFImportExport.cpp | 2 +- tools/assimp_cmd/CMakeLists.txt | 2 +- tools/assimp_cmd/CompareDump.cpp | 2 +- tools/assimp_cmd/Export.cpp | 2 +- tools/assimp_cmd/ImageExtractor.cpp | 2 +- tools/assimp_cmd/Info.cpp | 2 +- tools/assimp_cmd/Main.cpp | 2 +- tools/assimp_cmd/Main.h | 2 +- tools/assimp_cmd/WriteDump.cpp | 2 +- tools/assimp_view/AnimEvaluator.cpp | 2 +- tools/assimp_view/AnimEvaluator.h | 2 +- tools/assimp_view/AssetHelper.h | 2 +- tools/assimp_view/Background.cpp | 2 +- tools/assimp_view/CMakeLists.txt | 2 +- tools/assimp_view/Display.cpp | 2 +- tools/assimp_view/HelpDialog.cpp | 2 +- tools/assimp_view/Input.cpp | 2 +- tools/assimp_view/LogDisplay.cpp | 2 +- tools/assimp_view/LogWindow.cpp | 2 +- tools/assimp_view/Material.cpp | 2 +- tools/assimp_view/MaterialManager.h | 2 +- tools/assimp_view/MeshRenderer.cpp | 2 +- tools/assimp_view/MessageProc.cpp | 2 +- tools/assimp_view/Normals.cpp | 2 +- tools/assimp_view/SceneAnimator.cpp | 2 +- tools/assimp_view/SceneAnimator.h | 2 +- tools/assimp_view/Shaders.cpp | 2 +- tools/assimp_view/assimp_view.cpp | 2 +- tools/assimp_view/assimp_view.h | 2 +- 615 files changed, 619 insertions(+), 619 deletions(-) diff --git a/CMakeLists.txt b/CMakeLists.txt index 0133b47a4..70399798d 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -1,6 +1,6 @@ # Open Asset Import Library (assimp) # ---------------------------------------------------------------------- -# Copyright (c) 2006-2023, assimp team +# Copyright (c) 2006-2024, assimp team # # All rights reserved. # diff --git a/code/AssetLib/3DS/3DSConverter.cpp b/code/AssetLib/3DS/3DSConverter.cpp index 6d3f09cb7..7ae756668 100644 --- a/code/AssetLib/3DS/3DSConverter.cpp +++ b/code/AssetLib/3DS/3DSConverter.cpp @@ -3,7 +3,7 @@ Open Asset Import Library (assimp) --------------------------------------------------------------------------- -Copyright (c) 2006-2022, assimp team +Copyright (c) 2006-2024, assimp team All rights reserved. diff --git a/code/AssetLib/3DS/3DSExporter.cpp b/code/AssetLib/3DS/3DSExporter.cpp index 1b335a272..8477ed09f 100644 --- a/code/AssetLib/3DS/3DSExporter.cpp +++ b/code/AssetLib/3DS/3DSExporter.cpp @@ -2,7 +2,7 @@ Open Asset Import Library (assimp) ---------------------------------------------------------------------- -Copyright (c) 2006-2022, assimp team +Copyright (c) 2006-2024, assimp team All rights reserved. diff --git a/code/AssetLib/3DS/3DSExporter.h b/code/AssetLib/3DS/3DSExporter.h index 66e91e10d..9e3e42911 100644 --- a/code/AssetLib/3DS/3DSExporter.h +++ b/code/AssetLib/3DS/3DSExporter.h @@ -2,7 +2,7 @@ Open Asset Import Library (assimp) ---------------------------------------------------------------------- -Copyright (c) 2006-2022, assimp team +Copyright (c) 2006-2024, assimp team All rights reserved. diff --git a/code/AssetLib/3DS/3DSHelper.h b/code/AssetLib/3DS/3DSHelper.h index 2279d105c..8f85f2e4d 100644 --- a/code/AssetLib/3DS/3DSHelper.h +++ b/code/AssetLib/3DS/3DSHelper.h @@ -2,7 +2,7 @@ Open Asset Import Library (assimp) ---------------------------------------------------------------------- -Copyright (c) 2006-2022, assimp team +Copyright (c) 2006-2024, assimp team All rights reserved. diff --git a/code/AssetLib/3DS/3DSLoader.cpp b/code/AssetLib/3DS/3DSLoader.cpp index a406ea1d2..3317017be 100644 --- a/code/AssetLib/3DS/3DSLoader.cpp +++ b/code/AssetLib/3DS/3DSLoader.cpp @@ -3,7 +3,7 @@ Open Asset Import Library (assimp) --------------------------------------------------------------------------- -Copyright (c) 2006-2022, assimp team +Copyright (c) 2006-2024, assimp team All rights reserved. diff --git a/code/AssetLib/3DS/3DSLoader.h b/code/AssetLib/3DS/3DSLoader.h index c579507e0..1d6953e29 100644 --- a/code/AssetLib/3DS/3DSLoader.h +++ b/code/AssetLib/3DS/3DSLoader.h @@ -3,7 +3,7 @@ Open Asset Import Library (assimp) ---------------------------------------------------------------------- -Copyright (c) 2006-2022, assimp team +Copyright (c) 2006-2024, assimp team All rights reserved. diff --git a/code/AssetLib/3MF/3MFTypes.h b/code/AssetLib/3MF/3MFTypes.h index 8b7cce652..57d2b281a 100644 --- a/code/AssetLib/3MF/3MFTypes.h +++ b/code/AssetLib/3MF/3MFTypes.h @@ -2,7 +2,7 @@ Open Asset Import Library (assimp) ---------------------------------------------------------------------- -Copyright (c) 2006-2022, assimp team +Copyright (c) 2006-2024, assimp team All rights reserved. diff --git a/code/AssetLib/3MF/3MFXmlTags.h b/code/AssetLib/3MF/3MFXmlTags.h index f94135187..aea66667b 100644 --- a/code/AssetLib/3MF/3MFXmlTags.h +++ b/code/AssetLib/3MF/3MFXmlTags.h @@ -2,7 +2,7 @@ Open Asset Import Library (assimp) ---------------------------------------------------------------------- -Copyright (c) 2006-2022, assimp team +Copyright (c) 2006-2024, assimp team All rights reserved. diff --git a/code/AssetLib/3MF/D3MFExporter.cpp b/code/AssetLib/3MF/D3MFExporter.cpp index 4ba3bbf24..6caa4c84e 100644 --- a/code/AssetLib/3MF/D3MFExporter.cpp +++ b/code/AssetLib/3MF/D3MFExporter.cpp @@ -2,7 +2,7 @@ Open Asset Import Library (assimp) ---------------------------------------------------------------------- -Copyright (c) 2006-2022, assimp team +Copyright (c) 2006-2024, assimp team All rights reserved. diff --git a/code/AssetLib/3MF/D3MFExporter.h b/code/AssetLib/3MF/D3MFExporter.h index 680d54f91..6be0c32ca 100644 --- a/code/AssetLib/3MF/D3MFExporter.h +++ b/code/AssetLib/3MF/D3MFExporter.h @@ -2,7 +2,7 @@ Open Asset Import Library (assimp) ---------------------------------------------------------------------- -Copyright (c) 2006-2022, assimp team +Copyright (c) 2006-2024, assimp team All rights reserved. diff --git a/code/AssetLib/3MF/D3MFImporter.cpp b/code/AssetLib/3MF/D3MFImporter.cpp index 9a5081db9..987cdd492 100644 --- a/code/AssetLib/3MF/D3MFImporter.cpp +++ b/code/AssetLib/3MF/D3MFImporter.cpp @@ -2,7 +2,7 @@ Open Asset Import Library (assimp) ---------------------------------------------------------------------- -Copyright (c) 2006-2022, assimp team +Copyright (c) 2006-2024, assimp team All rights reserved. diff --git a/code/AssetLib/3MF/D3MFImporter.h b/code/AssetLib/3MF/D3MFImporter.h index 9ae68acb0..82a1546cd 100644 --- a/code/AssetLib/3MF/D3MFImporter.h +++ b/code/AssetLib/3MF/D3MFImporter.h @@ -2,7 +2,7 @@ Open Asset Import Library (assimp) ---------------------------------------------------------------------- -Copyright (c) 2006-2022, assimp team +Copyright (c) 2006-2024, assimp team All rights reserved. diff --git a/code/AssetLib/3MF/D3MFOpcPackage.cpp b/code/AssetLib/3MF/D3MFOpcPackage.cpp index 6284ce017..be0615904 100644 --- a/code/AssetLib/3MF/D3MFOpcPackage.cpp +++ b/code/AssetLib/3MF/D3MFOpcPackage.cpp @@ -2,7 +2,7 @@ Open Asset Import Library (assimp) ---------------------------------------------------------------------- -Copyright (c) 2006-2022, assimp team +Copyright (c) 2006-2024, assimp team All rights reserved. diff --git a/code/AssetLib/3MF/D3MFOpcPackage.h b/code/AssetLib/3MF/D3MFOpcPackage.h index f6803a0ef..9782752bf 100644 --- a/code/AssetLib/3MF/D3MFOpcPackage.h +++ b/code/AssetLib/3MF/D3MFOpcPackage.h @@ -2,7 +2,7 @@ Open Asset Import Library (assimp) ---------------------------------------------------------------------- -Copyright (c) 2006-2022, assimp team +Copyright (c) 2006-2024, assimp team All rights reserved. diff --git a/code/AssetLib/3MF/XmlSerializer.cpp b/code/AssetLib/3MF/XmlSerializer.cpp index cdaf3f432..354ed19bb 100644 --- a/code/AssetLib/3MF/XmlSerializer.cpp +++ b/code/AssetLib/3MF/XmlSerializer.cpp @@ -2,7 +2,7 @@ Open Asset Import Library (assimp) ---------------------------------------------------------------------- -Copyright (c) 2006-2022, assimp team +Copyright (c) 2006-2024, assimp team All rights reserved. diff --git a/code/AssetLib/3MF/XmlSerializer.h b/code/AssetLib/3MF/XmlSerializer.h index 39eb2ddf9..d0700a631 100644 --- a/code/AssetLib/3MF/XmlSerializer.h +++ b/code/AssetLib/3MF/XmlSerializer.h @@ -2,7 +2,7 @@ Open Asset Import Library (assimp) ---------------------------------------------------------------------- -Copyright (c) 2006-2022, assimp team +Copyright (c) 2006-2024, assimp team All rights reserved. diff --git a/code/AssetLib/AC/ACLoader.cpp b/code/AssetLib/AC/ACLoader.cpp index cd3fe8c3a..dbcb39b30 100644 --- a/code/AssetLib/AC/ACLoader.cpp +++ b/code/AssetLib/AC/ACLoader.cpp @@ -3,7 +3,7 @@ Open Asset Import Library (assimp) --------------------------------------------------------------------------- -Copyright (c) 2006-2022, assimp team +Copyright (c) 2006-2024, assimp team All rights reserved. diff --git a/code/AssetLib/AMF/AMFImporter.cpp b/code/AssetLib/AMF/AMFImporter.cpp index eabdb35e1..7c0d3b4e9 100644 --- a/code/AssetLib/AMF/AMFImporter.cpp +++ b/code/AssetLib/AMF/AMFImporter.cpp @@ -3,7 +3,7 @@ Open Asset Import Library (assimp) --------------------------------------------------------------------------- -Copyright (c) 2006-2022, assimp team +Copyright (c) 2006-2024, assimp team All rights reserved. diff --git a/code/AssetLib/AMF/AMFImporter.hpp b/code/AssetLib/AMF/AMFImporter.hpp index fbaf4fc6d..50be465ce 100644 --- a/code/AssetLib/AMF/AMFImporter.hpp +++ b/code/AssetLib/AMF/AMFImporter.hpp @@ -3,7 +3,7 @@ Open Asset Import Library (assimp) --------------------------------------------------------------------------- -Copyright (c) 2006-2022, assimp team +Copyright (c) 2006-2024, assimp team All rights reserved. diff --git a/code/AssetLib/AMF/AMFImporter_Geometry.cpp b/code/AssetLib/AMF/AMFImporter_Geometry.cpp index 341999f56..db262dfbd 100644 --- a/code/AssetLib/AMF/AMFImporter_Geometry.cpp +++ b/code/AssetLib/AMF/AMFImporter_Geometry.cpp @@ -3,7 +3,7 @@ Open Asset Import Library (assimp) --------------------------------------------------------------------------- -Copyright (c) 2006-2022, assimp team +Copyright (c) 2006-2024, assimp team All rights reserved. diff --git a/code/AssetLib/AMF/AMFImporter_Material.cpp b/code/AssetLib/AMF/AMFImporter_Material.cpp index 676e74856..ae27f5d37 100644 --- a/code/AssetLib/AMF/AMFImporter_Material.cpp +++ b/code/AssetLib/AMF/AMFImporter_Material.cpp @@ -3,7 +3,7 @@ Open Asset Import Library (assimp) --------------------------------------------------------------------------- -Copyright (c) 2006-2022, assimp team +Copyright (c) 2006-2024, assimp team All rights reserved. diff --git a/code/AssetLib/AMF/AMFImporter_Node.hpp b/code/AssetLib/AMF/AMFImporter_Node.hpp index dd27316d3..21068a9ba 100644 --- a/code/AssetLib/AMF/AMFImporter_Node.hpp +++ b/code/AssetLib/AMF/AMFImporter_Node.hpp @@ -3,7 +3,7 @@ Open Asset Import Library (assimp) --------------------------------------------------------------------------- -Copyright (c) 2006-2022, assimp team +Copyright (c) 2006-2024, assimp team All rights reserved. diff --git a/code/AssetLib/AMF/AMFImporter_Postprocess.cpp b/code/AssetLib/AMF/AMFImporter_Postprocess.cpp index d5160870a..969c64bd2 100644 --- a/code/AssetLib/AMF/AMFImporter_Postprocess.cpp +++ b/code/AssetLib/AMF/AMFImporter_Postprocess.cpp @@ -3,7 +3,7 @@ Open Asset Import Library (assimp) --------------------------------------------------------------------------- -Copyright (c) 2006-2022, assimp team +Copyright (c) 2006-2024, assimp team All rights reserved. diff --git a/code/AssetLib/ASE/ASELoader.cpp b/code/AssetLib/ASE/ASELoader.cpp index f98316661..7e411fc03 100644 --- a/code/AssetLib/ASE/ASELoader.cpp +++ b/code/AssetLib/ASE/ASELoader.cpp @@ -3,7 +3,7 @@ Open Asset Import Library (assimp) --------------------------------------------------------------------------- -Copyright (c) 2006-2022, assimp team +Copyright (c) 2006-2024, assimp team All rights reserved. diff --git a/code/AssetLib/ASE/ASELoader.h b/code/AssetLib/ASE/ASELoader.h index 2509671ef..5654fa630 100644 --- a/code/AssetLib/ASE/ASELoader.h +++ b/code/AssetLib/ASE/ASELoader.h @@ -2,7 +2,7 @@ Open Asset Import Library (assimp) ---------------------------------------------------------------------- -Copyright (c) 2006-2022, assimp team +Copyright (c) 2006-2024, assimp team All rights reserved. diff --git a/code/AssetLib/ASE/ASEParser.cpp b/code/AssetLib/ASE/ASEParser.cpp index 3b515def7..e3c358aa5 100644 --- a/code/AssetLib/ASE/ASEParser.cpp +++ b/code/AssetLib/ASE/ASEParser.cpp @@ -3,7 +3,7 @@ Open Asset Import Library (assimp) --------------------------------------------------------------------------- -Copyright (c) 2006-2022, assimp team +Copyright (c) 2006-2024, assimp team All rights reserved. diff --git a/code/AssetLib/ASE/ASEParser.h b/code/AssetLib/ASE/ASEParser.h index fa7c6d3c5..263b5ca73 100644 --- a/code/AssetLib/ASE/ASEParser.h +++ b/code/AssetLib/ASE/ASEParser.h @@ -2,7 +2,7 @@ Open Asset Import Library (assimp) ---------------------------------------------------------------------- -Copyright (c) 2006-2022, assimp team +Copyright (c) 2006-2024, assimp team All rights reserved. diff --git a/code/AssetLib/Assbin/AssbinExporter.cpp b/code/AssetLib/Assbin/AssbinExporter.cpp index 149b3c5f3..b8465f866 100644 --- a/code/AssetLib/Assbin/AssbinExporter.cpp +++ b/code/AssetLib/Assbin/AssbinExporter.cpp @@ -2,7 +2,7 @@ Open Asset Import Library (assimp) ---------------------------------------------------------------------- -Copyright (c) 2006-2022, assimp team +Copyright (c) 2006-2024, assimp team All rights reserved. diff --git a/code/AssetLib/Assbin/AssbinExporter.h b/code/AssetLib/Assbin/AssbinExporter.h index 8b721994d..271b6b833 100644 --- a/code/AssetLib/Assbin/AssbinExporter.h +++ b/code/AssetLib/Assbin/AssbinExporter.h @@ -2,7 +2,7 @@ Open Asset Import Library (assimp) ---------------------------------------------------------------------- -Copyright (c) 2006-2022, assimp team +Copyright (c) 2006-2024, assimp team All rights reserved. diff --git a/code/AssetLib/Assbin/AssbinFileWriter.cpp b/code/AssetLib/Assbin/AssbinFileWriter.cpp index 782595bc1..90bcccf90 100644 --- a/code/AssetLib/Assbin/AssbinFileWriter.cpp +++ b/code/AssetLib/Assbin/AssbinFileWriter.cpp @@ -2,7 +2,7 @@ Open Asset Import Library (assimp) ---------------------------------------------------------------------- -Copyright (c) 2006-2022, assimp team +Copyright (c) 2006-2024, assimp team All rights reserved. diff --git a/code/AssetLib/Assbin/AssbinFileWriter.h b/code/AssetLib/Assbin/AssbinFileWriter.h index cfed3b400..84641df46 100644 --- a/code/AssetLib/Assbin/AssbinFileWriter.h +++ b/code/AssetLib/Assbin/AssbinFileWriter.h @@ -2,7 +2,7 @@ Open Asset Import Library (assimp) ---------------------------------------------------------------------- -Copyright (c) 2006-2022, assimp team +Copyright (c) 2006-2024, assimp team All rights reserved. diff --git a/code/AssetLib/Assbin/AssbinLoader.cpp b/code/AssetLib/Assbin/AssbinLoader.cpp index 6995ea976..d2566a85c 100644 --- a/code/AssetLib/Assbin/AssbinLoader.cpp +++ b/code/AssetLib/Assbin/AssbinLoader.cpp @@ -3,7 +3,7 @@ Open Asset Import Library (assimp) --------------------------------------------------------------------------- -Copyright (c) 2006-2022, assimp team +Copyright (c) 2006-2024, assimp team All rights reserved. diff --git a/code/AssetLib/Assbin/AssbinLoader.h b/code/AssetLib/Assbin/AssbinLoader.h index f922b91fd..2b85e6655 100644 --- a/code/AssetLib/Assbin/AssbinLoader.h +++ b/code/AssetLib/Assbin/AssbinLoader.h @@ -3,7 +3,7 @@ Open Asset Import Library (assimp) ---------------------------------------------------------------------- -Copyright (c) 2006-2022, assimp team +Copyright (c) 2006-2024, assimp team All rights reserved. diff --git a/code/AssetLib/Assxml/AssxmlExporter.cpp b/code/AssetLib/Assxml/AssxmlExporter.cpp index 731916a25..b9691b822 100644 --- a/code/AssetLib/Assxml/AssxmlExporter.cpp +++ b/code/AssetLib/Assxml/AssxmlExporter.cpp @@ -2,7 +2,7 @@ Open Asset Import Library (assimp) ---------------------------------------------------------------------- -Copyright (c) 2006-2022, assimp team +Copyright (c) 2006-2024, assimp team All rights reserved. diff --git a/code/AssetLib/Assxml/AssxmlExporter.h b/code/AssetLib/Assxml/AssxmlExporter.h index 6fcdebfab..28a9b7f35 100644 --- a/code/AssetLib/Assxml/AssxmlExporter.h +++ b/code/AssetLib/Assxml/AssxmlExporter.h @@ -2,7 +2,7 @@ Open Asset Import Library (assimp) ---------------------------------------------------------------------- -Copyright (c) 2006-2022, assimp team +Copyright (c) 2006-2024, assimp team All rights reserved. diff --git a/code/AssetLib/Assxml/AssxmlFileWriter.cpp b/code/AssetLib/Assxml/AssxmlFileWriter.cpp index 8f8e76bd2..f6fdc4a0c 100644 --- a/code/AssetLib/Assxml/AssxmlFileWriter.cpp +++ b/code/AssetLib/Assxml/AssxmlFileWriter.cpp @@ -2,7 +2,7 @@ Open Asset Import Library (assimp) ---------------------------------------------------------------------- -Copyright (c) 2006-2022, assimp team +Copyright (c) 2006-2024, assimp team All rights reserved. diff --git a/code/AssetLib/Assxml/AssxmlFileWriter.h b/code/AssetLib/Assxml/AssxmlFileWriter.h index 0620c9db7..1051a03a0 100644 --- a/code/AssetLib/Assxml/AssxmlFileWriter.h +++ b/code/AssetLib/Assxml/AssxmlFileWriter.h @@ -2,7 +2,7 @@ Open Asset Import Library (assimp) ---------------------------------------------------------------------- -Copyright (c) 2006-2022, assimp team +Copyright (c) 2006-2024, assimp team All rights reserved. diff --git a/code/AssetLib/B3D/B3DImporter.cpp b/code/AssetLib/B3D/B3DImporter.cpp index 670f3de53..d0029277c 100644 --- a/code/AssetLib/B3D/B3DImporter.cpp +++ b/code/AssetLib/B3D/B3DImporter.cpp @@ -3,7 +3,7 @@ Open Asset Import Library (assimp) --------------------------------------------------------------------------- -Copyright (c) 2006-2022, assimp team +Copyright (c) 2006-2024, assimp team All rights reserved. diff --git a/code/AssetLib/B3D/B3DImporter.h b/code/AssetLib/B3D/B3DImporter.h index e47d9078b..0fcfae620 100644 --- a/code/AssetLib/B3D/B3DImporter.h +++ b/code/AssetLib/B3D/B3DImporter.h @@ -2,7 +2,7 @@ Open Asset Import Library (assimp) ---------------------------------------------------------------------- -Copyright (c) 2006-2022, assimp team +Copyright (c) 2006-2024, assimp team All rights reserved. diff --git a/code/AssetLib/BVH/BVHLoader.cpp b/code/AssetLib/BVH/BVHLoader.cpp index 4d2cfde15..2b37286ea 100644 --- a/code/AssetLib/BVH/BVHLoader.cpp +++ b/code/AssetLib/BVH/BVHLoader.cpp @@ -4,7 +4,7 @@ Open Asset Import Library (assimp) --------------------------------------------------------------------------- -Copyright (c) 2006-2022, assimp team +Copyright (c) 2006-2024, assimp team diff --git a/code/AssetLib/BVH/BVHLoader.h b/code/AssetLib/BVH/BVHLoader.h index 56c32bd99..2c5e24114 100644 --- a/code/AssetLib/BVH/BVHLoader.h +++ b/code/AssetLib/BVH/BVHLoader.h @@ -4,7 +4,7 @@ Open Asset Import Library (assimp) ---------------------------------------------------------------------- -Copyright (c) 2006-2022, assimp team +Copyright (c) 2006-2024, assimp team All rights reserved. diff --git a/code/AssetLib/Blender/BlenderBMesh.cpp b/code/AssetLib/Blender/BlenderBMesh.cpp index a82e7c678..0660967bd 100644 --- a/code/AssetLib/Blender/BlenderBMesh.cpp +++ b/code/AssetLib/Blender/BlenderBMesh.cpp @@ -2,7 +2,7 @@ Open Asset Import Library (assimp) ---------------------------------------------------------------------- -Copyright (c) 2006-2022, assimp team +Copyright (c) 2006-2024, assimp team All rights reserved. Redistribution and use of this software in source and binary forms, diff --git a/code/AssetLib/Blender/BlenderBMesh.h b/code/AssetLib/Blender/BlenderBMesh.h index 7d2f71717..1798aaf74 100644 --- a/code/AssetLib/Blender/BlenderBMesh.h +++ b/code/AssetLib/Blender/BlenderBMesh.h @@ -2,7 +2,7 @@ Open Asset Import Library (assimp) ---------------------------------------------------------------------- -Copyright (c) 2006-2022, assimp team +Copyright (c) 2006-2024, assimp team All rights reserved. Redistribution and use of this software in source and binary forms, diff --git a/code/AssetLib/Blender/BlenderDNA.cpp b/code/AssetLib/Blender/BlenderDNA.cpp index d22c4bfd7..311911249 100644 --- a/code/AssetLib/Blender/BlenderDNA.cpp +++ b/code/AssetLib/Blender/BlenderDNA.cpp @@ -2,7 +2,7 @@ Open Asset Import Library (assimp) ---------------------------------------------------------------------- -Copyright (c) 2006-2022, assimp team +Copyright (c) 2006-2024, assimp team All rights reserved. diff --git a/code/AssetLib/Blender/BlenderDNA.h b/code/AssetLib/Blender/BlenderDNA.h index 494dc4b34..f6a691fd6 100644 --- a/code/AssetLib/Blender/BlenderDNA.h +++ b/code/AssetLib/Blender/BlenderDNA.h @@ -2,7 +2,7 @@ Open Asset Import Library (assimp) ---------------------------------------------------------------------- -Copyright (c) 2006-2022, assimp team +Copyright (c) 2006-2024, assimp team All rights reserved. diff --git a/code/AssetLib/Blender/BlenderDNA.inl b/code/AssetLib/Blender/BlenderDNA.inl index 4f64987a5..9bcb602ba 100644 --- a/code/AssetLib/Blender/BlenderDNA.inl +++ b/code/AssetLib/Blender/BlenderDNA.inl @@ -2,7 +2,7 @@ Open Asset Import Library (assimp) ---------------------------------------------------------------------- -Copyright (c) 2006-2022, assimp team +Copyright (c) 2006-2024, assimp team All rights reserved. diff --git a/code/AssetLib/Blender/BlenderIntermediate.h b/code/AssetLib/Blender/BlenderIntermediate.h index 546b79f09..700beb7b0 100644 --- a/code/AssetLib/Blender/BlenderIntermediate.h +++ b/code/AssetLib/Blender/BlenderIntermediate.h @@ -2,7 +2,7 @@ Open Asset Import Library (assimp) ---------------------------------------------------------------------- -Copyright (c) 2006-2022, assimp team +Copyright (c) 2006-2024, assimp team All rights reserved. diff --git a/code/AssetLib/Blender/BlenderLoader.cpp b/code/AssetLib/Blender/BlenderLoader.cpp index 35b35f08d..1a40a2fe5 100644 --- a/code/AssetLib/Blender/BlenderLoader.cpp +++ b/code/AssetLib/Blender/BlenderLoader.cpp @@ -3,7 +3,7 @@ Open Asset Import Library (assimp) ---------------------------------------------------------------------- -Copyright (c) 2006-2022, assimp team +Copyright (c) 2006-2024, assimp team All rights reserved. diff --git a/code/AssetLib/Blender/BlenderLoader.h b/code/AssetLib/Blender/BlenderLoader.h index 2bdc24ae2..5c800c627 100644 --- a/code/AssetLib/Blender/BlenderLoader.h +++ b/code/AssetLib/Blender/BlenderLoader.h @@ -2,7 +2,7 @@ Open Asset Import Library (assimp) ---------------------------------------------------------------------- -Copyright (c) 2006-2022, assimp team +Copyright (c) 2006-2024, assimp team All rights reserved. diff --git a/code/AssetLib/Blender/BlenderModifier.cpp b/code/AssetLib/Blender/BlenderModifier.cpp index f925de608..2cd8bda7c 100644 --- a/code/AssetLib/Blender/BlenderModifier.cpp +++ b/code/AssetLib/Blender/BlenderModifier.cpp @@ -2,7 +2,7 @@ Open Asset Import Library (assimp) ---------------------------------------------------------------------- -Copyright (c) 2006-2022, assimp team +Copyright (c) 2006-2024, assimp team All rights reserved. diff --git a/code/AssetLib/Blender/BlenderModifier.h b/code/AssetLib/Blender/BlenderModifier.h index 180a456a1..2d6940357 100644 --- a/code/AssetLib/Blender/BlenderModifier.h +++ b/code/AssetLib/Blender/BlenderModifier.h @@ -2,7 +2,7 @@ Open Asset Import Library (assimp) ---------------------------------------------------------------------- -Copyright (c) 2006-2022, assimp team +Copyright (c) 2006-2024, assimp team All rights reserved. diff --git a/code/AssetLib/Blender/BlenderScene.h b/code/AssetLib/Blender/BlenderScene.h index ba7ded909..671891c68 100644 --- a/code/AssetLib/Blender/BlenderScene.h +++ b/code/AssetLib/Blender/BlenderScene.h @@ -2,7 +2,7 @@ Open Asset Import Library (assimp) ---------------------------------------------------------------------- -Copyright (c) 2006-2022, assimp team +Copyright (c) 2006-2024, assimp team All rights reserved. diff --git a/code/AssetLib/Blender/BlenderTessellator.cpp b/code/AssetLib/Blender/BlenderTessellator.cpp index 84bc2ea1a..f51cf9780 100644 --- a/code/AssetLib/Blender/BlenderTessellator.cpp +++ b/code/AssetLib/Blender/BlenderTessellator.cpp @@ -2,7 +2,7 @@ Open Asset Import Library (assimp) ---------------------------------------------------------------------- -Copyright (c) 2006-2022, assimp team +Copyright (c) 2006-2024, assimp team All rights reserved. diff --git a/code/AssetLib/Blender/BlenderTessellator.h b/code/AssetLib/Blender/BlenderTessellator.h index 21a4f4701..e43535f6c 100644 --- a/code/AssetLib/Blender/BlenderTessellator.h +++ b/code/AssetLib/Blender/BlenderTessellator.h @@ -2,7 +2,7 @@ Open Asset Import Library (assimp) ---------------------------------------------------------------------- -Copyright (c) 2006-2022, assimp team +Copyright (c) 2006-2024, assimp team All rights reserved. diff --git a/code/AssetLib/COB/COBLoader.cpp b/code/AssetLib/COB/COBLoader.cpp index 3b7ae5525..f0899bddd 100644 --- a/code/AssetLib/COB/COBLoader.cpp +++ b/code/AssetLib/COB/COBLoader.cpp @@ -2,7 +2,7 @@ Open Asset Import Library (assimp) ---------------------------------------------------------------------- -Copyright (c) 2006-2022, assimp team +Copyright (c) 2006-2024, assimp team All rights reserved. diff --git a/code/AssetLib/COB/COBLoader.h b/code/AssetLib/COB/COBLoader.h index cc124f533..ec3c7756b 100644 --- a/code/AssetLib/COB/COBLoader.h +++ b/code/AssetLib/COB/COBLoader.h @@ -2,7 +2,7 @@ Open Asset Import Library (assimp) ---------------------------------------------------------------------- -Copyright (c) 2006-2022, assimp team +Copyright (c) 2006-2024, assimp team All rights reserved. diff --git a/code/AssetLib/COB/COBScene.h b/code/AssetLib/COB/COBScene.h index cc49de276..ea4c01251 100644 --- a/code/AssetLib/COB/COBScene.h +++ b/code/AssetLib/COB/COBScene.h @@ -2,7 +2,7 @@ Open Asset Import Library (assimp) ---------------------------------------------------------------------- -Copyright (c) 2006-2022, assimp team +Copyright (c) 2006-2024, assimp team All rights reserved. diff --git a/code/AssetLib/CSM/CSMLoader.cpp b/code/AssetLib/CSM/CSMLoader.cpp index a8513cb3d..47beee514 100644 --- a/code/AssetLib/CSM/CSMLoader.cpp +++ b/code/AssetLib/CSM/CSMLoader.cpp @@ -3,7 +3,7 @@ Open Asset Import Library (assimp) --------------------------------------------------------------------------- -Copyright (c) 2006-2022, assimp team +Copyright (c) 2006-2024, assimp team diff --git a/code/AssetLib/CSM/CSMLoader.h b/code/AssetLib/CSM/CSMLoader.h index fc9017d17..2bad73717 100644 --- a/code/AssetLib/CSM/CSMLoader.h +++ b/code/AssetLib/CSM/CSMLoader.h @@ -2,7 +2,7 @@ Open Asset Import Library (assimp) ---------------------------------------------------------------------- -Copyright (c) 2006-2022, assimp team +Copyright (c) 2006-2024, assimp team All rights reserved. diff --git a/code/AssetLib/Collada/ColladaExporter.cpp b/code/AssetLib/Collada/ColladaExporter.cpp index 29b714bd7..3fc3a6e15 100644 --- a/code/AssetLib/Collada/ColladaExporter.cpp +++ b/code/AssetLib/Collada/ColladaExporter.cpp @@ -2,7 +2,7 @@ Open Asset Import Library (assimp) ---------------------------------------------------------------------- -Copyright (c) 2006-2022, assimp team +Copyright (c) 2006-2024, assimp team All rights reserved. diff --git a/code/AssetLib/Collada/ColladaExporter.h b/code/AssetLib/Collada/ColladaExporter.h index e372a5c5c..05e076034 100644 --- a/code/AssetLib/Collada/ColladaExporter.h +++ b/code/AssetLib/Collada/ColladaExporter.h @@ -2,7 +2,7 @@ Open Asset Import Library (assimp) ---------------------------------------------------------------------- -Copyright (c) 2006-2022, assimp team +Copyright (c) 2006-2024, assimp team All rights reserved. diff --git a/code/AssetLib/Collada/ColladaHelper.cpp b/code/AssetLib/Collada/ColladaHelper.cpp index 0fb172fbb..b5de70624 100644 --- a/code/AssetLib/Collada/ColladaHelper.cpp +++ b/code/AssetLib/Collada/ColladaHelper.cpp @@ -2,7 +2,7 @@ Open Asset Import Library (assimp) ---------------------------------------------------------------------- -Copyright (c) 2006-2022, assimp team +Copyright (c) 2006-2024, assimp team All rights reserved. diff --git a/code/AssetLib/Collada/ColladaHelper.h b/code/AssetLib/Collada/ColladaHelper.h index c5b6a2d13..6662d7354 100644 --- a/code/AssetLib/Collada/ColladaHelper.h +++ b/code/AssetLib/Collada/ColladaHelper.h @@ -2,7 +2,7 @@ Open Asset Import Library (assimp) ---------------------------------------------------------------------- -Copyright (c) 2006-2022, assimp team +Copyright (c) 2006-2024, assimp team All rights reserved. diff --git a/code/AssetLib/Collada/ColladaLoader.cpp b/code/AssetLib/Collada/ColladaLoader.cpp index 41e529de0..17c4f4b28 100644 --- a/code/AssetLib/Collada/ColladaLoader.cpp +++ b/code/AssetLib/Collada/ColladaLoader.cpp @@ -3,7 +3,7 @@ Open Asset Import Library (assimp) --------------------------------------------------------------------------- -Copyright (c) 2006-2022, assimp team +Copyright (c) 2006-2024, assimp team All rights reserved. diff --git a/code/AssetLib/Collada/ColladaLoader.h b/code/AssetLib/Collada/ColladaLoader.h index 3cea7f531..0603d419c 100644 --- a/code/AssetLib/Collada/ColladaLoader.h +++ b/code/AssetLib/Collada/ColladaLoader.h @@ -4,7 +4,7 @@ Open Asset Import Library (assimp) ---------------------------------------------------------------------- -Copyright (c) 2006-2022, assimp team +Copyright (c) 2006-2024, assimp team All rights reserved. diff --git a/code/AssetLib/Collada/ColladaParser.h b/code/AssetLib/Collada/ColladaParser.h index 15982934f..d428ad674 100644 --- a/code/AssetLib/Collada/ColladaParser.h +++ b/code/AssetLib/Collada/ColladaParser.h @@ -2,7 +2,7 @@ Open Asset Import Library (assimp) ---------------------------------------------------------------------- - Copyright (c) 2006-2022, assimp team + Copyright (c) 2006-2024, assimp team All rights reserved. diff --git a/code/AssetLib/DXF/DXFHelper.h b/code/AssetLib/DXF/DXFHelper.h index 4d7893cc4..0bbecdc9e 100644 --- a/code/AssetLib/DXF/DXFHelper.h +++ b/code/AssetLib/DXF/DXFHelper.h @@ -2,7 +2,7 @@ Open Asset Import Library (assimp) ---------------------------------------------------------------------- -Copyright (c) 2006-2022, assimp team +Copyright (c) 2006-2024, assimp team All rights reserved. diff --git a/code/AssetLib/DXF/DXFLoader.h b/code/AssetLib/DXF/DXFLoader.h index 89a0b79c2..9230bccbd 100644 --- a/code/AssetLib/DXF/DXFLoader.h +++ b/code/AssetLib/DXF/DXFLoader.h @@ -2,7 +2,7 @@ Open Asset Import Library (assimp) ---------------------------------------------------------------------- -Copyright (c) 2006-2022, assimp team +Copyright (c) 2006-2024, assimp team All rights reserved. diff --git a/code/AssetLib/FBX/FBXAnimation.cpp b/code/AssetLib/FBX/FBXAnimation.cpp index af92ebe51..fdde37f24 100644 --- a/code/AssetLib/FBX/FBXAnimation.cpp +++ b/code/AssetLib/FBX/FBXAnimation.cpp @@ -2,7 +2,7 @@ Open Asset Import Library (assimp) ---------------------------------------------------------------------- -Copyright (c) 2006-2022, assimp team +Copyright (c) 2006-2024, assimp team All rights reserved. diff --git a/code/AssetLib/FBX/FBXBinaryTokenizer.cpp b/code/AssetLib/FBX/FBXBinaryTokenizer.cpp index 55424a6a8..b828090e5 100644 --- a/code/AssetLib/FBX/FBXBinaryTokenizer.cpp +++ b/code/AssetLib/FBX/FBXBinaryTokenizer.cpp @@ -2,7 +2,7 @@ Open Asset Import Library (assimp) ---------------------------------------------------------------------- -Copyright (c) 2006-2022, assimp team +Copyright (c) 2006-2024, assimp team All rights reserved. diff --git a/code/AssetLib/FBX/FBXCommon.h b/code/AssetLib/FBX/FBXCommon.h index c3d715892..7e0fb2553 100644 --- a/code/AssetLib/FBX/FBXCommon.h +++ b/code/AssetLib/FBX/FBXCommon.h @@ -2,7 +2,7 @@ Open Asset Import Library (assimp) ---------------------------------------------------------------------- -Copyright (c) 2006-2022, assimp team +Copyright (c) 2006-2024, assimp team All rights reserved. diff --git a/code/AssetLib/FBX/FBXCompileConfig.h b/code/AssetLib/FBX/FBXCompileConfig.h index 927a3c5f6..9885ca346 100644 --- a/code/AssetLib/FBX/FBXCompileConfig.h +++ b/code/AssetLib/FBX/FBXCompileConfig.h @@ -2,7 +2,7 @@ Open Asset Import Library (assimp) ---------------------------------------------------------------------- -Copyright (c) 2006-2022, assimp team +Copyright (c) 2006-2024, assimp team All rights reserved. diff --git a/code/AssetLib/FBX/FBXConverter.cpp b/code/AssetLib/FBX/FBXConverter.cpp index 62ada774f..204d3e6fa 100644 --- a/code/AssetLib/FBX/FBXConverter.cpp +++ b/code/AssetLib/FBX/FBXConverter.cpp @@ -2,7 +2,7 @@ Open Asset Import Library (assimp) ---------------------------------------------------------------------- -Copyright (c) 2006-2022, assimp team +Copyright (c) 2006-2024, assimp team All rights reserved. diff --git a/code/AssetLib/FBX/FBXConverter.h b/code/AssetLib/FBX/FBXConverter.h index 41acb6ffe..73dc9e5a7 100644 --- a/code/AssetLib/FBX/FBXConverter.h +++ b/code/AssetLib/FBX/FBXConverter.h @@ -2,7 +2,7 @@ Open Asset Import Library (assimp) ---------------------------------------------------------------------- -Copyright (c) 2006-2022, assimp team +Copyright (c) 2006-2024, assimp team All rights reserved. diff --git a/code/AssetLib/FBX/FBXDeformer.cpp b/code/AssetLib/FBX/FBXDeformer.cpp index 8f944527a..582042360 100644 --- a/code/AssetLib/FBX/FBXDeformer.cpp +++ b/code/AssetLib/FBX/FBXDeformer.cpp @@ -2,7 +2,7 @@ Open Asset Import Library (assimp) ---------------------------------------------------------------------- -Copyright (c) 2006-2022, assimp team +Copyright (c) 2006-2024, assimp team All rights reserved. diff --git a/code/AssetLib/FBX/FBXDocument.cpp b/code/AssetLib/FBX/FBXDocument.cpp index ee4a6632b..3fb0964c4 100644 --- a/code/AssetLib/FBX/FBXDocument.cpp +++ b/code/AssetLib/FBX/FBXDocument.cpp @@ -2,7 +2,7 @@ Open Asset Import Library (assimp) ---------------------------------------------------------------------- -Copyright (c) 2006-2022, assimp team +Copyright (c) 2006-2024, assimp team All rights reserved. diff --git a/code/AssetLib/FBX/FBXDocument.h b/code/AssetLib/FBX/FBXDocument.h index 3af757a19..a103321c0 100644 --- a/code/AssetLib/FBX/FBXDocument.h +++ b/code/AssetLib/FBX/FBXDocument.h @@ -2,7 +2,7 @@ Open Asset Import Library (assimp) ---------------------------------------------------------------------- -Copyright (c) 2006-2022, assimp team +Copyright (c) 2006-2024, assimp team All rights reserved. diff --git a/code/AssetLib/FBX/FBXDocumentUtil.cpp b/code/AssetLib/FBX/FBXDocumentUtil.cpp index c41eb2747..64105f351 100644 --- a/code/AssetLib/FBX/FBXDocumentUtil.cpp +++ b/code/AssetLib/FBX/FBXDocumentUtil.cpp @@ -2,7 +2,7 @@ Open Asset Import Library (assimp) ---------------------------------------------------------------------- -Copyright (c) 2006-2022, assimp team +Copyright (c) 2006-2024, assimp team All rights reserved. diff --git a/code/AssetLib/FBX/FBXExportNode.cpp b/code/AssetLib/FBX/FBXExportNode.cpp index 21e591425..ae9586968 100644 --- a/code/AssetLib/FBX/FBXExportNode.cpp +++ b/code/AssetLib/FBX/FBXExportNode.cpp @@ -2,7 +2,7 @@ Open Asset Import Library (assimp) ---------------------------------------------------------------------- -Copyright (c) 2006-2022, assimp team +Copyright (c) 2006-2024, assimp team All rights reserved. diff --git a/code/AssetLib/FBX/FBXExportNode.h b/code/AssetLib/FBX/FBXExportNode.h index 99644b216..7661ab1be 100644 --- a/code/AssetLib/FBX/FBXExportNode.h +++ b/code/AssetLib/FBX/FBXExportNode.h @@ -2,7 +2,7 @@ Open Asset Import Library (assimp) ---------------------------------------------------------------------- -Copyright (c) 2006-2022, assimp team +Copyright (c) 2006-2024, assimp team All rights reserved. diff --git a/code/AssetLib/FBX/FBXExportProperty.cpp b/code/AssetLib/FBX/FBXExportProperty.cpp index 3216d7d85..5fbe84fa7 100644 --- a/code/AssetLib/FBX/FBXExportProperty.cpp +++ b/code/AssetLib/FBX/FBXExportProperty.cpp @@ -2,7 +2,7 @@ Open Asset Import Library (assimp) ---------------------------------------------------------------------- -Copyright (c) 2006-2022, assimp team +Copyright (c) 2006-2024, assimp team All rights reserved. diff --git a/code/AssetLib/FBX/FBXExportProperty.h b/code/AssetLib/FBX/FBXExportProperty.h index 26d0cf223..93f8cfbe0 100644 --- a/code/AssetLib/FBX/FBXExportProperty.h +++ b/code/AssetLib/FBX/FBXExportProperty.h @@ -2,7 +2,7 @@ Open Asset Import Library (assimp) ---------------------------------------------------------------------- -Copyright (c) 2006-2022, assimp team +Copyright (c) 2006-2024, assimp team All rights reserved. diff --git a/code/AssetLib/FBX/FBXExporter.cpp b/code/AssetLib/FBX/FBXExporter.cpp index 50daf7996..cbaf83f0f 100644 --- a/code/AssetLib/FBX/FBXExporter.cpp +++ b/code/AssetLib/FBX/FBXExporter.cpp @@ -2,7 +2,7 @@ Open Asset Import Library (assimp) ---------------------------------------------------------------------- -Copyright (c) 2006-2022, assimp team +Copyright (c) 2006-2024, assimp team All rights reserved. diff --git a/code/AssetLib/FBX/FBXExporter.h b/code/AssetLib/FBX/FBXExporter.h index 659f9368a..df9029196 100644 --- a/code/AssetLib/FBX/FBXExporter.h +++ b/code/AssetLib/FBX/FBXExporter.h @@ -2,7 +2,7 @@ Open Asset Import Library (assimp) ---------------------------------------------------------------------- -Copyright (c) 2006-2022, assimp team +Copyright (c) 2006-2024, assimp team All rights reserved. diff --git a/code/AssetLib/FBX/FBXImportSettings.h b/code/AssetLib/FBX/FBXImportSettings.h index 698901180..74290f7e0 100644 --- a/code/AssetLib/FBX/FBXImportSettings.h +++ b/code/AssetLib/FBX/FBXImportSettings.h @@ -2,7 +2,7 @@ Open Asset Import Library (assimp) ---------------------------------------------------------------------- -Copyright (c) 2006-2022, assimp team +Copyright (c) 2006-2024, assimp team All rights reserved. diff --git a/code/AssetLib/FBX/FBXImporter.cpp b/code/AssetLib/FBX/FBXImporter.cpp index afd4b11c1..3a8fb8b8a 100644 --- a/code/AssetLib/FBX/FBXImporter.cpp +++ b/code/AssetLib/FBX/FBXImporter.cpp @@ -2,7 +2,7 @@ Open Asset Import Library (assimp) ---------------------------------------------------------------------- -Copyright (c) 2006-2022, assimp team +Copyright (c) 2006-2024, assimp team All rights reserved. diff --git a/code/AssetLib/FBX/FBXImporter.h b/code/AssetLib/FBX/FBXImporter.h index d12b45969..8e8a7db78 100644 --- a/code/AssetLib/FBX/FBXImporter.h +++ b/code/AssetLib/FBX/FBXImporter.h @@ -2,7 +2,7 @@ Open Asset Import Library (assimp) ---------------------------------------------------------------------- -Copyright (c) 2006-2022, assimp team +Copyright (c) 2006-2024, assimp team All rights reserved. diff --git a/code/AssetLib/FBX/FBXMaterial.cpp b/code/AssetLib/FBX/FBXMaterial.cpp index bcb9bc42a..3872a4b38 100644 --- a/code/AssetLib/FBX/FBXMaterial.cpp +++ b/code/AssetLib/FBX/FBXMaterial.cpp @@ -2,7 +2,7 @@ Open Asset Import Library (assimp) ---------------------------------------------------------------------- -Copyright (c) 2006-2022, assimp team +Copyright (c) 2006-2024, assimp team All rights reserved. diff --git a/code/AssetLib/FBX/FBXMeshGeometry.cpp b/code/AssetLib/FBX/FBXMeshGeometry.cpp index 8c6499a91..3b706727a 100644 --- a/code/AssetLib/FBX/FBXMeshGeometry.cpp +++ b/code/AssetLib/FBX/FBXMeshGeometry.cpp @@ -2,7 +2,7 @@ Open Asset Import Library (assimp) ---------------------------------------------------------------------- -Copyright (c) 2006-2022, assimp team +Copyright (c) 2006-2024, assimp team All rights reserved. diff --git a/code/AssetLib/FBX/FBXMeshGeometry.h b/code/AssetLib/FBX/FBXMeshGeometry.h index 3d67ec567..980d1a334 100644 --- a/code/AssetLib/FBX/FBXMeshGeometry.h +++ b/code/AssetLib/FBX/FBXMeshGeometry.h @@ -2,7 +2,7 @@ Open Asset Import Library (assimp) ---------------------------------------------------------------------- -Copyright (c) 2006-2023, assimp team +Copyright (c) 2006-2024, assimp team All rights reserved. diff --git a/code/AssetLib/FBX/FBXModel.cpp b/code/AssetLib/FBX/FBXModel.cpp index d731d2e29..c108dd78b 100644 --- a/code/AssetLib/FBX/FBXModel.cpp +++ b/code/AssetLib/FBX/FBXModel.cpp @@ -2,7 +2,7 @@ Open Asset Import Library (assimp) ---------------------------------------------------------------------- -Copyright (c) 2006-2022, assimp team +Copyright (c) 2006-2024, assimp team All rights reserved. diff --git a/code/AssetLib/FBX/FBXNodeAttribute.cpp b/code/AssetLib/FBX/FBXNodeAttribute.cpp index 34fcdcf77..1e7dfa8c0 100644 --- a/code/AssetLib/FBX/FBXNodeAttribute.cpp +++ b/code/AssetLib/FBX/FBXNodeAttribute.cpp @@ -2,7 +2,7 @@ Open Asset Import Library (assimp) ---------------------------------------------------------------------- -Copyright (c) 2006-2022, assimp team +Copyright (c) 2006-2024, assimp team All rights reserved. diff --git a/code/AssetLib/FBX/FBXParser.cpp b/code/AssetLib/FBX/FBXParser.cpp index 7baa7ed39..d0482e067 100644 --- a/code/AssetLib/FBX/FBXParser.cpp +++ b/code/AssetLib/FBX/FBXParser.cpp @@ -2,7 +2,7 @@ Open Asset Import Library (assimp) ---------------------------------------------------------------------- -Copyright (c) 2006-2022, assimp team +Copyright (c) 2006-2024, assimp team All rights reserved. diff --git a/code/AssetLib/FBX/FBXParser.h b/code/AssetLib/FBX/FBXParser.h index 5f231738d..63dbb023b 100644 --- a/code/AssetLib/FBX/FBXParser.h +++ b/code/AssetLib/FBX/FBXParser.h @@ -2,7 +2,7 @@ Open Asset Import Library (assimp) ---------------------------------------------------------------------- -Copyright (c) 2006-2022, assimp team +Copyright (c) 2006-2024, assimp team All rights reserved. diff --git a/code/AssetLib/FBX/FBXProperties.cpp b/code/AssetLib/FBX/FBXProperties.cpp index 1c050617d..df39098fa 100644 --- a/code/AssetLib/FBX/FBXProperties.cpp +++ b/code/AssetLib/FBX/FBXProperties.cpp @@ -2,7 +2,7 @@ Open Asset Import Library (assimp) ---------------------------------------------------------------------- -Copyright (c) 2006-2022, assimp team +Copyright (c) 2006-2024, assimp team All rights reserved. diff --git a/code/AssetLib/FBX/FBXProperties.h b/code/AssetLib/FBX/FBXProperties.h index 18816117a..4799b8056 100644 --- a/code/AssetLib/FBX/FBXProperties.h +++ b/code/AssetLib/FBX/FBXProperties.h @@ -2,7 +2,7 @@ Open Asset Import Library (assimp) ---------------------------------------------------------------------- -Copyright (c) 2006-2022, assimp team +Copyright (c) 2006-2024, assimp team All rights reserved. diff --git a/code/AssetLib/FBX/FBXTokenizer.cpp b/code/AssetLib/FBX/FBXTokenizer.cpp index 45d5e7750..007e08d46 100644 --- a/code/AssetLib/FBX/FBXTokenizer.cpp +++ b/code/AssetLib/FBX/FBXTokenizer.cpp @@ -2,7 +2,7 @@ Open Asset Import Library (assimp) ---------------------------------------------------------------------- -Copyright (c) 2006-2022, assimp team +Copyright (c) 2006-2024, assimp team All rights reserved. diff --git a/code/AssetLib/FBX/FBXTokenizer.h b/code/AssetLib/FBX/FBXTokenizer.h index 05a0725bd..dedfab66a 100644 --- a/code/AssetLib/FBX/FBXTokenizer.h +++ b/code/AssetLib/FBX/FBXTokenizer.h @@ -2,7 +2,7 @@ Open Asset Import Library (assimp) ---------------------------------------------------------------------- -Copyright (c) 2006-2022, assimp team +Copyright (c) 2006-2024, assimp team All rights reserved. diff --git a/code/AssetLib/FBX/FBXUtil.cpp b/code/AssetLib/FBX/FBXUtil.cpp index e2903c536..a787a9f1d 100644 --- a/code/AssetLib/FBX/FBXUtil.cpp +++ b/code/AssetLib/FBX/FBXUtil.cpp @@ -2,7 +2,7 @@ Open Asset Import Library (assimp) ---------------------------------------------------------------------- -Copyright (c) 2006-2022, assimp team +Copyright (c) 2006-2024, assimp team All rights reserved. diff --git a/code/AssetLib/FBX/FBXUtil.h b/code/AssetLib/FBX/FBXUtil.h index 4674a5054..eb9ae14ed 100644 --- a/code/AssetLib/FBX/FBXUtil.h +++ b/code/AssetLib/FBX/FBXUtil.h @@ -2,7 +2,7 @@ Open Asset Import Library (assimp) ---------------------------------------------------------------------- -Copyright (c) 2006-2022, assimp team +Copyright (c) 2006-2024, assimp team All rights reserved. diff --git a/code/AssetLib/HMP/HMPFileData.h b/code/AssetLib/HMP/HMPFileData.h index b297136ba..4fc54e2c8 100644 --- a/code/AssetLib/HMP/HMPFileData.h +++ b/code/AssetLib/HMP/HMPFileData.h @@ -2,7 +2,7 @@ Open Asset Import Library (assimp) ---------------------------------------------------------------------- -Copyright (c) 2006-2022, assimp team +Copyright (c) 2006-2024, assimp team All rights reserved. diff --git a/code/AssetLib/HMP/HMPLoader.cpp b/code/AssetLib/HMP/HMPLoader.cpp index 5ccb2b474..30931a920 100644 --- a/code/AssetLib/HMP/HMPLoader.cpp +++ b/code/AssetLib/HMP/HMPLoader.cpp @@ -3,7 +3,7 @@ Open Asset Import Library (assimp) --------------------------------------------------------------------------- -Copyright (c) 2006-2022, assimp team +Copyright (c) 2006-2024, assimp team All rights reserved. diff --git a/code/AssetLib/HMP/HMPLoader.h b/code/AssetLib/HMP/HMPLoader.h index 4d5f5f22f..e665b8d18 100644 --- a/code/AssetLib/HMP/HMPLoader.h +++ b/code/AssetLib/HMP/HMPLoader.h @@ -2,7 +2,7 @@ Open Asset Import Library (assimp) ---------------------------------------------------------------------- -Copyright (c) 2006-2022, assimp team +Copyright (c) 2006-2024, assimp team All rights reserved. diff --git a/code/AssetLib/HMP/HalfLifeFileData.h b/code/AssetLib/HMP/HalfLifeFileData.h index f47862b7a..687b6108c 100644 --- a/code/AssetLib/HMP/HalfLifeFileData.h +++ b/code/AssetLib/HMP/HalfLifeFileData.h @@ -2,7 +2,7 @@ Open Asset Import Library (assimp) ---------------------------------------------------------------------- -Copyright (c) 2006-2022, assimp team +Copyright (c) 2006-2024, assimp team All rights reserved. diff --git a/code/AssetLib/IFC/IFCBoolean.cpp b/code/AssetLib/IFC/IFCBoolean.cpp index f4d53990e..559bd7b2f 100644 --- a/code/AssetLib/IFC/IFCBoolean.cpp +++ b/code/AssetLib/IFC/IFCBoolean.cpp @@ -2,7 +2,7 @@ Open Asset Import Library (assimp) ---------------------------------------------------------------------- -Copyright (c) 2006-2022, assimp team +Copyright (c) 2006-2024, assimp team All rights reserved. Redistribution and use of this software in source and binary forms, diff --git a/code/AssetLib/IFC/IFCCurve.cpp b/code/AssetLib/IFC/IFCCurve.cpp index 44165befc..847803dfa 100644 --- a/code/AssetLib/IFC/IFCCurve.cpp +++ b/code/AssetLib/IFC/IFCCurve.cpp @@ -2,7 +2,7 @@ Open Asset Import Library (assimp) ---------------------------------------------------------------------- -Copyright (c) 2006-2022, assimp team +Copyright (c) 2006-2024, assimp team All rights reserved. diff --git a/code/AssetLib/IFC/IFCGeometry.cpp b/code/AssetLib/IFC/IFCGeometry.cpp index 83afd2b59..d488b2376 100644 --- a/code/AssetLib/IFC/IFCGeometry.cpp +++ b/code/AssetLib/IFC/IFCGeometry.cpp @@ -2,7 +2,7 @@ Open Asset Import Library (assimp) ---------------------------------------------------------------------- -Copyright (c) 2006-2022, assimp team +Copyright (c) 2006-2024, assimp team All rights reserved. Redistribution and use of this software in source and binary forms, diff --git a/code/AssetLib/IFC/IFCLoader.cpp b/code/AssetLib/IFC/IFCLoader.cpp index c919d9982..9414697df 100644 --- a/code/AssetLib/IFC/IFCLoader.cpp +++ b/code/AssetLib/IFC/IFCLoader.cpp @@ -2,7 +2,7 @@ Open Asset Import Library (assimp) ---------------------------------------------------------------------- -Copyright (c) 2006-2022, assimp team +Copyright (c) 2006-2024, assimp team All rights reserved. diff --git a/code/AssetLib/IFC/IFCLoader.h b/code/AssetLib/IFC/IFCLoader.h index 9651b633a..d518650b7 100644 --- a/code/AssetLib/IFC/IFCLoader.h +++ b/code/AssetLib/IFC/IFCLoader.h @@ -2,7 +2,7 @@ Open Asset Import Library (assimp) ---------------------------------------------------------------------- -Copyright (c) 2006-2022, assimp team +Copyright (c) 2006-2024, assimp team All rights reserved. diff --git a/code/AssetLib/IFC/IFCMaterial.cpp b/code/AssetLib/IFC/IFCMaterial.cpp index 0b7b83e7c..fd4003a67 100644 --- a/code/AssetLib/IFC/IFCMaterial.cpp +++ b/code/AssetLib/IFC/IFCMaterial.cpp @@ -2,7 +2,7 @@ Open Asset Import Library (assimp) ---------------------------------------------------------------------- -Copyright (c) 2006-2022, assimp team +Copyright (c) 2006-2024, assimp team All rights reserved. diff --git a/code/AssetLib/IFC/IFCOpenings.cpp b/code/AssetLib/IFC/IFCOpenings.cpp index c47446dda..1d37dd8ef 100644 --- a/code/AssetLib/IFC/IFCOpenings.cpp +++ b/code/AssetLib/IFC/IFCOpenings.cpp @@ -2,7 +2,7 @@ Open Asset Import Library (assimp) ---------------------------------------------------------------------- -Copyright (c) 2006-2022, assimp team +Copyright (c) 2006-2024, assimp team All rights reserved. Redistribution and use of this software in source and binary forms, diff --git a/code/AssetLib/IFC/IFCProfile.cpp b/code/AssetLib/IFC/IFCProfile.cpp index 0e4670560..72a96c29b 100644 --- a/code/AssetLib/IFC/IFCProfile.cpp +++ b/code/AssetLib/IFC/IFCProfile.cpp @@ -2,7 +2,7 @@ Open Asset Import Library (assimp) ---------------------------------------------------------------------- -Copyright (c) 2006-2022, assimp team +Copyright (c) 2006-2024, assimp team All rights reserved. diff --git a/code/AssetLib/IFC/IFCUtil.cpp b/code/AssetLib/IFC/IFCUtil.cpp index 27f3141c8..3977e22b5 100644 --- a/code/AssetLib/IFC/IFCUtil.cpp +++ b/code/AssetLib/IFC/IFCUtil.cpp @@ -2,7 +2,7 @@ Open Asset Import Library (assimp) ---------------------------------------------------------------------- -Copyright (c) 2006-2022, assimp team +Copyright (c) 2006-2024, assimp team All rights reserved. diff --git a/code/AssetLib/IFC/IFCUtil.h b/code/AssetLib/IFC/IFCUtil.h index f9063ce22..885bcb48f 100644 --- a/code/AssetLib/IFC/IFCUtil.h +++ b/code/AssetLib/IFC/IFCUtil.h @@ -2,7 +2,7 @@ Open Asset Import Library (assimp) ---------------------------------------------------------------------- -Copyright (c) 2006-2022, assimp team +Copyright (c) 2006-2024, assimp team All rights reserved. diff --git a/code/AssetLib/Irr/IRRLoader.cpp b/code/AssetLib/Irr/IRRLoader.cpp index 2a481a6d8..f41a2543d 100644 --- a/code/AssetLib/Irr/IRRLoader.cpp +++ b/code/AssetLib/Irr/IRRLoader.cpp @@ -3,7 +3,7 @@ Open Asset Import Library (assimp) --------------------------------------------------------------------------- -Copyright (c) 2006-2022, assimp team +Copyright (c) 2006-2024, assimp team All rights reserved. diff --git a/code/AssetLib/Irr/IRRLoader.h b/code/AssetLib/Irr/IRRLoader.h index 72ad5d35e..2a8bfd562 100644 --- a/code/AssetLib/Irr/IRRLoader.h +++ b/code/AssetLib/Irr/IRRLoader.h @@ -2,7 +2,7 @@ Open Asset Import Library (assimp) ---------------------------------------------------------------------- -Copyright (c) 2006-2022, assimp team +Copyright (c) 2006-2024, assimp team All rights reserved. diff --git a/code/AssetLib/Irr/IRRShared.cpp b/code/AssetLib/Irr/IRRShared.cpp index 9ab8d0899..20d56bb02 100644 --- a/code/AssetLib/Irr/IRRShared.cpp +++ b/code/AssetLib/Irr/IRRShared.cpp @@ -3,7 +3,7 @@ Open Asset Import Library (assimp) --------------------------------------------------------------------------- -Copyright (c) 2006-2022, assimp team +Copyright (c) 2006-2024, assimp team All rights reserved. diff --git a/code/AssetLib/LWO/LWOAnimation.cpp b/code/AssetLib/LWO/LWOAnimation.cpp index 8dda4586f..5b9c6882e 100644 --- a/code/AssetLib/LWO/LWOAnimation.cpp +++ b/code/AssetLib/LWO/LWOAnimation.cpp @@ -2,7 +2,7 @@ Open Asset Import Library (assimp) ---------------------------------------------------------------------- -Copyright (c) 2006-2022, assimp team +Copyright (c) 2006-2024, assimp team All rights reserved. diff --git a/code/AssetLib/LWO/LWOAnimation.h b/code/AssetLib/LWO/LWOAnimation.h index 1e419d461..9daa7009c 100644 --- a/code/AssetLib/LWO/LWOAnimation.h +++ b/code/AssetLib/LWO/LWOAnimation.h @@ -2,7 +2,7 @@ Open Asset Import Library (assimp) ---------------------------------------------------------------------- -Copyright (c) 2006-2022, assimp team +Copyright (c) 2006-2024, assimp team All rights reserved. diff --git a/code/AssetLib/LWO/LWOBLoader.cpp b/code/AssetLib/LWO/LWOBLoader.cpp index fc9132d88..b5c14f158 100644 --- a/code/AssetLib/LWO/LWOBLoader.cpp +++ b/code/AssetLib/LWO/LWOBLoader.cpp @@ -3,7 +3,7 @@ Open Asset Import Library (assimp) --------------------------------------------------------------------------- -Copyright (c) 2006-2022, assimp team +Copyright (c) 2006-2024, assimp team diff --git a/code/AssetLib/LWO/LWOFileData.h b/code/AssetLib/LWO/LWOFileData.h index 656dd4529..c81111251 100644 --- a/code/AssetLib/LWO/LWOFileData.h +++ b/code/AssetLib/LWO/LWOFileData.h @@ -2,7 +2,7 @@ Open Asset Import Library (assimp) ---------------------------------------------------------------------- -Copyright (c) 2006-2022, assimp team +Copyright (c) 2006-2024, assimp team All rights reserved. diff --git a/code/AssetLib/LWO/LWOLoader.cpp b/code/AssetLib/LWO/LWOLoader.cpp index 7e93b65f8..025ca7408 100644 --- a/code/AssetLib/LWO/LWOLoader.cpp +++ b/code/AssetLib/LWO/LWOLoader.cpp @@ -3,7 +3,7 @@ Open Asset Import Library (assimp) --------------------------------------------------------------------------- -Copyright (c) 2006-2022, assimp team +Copyright (c) 2006-2024, assimp team All rights reserved. diff --git a/code/AssetLib/LWO/LWOLoader.h b/code/AssetLib/LWO/LWOLoader.h index 9e116a3cc..3f81ff449 100644 --- a/code/AssetLib/LWO/LWOLoader.h +++ b/code/AssetLib/LWO/LWOLoader.h @@ -2,7 +2,7 @@ Open Asset Import Library (assimp) ---------------------------------------------------------------------- -Copyright (c) 2006-2022, assimp team +Copyright (c) 2006-2024, assimp team All rights reserved. diff --git a/code/AssetLib/LWO/LWOMaterial.cpp b/code/AssetLib/LWO/LWOMaterial.cpp index 8d83dfb67..1d7d137e1 100644 --- a/code/AssetLib/LWO/LWOMaterial.cpp +++ b/code/AssetLib/LWO/LWOMaterial.cpp @@ -3,7 +3,7 @@ Open Asset Import Library (assimp) --------------------------------------------------------------------------- -Copyright (c) 2006-2022, assimp team +Copyright (c) 2006-2024, assimp team diff --git a/code/AssetLib/LWS/LWSLoader.h b/code/AssetLib/LWS/LWSLoader.h index 5db6852c1..f66688249 100644 --- a/code/AssetLib/LWS/LWSLoader.h +++ b/code/AssetLib/LWS/LWSLoader.h @@ -2,7 +2,7 @@ Open Asset Import Library (assimp) ---------------------------------------------------------------------- -Copyright (c) 2006-2022, assimp team +Copyright (c) 2006-2024, assimp team All rights reserved. diff --git a/code/AssetLib/M3D/M3DExporter.cpp b/code/AssetLib/M3D/M3DExporter.cpp index cf87b6221..5545be415 100644 --- a/code/AssetLib/M3D/M3DExporter.cpp +++ b/code/AssetLib/M3D/M3DExporter.cpp @@ -2,7 +2,7 @@ Open Asset Import Library (assimp) ---------------------------------------------------------------------- -Copyright (c) 2006-2022, assimp team +Copyright (c) 2006-2024, assimp team Copyright (c) 2019 bzt All rights reserved. diff --git a/code/AssetLib/M3D/M3DExporter.h b/code/AssetLib/M3D/M3DExporter.h index d77743f56..0e9ab4305 100644 --- a/code/AssetLib/M3D/M3DExporter.h +++ b/code/AssetLib/M3D/M3DExporter.h @@ -2,7 +2,7 @@ Open Asset Import Library (assimp) ---------------------------------------------------------------------- -Copyright (c) 2006-2022, assimp team +Copyright (c) 2006-2024, assimp team Copyright (c) 2019 bzt All rights reserved. diff --git a/code/AssetLib/M3D/M3DImporter.cpp b/code/AssetLib/M3D/M3DImporter.cpp index 71f416139..b74b72dc8 100644 --- a/code/AssetLib/M3D/M3DImporter.cpp +++ b/code/AssetLib/M3D/M3DImporter.cpp @@ -2,7 +2,7 @@ Open Asset Import Library (assimp) ---------------------------------------------------------------------- -Copyright (c) 2006-2022, assimp team +Copyright (c) 2006-2024, assimp team Copyright (c) 2019 bzt All rights reserved. diff --git a/code/AssetLib/M3D/M3DImporter.h b/code/AssetLib/M3D/M3DImporter.h index 9ca8f9211..d9e546f39 100644 --- a/code/AssetLib/M3D/M3DImporter.h +++ b/code/AssetLib/M3D/M3DImporter.h @@ -2,7 +2,7 @@ Open Asset Import Library (assimp) ---------------------------------------------------------------------- -Copyright (c) 2006-2022, assimp team +Copyright (c) 2006-2024, assimp team Copyright (c) 2019 bzt All rights reserved. diff --git a/code/AssetLib/M3D/M3DMaterials.h b/code/AssetLib/M3D/M3DMaterials.h index a1b0fd742..dc87a99c7 100644 --- a/code/AssetLib/M3D/M3DMaterials.h +++ b/code/AssetLib/M3D/M3DMaterials.h @@ -2,7 +2,7 @@ Open Asset Import Library (assimp) ---------------------------------------------------------------------- -Copyright (c) 2006-2022, assimp team +Copyright (c) 2006-2024, assimp team Copyright (c) 2019 bzt All rights reserved. diff --git a/code/AssetLib/M3D/M3DWrapper.cpp b/code/AssetLib/M3D/M3DWrapper.cpp index 05087d592..3741bbca3 100644 --- a/code/AssetLib/M3D/M3DWrapper.cpp +++ b/code/AssetLib/M3D/M3DWrapper.cpp @@ -2,7 +2,7 @@ Open Asset Import Library (assimp) ---------------------------------------------------------------------- -Copyright (c) 2006-2022, assimp team +Copyright (c) 2006-2024, assimp team Copyright (c) 2019 bzt All rights reserved. diff --git a/code/AssetLib/M3D/M3DWrapper.h b/code/AssetLib/M3D/M3DWrapper.h index 880aca996..8a3fd92be 100644 --- a/code/AssetLib/M3D/M3DWrapper.h +++ b/code/AssetLib/M3D/M3DWrapper.h @@ -3,7 +3,7 @@ Open Asset Import Library (assimp) ---------------------------------------------------------------------- -Copyright (c) 2006-2022, assimp team +Copyright (c) 2006-2024, assimp team Copyright (c) 2019 bzt All rights reserved. diff --git a/code/AssetLib/MD2/MD2FileData.h b/code/AssetLib/MD2/MD2FileData.h index 3bce8feee..6c1f7069b 100644 --- a/code/AssetLib/MD2/MD2FileData.h +++ b/code/AssetLib/MD2/MD2FileData.h @@ -2,7 +2,7 @@ Open Asset Import Library (assimp) ---------------------------------------------------------------------- -Copyright (c) 2006-2022, assimp team +Copyright (c) 2006-2024, assimp team All rights reserved. diff --git a/code/AssetLib/MD2/MD2Loader.cpp b/code/AssetLib/MD2/MD2Loader.cpp index 596d26414..99dc70d08 100644 --- a/code/AssetLib/MD2/MD2Loader.cpp +++ b/code/AssetLib/MD2/MD2Loader.cpp @@ -3,7 +3,7 @@ Open Asset Import Library (assimp) --------------------------------------------------------------------------- -Copyright (c) 2006-2022, assimp team +Copyright (c) 2006-2024, assimp team All rights reserved. diff --git a/code/AssetLib/MD2/MD2Loader.h b/code/AssetLib/MD2/MD2Loader.h index bab026ea0..5ac34ad4c 100644 --- a/code/AssetLib/MD2/MD2Loader.h +++ b/code/AssetLib/MD2/MD2Loader.h @@ -2,7 +2,7 @@ Open Asset Import Library (assimp) ---------------------------------------------------------------------- -Copyright (c) 2006-2022, assimp team +Copyright (c) 2006-2024, assimp team All rights reserved. diff --git a/code/AssetLib/MD2/MD2NormalTable.h b/code/AssetLib/MD2/MD2NormalTable.h index 1837939e8..7d13b9ad1 100644 --- a/code/AssetLib/MD2/MD2NormalTable.h +++ b/code/AssetLib/MD2/MD2NormalTable.h @@ -2,7 +2,7 @@ Open Asset Import Library (assimp) ---------------------------------------------------------------------- -Copyright (c) 2006-2022, assimp team +Copyright (c) 2006-2024, assimp team All rights reserved. diff --git a/code/AssetLib/MD3/MD3FileData.h b/code/AssetLib/MD3/MD3FileData.h index 01475e679..4251243b3 100644 --- a/code/AssetLib/MD3/MD3FileData.h +++ b/code/AssetLib/MD3/MD3FileData.h @@ -2,7 +2,7 @@ Open Asset Import Library (assimp) ---------------------------------------------------------------------- -Copyright (c) 2006-2022, assimp team +Copyright (c) 2006-2024, assimp team All rights reserved. diff --git a/code/AssetLib/MD3/MD3Loader.cpp b/code/AssetLib/MD3/MD3Loader.cpp index e4179d05d..3dd8d9c66 100644 --- a/code/AssetLib/MD3/MD3Loader.cpp +++ b/code/AssetLib/MD3/MD3Loader.cpp @@ -3,7 +3,7 @@ Open Asset Import Library (assimp) --------------------------------------------------------------------------- -Copyright (c) 2006-2022, assimp team +Copyright (c) 2006-2024, assimp team diff --git a/code/AssetLib/MD3/MD3Loader.h b/code/AssetLib/MD3/MD3Loader.h index d911bb1da..eee66a3df 100644 --- a/code/AssetLib/MD3/MD3Loader.h +++ b/code/AssetLib/MD3/MD3Loader.h @@ -2,7 +2,7 @@ Open Asset Import Library (assimp) ---------------------------------------------------------------------- -Copyright (c) 2006-2022, assimp team +Copyright (c) 2006-2024, assimp team All rights reserved. diff --git a/code/AssetLib/MD5/MD5Loader.cpp b/code/AssetLib/MD5/MD5Loader.cpp index d4cdc0c44..0976484a4 100644 --- a/code/AssetLib/MD5/MD5Loader.cpp +++ b/code/AssetLib/MD5/MD5Loader.cpp @@ -3,7 +3,7 @@ Open Asset Import Library (assimp) --------------------------------------------------------------------------- -Copyright (c) 2006-2022, assimp team +Copyright (c) 2006-2024, assimp team All rights reserved. diff --git a/code/AssetLib/MDC/MDCFileData.h b/code/AssetLib/MDC/MDCFileData.h index 36c589e91..5d7084b5d 100644 --- a/code/AssetLib/MDC/MDCFileData.h +++ b/code/AssetLib/MDC/MDCFileData.h @@ -2,7 +2,7 @@ Open Asset Import Library (assimp) ---------------------------------------------------------------------- -Copyright (c) 2006-2022, assimp team +Copyright (c) 2006-2024, assimp team All rights reserved. diff --git a/code/AssetLib/MDC/MDCLoader.cpp b/code/AssetLib/MDC/MDCLoader.cpp index 87247adec..c81ba67a6 100644 --- a/code/AssetLib/MDC/MDCLoader.cpp +++ b/code/AssetLib/MDC/MDCLoader.cpp @@ -3,7 +3,7 @@ Open Asset Import Library (assimp) --------------------------------------------------------------------------- -Copyright (c) 2006-2022, assimp team +Copyright (c) 2006-2024, assimp team All rights reserved. diff --git a/code/AssetLib/MDC/MDCLoader.h b/code/AssetLib/MDC/MDCLoader.h index a1f8d9fc9..09ecc6865 100644 --- a/code/AssetLib/MDC/MDCLoader.h +++ b/code/AssetLib/MDC/MDCLoader.h @@ -2,7 +2,7 @@ Open Asset Import Library (assimp) ---------------------------------------------------------------------- -Copyright (c) 2006-2022, assimp team +Copyright (c) 2006-2024, assimp team All rights reserved. diff --git a/code/AssetLib/MDL/HalfLife/HL1FileData.h b/code/AssetLib/MDL/HalfLife/HL1FileData.h index 28b1b2822..485f538ab 100644 --- a/code/AssetLib/MDL/HalfLife/HL1FileData.h +++ b/code/AssetLib/MDL/HalfLife/HL1FileData.h @@ -3,7 +3,7 @@ Open Asset Import Library (assimp) --------------------------------------------------------------------------- -Copyright (c) 2006-2022, assimp team +Copyright (c) 2006-2024, assimp team All rights reserved. diff --git a/code/AssetLib/MDL/HalfLife/HL1ImportDefinitions.h b/code/AssetLib/MDL/HalfLife/HL1ImportDefinitions.h index d412aeede..344574d24 100644 --- a/code/AssetLib/MDL/HalfLife/HL1ImportDefinitions.h +++ b/code/AssetLib/MDL/HalfLife/HL1ImportDefinitions.h @@ -3,7 +3,7 @@ Open Asset Import Library (assimp) --------------------------------------------------------------------------- -Copyright (c) 2006-2022, assimp team +Copyright (c) 2006-2024, assimp team All rights reserved. diff --git a/code/AssetLib/MDL/HalfLife/HL1ImportSettings.h b/code/AssetLib/MDL/HalfLife/HL1ImportSettings.h index 340ba2da5..52f98cb58 100644 --- a/code/AssetLib/MDL/HalfLife/HL1ImportSettings.h +++ b/code/AssetLib/MDL/HalfLife/HL1ImportSettings.h @@ -3,7 +3,7 @@ Open Asset Import Library (assimp) --------------------------------------------------------------------------- -Copyright (c) 2006-2022, assimp team +Copyright (c) 2006-2024, assimp team All rights reserved. diff --git a/code/AssetLib/MDL/HalfLife/HL1MDLLoader.cpp b/code/AssetLib/MDL/HalfLife/HL1MDLLoader.cpp index a8141fcc1..2d7f6a7c2 100644 --- a/code/AssetLib/MDL/HalfLife/HL1MDLLoader.cpp +++ b/code/AssetLib/MDL/HalfLife/HL1MDLLoader.cpp @@ -3,7 +3,7 @@ Open Asset Import Library (assimp) --------------------------------------------------------------------------- -Copyright (c) 2006-2022, assimp team +Copyright (c) 2006-2024, assimp team All rights reserved. diff --git a/code/AssetLib/MDL/HalfLife/HL1MDLLoader.h b/code/AssetLib/MDL/HalfLife/HL1MDLLoader.h index 286b6e64c..ab5bb6942 100644 --- a/code/AssetLib/MDL/HalfLife/HL1MDLLoader.h +++ b/code/AssetLib/MDL/HalfLife/HL1MDLLoader.h @@ -3,7 +3,7 @@ Open Asset Import Library (assimp) --------------------------------------------------------------------------- -Copyright (c) 2006-2022, assimp team +Copyright (c) 2006-2024, assimp team All rights reserved. diff --git a/code/AssetLib/MDL/HalfLife/HL1MeshTrivert.h b/code/AssetLib/MDL/HalfLife/HL1MeshTrivert.h index 4ef8a13ce..9c389a659 100644 --- a/code/AssetLib/MDL/HalfLife/HL1MeshTrivert.h +++ b/code/AssetLib/MDL/HalfLife/HL1MeshTrivert.h @@ -3,7 +3,7 @@ Open Asset Import Library (assimp) --------------------------------------------------------------------------- -Copyright (c) 2006-2022, assimp team +Copyright (c) 2006-2024, assimp team All rights reserved. diff --git a/code/AssetLib/MDL/HalfLife/HalfLifeMDLBaseHeader.h b/code/AssetLib/MDL/HalfLife/HalfLifeMDLBaseHeader.h index c7808c401..25ef27bca 100644 --- a/code/AssetLib/MDL/HalfLife/HalfLifeMDLBaseHeader.h +++ b/code/AssetLib/MDL/HalfLife/HalfLifeMDLBaseHeader.h @@ -3,7 +3,7 @@ Open Asset Import Library (assimp) --------------------------------------------------------------------------- -Copyright (c) 2006-2022, assimp team +Copyright (c) 2006-2024, assimp team All rights reserved. diff --git a/code/AssetLib/MDL/HalfLife/LogFunctions.h b/code/AssetLib/MDL/HalfLife/LogFunctions.h index 003774dc1..c8cdf9b15 100644 --- a/code/AssetLib/MDL/HalfLife/LogFunctions.h +++ b/code/AssetLib/MDL/HalfLife/LogFunctions.h @@ -3,7 +3,7 @@ Open Asset Import Library (assimp) --------------------------------------------------------------------------- -Copyright (c) 2006-2022, assimp team +Copyright (c) 2006-2024, assimp team All rights reserved. diff --git a/code/AssetLib/MDL/HalfLife/UniqueNameGenerator.cpp b/code/AssetLib/MDL/HalfLife/UniqueNameGenerator.cpp index 3cca8c558..b79ec3613 100644 --- a/code/AssetLib/MDL/HalfLife/UniqueNameGenerator.cpp +++ b/code/AssetLib/MDL/HalfLife/UniqueNameGenerator.cpp @@ -3,7 +3,7 @@ Open Asset Import Library (assimp) --------------------------------------------------------------------------- -Copyright (c) 2006-2022, assimp team +Copyright (c) 2006-2024, assimp team All rights reserved. diff --git a/code/AssetLib/MDL/HalfLife/UniqueNameGenerator.h b/code/AssetLib/MDL/HalfLife/UniqueNameGenerator.h index 73b6f9e74..cf190bc3b 100644 --- a/code/AssetLib/MDL/HalfLife/UniqueNameGenerator.h +++ b/code/AssetLib/MDL/HalfLife/UniqueNameGenerator.h @@ -3,7 +3,7 @@ Open Asset Import Library (assimp) --------------------------------------------------------------------------- -Copyright (c) 2006-2022, assimp team +Copyright (c) 2006-2024, assimp team All rights reserved. diff --git a/code/AssetLib/MDL/MDLDefaultColorMap.h b/code/AssetLib/MDL/MDLDefaultColorMap.h index 2eecac2dc..cbdc977ad 100644 --- a/code/AssetLib/MDL/MDLDefaultColorMap.h +++ b/code/AssetLib/MDL/MDLDefaultColorMap.h @@ -2,7 +2,7 @@ Open Asset Import Library (assimp) ---------------------------------------------------------------------- -Copyright (c) 2006-2022, assimp team +Copyright (c) 2006-2024, assimp team All rights reserved. diff --git a/code/AssetLib/MDL/MDLFileData.h b/code/AssetLib/MDL/MDLFileData.h index 7ec2afe9a..62117e788 100644 --- a/code/AssetLib/MDL/MDLFileData.h +++ b/code/AssetLib/MDL/MDLFileData.h @@ -2,7 +2,7 @@ Open Asset Import Library (assimp) ---------------------------------------------------------------------- -Copyright (c) 2006-2022, assimp team +Copyright (c) 2006-2024, assimp team All rights reserved. diff --git a/code/AssetLib/MDL/MDLLoader.cpp b/code/AssetLib/MDL/MDLLoader.cpp index 2b14fe980..99b0145af 100644 --- a/code/AssetLib/MDL/MDLLoader.cpp +++ b/code/AssetLib/MDL/MDLLoader.cpp @@ -3,7 +3,7 @@ Open Asset Import Library (assimp) --------------------------------------------------------------------------- -Copyright (c) 2006-2022, assimp team +Copyright (c) 2006-2024, assimp team All rights reserved. diff --git a/code/AssetLib/MDL/MDLLoader.h b/code/AssetLib/MDL/MDLLoader.h index 333f7c8b1..f99f061ce 100644 --- a/code/AssetLib/MDL/MDLLoader.h +++ b/code/AssetLib/MDL/MDLLoader.h @@ -2,7 +2,7 @@ Open Asset Import Library (assimp) ---------------------------------------------------------------------- -Copyright (c) 2006-2022, assimp team +Copyright (c) 2006-2024, assimp team All rights reserved. diff --git a/code/AssetLib/MDL/MDLMaterialLoader.cpp b/code/AssetLib/MDL/MDLMaterialLoader.cpp index f8dafdb3e..38c42c1a5 100644 --- a/code/AssetLib/MDL/MDLMaterialLoader.cpp +++ b/code/AssetLib/MDL/MDLMaterialLoader.cpp @@ -3,7 +3,7 @@ Open Asset Import Library (assimp) --------------------------------------------------------------------------- -Copyright (c) 2006-2022, assimp team +Copyright (c) 2006-2024, assimp team All rights reserved. diff --git a/code/AssetLib/MMD/MMDCpp14.h b/code/AssetLib/MMD/MMDCpp14.h index 10d376829..4a04bf69e 100644 --- a/code/AssetLib/MMD/MMDCpp14.h +++ b/code/AssetLib/MMD/MMDCpp14.h @@ -2,7 +2,7 @@ Open Asset Import Library (assimp) ---------------------------------------------------------------------- -Copyright (c) 2006-2022, assimp team +Copyright (c) 2006-2024, assimp team All rights reserved. diff --git a/code/AssetLib/MMD/MMDImporter.cpp b/code/AssetLib/MMD/MMDImporter.cpp index b96d45c98..1e88cefd2 100644 --- a/code/AssetLib/MMD/MMDImporter.cpp +++ b/code/AssetLib/MMD/MMDImporter.cpp @@ -3,7 +3,7 @@ Open Asset Import Library (assimp) --------------------------------------------------------------------------- -Copyright (c) 2006-2022, assimp team +Copyright (c) 2006-2024, assimp team All rights reserved. diff --git a/code/AssetLib/MMD/MMDImporter.h b/code/AssetLib/MMD/MMDImporter.h index 1f584bf12..71fc534a4 100644 --- a/code/AssetLib/MMD/MMDImporter.h +++ b/code/AssetLib/MMD/MMDImporter.h @@ -2,7 +2,7 @@ Open Asset Import Library (assimp) ---------------------------------------------------------------------- -Copyright (c) 2006-2022, assimp team +Copyright (c) 2006-2024, assimp team All rights reserved. Redistribution and use of this software in source and binary forms, diff --git a/code/AssetLib/MMD/MMDPmdParser.h b/code/AssetLib/MMD/MMDPmdParser.h index 23aaac555..b11c72f8d 100644 --- a/code/AssetLib/MMD/MMDPmdParser.h +++ b/code/AssetLib/MMD/MMDPmdParser.h @@ -2,7 +2,7 @@ Open Asset Import Library (assimp) ---------------------------------------------------------------------- -Copyright (c) 2006-2022, assimp team +Copyright (c) 2006-2024, assimp team All rights reserved. diff --git a/code/AssetLib/MMD/MMDPmxParser.cpp b/code/AssetLib/MMD/MMDPmxParser.cpp index 6b04f02e9..5a3e61dcd 100644 --- a/code/AssetLib/MMD/MMDPmxParser.cpp +++ b/code/AssetLib/MMD/MMDPmxParser.cpp @@ -2,7 +2,7 @@ Open Asset Import Library (assimp) ---------------------------------------------------------------------- -Copyright (c) 2006-2022, assimp team +Copyright (c) 2006-2024, assimp team All rights reserved. diff --git a/code/AssetLib/MMD/MMDPmxParser.h b/code/AssetLib/MMD/MMDPmxParser.h index 424fc725a..e90e554e7 100644 --- a/code/AssetLib/MMD/MMDPmxParser.h +++ b/code/AssetLib/MMD/MMDPmxParser.h @@ -2,7 +2,7 @@ Open Asset Import Library (assimp) ---------------------------------------------------------------------- -Copyright (c) 2006-2022, assimp team +Copyright (c) 2006-2024, assimp team All rights reserved. diff --git a/code/AssetLib/MMD/MMDVmdParser.h b/code/AssetLib/MMD/MMDVmdParser.h index d5c7dedff..2ba9fb931 100644 --- a/code/AssetLib/MMD/MMDVmdParser.h +++ b/code/AssetLib/MMD/MMDVmdParser.h @@ -2,7 +2,7 @@ Open Asset Import Library (assimp) ---------------------------------------------------------------------- -Copyright (c) 2006-2022, assimp team +Copyright (c) 2006-2024, assimp team All rights reserved. diff --git a/code/AssetLib/MS3D/MS3DLoader.cpp b/code/AssetLib/MS3D/MS3DLoader.cpp index e0f0f8b5a..fac102f5f 100644 --- a/code/AssetLib/MS3D/MS3DLoader.cpp +++ b/code/AssetLib/MS3D/MS3DLoader.cpp @@ -3,7 +3,7 @@ Open Asset Import Library (assimp) --------------------------------------------------------------------------- -Copyright (c) 2006-2022, assimp team +Copyright (c) 2006-2024, assimp team diff --git a/code/AssetLib/MS3D/MS3DLoader.h b/code/AssetLib/MS3D/MS3DLoader.h index 3e25f1f59..5a28391eb 100644 --- a/code/AssetLib/MS3D/MS3DLoader.h +++ b/code/AssetLib/MS3D/MS3DLoader.h @@ -2,7 +2,7 @@ Open Asset Import Library (assimp) ---------------------------------------------------------------------- -Copyright (c) 2006-2022, assimp team +Copyright (c) 2006-2024, assimp team All rights reserved. diff --git a/code/AssetLib/NDO/NDOLoader.cpp b/code/AssetLib/NDO/NDOLoader.cpp index 405438dfc..3515c14b4 100644 --- a/code/AssetLib/NDO/NDOLoader.cpp +++ b/code/AssetLib/NDO/NDOLoader.cpp @@ -3,7 +3,7 @@ Open Asset Import Library (assimp) --------------------------------------------------------------------------- -Copyright (c) 2006-2022, assimp team +Copyright (c) 2006-2024, assimp team All rights reserved. diff --git a/code/AssetLib/NDO/NDOLoader.h b/code/AssetLib/NDO/NDOLoader.h index c4f127851..c3ab15230 100644 --- a/code/AssetLib/NDO/NDOLoader.h +++ b/code/AssetLib/NDO/NDOLoader.h @@ -2,7 +2,7 @@ Open Asset Import Library (assimp) ---------------------------------------------------------------------- -Copyright (c) 2006-2022, assimp team +Copyright (c) 2006-2024, assimp team All rights reserved. Redistribution and use of this software in source and binary forms, diff --git a/code/AssetLib/NFF/NFFLoader.cpp b/code/AssetLib/NFF/NFFLoader.cpp index 6191d6def..481a4bc19 100644 --- a/code/AssetLib/NFF/NFFLoader.cpp +++ b/code/AssetLib/NFF/NFFLoader.cpp @@ -3,7 +3,7 @@ Open Asset Import Library (assimp) --------------------------------------------------------------------------- -Copyright (c) 2006-2022, assimp team +Copyright (c) 2006-2024, assimp team All rights reserved. diff --git a/code/AssetLib/NFF/NFFLoader.h b/code/AssetLib/NFF/NFFLoader.h index b402aec84..dfa6a882f 100644 --- a/code/AssetLib/NFF/NFFLoader.h +++ b/code/AssetLib/NFF/NFFLoader.h @@ -2,7 +2,7 @@ Open Asset Import Library (assimp) ---------------------------------------------------------------------- -Copyright (c) 2006-2022, assimp team +Copyright (c) 2006-2024, assimp team All rights reserved. diff --git a/code/AssetLib/OFF/OFFLoader.cpp b/code/AssetLib/OFF/OFFLoader.cpp index 37fc2d31a..566e3212e 100644 --- a/code/AssetLib/OFF/OFFLoader.cpp +++ b/code/AssetLib/OFF/OFFLoader.cpp @@ -3,7 +3,7 @@ Open Asset Import Library (assimp) --------------------------------------------------------------------------- -Copyright (c) 2006-2022, assimp team +Copyright (c) 2006-2024, assimp team All rights reserved. diff --git a/code/AssetLib/OFF/OFFLoader.h b/code/AssetLib/OFF/OFFLoader.h index b8577e507..02829d360 100644 --- a/code/AssetLib/OFF/OFFLoader.h +++ b/code/AssetLib/OFF/OFFLoader.h @@ -2,7 +2,7 @@ Open Asset Import Library (assimp) ---------------------------------------------------------------------- -Copyright (c) 2006-2022, assimp team +Copyright (c) 2006-2024, assimp team All rights reserved. diff --git a/code/AssetLib/Obj/ObjFileData.h b/code/AssetLib/Obj/ObjFileData.h index 22090e63e..3dc20c799 100644 --- a/code/AssetLib/Obj/ObjFileData.h +++ b/code/AssetLib/Obj/ObjFileData.h @@ -2,7 +2,7 @@ Open Asset Import Library (assimp) ---------------------------------------------------------------------- -Copyright (c) 2006-2022, assimp team +Copyright (c) 2006-2024, assimp team All rights reserved. diff --git a/code/AssetLib/Obj/ObjFileImporter.cpp b/code/AssetLib/Obj/ObjFileImporter.cpp index 339e90b06..e956f83d4 100644 --- a/code/AssetLib/Obj/ObjFileImporter.cpp +++ b/code/AssetLib/Obj/ObjFileImporter.cpp @@ -3,7 +3,7 @@ Open Asset Import Library (assimp) --------------------------------------------------------------------------- -Copyright (c) 2006-2023, assimp team +Copyright (c) 2006-2024, assimp team All rights reserved. diff --git a/code/AssetLib/Obj/ObjFileParser.cpp b/code/AssetLib/Obj/ObjFileParser.cpp index 9f5522ed2..4aae6d7e7 100644 --- a/code/AssetLib/Obj/ObjFileParser.cpp +++ b/code/AssetLib/Obj/ObjFileParser.cpp @@ -3,7 +3,7 @@ Open Asset Import Library (assimp) --------------------------------------------------------------------------- -Copyright (c) 2006-2022, assimp team +Copyright (c) 2006-2024, assimp team All rights reserved. diff --git a/code/AssetLib/Obj/ObjTools.h b/code/AssetLib/Obj/ObjTools.h index ca173de0a..664402ee3 100644 --- a/code/AssetLib/Obj/ObjTools.h +++ b/code/AssetLib/Obj/ObjTools.h @@ -2,7 +2,7 @@ Open Asset Import Library (assimp) ---------------------------------------------------------------------- -Copyright (c) 2006-2022, assimp team +Copyright (c) 2006-2024, assimp team All rights reserved. diff --git a/code/AssetLib/Ogre/OgreBinarySerializer.cpp b/code/AssetLib/Ogre/OgreBinarySerializer.cpp index 738e1181e..ee92785ef 100644 --- a/code/AssetLib/Ogre/OgreBinarySerializer.cpp +++ b/code/AssetLib/Ogre/OgreBinarySerializer.cpp @@ -2,7 +2,7 @@ Open Asset Import Library (assimp) ---------------------------------------------------------------------- -Copyright (c) 2006-2022, assimp team +Copyright (c) 2006-2024, assimp team All rights reserved. diff --git a/code/AssetLib/Ogre/OgreBinarySerializer.h b/code/AssetLib/Ogre/OgreBinarySerializer.h index eb026ea70..7bba8b768 100644 --- a/code/AssetLib/Ogre/OgreBinarySerializer.h +++ b/code/AssetLib/Ogre/OgreBinarySerializer.h @@ -2,7 +2,7 @@ Open Asset Import Library (assimp) ---------------------------------------------------------------------- -Copyright (c) 2006-2022, assimp team +Copyright (c) 2006-2024, assimp team All rights reserved. diff --git a/code/AssetLib/Ogre/OgreImporter.cpp b/code/AssetLib/Ogre/OgreImporter.cpp index 5bf6901a0..8e58179bc 100644 --- a/code/AssetLib/Ogre/OgreImporter.cpp +++ b/code/AssetLib/Ogre/OgreImporter.cpp @@ -2,7 +2,7 @@ Open Asset Import Library (assimp) ---------------------------------------------------------------------- -Copyright (c) 2006-2022, assimp team +Copyright (c) 2006-2024, assimp team All rights reserved. diff --git a/code/AssetLib/Ogre/OgreImporter.h b/code/AssetLib/Ogre/OgreImporter.h index 3a72ae70e..2347956f2 100644 --- a/code/AssetLib/Ogre/OgreImporter.h +++ b/code/AssetLib/Ogre/OgreImporter.h @@ -2,7 +2,7 @@ Open Asset Import Library (assimp) ---------------------------------------------------------------------- -Copyright (c) 2006-2022, assimp team +Copyright (c) 2006-2024, assimp team All rights reserved. diff --git a/code/AssetLib/Ogre/OgreMaterial.cpp b/code/AssetLib/Ogre/OgreMaterial.cpp index 0def59b79..d1244ada3 100644 --- a/code/AssetLib/Ogre/OgreMaterial.cpp +++ b/code/AssetLib/Ogre/OgreMaterial.cpp @@ -2,7 +2,7 @@ Open Asset Import Library (assimp) ---------------------------------------------------------------------- -Copyright (c) 2006-2022, assimp team +Copyright (c) 2006-2024, assimp team All rights reserved. diff --git a/code/AssetLib/Ogre/OgreParsingUtils.h b/code/AssetLib/Ogre/OgreParsingUtils.h index 60dd5cf76..2591644e3 100644 --- a/code/AssetLib/Ogre/OgreParsingUtils.h +++ b/code/AssetLib/Ogre/OgreParsingUtils.h @@ -2,7 +2,7 @@ Open Asset Import Library (assimp) ---------------------------------------------------------------------- -Copyright (c) 2006-2022, assimp team +Copyright (c) 2006-2024, assimp team All rights reserved. diff --git a/code/AssetLib/Ogre/OgreStructs.cpp b/code/AssetLib/Ogre/OgreStructs.cpp index ed8b9be79..29a8d768d 100644 --- a/code/AssetLib/Ogre/OgreStructs.cpp +++ b/code/AssetLib/Ogre/OgreStructs.cpp @@ -2,7 +2,7 @@ Open Asset Import Library (assimp) ---------------------------------------------------------------------- -Copyright (c) 2006-2022, assimp team +Copyright (c) 2006-2024, assimp team All rights reserved. diff --git a/code/AssetLib/Ogre/OgreStructs.h b/code/AssetLib/Ogre/OgreStructs.h index dcdf0670f..1ba8e840f 100644 --- a/code/AssetLib/Ogre/OgreStructs.h +++ b/code/AssetLib/Ogre/OgreStructs.h @@ -2,7 +2,7 @@ Open Asset Import Library (assimp) ---------------------------------------------------------------------- -Copyright (c) 2006-2022, assimp team +Copyright (c) 2006-2024, assimp team All rights reserved. diff --git a/code/AssetLib/Ogre/OgreXmlSerializer.cpp b/code/AssetLib/Ogre/OgreXmlSerializer.cpp index 8a1b88510..2eaa74c01 100644 --- a/code/AssetLib/Ogre/OgreXmlSerializer.cpp +++ b/code/AssetLib/Ogre/OgreXmlSerializer.cpp @@ -2,7 +2,7 @@ Open Asset Import Library (assimp) ---------------------------------------------------------------------- -Copyright (c) 2006-2022, assimp team +Copyright (c) 2006-2024, assimp team All rights reserved. diff --git a/code/AssetLib/Ogre/OgreXmlSerializer.h b/code/AssetLib/Ogre/OgreXmlSerializer.h index 406681f55..c6f8e23a2 100644 --- a/code/AssetLib/Ogre/OgreXmlSerializer.h +++ b/code/AssetLib/Ogre/OgreXmlSerializer.h @@ -2,7 +2,7 @@ Open Asset Import Library (assimp) ---------------------------------------------------------------------- -Copyright (c) 2006-2022, assimp team +Copyright (c) 2006-2024, assimp team All rights reserved. diff --git a/code/AssetLib/OpenGEX/OpenGEXExporter.cpp b/code/AssetLib/OpenGEX/OpenGEXExporter.cpp index f812d0ddb..cbea5f39b 100644 --- a/code/AssetLib/OpenGEX/OpenGEXExporter.cpp +++ b/code/AssetLib/OpenGEX/OpenGEXExporter.cpp @@ -2,7 +2,7 @@ Open Asset Import Library (assimp) ---------------------------------------------------------------------- -Copyright (c) 2006-2022, assimp team +Copyright (c) 2006-2024, assimp team All rights reserved. diff --git a/code/AssetLib/OpenGEX/OpenGEXExporter.h b/code/AssetLib/OpenGEX/OpenGEXExporter.h index 8e31b9ae3..93e5ffc74 100644 --- a/code/AssetLib/OpenGEX/OpenGEXExporter.h +++ b/code/AssetLib/OpenGEX/OpenGEXExporter.h @@ -2,7 +2,7 @@ Open Asset Import Library (assimp) ---------------------------------------------------------------------- -Copyright (c) 2006-2022, assimp team +Copyright (c) 2006-2024, assimp team All rights reserved. diff --git a/code/AssetLib/OpenGEX/OpenGEXImporter.cpp b/code/AssetLib/OpenGEX/OpenGEXImporter.cpp index 735f56755..20b2e77ac 100644 --- a/code/AssetLib/OpenGEX/OpenGEXImporter.cpp +++ b/code/AssetLib/OpenGEX/OpenGEXImporter.cpp @@ -2,7 +2,7 @@ Open Asset Import Library (assimp) ---------------------------------------------------------------------- -Copyright (c) 2006-2022, assimp team +Copyright (c) 2006-2024, assimp team All rights reserved. diff --git a/code/AssetLib/OpenGEX/OpenGEXImporter.h b/code/AssetLib/OpenGEX/OpenGEXImporter.h index 997d58af9..cf5773387 100644 --- a/code/AssetLib/OpenGEX/OpenGEXImporter.h +++ b/code/AssetLib/OpenGEX/OpenGEXImporter.h @@ -2,7 +2,7 @@ Open Asset Import Library (assimp) ---------------------------------------------------------------------- -Copyright (c) 2006-2022, assimp team +Copyright (c) 2006-2024, assimp team All rights reserved. diff --git a/code/AssetLib/OpenGEX/OpenGEXStructs.h b/code/AssetLib/OpenGEX/OpenGEXStructs.h index 5f845483d..91b31a41a 100644 --- a/code/AssetLib/OpenGEX/OpenGEXStructs.h +++ b/code/AssetLib/OpenGEX/OpenGEXStructs.h @@ -2,7 +2,7 @@ Open Asset Import Library (assimp) ---------------------------------------------------------------------- -Copyright (c) 2006-2022, assimp team +Copyright (c) 2006-2024, assimp team All rights reserved. diff --git a/code/AssetLib/Ply/PlyExporter.cpp b/code/AssetLib/Ply/PlyExporter.cpp index 9453e0d4d..2dc3311ff 100644 --- a/code/AssetLib/Ply/PlyExporter.cpp +++ b/code/AssetLib/Ply/PlyExporter.cpp @@ -2,7 +2,7 @@ Open Asset Import Library (assimp) ---------------------------------------------------------------------- -Copyright (c) 2006-2022, assimp team +Copyright (c) 2006-2024, assimp team All rights reserved. diff --git a/code/AssetLib/Ply/PlyExporter.h b/code/AssetLib/Ply/PlyExporter.h index ff3a54cb6..810626d69 100644 --- a/code/AssetLib/Ply/PlyExporter.h +++ b/code/AssetLib/Ply/PlyExporter.h @@ -2,7 +2,7 @@ Open Asset Import Library (assimp) ---------------------------------------------------------------------- -Copyright (c) 2006-2022, assimp team +Copyright (c) 2006-2024, assimp team All rights reserved. diff --git a/code/AssetLib/Ply/PlyLoader.cpp b/code/AssetLib/Ply/PlyLoader.cpp index f524e3a73..3e92339fb 100644 --- a/code/AssetLib/Ply/PlyLoader.cpp +++ b/code/AssetLib/Ply/PlyLoader.cpp @@ -3,7 +3,7 @@ Open Asset Import Library (assimp) --------------------------------------------------------------------------- -Copyright (c) 2006-2022, assimp team +Copyright (c) 2006-2024, assimp team All rights reserved. diff --git a/code/AssetLib/Ply/PlyLoader.h b/code/AssetLib/Ply/PlyLoader.h index f85445f91..048f40e3f 100644 --- a/code/AssetLib/Ply/PlyLoader.h +++ b/code/AssetLib/Ply/PlyLoader.h @@ -2,7 +2,7 @@ Open Asset Import Library (assimp) ---------------------------------------------------------------------- -Copyright (c) 2006-2022, assimp team +Copyright (c) 2006-2024, assimp team All rights reserved. diff --git a/code/AssetLib/Ply/PlyParser.cpp b/code/AssetLib/Ply/PlyParser.cpp index 7dcc4d239..dbbabc03f 100644 --- a/code/AssetLib/Ply/PlyParser.cpp +++ b/code/AssetLib/Ply/PlyParser.cpp @@ -3,7 +3,7 @@ Open Asset Import Library (assimp) --------------------------------------------------------------------------- -Copyright (c) 2006-2022, assimp team +Copyright (c) 2006-2024, assimp team All rights reserved. diff --git a/code/AssetLib/Ply/PlyParser.h b/code/AssetLib/Ply/PlyParser.h index 0e362926e..fc6f346af 100644 --- a/code/AssetLib/Ply/PlyParser.h +++ b/code/AssetLib/Ply/PlyParser.h @@ -2,7 +2,7 @@ Open Asset Import Library (assimp) ---------------------------------------------------------------------- -Copyright (c) 2006-2022, assimp team +Copyright (c) 2006-2024, assimp team All rights reserved. diff --git a/code/AssetLib/Q3BSP/Q3BSPFileData.h b/code/AssetLib/Q3BSP/Q3BSPFileData.h index 086cf7842..2d86ce564 100644 --- a/code/AssetLib/Q3BSP/Q3BSPFileData.h +++ b/code/AssetLib/Q3BSP/Q3BSPFileData.h @@ -2,7 +2,7 @@ Open Asset Import Library (assimp) ---------------------------------------------------------------------- -Copyright (c) 2006-2022, assimp team +Copyright (c) 2006-2024, assimp team All rights reserved. diff --git a/code/AssetLib/Q3BSP/Q3BSPFileImporter.cpp b/code/AssetLib/Q3BSP/Q3BSPFileImporter.cpp index a82f29cf1..d2ab59eb4 100644 --- a/code/AssetLib/Q3BSP/Q3BSPFileImporter.cpp +++ b/code/AssetLib/Q3BSP/Q3BSPFileImporter.cpp @@ -2,7 +2,7 @@ Open Asset Import Library (assimp) --------------------------------------------------------------------------------------------------- -Copyright (c) 2006-2022, assimp team +Copyright (c) 2006-2024, assimp team All rights reserved. diff --git a/code/AssetLib/Q3BSP/Q3BSPFileImporter.h b/code/AssetLib/Q3BSP/Q3BSPFileImporter.h index 63d6edb21..b779c55a5 100644 --- a/code/AssetLib/Q3BSP/Q3BSPFileImporter.h +++ b/code/AssetLib/Q3BSP/Q3BSPFileImporter.h @@ -2,7 +2,7 @@ Open Asset Import Library (assimp) ---------------------------------------------------------------------- -Copyright (c) 2006-2022, assimp team +Copyright (c) 2006-2024, assimp team All rights reserved. diff --git a/code/AssetLib/Q3BSP/Q3BSPFileParser.cpp b/code/AssetLib/Q3BSP/Q3BSPFileParser.cpp index 910da5b36..c9c3d24cf 100644 --- a/code/AssetLib/Q3BSP/Q3BSPFileParser.cpp +++ b/code/AssetLib/Q3BSP/Q3BSPFileParser.cpp @@ -2,7 +2,7 @@ Open Asset Import Library (assimp) ---------------------------------------------------------------------- -Copyright (c) 2006-2022, assimp team +Copyright (c) 2006-2024, assimp team All rights reserved. diff --git a/code/AssetLib/Q3BSP/Q3BSPFileParser.h b/code/AssetLib/Q3BSP/Q3BSPFileParser.h index 15cc751cc..de4d609e4 100644 --- a/code/AssetLib/Q3BSP/Q3BSPFileParser.h +++ b/code/AssetLib/Q3BSP/Q3BSPFileParser.h @@ -2,7 +2,7 @@ Open Asset Import Library (assimp) ---------------------------------------------------------------------- -Copyright (c) 2006-2022, assimp team +Copyright (c) 2006-2024, assimp team All rights reserved. diff --git a/code/AssetLib/Q3D/Q3DLoader.cpp b/code/AssetLib/Q3D/Q3DLoader.cpp index b599ad8f2..435b92e82 100644 --- a/code/AssetLib/Q3D/Q3DLoader.cpp +++ b/code/AssetLib/Q3D/Q3DLoader.cpp @@ -3,7 +3,7 @@ Open Asset Import Library (assimp) --------------------------------------------------------------------------- -Copyright (c) 2006-2022, assimp team +Copyright (c) 2006-2024, assimp team All rights reserved. diff --git a/code/AssetLib/Q3D/Q3DLoader.h b/code/AssetLib/Q3D/Q3DLoader.h index 54af86dc2..ed33ed7ca 100644 --- a/code/AssetLib/Q3D/Q3DLoader.h +++ b/code/AssetLib/Q3D/Q3DLoader.h @@ -2,7 +2,7 @@ Open Asset Import Library (assimp) ---------------------------------------------------------------------- -Copyright (c) 2006-2022, assimp team +Copyright (c) 2006-2024, assimp team All rights reserved. diff --git a/code/AssetLib/Raw/RawLoader.cpp b/code/AssetLib/Raw/RawLoader.cpp index 338ca9efa..6c04680b8 100644 --- a/code/AssetLib/Raw/RawLoader.cpp +++ b/code/AssetLib/Raw/RawLoader.cpp @@ -3,7 +3,7 @@ Open Asset Import Library (assimp) --------------------------------------------------------------------------- -Copyright (c) 2006-2022, assimp team +Copyright (c) 2006-2024, assimp team All rights reserved. diff --git a/code/AssetLib/Raw/RawLoader.h b/code/AssetLib/Raw/RawLoader.h index 83e4a9f1f..aa0fbdf81 100644 --- a/code/AssetLib/Raw/RawLoader.h +++ b/code/AssetLib/Raw/RawLoader.h @@ -2,7 +2,7 @@ Open Asset Import Library (assimp) ---------------------------------------------------------------------- -Copyright (c) 2006-2022, assimp team +Copyright (c) 2006-2024, assimp team All rights reserved. diff --git a/code/AssetLib/SIB/SIBImporter.cpp b/code/AssetLib/SIB/SIBImporter.cpp index 840f74b7d..e55e67541 100644 --- a/code/AssetLib/SIB/SIBImporter.cpp +++ b/code/AssetLib/SIB/SIBImporter.cpp @@ -3,7 +3,7 @@ Open Asset Import Library (assimp) --------------------------------------------------------------------------- -Copyright (c) 2006-2022, assimp team +Copyright (c) 2006-2024, assimp team All rights reserved. diff --git a/code/AssetLib/SIB/SIBImporter.h b/code/AssetLib/SIB/SIBImporter.h index 903c36561..9dd0c0095 100644 --- a/code/AssetLib/SIB/SIBImporter.h +++ b/code/AssetLib/SIB/SIBImporter.h @@ -2,7 +2,7 @@ Open Asset Import Library (assimp) ---------------------------------------------------------------------- -Copyright (c) 2006-2022, assimp team +Copyright (c) 2006-2024, assimp team All rights reserved. diff --git a/code/AssetLib/SMD/SMDLoader.cpp b/code/AssetLib/SMD/SMDLoader.cpp index 1d02847c8..df598e5c7 100644 --- a/code/AssetLib/SMD/SMDLoader.cpp +++ b/code/AssetLib/SMD/SMDLoader.cpp @@ -3,7 +3,7 @@ Open Asset Import Library (assimp) --------------------------------------------------------------------------- -Copyright (c) 2006-2022, assimp team +Copyright (c) 2006-2024, assimp team All rights reserved. diff --git a/code/AssetLib/SMD/SMDLoader.h b/code/AssetLib/SMD/SMDLoader.h index 8286aa5eb..c2f2f0a49 100644 --- a/code/AssetLib/SMD/SMDLoader.h +++ b/code/AssetLib/SMD/SMDLoader.h @@ -2,7 +2,7 @@ Open Asset Import Library (assimp) ---------------------------------------------------------------------- -Copyright (c) 2006-2022, assimp team +Copyright (c) 2006-2024, assimp team All rights reserved. diff --git a/code/AssetLib/STEPParser/STEPFileEncoding.cpp b/code/AssetLib/STEPParser/STEPFileEncoding.cpp index 92eb4f284..d7f512cbb 100644 --- a/code/AssetLib/STEPParser/STEPFileEncoding.cpp +++ b/code/AssetLib/STEPParser/STEPFileEncoding.cpp @@ -2,7 +2,7 @@ Open Asset Import Library (assimp) ---------------------------------------------------------------------- -Copyright (c) 2006-2022, assimp team +Copyright (c) 2006-2024, assimp team All rights reserved. diff --git a/code/AssetLib/STEPParser/STEPFileEncoding.h b/code/AssetLib/STEPParser/STEPFileEncoding.h index 950c9b3e2..6988a5822 100644 --- a/code/AssetLib/STEPParser/STEPFileEncoding.h +++ b/code/AssetLib/STEPParser/STEPFileEncoding.h @@ -2,7 +2,7 @@ Open Asset Import Library (assimp) ---------------------------------------------------------------------- -Copyright (c) 2006-2022, assimp team +Copyright (c) 2006-2024, assimp team All rights reserved. diff --git a/code/AssetLib/STEPParser/STEPFileReader.cpp b/code/AssetLib/STEPParser/STEPFileReader.cpp index 58d9cacc4..6bc8981f1 100644 --- a/code/AssetLib/STEPParser/STEPFileReader.cpp +++ b/code/AssetLib/STEPParser/STEPFileReader.cpp @@ -2,7 +2,7 @@ Open Asset Import Library (assimp) ---------------------------------------------------------------------- -Copyright (c) 2006-2022, assimp team +Copyright (c) 2006-2024, assimp team All rights reserved. diff --git a/code/AssetLib/STEPParser/STEPFileReader.h b/code/AssetLib/STEPParser/STEPFileReader.h index 5a8eb7a6e..85a7c5cb0 100644 --- a/code/AssetLib/STEPParser/STEPFileReader.h +++ b/code/AssetLib/STEPParser/STEPFileReader.h @@ -2,7 +2,7 @@ Open Asset Import Library (assimp) ---------------------------------------------------------------------- -Copyright (c) 2006-2022, assimp team +Copyright (c) 2006-2024, assimp team All rights reserved. diff --git a/code/AssetLib/STL/STLExporter.cpp b/code/AssetLib/STL/STLExporter.cpp index 9bbc2063f..0ff96296a 100644 --- a/code/AssetLib/STL/STLExporter.cpp +++ b/code/AssetLib/STL/STLExporter.cpp @@ -2,7 +2,7 @@ Open Asset Import Library (assimp) ---------------------------------------------------------------------- -Copyright (c) 2006-2022, assimp team +Copyright (c) 2006-2024, assimp team All rights reserved. diff --git a/code/AssetLib/STL/STLExporter.h b/code/AssetLib/STL/STLExporter.h index 066dcfefd..b751e196c 100644 --- a/code/AssetLib/STL/STLExporter.h +++ b/code/AssetLib/STL/STLExporter.h @@ -2,7 +2,7 @@ Open Asset Import Library (assimp) ---------------------------------------------------------------------- -Copyright (c) 2006-2022, assimp team +Copyright (c) 2006-2024, assimp team All rights reserved. diff --git a/code/AssetLib/STL/STLLoader.cpp b/code/AssetLib/STL/STLLoader.cpp index 397aa59b1..38cd2a0b8 100644 --- a/code/AssetLib/STL/STLLoader.cpp +++ b/code/AssetLib/STL/STLLoader.cpp @@ -3,7 +3,7 @@ Open Asset Import Library (assimp) --------------------------------------------------------------------------- -Copyright (c) 2006-2022, assimp team +Copyright (c) 2006-2024, assimp team All rights reserved. diff --git a/code/AssetLib/STL/STLLoader.h b/code/AssetLib/STL/STLLoader.h index 0be6a95f0..cc6ab9607 100644 --- a/code/AssetLib/STL/STLLoader.h +++ b/code/AssetLib/STL/STLLoader.h @@ -2,7 +2,7 @@ Open Asset Import Library (assimp) ---------------------------------------------------------------------- -Copyright (c) 2006-2022, assimp team +Copyright (c) 2006-2024, assimp team All rights reserved. diff --git a/code/AssetLib/Step/STEPFile.h b/code/AssetLib/Step/STEPFile.h index e5da75b61..d8bc0ac49 100644 --- a/code/AssetLib/Step/STEPFile.h +++ b/code/AssetLib/Step/STEPFile.h @@ -2,7 +2,7 @@ Open Asset Import Library (assimp) ---------------------------------------------------------------------- -Copyright (c) 2006-2022, assimp team +Copyright (c) 2006-2024, assimp team All rights reserved. diff --git a/code/AssetLib/Step/StepExporter.cpp b/code/AssetLib/Step/StepExporter.cpp index e13c9edab..2188ddfec 100644 --- a/code/AssetLib/Step/StepExporter.cpp +++ b/code/AssetLib/Step/StepExporter.cpp @@ -2,7 +2,7 @@ Open Asset Import Library (assimp) ---------------------------------------------------------------------- -Copyright (c) 2006-2022, assimp team +Copyright (c) 2006-2024, assimp team All rights reserved. diff --git a/code/AssetLib/Step/StepExporter.h b/code/AssetLib/Step/StepExporter.h index a02262659..9ae5fb820 100644 --- a/code/AssetLib/Step/StepExporter.h +++ b/code/AssetLib/Step/StepExporter.h @@ -2,7 +2,7 @@ Open Asset Import Library (assimp) ---------------------------------------------------------------------- -Copyright (c) 2006-2022, assimp team +Copyright (c) 2006-2024, assimp team All rights reserved. diff --git a/code/AssetLib/Terragen/TerragenLoader.cpp b/code/AssetLib/Terragen/TerragenLoader.cpp index b1870414c..150ebd011 100644 --- a/code/AssetLib/Terragen/TerragenLoader.cpp +++ b/code/AssetLib/Terragen/TerragenLoader.cpp @@ -3,7 +3,7 @@ Open Asset Import Library (assimp) --------------------------------------------------------------------------- -Copyright (c) 2006-2022, assimp team +Copyright (c) 2006-2024, assimp team All rights reserved. diff --git a/code/AssetLib/Terragen/TerragenLoader.h b/code/AssetLib/Terragen/TerragenLoader.h index 0c7b686e9..2d529464b 100644 --- a/code/AssetLib/Terragen/TerragenLoader.h +++ b/code/AssetLib/Terragen/TerragenLoader.h @@ -2,7 +2,7 @@ Open Asset Import Library (assimp) ---------------------------------------------------------------------- -Copyright (c) 2006-2022, assimp team +Copyright (c) 2006-2024, assimp team All rights reserved. diff --git a/code/AssetLib/Unreal/UnrealLoader.cpp b/code/AssetLib/Unreal/UnrealLoader.cpp index ab3f7c3be..3810e5bf4 100644 --- a/code/AssetLib/Unreal/UnrealLoader.cpp +++ b/code/AssetLib/Unreal/UnrealLoader.cpp @@ -3,7 +3,7 @@ Open Asset Import Library (assimp) --------------------------------------------------------------------------- -Copyright (c) 2006-2022, assimp team +Copyright (c) 2006-2024, assimp team All rights reserved. diff --git a/code/AssetLib/Unreal/UnrealLoader.h b/code/AssetLib/Unreal/UnrealLoader.h index fda784cfb..b32a5fc74 100644 --- a/code/AssetLib/Unreal/UnrealLoader.h +++ b/code/AssetLib/Unreal/UnrealLoader.h @@ -2,7 +2,7 @@ Open Asset Import Library (assimp) ---------------------------------------------------------------------- -Copyright (c) 2006-2022, assimp team +Copyright (c) 2006-2024, assimp team All rights reserved. diff --git a/code/AssetLib/X/XFileExporter.cpp b/code/AssetLib/X/XFileExporter.cpp index f0b1608c1..15ecf9464 100644 --- a/code/AssetLib/X/XFileExporter.cpp +++ b/code/AssetLib/X/XFileExporter.cpp @@ -2,7 +2,7 @@ Open Asset Import Library (assimp) ---------------------------------------------------------------------- -Copyright (c) 2006-2022, assimp team +Copyright (c) 2006-2024, assimp team All rights reserved. diff --git a/code/AssetLib/X/XFileExporter.h b/code/AssetLib/X/XFileExporter.h index 1d9a5ae77..744944062 100644 --- a/code/AssetLib/X/XFileExporter.h +++ b/code/AssetLib/X/XFileExporter.h @@ -2,7 +2,7 @@ Open Asset Import Library (assimp) ---------------------------------------------------------------------- -Copyright (c) 2006-2022, assimp team +Copyright (c) 2006-2024, assimp team All rights reserved. diff --git a/code/AssetLib/X/XFileHelper.h b/code/AssetLib/X/XFileHelper.h index 4b95672f3..e3fff2b66 100644 --- a/code/AssetLib/X/XFileHelper.h +++ b/code/AssetLib/X/XFileHelper.h @@ -2,7 +2,7 @@ Open Asset Import Library (assimp) ---------------------------------------------------------------------- -Copyright (c) 2006-2022, assimp team +Copyright (c) 2006-2024, assimp team All rights reserved. diff --git a/code/AssetLib/X/XFileImporter.cpp b/code/AssetLib/X/XFileImporter.cpp index 22697d679..b386ff959 100644 --- a/code/AssetLib/X/XFileImporter.cpp +++ b/code/AssetLib/X/XFileImporter.cpp @@ -3,7 +3,7 @@ Open Asset Import Library (assimp) --------------------------------------------------------------------------- -Copyright (c) 2006-2022, assimp team +Copyright (c) 2006-2024, assimp team All rights reserved. diff --git a/code/AssetLib/X/XFileImporter.h b/code/AssetLib/X/XFileImporter.h index 7be9cc8ec..cd741deec 100644 --- a/code/AssetLib/X/XFileImporter.h +++ b/code/AssetLib/X/XFileImporter.h @@ -2,7 +2,7 @@ Open Asset Import Library (assimp) ---------------------------------------------------------------------- -Copyright (c) 2006-2022, assimp team +Copyright (c) 2006-2024, assimp team All rights reserved. diff --git a/code/AssetLib/X/XFileParser.cpp b/code/AssetLib/X/XFileParser.cpp index 770c75a77..63c654b65 100644 --- a/code/AssetLib/X/XFileParser.cpp +++ b/code/AssetLib/X/XFileParser.cpp @@ -3,7 +3,7 @@ Open Asset Import Library (assimp) --------------------------------------------------------------------------- -Copyright (c) 2006-2022, assimp team +Copyright (c) 2006-2024, assimp team All rights reserved. diff --git a/code/AssetLib/X/XFileParser.h b/code/AssetLib/X/XFileParser.h index 36eac2ada..32375511a 100644 --- a/code/AssetLib/X/XFileParser.h +++ b/code/AssetLib/X/XFileParser.h @@ -2,7 +2,7 @@ Open Asset Import Library (assimp) ---------------------------------------------------------------------- -Copyright (c) 2006-2022, assimp team +Copyright (c) 2006-2024, assimp team All rights reserved. diff --git a/code/AssetLib/X3D/X3DImporter.cpp b/code/AssetLib/X3D/X3DImporter.cpp index eeb20b7c1..ada388080 100644 --- a/code/AssetLib/X3D/X3DImporter.cpp +++ b/code/AssetLib/X3D/X3DImporter.cpp @@ -2,7 +2,7 @@ Open Asset Import Library (assimp) ---------------------------------------------------------------------- -Copyright (c) 2006-2022, assimp team +Copyright (c) 2006-2024, assimp team All rights reserved. diff --git a/code/AssetLib/X3D/X3DImporter.hpp b/code/AssetLib/X3D/X3DImporter.hpp index 705a2472e..623160a38 100644 --- a/code/AssetLib/X3D/X3DImporter.hpp +++ b/code/AssetLib/X3D/X3DImporter.hpp @@ -2,7 +2,7 @@ Open Asset Import Library (assimp) ---------------------------------------------------------------------- -Copyright (c) 2006-2022, assimp team +Copyright (c) 2006-2024, assimp team All rights reserved. diff --git a/code/AssetLib/X3D/X3DImporter_Geometry2D.cpp b/code/AssetLib/X3D/X3DImporter_Geometry2D.cpp index 240ff14a8..b4562ace2 100644 --- a/code/AssetLib/X3D/X3DImporter_Geometry2D.cpp +++ b/code/AssetLib/X3D/X3DImporter_Geometry2D.cpp @@ -2,7 +2,7 @@ Open Asset Import Library (assimp) ---------------------------------------------------------------------- -Copyright (c) 2006-2022, assimp team +Copyright (c) 2006-2024, assimp team All rights reserved. diff --git a/code/AssetLib/XGL/XGLLoader.cpp b/code/AssetLib/XGL/XGLLoader.cpp index cb5237dc8..614fac641 100644 --- a/code/AssetLib/XGL/XGLLoader.cpp +++ b/code/AssetLib/XGL/XGLLoader.cpp @@ -3,7 +3,7 @@ Open Asset Import Library (assimp) --------------------------------------------------------------------------- -Copyright (c) 2006-2023, assimp team +Copyright (c) 2006-2024, assimp team All rights reserved. diff --git a/code/AssetLib/XGL/XGLLoader.h b/code/AssetLib/XGL/XGLLoader.h index f620561d1..9d39bc811 100644 --- a/code/AssetLib/XGL/XGLLoader.h +++ b/code/AssetLib/XGL/XGLLoader.h @@ -2,7 +2,7 @@ Open Asset Import Library (assimp) ---------------------------------------------------------------------- -Copyright (c) 2006-2022, assimp team +Copyright (c) 2006-2024, assimp team All rights reserved. diff --git a/code/AssetLib/glTF/glTFAsset.h b/code/AssetLib/glTF/glTFAsset.h index b5e6375ad..27dfae005 100644 --- a/code/AssetLib/glTF/glTFAsset.h +++ b/code/AssetLib/glTF/glTFAsset.h @@ -2,7 +2,7 @@ Open Asset Import Library (assimp) ---------------------------------------------------------------------- -Copyright (c) 2006-2022, assimp team +Copyright (c) 2006-2024, assimp team All rights reserved. diff --git a/code/AssetLib/glTF/glTFAsset.inl b/code/AssetLib/glTF/glTFAsset.inl index eddbf5706..5e554a31e 100644 --- a/code/AssetLib/glTF/glTFAsset.inl +++ b/code/AssetLib/glTF/glTFAsset.inl @@ -2,7 +2,7 @@ Open Asset Import Library (assimp) ---------------------------------------------------------------------- -Copyright (c) 2006-2022, assimp team +Copyright (c) 2006-2024, assimp team All rights reserved. diff --git a/code/AssetLib/glTF/glTFAssetWriter.h b/code/AssetLib/glTF/glTFAssetWriter.h index 6dbc42420..832c9e847 100644 --- a/code/AssetLib/glTF/glTFAssetWriter.h +++ b/code/AssetLib/glTF/glTFAssetWriter.h @@ -2,7 +2,7 @@ Open Asset Import Library (assimp) ---------------------------------------------------------------------- -Copyright (c) 2006-2022, assimp team +Copyright (c) 2006-2024, assimp team All rights reserved. diff --git a/code/AssetLib/glTF/glTFAssetWriter.inl b/code/AssetLib/glTF/glTFAssetWriter.inl index 2d80598ac..c0b8edfa2 100644 --- a/code/AssetLib/glTF/glTFAssetWriter.inl +++ b/code/AssetLib/glTF/glTFAssetWriter.inl @@ -2,7 +2,7 @@ Open Asset Import Library (assimp) ---------------------------------------------------------------------- -Copyright (c) 2006-2022, assimp team +Copyright (c) 2006-2024, assimp team All rights reserved. diff --git a/code/AssetLib/glTF/glTFCommon.cpp b/code/AssetLib/glTF/glTFCommon.cpp index fea680cd3..11e038fa3 100644 --- a/code/AssetLib/glTF/glTFCommon.cpp +++ b/code/AssetLib/glTF/glTFCommon.cpp @@ -2,7 +2,7 @@ Open Asset Import Library (assimp) ---------------------------------------------------------------------- -Copyright (c) 2006-2022, assimp team +Copyright (c) 2006-2024, assimp team All rights reserved. diff --git a/code/AssetLib/glTF/glTFCommon.h b/code/AssetLib/glTF/glTFCommon.h index 187fbbdb5..e42d905ff 100644 --- a/code/AssetLib/glTF/glTFCommon.h +++ b/code/AssetLib/glTF/glTFCommon.h @@ -2,7 +2,7 @@ Open Asset Import Library (assimp) ---------------------------------------------------------------------- -Copyright (c) 2006-2022, assimp team +Copyright (c) 2006-2024, assimp team All rights reserved. diff --git a/code/AssetLib/glTF/glTFExporter.cpp b/code/AssetLib/glTF/glTFExporter.cpp index 9b44578c0..0cffda024 100644 --- a/code/AssetLib/glTF/glTFExporter.cpp +++ b/code/AssetLib/glTF/glTFExporter.cpp @@ -2,7 +2,7 @@ Open Asset Import Library (assimp) ---------------------------------------------------------------------- -Copyright (c) 2006-2022, assimp team +Copyright (c) 2006-2024, assimp team All rights reserved. diff --git a/code/AssetLib/glTF/glTFExporter.h b/code/AssetLib/glTF/glTFExporter.h index 1d036509c..adac06197 100644 --- a/code/AssetLib/glTF/glTFExporter.h +++ b/code/AssetLib/glTF/glTFExporter.h @@ -2,7 +2,7 @@ Open Asset Import Library (assimp) ---------------------------------------------------------------------- -Copyright (c) 2006-2022, assimp team +Copyright (c) 2006-2024, assimp team All rights reserved. diff --git a/code/AssetLib/glTF/glTFImporter.cpp b/code/AssetLib/glTF/glTFImporter.cpp index cd8b7762d..1d718fd20 100644 --- a/code/AssetLib/glTF/glTFImporter.cpp +++ b/code/AssetLib/glTF/glTFImporter.cpp @@ -2,7 +2,7 @@ Open Asset Import Library (assimp) ---------------------------------------------------------------------- -Copyright (c) 2006-2022, assimp team +Copyright (c) 2006-2024, assimp team All rights reserved. diff --git a/code/AssetLib/glTF/glTFImporter.h b/code/AssetLib/glTF/glTFImporter.h index 529da53cc..384299b1f 100644 --- a/code/AssetLib/glTF/glTFImporter.h +++ b/code/AssetLib/glTF/glTFImporter.h @@ -2,7 +2,7 @@ Open Asset Import Library (assimp) ---------------------------------------------------------------------- -Copyright (c) 2006-2022, assimp team +Copyright (c) 2006-2024, assimp team All rights reserved. diff --git a/code/AssetLib/glTF2/glTF2Asset.h b/code/AssetLib/glTF2/glTF2Asset.h index 4cfaca4da..60ed368d1 100644 --- a/code/AssetLib/glTF2/glTF2Asset.h +++ b/code/AssetLib/glTF2/glTF2Asset.h @@ -2,7 +2,7 @@ Open Asset Import Library (assimp) ---------------------------------------------------------------------- -Copyright (c) 2006-2022, assimp team +Copyright (c) 2006-2024, assimp team All rights reserved. diff --git a/code/AssetLib/glTF2/glTF2Asset.inl b/code/AssetLib/glTF2/glTF2Asset.inl index 09a58da54..457fee8fa 100644 --- a/code/AssetLib/glTF2/glTF2Asset.inl +++ b/code/AssetLib/glTF2/glTF2Asset.inl @@ -2,7 +2,7 @@ Open Asset Import Library (assimp) ---------------------------------------------------------------------- -Copyright (c) 2006-2022, assimp team +Copyright (c) 2006-2024, assimp team All rights reserved. diff --git a/code/AssetLib/glTF2/glTF2AssetWriter.h b/code/AssetLib/glTF2/glTF2AssetWriter.h index 4e5177b4e..f57b6558d 100644 --- a/code/AssetLib/glTF2/glTF2AssetWriter.h +++ b/code/AssetLib/glTF2/glTF2AssetWriter.h @@ -2,7 +2,7 @@ Open Asset Import Library (assimp) ---------------------------------------------------------------------- -Copyright (c) 2006-2022, assimp team +Copyright (c) 2006-2024, assimp team All rights reserved. diff --git a/code/AssetLib/glTF2/glTF2AssetWriter.inl b/code/AssetLib/glTF2/glTF2AssetWriter.inl index bfd9135d3..17e29d8e7 100644 --- a/code/AssetLib/glTF2/glTF2AssetWriter.inl +++ b/code/AssetLib/glTF2/glTF2AssetWriter.inl @@ -2,7 +2,7 @@ Open Asset Import Library (assimp) ---------------------------------------------------------------------- -Copyright (c) 2006-2022, assimp team +Copyright (c) 2006-2024, assimp team All rights reserved. diff --git a/code/AssetLib/glTF2/glTF2Exporter.cpp b/code/AssetLib/glTF2/glTF2Exporter.cpp index 20a1f7ae9..3df9d5dda 100644 --- a/code/AssetLib/glTF2/glTF2Exporter.cpp +++ b/code/AssetLib/glTF2/glTF2Exporter.cpp @@ -2,7 +2,7 @@ Open Asset Import Library (assimp) ---------------------------------------------------------------------- -Copyright (c) 2006-2022, assimp team +Copyright (c) 2006-2024, assimp team All rights reserved. diff --git a/code/AssetLib/glTF2/glTF2Exporter.h b/code/AssetLib/glTF2/glTF2Exporter.h index 47b668de7..27e187854 100644 --- a/code/AssetLib/glTF2/glTF2Exporter.h +++ b/code/AssetLib/glTF2/glTF2Exporter.h @@ -2,7 +2,7 @@ Open Asset Import Library (assimp) ---------------------------------------------------------------------- -Copyright (c) 2006-2022, assimp team +Copyright (c) 2006-2024, assimp team All rights reserved. diff --git a/code/AssetLib/glTF2/glTF2Importer.cpp b/code/AssetLib/glTF2/glTF2Importer.cpp index e89baaf0d..5f895ff74 100644 --- a/code/AssetLib/glTF2/glTF2Importer.cpp +++ b/code/AssetLib/glTF2/glTF2Importer.cpp @@ -2,7 +2,7 @@ Open Asset Import Library (assimp) ---------------------------------------------------------------------- -Copyright (c) 2006-2022, assimp team +Copyright (c) 2006-2024, assimp team All rights reserved. diff --git a/code/AssetLib/glTF2/glTF2Importer.h b/code/AssetLib/glTF2/glTF2Importer.h index 2be42126c..68af0cb9c 100644 --- a/code/AssetLib/glTF2/glTF2Importer.h +++ b/code/AssetLib/glTF2/glTF2Importer.h @@ -2,7 +2,7 @@ Open Asset Import Library (assimp) ---------------------------------------------------------------------- -Copyright (c) 2006-2022, assimp team +Copyright (c) 2006-2024, assimp team All rights reserved. diff --git a/code/CApi/AssimpCExport.cpp b/code/CApi/AssimpCExport.cpp index 21e40205c..99ad41ab7 100644 --- a/code/CApi/AssimpCExport.cpp +++ b/code/CApi/AssimpCExport.cpp @@ -3,7 +3,7 @@ Open Asset Import Library (assimp) --------------------------------------------------------------------------- -Copyright (c) 2006-2022, assimp team +Copyright (c) 2006-2024, assimp team All rights reserved. diff --git a/code/CApi/CInterfaceIOWrapper.cpp b/code/CApi/CInterfaceIOWrapper.cpp index f0e46cd08..84648482b 100644 --- a/code/CApi/CInterfaceIOWrapper.cpp +++ b/code/CApi/CInterfaceIOWrapper.cpp @@ -3,7 +3,7 @@ Open Asset Import Library (assimp) --------------------------------------------------------------------------- -Copyright (c) 2006-2022, assimp team +Copyright (c) 2006-2024, assimp team All rights reserved. diff --git a/code/CApi/CInterfaceIOWrapper.h b/code/CApi/CInterfaceIOWrapper.h index 28d4c3e75..34c4a7311 100644 --- a/code/CApi/CInterfaceIOWrapper.h +++ b/code/CApi/CInterfaceIOWrapper.h @@ -3,7 +3,7 @@ Open Asset Import Library (assimp) --------------------------------------------------------------------------- -Copyright (c) 2006-2022, assimp team +Copyright (c) 2006-2024, assimp team All rights reserved. diff --git a/code/CMakeLists.txt b/code/CMakeLists.txt index bc5b7b16f..28e2d40c6 100644 --- a/code/CMakeLists.txt +++ b/code/CMakeLists.txt @@ -1,6 +1,6 @@ # Open Asset Import Library (assimp) # ---------------------------------------------------------------------- -# Copyright (c) 2006-2022, assimp team +# Copyright (c) 2006-2024, assimp team # # All rights reserved. # diff --git a/code/Common/AssertHandler.cpp b/code/Common/AssertHandler.cpp index 2fd4046ad..ee2d2b95c 100644 --- a/code/Common/AssertHandler.cpp +++ b/code/Common/AssertHandler.cpp @@ -3,7 +3,7 @@ Open Asset Import Library (assimp) --------------------------------------------------------------------------- -Copyright (c) 2006-2022, assimp team +Copyright (c) 2006-2024, assimp team All rights reserved. diff --git a/code/Common/Assimp.cpp b/code/Common/Assimp.cpp index e3b39c349..cf57bac4b 100644 --- a/code/Common/Assimp.cpp +++ b/code/Common/Assimp.cpp @@ -3,7 +3,7 @@ Open Asset Import Library (assimp) --------------------------------------------------------------------------- -Copyright (c) 2006-2022, assimp team +Copyright (c) 2006-2024, assimp team All rights reserved. diff --git a/code/Common/Base64.cpp b/code/Common/Base64.cpp index 65308f4fd..76f9b120e 100644 --- a/code/Common/Base64.cpp +++ b/code/Common/Base64.cpp @@ -3,7 +3,7 @@ Open Asset Import Library (assimp) --------------------------------------------------------------------------- -Copyright (c) 2006-2022, assimp team +Copyright (c) 2006-2024, assimp team All rights reserved. diff --git a/code/Common/BaseImporter.cpp b/code/Common/BaseImporter.cpp index 9ef69a8e6..18f08be8b 100644 --- a/code/Common/BaseImporter.cpp +++ b/code/Common/BaseImporter.cpp @@ -3,7 +3,7 @@ Open Asset Import Library (assimp) --------------------------------------------------------------------------- -Copyright (c) 2006-2022, assimp team +Copyright (c) 2006-2024, assimp team All rights reserved. diff --git a/code/Common/BaseProcess.cpp b/code/Common/BaseProcess.cpp index 8ff7c98e9..4d42037be 100644 --- a/code/Common/BaseProcess.cpp +++ b/code/Common/BaseProcess.cpp @@ -3,7 +3,7 @@ Open Asset Import Library (assimp) --------------------------------------------------------------------------- -Copyright (c) 2006-2022, assimp team +Copyright (c) 2006-2024, assimp team All rights reserved. diff --git a/code/Common/BaseProcess.h b/code/Common/BaseProcess.h index d2af4faa6..01c1d1d22 100644 --- a/code/Common/BaseProcess.h +++ b/code/Common/BaseProcess.h @@ -2,7 +2,7 @@ Open Asset Import Library (assimp) ---------------------------------------------------------------------- -Copyright (c) 2006-2022, assimp team +Copyright (c) 2006-2024, assimp team All rights reserved. diff --git a/code/Common/Bitmap.cpp b/code/Common/Bitmap.cpp index 65dfd1754..246ad9e65 100644 --- a/code/Common/Bitmap.cpp +++ b/code/Common/Bitmap.cpp @@ -3,7 +3,7 @@ Open Asset Import Library (assimp) --------------------------------------------------------------------------- -Copyright (c) 2006-2022, assimp team +Copyright (c) 2006-2024, assimp team All rights reserved. diff --git a/code/Common/Compression.cpp b/code/Common/Compression.cpp index a6a7be7e4..091171771 100644 --- a/code/Common/Compression.cpp +++ b/code/Common/Compression.cpp @@ -2,7 +2,7 @@ Open Asset Import Library (assimp) ---------------------------------------------------------------------- -Copyright (c) 2006-2022, assimp team +Copyright (c) 2006-2024, assimp team All rights reserved. diff --git a/code/Common/Compression.h b/code/Common/Compression.h index cfedc7409..0bec91bba 100644 --- a/code/Common/Compression.h +++ b/code/Common/Compression.h @@ -2,7 +2,7 @@ Open Asset Import Library (assimp) ---------------------------------------------------------------------- -Copyright (c) 2006-2022, assimp team +Copyright (c) 2006-2024, assimp team All rights reserved. diff --git a/code/Common/CreateAnimMesh.cpp b/code/Common/CreateAnimMesh.cpp index 58f3d909d..467651587 100644 --- a/code/Common/CreateAnimMesh.cpp +++ b/code/Common/CreateAnimMesh.cpp @@ -4,7 +4,7 @@ Open Asset Import Library (assimp) --------------------------------------------------------------------------- Copyright (C) 2016 The Qt Company Ltd. -Copyright (c) 2006-2022, assimp team +Copyright (c) 2006-2024, assimp team All rights reserved. diff --git a/code/Common/DefaultIOStream.cpp b/code/Common/DefaultIOStream.cpp index f2c772187..e423eae4f 100644 --- a/code/Common/DefaultIOStream.cpp +++ b/code/Common/DefaultIOStream.cpp @@ -3,7 +3,7 @@ Open Asset Import Library (assimp) --------------------------------------------------------------------------- -Copyright (c) 2006-2022, assimp team +Copyright (c) 2006-2024, assimp team All rights reserved. diff --git a/code/Common/DefaultIOSystem.cpp b/code/Common/DefaultIOSystem.cpp index a72627154..e74add55f 100644 --- a/code/Common/DefaultIOSystem.cpp +++ b/code/Common/DefaultIOSystem.cpp @@ -3,7 +3,7 @@ Open Asset Import Library (assimp) --------------------------------------------------------------------------- -Copyright (c) 2006-2022, assimp team +Copyright (c) 2006-2024, assimp team All rights reserved. diff --git a/code/Common/DefaultLogger.cpp b/code/Common/DefaultLogger.cpp index 5cb32d38f..828e326e2 100644 --- a/code/Common/DefaultLogger.cpp +++ b/code/Common/DefaultLogger.cpp @@ -3,7 +3,7 @@ Open Asset Import Library (assimp) --------------------------------------------------------------------------- -Copyright (c) 2006-2022, assimp team +Copyright (c) 2006-2024, assimp team diff --git a/code/Common/DefaultProgressHandler.h b/code/Common/DefaultProgressHandler.h index ac1bb68db..2ace9e02a 100644 --- a/code/Common/DefaultProgressHandler.h +++ b/code/Common/DefaultProgressHandler.h @@ -2,7 +2,7 @@ Open Asset Import Library (assimp) ---------------------------------------------------------------------- -Copyright (c) 2006-2022, assimp team +Copyright (c) 2006-2024, assimp team All rights reserved. diff --git a/code/Common/Exceptional.cpp b/code/Common/Exceptional.cpp index b25281a97..0629f716e 100644 --- a/code/Common/Exceptional.cpp +++ b/code/Common/Exceptional.cpp @@ -3,7 +3,7 @@ Open Asset Import Library (assimp) --------------------------------------------------------------------------- -Copyright (c) 2006-2022, assimp team +Copyright (c) 2006-2024, assimp team All rights reserved. diff --git a/code/Common/Exporter.cpp b/code/Common/Exporter.cpp index 0795da65c..4da055064 100644 --- a/code/Common/Exporter.cpp +++ b/code/Common/Exporter.cpp @@ -3,7 +3,7 @@ Open Asset Import Library (assimp) --------------------------------------------------------------------------- -Copyright (c) 2006-2022, assimp team +Copyright (c) 2006-2024, assimp team All rights reserved. diff --git a/code/Common/FileLogStream.h b/code/Common/FileLogStream.h index 334541485..f64f88f48 100644 --- a/code/Common/FileLogStream.h +++ b/code/Common/FileLogStream.h @@ -2,7 +2,7 @@ Open Asset Import Library (assimp) ---------------------------------------------------------------------- -Copyright (c) 2006-2022, assimp team +Copyright (c) 2006-2024, assimp team All rights reserved. diff --git a/code/Common/IOSystem.cpp b/code/Common/IOSystem.cpp index 1e63827ba..aa91e9b49 100644 --- a/code/Common/IOSystem.cpp +++ b/code/Common/IOSystem.cpp @@ -3,7 +3,7 @@ Open Asset Import Library (assimp) --------------------------------------------------------------------------- -Copyright (c) 2006-2022, assimp team +Copyright (c) 2006-2024, assimp team All rights reserved. diff --git a/code/Common/Importer.cpp b/code/Common/Importer.cpp index bdf64ac8f..284ad89cc 100644 --- a/code/Common/Importer.cpp +++ b/code/Common/Importer.cpp @@ -3,7 +3,7 @@ Open Asset Import Library (assimp) --------------------------------------------------------------------------- -Copyright (c) 2006-2022, assimp team +Copyright (c) 2006-2024, assimp team All rights reserved. diff --git a/code/Common/Importer.h b/code/Common/Importer.h index ab7e3a6b3..2aa6d9bda 100644 --- a/code/Common/Importer.h +++ b/code/Common/Importer.h @@ -2,7 +2,7 @@ Open Asset Import Library (assimp) ---------------------------------------------------------------------- -Copyright (c) 2006-2022, assimp team +Copyright (c) 2006-2024, assimp team All rights reserved. diff --git a/code/Common/ImporterRegistry.cpp b/code/Common/ImporterRegistry.cpp index c67fee936..92a04e692 100644 --- a/code/Common/ImporterRegistry.cpp +++ b/code/Common/ImporterRegistry.cpp @@ -3,7 +3,7 @@ Open Asset Import Library (assimp) --------------------------------------------------------------------------- -Copyright (c) 2006-2022, assimp team +Copyright (c) 2006-2024, assimp team All rights reserved. diff --git a/code/Common/Maybe.h b/code/Common/Maybe.h index 387c1bcaf..99b18b67c 100644 --- a/code/Common/Maybe.h +++ b/code/Common/Maybe.h @@ -2,7 +2,7 @@ Open Asset Import Library (assimp) ---------------------------------------------------------------------- -Copyright (c) 2006-2022, assimp team +Copyright (c) 2006-2024, assimp team All rights reserved. diff --git a/code/Common/PolyTools.h b/code/Common/PolyTools.h index b53de8579..46ceb9d75 100644 --- a/code/Common/PolyTools.h +++ b/code/Common/PolyTools.h @@ -2,7 +2,7 @@ Open Asset Import Library (assimp) ---------------------------------------------------------------------- -Copyright (c) 2006-2022, assimp team +Copyright (c) 2006-2024, assimp team All rights reserved. diff --git a/code/Common/PostStepRegistry.cpp b/code/Common/PostStepRegistry.cpp index de4f39083..fdf33fc40 100644 --- a/code/Common/PostStepRegistry.cpp +++ b/code/Common/PostStepRegistry.cpp @@ -3,7 +3,7 @@ Open Asset Import Library (assimp) --------------------------------------------------------------------------- -Copyright (c) 2006-2022, assimp team +Copyright (c) 2006-2024, assimp team diff --git a/code/Common/RemoveComments.cpp b/code/Common/RemoveComments.cpp index 52dd37ff0..a6a472400 100644 --- a/code/Common/RemoveComments.cpp +++ b/code/Common/RemoveComments.cpp @@ -2,7 +2,7 @@ Open Asset Import Library (assimp) ---------------------------------------------------------------------- -Copyright (c) 2006-2022, assimp team +Copyright (c) 2006-2024, assimp team All rights reserved. diff --git a/code/Common/SGSpatialSort.cpp b/code/Common/SGSpatialSort.cpp index 0ef1853c0..4cf1ac50f 100644 --- a/code/Common/SGSpatialSort.cpp +++ b/code/Common/SGSpatialSort.cpp @@ -3,7 +3,7 @@ Open Asset Import Library (assimp) --------------------------------------------------------------------------- -Copyright (c) 2006-2022, assimp team +Copyright (c) 2006-2024, assimp team diff --git a/code/Common/SceneCombiner.cpp b/code/Common/SceneCombiner.cpp index 0188f5dea..44897a40b 100644 --- a/code/Common/SceneCombiner.cpp +++ b/code/Common/SceneCombiner.cpp @@ -2,7 +2,7 @@ Open Asset Import Library (assimp) ---------------------------------------------------------------------- -Copyright (c) 2006-2022, assimp team +Copyright (c) 2006-2024, assimp team All rights reserved. diff --git a/code/Common/ScenePreprocessor.cpp b/code/Common/ScenePreprocessor.cpp index 18a257ad4..b4bbe9d67 100644 --- a/code/Common/ScenePreprocessor.cpp +++ b/code/Common/ScenePreprocessor.cpp @@ -2,7 +2,7 @@ Open Asset Import Library (assimp) ---------------------------------------------------------------------- -Copyright (c) 2006-2022, assimp team +Copyright (c) 2006-2024, assimp team All rights reserved. diff --git a/code/Common/ScenePreprocessor.h b/code/Common/ScenePreprocessor.h index 49e06ed1c..2f491e9a8 100644 --- a/code/Common/ScenePreprocessor.h +++ b/code/Common/ScenePreprocessor.h @@ -2,7 +2,7 @@ Open Asset Import Library (assimp) ---------------------------------------------------------------------- -Copyright (c) 2006-2022, assimp team +Copyright (c) 2006-2024, assimp team All rights reserved. diff --git a/code/Common/ScenePrivate.h b/code/Common/ScenePrivate.h index 3910db78c..b8c524aa2 100644 --- a/code/Common/ScenePrivate.h +++ b/code/Common/ScenePrivate.h @@ -2,7 +2,7 @@ Open Asset Import Library (assimp) ---------------------------------------------------------------------- -Copyright (c) 2006-2022, assimp team +Copyright (c) 2006-2024, assimp team All rights reserved. diff --git a/code/Common/SkeletonMeshBuilder.cpp b/code/Common/SkeletonMeshBuilder.cpp index f3c8fb412..167652700 100644 --- a/code/Common/SkeletonMeshBuilder.cpp +++ b/code/Common/SkeletonMeshBuilder.cpp @@ -2,7 +2,7 @@ Open Asset Import Library (assimp) ---------------------------------------------------------------------- -Copyright (c) 2006-2022, assimp team +Copyright (c) 2006-2024, assimp team All rights reserved. diff --git a/code/Common/SpatialSort.cpp b/code/Common/SpatialSort.cpp index c8c5c30ed..34cb3fb05 100644 --- a/code/Common/SpatialSort.cpp +++ b/code/Common/SpatialSort.cpp @@ -3,7 +3,7 @@ Open Asset Import Library (assimp) --------------------------------------------------------------------------- -Copyright (c) 2006-2022, assimp team +Copyright (c) 2006-2024, assimp team All rights reserved. diff --git a/code/Common/StackAllocator.h b/code/Common/StackAllocator.h index 191010cac..b9123b608 100644 --- a/code/Common/StackAllocator.h +++ b/code/Common/StackAllocator.h @@ -2,7 +2,7 @@ Open Asset Import Library (assimp) ---------------------------------------------------------------------- -Copyright (c) 2006-2022, assimp team +Copyright (c) 2006-2024, assimp team All rights reserved. diff --git a/code/Common/StackAllocator.inl b/code/Common/StackAllocator.inl index 2c3164ca7..bca0ce1ef 100644 --- a/code/Common/StackAllocator.inl +++ b/code/Common/StackAllocator.inl @@ -2,7 +2,7 @@ Open Asset Import Library (assimp) ---------------------------------------------------------------------- -Copyright (c) 2006-2022, assimp team +Copyright (c) 2006-2024, assimp team All rights reserved. diff --git a/code/Common/StandardShapes.cpp b/code/Common/StandardShapes.cpp index abf3c4839..4a967997e 100644 --- a/code/Common/StandardShapes.cpp +++ b/code/Common/StandardShapes.cpp @@ -2,7 +2,7 @@ Open Asset Import Library (assimp) ---------------------------------------------------------------------- -Copyright (c) 2006-2022, assimp team +Copyright (c) 2006-2024, assimp team All rights reserved. diff --git a/code/Common/StbCommon.h b/code/Common/StbCommon.h index 91f8e424a..aef23ce17 100644 --- a/code/Common/StbCommon.h +++ b/code/Common/StbCommon.h @@ -2,7 +2,7 @@ Open Asset Import Library (assimp) ---------------------------------------------------------------------- -Copyright (c) 2006-2022, assimp team +Copyright (c) 2006-2024, assimp team All rights reserved. diff --git a/code/Common/StdOStreamLogStream.h b/code/Common/StdOStreamLogStream.h index cc0e06263..683c87d5f 100644 --- a/code/Common/StdOStreamLogStream.h +++ b/code/Common/StdOStreamLogStream.h @@ -3,7 +3,7 @@ Open Asset Import Library (assimp) --------------------------------------------------------------------------- -Copyright (c) 2006-2022, assimp team +Copyright (c) 2006-2024, assimp team diff --git a/code/Common/Subdivision.cpp b/code/Common/Subdivision.cpp index 3aea5d4c5..782fe8a21 100644 --- a/code/Common/Subdivision.cpp +++ b/code/Common/Subdivision.cpp @@ -2,7 +2,7 @@ Open Asset Import Library (assimp) ---------------------------------------------------------------------- -Copyright (c) 2006-2022, assimp team +Copyright (c) 2006-2024, assimp team All rights reserved. diff --git a/code/Common/TargetAnimation.cpp b/code/Common/TargetAnimation.cpp index 5f6d9bad0..52924a3b9 100644 --- a/code/Common/TargetAnimation.cpp +++ b/code/Common/TargetAnimation.cpp @@ -2,7 +2,7 @@ Open Asset Import Library (assimp) ---------------------------------------------------------------------- -Copyright (c) 2006-2022, assimp team +Copyright (c) 2006-2024, assimp team All rights reserved. diff --git a/code/Common/TargetAnimation.h b/code/Common/TargetAnimation.h index 863406b94..96d2b1bc8 100644 --- a/code/Common/TargetAnimation.h +++ b/code/Common/TargetAnimation.h @@ -2,7 +2,7 @@ Open Asset Import Library (assimp) ---------------------------------------------------------------------- -Copyright (c) 2006-2022, assimp team +Copyright (c) 2006-2024, assimp team All rights reserved. diff --git a/code/Common/Version.cpp b/code/Common/Version.cpp index 1699b99d6..24a5f5250 100644 --- a/code/Common/Version.cpp +++ b/code/Common/Version.cpp @@ -3,7 +3,7 @@ Open Asset Import Library (assimp) --------------------------------------------------------------------------- -Copyright (c) 2006-2023, assimp team +Copyright (c) 2006-2024, assimp team All rights reserved. diff --git a/code/Common/VertexTriangleAdjacency.cpp b/code/Common/VertexTriangleAdjacency.cpp index 555e3e386..84344c907 100644 --- a/code/Common/VertexTriangleAdjacency.cpp +++ b/code/Common/VertexTriangleAdjacency.cpp @@ -3,7 +3,7 @@ Open Asset Import Library (assimp) --------------------------------------------------------------------------- -Copyright (c) 2006-2022, assimp team +Copyright (c) 2006-2024, assimp team diff --git a/code/Common/VertexTriangleAdjacency.h b/code/Common/VertexTriangleAdjacency.h index 41d809450..20d3bd32c 100644 --- a/code/Common/VertexTriangleAdjacency.h +++ b/code/Common/VertexTriangleAdjacency.h @@ -2,7 +2,7 @@ Open Asset Import Library (assimp) ---------------------------------------------------------------------- -Copyright (c) 2006-2022, assimp team +Copyright (c) 2006-2024, assimp team All rights reserved. diff --git a/code/Common/Win32DebugLogStream.h b/code/Common/Win32DebugLogStream.h index 34d849e83..f8bc017af 100644 --- a/code/Common/Win32DebugLogStream.h +++ b/code/Common/Win32DebugLogStream.h @@ -3,7 +3,7 @@ Open Asset Import Library (assimp) --------------------------------------------------------------------------- -Copyright (c) 2006-2022, assimp team +Copyright (c) 2006-2024, assimp team diff --git a/code/Common/ZipArchiveIOSystem.cpp b/code/Common/ZipArchiveIOSystem.cpp index 51a250810..c8babd4cb 100644 --- a/code/Common/ZipArchiveIOSystem.cpp +++ b/code/Common/ZipArchiveIOSystem.cpp @@ -2,7 +2,7 @@ Open Asset Import Library (assimp) ---------------------------------------------------------------------- -Copyright (c) 2006-2022, assimp team +Copyright (c) 2006-2024, assimp team All rights reserved. diff --git a/code/Common/material.cpp b/code/Common/material.cpp index ffc2f415b..76676ec1a 100644 --- a/code/Common/material.cpp +++ b/code/Common/material.cpp @@ -2,7 +2,7 @@ Open Asset Import Library (assimp) ---------------------------------------------------------------------- -Copyright (c) 2006-2022, assimp team +Copyright (c) 2006-2024, assimp team All rights reserved. diff --git a/code/Common/scene.cpp b/code/Common/scene.cpp index b0e882154..e42f4b2e6 100644 --- a/code/Common/scene.cpp +++ b/code/Common/scene.cpp @@ -3,7 +3,7 @@ Open Asset Import Library (assimp) --------------------------------------------------------------------------- -Copyright (c) 2006-2022, assimp team +Copyright (c) 2006-2024, assimp team All rights reserved. diff --git a/code/Common/simd.cpp b/code/Common/simd.cpp index 0dd437d26..6a48750b0 100644 --- a/code/Common/simd.cpp +++ b/code/Common/simd.cpp @@ -3,7 +3,7 @@ Open Asset Import Library (assimp) --------------------------------------------------------------------------- -Copyright (c) 2006-2022, assimp team +Copyright (c) 2006-2024, assimp team All rights reserved. diff --git a/code/Common/simd.h b/code/Common/simd.h index a1d936629..05d27d253 100644 --- a/code/Common/simd.h +++ b/code/Common/simd.h @@ -3,7 +3,7 @@ Open Asset Import Library (assimp) --------------------------------------------------------------------------- -Copyright (c) 2006-2022, assimp team +Copyright (c) 2006-2024, assimp team All rights reserved. diff --git a/code/Geometry/GeometryUtils.cpp b/code/Geometry/GeometryUtils.cpp index cec1e74c5..375e501d3 100644 --- a/code/Geometry/GeometryUtils.cpp +++ b/code/Geometry/GeometryUtils.cpp @@ -2,7 +2,7 @@ Open Asset Import Library (assimp) ---------------------------------------------------------------------- -Copyright (c) 2006-2022, assimp team +Copyright (c) 2006-2024, assimp team All rights reserved. diff --git a/code/Geometry/GeometryUtils.h b/code/Geometry/GeometryUtils.h index b6fff99e1..2e205c872 100644 --- a/code/Geometry/GeometryUtils.h +++ b/code/Geometry/GeometryUtils.h @@ -2,7 +2,7 @@ Open Asset Import Library (assimp) ---------------------------------------------------------------------- -Copyright (c) 2006-2022, assimp team +Copyright (c) 2006-2024, assimp team All rights reserved. diff --git a/code/Material/MaterialSystem.cpp b/code/Material/MaterialSystem.cpp index cc8ca2f88..dbae4b7e4 100644 --- a/code/Material/MaterialSystem.cpp +++ b/code/Material/MaterialSystem.cpp @@ -2,7 +2,7 @@ Open Asset Import Library (assimp) ---------------------------------------------------------------------- -Copyright (c) 2006-2022, assimp team +Copyright (c) 2006-2024, assimp team All rights reserved. diff --git a/code/Material/MaterialSystem.h b/code/Material/MaterialSystem.h index 41891ad97..e7c752179 100644 --- a/code/Material/MaterialSystem.h +++ b/code/Material/MaterialSystem.h @@ -2,7 +2,7 @@ Open Asset Import Library (assimp) ---------------------------------------------------------------------- -Copyright (c) 2006-2022, assimp team +Copyright (c) 2006-2024, assimp team All rights reserved. diff --git a/code/Pbrt/PbrtExporter.cpp b/code/Pbrt/PbrtExporter.cpp index 9e4ca293d..907e9a6a2 100644 --- a/code/Pbrt/PbrtExporter.cpp +++ b/code/Pbrt/PbrtExporter.cpp @@ -2,7 +2,7 @@ Open Asset Import Library (assimp) ---------------------------------------------------------------------- -Copyright (c) 2006-2022, assimp team +Copyright (c) 2006-2024, assimp team All rights reserved. diff --git a/code/Pbrt/PbrtExporter.h b/code/Pbrt/PbrtExporter.h index a4b1a608a..0242ddcf0 100644 --- a/code/Pbrt/PbrtExporter.h +++ b/code/Pbrt/PbrtExporter.h @@ -2,7 +2,7 @@ Open Asset Import Library (assimp) ---------------------------------------------------------------------- -Copyright (c) 2006-2022, assimp team +Copyright (c) 2006-2024, assimp team All rights reserved. diff --git a/code/PostProcessing/ArmaturePopulate.cpp b/code/PostProcessing/ArmaturePopulate.cpp index 234a00232..fa524a7fd 100644 --- a/code/PostProcessing/ArmaturePopulate.cpp +++ b/code/PostProcessing/ArmaturePopulate.cpp @@ -2,7 +2,7 @@ Open Asset Import Library (assimp) ---------------------------------------------------------------------- -Copyright (c) 2006-2022, assimp team +Copyright (c) 2006-2024, assimp team All rights reserved. diff --git a/code/PostProcessing/ArmaturePopulate.h b/code/PostProcessing/ArmaturePopulate.h index 52d3adfef..af1792fb0 100644 --- a/code/PostProcessing/ArmaturePopulate.h +++ b/code/PostProcessing/ArmaturePopulate.h @@ -2,7 +2,7 @@ Open Asset Import Library (assimp) ---------------------------------------------------------------------- -Copyright (c) 2006-2022, assimp team +Copyright (c) 2006-2024, assimp team All rights reserved. diff --git a/code/PostProcessing/CalcTangentsProcess.cpp b/code/PostProcessing/CalcTangentsProcess.cpp index a23ac856b..82fde1348 100644 --- a/code/PostProcessing/CalcTangentsProcess.cpp +++ b/code/PostProcessing/CalcTangentsProcess.cpp @@ -3,7 +3,7 @@ Open Asset Import Library (assimp) --------------------------------------------------------------------------- -Copyright (c) 2006-2022, assimp team +Copyright (c) 2006-2024, assimp team diff --git a/code/PostProcessing/CalcTangentsProcess.h b/code/PostProcessing/CalcTangentsProcess.h index aaccb5307..3d7bb2a5e 100644 --- a/code/PostProcessing/CalcTangentsProcess.h +++ b/code/PostProcessing/CalcTangentsProcess.h @@ -2,7 +2,7 @@ Open Asset Import Library (assimp) ---------------------------------------------------------------------- -Copyright (c) 2006-2022, assimp team +Copyright (c) 2006-2024, assimp team All rights reserved. diff --git a/code/PostProcessing/ComputeUVMappingProcess.cpp b/code/PostProcessing/ComputeUVMappingProcess.cpp index f75dc5952..2aa34de28 100644 --- a/code/PostProcessing/ComputeUVMappingProcess.cpp +++ b/code/PostProcessing/ComputeUVMappingProcess.cpp @@ -2,7 +2,7 @@ Open Asset Import Library (assimp) ---------------------------------------------------------------------- -Copyright (c) 2006-2022, assimp team +Copyright (c) 2006-2024, assimp team All rights reserved. diff --git a/code/PostProcessing/ComputeUVMappingProcess.h b/code/PostProcessing/ComputeUVMappingProcess.h index c4158f402..2a40a15b1 100644 --- a/code/PostProcessing/ComputeUVMappingProcess.h +++ b/code/PostProcessing/ComputeUVMappingProcess.h @@ -2,7 +2,7 @@ Open Asset Import Library (assimp) ---------------------------------------------------------------------- -Copyright (c) 2006-2022, assimp team +Copyright (c) 2006-2024, assimp team All rights reserved. diff --git a/code/PostProcessing/ConvertToLHProcess.cpp b/code/PostProcessing/ConvertToLHProcess.cpp index 80abf84a5..77c7cb853 100644 --- a/code/PostProcessing/ConvertToLHProcess.cpp +++ b/code/PostProcessing/ConvertToLHProcess.cpp @@ -3,7 +3,7 @@ Open Asset Import Library (assimp) --------------------------------------------------------------------------- -Copyright (c) 2006-2022, assimp team +Copyright (c) 2006-2024, assimp team All rights reserved. diff --git a/code/PostProcessing/ConvertToLHProcess.h b/code/PostProcessing/ConvertToLHProcess.h index ea001b95b..e5ef19a8d 100644 --- a/code/PostProcessing/ConvertToLHProcess.h +++ b/code/PostProcessing/ConvertToLHProcess.h @@ -2,7 +2,7 @@ Open Asset Import Library (assimp) ---------------------------------------------------------------------- -Copyright (c) 2006-2022, assimp team +Copyright (c) 2006-2024, assimp team All rights reserved. diff --git a/code/PostProcessing/DeboneProcess.cpp b/code/PostProcessing/DeboneProcess.cpp index e91196ce2..1ae79ee30 100644 --- a/code/PostProcessing/DeboneProcess.cpp +++ b/code/PostProcessing/DeboneProcess.cpp @@ -2,7 +2,7 @@ Open Asset Import Library (assimp) ---------------------------------------------------------------------- -Copyright (c) 2006-2022, assimp team +Copyright (c) 2006-2024, assimp team All rights reserved. diff --git a/code/PostProcessing/DeboneProcess.h b/code/PostProcessing/DeboneProcess.h index ae4448e0e..cc2d43cb7 100644 --- a/code/PostProcessing/DeboneProcess.h +++ b/code/PostProcessing/DeboneProcess.h @@ -2,7 +2,7 @@ Open Asset Import Library (assimp) ---------------------------------------------------------------------- -Copyright (c) 2006-2022, assimp team +Copyright (c) 2006-2024, assimp team All rights reserved. diff --git a/code/PostProcessing/DropFaceNormalsProcess.cpp b/code/PostProcessing/DropFaceNormalsProcess.cpp index c5f6333e0..29967b74b 100644 --- a/code/PostProcessing/DropFaceNormalsProcess.cpp +++ b/code/PostProcessing/DropFaceNormalsProcess.cpp @@ -3,7 +3,7 @@ Open Asset Import Library (assimp) --------------------------------------------------------------------------- -Copyright (c) 2006-2022, assimp team +Copyright (c) 2006-2024, assimp team diff --git a/code/PostProcessing/DropFaceNormalsProcess.h b/code/PostProcessing/DropFaceNormalsProcess.h index df542f2ba..84f9dbe83 100644 --- a/code/PostProcessing/DropFaceNormalsProcess.h +++ b/code/PostProcessing/DropFaceNormalsProcess.h @@ -2,7 +2,7 @@ Open Asset Import Library (assimp) ---------------------------------------------------------------------- -Copyright (c) 2006-2022, assimp team +Copyright (c) 2006-2024, assimp team All rights reserved. diff --git a/code/PostProcessing/EmbedTexturesProcess.cpp b/code/PostProcessing/EmbedTexturesProcess.cpp index d5d2ef872..568031d8f 100644 --- a/code/PostProcessing/EmbedTexturesProcess.cpp +++ b/code/PostProcessing/EmbedTexturesProcess.cpp @@ -2,7 +2,7 @@ Open Asset Import Library (assimp) ---------------------------------------------------------------------- -Copyright (c) 2006-2022, assimp team +Copyright (c) 2006-2024, assimp team All rights reserved. diff --git a/code/PostProcessing/EmbedTexturesProcess.h b/code/PostProcessing/EmbedTexturesProcess.h index 77d4d9c72..8210eec96 100644 --- a/code/PostProcessing/EmbedTexturesProcess.h +++ b/code/PostProcessing/EmbedTexturesProcess.h @@ -2,7 +2,7 @@ Open Asset Import Library (assimp) ---------------------------------------------------------------------- -Copyright (c) 2006-2022, assimp team +Copyright (c) 2006-2024, assimp team All rights reserved. diff --git a/code/PostProcessing/FindDegenerates.cpp b/code/PostProcessing/FindDegenerates.cpp index d9c14425c..c506b08b5 100644 --- a/code/PostProcessing/FindDegenerates.cpp +++ b/code/PostProcessing/FindDegenerates.cpp @@ -3,7 +3,7 @@ Open Asset Import Library (assimp) --------------------------------------------------------------------------- -Copyright (c) 2006-2022, assimp team +Copyright (c) 2006-2024, assimp team All rights reserved. diff --git a/code/PostProcessing/FindDegenerates.h b/code/PostProcessing/FindDegenerates.h index 6b37a47cf..0d046df2d 100644 --- a/code/PostProcessing/FindDegenerates.h +++ b/code/PostProcessing/FindDegenerates.h @@ -2,7 +2,7 @@ Open Asset Import Library (assimp) ---------------------------------------------------------------------- -Copyright (c) 2006-2022, assimp team +Copyright (c) 2006-2024, assimp team All rights reserved. diff --git a/code/PostProcessing/FindInstancesProcess.cpp b/code/PostProcessing/FindInstancesProcess.cpp index 55974b1c3..9186dd3dd 100644 --- a/code/PostProcessing/FindInstancesProcess.cpp +++ b/code/PostProcessing/FindInstancesProcess.cpp @@ -3,7 +3,7 @@ Open Asset Import Library (assimp) --------------------------------------------------------------------------- -Copyright (c) 2006-2022, assimp team +Copyright (c) 2006-2024, assimp team diff --git a/code/PostProcessing/FindInstancesProcess.h b/code/PostProcessing/FindInstancesProcess.h index 6927301ca..63e988abf 100644 --- a/code/PostProcessing/FindInstancesProcess.h +++ b/code/PostProcessing/FindInstancesProcess.h @@ -2,7 +2,7 @@ Open Asset Import Library (assimp) ---------------------------------------------------------------------- -Copyright (c) 2006-2022, assimp team +Copyright (c) 2006-2024, assimp team All rights reserved. diff --git a/code/PostProcessing/FindInvalidDataProcess.cpp b/code/PostProcessing/FindInvalidDataProcess.cpp index 64abf7589..12f345407 100644 --- a/code/PostProcessing/FindInvalidDataProcess.cpp +++ b/code/PostProcessing/FindInvalidDataProcess.cpp @@ -3,7 +3,7 @@ Open Asset Import Library (assimp) --------------------------------------------------------------------------- -Copyright (c) 2006-2023, assimp team +Copyright (c) 2006-2024, assimp team All rights reserved. diff --git a/code/PostProcessing/FindInvalidDataProcess.h b/code/PostProcessing/FindInvalidDataProcess.h index 024eb9b1e..516db4272 100644 --- a/code/PostProcessing/FindInvalidDataProcess.h +++ b/code/PostProcessing/FindInvalidDataProcess.h @@ -2,7 +2,7 @@ Open Asset Import Library (assimp) ---------------------------------------------------------------------- -Copyright (c) 2006-2022, assimp team +Copyright (c) 2006-2024, assimp team All rights reserved. diff --git a/code/PostProcessing/FixNormalsStep.cpp b/code/PostProcessing/FixNormalsStep.cpp index 54ac05cc8..2bf85430f 100644 --- a/code/PostProcessing/FixNormalsStep.cpp +++ b/code/PostProcessing/FixNormalsStep.cpp @@ -3,7 +3,7 @@ Open Asset Import Library (assimp) --------------------------------------------------------------------------- -Copyright (c) 2006-2022, assimp team +Copyright (c) 2006-2024, assimp team diff --git a/code/PostProcessing/FixNormalsStep.h b/code/PostProcessing/FixNormalsStep.h index 20be1958b..b25d92282 100644 --- a/code/PostProcessing/FixNormalsStep.h +++ b/code/PostProcessing/FixNormalsStep.h @@ -2,7 +2,7 @@ Open Asset Import Library (assimp) ---------------------------------------------------------------------- -Copyright (c) 2006-2022, assimp team +Copyright (c) 2006-2024, assimp team All rights reserved. diff --git a/code/PostProcessing/GenBoundingBoxesProcess.cpp b/code/PostProcessing/GenBoundingBoxesProcess.cpp index ca8e4d6d0..da9fd7137 100644 --- a/code/PostProcessing/GenBoundingBoxesProcess.cpp +++ b/code/PostProcessing/GenBoundingBoxesProcess.cpp @@ -3,7 +3,7 @@ Open Asset Import Library (assimp) --------------------------------------------------------------------------- -Copyright (c) 2006-2022, assimp team +Copyright (c) 2006-2024, assimp team All rights reserved. diff --git a/code/PostProcessing/GenBoundingBoxesProcess.h b/code/PostProcessing/GenBoundingBoxesProcess.h index 0cf8514f4..c24009dc9 100644 --- a/code/PostProcessing/GenBoundingBoxesProcess.h +++ b/code/PostProcessing/GenBoundingBoxesProcess.h @@ -3,7 +3,7 @@ Open Asset Import Library (assimp) --------------------------------------------------------------------------- -Copyright (c) 2006-2022, assimp team +Copyright (c) 2006-2024, assimp team All rights reserved. diff --git a/code/PostProcessing/GenFaceNormalsProcess.cpp b/code/PostProcessing/GenFaceNormalsProcess.cpp index 1d259ce22..79a30ca24 100644 --- a/code/PostProcessing/GenFaceNormalsProcess.cpp +++ b/code/PostProcessing/GenFaceNormalsProcess.cpp @@ -3,7 +3,7 @@ Open Asset Import Library (assimp) --------------------------------------------------------------------------- -Copyright (c) 2006-2022, assimp team +Copyright (c) 2006-2024, assimp team diff --git a/code/PostProcessing/GenFaceNormalsProcess.h b/code/PostProcessing/GenFaceNormalsProcess.h index 94794631e..a5aad13d1 100644 --- a/code/PostProcessing/GenFaceNormalsProcess.h +++ b/code/PostProcessing/GenFaceNormalsProcess.h @@ -2,7 +2,7 @@ Open Asset Import Library (assimp) ---------------------------------------------------------------------- -Copyright (c) 2006-2022, assimp team +Copyright (c) 2006-2024, assimp team All rights reserved. diff --git a/code/PostProcessing/GenVertexNormalsProcess.cpp b/code/PostProcessing/GenVertexNormalsProcess.cpp index 4869263ab..f7fef6bc4 100644 --- a/code/PostProcessing/GenVertexNormalsProcess.cpp +++ b/code/PostProcessing/GenVertexNormalsProcess.cpp @@ -3,7 +3,7 @@ Open Asset Import Library (assimp) --------------------------------------------------------------------------- -Copyright (c) 2006-2022, assimp team +Copyright (c) 2006-2024, assimp team All rights reserved. diff --git a/code/PostProcessing/GenVertexNormalsProcess.h b/code/PostProcessing/GenVertexNormalsProcess.h index b7db9c4f2..677c06a43 100644 --- a/code/PostProcessing/GenVertexNormalsProcess.h +++ b/code/PostProcessing/GenVertexNormalsProcess.h @@ -2,7 +2,7 @@ Open Asset Import Library (assimp) ---------------------------------------------------------------------- -Copyright (c) 2006-2022, assimp team +Copyright (c) 2006-2024, assimp team All rights reserved. diff --git a/code/PostProcessing/ImproveCacheLocality.cpp b/code/PostProcessing/ImproveCacheLocality.cpp index d7bb95698..c165b0114 100644 --- a/code/PostProcessing/ImproveCacheLocality.cpp +++ b/code/PostProcessing/ImproveCacheLocality.cpp @@ -3,7 +3,7 @@ Open Asset Import Library (assimp) --------------------------------------------------------------------------- -Copyright (c) 2006-2023, assimp team +Copyright (c) 2006-2024, assimp team All rights reserved. diff --git a/code/PostProcessing/ImproveCacheLocality.h b/code/PostProcessing/ImproveCacheLocality.h index 6f4d55719..30fa59608 100644 --- a/code/PostProcessing/ImproveCacheLocality.h +++ b/code/PostProcessing/ImproveCacheLocality.h @@ -2,7 +2,7 @@ Open Asset Import Library (assimp) ---------------------------------------------------------------------- -Copyright (c) 2006-2022, assimp team +Copyright (c) 2006-2024, assimp team All rights reserved. diff --git a/code/PostProcessing/JoinVerticesProcess.cpp b/code/PostProcessing/JoinVerticesProcess.cpp index 4de6c3e1b..f4c623c98 100644 --- a/code/PostProcessing/JoinVerticesProcess.cpp +++ b/code/PostProcessing/JoinVerticesProcess.cpp @@ -3,7 +3,7 @@ Open Asset Import Library (assimp) --------------------------------------------------------------------------- -Copyright (c) 2006-2022, assimp team +Copyright (c) 2006-2024, assimp team All rights reserved. diff --git a/code/PostProcessing/JoinVerticesProcess.h b/code/PostProcessing/JoinVerticesProcess.h index aa8dc5794..60630dae3 100644 --- a/code/PostProcessing/JoinVerticesProcess.h +++ b/code/PostProcessing/JoinVerticesProcess.h @@ -2,7 +2,7 @@ Open Asset Import Library (assimp) ---------------------------------------------------------------------- -Copyright (c) 2006-2022, assimp team +Copyright (c) 2006-2024, assimp team All rights reserved. diff --git a/code/PostProcessing/LimitBoneWeightsProcess.cpp b/code/PostProcessing/LimitBoneWeightsProcess.cpp index 16b32143e..816914ada 100644 --- a/code/PostProcessing/LimitBoneWeightsProcess.cpp +++ b/code/PostProcessing/LimitBoneWeightsProcess.cpp @@ -2,7 +2,7 @@ Open Asset Import Library (assimp) ---------------------------------------------------------------------- -Copyright (c) 2006-2023, assimp team +Copyright (c) 2006-2024, assimp team All rights reserved. diff --git a/code/PostProcessing/LimitBoneWeightsProcess.h b/code/PostProcessing/LimitBoneWeightsProcess.h index 8e5ebd80d..b2612c313 100644 --- a/code/PostProcessing/LimitBoneWeightsProcess.h +++ b/code/PostProcessing/LimitBoneWeightsProcess.h @@ -2,7 +2,7 @@ Open Asset Import Library (assimp) ---------------------------------------------------------------------- -Copyright (c) 2006-2022, assimp team +Copyright (c) 2006-2024, assimp team All rights reserved. diff --git a/code/PostProcessing/MakeVerboseFormat.cpp b/code/PostProcessing/MakeVerboseFormat.cpp index 1cc2fdc02..d0c5693e7 100644 --- a/code/PostProcessing/MakeVerboseFormat.cpp +++ b/code/PostProcessing/MakeVerboseFormat.cpp @@ -3,7 +3,7 @@ Open Asset Import Library (assimp) --------------------------------------------------------------------------- -Copyright (c) 2006-2022, assimp team +Copyright (c) 2006-2024, assimp team diff --git a/code/PostProcessing/MakeVerboseFormat.h b/code/PostProcessing/MakeVerboseFormat.h index f21f5919e..02fe21fa7 100644 --- a/code/PostProcessing/MakeVerboseFormat.h +++ b/code/PostProcessing/MakeVerboseFormat.h @@ -2,7 +2,7 @@ Open Asset Import Library (assimp) ---------------------------------------------------------------------- -Copyright (c) 2006-2022, assimp team +Copyright (c) 2006-2024, assimp team All rights reserved. diff --git a/code/PostProcessing/OptimizeGraph.cpp b/code/PostProcessing/OptimizeGraph.cpp index bcd654634..3be5ff514 100644 --- a/code/PostProcessing/OptimizeGraph.cpp +++ b/code/PostProcessing/OptimizeGraph.cpp @@ -3,7 +3,7 @@ Open Asset Import Library (assimp) --------------------------------------------------------------------------- -Copyright (c) 2006-2022, assimp team +Copyright (c) 2006-2024, assimp team All rights reserved. diff --git a/code/PostProcessing/OptimizeGraph.h b/code/PostProcessing/OptimizeGraph.h index 23e59e67d..c32748d7f 100644 --- a/code/PostProcessing/OptimizeGraph.h +++ b/code/PostProcessing/OptimizeGraph.h @@ -2,7 +2,7 @@ Open Asset Import Library (assimp) ---------------------------------------------------------------------- -Copyright (c) 2006-2022, assimp team +Copyright (c) 2006-2024, assimp team All rights reserved. diff --git a/code/PostProcessing/OptimizeMeshes.cpp b/code/PostProcessing/OptimizeMeshes.cpp index 0fd597808..44792420c 100644 --- a/code/PostProcessing/OptimizeMeshes.cpp +++ b/code/PostProcessing/OptimizeMeshes.cpp @@ -3,7 +3,7 @@ Open Asset Import Library (assimp) --------------------------------------------------------------------------- -Copyright (c) 2006-2022, assimp team +Copyright (c) 2006-2024, assimp team diff --git a/code/PostProcessing/OptimizeMeshes.h b/code/PostProcessing/OptimizeMeshes.h index 0b062959a..e424ae24a 100644 --- a/code/PostProcessing/OptimizeMeshes.h +++ b/code/PostProcessing/OptimizeMeshes.h @@ -2,7 +2,7 @@ Open Asset Import Library (assimp) ---------------------------------------------------------------------- -Copyright (c) 2006-2022, assimp team +Copyright (c) 2006-2024, assimp team All rights reserved. diff --git a/code/PostProcessing/PretransformVertices.cpp b/code/PostProcessing/PretransformVertices.cpp index aff6e535a..37727c968 100644 --- a/code/PostProcessing/PretransformVertices.cpp +++ b/code/PostProcessing/PretransformVertices.cpp @@ -3,7 +3,7 @@ Open Asset Import Library (assimp) --------------------------------------------------------------------------- -Copyright (c) 2006-2022, assimp team +Copyright (c) 2006-2024, assimp team All rights reserved. diff --git a/code/PostProcessing/PretransformVertices.h b/code/PostProcessing/PretransformVertices.h index 69d3d8400..74c886488 100644 --- a/code/PostProcessing/PretransformVertices.h +++ b/code/PostProcessing/PretransformVertices.h @@ -2,7 +2,7 @@ Open Asset Import Library (assimp) ---------------------------------------------------------------------- -Copyright (c) 2006-2022, assimp team +Copyright (c) 2006-2024, assimp team All rights reserved. diff --git a/code/PostProcessing/ProcessHelper.cpp b/code/PostProcessing/ProcessHelper.cpp index 36ffd6fe0..4dcc8a60a 100644 --- a/code/PostProcessing/ProcessHelper.cpp +++ b/code/PostProcessing/ProcessHelper.cpp @@ -2,7 +2,7 @@ Open Asset Import Library (assimp) ---------------------------------------------------------------------- -Copyright (c) 2006-2022, assimp team +Copyright (c) 2006-2024, assimp team All rights reserved. diff --git a/code/PostProcessing/ProcessHelper.h b/code/PostProcessing/ProcessHelper.h index 78df94ca1..273b122ae 100644 --- a/code/PostProcessing/ProcessHelper.h +++ b/code/PostProcessing/ProcessHelper.h @@ -2,7 +2,7 @@ Open Asset Import Library (assimp) ---------------------------------------------------------------------- -Copyright (c) 2006-2022, assimp team +Copyright (c) 2006-2024, assimp team All rights reserved. diff --git a/code/PostProcessing/RemoveRedundantMaterials.cpp b/code/PostProcessing/RemoveRedundantMaterials.cpp index b5fa7e732..e32fe21ac 100644 --- a/code/PostProcessing/RemoveRedundantMaterials.cpp +++ b/code/PostProcessing/RemoveRedundantMaterials.cpp @@ -3,7 +3,7 @@ Open Asset Import Library (assimp) --------------------------------------------------------------------------- -Copyright (c) 2006-2022, assimp team +Copyright (c) 2006-2024, assimp team All rights reserved. diff --git a/code/PostProcessing/RemoveRedundantMaterials.h b/code/PostProcessing/RemoveRedundantMaterials.h index 1b42bea55..107de0daa 100644 --- a/code/PostProcessing/RemoveRedundantMaterials.h +++ b/code/PostProcessing/RemoveRedundantMaterials.h @@ -2,7 +2,7 @@ Open Asset Import Library (assimp) ---------------------------------------------------------------------- -Copyright (c) 2006-2022, assimp team +Copyright (c) 2006-2024, assimp team All rights reserved. diff --git a/code/PostProcessing/RemoveVCProcess.cpp b/code/PostProcessing/RemoveVCProcess.cpp index bcad65423..13ef81e23 100644 --- a/code/PostProcessing/RemoveVCProcess.cpp +++ b/code/PostProcessing/RemoveVCProcess.cpp @@ -3,7 +3,7 @@ Open Asset Import Library (assimp) --------------------------------------------------------------------------- -Copyright (c) 2006-2022, assimp team +Copyright (c) 2006-2024, assimp team All rights reserved. diff --git a/code/PostProcessing/RemoveVCProcess.h b/code/PostProcessing/RemoveVCProcess.h index 45c0b3a71..8d9b5167a 100644 --- a/code/PostProcessing/RemoveVCProcess.h +++ b/code/PostProcessing/RemoveVCProcess.h @@ -2,7 +2,7 @@ Open Asset Import Library (assimp) ---------------------------------------------------------------------- -Copyright (c) 2006-2022, assimp team +Copyright (c) 2006-2024, assimp team All rights reserved. diff --git a/code/PostProcessing/ScaleProcess.cpp b/code/PostProcessing/ScaleProcess.cpp index 1bb9196f1..5cd7eea6e 100644 --- a/code/PostProcessing/ScaleProcess.cpp +++ b/code/PostProcessing/ScaleProcess.cpp @@ -2,7 +2,7 @@ Open Asset Import Library (assimp) ---------------------------------------------------------------------- -Copyright (c) 2006-2022, assimp team +Copyright (c) 2006-2024, assimp team All rights reserved. diff --git a/code/PostProcessing/ScaleProcess.h b/code/PostProcessing/ScaleProcess.h index ae1c3ed00..2887c7221 100644 --- a/code/PostProcessing/ScaleProcess.h +++ b/code/PostProcessing/ScaleProcess.h @@ -2,7 +2,7 @@ Open Asset Import Library (assimp) ---------------------------------------------------------------------- -Copyright (c) 2006-2022, assimp team +Copyright (c) 2006-2024, assimp team All rights reserved. diff --git a/code/PostProcessing/SortByPTypeProcess.cpp b/code/PostProcessing/SortByPTypeProcess.cpp index 47633dce5..48ebbc573 100644 --- a/code/PostProcessing/SortByPTypeProcess.cpp +++ b/code/PostProcessing/SortByPTypeProcess.cpp @@ -3,7 +3,7 @@ Open Asset Import Library (assimp) --------------------------------------------------------------------------- -Copyright (c) 2006-2022, assimp team +Copyright (c) 2006-2024, assimp team All rights reserved. diff --git a/code/PostProcessing/SortByPTypeProcess.h b/code/PostProcessing/SortByPTypeProcess.h index ce4f7da62..aa7774d7f 100644 --- a/code/PostProcessing/SortByPTypeProcess.h +++ b/code/PostProcessing/SortByPTypeProcess.h @@ -2,7 +2,7 @@ Open Asset Import Library (assimp) ---------------------------------------------------------------------- -Copyright (c) 2006-2022, assimp team +Copyright (c) 2006-2024, assimp team All rights reserved. diff --git a/code/PostProcessing/SplitByBoneCountProcess.cpp b/code/PostProcessing/SplitByBoneCountProcess.cpp index 969146fee..ea50f8f7f 100644 --- a/code/PostProcessing/SplitByBoneCountProcess.cpp +++ b/code/PostProcessing/SplitByBoneCountProcess.cpp @@ -2,7 +2,7 @@ Open Asset Import Library (assimp) ---------------------------------------------------------------------- -Copyright (c) 2006-2022, assimp team +Copyright (c) 2006-2024, assimp team All rights reserved. diff --git a/code/PostProcessing/SplitByBoneCountProcess.h b/code/PostProcessing/SplitByBoneCountProcess.h index efe85824f..c90661cb5 100644 --- a/code/PostProcessing/SplitByBoneCountProcess.h +++ b/code/PostProcessing/SplitByBoneCountProcess.h @@ -2,7 +2,7 @@ Open Asset Import Library (assimp) ---------------------------------------------------------------------- -Copyright (c) 2006-2022, assimp team +Copyright (c) 2006-2024, assimp team All rights reserved. diff --git a/code/PostProcessing/SplitLargeMeshes.cpp b/code/PostProcessing/SplitLargeMeshes.cpp index b6e5b772a..3bee28521 100644 --- a/code/PostProcessing/SplitLargeMeshes.cpp +++ b/code/PostProcessing/SplitLargeMeshes.cpp @@ -2,7 +2,7 @@ Open Asset Import Library (assimp) ---------------------------------------------------------------------- -Copyright (c) 2006-2022, assimp team +Copyright (c) 2006-2024, assimp team All rights reserved. diff --git a/code/PostProcessing/SplitLargeMeshes.h b/code/PostProcessing/SplitLargeMeshes.h index 4e0d764c1..25bf300d5 100644 --- a/code/PostProcessing/SplitLargeMeshes.h +++ b/code/PostProcessing/SplitLargeMeshes.h @@ -2,7 +2,7 @@ Open Asset Import Library (assimp) ---------------------------------------------------------------------- -Copyright (c) 2006-2022, assimp team +Copyright (c) 2006-2024, assimp team All rights reserved. diff --git a/code/PostProcessing/TextureTransform.cpp b/code/PostProcessing/TextureTransform.cpp index 3de357c17..53dba3860 100644 --- a/code/PostProcessing/TextureTransform.cpp +++ b/code/PostProcessing/TextureTransform.cpp @@ -2,7 +2,7 @@ Open Asset Import Library (assimp) ---------------------------------------------------------------------- -Copyright (c) 2006-2022, assimp team +Copyright (c) 2006-2024, assimp team All rights reserved. diff --git a/code/PostProcessing/TextureTransform.h b/code/PostProcessing/TextureTransform.h index c9f0480ba..7c0addf09 100644 --- a/code/PostProcessing/TextureTransform.h +++ b/code/PostProcessing/TextureTransform.h @@ -2,7 +2,7 @@ Open Asset Import Library (assimp) ---------------------------------------------------------------------- -Copyright (c) 2006-2022, assimp team +Copyright (c) 2006-2024, assimp team All rights reserved. diff --git a/code/PostProcessing/TriangulateProcess.cpp b/code/PostProcessing/TriangulateProcess.cpp index f16de2196..ac483f215 100644 --- a/code/PostProcessing/TriangulateProcess.cpp +++ b/code/PostProcessing/TriangulateProcess.cpp @@ -3,7 +3,7 @@ Open Asset Import Library (assimp) --------------------------------------------------------------------------- -Copyright (c) 2006-2022, assimp team +Copyright (c) 2006-2024, assimp team All rights reserved. diff --git a/code/PostProcessing/TriangulateProcess.h b/code/PostProcessing/TriangulateProcess.h index ac31e4377..e17a10e33 100644 --- a/code/PostProcessing/TriangulateProcess.h +++ b/code/PostProcessing/TriangulateProcess.h @@ -2,7 +2,7 @@ Open Asset Import Library (assimp) ---------------------------------------------------------------------- -Copyright (c) 2006-2022, assimp team +Copyright (c) 2006-2024, assimp team All rights reserved. diff --git a/code/PostProcessing/ValidateDataStructure.cpp b/code/PostProcessing/ValidateDataStructure.cpp index 14259e11a..a0a73e200 100644 --- a/code/PostProcessing/ValidateDataStructure.cpp +++ b/code/PostProcessing/ValidateDataStructure.cpp @@ -3,7 +3,7 @@ Open Asset Import Library (assimp) --------------------------------------------------------------------------- -Copyright (c) 2006-2022, assimp team +Copyright (c) 2006-2024, assimp team All rights reserved. diff --git a/code/PostProcessing/ValidateDataStructure.h b/code/PostProcessing/ValidateDataStructure.h index 9cfd4ced1..8bc13e60d 100644 --- a/code/PostProcessing/ValidateDataStructure.h +++ b/code/PostProcessing/ValidateDataStructure.h @@ -2,7 +2,7 @@ Open Asset Import Library (assimp) ---------------------------------------------------------------------- -Copyright (c) 2006-2022, assimp team +Copyright (c) 2006-2024, assimp team All rights reserved. diff --git a/contrib/pugixml/readme.txt b/contrib/pugixml/readme.txt index 9dffb72a1..2c1865437 100644 --- a/contrib/pugixml/readme.txt +++ b/contrib/pugixml/readme.txt @@ -1,6 +1,6 @@ pugixml 1.13 - an XML processing library -Copyright (C) 2006-2022, by Arseny Kapoulkine (arseny.kapoulkine@gmail.com) +Copyright (c) 2006-2024, by Arseny Kapoulkine (arseny.kapoulkine@gmail.com) Report bugs and download new versions at https://pugixml.org/ This is the distribution of pugixml, which is a C++ XML processing library, @@ -26,7 +26,7 @@ The distribution contains the following folders: This library is distributed under the MIT License: -Copyright (c) 2006-2022 Arseny Kapoulkine +Copyright (c) 2006-2024 Arseny Kapoulkine Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation diff --git a/contrib/pugixml/src/pugiconfig.hpp b/contrib/pugixml/src/pugiconfig.hpp index 9bf2efd39..1a3956903 100644 --- a/contrib/pugixml/src/pugiconfig.hpp +++ b/contrib/pugixml/src/pugiconfig.hpp @@ -1,7 +1,7 @@ /** * pugixml parser - version 1.13 * -------------------------------------------------------- - * Copyright (C) 2006-2022, by Arseny Kapoulkine (arseny.kapoulkine@gmail.com) + * Copyright (c) 2006-2024, by Arseny Kapoulkine (arseny.kapoulkine@gmail.com) * Report bugs and download new versions at https://pugixml.org/ * * This library is distributed under the MIT License. See notice at the end @@ -52,7 +52,7 @@ #endif /** - * Copyright (c) 2006-2022 Arseny Kapoulkine + * Copyright (c) 2006-2024 Arseny Kapoulkine * * Permission is hereby granted, free of charge, to any person * obtaining a copy of this software and associated documentation diff --git a/contrib/pugixml/src/pugixml.cpp b/contrib/pugixml/src/pugixml.cpp index c63645b67..6d6bd0edb 100644 --- a/contrib/pugixml/src/pugixml.cpp +++ b/contrib/pugixml/src/pugixml.cpp @@ -1,7 +1,7 @@ /** * pugixml parser - version 1.13 * -------------------------------------------------------- - * Copyright (C) 2006-2022, by Arseny Kapoulkine (arseny.kapoulkine@gmail.com) + * Copyright (c) 2006-2024, by Arseny Kapoulkine (arseny.kapoulkine@gmail.com) * Report bugs and download new versions at https://pugixml.org/ * * This library is distributed under the MIT License. See notice at the end @@ -13133,7 +13133,7 @@ namespace pugi #endif /** - * Copyright (c) 2006-2022 Arseny Kapoulkine + * Copyright (c) 2006-2024 Arseny Kapoulkine * * Permission is hereby granted, free of charge, to any person * obtaining a copy of this software and associated documentation diff --git a/contrib/pugixml/src/pugixml.hpp b/contrib/pugixml/src/pugixml.hpp index 050df154c..fde6a4a86 100644 --- a/contrib/pugixml/src/pugixml.hpp +++ b/contrib/pugixml/src/pugixml.hpp @@ -1,7 +1,7 @@ /** * pugixml parser - version 1.13 * -------------------------------------------------------- - * Copyright (C) 2006-2022, by Arseny Kapoulkine (arseny.kapoulkine@gmail.com) + * Copyright (c) 2006-2024, by Arseny Kapoulkine (arseny.kapoulkine@gmail.com) * Report bugs and download new versions at https://pugixml.org/ * * This library is distributed under the MIT License. See notice at the end @@ -1481,7 +1481,7 @@ namespace std #endif /** - * Copyright (c) 2006-2022 Arseny Kapoulkine + * Copyright (c) 2006-2024 Arseny Kapoulkine * * Permission is hereby granted, free of charge, to any person * obtaining a copy of this software and associated documentation diff --git a/fuzz/assimp_fuzzer.cc b/fuzz/assimp_fuzzer.cc index e347f59cb..8178674e8 100644 --- a/fuzz/assimp_fuzzer.cc +++ b/fuzz/assimp_fuzzer.cc @@ -3,7 +3,7 @@ Open Asset Import Library (assimp) --------------------------------------------------------------------------- -Copyright (c) 2006-2023, assimp team +Copyright (c) 2006-2024, assimp team All rights reserved. diff --git a/include/assimp/Base64.hpp b/include/assimp/Base64.hpp index 10288713c..6a3551307 100644 --- a/include/assimp/Base64.hpp +++ b/include/assimp/Base64.hpp @@ -3,7 +3,7 @@ Open Asset Import Library (assimp) --------------------------------------------------------------------------- -Copyright (c) 2006-2022, assimp team +Copyright (c) 2006-2024, assimp team All rights reserved. diff --git a/include/assimp/BaseImporter.h b/include/assimp/BaseImporter.h index f9df32b32..b82ddd70d 100644 --- a/include/assimp/BaseImporter.h +++ b/include/assimp/BaseImporter.h @@ -2,7 +2,7 @@ Open Asset Import Library (assimp) ---------------------------------------------------------------------- -Copyright (c) 2006-2022, assimp team +Copyright (c) 2006-2024, assimp team All rights reserved. diff --git a/include/assimp/Bitmap.h b/include/assimp/Bitmap.h index 2678b5f64..5145a6cd5 100644 --- a/include/assimp/Bitmap.h +++ b/include/assimp/Bitmap.h @@ -3,7 +3,7 @@ Open Asset Import Library (assimp) --------------------------------------------------------------------------- -Copyright (c) 2006-2022, assimp team +Copyright (c) 2006-2024, assimp team All rights reserved. diff --git a/include/assimp/BlobIOSystem.h b/include/assimp/BlobIOSystem.h index 7e8d46a53..eb23f9e92 100644 --- a/include/assimp/BlobIOSystem.h +++ b/include/assimp/BlobIOSystem.h @@ -3,7 +3,7 @@ Open Asset Import Library (assimp) --------------------------------------------------------------------------- -Copyright (c) 2006-2022, assimp team +Copyright (c) 2006-2024, assimp team All rights reserved. diff --git a/include/assimp/ByteSwapper.h b/include/assimp/ByteSwapper.h index 488f7a51d..179f7b555 100644 --- a/include/assimp/ByteSwapper.h +++ b/include/assimp/ByteSwapper.h @@ -2,7 +2,7 @@ Open Asset Import Library (assimp) ---------------------------------------------------------------------- -Copyright (c) 2006-2022, assimp team +Copyright (c) 2006-2024, assimp team All rights reserved. diff --git a/include/assimp/ColladaMetaData.h b/include/assimp/ColladaMetaData.h index 52eb3c508..9973d16a5 100644 --- a/include/assimp/ColladaMetaData.h +++ b/include/assimp/ColladaMetaData.h @@ -2,7 +2,7 @@ Open Asset Import Library (assimp) ---------------------------------------------------------------------- -Copyright (c) 2006-2022, assimp team +Copyright (c) 2006-2024, assimp team All rights reserved. diff --git a/include/assimp/CreateAnimMesh.h b/include/assimp/CreateAnimMesh.h index e5211f504..6e14ac747 100644 --- a/include/assimp/CreateAnimMesh.h +++ b/include/assimp/CreateAnimMesh.h @@ -2,7 +2,7 @@ Open Asset Import Library (assimp) ---------------------------------------------------------------------- -Copyright (c) 2006-2022, assimp team +Copyright (c) 2006-2024, assimp team All rights reserved. diff --git a/include/assimp/DefaultIOStream.h b/include/assimp/DefaultIOStream.h index 67cba3c5c..c39d9a8e1 100644 --- a/include/assimp/DefaultIOStream.h +++ b/include/assimp/DefaultIOStream.h @@ -2,7 +2,7 @@ Open Asset Import Library (assimp) ---------------------------------------------------------------------- -Copyright (c) 2006-2022, assimp team +Copyright (c) 2006-2024, assimp team All rights reserved. diff --git a/include/assimp/DefaultIOSystem.h b/include/assimp/DefaultIOSystem.h index 8545e75cf..0aeef9eb8 100644 --- a/include/assimp/DefaultIOSystem.h +++ b/include/assimp/DefaultIOSystem.h @@ -2,7 +2,7 @@ Open Asset Import Library (assimp) ---------------------------------------------------------------------- -Copyright (c) 2006-2022, assimp team +Copyright (c) 2006-2024, assimp team All rights reserved. diff --git a/include/assimp/DefaultLogger.hpp b/include/assimp/DefaultLogger.hpp index 723097ff2..b43eebb70 100644 --- a/include/assimp/DefaultLogger.hpp +++ b/include/assimp/DefaultLogger.hpp @@ -2,7 +2,7 @@ Open Asset Import Library (assimp) ---------------------------------------------------------------------- -Copyright (c) 2006-2022, assimp team +Copyright (c) 2006-2024, assimp team All rights reserved. diff --git a/include/assimp/Exceptional.h b/include/assimp/Exceptional.h index ec3d38c5a..b4b51863f 100644 --- a/include/assimp/Exceptional.h +++ b/include/assimp/Exceptional.h @@ -2,7 +2,7 @@ Open Asset Import Library (assimp) ---------------------------------------------------------------------- -Copyright (c) 2006-2022, assimp team +Copyright (c) 2006-2024, assimp team All rights reserved. Redistribution and use of this software in source and binary forms, diff --git a/include/assimp/Exporter.hpp b/include/assimp/Exporter.hpp index 09a459442..bdec20b97 100644 --- a/include/assimp/Exporter.hpp +++ b/include/assimp/Exporter.hpp @@ -3,7 +3,7 @@ Open Asset Import Library (assimp) --------------------------------------------------------------------------- -Copyright (c) 2006-2022, assimp team +Copyright (c) 2006-2024, assimp team All rights reserved. diff --git a/include/assimp/GenericProperty.h b/include/assimp/GenericProperty.h index 073d53312..a35ebf23d 100644 --- a/include/assimp/GenericProperty.h +++ b/include/assimp/GenericProperty.h @@ -2,7 +2,7 @@ Open Asset Import Library (assimp) ---------------------------------------------------------------------- -Copyright (c) 2006-2022, assimp team +Copyright (c) 2006-2024, assimp team All rights reserved. diff --git a/include/assimp/GltfMaterial.h b/include/assimp/GltfMaterial.h index 86ca8897c..5e63b9132 100644 --- a/include/assimp/GltfMaterial.h +++ b/include/assimp/GltfMaterial.h @@ -3,7 +3,7 @@ Open Asset Import Library (assimp) --------------------------------------------------------------------------- -Copyright (c) 2006-2022, assimp team +Copyright (c) 2006-2024, assimp team All rights reserved. diff --git a/include/assimp/Hash.h b/include/assimp/Hash.h index cf889362c..9dec87408 100644 --- a/include/assimp/Hash.h +++ b/include/assimp/Hash.h @@ -2,7 +2,7 @@ Open Asset Import Library (assimp) ---------------------------------------------------------------------- -Copyright (c) 2006-2022, assimp team +Copyright (c) 2006-2024, assimp team All rights reserved. diff --git a/include/assimp/IOStream.hpp b/include/assimp/IOStream.hpp index 12beb0dbb..bbc41ab21 100644 --- a/include/assimp/IOStream.hpp +++ b/include/assimp/IOStream.hpp @@ -3,7 +3,7 @@ Open Asset Import Library (assimp) --------------------------------------------------------------------------- -Copyright (c) 2006-2022, assimp team +Copyright (c) 2006-2024, assimp team All rights reserved. diff --git a/include/assimp/IOStreamBuffer.h b/include/assimp/IOStreamBuffer.h index 47db35a95..2d3bcb730 100644 --- a/include/assimp/IOStreamBuffer.h +++ b/include/assimp/IOStreamBuffer.h @@ -2,7 +2,7 @@ Open Asset Import Library (assimp) ---------------------------------------------------------------------- -Copyright (c) 2006-2022, assimp team +Copyright (c) 2006-2024, assimp team All rights reserved. diff --git a/include/assimp/IOSystem.hpp b/include/assimp/IOSystem.hpp index acb1f8eae..b345151d5 100644 --- a/include/assimp/IOSystem.hpp +++ b/include/assimp/IOSystem.hpp @@ -3,7 +3,7 @@ Open Asset Import Library (assimp) --------------------------------------------------------------------------- -Copyright (c) 2006-2022, assimp team +Copyright (c) 2006-2024, assimp team All rights reserved. diff --git a/include/assimp/Importer.hpp b/include/assimp/Importer.hpp index 418643f1f..ed12deb75 100644 --- a/include/assimp/Importer.hpp +++ b/include/assimp/Importer.hpp @@ -3,7 +3,7 @@ Open Asset Import Library (assimp) --------------------------------------------------------------------------- -Copyright (c) 2006-2022, assimp team +Copyright (c) 2006-2024, assimp team diff --git a/include/assimp/LineSplitter.h b/include/assimp/LineSplitter.h index 0504e03d6..5d75294dd 100644 --- a/include/assimp/LineSplitter.h +++ b/include/assimp/LineSplitter.h @@ -2,7 +2,7 @@ Open Asset Import Library (assimp) ---------------------------------------------------------------------- -Copyright (c) 2006-2022, assimp team +Copyright (c) 2006-2024, assimp team All rights reserved. diff --git a/include/assimp/LogAux.h b/include/assimp/LogAux.h index a8cb8f24c..20a7564b8 100644 --- a/include/assimp/LogAux.h +++ b/include/assimp/LogAux.h @@ -2,7 +2,7 @@ Open Asset Import Library (assimp) ---------------------------------------------------------------------- -Copyright (c) 2006-2022, assimp team +Copyright (c) 2006-2024, assimp team All rights reserved. diff --git a/include/assimp/LogStream.hpp b/include/assimp/LogStream.hpp index 3b17b200a..2d9f1d350 100644 --- a/include/assimp/LogStream.hpp +++ b/include/assimp/LogStream.hpp @@ -2,7 +2,7 @@ Open Asset Import Library (assimp) ---------------------------------------------------------------------- -Copyright (c) 2006-2022, assimp team +Copyright (c) 2006-2024, assimp team All rights reserved. diff --git a/include/assimp/Logger.hpp b/include/assimp/Logger.hpp index e8df64dd8..0051153e2 100644 --- a/include/assimp/Logger.hpp +++ b/include/assimp/Logger.hpp @@ -2,7 +2,7 @@ Open Asset Import Library (assimp) ---------------------------------------------------------------------- -Copyright (c) 2006-2022, assimp team +Copyright (c) 2006-2024, assimp team All rights reserved. diff --git a/include/assimp/MathFunctions.h b/include/assimp/MathFunctions.h index f2a7ccdf6..eaa8b4ac4 100644 --- a/include/assimp/MathFunctions.h +++ b/include/assimp/MathFunctions.h @@ -3,7 +3,7 @@ Open Asset Import Library (assimp) --------------------------------------------------------------------------- -Copyright (c) 2006-2022, assimp team +Copyright (c) 2006-2024, assimp team All rights reserved. diff --git a/include/assimp/MemoryIOWrapper.h b/include/assimp/MemoryIOWrapper.h index 4023f7529..ef06af273 100644 --- a/include/assimp/MemoryIOWrapper.h +++ b/include/assimp/MemoryIOWrapper.h @@ -2,7 +2,7 @@ Open Asset Import Library (assimp) ---------------------------------------------------------------------- -Copyright (c) 2006-2022, assimp team +Copyright (c) 2006-2024, assimp team All rights reserved. diff --git a/include/assimp/NullLogger.hpp b/include/assimp/NullLogger.hpp index 1b594ea28..552bcf66a 100644 --- a/include/assimp/NullLogger.hpp +++ b/include/assimp/NullLogger.hpp @@ -2,7 +2,7 @@ Open Asset Import Library (assimp) ---------------------------------------------------------------------- -Copyright (c) 2006-2022, assimp team +Copyright (c) 2006-2024, assimp team All rights reserved. diff --git a/include/assimp/ObjMaterial.h b/include/assimp/ObjMaterial.h index 9c511916a..21087ebcb 100644 --- a/include/assimp/ObjMaterial.h +++ b/include/assimp/ObjMaterial.h @@ -3,7 +3,7 @@ Open Asset Import Library (assimp) --------------------------------------------------------------------------- -Copyright (c) 2006-2022, assimp team +Copyright (c) 2006-2024, assimp team All rights reserved. diff --git a/include/assimp/ParsingUtils.h b/include/assimp/ParsingUtils.h index 570f10aac..e0ee2d77c 100644 --- a/include/assimp/ParsingUtils.h +++ b/include/assimp/ParsingUtils.h @@ -2,7 +2,7 @@ Open Asset Import Library (assimp) ---------------------------------------------------------------------- -Copyright (c) 2006-2022, assimp team +Copyright (c) 2006-2024, assimp team All rights reserved. diff --git a/include/assimp/Profiler.h b/include/assimp/Profiler.h index 3b9263b40..ff4f590c3 100644 --- a/include/assimp/Profiler.h +++ b/include/assimp/Profiler.h @@ -2,7 +2,7 @@ Open Asset Import Library (assimp) ---------------------------------------------------------------------- -Copyright (c) 2006-2022, assimp team +Copyright (c) 2006-2024, assimp team All rights reserved. diff --git a/include/assimp/ProgressHandler.hpp b/include/assimp/ProgressHandler.hpp index 93d881659..2a1ab309c 100644 --- a/include/assimp/ProgressHandler.hpp +++ b/include/assimp/ProgressHandler.hpp @@ -2,7 +2,7 @@ Open Asset Import Library (assimp) ---------------------------------------------------------------------- -Copyright (c) 2006-2022, assimp team +Copyright (c) 2006-2024, assimp team All rights reserved. diff --git a/include/assimp/RemoveComments.h b/include/assimp/RemoveComments.h index c2defff63..a7a9a2381 100644 --- a/include/assimp/RemoveComments.h +++ b/include/assimp/RemoveComments.h @@ -2,7 +2,7 @@ Open Asset Import Library (assimp) ---------------------------------------------------------------------- -Copyright (c) 2006-2022, assimp team +Copyright (c) 2006-2024, assimp team All rights reserved. diff --git a/include/assimp/SGSpatialSort.h b/include/assimp/SGSpatialSort.h index 96feefabb..ea774a9d9 100644 --- a/include/assimp/SGSpatialSort.h +++ b/include/assimp/SGSpatialSort.h @@ -2,7 +2,7 @@ Open Asset Import Library (assimp) ---------------------------------------------------------------------- -Copyright (c) 2006-2022, assimp team +Copyright (c) 2006-2024, assimp team All rights reserved. diff --git a/include/assimp/SceneCombiner.h b/include/assimp/SceneCombiner.h index d6096900c..790a18c2d 100644 --- a/include/assimp/SceneCombiner.h +++ b/include/assimp/SceneCombiner.h @@ -2,7 +2,7 @@ Open Asset Import Library (assimp) ---------------------------------------------------------------------- -Copyright (c) 2006-2022, assimp team +Copyright (c) 2006-2024, assimp team All rights reserved. diff --git a/include/assimp/SkeletonMeshBuilder.h b/include/assimp/SkeletonMeshBuilder.h index 2929aaa61..620748632 100644 --- a/include/assimp/SkeletonMeshBuilder.h +++ b/include/assimp/SkeletonMeshBuilder.h @@ -4,7 +4,7 @@ Open Asset Import Library (assimp) ---------------------------------------------------------------------- -Copyright (c) 2006-2022, assimp team +Copyright (c) 2006-2024, assimp team All rights reserved. diff --git a/include/assimp/SmallVector.h b/include/assimp/SmallVector.h index 60ad26411..8e8e2db5f 100644 --- a/include/assimp/SmallVector.h +++ b/include/assimp/SmallVector.h @@ -2,7 +2,7 @@ Open Asset Import Library (assimp) ---------------------------------------------------------------------- -Copyright (c) 2006-2022, assimp team +Copyright (c) 2006-2024, assimp team All rights reserved. diff --git a/include/assimp/SmoothingGroups.h b/include/assimp/SmoothingGroups.h index 4625a2916..e77a8b2d9 100644 --- a/include/assimp/SmoothingGroups.h +++ b/include/assimp/SmoothingGroups.h @@ -2,7 +2,7 @@ Open Asset Import Library (assimp) ---------------------------------------------------------------------- -Copyright (c) 2006-2022, assimp team +Copyright (c) 2006-2024, assimp team All rights reserved. diff --git a/include/assimp/SmoothingGroups.inl b/include/assimp/SmoothingGroups.inl index d5fff5bf7..6de5ee997 100644 --- a/include/assimp/SmoothingGroups.inl +++ b/include/assimp/SmoothingGroups.inl @@ -3,7 +3,7 @@ Open Asset Import Library (assimp) --------------------------------------------------------------------------- -Copyright (c) 2006-2022, assimp team +Copyright (c) 2006-2024, assimp team All rights reserved. diff --git a/include/assimp/SpatialSort.h b/include/assimp/SpatialSort.h index cd055450e..e527b15a2 100644 --- a/include/assimp/SpatialSort.h +++ b/include/assimp/SpatialSort.h @@ -2,7 +2,7 @@ Open Asset Import Library (assimp) ---------------------------------------------------------------------- -Copyright (c) 2006-2022, assimp team +Copyright (c) 2006-2024, assimp team All rights reserved. diff --git a/include/assimp/StandardShapes.h b/include/assimp/StandardShapes.h index 77880cf9e..aad2ce395 100644 --- a/include/assimp/StandardShapes.h +++ b/include/assimp/StandardShapes.h @@ -2,7 +2,7 @@ Open Asset Import Library (assimp) ---------------------------------------------------------------------- -Copyright (c) 2006-2022, assimp team +Copyright (c) 2006-2024, assimp team All rights reserved. diff --git a/include/assimp/StreamReader.h b/include/assimp/StreamReader.h index 44b24a33b..66e83b7ac 100644 --- a/include/assimp/StreamReader.h +++ b/include/assimp/StreamReader.h @@ -3,7 +3,7 @@ Open Asset Import Library (assimp) --------------------------------------------------------------------------- -Copyright (c) 2006-2022, assimp team +Copyright (c) 2006-2024, assimp team All rights reserved. diff --git a/include/assimp/StreamWriter.h b/include/assimp/StreamWriter.h index 50e28447c..7b84789d1 100644 --- a/include/assimp/StreamWriter.h +++ b/include/assimp/StreamWriter.h @@ -3,7 +3,7 @@ Open Asset Import Library (assimp) --------------------------------------------------------------------------- -Copyright (c) 2006-2022, assimp team +Copyright (c) 2006-2024, assimp team All rights reserved. diff --git a/include/assimp/StringComparison.h b/include/assimp/StringComparison.h index 0518d426d..283d8ba6b 100644 --- a/include/assimp/StringComparison.h +++ b/include/assimp/StringComparison.h @@ -2,7 +2,7 @@ Open Asset Import Library (assimp) ---------------------------------------------------------------------- -Copyright (c) 2006-2022, assimp team +Copyright (c) 2006-2024, assimp team All rights reserved. diff --git a/include/assimp/StringUtils.h b/include/assimp/StringUtils.h index cd8726785..0af923902 100644 --- a/include/assimp/StringUtils.h +++ b/include/assimp/StringUtils.h @@ -2,7 +2,7 @@ Open Asset Import Library (assimp) ---------------------------------------------------------------------- -Copyright (c) 2006-2022, assimp team +Copyright (c) 2006-2024, assimp team All rights reserved. diff --git a/include/assimp/Subdivision.h b/include/assimp/Subdivision.h index 114120368..75f44cbb5 100644 --- a/include/assimp/Subdivision.h +++ b/include/assimp/Subdivision.h @@ -2,7 +2,7 @@ Open Asset Import Library (assimp) ---------------------------------------------------------------------- -Copyright (c) 2006-2022, assimp team +Copyright (c) 2006-2024, assimp team All rights reserved. diff --git a/include/assimp/TinyFormatter.h b/include/assimp/TinyFormatter.h index df2a32eca..387fc86b6 100644 --- a/include/assimp/TinyFormatter.h +++ b/include/assimp/TinyFormatter.h @@ -2,7 +2,7 @@ Open Asset Import Library (assimp) ---------------------------------------------------------------------- -Copyright (c) 2006-2022, assimp team +Copyright (c) 2006-2024, assimp team All rights reserved. diff --git a/include/assimp/Vertex.h b/include/assimp/Vertex.h index 3fc974504..62a531ce2 100644 --- a/include/assimp/Vertex.h +++ b/include/assimp/Vertex.h @@ -2,7 +2,7 @@ Open Asset Import Library (assimp) ---------------------------------------------------------------------- -Copyright (c) 2006-2022, assimp team +Copyright (c) 2006-2024, assimp team All rights reserved. diff --git a/include/assimp/XMLTools.h b/include/assimp/XMLTools.h index b2766f19b..fa27af134 100644 --- a/include/assimp/XMLTools.h +++ b/include/assimp/XMLTools.h @@ -2,7 +2,7 @@ Open Asset Import Library (assimp) ---------------------------------------------------------------------- -Copyright (c) 2006-2022, assimp team +Copyright (c) 2006-2024, assimp team All rights reserved. diff --git a/include/assimp/XmlParser.h b/include/assimp/XmlParser.h index 4ab42ba2a..4c19098a4 100644 --- a/include/assimp/XmlParser.h +++ b/include/assimp/XmlParser.h @@ -2,7 +2,7 @@ Open Asset Import Library (assimp) ---------------------------------------------------------------------- -Copyright (c) 2006-2022, assimp team +Copyright (c) 2006-2024, assimp team All rights reserved. diff --git a/include/assimp/aabb.h b/include/assimp/aabb.h index b38aa1697..4d117e473 100644 --- a/include/assimp/aabb.h +++ b/include/assimp/aabb.h @@ -3,7 +3,7 @@ Open Asset Import Library (assimp) --------------------------------------------------------------------------- -Copyright (c) 2006-2022, assimp team +Copyright (c) 2006-2024, assimp team All rights reserved. diff --git a/include/assimp/ai_assert.h b/include/assimp/ai_assert.h index e49a482dd..e4d43f31c 100644 --- a/include/assimp/ai_assert.h +++ b/include/assimp/ai_assert.h @@ -3,7 +3,7 @@ Open Asset Import Library (assimp) --------------------------------------------------------------------------- -Copyright (c) 2006-2022, assimp team +Copyright (c) 2006-2024, assimp team All rights reserved. diff --git a/include/assimp/anim.h b/include/assimp/anim.h index 49f0d5014..871207576 100644 --- a/include/assimp/anim.h +++ b/include/assimp/anim.h @@ -3,7 +3,7 @@ Open Asset Import Library (assimp) --------------------------------------------------------------------------- -Copyright (c) 2006-2022, assimp team +Copyright (c) 2006-2024, assimp team All rights reserved. diff --git a/include/assimp/camera.h b/include/assimp/camera.h index 09255fa05..b8ea59927 100644 --- a/include/assimp/camera.h +++ b/include/assimp/camera.h @@ -3,7 +3,7 @@ Open Asset Import Library (assimp) --------------------------------------------------------------------------- -Copyright (c) 2006-2022, assimp team +Copyright (c) 2006-2024, assimp team All rights reserved. diff --git a/include/assimp/cexport.h b/include/assimp/cexport.h index a45ece39b..175fe5ea4 100644 --- a/include/assimp/cexport.h +++ b/include/assimp/cexport.h @@ -3,7 +3,7 @@ Open Asset Import Library (assimp) --------------------------------------------------------------------------- -Copyright (c) 2006-2022, assimp team +Copyright (c) 2006-2024, assimp team All rights reserved. diff --git a/include/assimp/cfileio.h b/include/assimp/cfileio.h index fc1b95ad1..bd971957c 100644 --- a/include/assimp/cfileio.h +++ b/include/assimp/cfileio.h @@ -3,7 +3,7 @@ Open Asset Import Library (assimp) --------------------------------------------------------------------------- -Copyright (c) 2006-2022, assimp team +Copyright (c) 2006-2024, assimp team All rights reserved. diff --git a/include/assimp/cimport.h b/include/assimp/cimport.h index 935ed18bd..b0b4e038a 100644 --- a/include/assimp/cimport.h +++ b/include/assimp/cimport.h @@ -3,7 +3,7 @@ Open Asset Import Library (assimp) --------------------------------------------------------------------------- -Copyright (c) 2006-2022, assimp team +Copyright (c) 2006-2024, assimp team All rights reserved. diff --git a/include/assimp/color4.h b/include/assimp/color4.h index e1e354939..cdd61e451 100644 --- a/include/assimp/color4.h +++ b/include/assimp/color4.h @@ -3,7 +3,7 @@ Open Asset Import Library (assimp) --------------------------------------------------------------------------- -Copyright (c) 2006-2022, assimp team +Copyright (c) 2006-2024, assimp team All rights reserved. diff --git a/include/assimp/color4.inl b/include/assimp/color4.inl index aed3de6f1..7fd067758 100644 --- a/include/assimp/color4.inl +++ b/include/assimp/color4.inl @@ -3,7 +3,7 @@ Open Asset Import Library (assimp) --------------------------------------------------------------------------- -Copyright (c) 2006-2022, assimp team +Copyright (c) 2006-2024, assimp team All rights reserved. diff --git a/include/assimp/commonMetaData.h b/include/assimp/commonMetaData.h index ccded585b..53d2f37aa 100644 --- a/include/assimp/commonMetaData.h +++ b/include/assimp/commonMetaData.h @@ -3,7 +3,7 @@ Open Asset Import Library (assimp) --------------------------------------------------------------------------- -Copyright (c) 2006-2022, assimp team +Copyright (c) 2006-2024, assimp team All rights reserved. diff --git a/include/assimp/config.h.in b/include/assimp/config.h.in index 403ddb32a..67fc988be 100644 --- a/include/assimp/config.h.in +++ b/include/assimp/config.h.in @@ -3,7 +3,7 @@ Open Asset Import Library (assimp) --------------------------------------------------------------------------- -Copyright (c) 2006-2022, assimp team +Copyright (c) 2006-2024, assimp team All rights reserved. diff --git a/include/assimp/defs.h b/include/assimp/defs.h index e1aaafd44..6a971928d 100644 --- a/include/assimp/defs.h +++ b/include/assimp/defs.h @@ -3,7 +3,7 @@ Open Asset Import Library (assimp) --------------------------------------------------------------------------- -Copyright (c) 2006-2022, assimp team +Copyright (c) 2006-2024, assimp team All rights reserved. diff --git a/include/assimp/importerdesc.h b/include/assimp/importerdesc.h index d08bd1781..e26751049 100644 --- a/include/assimp/importerdesc.h +++ b/include/assimp/importerdesc.h @@ -3,7 +3,7 @@ Open Asset Import Library (assimp) --------------------------------------------------------------------------- -Copyright (c) 2006-2022, assimp team +Copyright (c) 2006-2024, assimp team All rights reserved. diff --git a/include/assimp/light.h b/include/assimp/light.h index 3331997a9..3233cec70 100644 --- a/include/assimp/light.h +++ b/include/assimp/light.h @@ -3,7 +3,7 @@ Open Asset Import Library (assimp) --------------------------------------------------------------------------- -Copyright (c) 2006-2022, assimp team +Copyright (c) 2006-2024, assimp team All rights reserved. diff --git a/include/assimp/material.h b/include/assimp/material.h index 80551e53d..30db265e8 100644 --- a/include/assimp/material.h +++ b/include/assimp/material.h @@ -3,7 +3,7 @@ Open Asset Import Library (assimp) --------------------------------------------------------------------------- -Copyright (c) 2006-2022, assimp team +Copyright (c) 2006-2024, assimp team All rights reserved. diff --git a/include/assimp/material.inl b/include/assimp/material.inl index b7222f9c7..fdf837db4 100644 --- a/include/assimp/material.inl +++ b/include/assimp/material.inl @@ -3,7 +3,7 @@ Open Asset Import Library (assimp) --------------------------------------------------------------------------- -Copyright (c) 2006-2022, assimp team +Copyright (c) 2006-2024, assimp team All rights reserved. diff --git a/include/assimp/matrix3x3.h b/include/assimp/matrix3x3.h index 74382e263..a49394ea4 100644 --- a/include/assimp/matrix3x3.h +++ b/include/assimp/matrix3x3.h @@ -3,7 +3,7 @@ Open Asset Import Library (assimp) --------------------------------------------------------------------------- -Copyright (c) 2006-2022, assimp team +Copyright (c) 2006-2024, assimp team All rights reserved. diff --git a/include/assimp/matrix3x3.inl b/include/assimp/matrix3x3.inl index 99d9197e3..c41a5a076 100644 --- a/include/assimp/matrix3x3.inl +++ b/include/assimp/matrix3x3.inl @@ -3,7 +3,7 @@ Open Asset Import Library (assimp) --------------------------------------------------------------------------- -Copyright (c) 2006-2022, assimp team +Copyright (c) 2006-2024, assimp team All rights reserved. diff --git a/include/assimp/matrix4x4.h b/include/assimp/matrix4x4.h index 7de59c706..a3a8abe22 100644 --- a/include/assimp/matrix4x4.h +++ b/include/assimp/matrix4x4.h @@ -3,7 +3,7 @@ Open Asset Import Library (assimp) --------------------------------------------------------------------------- -Copyright (c) 2006-2022, assimp team +Copyright (c) 2006-2024, assimp team diff --git a/include/assimp/mesh.h b/include/assimp/mesh.h index 45f50d5a5..ed9a8faf9 100644 --- a/include/assimp/mesh.h +++ b/include/assimp/mesh.h @@ -3,7 +3,7 @@ Open Asset Import Library (assimp) --------------------------------------------------------------------------- -Copyright (c) 2006-2023, assimp team +Copyright (c) 2006-2024, assimp team All rights reserved. diff --git a/include/assimp/metadata.h b/include/assimp/metadata.h index c766d0ae2..8d387ca00 100644 --- a/include/assimp/metadata.h +++ b/include/assimp/metadata.h @@ -3,7 +3,7 @@ Open Asset Import Library (assimp) --------------------------------------------------------------------------- -Copyright (c) 2006-2022, assimp team +Copyright (c) 2006-2024, assimp team All rights reserved. diff --git a/include/assimp/pbrmaterial.h b/include/assimp/pbrmaterial.h index 3bdf151a3..172d2b8cb 100644 --- a/include/assimp/pbrmaterial.h +++ b/include/assimp/pbrmaterial.h @@ -3,7 +3,7 @@ Open Asset Import Library (assimp) --------------------------------------------------------------------------- -Copyright (c) 2006-2022, assimp team +Copyright (c) 2006-2024, assimp team All rights reserved. diff --git a/include/assimp/postprocess.h b/include/assimp/postprocess.h index a905a8be0..962d500f8 100644 --- a/include/assimp/postprocess.h +++ b/include/assimp/postprocess.h @@ -2,7 +2,7 @@ Open Asset Import Library (assimp) ---------------------------------------------------------------------- -Copyright (c) 2006-2022, assimp team +Copyright (c) 2006-2024, assimp team All rights reserved. diff --git a/include/assimp/qnan.h b/include/assimp/qnan.h index c64cabaad..2c071320f 100644 --- a/include/assimp/qnan.h +++ b/include/assimp/qnan.h @@ -3,7 +3,7 @@ Open Asset Import Library (assimp) --------------------------------------------------------------------------- -Copyright (c) 2006-2022, assimp team +Copyright (c) 2006-2024, assimp team diff --git a/include/assimp/quaternion.inl b/include/assimp/quaternion.inl index 2cb24653c..d3e391331 100644 --- a/include/assimp/quaternion.inl +++ b/include/assimp/quaternion.inl @@ -3,7 +3,7 @@ Open Asset Import Library (assimp) --------------------------------------------------------------------------- -Copyright (c) 2006-2022, assimp team +Copyright (c) 2006-2024, assimp team diff --git a/include/assimp/scene.h b/include/assimp/scene.h index 1b830a5b0..86ab9bf60 100644 --- a/include/assimp/scene.h +++ b/include/assimp/scene.h @@ -3,7 +3,7 @@ Open Asset Import Library (assimp) --------------------------------------------------------------------------- -Copyright (c) 2006-2022, assimp team +Copyright (c) 2006-2024, assimp team All rights reserved. diff --git a/include/assimp/texture.h b/include/assimp/texture.h index 576fa7711..53837fc86 100644 --- a/include/assimp/texture.h +++ b/include/assimp/texture.h @@ -3,7 +3,7 @@ Open Asset Import Library (assimp) --------------------------------------------------------------------------- -Copyright (c) 2006-2022, assimp team +Copyright (c) 2006-2024, assimp team All rights reserved. diff --git a/include/assimp/vector2.h b/include/assimp/vector2.h index f06e9441d..a8bfddba2 100644 --- a/include/assimp/vector2.h +++ b/include/assimp/vector2.h @@ -3,7 +3,7 @@ Open Asset Import Library (assimp) --------------------------------------------------------------------------- -Copyright (c) 2006-2022, assimp team +Copyright (c) 2006-2024, assimp team All rights reserved. diff --git a/include/assimp/vector2.inl b/include/assimp/vector2.inl index 245eb3190..a5592ea31 100644 --- a/include/assimp/vector2.inl +++ b/include/assimp/vector2.inl @@ -3,7 +3,7 @@ Open Asset Import Library (assimp) --------------------------------------------------------------------------- -Copyright (c) 2006-2022, assimp team +Copyright (c) 2006-2024, assimp team diff --git a/include/assimp/vector3.h b/include/assimp/vector3.h index eb940e7f9..c09fe9b08 100644 --- a/include/assimp/vector3.h +++ b/include/assimp/vector3.h @@ -3,7 +3,7 @@ Open Asset Import Library (assimp) --------------------------------------------------------------------------- -Copyright (c) 2006-2022, assimp team +Copyright (c) 2006-2024, assimp team All rights reserved. diff --git a/include/assimp/vector3.inl b/include/assimp/vector3.inl index 28ca2be07..c42e4cf32 100644 --- a/include/assimp/vector3.inl +++ b/include/assimp/vector3.inl @@ -3,7 +3,7 @@ Open Asset Import Library (assimp) --------------------------------------------------------------------------- -Copyright (c) 2006-2022, assimp team +Copyright (c) 2006-2024, assimp team All rights reserved. diff --git a/include/assimp/version.h b/include/assimp/version.h index 812be551c..f7bcf5bbf 100644 --- a/include/assimp/version.h +++ b/include/assimp/version.h @@ -3,7 +3,7 @@ Open Asset Import Library (assimp) --------------------------------------------------------------------------- -Copyright (c) 2006-2023, assimp team +Copyright (c) 2006-2024, assimp team All rights reserved. diff --git a/test/CMakeLists.txt b/test/CMakeLists.txt index da6a5b00b..a59cafbbc 100644 --- a/test/CMakeLists.txt +++ b/test/CMakeLists.txt @@ -1,6 +1,6 @@ # Open Asset Import Library (assimp) # ---------------------------------------------------------------------- -# Copyright (c) 2006-2022, assimp team +# Copyright (c) 2006-2024, assimp team # # All rights reserved. # diff --git a/test/unit/AbstractImportExportBase.cpp b/test/unit/AbstractImportExportBase.cpp index 077a4d1f2..80e53500d 100644 --- a/test/unit/AbstractImportExportBase.cpp +++ b/test/unit/AbstractImportExportBase.cpp @@ -3,7 +3,7 @@ Open Asset Import Library (assimp) --------------------------------------------------------------------------- -Copyright (c) 2006-2022, assimp team +Copyright (c) 2006-2024, assimp team diff --git a/test/unit/AssimpAPITest.cpp b/test/unit/AssimpAPITest.cpp index b8739b039..effe940b1 100644 --- a/test/unit/AssimpAPITest.cpp +++ b/test/unit/AssimpAPITest.cpp @@ -3,7 +3,7 @@ Open Asset Import Library (assimp) --------------------------------------------------------------------------- -Copyright (c) 2006-2022, assimp team +Copyright (c) 2006-2024, assimp team All rights reserved. diff --git a/test/unit/AssimpAPITest_aiMatrix3x3.cpp b/test/unit/AssimpAPITest_aiMatrix3x3.cpp index 90976ba6e..7b4532dce 100644 --- a/test/unit/AssimpAPITest_aiMatrix3x3.cpp +++ b/test/unit/AssimpAPITest_aiMatrix3x3.cpp @@ -3,7 +3,7 @@ Open Asset Import Library (assimp) --------------------------------------------------------------------------- -Copyright (c) 2006-2022, assimp team +Copyright (c) 2006-2024, assimp team diff --git a/test/unit/AssimpAPITest_aiQuaternion.cpp b/test/unit/AssimpAPITest_aiQuaternion.cpp index 68daeefec..fe28bc9d0 100644 --- a/test/unit/AssimpAPITest_aiQuaternion.cpp +++ b/test/unit/AssimpAPITest_aiQuaternion.cpp @@ -3,7 +3,7 @@ Open Asset Import Library (assimp) --------------------------------------------------------------------------- -Copyright (c) 2006-2022, assimp team +Copyright (c) 2006-2024, assimp team diff --git a/test/unit/AssimpAPITest_aiVector2D.cpp b/test/unit/AssimpAPITest_aiVector2D.cpp index 44bb34aec..8831016cd 100644 --- a/test/unit/AssimpAPITest_aiVector2D.cpp +++ b/test/unit/AssimpAPITest_aiVector2D.cpp @@ -3,7 +3,7 @@ Open Asset Import Library (assimp) --------------------------------------------------------------------------- -Copyright (c) 2006-2022, assimp team +Copyright (c) 2006-2024, assimp team diff --git a/test/unit/AssimpAPITest_aiVector3D.cpp b/test/unit/AssimpAPITest_aiVector3D.cpp index c7521163d..67ad11bb6 100644 --- a/test/unit/AssimpAPITest_aiVector3D.cpp +++ b/test/unit/AssimpAPITest_aiVector3D.cpp @@ -3,7 +3,7 @@ Open Asset Import Library (assimp) --------------------------------------------------------------------------- -Copyright (c) 2006-2022, assimp team +Copyright (c) 2006-2024, assimp team diff --git a/test/unit/Common/uiScene.cpp b/test/unit/Common/uiScene.cpp index 509bf71b1..5002b5dd8 100644 --- a/test/unit/Common/uiScene.cpp +++ b/test/unit/Common/uiScene.cpp @@ -3,7 +3,7 @@ Open Asset Import Library (assimp) --------------------------------------------------------------------------- -Copyright (c) 2006-2022, assimp team +Copyright (c) 2006-2024, assimp team All rights reserved. diff --git a/test/unit/Common/utAssertHandler.cpp b/test/unit/Common/utAssertHandler.cpp index 039ba8345..53bf5c929 100644 --- a/test/unit/Common/utAssertHandler.cpp +++ b/test/unit/Common/utAssertHandler.cpp @@ -3,7 +3,7 @@ Open Asset Import Library (assimp) --------------------------------------------------------------------------- -Copyright (c) 2006-2022, assimp team +Copyright (c) 2006-2024, assimp team All rights reserved. diff --git a/test/unit/Common/utBase64.cpp b/test/unit/Common/utBase64.cpp index ec927b980..910a908cb 100644 --- a/test/unit/Common/utBase64.cpp +++ b/test/unit/Common/utBase64.cpp @@ -3,7 +3,7 @@ Open Asset Import Library (assimp) --------------------------------------------------------------------------- -Copyright (c) 2006-2022, assimp team +Copyright (c) 2006-2024, assimp team All rights reserved. diff --git a/test/unit/Common/utBaseProcess.cpp b/test/unit/Common/utBaseProcess.cpp index 359042315..f70dae07b 100644 --- a/test/unit/Common/utBaseProcess.cpp +++ b/test/unit/Common/utBaseProcess.cpp @@ -3,7 +3,7 @@ Open Asset Import Library (assimp) --------------------------------------------------------------------------- -Copyright (c) 2006-2022, assimp team +Copyright (c) 2006-2024, assimp team All rights reserved. diff --git a/test/unit/Common/utHash.cpp b/test/unit/Common/utHash.cpp index 97e2d91c1..912aca11d 100644 --- a/test/unit/Common/utHash.cpp +++ b/test/unit/Common/utHash.cpp @@ -3,7 +3,7 @@ Open Asset Import Library (assimp) --------------------------------------------------------------------------- -Copyright (c) 2006-2022, assimp team +Copyright (c) 2006-2024, assimp team All rights reserved. diff --git a/test/unit/Common/utLineSplitter.cpp b/test/unit/Common/utLineSplitter.cpp index 0a97f72d9..f62a00c74 100644 --- a/test/unit/Common/utLineSplitter.cpp +++ b/test/unit/Common/utLineSplitter.cpp @@ -3,7 +3,7 @@ Open Asset Import Library (assimp) --------------------------------------------------------------------------- -Copyright (c) 2006-2022, assimp team +Copyright (c) 2006-2024, assimp team diff --git a/test/unit/Common/utMaybe.cpp b/test/unit/Common/utMaybe.cpp index 9de300290..c66b8f603 100644 --- a/test/unit/Common/utMaybe.cpp +++ b/test/unit/Common/utMaybe.cpp @@ -3,7 +3,7 @@ Open Asset Import Library (assimp) --------------------------------------------------------------------------- -Copyright (c) 2006-2022, assimp team +Copyright (c) 2006-2024, assimp team All rights reserved. diff --git a/test/unit/Common/utMesh.cpp b/test/unit/Common/utMesh.cpp index 77a711394..7baaa92a0 100644 --- a/test/unit/Common/utMesh.cpp +++ b/test/unit/Common/utMesh.cpp @@ -3,7 +3,7 @@ Open Asset Import Library (assimp) --------------------------------------------------------------------------- -Copyright (c) 2006-2022, assimp team +Copyright (c) 2006-2024, assimp team All rights reserved. diff --git a/test/unit/Common/utSpatialSort.cpp b/test/unit/Common/utSpatialSort.cpp index 6b05ac65e..a75daebce 100644 --- a/test/unit/Common/utSpatialSort.cpp +++ b/test/unit/Common/utSpatialSort.cpp @@ -3,7 +3,7 @@ Open Asset Import Library (assimp) --------------------------------------------------------------------------- -Copyright (c) 2006-2022, assimp team +Copyright (c) 2006-2024, assimp team All rights reserved. diff --git a/test/unit/Common/utStandardShapes.cpp b/test/unit/Common/utStandardShapes.cpp index d7e6d21d7..e1843d6c5 100644 --- a/test/unit/Common/utStandardShapes.cpp +++ b/test/unit/Common/utStandardShapes.cpp @@ -1,7 +1,7 @@ /* Open Asset Import Library (assimp) ---------------------------------------------------------------------- -Copyright (c) 2006-2022, assimp team +Copyright (c) 2006-2024, assimp team All rights reserved. Redistribution and use of this software in source and binary forms, with or without modification, are permitted provided that the diff --git a/test/unit/Common/utXmlParser.cpp b/test/unit/Common/utXmlParser.cpp index 2db78e30d..b566aa381 100644 --- a/test/unit/Common/utXmlParser.cpp +++ b/test/unit/Common/utXmlParser.cpp @@ -2,7 +2,7 @@ Open Asset Import Library (assimp) --------------------------------------------------------------------------- -Copyright (c) 2006-2022, assimp team +Copyright (c) 2006-2024, assimp team All rights reserved. diff --git a/test/unit/Geometry/utGeometryUtils.cpp b/test/unit/Geometry/utGeometryUtils.cpp index 2e764860d..345946132 100644 --- a/test/unit/Geometry/utGeometryUtils.cpp +++ b/test/unit/Geometry/utGeometryUtils.cpp @@ -3,7 +3,7 @@ Open Asset Import Library (assimp) --------------------------------------------------------------------------- -Copyright (c) 2006-2022, assimp team +Copyright (c) 2006-2024, assimp team All rights reserved. diff --git a/test/unit/ImportExport/MDL/MDLHL1TestFiles.h b/test/unit/ImportExport/MDL/MDLHL1TestFiles.h index 3c0630f63..0fff3411e 100644 --- a/test/unit/ImportExport/MDL/MDLHL1TestFiles.h +++ b/test/unit/ImportExport/MDL/MDLHL1TestFiles.h @@ -3,7 +3,7 @@ Open Asset Import Library (assimp) --------------------------------------------------------------------------- -Copyright (c) 2006-2022, assimp team +Copyright (c) 2006-2024, assimp team All rights reserved. diff --git a/test/unit/ImportExport/MDL/utMDLImporter_HL1_ImportSettings.cpp b/test/unit/ImportExport/MDL/utMDLImporter_HL1_ImportSettings.cpp index d50c2b35a..f6e03cb09 100644 --- a/test/unit/ImportExport/MDL/utMDLImporter_HL1_ImportSettings.cpp +++ b/test/unit/ImportExport/MDL/utMDLImporter_HL1_ImportSettings.cpp @@ -3,7 +3,7 @@ Open Asset Import Library (assimp) --------------------------------------------------------------------------- -Copyright (c) 2006-2022, assimp team +Copyright (c) 2006-2024, assimp team All rights reserved. diff --git a/test/unit/ImportExport/MDL/utMDLImporter_HL1_Materials.cpp b/test/unit/ImportExport/MDL/utMDLImporter_HL1_Materials.cpp index f733893ca..d0345e3e4 100644 --- a/test/unit/ImportExport/MDL/utMDLImporter_HL1_Materials.cpp +++ b/test/unit/ImportExport/MDL/utMDLImporter_HL1_Materials.cpp @@ -3,7 +3,7 @@ Open Asset Import Library (assimp) --------------------------------------------------------------------------- -Copyright (c) 2006-2022, assimp team +Copyright (c) 2006-2024, assimp team All rights reserved. diff --git a/test/unit/ImportExport/MDL/utMDLImporter_HL1_Nodes.cpp b/test/unit/ImportExport/MDL/utMDLImporter_HL1_Nodes.cpp index 49ae8a16c..1029a6138 100644 --- a/test/unit/ImportExport/MDL/utMDLImporter_HL1_Nodes.cpp +++ b/test/unit/ImportExport/MDL/utMDLImporter_HL1_Nodes.cpp @@ -3,7 +3,7 @@ Open Asset Import Library (assimp) --------------------------------------------------------------------------- -Copyright (c) 2006-2022, assimp team +Copyright (c) 2006-2024, assimp team All rights reserved. diff --git a/test/unit/ImportExport/RAW/utRAWImportExport.cpp b/test/unit/ImportExport/RAW/utRAWImportExport.cpp index bdd7f8533..9981ed2f7 100644 --- a/test/unit/ImportExport/RAW/utRAWImportExport.cpp +++ b/test/unit/ImportExport/RAW/utRAWImportExport.cpp @@ -3,7 +3,7 @@ Open Asset Import Library (assimp) --------------------------------------------------------------------------- -Copyright (c) 2006-2022, assimp team +Copyright (c) 2006-2024, assimp team All rights reserved. diff --git a/test/unit/ImportExport/Terragen/utTerragenImportExport.cpp b/test/unit/ImportExport/Terragen/utTerragenImportExport.cpp index 8ec20e0c0..1ddde44a6 100644 --- a/test/unit/ImportExport/Terragen/utTerragenImportExport.cpp +++ b/test/unit/ImportExport/Terragen/utTerragenImportExport.cpp @@ -3,7 +3,7 @@ Open Asset Import Library (assimp) --------------------------------------------------------------------------- -Copyright (c) 2006-2022, assimp team +Copyright (c) 2006-2024, assimp team All rights reserved. diff --git a/test/unit/ImportExport/utAssjsonImportExport.cpp b/test/unit/ImportExport/utAssjsonImportExport.cpp index 3470874b5..c32b0f160 100644 --- a/test/unit/ImportExport/utAssjsonImportExport.cpp +++ b/test/unit/ImportExport/utAssjsonImportExport.cpp @@ -3,7 +3,7 @@ Open Asset Import Library (assimp) --------------------------------------------------------------------------- -Copyright (c) 2006-2022, assimp team +Copyright (c) 2006-2024, assimp team All rights reserved. diff --git a/test/unit/ImportExport/utCOBImportExport.cpp b/test/unit/ImportExport/utCOBImportExport.cpp index 187f16ede..705cda38d 100644 --- a/test/unit/ImportExport/utCOBImportExport.cpp +++ b/test/unit/ImportExport/utCOBImportExport.cpp @@ -3,7 +3,7 @@ Open Asset Import Library (assimp) --------------------------------------------------------------------------- -Copyright (c) 2006-2022, assimp team +Copyright (c) 2006-2024, assimp team All rights reserved. diff --git a/test/unit/ImportExport/utExporter.cpp b/test/unit/ImportExport/utExporter.cpp index 096a5c49d..d94f179ed 100644 --- a/test/unit/ImportExport/utExporter.cpp +++ b/test/unit/ImportExport/utExporter.cpp @@ -3,7 +3,7 @@ Open Asset Import Library (assimp) --------------------------------------------------------------------------- -Copyright (c) 2006-2022, assimp team +Copyright (c) 2006-2024, assimp team All rights reserved. diff --git a/test/unit/ImportExport/utMD2Importer.cpp b/test/unit/ImportExport/utMD2Importer.cpp index 0fcf76bfc..975b8f641 100644 --- a/test/unit/ImportExport/utMD2Importer.cpp +++ b/test/unit/ImportExport/utMD2Importer.cpp @@ -3,7 +3,7 @@ Open Asset Import Library (assimp) --------------------------------------------------------------------------- -Copyright (c) 2006-2022, assimp team +Copyright (c) 2006-2024, assimp team All rights reserved. diff --git a/test/unit/ImportExport/utMD5Importer.cpp b/test/unit/ImportExport/utMD5Importer.cpp index 082121937..6fe558565 100644 --- a/test/unit/ImportExport/utMD5Importer.cpp +++ b/test/unit/ImportExport/utMD5Importer.cpp @@ -3,7 +3,7 @@ Open Asset Import Library (assimp) --------------------------------------------------------------------------- -Copyright (c) 2006-2022, assimp team +Copyright (c) 2006-2024, assimp team All rights reserved. diff --git a/test/unit/ImportExport/utMDLImporter.cpp b/test/unit/ImportExport/utMDLImporter.cpp index c8960601d..43cdf9a1d 100644 --- a/test/unit/ImportExport/utMDLImporter.cpp +++ b/test/unit/ImportExport/utMDLImporter.cpp @@ -3,7 +3,7 @@ Open Asset Import Library (assimp) --------------------------------------------------------------------------- -Copyright (c) 2006-2022, assimp team +Copyright (c) 2006-2024, assimp team All rights reserved. diff --git a/test/unit/ImportExport/utNFFImportExport.cpp b/test/unit/ImportExport/utNFFImportExport.cpp index 621324a85..b989578f5 100644 --- a/test/unit/ImportExport/utNFFImportExport.cpp +++ b/test/unit/ImportExport/utNFFImportExport.cpp @@ -3,7 +3,7 @@ Open Asset Import Library (assimp) --------------------------------------------------------------------------- -Copyright (c) 2006-2022, assimp team +Copyright (c) 2006-2024, assimp team All rights reserved. diff --git a/test/unit/ImportExport/utOFFImportExport.cpp b/test/unit/ImportExport/utOFFImportExport.cpp index 78ae4acc4..abd1fe154 100644 --- a/test/unit/ImportExport/utOFFImportExport.cpp +++ b/test/unit/ImportExport/utOFFImportExport.cpp @@ -3,7 +3,7 @@ Open Asset Import Library (assimp) --------------------------------------------------------------------------- -Copyright (c) 2006-2022, assimp team +Copyright (c) 2006-2024, assimp team All rights reserved. diff --git a/test/unit/ImportExport/utOgreImportExport.cpp b/test/unit/ImportExport/utOgreImportExport.cpp index 7312d6b58..d3234c036 100644 --- a/test/unit/ImportExport/utOgreImportExport.cpp +++ b/test/unit/ImportExport/utOgreImportExport.cpp @@ -3,7 +3,7 @@ Open Asset Import Library (assimp) --------------------------------------------------------------------------- -Copyright (c) 2006-2022, assimp team +Copyright (c) 2006-2024, assimp team All rights reserved. diff --git a/test/unit/ImportExport/utQ3BSPFileImportExport.cpp b/test/unit/ImportExport/utQ3BSPFileImportExport.cpp index f5694d2ee..d8738eff7 100644 --- a/test/unit/ImportExport/utQ3BSPFileImportExport.cpp +++ b/test/unit/ImportExport/utQ3BSPFileImportExport.cpp @@ -3,7 +3,7 @@ Open Asset Import Library (assimp) --------------------------------------------------------------------------- -Copyright (c) 2006-2022, assimp team +Copyright (c) 2006-2024, assimp team All rights reserved. diff --git a/test/unit/ImportExport/utXGLImportExport.cpp b/test/unit/ImportExport/utXGLImportExport.cpp index 8199806cc..080290e1d 100644 --- a/test/unit/ImportExport/utXGLImportExport.cpp +++ b/test/unit/ImportExport/utXGLImportExport.cpp @@ -3,7 +3,7 @@ Open Asset Import Library (assimp) --------------------------------------------------------------------------- -Copyright (c) 2006-2022, assimp team +Copyright (c) 2006-2024, assimp team All rights reserved. diff --git a/test/unit/MathTest.cpp b/test/unit/MathTest.cpp index 86a5d7e0f..6069df22e 100644 --- a/test/unit/MathTest.cpp +++ b/test/unit/MathTest.cpp @@ -3,7 +3,7 @@ Open Asset Import Library (assimp) --------------------------------------------------------------------------- -Copyright (c) 2006-2022, assimp team +Copyright (c) 2006-2024, assimp team All rights reserved. diff --git a/test/unit/MathTest.h b/test/unit/MathTest.h index 08411e82f..a09024370 100644 --- a/test/unit/MathTest.h +++ b/test/unit/MathTest.h @@ -3,7 +3,7 @@ Open Asset Import Library (assimp) --------------------------------------------------------------------------- -Copyright (c) 2006-2022, assimp team +Copyright (c) 2006-2024, assimp team diff --git a/test/unit/RandomNumberGeneration.h b/test/unit/RandomNumberGeneration.h index 95ba5b43b..0383332e4 100644 --- a/test/unit/RandomNumberGeneration.h +++ b/test/unit/RandomNumberGeneration.h @@ -3,7 +3,7 @@ Open Asset Import Library (assimp) --------------------------------------------------------------------------- -Copyright (c) 2006-2022, assimp team +Copyright (c) 2006-2024, assimp team All rights reserved. diff --git a/test/unit/SceneDiffer.cpp b/test/unit/SceneDiffer.cpp index a7132496a..6cbc33dde 100644 --- a/test/unit/SceneDiffer.cpp +++ b/test/unit/SceneDiffer.cpp @@ -3,7 +3,7 @@ Open Asset Import Library (assimp) --------------------------------------------------------------------------- -Copyright (c) 2006-2022, assimp team +Copyright (c) 2006-2024, assimp team diff --git a/test/unit/SceneDiffer.h b/test/unit/SceneDiffer.h index 2ac429b76..06065bd5f 100644 --- a/test/unit/SceneDiffer.h +++ b/test/unit/SceneDiffer.h @@ -3,7 +3,7 @@ Open Asset Import Library (assimp) --------------------------------------------------------------------------- -Copyright (c) 2006-2022, assimp team +Copyright (c) 2006-2024, assimp team diff --git a/test/unit/TestIOSystem.h b/test/unit/TestIOSystem.h index fe2455e52..8791f9b92 100644 --- a/test/unit/TestIOSystem.h +++ b/test/unit/TestIOSystem.h @@ -3,7 +3,7 @@ Open Asset Import Library (assimp) --------------------------------------------------------------------------- -Copyright (c) 2006-2022, assimp team +Copyright (c) 2006-2024, assimp team All rights reserved. diff --git a/test/unit/TestModelFactory.h b/test/unit/TestModelFactory.h index c938af0fd..2ddf37e3e 100644 --- a/test/unit/TestModelFactory.h +++ b/test/unit/TestModelFactory.h @@ -3,7 +3,7 @@ Open Asset Import Library (assimp) --------------------------------------------------------------------------- -Copyright (c) 2006-2022, assimp team +Copyright (c) 2006-2024, assimp team diff --git a/test/unit/UTLogStream.h b/test/unit/UTLogStream.h index 6e5d75762..d35de8bdc 100644 --- a/test/unit/UTLogStream.h +++ b/test/unit/UTLogStream.h @@ -3,7 +3,7 @@ Open Asset Import Library (assimp) --------------------------------------------------------------------------- -Copyright (c) 2006-2022, assimp team +Copyright (c) 2006-2024, assimp team All rights reserved. diff --git a/test/unit/ut3DImportExport.cpp b/test/unit/ut3DImportExport.cpp index 32b77ddf8..4cd538c46 100644 --- a/test/unit/ut3DImportExport.cpp +++ b/test/unit/ut3DImportExport.cpp @@ -3,7 +3,7 @@ Open Asset Import Library (assimp) --------------------------------------------------------------------------- -Copyright (c) 2006-2022, assimp team +Copyright (c) 2006-2024, assimp team All rights reserved. diff --git a/test/unit/ut3DSImportExport.cpp b/test/unit/ut3DSImportExport.cpp index 7279227fc..a2da3607c 100644 --- a/test/unit/ut3DSImportExport.cpp +++ b/test/unit/ut3DSImportExport.cpp @@ -3,7 +3,7 @@ Open Asset Import Library (assimp) --------------------------------------------------------------------------- -Copyright (c) 2006-2022, assimp team +Copyright (c) 2006-2024, assimp team All rights reserved. diff --git a/test/unit/utACImportExport.cpp b/test/unit/utACImportExport.cpp index ee22f44f8..4fdb68651 100644 --- a/test/unit/utACImportExport.cpp +++ b/test/unit/utACImportExport.cpp @@ -3,7 +3,7 @@ Open Asset Import Library (assimp) --------------------------------------------------------------------------- -Copyright (c) 2006-2022, assimp team +Copyright (c) 2006-2024, assimp team All rights reserved. diff --git a/test/unit/utAMFImportExport.cpp b/test/unit/utAMFImportExport.cpp index 7319320cf..996614572 100644 --- a/test/unit/utAMFImportExport.cpp +++ b/test/unit/utAMFImportExport.cpp @@ -3,7 +3,7 @@ Open Asset Import Library (assimp) --------------------------------------------------------------------------- -Copyright (c) 2006-2022, assimp team +Copyright (c) 2006-2024, assimp team All rights reserved. diff --git a/test/unit/utASEImportExport.cpp b/test/unit/utASEImportExport.cpp index af05a2fe5..e2d1bfa59 100644 --- a/test/unit/utASEImportExport.cpp +++ b/test/unit/utASEImportExport.cpp @@ -3,7 +3,7 @@ Open Asset Import Library (assimp) --------------------------------------------------------------------------- -Copyright (c) 2006-2022, assimp team +Copyright (c) 2006-2024, assimp team All rights reserved. diff --git a/test/unit/utAnim.cpp b/test/unit/utAnim.cpp index 956810d74..613f7f03b 100644 --- a/test/unit/utAnim.cpp +++ b/test/unit/utAnim.cpp @@ -3,7 +3,7 @@ Open Asset Import Library (assimp) --------------------------------------------------------------------------- -Copyright (c) 2006-2022, assimp team +Copyright (c) 2006-2024, assimp team All rights reserved. diff --git a/test/unit/utArmaturePopulate.cpp b/test/unit/utArmaturePopulate.cpp index 0acea7b50..9f4545c6a 100644 --- a/test/unit/utArmaturePopulate.cpp +++ b/test/unit/utArmaturePopulate.cpp @@ -3,7 +3,7 @@ Open Asset Import Library (assimp) --------------------------------------------------------------------------- -Copyright (c) 2006-2022, assimp team +Copyright (c) 2006-2024, assimp team All rights reserved. diff --git a/test/unit/utAssbinImportExport.cpp b/test/unit/utAssbinImportExport.cpp index 437a0a5fe..5eb2f56bd 100644 --- a/test/unit/utAssbinImportExport.cpp +++ b/test/unit/utAssbinImportExport.cpp @@ -3,7 +3,7 @@ Open Asset Import Library (assimp) --------------------------------------------------------------------------- -Copyright (c) 2006-2022, assimp team +Copyright (c) 2006-2024, assimp team All rights reserved. diff --git a/test/unit/utB3DImportExport.cpp b/test/unit/utB3DImportExport.cpp index 9672aa01b..76017f66c 100644 --- a/test/unit/utB3DImportExport.cpp +++ b/test/unit/utB3DImportExport.cpp @@ -3,7 +3,7 @@ Open Asset Import Library (assimp) --------------------------------------------------------------------------- -Copyright (c) 2006-2022, assimp team +Copyright (c) 2006-2024, assimp team All rights reserved. diff --git a/test/unit/utBVHImportExport.cpp b/test/unit/utBVHImportExport.cpp index 5a0ff1e10..94636c7bf 100644 --- a/test/unit/utBVHImportExport.cpp +++ b/test/unit/utBVHImportExport.cpp @@ -3,7 +3,7 @@ Open Asset Import Library (assimp) --------------------------------------------------------------------------- -Copyright (c) 2006-2022, assimp team +Copyright (c) 2006-2024, assimp team All rights reserved. diff --git a/test/unit/utBatchLoader.cpp b/test/unit/utBatchLoader.cpp index df6aa7995..be1ac30ad 100644 --- a/test/unit/utBatchLoader.cpp +++ b/test/unit/utBatchLoader.cpp @@ -3,7 +3,7 @@ Open Asset Import Library (assimp) --------------------------------------------------------------------------- -Copyright (c) 2006-2022, assimp team +Copyright (c) 2006-2024, assimp team diff --git a/test/unit/utBlendImportAreaLight.cpp b/test/unit/utBlendImportAreaLight.cpp index 470d80737..cc6e1e1a0 100644 --- a/test/unit/utBlendImportAreaLight.cpp +++ b/test/unit/utBlendImportAreaLight.cpp @@ -3,7 +3,7 @@ Open Asset Import Library (assimp) --------------------------------------------------------------------------- -Copyright (c) 2006-2022, assimp team +Copyright (c) 2006-2024, assimp team All rights reserved. diff --git a/test/unit/utBlendImportMaterials.cpp b/test/unit/utBlendImportMaterials.cpp index 11499cc18..416fb3236 100644 --- a/test/unit/utBlendImportMaterials.cpp +++ b/test/unit/utBlendImportMaterials.cpp @@ -3,7 +3,7 @@ Open Asset Import Library (assimp) --------------------------------------------------------------------------- -Copyright (c) 2006-2022, assimp team +Copyright (c) 2006-2024, assimp team All rights reserved. diff --git a/test/unit/utBlenderImportExport.cpp b/test/unit/utBlenderImportExport.cpp index c220b7daa..0eda7b661 100644 --- a/test/unit/utBlenderImportExport.cpp +++ b/test/unit/utBlenderImportExport.cpp @@ -3,7 +3,7 @@ Open Asset Import Library (assimp) --------------------------------------------------------------------------- -Copyright (c) 2006-2022, assimp team +Copyright (c) 2006-2024, assimp team diff --git a/test/unit/utBlenderIntermediate.cpp b/test/unit/utBlenderIntermediate.cpp index c2cc51e8d..b76c48b44 100644 --- a/test/unit/utBlenderIntermediate.cpp +++ b/test/unit/utBlenderIntermediate.cpp @@ -3,7 +3,7 @@ Open Asset Import Library (assimp) --------------------------------------------------------------------------- -Copyright (c) 2006-2022, assimp team +Copyright (c) 2006-2024, assimp team diff --git a/test/unit/utBlenderWork.cpp b/test/unit/utBlenderWork.cpp index 977877250..2ba6329ca 100644 --- a/test/unit/utBlenderWork.cpp +++ b/test/unit/utBlenderWork.cpp @@ -3,7 +3,7 @@ Open Asset Import Library (assimp) --------------------------------------------------------------------------- -Copyright (c) 2006-2022, assimp team +Copyright (c) 2006-2024, assimp team All rights reserved. diff --git a/test/unit/utCSMImportExport.cpp b/test/unit/utCSMImportExport.cpp index 13bfd52bc..8ef14e282 100644 --- a/test/unit/utCSMImportExport.cpp +++ b/test/unit/utCSMImportExport.cpp @@ -3,7 +3,7 @@ Open Asset Import Library (assimp) --------------------------------------------------------------------------- -Copyright (c) 2006-2022, assimp team +Copyright (c) 2006-2024, assimp team All rights reserved. diff --git a/test/unit/utColladaExport.cpp b/test/unit/utColladaExport.cpp index 0df9312f2..e0a62b338 100644 --- a/test/unit/utColladaExport.cpp +++ b/test/unit/utColladaExport.cpp @@ -3,7 +3,7 @@ Open Asset Import Library (assimp) --------------------------------------------------------------------------- -Copyright (c) 2006-2022, assimp team +Copyright (c) 2006-2024, assimp team All rights reserved. diff --git a/test/unit/utColladaImportExport.cpp b/test/unit/utColladaImportExport.cpp index 52a927b12..4e92c6930 100644 --- a/test/unit/utColladaImportExport.cpp +++ b/test/unit/utColladaImportExport.cpp @@ -3,7 +3,7 @@ Open Asset Import Library (assimp) --------------------------------------------------------------------------- -Copyright (c) 2006-2022, assimp team +Copyright (c) 2006-2024, assimp team All rights reserved. diff --git a/test/unit/utD3MFImportExport.cpp b/test/unit/utD3MFImportExport.cpp index ed290e876..f25b2dcf7 100644 --- a/test/unit/utD3MFImportExport.cpp +++ b/test/unit/utD3MFImportExport.cpp @@ -3,7 +3,7 @@ Open Asset Import Library (assimp) --------------------------------------------------------------------------- -Copyright (c) 2006-2022, assimp team +Copyright (c) 2006-2024, assimp team All rights reserved. diff --git a/test/unit/utDXFImporterExporter.cpp b/test/unit/utDXFImporterExporter.cpp index 53c5328e4..ee0c57db6 100644 --- a/test/unit/utDXFImporterExporter.cpp +++ b/test/unit/utDXFImporterExporter.cpp @@ -3,7 +3,7 @@ Open Asset Import Library (assimp) --------------------------------------------------------------------------- -Copyright (c) 2006-2022, assimp team +Copyright (c) 2006-2024, assimp team All rights reserved. diff --git a/test/unit/utDefaultIOStream.cpp b/test/unit/utDefaultIOStream.cpp index 803c6f6f6..2a2d7a894 100644 --- a/test/unit/utDefaultIOStream.cpp +++ b/test/unit/utDefaultIOStream.cpp @@ -2,7 +2,7 @@ Open Asset Import Library (assimp) --------------------------------------------------------------------------- -Copyright (c) 2006-2022, assimp team +Copyright (c) 2006-2024, assimp team diff --git a/test/unit/utExport.cpp b/test/unit/utExport.cpp index cb7826bfc..ebb664fa4 100644 --- a/test/unit/utExport.cpp +++ b/test/unit/utExport.cpp @@ -3,7 +3,7 @@ Open Asset Import Library (assimp) --------------------------------------------------------------------------- -Copyright (c) 2006-2022, assimp team +Copyright (c) 2006-2024, assimp team All rights reserved. diff --git a/test/unit/utFBXImporterExporter.cpp b/test/unit/utFBXImporterExporter.cpp index 9fa293aaf..5cc40d216 100644 --- a/test/unit/utFBXImporterExporter.cpp +++ b/test/unit/utFBXImporterExporter.cpp @@ -3,7 +3,7 @@ Open Asset Import Library (assimp) --------------------------------------------------------------------------- -Copyright (c) 2006-2022, assimp team +Copyright (c) 2006-2024, assimp team All rights reserved. diff --git a/test/unit/utFastAtof.cpp b/test/unit/utFastAtof.cpp index cc25482d2..50c26ca03 100644 --- a/test/unit/utFastAtof.cpp +++ b/test/unit/utFastAtof.cpp @@ -3,7 +3,7 @@ Open Asset Import Library (assimp) --------------------------------------------------------------------------- -Copyright (c) 2006-2022, assimp team +Copyright (c) 2006-2024, assimp team diff --git a/test/unit/utFindDegenerates.cpp b/test/unit/utFindDegenerates.cpp index 5eadc032c..04f554716 100644 --- a/test/unit/utFindDegenerates.cpp +++ b/test/unit/utFindDegenerates.cpp @@ -3,7 +3,7 @@ Open Asset Import Library (assimp) --------------------------------------------------------------------------- -Copyright (c) 2006-2022, assimp team +Copyright (c) 2006-2024, assimp team All rights reserved. diff --git a/test/unit/utFindInvalidData.cpp b/test/unit/utFindInvalidData.cpp index b995b951b..ab845b35e 100644 --- a/test/unit/utFindInvalidData.cpp +++ b/test/unit/utFindInvalidData.cpp @@ -3,7 +3,7 @@ Open Asset Import Library (assimp) --------------------------------------------------------------------------- -Copyright (c) 2006-2022, assimp team +Copyright (c) 2006-2024, assimp team All rights reserved. diff --git a/test/unit/utFixInfacingNormals.cpp b/test/unit/utFixInfacingNormals.cpp index 8f75dd2f0..54fef7b59 100644 --- a/test/unit/utFixInfacingNormals.cpp +++ b/test/unit/utFixInfacingNormals.cpp @@ -3,7 +3,7 @@ Open Asset Import Library (assimp) --------------------------------------------------------------------------- -Copyright (c) 2006-2022, assimp team +Copyright (c) 2006-2024, assimp team diff --git a/test/unit/utGenBoundingBoxesProcess.cpp b/test/unit/utGenBoundingBoxesProcess.cpp index c512e7f80..18b15c31e 100644 --- a/test/unit/utGenBoundingBoxesProcess.cpp +++ b/test/unit/utGenBoundingBoxesProcess.cpp @@ -3,7 +3,7 @@ Open Asset Import Library (assimp) --------------------------------------------------------------------------- -Copyright (c) 2006-2022, assimp team +Copyright (c) 2006-2024, assimp team All rights reserved. diff --git a/test/unit/utGenNormals.cpp b/test/unit/utGenNormals.cpp index 92d477dbf..4a1db0216 100644 --- a/test/unit/utGenNormals.cpp +++ b/test/unit/utGenNormals.cpp @@ -3,7 +3,7 @@ Open Asset Import Library (assimp) --------------------------------------------------------------------------- -Copyright (c) 2006-2022, assimp team +Copyright (c) 2006-2024, assimp team All rights reserved. diff --git a/test/unit/utHMPImportExport.cpp b/test/unit/utHMPImportExport.cpp index 83e7ba09d..8171bb26a 100644 --- a/test/unit/utHMPImportExport.cpp +++ b/test/unit/utHMPImportExport.cpp @@ -3,7 +3,7 @@ Open Asset Import Library (assimp) --------------------------------------------------------------------------- -Copyright (c) 2006-2022, assimp team +Copyright (c) 2006-2024, assimp team All rights reserved. diff --git a/test/unit/utIFCImportExport.cpp b/test/unit/utIFCImportExport.cpp index 49c7446c7..06009be2b 100644 --- a/test/unit/utIFCImportExport.cpp +++ b/test/unit/utIFCImportExport.cpp @@ -3,7 +3,7 @@ Open Asset Import Library (assimp) --------------------------------------------------------------------------- -Copyright (c) 2006-2022, assimp team +Copyright (c) 2006-2024, assimp team All rights reserved. diff --git a/test/unit/utIOStreamBuffer.cpp b/test/unit/utIOStreamBuffer.cpp index 7565014c1..381716040 100644 --- a/test/unit/utIOStreamBuffer.cpp +++ b/test/unit/utIOStreamBuffer.cpp @@ -3,7 +3,7 @@ Open Asset Import Library (assimp) --------------------------------------------------------------------------- -Copyright (c) 2006-2022, assimp team +Copyright (c) 2006-2024, assimp team diff --git a/test/unit/utIOSystem.cpp b/test/unit/utIOSystem.cpp index d69e645fe..5bc9996b0 100644 --- a/test/unit/utIOSystem.cpp +++ b/test/unit/utIOSystem.cpp @@ -3,7 +3,7 @@ Open Asset Import Library (assimp) --------------------------------------------------------------------------- -Copyright (c) 2006-2022, assimp team +Copyright (c) 2006-2024, assimp team diff --git a/test/unit/utImporter.cpp b/test/unit/utImporter.cpp index 5ecc45e34..2470283c0 100644 --- a/test/unit/utImporter.cpp +++ b/test/unit/utImporter.cpp @@ -3,7 +3,7 @@ Open Asset Import Library (assimp) --------------------------------------------------------------------------- -Copyright (c) 2006-2022, assimp team +Copyright (c) 2006-2024, assimp team All rights reserved. diff --git a/test/unit/utImproveCacheLocality.cpp b/test/unit/utImproveCacheLocality.cpp index 0e97eb0c7..269721eda 100644 --- a/test/unit/utImproveCacheLocality.cpp +++ b/test/unit/utImproveCacheLocality.cpp @@ -3,7 +3,7 @@ Open Asset Import Library (assimp) --------------------------------------------------------------------------- -Copyright (c) 2006-2022, assimp team +Copyright (c) 2006-2024, assimp team All rights reserved. diff --git a/test/unit/utIssues.cpp b/test/unit/utIssues.cpp index 546c36ad0..4a3fa1585 100644 --- a/test/unit/utIssues.cpp +++ b/test/unit/utIssues.cpp @@ -3,7 +3,7 @@ Open Asset Import Library (assimp) --------------------------------------------------------------------------- -Copyright (c) 2006-2022, assimp team +Copyright (c) 2006-2024, assimp team diff --git a/test/unit/utJoinVertices.cpp b/test/unit/utJoinVertices.cpp index b0700900c..9dbe87536 100644 --- a/test/unit/utJoinVertices.cpp +++ b/test/unit/utJoinVertices.cpp @@ -3,7 +3,7 @@ Open Asset Import Library (assimp) --------------------------------------------------------------------------- -Copyright (c) 2006-2022, assimp team +Copyright (c) 2006-2024, assimp team All rights reserved. diff --git a/test/unit/utLWOImportExport.cpp b/test/unit/utLWOImportExport.cpp index 2ab1c4722..78572a7db 100644 --- a/test/unit/utLWOImportExport.cpp +++ b/test/unit/utLWOImportExport.cpp @@ -3,7 +3,7 @@ Open Asset Import Library (assimp) --------------------------------------------------------------------------- -Copyright (c) 2006-2022, assimp team +Copyright (c) 2006-2024, assimp team All rights reserved. diff --git a/test/unit/utLWSImportExport.cpp b/test/unit/utLWSImportExport.cpp index 730911ec2..3f9c62361 100644 --- a/test/unit/utLWSImportExport.cpp +++ b/test/unit/utLWSImportExport.cpp @@ -3,7 +3,7 @@ Open Asset Import Library (assimp) --------------------------------------------------------------------------- -Copyright (c) 2006-2022, assimp team +Copyright (c) 2006-2024, assimp team All rights reserved. diff --git a/test/unit/utLimitBoneWeights.cpp b/test/unit/utLimitBoneWeights.cpp index bf3ea93f5..5a543aa2b 100644 --- a/test/unit/utLimitBoneWeights.cpp +++ b/test/unit/utLimitBoneWeights.cpp @@ -3,7 +3,7 @@ Open Asset Import Library (assimp) --------------------------------------------------------------------------- -Copyright (c) 2006-2022, assimp team +Copyright (c) 2006-2024, assimp team All rights reserved. diff --git a/test/unit/utMDCImportExport.cpp b/test/unit/utMDCImportExport.cpp index 29b9ed56c..d5b8dee0b 100644 --- a/test/unit/utMDCImportExport.cpp +++ b/test/unit/utMDCImportExport.cpp @@ -3,7 +3,7 @@ Open Asset Import Library (assimp) --------------------------------------------------------------------------- -Copyright (c) 2006-2022, assimp team +Copyright (c) 2006-2024, assimp team All rights reserved. diff --git a/test/unit/utMaterialSystem.cpp b/test/unit/utMaterialSystem.cpp index a84ae8333..8b1691b3f 100644 --- a/test/unit/utMaterialSystem.cpp +++ b/test/unit/utMaterialSystem.cpp @@ -3,7 +3,7 @@ Open Asset Import Library (assimp) --------------------------------------------------------------------------- -Copyright (c) 2006-2022, assimp team +Copyright (c) 2006-2024, assimp team All rights reserved. diff --git a/test/unit/utMatrix3x3.cpp b/test/unit/utMatrix3x3.cpp index ae722a811..54bbece7d 100644 --- a/test/unit/utMatrix3x3.cpp +++ b/test/unit/utMatrix3x3.cpp @@ -3,7 +3,7 @@ Open Asset Import Library (assimp) --------------------------------------------------------------------------- -Copyright (c) 2006-2022, assimp team +Copyright (c) 2006-2024, assimp team All rights reserved. diff --git a/test/unit/utMatrix4x4.cpp b/test/unit/utMatrix4x4.cpp index 86a70bfe4..510900e82 100644 --- a/test/unit/utMatrix4x4.cpp +++ b/test/unit/utMatrix4x4.cpp @@ -3,7 +3,7 @@ Open Asset Import Library (assimp) --------------------------------------------------------------------------- -Copyright (c) 2006-2022, assimp team +Copyright (c) 2006-2024, assimp team All rights reserved. diff --git a/test/unit/utMetadata.cpp b/test/unit/utMetadata.cpp index 676404c3c..e7cd239aa 100644 --- a/test/unit/utMetadata.cpp +++ b/test/unit/utMetadata.cpp @@ -3,7 +3,7 @@ Open Asset Import Library (assimp) --------------------------------------------------------------------------- -Copyright (c) 2006-2022, assimp team +Copyright (c) 2006-2024, assimp team All rights reserved. diff --git a/test/unit/utObjImportExport.cpp b/test/unit/utObjImportExport.cpp index ce778a950..8e9b4e633 100644 --- a/test/unit/utObjImportExport.cpp +++ b/test/unit/utObjImportExport.cpp @@ -3,7 +3,7 @@ Open Asset Import Library (assimp) --------------------------------------------------------------------------- -Copyright (c) 2006-2022, assimp team +Copyright (c) 2006-2024, assimp team All rights reserved. diff --git a/test/unit/utObjTools.cpp b/test/unit/utObjTools.cpp index f2e5304ad..f1437ff32 100644 --- a/test/unit/utObjTools.cpp +++ b/test/unit/utObjTools.cpp @@ -3,7 +3,7 @@ Open Asset Import Library (assimp) --------------------------------------------------------------------------- -Copyright (c) 2006-2022, assimp team +Copyright (c) 2006-2024, assimp team All rights reserved. diff --git a/test/unit/utOpenGEXImportExport.cpp b/test/unit/utOpenGEXImportExport.cpp index ed22a6fb7..51da9e237 100644 --- a/test/unit/utOpenGEXImportExport.cpp +++ b/test/unit/utOpenGEXImportExport.cpp @@ -3,7 +3,7 @@ Open Asset Import Library (assimp) --------------------------------------------------------------------------- -Copyright (c) 2006-2022, assimp team +Copyright (c) 2006-2024, assimp team All rights reserved. diff --git a/test/unit/utPLYImportExport.cpp b/test/unit/utPLYImportExport.cpp index 13c90fc47..e748a40cf 100644 --- a/test/unit/utPLYImportExport.cpp +++ b/test/unit/utPLYImportExport.cpp @@ -3,7 +3,7 @@ Open Asset Import Library (assimp) --------------------------------------------------------------------------- -Copyright (c) 2006-2022, assimp team +Copyright (c) 2006-2024, assimp team All rights reserved. diff --git a/test/unit/utPMXImporter.cpp b/test/unit/utPMXImporter.cpp index 167fb234a..a5aba923b 100644 --- a/test/unit/utPMXImporter.cpp +++ b/test/unit/utPMXImporter.cpp @@ -3,7 +3,7 @@ Open Asset Import Library (assimp) --------------------------------------------------------------------------- -Copyright (c) 2006-2022, assimp team +Copyright (c) 2006-2024, assimp team All rights reserved. diff --git a/test/unit/utPretransformVertices.cpp b/test/unit/utPretransformVertices.cpp index b3ae818bc..9652ec611 100644 --- a/test/unit/utPretransformVertices.cpp +++ b/test/unit/utPretransformVertices.cpp @@ -3,7 +3,7 @@ Open Asset Import Library (assimp) --------------------------------------------------------------------------- -Copyright (c) 2006-2022, assimp team +Copyright (c) 2006-2024, assimp team All rights reserved. diff --git a/test/unit/utProfiler.cpp b/test/unit/utProfiler.cpp index 6738d568e..a9a54a934 100644 --- a/test/unit/utProfiler.cpp +++ b/test/unit/utProfiler.cpp @@ -3,7 +3,7 @@ Open Asset Import Library (assimp) --------------------------------------------------------------------------- -Copyright (c) 2006-2022, assimp team +Copyright (c) 2006-2024, assimp team diff --git a/test/unit/utQ3DImportExport.cpp b/test/unit/utQ3DImportExport.cpp index e5396a680..4fb71bb69 100644 --- a/test/unit/utQ3DImportExport.cpp +++ b/test/unit/utQ3DImportExport.cpp @@ -3,7 +3,7 @@ Open Asset Import Library (assimp) --------------------------------------------------------------------------- -Copyright (c) 2006-2022, assimp team +Copyright (c) 2006-2024, assimp team All rights reserved. diff --git a/test/unit/utRemoveComments.cpp b/test/unit/utRemoveComments.cpp index 44fb56ef8..f101b7d9e 100644 --- a/test/unit/utRemoveComments.cpp +++ b/test/unit/utRemoveComments.cpp @@ -3,7 +3,7 @@ Open Asset Import Library (assimp) --------------------------------------------------------------------------- -Copyright (c) 2006-2022, assimp team +Copyright (c) 2006-2024, assimp team All rights reserved. diff --git a/test/unit/utRemoveComponent.cpp b/test/unit/utRemoveComponent.cpp index dd9e4f9cb..5fbfe612c 100644 --- a/test/unit/utRemoveComponent.cpp +++ b/test/unit/utRemoveComponent.cpp @@ -3,7 +3,7 @@ Open Asset Import Library (assimp) --------------------------------------------------------------------------- -Copyright (c) 2006-2022, assimp team +Copyright (c) 2006-2024, assimp team All rights reserved. diff --git a/test/unit/utRemoveRedundantMaterials.cpp b/test/unit/utRemoveRedundantMaterials.cpp index 99b91aa5f..5c9983859 100644 --- a/test/unit/utRemoveRedundantMaterials.cpp +++ b/test/unit/utRemoveRedundantMaterials.cpp @@ -3,7 +3,7 @@ Open Asset Import Library (assimp) --------------------------------------------------------------------------- -Copyright (c) 2006-2022, assimp team +Copyright (c) 2006-2024, assimp team All rights reserved. diff --git a/test/unit/utRemoveVCProcess.cpp b/test/unit/utRemoveVCProcess.cpp index b555b0c86..fdb4049b9 100644 --- a/test/unit/utRemoveVCProcess.cpp +++ b/test/unit/utRemoveVCProcess.cpp @@ -3,7 +3,7 @@ Open Asset Import Library (assimp) --------------------------------------------------------------------------- -Copyright (c) 2006-2022, assimp team +Copyright (c) 2006-2024, assimp team All rights reserved. diff --git a/test/unit/utSIBImporter.cpp b/test/unit/utSIBImporter.cpp index b36e0883f..e2deb85c2 100644 --- a/test/unit/utSIBImporter.cpp +++ b/test/unit/utSIBImporter.cpp @@ -3,7 +3,7 @@ Open Asset Import Library (assimp) --------------------------------------------------------------------------- -Copyright (c) 2006-2022, assimp team +Copyright (c) 2006-2024, assimp team All rights reserved. diff --git a/test/unit/utSMDImportExport.cpp b/test/unit/utSMDImportExport.cpp index 08683d554..6e2bc08e7 100644 --- a/test/unit/utSMDImportExport.cpp +++ b/test/unit/utSMDImportExport.cpp @@ -3,7 +3,7 @@ Open Asset Import Library (assimp) --------------------------------------------------------------------------- -Copyright (c) 2006-2022, assimp team +Copyright (c) 2006-2024, assimp team All rights reserved. diff --git a/test/unit/utSTLImportExport.cpp b/test/unit/utSTLImportExport.cpp index 4bf374a1b..7e2c29168 100644 --- a/test/unit/utSTLImportExport.cpp +++ b/test/unit/utSTLImportExport.cpp @@ -3,7 +3,7 @@ Open Asset Import Library (assimp) --------------------------------------------------------------------------- -Copyright (c) 2006-2022, assimp team +Copyright (c) 2006-2024, assimp team All rights reserved. diff --git a/test/unit/utScaleProcess.cpp b/test/unit/utScaleProcess.cpp index baa13ab52..5772d4883 100644 --- a/test/unit/utScaleProcess.cpp +++ b/test/unit/utScaleProcess.cpp @@ -3,7 +3,7 @@ Open Asset Import Library (assimp) --------------------------------------------------------------------------- -Copyright (c) 2006-2022, assimp team +Copyright (c) 2006-2024, assimp team All rights reserved. diff --git a/test/unit/utSceneCombiner.cpp b/test/unit/utSceneCombiner.cpp index d837e4dce..055b54f5b 100644 --- a/test/unit/utSceneCombiner.cpp +++ b/test/unit/utSceneCombiner.cpp @@ -3,7 +3,7 @@ Open Asset Import Library (assimp) --------------------------------------------------------------------------- -Copyright (c) 2006-2022, assimp team +Copyright (c) 2006-2024, assimp team All rights reserved. diff --git a/test/unit/utScenePreprocessor.cpp b/test/unit/utScenePreprocessor.cpp index 45d8a36ee..5e3dd95ce 100644 --- a/test/unit/utScenePreprocessor.cpp +++ b/test/unit/utScenePreprocessor.cpp @@ -3,7 +3,7 @@ Open Asset Import Library (assimp) --------------------------------------------------------------------------- -Copyright (c) 2006-2022, assimp team +Copyright (c) 2006-2024, assimp team All rights reserved. diff --git a/test/unit/utSharedPPData.cpp b/test/unit/utSharedPPData.cpp index 16ee9c75f..f70d352ff 100644 --- a/test/unit/utSharedPPData.cpp +++ b/test/unit/utSharedPPData.cpp @@ -3,7 +3,7 @@ Open Asset Import Library (assimp) --------------------------------------------------------------------------- -Copyright (c) 2006-2022, assimp team +Copyright (c) 2006-2024, assimp team diff --git a/test/unit/utSimd.cpp b/test/unit/utSimd.cpp index 720d657b6..3f073b475 100644 --- a/test/unit/utSimd.cpp +++ b/test/unit/utSimd.cpp @@ -3,7 +3,7 @@ Open Asset Import Library (assimp) --------------------------------------------------------------------------- -Copyright (c) 2006-2022, assimp team +Copyright (c) 2006-2024, assimp team All rights reserved. diff --git a/test/unit/utSortByPType.cpp b/test/unit/utSortByPType.cpp index 5fd360fcc..ff8b717ef 100644 --- a/test/unit/utSortByPType.cpp +++ b/test/unit/utSortByPType.cpp @@ -3,7 +3,7 @@ Open Asset Import Library (assimp) --------------------------------------------------------------------------- -Copyright (c) 2006-2022, assimp team +Copyright (c) 2006-2024, assimp team All rights reserved. diff --git a/test/unit/utSplitLargeMeshes.cpp b/test/unit/utSplitLargeMeshes.cpp index 160831baa..b8bab7193 100644 --- a/test/unit/utSplitLargeMeshes.cpp +++ b/test/unit/utSplitLargeMeshes.cpp @@ -3,7 +3,7 @@ Open Asset Import Library (assimp) --------------------------------------------------------------------------- -Copyright (c) 2006-2022, assimp team +Copyright (c) 2006-2024, assimp team All rights reserved. diff --git a/test/unit/utStringUtils.cpp b/test/unit/utStringUtils.cpp index 9c5ab31f5..7cb11797d 100644 --- a/test/unit/utStringUtils.cpp +++ b/test/unit/utStringUtils.cpp @@ -3,7 +3,7 @@ Open Asset Import Library (assimp) --------------------------------------------------------------------------- -Copyright (c) 2006-2022, assimp team +Copyright (c) 2006-2024, assimp team All rights reserved. diff --git a/test/unit/utTargetAnimation.cpp b/test/unit/utTargetAnimation.cpp index 9cbb45309..2711e895c 100644 --- a/test/unit/utTargetAnimation.cpp +++ b/test/unit/utTargetAnimation.cpp @@ -3,7 +3,7 @@ Open Asset Import Library (assimp) --------------------------------------------------------------------------- -Copyright (c) 2006-2022, assimp team +Copyright (c) 2006-2024, assimp team All rights reserved. diff --git a/test/unit/utTextureTransform.cpp b/test/unit/utTextureTransform.cpp index 9cbb45309..2711e895c 100644 --- a/test/unit/utTextureTransform.cpp +++ b/test/unit/utTextureTransform.cpp @@ -3,7 +3,7 @@ Open Asset Import Library (assimp) --------------------------------------------------------------------------- -Copyright (c) 2006-2022, assimp team +Copyright (c) 2006-2024, assimp team All rights reserved. diff --git a/test/unit/utTriangulate.cpp b/test/unit/utTriangulate.cpp index f51daea63..2df0ce6cd 100644 --- a/test/unit/utTriangulate.cpp +++ b/test/unit/utTriangulate.cpp @@ -3,7 +3,7 @@ Open Asset Import Library (assimp) --------------------------------------------------------------------------- -Copyright (c) 2006-2022, assimp team +Copyright (c) 2006-2024, assimp team All rights reserved. diff --git a/test/unit/utTypes.cpp b/test/unit/utTypes.cpp index 33d2b4f76..45a4b5517 100644 --- a/test/unit/utTypes.cpp +++ b/test/unit/utTypes.cpp @@ -3,7 +3,7 @@ Open Asset Import Library (assimp) --------------------------------------------------------------------------- -Copyright (c) 2006-2022, assimp team +Copyright (c) 2006-2024, assimp team diff --git a/test/unit/utVector3.cpp b/test/unit/utVector3.cpp index 2602c287c..f13521894 100644 --- a/test/unit/utVector3.cpp +++ b/test/unit/utVector3.cpp @@ -2,7 +2,7 @@ Open Asset Import Library (assimp) --------------------------------------------------------------------------- -Copyright (c) 2006-2022, assimp team +Copyright (c) 2006-2024, assimp team All rights reserved. diff --git a/test/unit/utVersion.cpp b/test/unit/utVersion.cpp index e4378e9f6..bba97a135 100644 --- a/test/unit/utVersion.cpp +++ b/test/unit/utVersion.cpp @@ -2,7 +2,7 @@ Open Asset Import Library (assimp) --------------------------------------------------------------------------- -Copyright (c) 2006-2023, assimp team +Copyright (c) 2006-2024, assimp team All rights reserved. diff --git a/test/unit/utVertexTriangleAdjacency.cpp b/test/unit/utVertexTriangleAdjacency.cpp index 8c8d9db04..f5ad492ef 100644 --- a/test/unit/utVertexTriangleAdjacency.cpp +++ b/test/unit/utVertexTriangleAdjacency.cpp @@ -3,7 +3,7 @@ Open Asset Import Library (assimp) --------------------------------------------------------------------------- -Copyright (c) 2006-2022, assimp team +Copyright (c) 2006-2024, assimp team All rights reserved. diff --git a/test/unit/utX3DImportExport.cpp b/test/unit/utX3DImportExport.cpp index a654765de..b0b6802b9 100644 --- a/test/unit/utX3DImportExport.cpp +++ b/test/unit/utX3DImportExport.cpp @@ -3,7 +3,7 @@ Open Asset Import Library (assimp) --------------------------------------------------------------------------- -Copyright (c) 2006-2022, assimp team +Copyright (c) 2006-2024, assimp team All rights reserved. diff --git a/test/unit/utXImporterExporter.cpp b/test/unit/utXImporterExporter.cpp index 4d247cc6f..807e3ca83 100644 --- a/test/unit/utXImporterExporter.cpp +++ b/test/unit/utXImporterExporter.cpp @@ -3,7 +3,7 @@ Open Asset Import Library (assimp) --------------------------------------------------------------------------- -Copyright (c) 2006-2022, assimp team +Copyright (c) 2006-2024, assimp team All rights reserved. diff --git a/test/unit/utglTF2ImportExport.cpp b/test/unit/utglTF2ImportExport.cpp index 478f75666..c29d17d33 100644 --- a/test/unit/utglTF2ImportExport.cpp +++ b/test/unit/utglTF2ImportExport.cpp @@ -3,7 +3,7 @@ Open Asset Import Library (assimp) --------------------------------------------------------------------------- -Copyright (c) 2006-2022, assimp team +Copyright (c) 2006-2024, assimp team All rights reserved. diff --git a/test/unit/utglTFImportExport.cpp b/test/unit/utglTFImportExport.cpp index cb20c1519..9d1cebc54 100644 --- a/test/unit/utglTFImportExport.cpp +++ b/test/unit/utglTFImportExport.cpp @@ -3,7 +3,7 @@ Open Asset Import Library (assimp) --------------------------------------------------------------------------- -Copyright (c) 2006-2022, assimp team +Copyright (c) 2006-2024, assimp team All rights reserved. diff --git a/tools/assimp_cmd/CMakeLists.txt b/tools/assimp_cmd/CMakeLists.txt index 5b80ee77b..2f4486723 100644 --- a/tools/assimp_cmd/CMakeLists.txt +++ b/tools/assimp_cmd/CMakeLists.txt @@ -1,7 +1,7 @@ # Open Asset Import Library (assimp) # ---------------------------------------------------------------------- # -# Copyright (c) 2006-2022, assimp team +# Copyright (c) 2006-2024, assimp team # All rights reserved. # # Redistribution and use of this software in source and binary forms, diff --git a/tools/assimp_cmd/CompareDump.cpp b/tools/assimp_cmd/CompareDump.cpp index 3cf22bb28..5ea162cae 100644 --- a/tools/assimp_cmd/CompareDump.cpp +++ b/tools/assimp_cmd/CompareDump.cpp @@ -3,7 +3,7 @@ Open Asset Import Library (assimp) --------------------------------------------------------------------------- -Copyright (c) 2006-2022, assimp team +Copyright (c) 2006-2024, assimp team diff --git a/tools/assimp_cmd/Export.cpp b/tools/assimp_cmd/Export.cpp index b78db157b..2961bad2c 100644 --- a/tools/assimp_cmd/Export.cpp +++ b/tools/assimp_cmd/Export.cpp @@ -3,7 +3,7 @@ Open Asset Import Library (assimp) --------------------------------------------------------------------------- -Copyright (c) 2006-2022, assimp team +Copyright (c) 2006-2024, assimp team All rights reserved. diff --git a/tools/assimp_cmd/ImageExtractor.cpp b/tools/assimp_cmd/ImageExtractor.cpp index 49edf9790..6469db42b 100644 --- a/tools/assimp_cmd/ImageExtractor.cpp +++ b/tools/assimp_cmd/ImageExtractor.cpp @@ -3,7 +3,7 @@ Open Asset Import Library (assimp) --------------------------------------------------------------------------- -Copyright (c) 2006-2022, assimp team +Copyright (c) 2006-2024, assimp team All rights reserved. diff --git a/tools/assimp_cmd/Info.cpp b/tools/assimp_cmd/Info.cpp index d67974269..18cf1a1c1 100644 --- a/tools/assimp_cmd/Info.cpp +++ b/tools/assimp_cmd/Info.cpp @@ -3,7 +3,7 @@ Open Asset Import Library (assimp) --------------------------------------------------------------------------- -Copyright (c) 2006-2022, assimp team +Copyright (c) 2006-2024, assimp team All rights reserved. diff --git a/tools/assimp_cmd/Main.cpp b/tools/assimp_cmd/Main.cpp index 06c44f029..aa7a137de 100644 --- a/tools/assimp_cmd/Main.cpp +++ b/tools/assimp_cmd/Main.cpp @@ -3,7 +3,7 @@ Open Asset Import Library (assimp) --------------------------------------------------------------------------- -Copyright (c) 2006-2022, assimp team +Copyright (c) 2006-2024, assimp team All rights reserved. diff --git a/tools/assimp_cmd/Main.h b/tools/assimp_cmd/Main.h index a95bc96f6..a3329dd0b 100644 --- a/tools/assimp_cmd/Main.h +++ b/tools/assimp_cmd/Main.h @@ -3,7 +3,7 @@ Open Asset Import Library (assimp) --------------------------------------------------------------------------- -Copyright (c) 2006-2022, assimp team +Copyright (c) 2006-2024, assimp team All rights reserved. diff --git a/tools/assimp_cmd/WriteDump.cpp b/tools/assimp_cmd/WriteDump.cpp index 4ada408fd..d922d7947 100644 --- a/tools/assimp_cmd/WriteDump.cpp +++ b/tools/assimp_cmd/WriteDump.cpp @@ -3,7 +3,7 @@ Open Asset Import Library (assimp) --------------------------------------------------------------------------- -Copyright (c) 2006-2022, assimp team +Copyright (c) 2006-2024, assimp team All rights reserved. diff --git a/tools/assimp_view/AnimEvaluator.cpp b/tools/assimp_view/AnimEvaluator.cpp index 4f8d1bda8..206afb284 100644 --- a/tools/assimp_view/AnimEvaluator.cpp +++ b/tools/assimp_view/AnimEvaluator.cpp @@ -3,7 +3,7 @@ Open Asset Import Library (assimp) --------------------------------------------------------------------------- -Copyright (c) 2006-2022, assimp team +Copyright (c) 2006-2024, assimp team All rights reserved. diff --git a/tools/assimp_view/AnimEvaluator.h b/tools/assimp_view/AnimEvaluator.h index aa44ab211..854b232dd 100644 --- a/tools/assimp_view/AnimEvaluator.h +++ b/tools/assimp_view/AnimEvaluator.h @@ -3,7 +3,7 @@ Open Asset Import Library (assimp) --------------------------------------------------------------------------- -Copyright (c) 2006-2022, assimp team +Copyright (c) 2006-2024, assimp team All rights reserved. diff --git a/tools/assimp_view/AssetHelper.h b/tools/assimp_view/AssetHelper.h index 8661d875f..16648f9c7 100644 --- a/tools/assimp_view/AssetHelper.h +++ b/tools/assimp_view/AssetHelper.h @@ -3,7 +3,7 @@ Open Asset Import Library (assimp) --------------------------------------------------------------------------- -Copyright (c) 2006-2022, assimp team +Copyright (c) 2006-2024, assimp team All rights reserved. diff --git a/tools/assimp_view/Background.cpp b/tools/assimp_view/Background.cpp index e49630204..6943115df 100644 --- a/tools/assimp_view/Background.cpp +++ b/tools/assimp_view/Background.cpp @@ -3,7 +3,7 @@ Open Asset Import Library (assimp) --------------------------------------------------------------------------- -Copyright (c) 2006-2022, assimp team +Copyright (c) 2006-2024, assimp team All rights reserved. diff --git a/tools/assimp_view/CMakeLists.txt b/tools/assimp_view/CMakeLists.txt index a5a9eed35..e8c354fc8 100644 --- a/tools/assimp_view/CMakeLists.txt +++ b/tools/assimp_view/CMakeLists.txt @@ -1,7 +1,7 @@ # Open Asset Import Library (assimp) # ---------------------------------------------------------------------- # -# Copyright (c) 2006-2022, assimp team +# Copyright (c) 2006-2024, assimp team # All rights reserved. diff --git a/tools/assimp_view/Display.cpp b/tools/assimp_view/Display.cpp index 5c2ee8ff5..5020d65ca 100644 --- a/tools/assimp_view/Display.cpp +++ b/tools/assimp_view/Display.cpp @@ -3,7 +3,7 @@ Open Asset Import Library (assimp) --------------------------------------------------------------------------- -Copyright (c) 2006-2022, assimp team +Copyright (c) 2006-2024, assimp team All rights reserved. diff --git a/tools/assimp_view/HelpDialog.cpp b/tools/assimp_view/HelpDialog.cpp index fde4e1caf..700619a6c 100644 --- a/tools/assimp_view/HelpDialog.cpp +++ b/tools/assimp_view/HelpDialog.cpp @@ -3,7 +3,7 @@ Open Asset Import Library (assimp) --------------------------------------------------------------------------- -Copyright (c) 2006-2022, assimp team +Copyright (c) 2006-2024, assimp team All rights reserved. diff --git a/tools/assimp_view/Input.cpp b/tools/assimp_view/Input.cpp index b8572d792..f9bda0451 100644 --- a/tools/assimp_view/Input.cpp +++ b/tools/assimp_view/Input.cpp @@ -3,7 +3,7 @@ Open Asset Import Library (assimp) --------------------------------------------------------------------------- -Copyright (c) 2006-2022, assimp team +Copyright (c) 2006-2024, assimp team All rights reserved. diff --git a/tools/assimp_view/LogDisplay.cpp b/tools/assimp_view/LogDisplay.cpp index 1bd650c08..41777856f 100644 --- a/tools/assimp_view/LogDisplay.cpp +++ b/tools/assimp_view/LogDisplay.cpp @@ -3,7 +3,7 @@ Open Asset Import Library (assimp) --------------------------------------------------------------------------- -Copyright (c) 2006-2022, assimp team +Copyright (c) 2006-2024, assimp team All rights reserved. diff --git a/tools/assimp_view/LogWindow.cpp b/tools/assimp_view/LogWindow.cpp index 8e80bf564..24a359f19 100644 --- a/tools/assimp_view/LogWindow.cpp +++ b/tools/assimp_view/LogWindow.cpp @@ -3,7 +3,7 @@ Open Asset Import Library (assimp) --------------------------------------------------------------------------- -Copyright (c) 2006-2022, assimp team +Copyright (c) 2006-2024, assimp team All rights reserved. diff --git a/tools/assimp_view/Material.cpp b/tools/assimp_view/Material.cpp index c28231332..2337f13fa 100644 --- a/tools/assimp_view/Material.cpp +++ b/tools/assimp_view/Material.cpp @@ -3,7 +3,7 @@ Open Asset Import Library (assimp) --------------------------------------------------------------------------- -Copyright (c) 2006-2022, assimp team +Copyright (c) 2006-2024, assimp team All rights reserved. diff --git a/tools/assimp_view/MaterialManager.h b/tools/assimp_view/MaterialManager.h index b708fb337..577f81a6b 100644 --- a/tools/assimp_view/MaterialManager.h +++ b/tools/assimp_view/MaterialManager.h @@ -3,7 +3,7 @@ Open Asset Import Library (assimp) --------------------------------------------------------------------------- -Copyright (c) 2006-2022, assimp team +Copyright (c) 2006-2024, assimp team All rights reserved. diff --git a/tools/assimp_view/MeshRenderer.cpp b/tools/assimp_view/MeshRenderer.cpp index 655e99d0b..710ce1cce 100644 --- a/tools/assimp_view/MeshRenderer.cpp +++ b/tools/assimp_view/MeshRenderer.cpp @@ -3,7 +3,7 @@ Open Asset Import Library (assimp) --------------------------------------------------------------------------- -Copyright (c) 2006-2022, assimp team +Copyright (c) 2006-2024, assimp team All rights reserved. diff --git a/tools/assimp_view/MessageProc.cpp b/tools/assimp_view/MessageProc.cpp index aea65a8d5..5acdafb68 100644 --- a/tools/assimp_view/MessageProc.cpp +++ b/tools/assimp_view/MessageProc.cpp @@ -3,7 +3,7 @@ Open Asset Import Library (assimp) --------------------------------------------------------------------------- -Copyright (c) 2006-2022, assimp team +Copyright (c) 2006-2024, assimp team All rights reserved. diff --git a/tools/assimp_view/Normals.cpp b/tools/assimp_view/Normals.cpp index b76408939..32c5a486a 100644 --- a/tools/assimp_view/Normals.cpp +++ b/tools/assimp_view/Normals.cpp @@ -3,7 +3,7 @@ Open Asset Import Library (assimp) --------------------------------------------------------------------------- -Copyright (c) 2006-2022, assimp team +Copyright (c) 2006-2024, assimp team All rights reserved. diff --git a/tools/assimp_view/SceneAnimator.cpp b/tools/assimp_view/SceneAnimator.cpp index c8b20229e..f24f2018f 100644 --- a/tools/assimp_view/SceneAnimator.cpp +++ b/tools/assimp_view/SceneAnimator.cpp @@ -3,7 +3,7 @@ Open Asset Import Library (assimp) --------------------------------------------------------------------------- -Copyright (c) 2006-2022, assimp team +Copyright (c) 2006-2024, assimp team All rights reserved. diff --git a/tools/assimp_view/SceneAnimator.h b/tools/assimp_view/SceneAnimator.h index 454357f30..444f71014 100644 --- a/tools/assimp_view/SceneAnimator.h +++ b/tools/assimp_view/SceneAnimator.h @@ -3,7 +3,7 @@ Open Asset Import Library (assimp) --------------------------------------------------------------------------- -Copyright (c) 2006-2022, assimp team +Copyright (c) 2006-2024, assimp team All rights reserved. diff --git a/tools/assimp_view/Shaders.cpp b/tools/assimp_view/Shaders.cpp index 9fd05ca8d..10e89e696 100644 --- a/tools/assimp_view/Shaders.cpp +++ b/tools/assimp_view/Shaders.cpp @@ -3,7 +3,7 @@ Open Asset Import Library (assimp) --------------------------------------------------------------------------- -Copyright (c) 2006-2022, assimp team +Copyright (c) 2006-2024, assimp team All rights reserved. diff --git a/tools/assimp_view/assimp_view.cpp b/tools/assimp_view/assimp_view.cpp index 8f2d131d2..c2c8bfd4a 100644 --- a/tools/assimp_view/assimp_view.cpp +++ b/tools/assimp_view/assimp_view.cpp @@ -3,7 +3,7 @@ Open Asset Import Library (assimp) --------------------------------------------------------------------------- -Copyright (c) 2006-2022, assimp team +Copyright (c) 2006-2024, assimp team All rights reserved. diff --git a/tools/assimp_view/assimp_view.h b/tools/assimp_view/assimp_view.h index e67cc9fd0..f5c08559d 100644 --- a/tools/assimp_view/assimp_view.h +++ b/tools/assimp_view/assimp_view.h @@ -3,7 +3,7 @@ Open Asset Import Library (assimp) --------------------------------------------------------------------------- -Copyright (c) 2006-2022, assimp team +Copyright (c) 2006-2024, assimp team All rights reserved. From f95050e7aab0579dcec3ce0cecb7a8f3555f65b2 Mon Sep 17 00:00:00 2001 From: sSsA01 <59872472+Riv1s-sSsA01@users.noreply.github.com> Date: Wed, 28 Feb 2024 04:26:13 +0900 Subject: [PATCH 49/77] Append a setting "AI_CONFIG_EXPORT_FBX_TRANSPARENCY_FACTOR_REFER_TO_OPACITY". (#5450) Co-authored-by: Kim Kulling --- code/AssetLib/FBX/FBXExporter.cpp | 24 +++++++++++++++++------- include/assimp/config.h.in | 10 ++++++++++ 2 files changed, 27 insertions(+), 7 deletions(-) diff --git a/code/AssetLib/FBX/FBXExporter.cpp b/code/AssetLib/FBX/FBXExporter.cpp index cbaf83f0f..ae210eb1a 100644 --- a/code/AssetLib/FBX/FBXExporter.cpp +++ b/code/AssetLib/FBX/FBXExporter.cpp @@ -1089,6 +1089,8 @@ void FBXExporter::WriteObjects () bool bJoinIdenticalVertices = mProperties->GetPropertyBool("bJoinIdenticalVertices", true); std::vector> vVertexIndice;//save vertex_indices as it is needed later + const auto bTransparencyFactorReferencedToOpacity = mProperties->GetPropertyBool(AI_CONFIG_EXPORT_FBX_TRANSPARENCY_FACTOR_REFER_TO_OPACITY, false); + // geometry (aiMesh) mesh_uids.clear(); indent = 1; @@ -1445,13 +1447,21 @@ void FBXExporter::WriteObjects () // "TransparentColor" / "TransparencyFactor"... // thanks FBX, for your insightful interpretation of consistency p.AddP70colorA("TransparentColor", c.r, c.g, c.b); - // TransparencyFactor defaults to 0.0, so set it to 1.0. - // note: Maya always sets this to 1.0, - // so we can't use it sensibly as "Opacity". - // In stead we rely on the legacy "Opacity" value, below. - // Blender also relies on "Opacity" not "TransparencyFactor", - // probably for a similar reason. - p.AddP70numberA("TransparencyFactor", 1.0); + + if (!bTransparencyFactorReferencedToOpacity) { + // TransparencyFactor defaults to 0.0, so set it to 1.0. + // note: Maya always sets this to 1.0, + // so we can't use it sensibly as "Opacity". + // In stead we rely on the legacy "Opacity" value, below. + // Blender also relies on "Opacity" not "TransparencyFactor", + // probably for a similar reason. + p.AddP70numberA("TransparencyFactor", 1.0); + } + } + if (bTransparencyFactorReferencedToOpacity) { + if (m->Get(AI_MATKEY_OPACITY, f) == aiReturn_SUCCESS) { + p.AddP70numberA("TransparencyFactor", 1.0 - f); + } } if (m->Get(AI_MATKEY_COLOR_REFLECTIVE, c) == aiReturn_SUCCESS) { p.AddP70colorA("ReflectionColor", c.r, c.g, c.b); diff --git a/include/assimp/config.h.in b/include/assimp/config.h.in index 67fc988be..897eecb19 100644 --- a/include/assimp/config.h.in +++ b/include/assimp/config.h.in @@ -1113,6 +1113,16 @@ enum aiComponent #define AI_CONFIG_EXPORT_GLTF_UNLIMITED_SKINNING_BONES_PER_VERTEX \ "USE_UNLIMITED_BONES_PER VERTEX" +/** @brief Specifies whether to write the value referenced to opacity in TransparencyFactor of each material. + * + * When this flag is not defined, the TransparencyFactor value of each meterial is 1.0. + * By enabling this flag, the value is 1.0 - opacity; + + * Property type: Bool. Default value: false. + */ +#define AI_CONFIG_EXPORT_FBX_TRANSPARENCY_FACTOR_REFER_TO_OPACITY \ + "EXPORT_FBX_TRANSPARENCY_FACTOR_REFER_TO_OPACITY" + /** * @brief Specifies the blob name, assimp uses for exporting. * From bb9101ae9eb2938cadfeadd4690bbdf910ca57f4 Mon Sep 17 00:00:00 2001 From: Bao Anchang Date: Mon, 4 Mar 2024 16:18:08 +0800 Subject: [PATCH 50/77] Eliminate non-ascii comments in clipper (#5480) --- contrib/clipper/clipper.cpp | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/contrib/clipper/clipper.cpp b/contrib/clipper/clipper.cpp index d75974336..c0a8565bb 100644 --- a/contrib/clipper/clipper.cpp +++ b/contrib/clipper/clipper.cpp @@ -4330,10 +4330,10 @@ double DistanceFromLineSqrd( const IntPoint& pt, const IntPoint& ln1, const IntPoint& ln2) { //The equation of a line in general form (Ax + By + C = 0) - //given 2 points (x�,y�) & (x�,y�) is ... - //(y� - y�)x + (x� - x�)y + (y� - y�)x� - (x� - x�)y� = 0 - //A = (y� - y�); B = (x� - x�); C = (y� - y�)x� - (x� - x�)y� - //perpendicular distance of point (x�,y�) = (Ax� + By� + C)/Sqrt(A� + B�) + //given 2 points (x_1, y_1) & (x_2, y_2) is ... + //(y_1 - y_2)x + (x_2 - x_1)y - (y_1 - y_2)x_1 - (x_2 - x_1)y_1 = 0 + //A = (y_1 - y_2); B = (x_2 - x_1); C = - (y_1 - y_2)x_1 - (x_2 - x_1)y_1 + //perpendicular distance of point (x_0, y_0) = |Ax_0 + By_0 + C| / Sqrt(A^2 + B^2) //see http://en.wikipedia.org/wiki/Perpendicular_distance double A = double(ln1.Y - ln2.Y); double B = double(ln2.X - ln1.X); From 727774f181e0f06d51db6fcafa343f46081c4cfa Mon Sep 17 00:00:00 2001 From: Laura Hermanns Date: Mon, 11 Mar 2024 04:09:23 -0400 Subject: [PATCH 51/77] Fix compilation for MSVC14. (#5490) - std::min/max were not defined in StackAllocator.inl; Also added explicit template arguments to break macro expansion if Windows.h is included prior and NOMINMAX macro is not present. - Made static_assert statements compatible with C++11 in ProcessHelper.cpp. - Removed unused string_view include in ObjFileParser.cpp. --- code/AssetLib/Obj/ObjFileParser.cpp | 1 - code/Common/StackAllocator.inl | 3 ++- code/PostProcessing/ProcessHelper.cpp | 4 ++-- 3 files changed, 4 insertions(+), 4 deletions(-) diff --git a/code/AssetLib/Obj/ObjFileParser.cpp b/code/AssetLib/Obj/ObjFileParser.cpp index 4aae6d7e7..c0f1fc483 100644 --- a/code/AssetLib/Obj/ObjFileParser.cpp +++ b/code/AssetLib/Obj/ObjFileParser.cpp @@ -52,7 +52,6 @@ OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. #include #include #include -#include namespace Assimp { diff --git a/code/Common/StackAllocator.inl b/code/Common/StackAllocator.inl index bca0ce1ef..80ad7ec45 100644 --- a/code/Common/StackAllocator.inl +++ b/code/Common/StackAllocator.inl @@ -41,6 +41,7 @@ OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. #include "StackAllocator.h" #include +#include using namespace Assimp; @@ -56,7 +57,7 @@ inline void *StackAllocator::Allocate(size_t byteSize) { { // double block size every time, up to maximum of g_maxBytesPerBlock. // Block size must be at least as large as byteSize, but we want to use this for small allocations anyway. - m_blockAllocationSize = std::max(std::min(m_blockAllocationSize * 2, g_maxBytesPerBlock), byteSize); + m_blockAllocationSize = std::max(std::min(m_blockAllocationSize * 2, g_maxBytesPerBlock), byteSize); uint8_t *data = new uint8_t[m_blockAllocationSize]; m_storageBlocks.emplace_back(data); m_subIndex = byteSize; diff --git a/code/PostProcessing/ProcessHelper.cpp b/code/PostProcessing/ProcessHelper.cpp index 4dcc8a60a..cfbac3e80 100644 --- a/code/PostProcessing/ProcessHelper.cpp +++ b/code/PostProcessing/ProcessHelper.cpp @@ -177,8 +177,8 @@ unsigned int GetMeshVFormatUnique(const aiMesh *pcMesh) { if (pcMesh->HasTangentsAndBitangents()) iRet |= 0x4; - static_assert(8 >= AI_MAX_NUMBER_OF_COLOR_SETS); - static_assert(8 >= AI_MAX_NUMBER_OF_TEXTURECOORDS); + static_assert(8 >= AI_MAX_NUMBER_OF_COLOR_SETS, "static_assert(8 >= AI_MAX_NUMBER_OF_COLOR_SETS)"); + static_assert(8 >= AI_MAX_NUMBER_OF_TEXTURECOORDS, "static_assert(8 >= AI_MAX_NUMBER_OF_TEXTURECOORDS)"); // texture coordinates unsigned int p = 0; From fcb1444b84f810c85ffc61354d58c877f940a5bb Mon Sep 17 00:00:00 2001 From: Kim Kulling Date: Sun, 17 Mar 2024 17:46:28 +0100 Subject: [PATCH 52/77] Add correction of fbx model rotation (#5494) --- code/AssetLib/FBX/FBXConverter.cpp | 49 ++++++++++++++++++++++++++++++ 1 file changed, 49 insertions(+) diff --git a/code/AssetLib/FBX/FBXConverter.cpp b/code/AssetLib/FBX/FBXConverter.cpp index 204d3e6fa..93f19de56 100644 --- a/code/AssetLib/FBX/FBXConverter.cpp +++ b/code/AssetLib/FBX/FBXConverter.cpp @@ -76,6 +76,53 @@ using namespace Util; #define CONVERT_FBX_TIME(time) static_cast(time) / 46186158000LL +static void correctRootTransform(const aiScene *scene) { + if (scene == nullptr) { + return; + } + + if (scene->mMetaData == nullptr) { + return; + } + + int32_t UpAxis = 1, UpAxisSign = 1, FrontAxis = 2, FrontAxisSign = 1, CoordAxis = 0, CoordAxisSign = 1; + double UnitScaleFactor = 1.0; + for (unsigned MetadataIndex = 0; MetadataIndex < scene->mMetaData->mNumProperties; ++MetadataIndex) { + if (strcmp(scene->mMetaData->mKeys[MetadataIndex].C_Str(), "UpAxis") == 0) { + scene->mMetaData->Get(MetadataIndex, UpAxis); + } + if (strcmp(scene->mMetaData->mKeys[MetadataIndex].C_Str(), "UpAxisSign") == 0) { + scene->mMetaData->Get(MetadataIndex, UpAxisSign); + } + if (strcmp(scene->mMetaData->mKeys[MetadataIndex].C_Str(), "FrontAxis") == 0) { + scene->mMetaData->Get(MetadataIndex, FrontAxis); + } + if (strcmp(scene->mMetaData->mKeys[MetadataIndex].C_Str(), "FrontAxisSign") == 0) { + scene->mMetaData->Get(MetadataIndex, FrontAxisSign); + } + if (strcmp(scene->mMetaData->mKeys[MetadataIndex].C_Str(), "CoordAxis") == 0) { + scene->mMetaData->Get(MetadataIndex, CoordAxis); + } + if (strcmp(scene->mMetaData->mKeys[MetadataIndex].C_Str(), "CoordAxisSign") == 0) { + scene->mMetaData->Get(MetadataIndex, CoordAxisSign); + } + if (strcmp(scene->mMetaData->mKeys[MetadataIndex].C_Str(), "UnitScaleFactor") == 0) { + scene->mMetaData->Get(MetadataIndex, UnitScaleFactor); + } + } + + aiVector3D upVec, forwardVec, rightVec; + upVec[UpAxis] = UpAxisSign * static_cast(UnitScaleFactor); + forwardVec[FrontAxis] = FrontAxisSign * static_cast(UnitScaleFactor); + rightVec[CoordAxis] = CoordAxisSign * (float)UnitScaleFactor; + + aiMatrix4x4 mat(rightVec.x, rightVec.y, rightVec.z, 0.0f, + upVec.x, upVec.y, upVec.z, 0.0f, + forwardVec.x, forwardVec.y, forwardVec.z, 0.0f, + 0.0f, 0.0f, 0.0f, 1.0f); + scene->mRootNode->mTransformation *= mat; +} + FBXConverter::FBXConverter(aiScene *out, const Document &doc, bool removeEmptyBones) : defaultMaterialIndex(), mMeshes(), @@ -133,6 +180,8 @@ FBXConverter::FBXConverter(aiScene *out, const Document &doc, bool removeEmptyBo // need not contain geometry (i.e. camera animations, raw armatures). if (out->mNumMeshes == 0) { out->mFlags |= AI_SCENE_FLAGS_INCOMPLETE; + } else { + correctRootTransform(mSceneOut); } } From 072320df4fc064f3bb690e24524e6d3fc090f4bd Mon Sep 17 00:00:00 2001 From: mosfet80 Date: Mon, 18 Mar 2024 23:24:51 +0100 Subject: [PATCH 53/77] Delete tools/make directory (#5491) Delete old .bat files Co-authored-by: Kim Kulling --- tools/make/build_env_win32.bat | 57 ------------------------------- tools/make/make_all_win32_x64.bat | 18 ---------- 2 files changed, 75 deletions(-) delete mode 100644 tools/make/build_env_win32.bat delete mode 100644 tools/make/make_all_win32_x64.bat diff --git a/tools/make/build_env_win32.bat b/tools/make/build_env_win32.bat deleted file mode 100644 index 4b8b4674b..000000000 --- a/tools/make/build_env_win32.bat +++ /dev/null @@ -1,57 +0,0 @@ -@echo off -set "initialdir=%cd%" -goto:main - -:exitsucc -cd /d "%initialdir%" -set initialdir= - -set MSBUILD_15="C:\Program Files (x86)\Microsoft Visual Studio\2018\Professional\MSBuild\15.0\Bin\msbuild.exe" -set MSBUILD_14="C:\Program Files (x86)\MSBuild\14.0\Bin\msbuild.exe" - -if not "%VS150%"=="" set MSBUILD_15="%VS150%\MSBuild\15.0\Bin\msbuild.exe" - -if /i %VS_VERSION%==2017 ( - set MS_BUILD_EXE=%MSBUILD_15% - set PLATFORM_VER=v141 -) else ( - set MS_BUILD_EXE=%MSBUILD_14% - set PLATFORM_VER=v140 -) - -set MSBUILD=%MS_BUILD_EXE% - -exit /b 0 - -:main -if not defined PLATFORM set "PLATFORM=x64" - -::my work here is done? - -set PATH_VSWHERE=C:\Program Files (x86)\Microsoft Visual Studio\Installer\ -REM set PATH_STUDIO="C:\Program Files (x86)\Microsoft Visual Studio\2017\Professional\" - -for /f "usebackq tokens=*" %%i in (`"%PATH_VSWHERE%vswhere" -latest -products * -requires Microsoft.Component.MSBuild -property installationPath`) do ( - set InstallDir=%%i -) - -IF EXIST "%InstallDir%\VC\Auxiliary\Build\vcvarsall.bat" set VS150=%InstallDir%\ - -set "CMAKE_GENERATOR=Visual Studio 15 2017 Win64" -if not "%VS150%"=="" call "%VS150%\VC\Auxiliary\Build\vcvarsall.bat" %PLATFORM% && echo found VS 2o17 && set PLATFORM_VER=v141 && set VS_VERSION=2017 && goto:exitsucc - -set "CMAKE_GENERATOR=Visual Studio 14 2015 Win64" -if defined VS140COMNTOOLS call "%VS140COMNTOOLS%..\..\VC\vcvarsall.bat" %PLATFORM% && echo found VS 2o15 && set PLATFORM_VER=v140 && set VS_VERSION=2015 && goto:exitsucc - -if defined VS130COMNTOOLS echo call ghostbusters... found lost VS version - -set "CMAKE_GENERATOR=Visual Studio 12 2013 Win64" -if defined VS120COMNTOOLS call "%VS120COMNTOOLS%..\..\VC\vcvarsall.bat" %PLATFORM% && echo found VS 2o13 && set PLATFORM_VER=v120 && set VS_VERSION=2013 && goto:exitsucc - -set "CMAKE_GENERATOR=Visual Studio 11 2012 Win64" -if defined VS110COMNTOOLS call "%VS110COMNTOOLS%..\..\VC\vcvarsall.bat" %PLATFORM% && echo found VS 2o12 && set PLATFORM_VER=v110 && set VS_VERSION=2012 && goto:exitsucc - -set "CMAKE_GENERATOR=Visual Studio 10 2010 Win64" -if defined VS100COMNTOOLS call "%VS100COMNTOOLS%..\..\VC\vcvarsall.bat" %PLATFORM% && echo found VS 2o1o && set PLATFORM_VER=v100 && set VS_VERSION=2010 && goto:exitsucc - -goto:exitsucc \ No newline at end of file diff --git a/tools/make/make_all_win32_x64.bat b/tools/make/make_all_win32_x64.bat deleted file mode 100644 index 4a1e663e6..000000000 --- a/tools/make/make_all_win32_x64.bat +++ /dev/null @@ -1,18 +0,0 @@ -rem @echo off -setlocal -call build_env_win32.bat - -set BUILD_CONFIG=release -set PLATFORM_CONFIG=x64 -set MAX_CPU_CONFIG=4 - -set CONFIG_PARAMETER=/p:Configuration="%BUILD_CONFIG%" -set PLATFORM_PARAMETER=/p:Platform="%PLATFORM_CONFIG%" -set CPU_PARAMETER=/maxcpucount:%MAX_CPU_CONFIG% -set PLATFORM_TOOLSET=/p:PlatformToolset=%PLATFORM_VER% - -pushd ..\..\ -cmake CMakeLists.txt -G "Visual Studio 15 2017 Win64" -%MSBUILD% assimp.sln %CONFIG_PARAMETER% %PLATFORM_PARAMETER% %CPU_PARAMETER% %PLATFORM_TOOLSET% -popd -endlocal From 730aa9d0b7821968d26c9738eba21a52f1c762bc Mon Sep 17 00:00:00 2001 From: mosfet80 Date: Wed, 20 Mar 2024 11:15:03 +0100 Subject: [PATCH 54/77] Delete packaging/windows-mkzip directory (#5492) Removed unused files Co-authored-by: Kim Kulling --- packaging/windows-mkzip/bin_readme.txt | 29 ----- packaging/windows-mkzip/mkfinal.bat | 169 ------------------------- packaging/windows-mkzip/mkrev.bat | 27 ---- 3 files changed, 225 deletions(-) delete mode 100644 packaging/windows-mkzip/bin_readme.txt delete mode 100644 packaging/windows-mkzip/mkfinal.bat delete mode 100644 packaging/windows-mkzip/mkrev.bat diff --git a/packaging/windows-mkzip/bin_readme.txt b/packaging/windows-mkzip/bin_readme.txt deleted file mode 100644 index f4402d6bf..000000000 --- a/packaging/windows-mkzip/bin_readme.txt +++ /dev/null @@ -1,29 +0,0 @@ - ------------------------------------------------------------------------------------- -Open Asset Import Library (Assimp) Tools/Binaries for Windows -Release Notes ------------------------------------------------------------------------------------- - - -Known Bugs & Limitations -======================== - -Viewer - -- For files more than one embedded texture, only the first is loaded. -- Normals appear flipped from time to time when either of the normals-related menu items was hit. -- Alpha-sorting is implemented, but still causes artifacts when models are moved quickly. -- Several important texture file formats (such as GIF) are not supported. -- HUD is blurred on the right side. ATI/AMD hardware only. - -Troubleshooting -=============== - -1. Missing d3dx9_42.dll? -Install the latest DirectX runtime or grab the file from somewhere (that's evil but mostly fine). - -2. Application configuration not correct / missing msv*** DLLs? -(Re)install Microsoft Visual C++ 2005 SP1 Redistributable (x86 or x64, depending on your system) - -3. Crashes immediately -You CPU lacks SSE2 support. Build Assimp from scratch to suit your CPU, sorry. diff --git a/packaging/windows-mkzip/mkfinal.bat b/packaging/windows-mkzip/mkfinal.bat deleted file mode 100644 index b626514c0..000000000 --- a/packaging/windows-mkzip/mkfinal.bat +++ /dev/null @@ -1,169 +0,0 @@ - -rem ----------------------------------------------------- -rem Batch file to build zipped redist packages -rem Two different packages are built: -rem -rem assimp---bin.zip -rem Binaries for x86 and x64 -rem Command line reference -rem -rem assimp---sdk.zip -rem Binaries for x86 and x64, Debug & Release -rem Libs for DLL build, x86 & 64, Debug & Release -rem Full SVN checkout exluding mkutil & port -rem -rem -rem PREREQUISITES: -rem -7za.exe (7zip standalone) -rem Download from http://www.7-zip.org/download.html -rem -rem -svnversion.exe (Subversion revision getter) -rem Download any command line SVN package -rem -rem -doxygen.exe (Doxygen client) -rem Download from www.doxygen.com -rem -rem -svn client -rem -rem NOTES: -rem ./bin must not have any local modifications -rem -rem ----------------------------------------------------- - -@echo off -color 4e -cls - -rem ----------------------------------------------------- -rem Setup file revision for build -rem ----------------------------------------------------- -call mkrev.bat - -rem ----------------------------------------------------- -rem Build output file names -rem ----------------------------------------------------- - -cd ..\..\bin -svnversion > tmpfile.txt -SET /p REVISIONBASE= < tmpfile.txt -DEL /q tmpfile.txt -cd ..\packaging\windows-mkzip - -SET VERSIONBASE=2.0.%REVISIONBASE% - -SET OUT_SDK=assimp--%VERSIONBASE%-sdk -SET OUT_BIN=assimp--%VERSIONBASE%-bin - -SET BINCFG_x86=release-dll_win32 -SET BINCFG_x64=release-dll_x64 - -SET BINCFG_x86_DEBUG=debug-dll_win32 -SET BINCFG_x64_DEBUG=debug-dll_x64 - -rem ----------------------------------------------------- -rem Delete previous output directories -rem ----------------------------------------------------- -RD /S /q final\ - -rem ----------------------------------------------------- -rem Create output directories -rem ----------------------------------------------------- - -mkdir final\%OUT_BIN%\x86 -mkdir final\%OUT_BIN%\x64 - -rem ----------------------------------------------------- -rem Copy all executables to 'final-bin' -rem ----------------------------------------------------- - -copy /Y ..\..\bin\assimpview_%BINCFG_x86%\assimp_view.exe "final\%OUT_BIN%\x86\assimp_view.exe" -copy /Y ..\..\bin\assimpview_%BINCFG_x64%\assimp_view.exe "final\%OUT_BIN%\x64\assimp_view.exe" - -copy /Y ..\..\bin\assimpcmd_%BINCFG_x86%\assimp.exe "final\%OUT_BIN%\x86\assimp.exe" -copy /Y ..\..\bin\assimpcmd_%BINCFG_x64%\assimp.exe "final\%OUT_BIN%\x64\assimp.exe" - -copy /Y ..\..\bin\assimp_%BINCFG_x86%\Assimp32.dll "final\%OUT_BIN%\x86\Assimp32.dll" -copy /Y ..\..\bin\assimp_%BINCFG_x64%\Assimp64.dll "final\%OUT_BIN%\x64\Assimp64.dll" - -copy ..\..\LICENSE final\%OUT_BIN%\LICENSE -copy ..\..\CREDITS final\%OUT_BIN%\CREDITS -copy bin_readme.txt final\%OUT_BIN%\README -copy bin_readme.txt final\%OUT_BIN%\README - -copy ..\..\doc\AssimpCmdDoc_Html\AssimpCmdDoc.chm final\%OUT_BIN%\CommandLine.chm - -rem ----------------------------------------------------- -rem Do a clean export of the repository and build SDK -rem -rem We take the current revision and remove some stuff -rem that is nto yet ready to be published. -rem ----------------------------------------------------- - -svn export .\..\..\ .\final\%OUT_SDK% - -mkdir final\%OUT_SDK%\doc\assimp_html -mkdir final\%OUT_SDK%\doc\assimpcmd_html -copy .\..\..\doc\AssimpDoc_Html\* final\%OUT_SDK%\doc\assimp_html -copy .\..\..\doc\AssimpCmdDoc_Html\* final\%OUT_SDK%\doc\assimpcmd_html -del final\%OUT_SDK%\doc\assimpcmd_html\AssimpCmdDoc.chm -del final\%OUT_SDK%\doc\assimp_html\AssimpDoc.chm - -rem Copy doc to a suitable place -move final\%OUT_SDK%\doc\AssimpDoc_Html\AssimpDoc.chm final\%OUT_SDK%\Documentation.chm -move final\%OUT_SDK%\doc\AssimpCmdDoc_Html\AssimpCmdDoc.chm final\%OUT_SDK%\CommandLine.chm - -rem Cleanup ./doc folder -del /q final\%OUT_SDK%\doc\Preamble.txt -RD /s /q final\%OUT_SDK%\doc\AssimpDoc_Html -RD /s /q final\%OUT_SDK%\doc\AssimpCmdDoc_Html - -rem Insert 'dummy' files into empty folders -echo. > final\%OUT_SDK%\lib\dummy -echo. > final\%OUT_SDK%\obj\dummy - - -RD /s /q final\%OUT_SDK%\port\swig - -rem Also, repackaging is not a must-have feature -RD /s /q final\%OUT_SDK%\packaging - -rem Copy prebuilt libs -mkdir "final\%OUT_SDK%\lib\assimp_%BINCFG_x86%" -mkdir "final\%OUT_SDK%\lib\assimp_%BINCFG_x64%" -mkdir "final\%OUT_SDK%\lib\assimp_%BINCFG_x86_DEBUG%" -mkdir "final\%OUT_SDK%\lib\assimp_%BINCFG_x64_DEBUG%" - -copy /Y ..\..\lib\assimp_%BINCFG_x86%\assimp.lib "final\%OUT_SDK%\lib\assimp_%BINCFG_x86%" -copy /Y ..\..\lib\assimp_%BINCFG_x64%\assimp.lib "final\%OUT_SDK%\lib\assimp_%BINCFG_x64%\" -copy /Y ..\..\lib\assimp_%BINCFG_x86_DEBUG%\assimp.lib "final\%OUT_SDK%\lib\assimp_%BINCFG_x86_DEBUG%\" -copy /Y ..\..\lib\assimp_%BINCFG_x64_DEBUG%\assimp.lib "final\%OUT_SDK%\lib\assimp_%BINCFG_x64_DEBUG%\" - -rem Copy prebuilt DLLs -mkdir "final\%OUT_SDK%\bin\assimp_%BINCFG_x86%" -mkdir "final\%OUT_SDK%\bin\assimp_%BINCFG_x64%" -mkdir "final\%OUT_SDK%\bin\assimp_%BINCFG_x86_DEBUG%" -mkdir "final\%OUT_SDK%\bin\assimp_%BINCFG_x64_DEBUG%" - - -copy /Y ..\..\bin\assimp_%BINCFG_x86%\Assimp32.dll "final\%OUT_SDK%\bin\assimp_%BINCFG_x86%\" -copy /Y ..\..\bin\assimp_%BINCFG_x64%\Assimp64.dll "final\%OUT_SDK%\bin\assimp_%BINCFG_x64%\" -copy /Y ..\..\bin\assimp_%BINCFG_x86_DEBUG%\Assimp32d.dll "final\%OUT_SDK%\bin\assimp_%BINCFG_x86_DEBUG%\" -copy /Y ..\..\bin\assimp_%BINCFG_x64_DEBUG%\Assimp64d.dll "final\%OUT_SDK%\bin\assimp_%BINCFG_x64_DEBUG%\" - - -rem ----------------------------------------------------- -rem Make final-bin.zip and final-sdk.zip -rem ----------------------------------------------------- - -IF NOT EXIST 7za.exe ( - cls - echo You need to have 7zip standalone installed to - echo build ZIP archives. Download: http://www.7-zip.org/download.html - pause -) else ( -7za.exe a -tzip "final\%OUT_BIN%.zip" ".\final\%OUT_BIN%" -7za.exe a -tzip "final\%OUT_SDK%.zip" ".\final\%OUT_SDK%" -) - -rem OK. We should have the release packages now. - diff --git a/packaging/windows-mkzip/mkrev.bat b/packaging/windows-mkzip/mkrev.bat deleted file mode 100644 index 9d8eec120..000000000 --- a/packaging/windows-mkzip/mkrev.bat +++ /dev/null @@ -1,27 +0,0 @@ -@echo off - -rem ----------------------------------------------------- -rem Tiny batch script to build the input file revision.h -rem revision.h contains the revision number of the wc. -rem It is included by assimp.rc. -rem ----------------------------------------------------- - -rem This is not very elegant, but it works. -rem ./bin shouldn't have any local modifications - -svnversion > tmpfile.txt -set /p addtext= < tmpfile.txt -del /q tmpfile.txt - -echo #define SVNRevision > tmpfile.txt - -if exist ..\..\revision.h del /q ..\..\revision.h -for /f "delims=" %%l in (tmpfile.txt) Do ( - for /f "delims=M:" %%r in ("%addtext%") Do ( - echo %%l %%r >> ..\..\revision.h - ) -) -del /q tmpfile.txt - - - From feb861f17bf937fd42e0591b3347b95009033eec Mon Sep 17 00:00:00 2001 From: Kristjan Skutta Date: Fri, 22 Mar 2024 00:01:57 +0100 Subject: [PATCH 55/77] Fix duplicate degrees to radians conversion in fbx importer. (#5427) Co-authored-by: Kim Kulling --- code/AssetLib/FBX/FBXConverter.cpp | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/code/AssetLib/FBX/FBXConverter.cpp b/code/AssetLib/FBX/FBXConverter.cpp index 93f19de56..cc73756fb 100644 --- a/code/AssetLib/FBX/FBXConverter.cpp +++ b/code/AssetLib/FBX/FBXConverter.cpp @@ -3288,9 +3288,9 @@ aiNodeAnim* FBXConverter::GenerateSimpleNodeAnim(const std::string& name, } if (keyframeLists[TransformationComp_Rotation].size() > 0) { - InterpolateKeys(outRotations, keytimes, keyframeLists[TransformationComp_Rotation], AI_DEG_TO_RAD(defRotation), maxTime, minTime, rotOrder); + InterpolateKeys(outRotations, keytimes, keyframeLists[TransformationComp_Rotation], defRotation, maxTime, minTime, rotOrder); } else { - aiQuaternion defQuat = EulerToQuaternion(AI_DEG_TO_RAD(defRotation), rotOrder); + aiQuaternion defQuat = EulerToQuaternion(defRotation, rotOrder); for (size_t i = 0; i < keyCount; ++i) { outRotations[i].mTime = CONVERT_FBX_TIME(keytimes[i]) * anim_fps; outRotations[i].mValue = defQuat; @@ -3312,7 +3312,7 @@ aiNodeAnim* FBXConverter::GenerateSimpleNodeAnim(const std::string& name, const aiVector3D& preRotation = PropertyGet(props, "PreRotation", ok); if (ok && preRotation.SquareLength() > zero_epsilon) { - const aiQuaternion preQuat = EulerToQuaternion(AI_DEG_TO_RAD(preRotation), Model::RotOrder_EulerXYZ); + const aiQuaternion preQuat = EulerToQuaternion(preRotation, Model::RotOrder_EulerXYZ); for (size_t i = 0; i < keyCount; ++i) { outRotations[i].mValue = preQuat * outRotations[i].mValue; } @@ -3320,7 +3320,7 @@ aiNodeAnim* FBXConverter::GenerateSimpleNodeAnim(const std::string& name, const aiVector3D& postRotation = PropertyGet(props, "PostRotation", ok); if (ok && postRotation.SquareLength() > zero_epsilon) { - const aiQuaternion postQuat = EulerToQuaternion(AI_DEG_TO_RAD(postRotation), Model::RotOrder_EulerXYZ); + const aiQuaternion postQuat = EulerToQuaternion(postRotation, Model::RotOrder_EulerXYZ); for (size_t i = 0; i < keyCount; ++i) { outRotations[i].mValue = outRotations[i].mValue * postQuat; } From 39ce0c0456b2cb4453dd69edd7d76274795e7287 Mon Sep 17 00:00:00 2001 From: Julian Knodt Date: Tue, 2 Apr 2024 09:31:19 -0700 Subject: [PATCH 56/77] Respect merge identical vertices in ObjExporter (#5521) Co-authored-by: Kim Kulling --- code/AssetLib/Obj/ObjExporter.cpp | 34 +++++++++++++++++-------------- code/AssetLib/Obj/ObjExporter.h | 13 +++++++----- 2 files changed, 27 insertions(+), 20 deletions(-) diff --git a/code/AssetLib/Obj/ObjExporter.cpp b/code/AssetLib/Obj/ObjExporter.cpp index a5d8325fc..7c5c051f3 100644 --- a/code/AssetLib/Obj/ObjExporter.cpp +++ b/code/AssetLib/Obj/ObjExporter.cpp @@ -59,9 +59,9 @@ namespace Assimp { // ------------------------------------------------------------------------------------------------ // Worker function for exporting a scene to Wavefront OBJ. Prototyped and registered in Exporter.cpp -void ExportSceneObj(const char* pFile,IOSystem* pIOSystem, const aiScene* pScene, const ExportProperties* /*pProperties*/) { +void ExportSceneObj(const char* pFile,IOSystem* pIOSystem, const aiScene* pScene, const ExportProperties* props) { // invoke the exporter - ObjExporter exporter(pFile, pScene); + ObjExporter exporter(pFile, pScene, false, props); if (exporter.mOutput.fail() || exporter.mOutputMat.fail()) { throw DeadlyExportError("output data creation failed. Most likely the file became too large: " + std::string(pFile)); @@ -86,9 +86,9 @@ void ExportSceneObj(const char* pFile,IOSystem* pIOSystem, const aiScene* pScene // ------------------------------------------------------------------------------------------------ // Worker function for exporting a scene to Wavefront OBJ without the material file. Prototyped and registered in Exporter.cpp -void ExportSceneObjNoMtl(const char* pFile,IOSystem* pIOSystem, const aiScene* pScene, const ExportProperties* ) { +void ExportSceneObjNoMtl(const char* pFile,IOSystem* pIOSystem, const aiScene* pScene, const ExportProperties* props) { // invoke the exporter - ObjExporter exporter(pFile, pScene, true); + ObjExporter exporter(pFile, pScene, true, props); if (exporter.mOutput.fail() || exporter.mOutputMat.fail()) { throw DeadlyExportError("output data creation failed. Most likely the file became too large: " + std::string(pFile)); @@ -111,7 +111,7 @@ void ExportSceneObjNoMtl(const char* pFile,IOSystem* pIOSystem, const aiScene* p static const std::string MaterialExt = ".mtl"; // ------------------------------------------------------------------------------------------------ -ObjExporter::ObjExporter(const char* _filename, const aiScene* pScene, bool noMtl) +ObjExporter::ObjExporter(const char* _filename, const aiScene* pScene, bool noMtl, const ExportProperties* props) : filename(_filename) , pScene(pScene) , vn() @@ -130,7 +130,10 @@ ObjExporter::ObjExporter(const char* _filename, const aiScene* pScene, bool noMt mOutputMat.imbue(l); mOutputMat.precision(ASSIMP_AI_REAL_TEXT_PRECISION); - WriteGeometryFile(noMtl); + WriteGeometryFile( + noMtl, + props == nullptr ? true : props->GetPropertyBool("bJoinIdenticalVertices", true) + ); if ( !noMtl ) { WriteMaterialFile(); } @@ -255,14 +258,14 @@ void ObjExporter::WriteMaterialFile() { } } -void ObjExporter::WriteGeometryFile(bool noMtl) { +void ObjExporter::WriteGeometryFile(bool noMtl, bool merge_identical_vertices) { WriteHeader(mOutput); if (!noMtl) mOutput << "mtllib " << GetMaterialLibName() << endl << endl; // collect mesh geometry aiMatrix4x4 mBase; - AddNode(pScene->mRootNode, mBase); + AddNode(pScene->mRootNode, mBase, merge_identical_vertices); // write vertex positions with colors, if any mVpMap.getKeys( vp ); @@ -330,7 +333,7 @@ void ObjExporter::WriteGeometryFile(bool noMtl) { } // ------------------------------------------------------------------------------------------------ -void ObjExporter::AddMesh(const aiString& name, const aiMesh* m, const aiMatrix4x4& mat) { +void ObjExporter::AddMesh(const aiString& name, const aiMesh* m, const aiMatrix4x4& mat, bool merge_identical_vertices) { mMeshes.emplace_back(); MeshInstance& mesh = mMeshes.back(); @@ -362,13 +365,14 @@ void ObjExporter::AddMesh(const aiString& name, const aiMesh* m, const aiMatrix4 for(unsigned int a = 0; a < f.mNumIndices; ++a) { const unsigned int idx = f.mIndices[a]; + const unsigned int fi = merge_identical_vertices ? 0 : idx; aiVector3D vert = mat * m->mVertices[idx]; if ( nullptr != m->mColors[ 0 ] ) { aiColor4D col4 = m->mColors[ 0 ][ idx ]; - face.indices[a].vp = mVpMap.getIndex({vert, aiColor3D(col4.r, col4.g, col4.b)}); + face.indices[a].vp = mVpMap.getIndex({vert, aiColor3D(col4.r, col4.g, col4.b), fi}); } else { - face.indices[a].vp = mVpMap.getIndex({vert, aiColor3D(0,0,0)}); + face.indices[a].vp = mVpMap.getIndex({vert, aiColor3D(0,0,0), fi}); } if (m->mNormals) { @@ -388,21 +392,21 @@ void ObjExporter::AddMesh(const aiString& name, const aiMesh* m, const aiMatrix4 } // ------------------------------------------------------------------------------------------------ -void ObjExporter::AddNode(const aiNode* nd, const aiMatrix4x4& mParent) { +void ObjExporter::AddNode(const aiNode* nd, const aiMatrix4x4& mParent, bool merge_identical_vertices) { const aiMatrix4x4& mAbs = mParent * nd->mTransformation; aiMesh *cm( nullptr ); for(unsigned int i = 0; i < nd->mNumMeshes; ++i) { cm = pScene->mMeshes[nd->mMeshes[i]]; if (nullptr != cm) { - AddMesh(cm->mName, pScene->mMeshes[nd->mMeshes[i]], mAbs); + AddMesh(cm->mName, pScene->mMeshes[nd->mMeshes[i]], mAbs, merge_identical_vertices); } else { - AddMesh(nd->mName, pScene->mMeshes[nd->mMeshes[i]], mAbs); + AddMesh(nd->mName, pScene->mMeshes[nd->mMeshes[i]], mAbs, merge_identical_vertices); } } for(unsigned int i = 0; i < nd->mNumChildren; ++i) { - AddNode(nd->mChildren[i], mAbs); + AddNode(nd->mChildren[i], mAbs, merge_identical_vertices); } } diff --git a/code/AssetLib/Obj/ObjExporter.h b/code/AssetLib/Obj/ObjExporter.h index a64f38f74..4c92aa16f 100644 --- a/code/AssetLib/Obj/ObjExporter.h +++ b/code/AssetLib/Obj/ObjExporter.h @@ -51,6 +51,8 @@ OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. #include #include +#include + struct aiScene; struct aiNode; struct aiMesh; @@ -63,7 +65,7 @@ namespace Assimp { class ObjExporter { public: /// Constructor for a specific scene to export - ObjExporter(const char* filename, const aiScene* pScene, bool noMtl=false); + ObjExporter(const char* filename, const aiScene* pScene, bool noMtl=false, const ExportProperties* props = nullptr); ~ObjExporter(); std::string GetMaterialLibName(); std::string GetMaterialLibFileName(); @@ -97,10 +99,10 @@ private: void WriteHeader(std::ostringstream& out); void WriteMaterialFile(); - void WriteGeometryFile(bool noMtl=false); + void WriteGeometryFile(bool noMtl=false, bool merge_identical_vertices = false); std::string GetMaterialName(unsigned int index); - void AddMesh(const aiString& name, const aiMesh* m, const aiMatrix4x4& mat); - void AddNode(const aiNode* nd, const aiMatrix4x4& mParent); + void AddMesh(const aiString& name, const aiMesh* m, const aiMatrix4x4& mat, bool merge_identical_vertices); + void AddNode(const aiNode* nd, const aiMatrix4x4& mParent, bool merge_identical_vertices); private: std::string filename; @@ -109,6 +111,7 @@ private: struct vertexData { aiVector3D vp; aiColor3D vc; // OBJ does not support 4D color + uint32_t index = 0; }; std::vector vn, vt; @@ -133,7 +136,7 @@ private: if (a.vc.g > b.vc.g) return false; if (a.vc.b < b.vc.b) return true; if (a.vc.b > b.vc.b) return false; - return false; + return a.index < b.index; } }; From 9d11b220eb4f19d823179bfe68ef89c81b1e1079 Mon Sep 17 00:00:00 2001 From: Oleg Ivanov Date: Sat, 6 Apr 2024 12:48:28 +0200 Subject: [PATCH 57/77] Fix utDefaultIOStream test under MinGW (#5525) --- test/unit/UnitTestFileGenerator.h | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) diff --git a/test/unit/UnitTestFileGenerator.h b/test/unit/UnitTestFileGenerator.h index 2166c6939..93007bad9 100644 --- a/test/unit/UnitTestFileGenerator.h +++ b/test/unit/UnitTestFileGenerator.h @@ -44,9 +44,14 @@ OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. #include #include +#if defined(_MSC_VER) || defined(__MINGW64__) || defined(__MINGW32__) +#define TMP_PATH "./" +#elif defined(__GNUC__) || defined(__clang__) +#define TMP_PATH "/tmp/" +#endif + #if defined(_MSC_VER) #include -#define TMP_PATH "./" inline FILE* MakeTmpFile(char* tmplate) { auto pathtemplate = _mktemp(tmplate); @@ -60,7 +65,6 @@ inline FILE* MakeTmpFile(char* tmplate) return fs; } #elif defined(__GNUC__) || defined(__clang__) -#define TMP_PATH "/tmp/" inline FILE* MakeTmpFile(char* tmplate) { auto fd = mkstemp(tmplate); From 52c2b6896a22a892789bc98965beff3ef7547019 Mon Sep 17 00:00:00 2001 From: RoboSchmied Date: Sat, 6 Apr 2024 21:26:32 +0200 Subject: [PATCH 58/77] Fix 16 typos (#5518) Signed-off-by: RoboSchmied Co-authored-by: Kim Kulling --- code/AssetLib/HMP/HMPFileData.h | 2 +- code/AssetLib/MD2/MD2FileData.h | 2 +- code/AssetLib/MD3/MD3FileData.h | 2 +- code/AssetLib/MDC/MDCFileData.h | 2 +- code/AssetLib/MDL/MDLFileData.h | 2 +- doc/dox.h | 2 +- include/assimp/ByteSwapper.h | 8 ++++---- include/assimp/StreamReader.h | 6 +++--- include/assimp/StreamWriter.h | 6 +++--- 9 files changed, 16 insertions(+), 16 deletions(-) diff --git a/code/AssetLib/HMP/HMPFileData.h b/code/AssetLib/HMP/HMPFileData.h index 4fc54e2c8..5f6ca4f55 100644 --- a/code/AssetLib/HMP/HMPFileData.h +++ b/code/AssetLib/HMP/HMPFileData.h @@ -49,7 +49,7 @@ namespace HMP { #include #include -// to make it easier for us, we test the magic word against both "endianesses" +// to make it easier for us, we test the magic word against both "endiannesses" #define AI_HMP_MAGIC_NUMBER_BE_4 AI_MAKE_MAGIC("HMP4") #define AI_HMP_MAGIC_NUMBER_LE_4 AI_MAKE_MAGIC("4PMH") diff --git a/code/AssetLib/MD2/MD2FileData.h b/code/AssetLib/MD2/MD2FileData.h index 6c1f7069b..0dba71e56 100644 --- a/code/AssetLib/MD2/MD2FileData.h +++ b/code/AssetLib/MD2/MD2FileData.h @@ -55,7 +55,7 @@ OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. namespace Assimp { namespace MD2 { -// to make it easier for us, we test the magic word against both "endianesses" +// to make it easier for us, we test the magic word against both "endiannesses" #define AI_MD2_MAGIC_NUMBER_BE AI_MAKE_MAGIC("IDP2") #define AI_MD2_MAGIC_NUMBER_LE AI_MAKE_MAGIC("2PDI") diff --git a/code/AssetLib/MD3/MD3FileData.h b/code/AssetLib/MD3/MD3FileData.h index 4251243b3..86d2647b6 100644 --- a/code/AssetLib/MD3/MD3FileData.h +++ b/code/AssetLib/MD3/MD3FileData.h @@ -62,7 +62,7 @@ OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. namespace Assimp { namespace MD3 { -// to make it easier for us, we test the magic word against both "endianesses" +// to make it easier for us, we test the magic word against both "endiannesses" #define AI_MD3_MAGIC_NUMBER_BE AI_MAKE_MAGIC("IDP3") #define AI_MD3_MAGIC_NUMBER_LE AI_MAKE_MAGIC("3PDI") diff --git a/code/AssetLib/MDC/MDCFileData.h b/code/AssetLib/MDC/MDCFileData.h index 5d7084b5d..4c5b4127c 100644 --- a/code/AssetLib/MDC/MDCFileData.h +++ b/code/AssetLib/MDC/MDCFileData.h @@ -61,7 +61,7 @@ http://themdcfile.planetwolfenstein.gamespy.com/MDC_File_Format.pdf namespace Assimp { namespace MDC { -// to make it easier for us, we test the magic word against both "endianesses" +// to make it easier for us, we test the magic word against both "endiannesses" #define AI_MDC_MAGIC_NUMBER_BE AI_MAKE_MAGIC("CPDI") #define AI_MDC_MAGIC_NUMBER_LE AI_MAKE_MAGIC("IDPC") diff --git a/code/AssetLib/MDL/MDLFileData.h b/code/AssetLib/MDL/MDLFileData.h index 62117e788..2aff59856 100644 --- a/code/AssetLib/MDL/MDLFileData.h +++ b/code/AssetLib/MDL/MDLFileData.h @@ -67,7 +67,7 @@ namespace Assimp { namespace MDL { // ------------------------------------------------------------------------------------- -// to make it easier for us, we test the magic word against both "endianesses" +// to make it easier for us, we test the magic word against both "endiannesses" // magic bytes used in Quake 1 MDL meshes #define AI_MDL_MAGIC_NUMBER_BE AI_MAKE_MAGIC("IDPO") diff --git a/doc/dox.h b/doc/dox.h index 1d5f59aa4..2fb127a2b 100644 --- a/doc/dox.h +++ b/doc/dox.h @@ -1545,7 +1545,7 @@ Don't trust the input data! Check all offsets! Mixed stuff for internal use by loaders, mostly documented (most of them are already included by AssimpPCH.h):
    • ByteSwapper (ByteSwapper.h) - manual byte swapping stuff for binary loaders.
    • -
    • StreamReader (StreamReader.h) - safe, endianess-correct, binary reading.
    • +
    • StreamReader (StreamReader.h) - safe, endianness-correct, binary reading.
    • IrrXML (irrXMLWrapper.h) - for XML-parsing (SAX.
    • CommentRemover (RemoveComments.h) - remove single-line and multi-line comments from a text file.
    • fast_atof, strtoul10, strtoul16, SkipSpaceAndLineEnd, SkipToNextToken .. large family of low-level diff --git a/include/assimp/ByteSwapper.h b/include/assimp/ByteSwapper.h index 179f7b555..f738ae701 100644 --- a/include/assimp/ByteSwapper.h +++ b/include/assimp/ByteSwapper.h @@ -263,7 +263,7 @@ struct ByteSwapper { }; // -------------------------------------------------------------------------------------------- -template +template struct Getter { void operator() (T* inout, bool le) { #ifdef AI_BUILD_BIG_ENDIAN @@ -278,12 +278,12 @@ struct Getter { } }; -template -struct Getter { +template +struct Getter { void operator() (T* inout, bool /*le*/) { // static branch - ByteSwapper1)> () (inout); + ByteSwapper1)> () (inout); } }; } // end Intern diff --git a/include/assimp/StreamReader.h b/include/assimp/StreamReader.h index 66e83b7ac..cc74bd652 100644 --- a/include/assimp/StreamReader.h +++ b/include/assimp/StreamReader.h @@ -68,7 +68,7 @@ namespace Assimp { * * XXX switch from unsigned int for size types to size_t? or ptrdiff_t?*/ // -------------------------------------------------------------------------------------------- -template +template class StreamReader { public: using diff = size_t; @@ -84,7 +84,7 @@ public: * reads from the current position to the end of the stream. * @param le If @c RuntimeSwitch is true: specifies whether the * stream is in little endian byte order. Otherwise the - * endianness information is contained in the @c SwapEndianess + * endianness information is contained in the @c SwapEndianness * template parameter and this parameter is meaningless. */ StreamReader(std::shared_ptr stream, bool le = false) : mStream(stream), @@ -291,7 +291,7 @@ public: T f; ::memcpy(&f, mCurrent, sizeof(T)); - Intern::Getter()(&f, mLe); + Intern::Getter()(&f, mLe); mCurrent += sizeof(T); return f; diff --git a/include/assimp/StreamWriter.h b/include/assimp/StreamWriter.h index 7b84789d1..32da6911b 100644 --- a/include/assimp/StreamWriter.h +++ b/include/assimp/StreamWriter.h @@ -65,7 +65,7 @@ namespace Assimp { * stream is to be determined at runtime. */ // -------------------------------------------------------------------------------------------- -template +template class StreamWriter { enum { INITIAL_CAPACITY = 1024 @@ -82,7 +82,7 @@ public: continues at the current position of the stream cursor. * @param le If @c RuntimeSwitch is true: specifies whether the * stream is in little endian byte order. Otherwise the - * endianness information is defined by the @c SwapEndianess + * endianness information is defined by the @c SwapEndianness * template parameter and this parameter is meaningless. */ StreamWriter(std::shared_ptr stream, bool le = false) : stream(stream) @@ -260,7 +260,7 @@ public: /** Generic write method. ByteSwap::Swap(T*) *must* be defined */ template void Put(T f) { - Intern :: Getter() (&f, le); + Intern :: Getter() (&f, le); if (cursor + sizeof(T) >= buffer.size()) { buffer.resize(cursor + sizeof(T)); From 790aad4b62a2886f262e51665e9cf0037d33750b Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Alejandro=20Gonz=C3=A1lez?= <7822554+AlexTMjugador@users.noreply.github.com> Date: Sun, 7 Apr 2024 00:25:46 +0200 Subject: [PATCH 59/77] Add macOS support to C4D importer (#5516) The latest Cineware SDK explicitly asserts macOS support in its documentation, but Assimp's C4D importer only works with Windows MSVC targets. Let's improve its portability by refactoring importer code to not depend on MSVC-only data types and quirks, and add support for linking against the universal macOS static libraries provided in the Cineware SDK. Note that the C4D importer still cannot support Linux platforms because Maxon does not provide the necessary precompiled Cineware libraries for that platform. Windows MinGW targets are also out of the question as the MinGW toolchain uses compiled libraries in a different format. Co-authored-by: Kim Kulling --- CMakeLists.txt | 19 +++++++++++++++---- code/AssetLib/C4D/C4DImporter.cpp | 18 +++++++----------- code/AssetLib/C4D/C4DImporter.h | 2 ++ 3 files changed, 24 insertions(+), 15 deletions(-) diff --git a/CMakeLists.txt b/CMakeLists.txt index 70399798d..676ef269e 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -563,9 +563,9 @@ SET ( ASSIMP_BUILD_NONFREE_C4D_IMPORTER OFF CACHE BOOL ) IF (ASSIMP_BUILD_NONFREE_C4D_IMPORTER) - IF ( MSVC ) - SET(C4D_INCLUDES "${CMAKE_CURRENT_SOURCE_DIR}/contrib/Cineware/includes") + SET(C4D_INCLUDES "${CMAKE_CURRENT_SOURCE_DIR}/contrib/Cineware/includes") + IF (WIN32) # pick the correct prebuilt library IF(MSVC143) SET(C4D_LIB_POSTFIX "_2022") @@ -583,7 +583,7 @@ IF (ASSIMP_BUILD_NONFREE_C4D_IMPORTER) SET(C4D_LIB_POSTFIX "_2010") ELSE() MESSAGE( FATAL_ERROR - "C4D is currently only supported with MSVC 10, 11, 12, 14, 14.2, 14.3" + "C4D for Windows is currently only supported with MSVC 10, 11, 12, 14, 14.2, 14.3" ) ENDIF() @@ -601,9 +601,20 @@ IF (ASSIMP_BUILD_NONFREE_C4D_IMPORTER) # winsock and winmm are necessary (and undocumented) dependencies of Cineware SDK because # it can be used to communicate with a running Cinema 4D instance SET(C4D_EXTRA_LIBRARIES WSock32.lib Winmm.lib) + ELSEIF (APPLE) + SET(C4D_LIB_BASE_PATH "${CMAKE_CURRENT_SOURCE_DIR}/contrib/Cineware/libraries/osx") + + SET(C4D_DEBUG_LIBRARIES + "${C4D_LIB_BASE_PATH}/debug/libcinewarelib.a" + "${C4D_LIB_BASE_PATH}/debug/libjpeglib.a" + ) + SET(C4D_RELEASE_LIBRARIES + "${C4D_LIB_BASE_PATH}/release/libcinewarelib.a" + "${C4D_LIB_BASE_PATH}/release/libjpeglib.a" + ) ELSE () MESSAGE( FATAL_ERROR - "C4D is currently only available on Windows with Cineware SDK installed in contrib/Cineware" + "C4D is currently only available on Windows and macOS with Cineware SDK installed in contrib/Cineware" ) ENDIF () ELSE () diff --git a/code/AssetLib/C4D/C4DImporter.cpp b/code/AssetLib/C4D/C4DImporter.cpp index c11ec0280..daef6ebe4 100644 --- a/code/AssetLib/C4D/C4DImporter.cpp +++ b/code/AssetLib/C4D/C4DImporter.cpp @@ -46,10 +46,6 @@ OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. // no #ifdefing here, Cinema4D support is carried out in a branch of assimp // where it is turned on in the CMake settings. -#ifndef _MSC_VER -# error C4D support is currently MSVC only -#endif - #include "C4DImporter.h" #include #include @@ -111,7 +107,7 @@ C4DImporter::C4DImporter() = default; C4DImporter::~C4DImporter() = default; // ------------------------------------------------------------------------------------------------ -bool C4DImporter::CanRead( const std::string& pFile, IOSystem* /*pIOHandler*/, bool /*checkSig*/) const { +bool C4DImporter::CanRead( const std::string& pFile, IOSystem* pIOHandler, bool checkSig) const { const std::string& extension = GetExtension(pFile); if (extension == "c4d") { return true; @@ -305,7 +301,7 @@ void C4DImporter::RecurseHierarchy(BaseObject* object, aiNode* parent) { // based on Cineware sample code while (object) { - const LONG type = object->GetType(); + const Int32 type = object->GetType(); const Matrix& ml = object->GetMl(); aiNode* const nd = new aiNode(); @@ -368,8 +364,8 @@ aiMesh* C4DImporter::ReadMesh(BaseObject* object) { PolygonObject* const polyObject = dynamic_cast(object); ai_assert(polyObject != nullptr); - const LONG pointCount = polyObject->GetPointCount(); - const LONG polyCount = polyObject->GetPolygonCount(); + const Int32 pointCount = polyObject->GetPointCount(); + const Int32 polyCount = polyObject->GetPolygonCount(); if(!polyObject || !pointCount) { LogWarn("ignoring mesh with zero vertices or faces"); return nullptr; @@ -391,7 +387,7 @@ aiMesh* C4DImporter::ReadMesh(BaseObject* object) { unsigned int vcount = 0; // first count vertices - for (LONG i = 0; i < polyCount; i++) + for (Int32 i = 0; i < polyCount; i++) { vcount += 3; @@ -434,7 +430,7 @@ aiMesh* C4DImporter::ReadMesh(BaseObject* object) { } // copy vertices and extra channels over and populate faces - for (LONG i = 0; i < polyCount; ++i, ++face) { + for (Int32 i = 0; i < polyCount; ++i, ++face) { ai_assert(polys[i].a < pointCount && polys[i].a >= 0); const Vector& pointA = points[polys[i].a]; verts->x = pointA.x; @@ -511,7 +507,7 @@ aiMesh* C4DImporter::ReadMesh(BaseObject* object) { if (tangents_src) { for(unsigned int k = 0; k < face->mNumIndices; ++k) { - LONG l; + Int32 l; switch(k) { case 0: l = polys[i].a; diff --git a/code/AssetLib/C4D/C4DImporter.h b/code/AssetLib/C4D/C4DImporter.h index c44cf5e37..effd2af09 100644 --- a/code/AssetLib/C4D/C4DImporter.h +++ b/code/AssetLib/C4D/C4DImporter.h @@ -78,6 +78,8 @@ namespace Assimp { // ------------------------------------------------------------------------------------------- class C4DImporter : public BaseImporter, public LogFunctions { public: + C4DImporter(); + ~C4DImporter() override; bool CanRead( const std::string& pFile, IOSystem*, bool checkSig) const override; protected: From 778ce90a04f1ce3c6a9031c99a8e2e445bc7f6b5 Mon Sep 17 00:00:00 2001 From: mosfet80 Date: Sun, 7 Apr 2024 16:49:55 +0200 Subject: [PATCH 60/77] Update hunter into CMakeLists.txt (#5505) Update 'CURL' to v8.5.0 Update 'xxHash' to v0.8.2 Update 're2' to v2023.03.01 docs: Add SHA1 calculation onliner and fix sums docs: fix URLs for FunctionalPlus and PocoCpp ceres-solver: update to 2.2.0-p2 with SuiteSparse v7.5.1-1 SuiteSparse: update to v7.5.1-1 Co-authored-by: Kim Kulling --- CMakeLists.txt | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/CMakeLists.txt b/CMakeLists.txt index 676ef269e..a19bad32e 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -49,8 +49,8 @@ option(ASSIMP_HUNTER_ENABLED "Enable Hunter package manager support" OFF) IF(ASSIMP_HUNTER_ENABLED) include("cmake-modules/HunterGate.cmake") HunterGate( - URL "https://github.com/cpp-pm/hunter/archive/v0.25.3.tar.gz" - SHA1 "3319fe6a3b08090df7df98dee75134d68e2ef5a3" + URL "https://github.com/cpp-pm/hunter/archive/v0.25.5.tar.gz" + SHA1 "a20151e4c0740ee7d0f9994476856d813cdead29" ) add_definitions(-DASSIMP_USE_HUNTER) ENDIF() From 1f920ee1fe396631cd8f5b3467159e8ffd298ee3 Mon Sep 17 00:00:00 2001 From: Tom Heaton <50220137+tomheaton@users.noreply.github.com> Date: Sun, 7 Apr 2024 19:16:48 +0100 Subject: [PATCH 61/77] Update matrix4x4.h (#5507) Co-authored-by: Kim Kulling --- include/assimp/matrix4x4.h | 1 + 1 file changed, 1 insertion(+) diff --git a/include/assimp/matrix4x4.h b/include/assimp/matrix4x4.h index a3a8abe22..861a7acef 100644 --- a/include/assimp/matrix4x4.h +++ b/include/assimp/matrix4x4.h @@ -53,6 +53,7 @@ OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. #include #include +#include #ifdef __cplusplus From 4a3e0e46ac45867c8c8fac9cbcdee3bc30e99f92 Mon Sep 17 00:00:00 2001 From: mosfet80 Date: Sun, 7 Apr 2024 21:24:57 +0200 Subject: [PATCH 62/77] updated json (#5501) fix https://github.com/Tencent/rapidjson/issues/1448 Co-authored-by: Kim Kulling --- .../rapidjson/include/rapidjson/allocators.h | 513 +++++++- .../rapidjson/include/rapidjson/document.h | 446 +++++-- .../rapidjson/include/rapidjson/error/en.h | 70 +- .../rapidjson/include/rapidjson/error/error.h | 85 +- .../include/rapidjson/internal/biginteger.h | 21 +- .../include/rapidjson/internal/diyfp.h | 6 +- .../include/rapidjson/internal/dtoa.h | 10 +- .../include/rapidjson/internal/regex.h | 2 +- .../include/rapidjson/internal/strfunc.h | 14 + .../include/rapidjson/internal/strtod.h | 15 +- contrib/rapidjson/include/rapidjson/pointer.h | 107 +- .../rapidjson/include/rapidjson/rapidjson.h | 89 +- contrib/rapidjson/include/rapidjson/reader.h | 42 +- contrib/rapidjson/include/rapidjson/schema.h | 1120 +++++++++++++---- contrib/rapidjson/include/rapidjson/uri.h | 481 +++++++ contrib/rapidjson/include/rapidjson/writer.h | 13 +- contrib/rapidjson/readme.md | 54 +- 17 files changed, 2615 insertions(+), 473 deletions(-) create mode 100644 contrib/rapidjson/include/rapidjson/uri.h diff --git a/contrib/rapidjson/include/rapidjson/allocators.h b/contrib/rapidjson/include/rapidjson/allocators.h index 44ec5295c..275417bd8 100644 --- a/contrib/rapidjson/include/rapidjson/allocators.h +++ b/contrib/rapidjson/include/rapidjson/allocators.h @@ -16,6 +16,14 @@ #define RAPIDJSON_ALLOCATORS_H_ #include "rapidjson.h" +#include "internal/meta.h" + +#include +#include + +#if RAPIDJSON_HAS_CXX11 +#include +#endif RAPIDJSON_NAMESPACE_BEGIN @@ -89,7 +97,14 @@ public: } return RAPIDJSON_REALLOC(originalPtr, newSize); } - static void Free(void *ptr) { RAPIDJSON_FREE(ptr); } + static void Free(void *ptr) RAPIDJSON_NOEXCEPT { RAPIDJSON_FREE(ptr); } + + bool operator==(const CrtAllocator&) const RAPIDJSON_NOEXCEPT { + return true; + } + bool operator!=(const CrtAllocator&) const RAPIDJSON_NOEXCEPT { + return false; + } }; /////////////////////////////////////////////////////////////////////////////// @@ -113,16 +128,64 @@ public: */ template class MemoryPoolAllocator { + //! Chunk header for perpending to each chunk. + /*! Chunks are stored as a singly linked list. + */ + struct ChunkHeader { + size_t capacity; //!< Capacity of the chunk in bytes (excluding the header itself). + size_t size; //!< Current size of allocated memory in bytes. + ChunkHeader *next; //!< Next chunk in the linked list. + }; + + struct SharedData { + ChunkHeader *chunkHead; //!< Head of the chunk linked-list. Only the head chunk serves allocation. + BaseAllocator* ownBaseAllocator; //!< base allocator created by this object. + size_t refcount; + bool ownBuffer; + }; + + static const size_t SIZEOF_SHARED_DATA = RAPIDJSON_ALIGN(sizeof(SharedData)); + static const size_t SIZEOF_CHUNK_HEADER = RAPIDJSON_ALIGN(sizeof(ChunkHeader)); + + static inline ChunkHeader *GetChunkHead(SharedData *shared) + { + return reinterpret_cast(reinterpret_cast(shared) + SIZEOF_SHARED_DATA); + } + static inline uint8_t *GetChunkBuffer(SharedData *shared) + { + return reinterpret_cast(shared->chunkHead) + SIZEOF_CHUNK_HEADER; + } + + static const size_t kDefaultChunkCapacity = RAPIDJSON_ALLOCATOR_DEFAULT_CHUNK_CAPACITY; //!< Default chunk capacity. + public: static const bool kNeedFree = false; //!< Tell users that no need to call Free() with this allocator. (concept Allocator) + static const bool kRefCounted = true; //!< Tell users that this allocator is reference counted on copy //! Constructor with chunkSize. /*! \param chunkSize The size of memory chunk. The default is kDefaultChunkSize. \param baseAllocator The allocator for allocating memory chunks. */ + explicit MemoryPoolAllocator(size_t chunkSize = kDefaultChunkCapacity, BaseAllocator* baseAllocator = 0) : - chunkHead_(0), chunk_capacity_(chunkSize), userBuffer_(0), baseAllocator_(baseAllocator), ownBaseAllocator_(0) + chunk_capacity_(chunkSize), + baseAllocator_(baseAllocator ? baseAllocator : RAPIDJSON_NEW(BaseAllocator)()), + shared_(static_cast(baseAllocator_ ? baseAllocator_->Malloc(SIZEOF_SHARED_DATA + SIZEOF_CHUNK_HEADER) : 0)) { + RAPIDJSON_ASSERT(baseAllocator_ != 0); + RAPIDJSON_ASSERT(shared_ != 0); + if (baseAllocator) { + shared_->ownBaseAllocator = 0; + } + else { + shared_->ownBaseAllocator = baseAllocator_; + } + shared_->chunkHead = GetChunkHead(shared_); + shared_->chunkHead->capacity = 0; + shared_->chunkHead->size = 0; + shared_->chunkHead->next = 0; + shared_->ownBuffer = true; + shared_->refcount = 1; } //! Constructor with user-supplied buffer. @@ -136,41 +199,101 @@ public: \param baseAllocator The allocator for allocating memory chunks. */ MemoryPoolAllocator(void *buffer, size_t size, size_t chunkSize = kDefaultChunkCapacity, BaseAllocator* baseAllocator = 0) : - chunkHead_(0), chunk_capacity_(chunkSize), userBuffer_(buffer), baseAllocator_(baseAllocator), ownBaseAllocator_(0) + chunk_capacity_(chunkSize), + baseAllocator_(baseAllocator), + shared_(static_cast(AlignBuffer(buffer, size))) { - RAPIDJSON_ASSERT(buffer != 0); - RAPIDJSON_ASSERT(size > sizeof(ChunkHeader)); - chunkHead_ = reinterpret_cast(buffer); - chunkHead_->capacity = size - sizeof(ChunkHeader); - chunkHead_->size = 0; - chunkHead_->next = 0; + RAPIDJSON_ASSERT(size >= SIZEOF_SHARED_DATA + SIZEOF_CHUNK_HEADER); + shared_->chunkHead = GetChunkHead(shared_); + shared_->chunkHead->capacity = size - SIZEOF_SHARED_DATA - SIZEOF_CHUNK_HEADER; + shared_->chunkHead->size = 0; + shared_->chunkHead->next = 0; + shared_->ownBaseAllocator = 0; + shared_->ownBuffer = false; + shared_->refcount = 1; } + MemoryPoolAllocator(const MemoryPoolAllocator& rhs) RAPIDJSON_NOEXCEPT : + chunk_capacity_(rhs.chunk_capacity_), + baseAllocator_(rhs.baseAllocator_), + shared_(rhs.shared_) + { + RAPIDJSON_NOEXCEPT_ASSERT(shared_->refcount > 0); + ++shared_->refcount; + } + MemoryPoolAllocator& operator=(const MemoryPoolAllocator& rhs) RAPIDJSON_NOEXCEPT + { + RAPIDJSON_NOEXCEPT_ASSERT(rhs.shared_->refcount > 0); + ++rhs.shared_->refcount; + this->~MemoryPoolAllocator(); + baseAllocator_ = rhs.baseAllocator_; + chunk_capacity_ = rhs.chunk_capacity_; + shared_ = rhs.shared_; + return *this; + } + +#if RAPIDJSON_HAS_CXX11_RVALUE_REFS + MemoryPoolAllocator(MemoryPoolAllocator&& rhs) RAPIDJSON_NOEXCEPT : + chunk_capacity_(rhs.chunk_capacity_), + baseAllocator_(rhs.baseAllocator_), + shared_(rhs.shared_) + { + RAPIDJSON_NOEXCEPT_ASSERT(rhs.shared_->refcount > 0); + rhs.shared_ = 0; + } + MemoryPoolAllocator& operator=(MemoryPoolAllocator&& rhs) RAPIDJSON_NOEXCEPT + { + RAPIDJSON_NOEXCEPT_ASSERT(rhs.shared_->refcount > 0); + this->~MemoryPoolAllocator(); + baseAllocator_ = rhs.baseAllocator_; + chunk_capacity_ = rhs.chunk_capacity_; + shared_ = rhs.shared_; + rhs.shared_ = 0; + return *this; + } +#endif + //! Destructor. /*! This deallocates all memory chunks, excluding the user-supplied buffer. */ - ~MemoryPoolAllocator() { + ~MemoryPoolAllocator() RAPIDJSON_NOEXCEPT { + if (!shared_) { + // do nothing if moved + return; + } + if (shared_->refcount > 1) { + --shared_->refcount; + return; + } Clear(); - RAPIDJSON_DELETE(ownBaseAllocator_); + BaseAllocator *a = shared_->ownBaseAllocator; + if (shared_->ownBuffer) { + baseAllocator_->Free(shared_); + } + RAPIDJSON_DELETE(a); } - //! Deallocates all memory chunks, excluding the user-supplied buffer. - void Clear() { - while (chunkHead_ && chunkHead_ != userBuffer_) { - ChunkHeader* next = chunkHead_->next; - baseAllocator_->Free(chunkHead_); - chunkHead_ = next; + //! Deallocates all memory chunks, excluding the first/user one. + void Clear() RAPIDJSON_NOEXCEPT { + RAPIDJSON_NOEXCEPT_ASSERT(shared_->refcount > 0); + for (;;) { + ChunkHeader* c = shared_->chunkHead; + if (!c->next) { + break; + } + shared_->chunkHead = c->next; + baseAllocator_->Free(c); } - if (chunkHead_ && chunkHead_ == userBuffer_) - chunkHead_->size = 0; // Clear user buffer + shared_->chunkHead->size = 0; } //! Computes the total capacity of allocated memory chunks. /*! \return total capacity in bytes. */ - size_t Capacity() const { + size_t Capacity() const RAPIDJSON_NOEXCEPT { + RAPIDJSON_NOEXCEPT_ASSERT(shared_->refcount > 0); size_t capacity = 0; - for (ChunkHeader* c = chunkHead_; c != 0; c = c->next) + for (ChunkHeader* c = shared_->chunkHead; c != 0; c = c->next) capacity += c->capacity; return capacity; } @@ -178,25 +301,35 @@ public: //! Computes the memory blocks allocated. /*! \return total used bytes. */ - size_t Size() const { + size_t Size() const RAPIDJSON_NOEXCEPT { + RAPIDJSON_NOEXCEPT_ASSERT(shared_->refcount > 0); size_t size = 0; - for (ChunkHeader* c = chunkHead_; c != 0; c = c->next) + for (ChunkHeader* c = shared_->chunkHead; c != 0; c = c->next) size += c->size; return size; } + //! Whether the allocator is shared. + /*! \return true or false. + */ + bool Shared() const RAPIDJSON_NOEXCEPT { + RAPIDJSON_NOEXCEPT_ASSERT(shared_->refcount > 0); + return shared_->refcount > 1; + } + //! Allocates a memory block. (concept Allocator) void* Malloc(size_t size) { + RAPIDJSON_NOEXCEPT_ASSERT(shared_->refcount > 0); if (!size) return NULL; size = RAPIDJSON_ALIGN(size); - if (chunkHead_ == 0 || chunkHead_->size + size > chunkHead_->capacity) + if (RAPIDJSON_UNLIKELY(shared_->chunkHead->size + size > shared_->chunkHead->capacity)) if (!AddChunk(chunk_capacity_ > size ? chunk_capacity_ : size)) return NULL; - void *buffer = reinterpret_cast(chunkHead_) + RAPIDJSON_ALIGN(sizeof(ChunkHeader)) + chunkHead_->size; - chunkHead_->size += size; + void *buffer = GetChunkBuffer(shared_) + shared_->chunkHead->size; + shared_->chunkHead->size += size; return buffer; } @@ -205,6 +338,7 @@ public: if (originalPtr == 0) return Malloc(newSize); + RAPIDJSON_NOEXCEPT_ASSERT(shared_->refcount > 0); if (newSize == 0) return NULL; @@ -216,10 +350,10 @@ public: return originalPtr; // Simply expand it if it is the last allocation and there is sufficient space - if (originalPtr == reinterpret_cast(chunkHead_) + RAPIDJSON_ALIGN(sizeof(ChunkHeader)) + chunkHead_->size - originalSize) { + if (originalPtr == GetChunkBuffer(shared_) + shared_->chunkHead->size - originalSize) { size_t increment = static_cast(newSize - originalSize); - if (chunkHead_->size + increment <= chunkHead_->capacity) { - chunkHead_->size += increment; + if (shared_->chunkHead->size + increment <= shared_->chunkHead->capacity) { + shared_->chunkHead->size += increment; return originalPtr; } } @@ -235,50 +369,325 @@ public: } //! Frees a memory block (concept Allocator) - static void Free(void *ptr) { (void)ptr; } // Do nothing + static void Free(void *ptr) RAPIDJSON_NOEXCEPT { (void)ptr; } // Do nothing + + //! Compare (equality) with another MemoryPoolAllocator + bool operator==(const MemoryPoolAllocator& rhs) const RAPIDJSON_NOEXCEPT { + RAPIDJSON_NOEXCEPT_ASSERT(shared_->refcount > 0); + RAPIDJSON_NOEXCEPT_ASSERT(rhs.shared_->refcount > 0); + return shared_ == rhs.shared_; + } + //! Compare (inequality) with another MemoryPoolAllocator + bool operator!=(const MemoryPoolAllocator& rhs) const RAPIDJSON_NOEXCEPT { + return !operator==(rhs); + } private: - //! Copy constructor is not permitted. - MemoryPoolAllocator(const MemoryPoolAllocator& rhs) /* = delete */; - //! Copy assignment operator is not permitted. - MemoryPoolAllocator& operator=(const MemoryPoolAllocator& rhs) /* = delete */; - //! Creates a new chunk. /*! \param capacity Capacity of the chunk in bytes. \return true if success. */ bool AddChunk(size_t capacity) { if (!baseAllocator_) - ownBaseAllocator_ = baseAllocator_ = RAPIDJSON_NEW(BaseAllocator)(); - if (ChunkHeader* chunk = reinterpret_cast(baseAllocator_->Malloc(RAPIDJSON_ALIGN(sizeof(ChunkHeader)) + capacity))) { + shared_->ownBaseAllocator = baseAllocator_ = RAPIDJSON_NEW(BaseAllocator)(); + if (ChunkHeader* chunk = static_cast(baseAllocator_->Malloc(SIZEOF_CHUNK_HEADER + capacity))) { chunk->capacity = capacity; chunk->size = 0; - chunk->next = chunkHead_; - chunkHead_ = chunk; + chunk->next = shared_->chunkHead; + shared_->chunkHead = chunk; return true; } else return false; } - static const int kDefaultChunkCapacity = RAPIDJSON_ALLOCATOR_DEFAULT_CHUNK_CAPACITY; //!< Default chunk capacity. + static inline void* AlignBuffer(void* buf, size_t &size) + { + RAPIDJSON_NOEXCEPT_ASSERT(buf != 0); + const uintptr_t mask = sizeof(void*) - 1; + const uintptr_t ubuf = reinterpret_cast(buf); + if (RAPIDJSON_UNLIKELY(ubuf & mask)) { + const uintptr_t abuf = (ubuf + mask) & ~mask; + RAPIDJSON_ASSERT(size >= abuf - ubuf); + buf = reinterpret_cast(abuf); + size -= abuf - ubuf; + } + return buf; + } - //! Chunk header for perpending to each chunk. - /*! Chunks are stored as a singly linked list. - */ - struct ChunkHeader { - size_t capacity; //!< Capacity of the chunk in bytes (excluding the header itself). - size_t size; //!< Current size of allocated memory in bytes. - ChunkHeader *next; //!< Next chunk in the linked list. + size_t chunk_capacity_; //!< The minimum capacity of chunk when they are allocated. + BaseAllocator* baseAllocator_; //!< base allocator for allocating memory chunks. + SharedData *shared_; //!< The shared data of the allocator +}; + +namespace internal { + template + struct IsRefCounted : + public FalseType + { }; + template + struct IsRefCounted::Type> : + public TrueType + { }; +} + +template +inline T* Realloc(A& a, T* old_p, size_t old_n, size_t new_n) +{ + RAPIDJSON_NOEXCEPT_ASSERT(old_n <= (std::numeric_limits::max)() / sizeof(T) && new_n <= (std::numeric_limits::max)() / sizeof(T)); + return static_cast(a.Realloc(old_p, old_n * sizeof(T), new_n * sizeof(T))); +} + +template +inline T *Malloc(A& a, size_t n = 1) +{ + return Realloc(a, NULL, 0, n); +} + +template +inline void Free(A& a, T *p, size_t n = 1) +{ + static_cast(Realloc(a, p, n, 0)); +} + +#ifdef __GNUC__ +RAPIDJSON_DIAG_PUSH +RAPIDJSON_DIAG_OFF(effc++) // std::allocator can safely be inherited +#endif + +template +class StdAllocator : + public std::allocator +{ + typedef std::allocator allocator_type; +#if RAPIDJSON_HAS_CXX11 + typedef std::allocator_traits traits_type; +#else + typedef allocator_type traits_type; +#endif + +public: + typedef BaseAllocator BaseAllocatorType; + + StdAllocator() RAPIDJSON_NOEXCEPT : + allocator_type(), + baseAllocator_() + { } + + StdAllocator(const StdAllocator& rhs) RAPIDJSON_NOEXCEPT : + allocator_type(rhs), + baseAllocator_(rhs.baseAllocator_) + { } + + template + StdAllocator(const StdAllocator& rhs) RAPIDJSON_NOEXCEPT : + allocator_type(rhs), + baseAllocator_(rhs.baseAllocator_) + { } + +#if RAPIDJSON_HAS_CXX11_RVALUE_REFS + StdAllocator(StdAllocator&& rhs) RAPIDJSON_NOEXCEPT : + allocator_type(std::move(rhs)), + baseAllocator_(std::move(rhs.baseAllocator_)) + { } +#endif +#if RAPIDJSON_HAS_CXX11 + using propagate_on_container_move_assignment = std::true_type; + using propagate_on_container_swap = std::true_type; +#endif + + /* implicit */ + StdAllocator(const BaseAllocator& baseAllocator) RAPIDJSON_NOEXCEPT : + allocator_type(), + baseAllocator_(baseAllocator) + { } + + ~StdAllocator() RAPIDJSON_NOEXCEPT + { } + + template + struct rebind { + typedef StdAllocator other; }; - ChunkHeader *chunkHead_; //!< Head of the chunk linked-list. Only the head chunk serves allocation. - size_t chunk_capacity_; //!< The minimum capacity of chunk when they are allocated. - void *userBuffer_; //!< User supplied buffer. - BaseAllocator* baseAllocator_; //!< base allocator for allocating memory chunks. - BaseAllocator* ownBaseAllocator_; //!< base allocator created by this object. + typedef typename traits_type::size_type size_type; + typedef typename traits_type::difference_type difference_type; + + typedef typename traits_type::value_type value_type; + typedef typename traits_type::pointer pointer; + typedef typename traits_type::const_pointer const_pointer; + +#if RAPIDJSON_HAS_CXX11 + + typedef typename std::add_lvalue_reference::type &reference; + typedef typename std::add_lvalue_reference::type>::type &const_reference; + + pointer address(reference r) const RAPIDJSON_NOEXCEPT + { + return std::addressof(r); + } + const_pointer address(const_reference r) const RAPIDJSON_NOEXCEPT + { + return std::addressof(r); + } + + size_type max_size() const RAPIDJSON_NOEXCEPT + { + return traits_type::max_size(*this); + } + + template + void construct(pointer p, Args&&... args) + { + traits_type::construct(*this, p, std::forward(args)...); + } + void destroy(pointer p) + { + traits_type::destroy(*this, p); + } + +#else // !RAPIDJSON_HAS_CXX11 + + typedef typename allocator_type::reference reference; + typedef typename allocator_type::const_reference const_reference; + + pointer address(reference r) const RAPIDJSON_NOEXCEPT + { + return allocator_type::address(r); + } + const_pointer address(const_reference r) const RAPIDJSON_NOEXCEPT + { + return allocator_type::address(r); + } + + size_type max_size() const RAPIDJSON_NOEXCEPT + { + return allocator_type::max_size(); + } + + void construct(pointer p, const_reference r) + { + allocator_type::construct(p, r); + } + void destroy(pointer p) + { + allocator_type::destroy(p); + } + +#endif // !RAPIDJSON_HAS_CXX11 + + template + U* allocate(size_type n = 1, const void* = 0) + { + return RAPIDJSON_NAMESPACE::Malloc(baseAllocator_, n); + } + template + void deallocate(U* p, size_type n = 1) + { + RAPIDJSON_NAMESPACE::Free(baseAllocator_, p, n); + } + + pointer allocate(size_type n = 1, const void* = 0) + { + return allocate(n); + } + void deallocate(pointer p, size_type n = 1) + { + deallocate(p, n); + } + +#if RAPIDJSON_HAS_CXX11 + using is_always_equal = std::is_empty; +#endif + + template + bool operator==(const StdAllocator& rhs) const RAPIDJSON_NOEXCEPT + { + return baseAllocator_ == rhs.baseAllocator_; + } + template + bool operator!=(const StdAllocator& rhs) const RAPIDJSON_NOEXCEPT + { + return !operator==(rhs); + } + + //! rapidjson Allocator concept + static const bool kNeedFree = BaseAllocator::kNeedFree; + static const bool kRefCounted = internal::IsRefCounted::Value; + void* Malloc(size_t size) + { + return baseAllocator_.Malloc(size); + } + void* Realloc(void* originalPtr, size_t originalSize, size_t newSize) + { + return baseAllocator_.Realloc(originalPtr, originalSize, newSize); + } + static void Free(void *ptr) RAPIDJSON_NOEXCEPT + { + BaseAllocator::Free(ptr); + } + +private: + template + friend class StdAllocator; // access to StdAllocator.* + + BaseAllocator baseAllocator_; }; +#if !RAPIDJSON_HAS_CXX17 // std::allocator deprecated in C++17 +template +class StdAllocator : + public std::allocator +{ + typedef std::allocator allocator_type; + +public: + typedef BaseAllocator BaseAllocatorType; + + StdAllocator() RAPIDJSON_NOEXCEPT : + allocator_type(), + baseAllocator_() + { } + + StdAllocator(const StdAllocator& rhs) RAPIDJSON_NOEXCEPT : + allocator_type(rhs), + baseAllocator_(rhs.baseAllocator_) + { } + + template + StdAllocator(const StdAllocator& rhs) RAPIDJSON_NOEXCEPT : + allocator_type(rhs), + baseAllocator_(rhs.baseAllocator_) + { } + + /* implicit */ + StdAllocator(const BaseAllocator& baseAllocator) RAPIDJSON_NOEXCEPT : + allocator_type(), + baseAllocator_(baseAllocator) + { } + + ~StdAllocator() RAPIDJSON_NOEXCEPT + { } + + template + struct rebind { + typedef StdAllocator other; + }; + + typedef typename allocator_type::value_type value_type; + +private: + template + friend class StdAllocator; // access to StdAllocator.* + + BaseAllocator baseAllocator_; +}; +#endif + +#ifdef __GNUC__ +RAPIDJSON_DIAG_POP +#endif + RAPIDJSON_NAMESPACE_END #endif // RAPIDJSON_ENCODINGS_H_ diff --git a/contrib/rapidjson/include/rapidjson/document.h b/contrib/rapidjson/include/rapidjson/document.h index 028235ec6..f183749ad 100644 --- a/contrib/rapidjson/include/rapidjson/document.h +++ b/contrib/rapidjson/include/rapidjson/document.h @@ -42,12 +42,21 @@ RAPIDJSON_DIAG_OFF(4244) // conversion from kXxxFlags to 'uint16_t', possible lo RAPIDJSON_DIAG_OFF(effc++) #endif // __GNUC__ +#ifdef GetObject +// see https://github.com/Tencent/rapidjson/issues/1448 +// a former included windows.h might have defined a macro called GetObject, which affects +// GetObject defined here. This ensures the macro does not get applied +#pragma push_macro("GetObject") +#define RAPIDJSON_WINDOWS_GETOBJECT_WORKAROUND_APPLIED +#undef GetObject +#endif + #ifndef RAPIDJSON_NOMEMBERITERATORCLASS #include // std::random_access_iterator_tag #endif -#if RAPIDJSON_HAS_CXX11_RVALUE_REFS -#include // std::move +#if RAPIDJSON_USE_MEMBERSMAP +#include // std::multimap #endif RAPIDJSON_NAMESPACE_BEGIN @@ -66,7 +75,7 @@ class GenericDocument; User can define this to use CrtAllocator or MemoryPoolAllocator. */ #ifndef RAPIDJSON_DEFAULT_ALLOCATOR -#define RAPIDJSON_DEFAULT_ALLOCATOR MemoryPoolAllocator +#define RAPIDJSON_DEFAULT_ALLOCATOR ::RAPIDJSON_NAMESPACE::MemoryPoolAllocator<::RAPIDJSON_NAMESPACE::CrtAllocator> #endif /*! \def RAPIDJSON_DEFAULT_STACK_ALLOCATOR @@ -76,7 +85,7 @@ class GenericDocument; User can define this to use CrtAllocator or MemoryPoolAllocator. */ #ifndef RAPIDJSON_DEFAULT_STACK_ALLOCATOR -#define RAPIDJSON_DEFAULT_STACK_ALLOCATOR CrtAllocator +#define RAPIDJSON_DEFAULT_STACK_ALLOCATOR ::RAPIDJSON_NAMESPACE::CrtAllocator #endif /*! \def RAPIDJSON_VALUE_DEFAULT_OBJECT_CAPACITY @@ -732,18 +741,8 @@ public: template GenericValue(const GenericValue& rhs, Allocator& allocator, bool copyConstStrings = false) { switch (rhs.GetType()) { - case kObjectType: { - SizeType count = rhs.data_.o.size; - Member* lm = reinterpret_cast(allocator.Malloc(count * sizeof(Member))); - const typename GenericValue::Member* rm = rhs.GetMembersPointer(); - for (SizeType i = 0; i < count; i++) { - new (&lm[i].name) GenericValue(rm[i].name, allocator, copyConstStrings); - new (&lm[i].value) GenericValue(rm[i].value, allocator, copyConstStrings); - } - data_.f.flags = kObjectFlag; - data_.o.size = data_.o.capacity = count; - SetMembersPointer(lm); - } + case kObjectType: + DoCopyMembers(rhs, allocator, copyConstStrings); break; case kArrayType: { SizeType count = rhs.data_.a.size; @@ -879,25 +878,30 @@ public: /*! Need to destruct elements of array, members of object, or copy-string. */ ~GenericValue() { - if (Allocator::kNeedFree) { // Shortcut by Allocator's trait + // With RAPIDJSON_USE_MEMBERSMAP, the maps need to be destroyed to release + // their Allocator if it's refcounted (e.g. MemoryPoolAllocator). + if (Allocator::kNeedFree || (RAPIDJSON_USE_MEMBERSMAP+0 && + internal::IsRefCounted::Value)) { switch(data_.f.flags) { case kArrayFlag: { GenericValue* e = GetElementsPointer(); for (GenericValue* v = e; v != e + data_.a.size; ++v) v->~GenericValue(); - Allocator::Free(e); + if (Allocator::kNeedFree) { // Shortcut by Allocator's trait + Allocator::Free(e); + } } break; case kObjectFlag: - for (MemberIterator m = MemberBegin(); m != MemberEnd(); ++m) - m->~Member(); - Allocator::Free(GetMembersPointer()); + DoFreeMembers(); break; case kCopyStringFlag: - Allocator::Free(const_cast(GetStringPointer())); + if (Allocator::kNeedFree) { // Shortcut by Allocator's trait + Allocator::Free(const_cast(GetStringPointer())); + } break; default: @@ -916,8 +920,13 @@ public: */ GenericValue& operator=(GenericValue& rhs) RAPIDJSON_NOEXCEPT { if (RAPIDJSON_LIKELY(this != &rhs)) { + // Can't destroy "this" before assigning "rhs", otherwise "rhs" + // could be used after free if it's an sub-Value of "this", + // hence the temporary danse. + GenericValue temp; + temp.RawAssign(rhs); this->~GenericValue(); - RawAssign(rhs); + RawAssign(temp); } return *this; } @@ -1024,7 +1033,7 @@ public: return false; for (ConstMemberIterator lhsMemberItr = MemberBegin(); lhsMemberItr != MemberEnd(); ++lhsMemberItr) { typename RhsType::ConstMemberIterator rhsMemberItr = rhs.FindMember(lhsMemberItr->name); - if (rhsMemberItr == rhs.MemberEnd() || lhsMemberItr->value != rhsMemberItr->value) + if (rhsMemberItr == rhs.MemberEnd() || (!(lhsMemberItr->value == rhsMemberItr->value))) return false; } return true; @@ -1033,7 +1042,7 @@ public: if (data_.a.size != rhs.data_.a.size) return false; for (SizeType i = 0; i < data_.a.size; i++) - if ((*this)[i] != rhs[i]) + if (!((*this)[i] == rhs[i])) return false; return true; @@ -1069,6 +1078,7 @@ public: */ template RAPIDJSON_DISABLEIF_RETURN((internal::OrExpr,internal::IsGenericValue >), (bool)) operator==(const T& rhs) const { return *this == GenericValue(rhs); } +#ifndef __cpp_impl_three_way_comparison //! Not-equal-to operator /*! \return !(*this == rhs) */ @@ -1093,6 +1103,7 @@ public: */ template friend RAPIDJSON_DISABLEIF_RETURN((internal::IsGenericValue), (bool)) operator!=(const T& lhs, const GenericValue& rhs) { return !(rhs == lhs); } //@} +#endif //!@name Type //@{ @@ -1219,13 +1230,28 @@ public: else { RAPIDJSON_ASSERT(false); // see above note - // This will generate -Wexit-time-destructors in clang - // static GenericValue NullValue; - // return NullValue; - - // Use static buffer and placement-new to prevent destruction - static char buffer[sizeof(GenericValue)]; +#if RAPIDJSON_HAS_CXX11 + // Use thread-local storage to prevent races between threads. + // Use static buffer and placement-new to prevent destruction, with + // alignas() to ensure proper alignment. + alignas(GenericValue) thread_local static char buffer[sizeof(GenericValue)]; return *new (buffer) GenericValue(); +#elif defined(_MSC_VER) && _MSC_VER < 1900 + // There's no way to solve both thread locality and proper alignment + // simultaneously. + __declspec(thread) static char buffer[sizeof(GenericValue)]; + return *new (buffer) GenericValue(); +#elif defined(__GNUC__) || defined(__clang__) + // This will generate -Wexit-time-destructors in clang, but that's + // better than having under-alignment. + __thread static GenericValue buffer; + return buffer; +#else + // Don't know what compiler this is, so don't know how to ensure + // thread-locality. + static GenericValue buffer; + return buffer; +#endif } } template @@ -1258,10 +1284,7 @@ public: */ GenericValue& MemberReserve(SizeType newCapacity, Allocator &allocator) { RAPIDJSON_ASSERT(IsObject()); - if (newCapacity > data_.o.capacity) { - SetMembersPointer(reinterpret_cast(allocator.Realloc(GetMembersPointer(), data_.o.capacity * sizeof(Member), newCapacity * sizeof(Member)))); - data_.o.capacity = newCapacity; - } + DoReserveMembers(newCapacity, allocator); return *this; } @@ -1335,11 +1358,7 @@ public: MemberIterator FindMember(const GenericValue& name) { RAPIDJSON_ASSERT(IsObject()); RAPIDJSON_ASSERT(name.IsString()); - MemberIterator member = MemberBegin(); - for ( ; member != MemberEnd(); ++member) - if (name.StringEqual(member->name)) - break; - return member; + return DoFindMember(name); } template ConstMemberIterator FindMember(const GenericValue& name) const { return const_cast(*this).FindMember(name); } @@ -1368,14 +1387,7 @@ public: GenericValue& AddMember(GenericValue& name, GenericValue& value, Allocator& allocator) { RAPIDJSON_ASSERT(IsObject()); RAPIDJSON_ASSERT(name.IsString()); - - ObjectData& o = data_.o; - if (o.size >= o.capacity) - MemberReserve(o.capacity == 0 ? kDefaultObjectCapacity : (o.capacity + (o.capacity + 1) / 2), allocator); - Member* members = GetMembersPointer(); - members[o.size].name.RawAssign(name); - members[o.size].value.RawAssign(value); - o.size++; + DoAddMember(name, value, allocator); return *this; } @@ -1509,9 +1521,7 @@ public: */ void RemoveAllMembers() { RAPIDJSON_ASSERT(IsObject()); - for (MemberIterator m = MemberBegin(); m != MemberEnd(); ++m) - m->~Member(); - data_.o.size = 0; + DoClearMembers(); } //! Remove a member in object by its name. @@ -1555,14 +1565,7 @@ public: RAPIDJSON_ASSERT(data_.o.size > 0); RAPIDJSON_ASSERT(GetMembersPointer() != 0); RAPIDJSON_ASSERT(m >= MemberBegin() && m < MemberEnd()); - - MemberIterator last(GetMembersPointer() + (data_.o.size - 1)); - if (data_.o.size > 1 && m != last) - *m = *last; // Move the last one to this place - else - m->~Member(); // Only one left, just destroy - --data_.o.size; - return m; + return DoRemoveMember(m); } //! Remove a member from an object by iterator. @@ -1594,13 +1597,7 @@ public: RAPIDJSON_ASSERT(first >= MemberBegin()); RAPIDJSON_ASSERT(first <= last); RAPIDJSON_ASSERT(last <= MemberEnd()); - - MemberIterator pos = MemberBegin() + (first - MemberBegin()); - for (MemberIterator itr = pos; itr != last; ++itr) - itr->~Member(); - std::memmove(static_cast(&*pos), &*last, static_cast(MemberEnd() - last) * sizeof(Member)); - data_.o.size -= static_cast(last - first); - return pos; + return DoEraseMembers(first, last); } //! Erase a member in object by its name. @@ -1629,7 +1626,9 @@ public: } Object GetObject() { RAPIDJSON_ASSERT(IsObject()); return Object(*this); } + Object GetObj() { RAPIDJSON_ASSERT(IsObject()); return Object(*this); } ConstObject GetObject() const { RAPIDJSON_ASSERT(IsObject()); return ConstObject(*this); } + ConstObject GetObj() const { RAPIDJSON_ASSERT(IsObject()); return ConstObject(*this); } //@} @@ -1851,12 +1850,12 @@ public: //!@name String //@{ - const Ch* GetString() const { RAPIDJSON_ASSERT(IsString()); return (data_.f.flags & kInlineStrFlag) ? data_.ss.str : GetStringPointer(); } + const Ch* GetString() const { RAPIDJSON_ASSERT(IsString()); return DataString(data_); } //! Get the length of string. /*! Since rapidjson permits "\\u0000" in the json string, strlen(v.GetString()) may not equal to v.GetStringLength(). */ - SizeType GetStringLength() const { RAPIDJSON_ASSERT(IsString()); return ((data_.f.flags & kInlineStrFlag) ? (data_.ss.GetLength()) : data_.s.length); } + SizeType GetStringLength() const { RAPIDJSON_ASSERT(IsString()); return DataStringLength(data_); } //! Set this value as a string without copying source string. /*! This version has better performance with supplied length, and also support string containing null character. @@ -1967,7 +1966,7 @@ public: case kArrayType: if (RAPIDJSON_UNLIKELY(!handler.StartArray())) return false; - for (const GenericValue* v = Begin(); v != End(); ++v) + for (ConstValueIterator v = Begin(); v != End(); ++v) if (RAPIDJSON_UNLIKELY(!v->Accept(handler))) return false; return handler.EndArray(data_.a.size); @@ -2105,6 +2104,13 @@ private: Flag f; }; // 16 bytes in 32-bit mode, 24 bytes in 64-bit mode, 16 bytes in 64-bit with RAPIDJSON_48BITPOINTER_OPTIMIZATION + static RAPIDJSON_FORCEINLINE const Ch* DataString(const Data& data) { + return (data.f.flags & kInlineStrFlag) ? data.ss.str : RAPIDJSON_GETPOINTER(Ch, data.s.str); + } + static RAPIDJSON_FORCEINLINE SizeType DataStringLength(const Data& data) { + return (data.f.flags & kInlineStrFlag) ? data.ss.GetLength() : data.s.length; + } + RAPIDJSON_FORCEINLINE const Ch* GetStringPointer() const { return RAPIDJSON_GETPOINTER(Ch, data_.s.str); } RAPIDJSON_FORCEINLINE const Ch* SetStringPointer(const Ch* str) { return RAPIDJSON_SETPOINTER(Ch, data_.s.str, str); } RAPIDJSON_FORCEINLINE GenericValue* GetElementsPointer() const { return RAPIDJSON_GETPOINTER(GenericValue, data_.a.elements); } @@ -2112,6 +2118,286 @@ private: RAPIDJSON_FORCEINLINE Member* GetMembersPointer() const { return RAPIDJSON_GETPOINTER(Member, data_.o.members); } RAPIDJSON_FORCEINLINE Member* SetMembersPointer(Member* members) { return RAPIDJSON_SETPOINTER(Member, data_.o.members, members); } +#if RAPIDJSON_USE_MEMBERSMAP + + struct MapTraits { + struct Less { + bool operator()(const Data& s1, const Data& s2) const { + SizeType n1 = DataStringLength(s1), n2 = DataStringLength(s2); + int cmp = std::memcmp(DataString(s1), DataString(s2), sizeof(Ch) * (n1 < n2 ? n1 : n2)); + return cmp < 0 || (cmp == 0 && n1 < n2); + } + }; + typedef std::pair Pair; + typedef std::multimap > Map; + typedef typename Map::iterator Iterator; + }; + typedef typename MapTraits::Map Map; + typedef typename MapTraits::Less MapLess; + typedef typename MapTraits::Pair MapPair; + typedef typename MapTraits::Iterator MapIterator; + + // + // Layout of the members' map/array, re(al)located according to the needed capacity: + // + // {Map*}<>{capacity}<>{Member[capacity]}<>{MapIterator[capacity]} + // + // (where <> stands for the RAPIDJSON_ALIGN-ment, if needed) + // + + static RAPIDJSON_FORCEINLINE size_t GetMapLayoutSize(SizeType capacity) { + return RAPIDJSON_ALIGN(sizeof(Map*)) + + RAPIDJSON_ALIGN(sizeof(SizeType)) + + RAPIDJSON_ALIGN(capacity * sizeof(Member)) + + capacity * sizeof(MapIterator); + } + + static RAPIDJSON_FORCEINLINE SizeType &GetMapCapacity(Map* &map) { + return *reinterpret_cast(reinterpret_cast(&map) + + RAPIDJSON_ALIGN(sizeof(Map*))); + } + + static RAPIDJSON_FORCEINLINE Member* GetMapMembers(Map* &map) { + return reinterpret_cast(reinterpret_cast(&map) + + RAPIDJSON_ALIGN(sizeof(Map*)) + + RAPIDJSON_ALIGN(sizeof(SizeType))); + } + + static RAPIDJSON_FORCEINLINE MapIterator* GetMapIterators(Map* &map) { + return reinterpret_cast(reinterpret_cast(&map) + + RAPIDJSON_ALIGN(sizeof(Map*)) + + RAPIDJSON_ALIGN(sizeof(SizeType)) + + RAPIDJSON_ALIGN(GetMapCapacity(map) * sizeof(Member))); + } + + static RAPIDJSON_FORCEINLINE Map* &GetMap(Member* members) { + RAPIDJSON_ASSERT(members != 0); + return *reinterpret_cast(reinterpret_cast(members) - + RAPIDJSON_ALIGN(sizeof(SizeType)) - + RAPIDJSON_ALIGN(sizeof(Map*))); + } + + // Some compilers' debug mechanisms want all iterators to be destroyed, for their accounting.. + RAPIDJSON_FORCEINLINE MapIterator DropMapIterator(MapIterator& rhs) { +#if RAPIDJSON_HAS_CXX11 + MapIterator ret = std::move(rhs); +#else + MapIterator ret = rhs; +#endif + rhs.~MapIterator(); + return ret; + } + + Map* &DoReallocMap(Map** oldMap, SizeType newCapacity, Allocator& allocator) { + Map **newMap = static_cast(allocator.Malloc(GetMapLayoutSize(newCapacity))); + GetMapCapacity(*newMap) = newCapacity; + if (!oldMap) { + *newMap = new (allocator.Malloc(sizeof(Map))) Map(MapLess(), allocator); + } + else { + *newMap = *oldMap; + size_t count = (*oldMap)->size(); + std::memcpy(static_cast(GetMapMembers(*newMap)), + static_cast(GetMapMembers(*oldMap)), + count * sizeof(Member)); + MapIterator *oldIt = GetMapIterators(*oldMap), + *newIt = GetMapIterators(*newMap); + while (count--) { + new (&newIt[count]) MapIterator(DropMapIterator(oldIt[count])); + } + Allocator::Free(oldMap); + } + return *newMap; + } + + RAPIDJSON_FORCEINLINE Member* DoAllocMembers(SizeType capacity, Allocator& allocator) { + return GetMapMembers(DoReallocMap(0, capacity, allocator)); + } + + void DoReserveMembers(SizeType newCapacity, Allocator& allocator) { + ObjectData& o = data_.o; + if (newCapacity > o.capacity) { + Member* oldMembers = GetMembersPointer(); + Map **oldMap = oldMembers ? &GetMap(oldMembers) : 0, + *&newMap = DoReallocMap(oldMap, newCapacity, allocator); + RAPIDJSON_SETPOINTER(Member, o.members, GetMapMembers(newMap)); + o.capacity = newCapacity; + } + } + + template + MemberIterator DoFindMember(const GenericValue& name) { + if (Member* members = GetMembersPointer()) { + Map* &map = GetMap(members); + MapIterator mit = map->find(reinterpret_cast(name.data_)); + if (mit != map->end()) { + return MemberIterator(&members[mit->second]); + } + } + return MemberEnd(); + } + + void DoClearMembers() { + if (Member* members = GetMembersPointer()) { + Map* &map = GetMap(members); + MapIterator* mit = GetMapIterators(map); + for (SizeType i = 0; i < data_.o.size; i++) { + map->erase(DropMapIterator(mit[i])); + members[i].~Member(); + } + data_.o.size = 0; + } + } + + void DoFreeMembers() { + if (Member* members = GetMembersPointer()) { + GetMap(members)->~Map(); + for (SizeType i = 0; i < data_.o.size; i++) { + members[i].~Member(); + } + if (Allocator::kNeedFree) { // Shortcut by Allocator's trait + Map** map = &GetMap(members); + Allocator::Free(*map); + Allocator::Free(map); + } + } + } + +#else // !RAPIDJSON_USE_MEMBERSMAP + + RAPIDJSON_FORCEINLINE Member* DoAllocMembers(SizeType capacity, Allocator& allocator) { + return Malloc(allocator, capacity); + } + + void DoReserveMembers(SizeType newCapacity, Allocator& allocator) { + ObjectData& o = data_.o; + if (newCapacity > o.capacity) { + Member* newMembers = Realloc(allocator, GetMembersPointer(), o.capacity, newCapacity); + RAPIDJSON_SETPOINTER(Member, o.members, newMembers); + o.capacity = newCapacity; + } + } + + template + MemberIterator DoFindMember(const GenericValue& name) { + MemberIterator member = MemberBegin(); + for ( ; member != MemberEnd(); ++member) + if (name.StringEqual(member->name)) + break; + return member; + } + + void DoClearMembers() { + for (MemberIterator m = MemberBegin(); m != MemberEnd(); ++m) + m->~Member(); + data_.o.size = 0; + } + + void DoFreeMembers() { + for (MemberIterator m = MemberBegin(); m != MemberEnd(); ++m) + m->~Member(); + Allocator::Free(GetMembersPointer()); + } + +#endif // !RAPIDJSON_USE_MEMBERSMAP + + void DoAddMember(GenericValue& name, GenericValue& value, Allocator& allocator) { + ObjectData& o = data_.o; + if (o.size >= o.capacity) + DoReserveMembers(o.capacity ? (o.capacity + (o.capacity + 1) / 2) : kDefaultObjectCapacity, allocator); + Member* members = GetMembersPointer(); + Member* m = members + o.size; + m->name.RawAssign(name); + m->value.RawAssign(value); +#if RAPIDJSON_USE_MEMBERSMAP + Map* &map = GetMap(members); + MapIterator* mit = GetMapIterators(map); + new (&mit[o.size]) MapIterator(map->insert(MapPair(m->name.data_, o.size))); +#endif + ++o.size; + } + + MemberIterator DoRemoveMember(MemberIterator m) { + ObjectData& o = data_.o; + Member* members = GetMembersPointer(); +#if RAPIDJSON_USE_MEMBERSMAP + Map* &map = GetMap(members); + MapIterator* mit = GetMapIterators(map); + SizeType mpos = static_cast(&*m - members); + map->erase(DropMapIterator(mit[mpos])); +#endif + MemberIterator last(members + (o.size - 1)); + if (o.size > 1 && m != last) { +#if RAPIDJSON_USE_MEMBERSMAP + new (&mit[mpos]) MapIterator(DropMapIterator(mit[&*last - members])); + mit[mpos]->second = mpos; +#endif + *m = *last; // Move the last one to this place + } + else { + m->~Member(); // Only one left, just destroy + } + --o.size; + return m; + } + + MemberIterator DoEraseMembers(ConstMemberIterator first, ConstMemberIterator last) { + ObjectData& o = data_.o; + MemberIterator beg = MemberBegin(), + pos = beg + (first - beg), + end = MemberEnd(); +#if RAPIDJSON_USE_MEMBERSMAP + Map* &map = GetMap(GetMembersPointer()); + MapIterator* mit = GetMapIterators(map); +#endif + for (MemberIterator itr = pos; itr != last; ++itr) { +#if RAPIDJSON_USE_MEMBERSMAP + map->erase(DropMapIterator(mit[itr - beg])); +#endif + itr->~Member(); + } +#if RAPIDJSON_USE_MEMBERSMAP + if (first != last) { + // Move remaining members/iterators + MemberIterator next = pos + (last - first); + for (MemberIterator itr = pos; next != end; ++itr, ++next) { + std::memcpy(static_cast(&*itr), &*next, sizeof(Member)); + SizeType mpos = static_cast(itr - beg); + new (&mit[mpos]) MapIterator(DropMapIterator(mit[next - beg])); + mit[mpos]->second = mpos; + } + } +#else + std::memmove(static_cast(&*pos), &*last, + static_cast(end - last) * sizeof(Member)); +#endif + o.size -= static_cast(last - first); + return pos; + } + + template + void DoCopyMembers(const GenericValue& rhs, Allocator& allocator, bool copyConstStrings) { + RAPIDJSON_ASSERT(rhs.GetType() == kObjectType); + + data_.f.flags = kObjectFlag; + SizeType count = rhs.data_.o.size; + Member* lm = DoAllocMembers(count, allocator); + const typename GenericValue::Member* rm = rhs.GetMembersPointer(); +#if RAPIDJSON_USE_MEMBERSMAP + Map* &map = GetMap(lm); + MapIterator* mit = GetMapIterators(map); +#endif + for (SizeType i = 0; i < count; i++) { + new (&lm[i].name) GenericValue(rm[i].name, allocator, copyConstStrings); + new (&lm[i].value) GenericValue(rm[i].value, allocator, copyConstStrings); +#if RAPIDJSON_USE_MEMBERSMAP + new (&mit[i]) MapIterator(map->insert(MapPair(lm[i].name.data_, i))); +#endif + } + data_.o.size = data_.o.capacity = count; + SetMembersPointer(lm); + } + // Initialize this value as array with initial data, without calling destructor. void SetArrayRaw(GenericValue* values, SizeType count, Allocator& allocator) { data_.f.flags = kArrayFlag; @@ -2129,9 +2415,16 @@ private: void SetObjectRaw(Member* members, SizeType count, Allocator& allocator) { data_.f.flags = kObjectFlag; if (count) { - Member* m = static_cast(allocator.Malloc(count * sizeof(Member))); + Member* m = DoAllocMembers(count, allocator); SetMembersPointer(m); std::memcpy(static_cast(m), members, count * sizeof(Member)); +#if RAPIDJSON_USE_MEMBERSMAP + Map* &map = GetMap(m); + MapIterator* mit = GetMapIterators(map); + for (SizeType i = 0; i < count; i++) { + new (&mit[i]) MapIterator(map->insert(MapPair(m[i].name.data_, i))); + } +#endif } else SetMembersPointer(0); @@ -2208,6 +2501,7 @@ public: typedef typename Encoding::Ch Ch; //!< Character type derived from Encoding. typedef GenericValue ValueType; //!< Value type of the document. typedef Allocator AllocatorType; //!< Allocator type from template parameter. + typedef StackAllocator StackAllocatorType; //!< StackAllocator type from template parameter. //! Constructor /*! Creates an empty document of specified type. @@ -2252,6 +2546,13 @@ public: #endif ~GenericDocument() { + // Clear the ::ValueType before ownAllocator is destroyed, ~ValueType() + // runs last and may access its elements or members which would be freed + // with an allocator like MemoryPoolAllocator (CrtAllocator does not + // free its data when destroyed, but MemoryPoolAllocator does). + if (ownAllocator_) { + ValueType::SetNull(); + } Destroy(); } @@ -2734,4 +3035,9 @@ private: RAPIDJSON_NAMESPACE_END RAPIDJSON_DIAG_POP +#ifdef RAPIDJSON_WINDOWS_GETOBJECT_WORKAROUND_APPLIED +#pragma pop_macro("GetObject") +#undef RAPIDJSON_WINDOWS_GETOBJECT_WORKAROUND_APPLIED +#endif + #endif // RAPIDJSON_DOCUMENT_H_ diff --git a/contrib/rapidjson/include/rapidjson/error/en.h b/contrib/rapidjson/include/rapidjson/error/en.h index 5d2e57b7f..c87b04eb1 100644 --- a/contrib/rapidjson/include/rapidjson/error/en.h +++ b/contrib/rapidjson/include/rapidjson/error/en.h @@ -1,5 +1,5 @@ // Tencent is pleased to support the open source community by making RapidJSON available. -// +// // Copyright (C) 2015 THL A29 Limited, a Tencent company, and Milo Yip. // // Licensed under the MIT License (the "License"); you may not use this file except @@ -7,9 +7,9 @@ // // http://opensource.org/licenses/MIT // -// Unless required by applicable law or agreed to in writing, software distributed -// under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR -// CONDITIONS OF ANY KIND, either express or implied. See the License for the +// Unless required by applicable law or agreed to in writing, software distributed +// under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR +// CONDITIONS OF ANY KIND, either express or implied. See the License for the // specific language governing permissions and limitations under the License. #ifndef RAPIDJSON_ERROR_EN_H_ @@ -39,13 +39,13 @@ inline const RAPIDJSON_ERROR_CHARTYPE* GetParseError_En(ParseErrorCode parseErro case kParseErrorDocumentEmpty: return RAPIDJSON_ERROR_STRING("The document is empty."); case kParseErrorDocumentRootNotSingular: return RAPIDJSON_ERROR_STRING("The document root must not be followed by other values."); - + case kParseErrorValueInvalid: return RAPIDJSON_ERROR_STRING("Invalid value."); - + case kParseErrorObjectMissName: return RAPIDJSON_ERROR_STRING("Missing a name for object member."); case kParseErrorObjectMissColon: return RAPIDJSON_ERROR_STRING("Missing a colon after a name of object member."); case kParseErrorObjectMissCommaOrCurlyBracket: return RAPIDJSON_ERROR_STRING("Missing a comma or '}' after an object member."); - + case kParseErrorArrayMissCommaOrSquareBracket: return RAPIDJSON_ERROR_STRING("Missing a comma or ']' after an array element."); case kParseErrorStringUnicodeEscapeInvalidHex: return RAPIDJSON_ERROR_STRING("Incorrect hex digit after \\u escape in string."); @@ -104,15 +104,69 @@ inline const RAPIDJSON_ERROR_CHARTYPE* GetValidateError_En(ValidateErrorCode val case kValidateErrorType: return RAPIDJSON_ERROR_STRING("Property has a type '%actual' that is not in the following list: '%expected'."); case kValidateErrorOneOf: return RAPIDJSON_ERROR_STRING("Property did not match any of the sub-schemas specified by 'oneOf', refer to following errors."); - case kValidateErrorOneOfMatch: return RAPIDJSON_ERROR_STRING("Property matched more than one of the sub-schemas specified by 'oneOf'."); + case kValidateErrorOneOfMatch: return RAPIDJSON_ERROR_STRING("Property matched more than one of the sub-schemas specified by 'oneOf', indices '%matches'."); case kValidateErrorAllOf: return RAPIDJSON_ERROR_STRING("Property did not match all of the sub-schemas specified by 'allOf', refer to following errors."); case kValidateErrorAnyOf: return RAPIDJSON_ERROR_STRING("Property did not match any of the sub-schemas specified by 'anyOf', refer to following errors."); case kValidateErrorNot: return RAPIDJSON_ERROR_STRING("Property matched the sub-schema specified by 'not'."); + case kValidateErrorReadOnly: return RAPIDJSON_ERROR_STRING("Property is read-only but has been provided when validation is for writing."); + case kValidateErrorWriteOnly: return RAPIDJSON_ERROR_STRING("Property is write-only but has been provided when validation is for reading."); + default: return RAPIDJSON_ERROR_STRING("Unknown error."); } } +//! Maps error code of schema document compilation into error message. +/*! + \ingroup RAPIDJSON_ERRORS + \param schemaErrorCode Error code obtained from compiling the schema document. + \return the error message. + \note User can make a copy of this function for localization. + Using switch-case is safer for future modification of error codes. +*/ + inline const RAPIDJSON_ERROR_CHARTYPE* GetSchemaError_En(SchemaErrorCode schemaErrorCode) { + switch (schemaErrorCode) { + case kSchemaErrorNone: return RAPIDJSON_ERROR_STRING("No error."); + + case kSchemaErrorStartUnknown: return RAPIDJSON_ERROR_STRING("Pointer '%value' to start of schema does not resolve to a location in the document."); + case kSchemaErrorRefPlainName: return RAPIDJSON_ERROR_STRING("$ref fragment '%value' must be a JSON pointer."); + case kSchemaErrorRefInvalid: return RAPIDJSON_ERROR_STRING("$ref must not be an empty string."); + case kSchemaErrorRefPointerInvalid: return RAPIDJSON_ERROR_STRING("$ref fragment '%value' is not a valid JSON pointer at offset '%offset'."); + case kSchemaErrorRefUnknown: return RAPIDJSON_ERROR_STRING("$ref '%value' does not resolve to a location in the target document."); + case kSchemaErrorRefCyclical: return RAPIDJSON_ERROR_STRING("$ref '%value' is cyclical."); + case kSchemaErrorRefNoRemoteProvider: return RAPIDJSON_ERROR_STRING("$ref is remote but there is no remote provider."); + case kSchemaErrorRefNoRemoteSchema: return RAPIDJSON_ERROR_STRING("$ref '%value' is remote but the remote provider did not return a schema."); + case kSchemaErrorRegexInvalid: return RAPIDJSON_ERROR_STRING("Invalid regular expression '%value' in 'pattern' or 'patternProperties'."); + case kSchemaErrorSpecUnknown: return RAPIDJSON_ERROR_STRING("JSON schema draft or OpenAPI version is not recognized."); + case kSchemaErrorSpecUnsupported: return RAPIDJSON_ERROR_STRING("JSON schema draft or OpenAPI version is not supported."); + case kSchemaErrorSpecIllegal: return RAPIDJSON_ERROR_STRING("Both JSON schema draft and OpenAPI version found in document."); + case kSchemaErrorReadOnlyAndWriteOnly: return RAPIDJSON_ERROR_STRING("Property must not be both 'readOnly' and 'writeOnly'."); + + default: return RAPIDJSON_ERROR_STRING("Unknown error."); + } + } + +//! Maps error code of pointer parse into error message. +/*! + \ingroup RAPIDJSON_ERRORS + \param pointerParseErrorCode Error code obtained from pointer parse. + \return the error message. + \note User can make a copy of this function for localization. + Using switch-case is safer for future modification of error codes. +*/ +inline const RAPIDJSON_ERROR_CHARTYPE* GetPointerParseError_En(PointerParseErrorCode pointerParseErrorCode) { + switch (pointerParseErrorCode) { + case kPointerParseErrorNone: return RAPIDJSON_ERROR_STRING("No error."); + + case kPointerParseErrorTokenMustBeginWithSolidus: return RAPIDJSON_ERROR_STRING("A token must begin with a '/'."); + case kPointerParseErrorInvalidEscape: return RAPIDJSON_ERROR_STRING("Invalid escape."); + case kPointerParseErrorInvalidPercentEncoding: return RAPIDJSON_ERROR_STRING("Invalid percent encoding in URI fragment."); + case kPointerParseErrorCharacterMustPercentEncode: return RAPIDJSON_ERROR_STRING("A character must be percent encoded in a URI fragment."); + + default: return RAPIDJSON_ERROR_STRING("Unknown error."); + } +} + RAPIDJSON_NAMESPACE_END #ifdef __clang__ diff --git a/contrib/rapidjson/include/rapidjson/error/error.h b/contrib/rapidjson/include/rapidjson/error/error.h index 6270da11a..cae345db3 100644 --- a/contrib/rapidjson/include/rapidjson/error/error.h +++ b/contrib/rapidjson/include/rapidjson/error/error.h @@ -1,5 +1,5 @@ // Tencent is pleased to support the open source community by making RapidJSON available. -// +// // Copyright (C) 2015 THL A29 Limited, a Tencent company, and Milo Yip. // // Licensed under the MIT License (the "License"); you may not use this file except @@ -7,9 +7,9 @@ // // http://opensource.org/licenses/MIT // -// Unless required by applicable law or agreed to in writing, software distributed -// under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR -// CONDITIONS OF ANY KIND, either express or implied. See the License for the +// Unless required by applicable law or agreed to in writing, software distributed +// under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR +// CONDITIONS OF ANY KIND, either express or implied. See the License for the // specific language governing permissions and limitations under the License. #ifndef RAPIDJSON_ERROR_ERROR_H_ @@ -42,7 +42,7 @@ RAPIDJSON_DIAG_OFF(padded) /////////////////////////////////////////////////////////////////////////////// // RAPIDJSON_ERROR_STRING -//! Macro for converting string literial to \ref RAPIDJSON_ERROR_CHARTYPE[]. +//! Macro for converting string literal to \ref RAPIDJSON_ERROR_CHARTYPE[]. /*! \ingroup RAPIDJSON_ERRORS By default this conversion macro does nothing. On Windows, user can define this macro as \c _T(x) for supporting both @@ -185,14 +185,17 @@ enum ValidateErrorCode { kValidateErrorPatternProperties, //!< See other errors. kValidateErrorDependencies, //!< Object has missing property or schema dependencies. - kValidateErrorEnum, //!< Property has a value that is not one of its allowed enumerated values - kValidateErrorType, //!< Property has a type that is not allowed by the schema.. + kValidateErrorEnum, //!< Property has a value that is not one of its allowed enumerated values. + kValidateErrorType, //!< Property has a type that is not allowed by the schema. kValidateErrorOneOf, //!< Property did not match any of the sub-schemas specified by 'oneOf'. kValidateErrorOneOfMatch, //!< Property matched more than one of the sub-schemas specified by 'oneOf'. kValidateErrorAllOf, //!< Property did not match all of the sub-schemas specified by 'allOf'. kValidateErrorAnyOf, //!< Property did not match any of the sub-schemas specified by 'anyOf'. - kValidateErrorNot //!< Property matched the sub-schema specified by 'not'. + kValidateErrorNot, //!< Property matched the sub-schema specified by 'not'. + + kValidateErrorReadOnly, //!< Property is read-only but has been provided when validation is for writing + kValidateErrorWriteOnly //!< Property is write-only but has been provided when validation is for reading }; //! Function pointer type of GetValidateError(). @@ -207,6 +210,72 @@ enum ValidateErrorCode { */ typedef const RAPIDJSON_ERROR_CHARTYPE* (*GetValidateErrorFunc)(ValidateErrorCode); +/////////////////////////////////////////////////////////////////////////////// +// SchemaErrorCode + +//! Error codes when validating. +/*! \ingroup RAPIDJSON_ERRORS + \see GenericSchemaValidator +*/ +enum SchemaErrorCode { + kSchemaErrorNone = 0, //!< No error. + + kSchemaErrorStartUnknown, //!< Pointer to start of schema does not resolve to a location in the document + kSchemaErrorRefPlainName, //!< $ref fragment must be a JSON pointer + kSchemaErrorRefInvalid, //!< $ref must not be an empty string + kSchemaErrorRefPointerInvalid, //!< $ref fragment is not a valid JSON pointer at offset + kSchemaErrorRefUnknown, //!< $ref does not resolve to a location in the target document + kSchemaErrorRefCyclical, //!< $ref is cyclical + kSchemaErrorRefNoRemoteProvider, //!< $ref is remote but there is no remote provider + kSchemaErrorRefNoRemoteSchema, //!< $ref is remote but the remote provider did not return a schema + kSchemaErrorRegexInvalid, //!< Invalid regular expression in 'pattern' or 'patternProperties' + kSchemaErrorSpecUnknown, //!< JSON schema draft or OpenAPI version is not recognized + kSchemaErrorSpecUnsupported, //!< JSON schema draft or OpenAPI version is not supported + kSchemaErrorSpecIllegal, //!< Both JSON schema draft and OpenAPI version found in document + kSchemaErrorReadOnlyAndWriteOnly //!< Property must not be both 'readOnly' and 'writeOnly' +}; + +//! Function pointer type of GetSchemaError(). +/*! \ingroup RAPIDJSON_ERRORS + + This is the prototype for \c GetSchemaError_X(), where \c X is a locale. + User can dynamically change locale in runtime, e.g.: +\code + GetSchemaErrorFunc GetSchemaError = GetSchemaError_En; // or whatever + const RAPIDJSON_ERROR_CHARTYPE* s = GetSchemaError(validator.GetInvalidSchemaCode()); +\endcode +*/ +typedef const RAPIDJSON_ERROR_CHARTYPE* (*GetSchemaErrorFunc)(SchemaErrorCode); + +/////////////////////////////////////////////////////////////////////////////// +// PointerParseErrorCode + +//! Error code of JSON pointer parsing. +/*! \ingroup RAPIDJSON_ERRORS + \see GenericPointer::GenericPointer, GenericPointer::GetParseErrorCode +*/ +enum PointerParseErrorCode { + kPointerParseErrorNone = 0, //!< The parse is successful + + kPointerParseErrorTokenMustBeginWithSolidus, //!< A token must begin with a '/' + kPointerParseErrorInvalidEscape, //!< Invalid escape + kPointerParseErrorInvalidPercentEncoding, //!< Invalid percent encoding in URI fragment + kPointerParseErrorCharacterMustPercentEncode //!< A character must percent encoded in URI fragment +}; + +//! Function pointer type of GetPointerParseError(). +/*! \ingroup RAPIDJSON_ERRORS + + This is the prototype for \c GetPointerParseError_X(), where \c X is a locale. + User can dynamically change locale in runtime, e.g.: +\code + GetPointerParseErrorFunc GetPointerParseError = GetPointerParseError_En; // or whatever + const RAPIDJSON_ERROR_CHARTYPE* s = GetPointerParseError(pointer.GetParseErrorCode()); +\endcode +*/ +typedef const RAPIDJSON_ERROR_CHARTYPE* (*GetPointerParseErrorFunc)(PointerParseErrorCode); + + RAPIDJSON_NAMESPACE_END #ifdef __clang__ diff --git a/contrib/rapidjson/include/rapidjson/internal/biginteger.h b/contrib/rapidjson/include/rapidjson/internal/biginteger.h index 12455788f..4930043dc 100644 --- a/contrib/rapidjson/include/rapidjson/internal/biginteger.h +++ b/contrib/rapidjson/include/rapidjson/internal/biginteger.h @@ -19,7 +19,11 @@ #if defined(_MSC_VER) && !defined(__INTEL_COMPILER) && defined(_M_AMD64) #include // for _umul128 +#if !defined(_ARM64EC_) #pragma intrinsic(_umul128) +#else +#pragma comment(lib,"softintrin") +#endif #endif RAPIDJSON_NAMESPACE_BEGIN @@ -37,7 +41,8 @@ public: digits_[0] = u; } - BigInteger(const char* decimals, size_t length) : count_(1) { + template + BigInteger(const Ch* decimals, size_t length) : count_(1) { RAPIDJSON_ASSERT(length > 0); digits_[0] = 0; size_t i = 0; @@ -221,7 +226,8 @@ public: bool IsZero() const { return count_ == 1 && digits_[0] == 0; } private: - void AppendDecimal64(const char* begin, const char* end) { + template + void AppendDecimal64(const Ch* begin, const Ch* end) { uint64_t u = ParseUint64(begin, end); if (IsZero()) *this = u; @@ -236,11 +242,12 @@ private: digits_[count_++] = digit; } - static uint64_t ParseUint64(const char* begin, const char* end) { + template + static uint64_t ParseUint64(const Ch* begin, const Ch* end) { uint64_t r = 0; - for (const char* p = begin; p != end; ++p) { - RAPIDJSON_ASSERT(*p >= '0' && *p <= '9'); - r = r * 10u + static_cast(*p - '0'); + for (const Ch* p = begin; p != end; ++p) { + RAPIDJSON_ASSERT(*p >= Ch('0') && *p <= Ch('9')); + r = r * 10u + static_cast(*p - Ch('0')); } return r; } @@ -252,7 +259,7 @@ private: if (low < k) (*outHigh)++; return low; -#elif (__GNUC__ > 4 || (__GNUC__ == 4 && __GNUC_MINOR__ >= 6)) && defined(__x86_64__) +#elif defined(__GNUC__) && (__GNUC__ > 4 || (__GNUC__ == 4 && __GNUC_MINOR__ >= 6)) && defined(__x86_64__) __extension__ typedef unsigned __int128 uint128; uint128 p = static_cast(a) * static_cast(b); p += k; diff --git a/contrib/rapidjson/include/rapidjson/internal/diyfp.h b/contrib/rapidjson/include/rapidjson/internal/diyfp.h index a40797ec2..1f60fb60c 100644 --- a/contrib/rapidjson/include/rapidjson/internal/diyfp.h +++ b/contrib/rapidjson/include/rapidjson/internal/diyfp.h @@ -25,7 +25,11 @@ #if defined(_MSC_VER) && defined(_M_AMD64) && !defined(__INTEL_COMPILER) #include +#if !defined(_ARM64EC_) #pragma intrinsic(_umul128) +#else +#pragma comment(lib,"softintrin") +#endif #endif RAPIDJSON_NAMESPACE_BEGIN @@ -75,7 +79,7 @@ struct DiyFp { if (l & (uint64_t(1) << 63)) // rounding h++; return DiyFp(h, e + rhs.e + 64); -#elif (__GNUC__ > 4 || (__GNUC__ == 4 && __GNUC_MINOR__ >= 6)) && defined(__x86_64__) +#elif defined(__GNUC__) && (__GNUC__ > 4 || (__GNUC__ == 4 && __GNUC_MINOR__ >= 6)) && defined(__x86_64__) __extension__ typedef unsigned __int128 uint128; uint128 p = static_cast(f) * static_cast(rhs.f); uint64_t h = static_cast(p >> 64); diff --git a/contrib/rapidjson/include/rapidjson/internal/dtoa.h b/contrib/rapidjson/include/rapidjson/internal/dtoa.h index 621402fd3..cd456721a 100644 --- a/contrib/rapidjson/include/rapidjson/internal/dtoa.h +++ b/contrib/rapidjson/include/rapidjson/internal/dtoa.h @@ -58,7 +58,11 @@ inline int CountDecimalDigit32(uint32_t n) { } inline void DigitGen(const DiyFp& W, const DiyFp& Mp, uint64_t delta, char* buffer, int* len, int* K) { - static const uint32_t kPow10[] = { 1, 10, 100, 1000, 10000, 100000, 1000000, 10000000, 100000000, 1000000000 }; + static const uint64_t kPow10[] = { 1ULL, 10ULL, 100ULL, 1000ULL, 10000ULL, 100000ULL, 1000000ULL, 10000000ULL, 100000000ULL, + 1000000000ULL, 10000000000ULL, 100000000000ULL, 1000000000000ULL, + 10000000000000ULL, 100000000000000ULL, 1000000000000000ULL, + 10000000000000000ULL, 100000000000000000ULL, 1000000000000000000ULL, + 10000000000000000000ULL }; const DiyFp one(uint64_t(1) << -Mp.e, Mp.e); const DiyFp wp_w = Mp - W; uint32_t p1 = static_cast(Mp.f >> -one.e); @@ -86,7 +90,7 @@ inline void DigitGen(const DiyFp& W, const DiyFp& Mp, uint64_t delta, char* buff uint64_t tmp = (static_cast(p1) << -one.e) + p2; if (tmp <= delta) { *K += kappa; - GrisuRound(buffer, *len, delta, tmp, static_cast(kPow10[kappa]) << -one.e, wp_w.f); + GrisuRound(buffer, *len, delta, tmp, kPow10[kappa] << -one.e, wp_w.f); return; } } @@ -103,7 +107,7 @@ inline void DigitGen(const DiyFp& W, const DiyFp& Mp, uint64_t delta, char* buff if (p2 < delta) { *K += kappa; int index = -kappa; - GrisuRound(buffer, *len, delta, p2, one.f, wp_w.f * (index < 9 ? kPow10[index] : 0)); + GrisuRound(buffer, *len, delta, p2, one.f, wp_w.f * (index < 20 ? kPow10[index] : 0)); return; } } diff --git a/contrib/rapidjson/include/rapidjson/internal/regex.h b/contrib/rapidjson/include/rapidjson/internal/regex.h index 6446c403a..7740dcd52 100644 --- a/contrib/rapidjson/include/rapidjson/internal/regex.h +++ b/contrib/rapidjson/include/rapidjson/internal/regex.h @@ -615,7 +615,7 @@ public: RAPIDJSON_ASSERT(regex_.IsValid()); if (!allocator_) ownAllocator_ = allocator_ = RAPIDJSON_NEW(Allocator)(); - stateSet_ = static_cast(allocator_->Malloc(GetStateSetSize())); + stateSet_ = static_cast(allocator_->Malloc(GetStateSetSize())); state0_.template Reserve(regex_.stateCount_); state1_.template Reserve(regex_.stateCount_); } diff --git a/contrib/rapidjson/include/rapidjson/internal/strfunc.h b/contrib/rapidjson/include/rapidjson/internal/strfunc.h index baecb6cc8..b698a8f43 100644 --- a/contrib/rapidjson/include/rapidjson/internal/strfunc.h +++ b/contrib/rapidjson/include/rapidjson/internal/strfunc.h @@ -45,6 +45,20 @@ inline SizeType StrLen(const wchar_t* s) { return SizeType(std::wcslen(s)); } +//! Custom strcmpn() which works on different character types. +/*! \tparam Ch Character type (e.g. char, wchar_t, short) + \param s1 Null-terminated input string. + \param s2 Null-terminated input string. + \return 0 if equal +*/ +template +inline int StrCmp(const Ch* s1, const Ch* s2) { + RAPIDJSON_ASSERT(s1 != 0); + RAPIDJSON_ASSERT(s2 != 0); + while(*s1 && (*s1 == *s2)) { s1++; s2++; } + return static_cast(*s1) < static_cast(*s2) ? -1 : static_cast(*s1) > static_cast(*s2); +} + //! Returns number of code points in a encoded string. template bool CountStringCodePoint(const typename Encoding::Ch* s, SizeType length, SizeType* outCount) { diff --git a/contrib/rapidjson/include/rapidjson/internal/strtod.h b/contrib/rapidjson/include/rapidjson/internal/strtod.h index d61a67a49..55f0e380b 100644 --- a/contrib/rapidjson/include/rapidjson/internal/strtod.h +++ b/contrib/rapidjson/include/rapidjson/internal/strtod.h @@ -128,17 +128,18 @@ inline bool StrtodFast(double d, int p, double* result) { } // Compute an approximation and see if it is within 1/2 ULP -inline bool StrtodDiyFp(const char* decimals, int dLen, int dExp, double* result) { +template +inline bool StrtodDiyFp(const Ch* decimals, int dLen, int dExp, double* result) { uint64_t significand = 0; int i = 0; // 2^64 - 1 = 18446744073709551615, 1844674407370955161 = 0x1999999999999999 for (; i < dLen; i++) { if (significand > RAPIDJSON_UINT64_C2(0x19999999, 0x99999999) || - (significand == RAPIDJSON_UINT64_C2(0x19999999, 0x99999999) && decimals[i] > '5')) + (significand == RAPIDJSON_UINT64_C2(0x19999999, 0x99999999) && decimals[i] > Ch('5'))) break; - significand = significand * 10u + static_cast(decimals[i] - '0'); + significand = significand * 10u + static_cast(decimals[i] - Ch('0')); } - if (i < dLen && decimals[i] >= '5') // Rounding + if (i < dLen && decimals[i] >= Ch('5')) // Rounding significand++; int remaining = dLen - i; @@ -205,7 +206,8 @@ inline bool StrtodDiyFp(const char* decimals, int dLen, int dExp, double* result return halfWay - static_cast(error) >= precisionBits || precisionBits >= halfWay + static_cast(error); } -inline double StrtodBigInteger(double approx, const char* decimals, int dLen, int dExp) { +template +inline double StrtodBigInteger(double approx, const Ch* decimals, int dLen, int dExp) { RAPIDJSON_ASSERT(dLen >= 0); const BigInteger dInt(decimals, static_cast(dLen)); Double a(approx); @@ -223,7 +225,8 @@ inline double StrtodBigInteger(double approx, const char* decimals, int dLen, in return a.NextPositiveDouble(); } -inline double StrtodFullPrecision(double d, int p, const char* decimals, size_t length, size_t decimalPosition, int exp) { +template +inline double StrtodFullPrecision(double d, int p, const Ch* decimals, size_t length, size_t decimalPosition, int exp) { RAPIDJSON_ASSERT(d >= 0.0); RAPIDJSON_ASSERT(length >= 1); diff --git a/contrib/rapidjson/include/rapidjson/pointer.h b/contrib/rapidjson/include/rapidjson/pointer.h index 90e5903bc..6f4ef3892 100644 --- a/contrib/rapidjson/include/rapidjson/pointer.h +++ b/contrib/rapidjson/include/rapidjson/pointer.h @@ -16,7 +16,9 @@ #define RAPIDJSON_POINTER_H_ #include "document.h" +#include "uri.h" #include "internal/itoa.h" +#include "error/error.h" // PointerParseErrorCode #ifdef __clang__ RAPIDJSON_DIAG_PUSH @@ -30,19 +32,6 @@ RAPIDJSON_NAMESPACE_BEGIN static const SizeType kPointerInvalidIndex = ~SizeType(0); //!< Represents an invalid index in GenericPointer::Token -//! Error code of parsing. -/*! \ingroup RAPIDJSON_ERRORS - \see GenericPointer::GenericPointer, GenericPointer::GetParseErrorCode -*/ -enum PointerParseErrorCode { - kPointerParseErrorNone = 0, //!< The parse is successful - - kPointerParseErrorTokenMustBeginWithSolidus, //!< A token must begin with a '/' - kPointerParseErrorInvalidEscape, //!< Invalid escape - kPointerParseErrorInvalidPercentEncoding, //!< Invalid percent encoding in URI fragment - kPointerParseErrorCharacterMustPercentEncode //!< A character must percent encoded in URI fragment -}; - /////////////////////////////////////////////////////////////////////////////// // GenericPointer @@ -68,10 +57,10 @@ enum PointerParseErrorCode { supplied tokens eliminates these. GenericPointer depends on GenericDocument and GenericValue. - + \tparam ValueType The value type of the DOM tree. E.g. GenericValue > \tparam Allocator The allocator type for allocating memory for internal representation. - + \note GenericPointer uses same encoding of ValueType. However, Allocator of GenericPointer is independent of Allocator of Value. */ @@ -80,8 +69,10 @@ class GenericPointer { public: typedef typename ValueType::EncodingType EncodingType; //!< Encoding type from Value typedef typename ValueType::Ch Ch; //!< Character type from Value + typedef GenericUri UriType; - //! A token is the basic units of internal representation. + + //! A token is the basic units of internal representation. /*! A JSON pointer string representation "/foo/123" is parsed to two tokens: "foo" and 123. 123 will be represented in both numeric form and string form. @@ -163,7 +154,7 @@ public: GenericPointer(const Token* tokens, size_t tokenCount) : allocator_(), ownAllocator_(), nameBuffer_(), tokens_(const_cast(tokens)), tokenCount_(tokenCount), parseErrorOffset_(), parseErrorCode_(kPointerParseErrorNone) {} //! Copy constructor. - GenericPointer(const GenericPointer& rhs) : allocator_(rhs.allocator_), ownAllocator_(), nameBuffer_(), tokens_(), tokenCount_(), parseErrorOffset_(), parseErrorCode_(kPointerParseErrorNone) { + GenericPointer(const GenericPointer& rhs) : allocator_(), ownAllocator_(), nameBuffer_(), tokens_(), tokenCount_(), parseErrorOffset_(), parseErrorCode_(kPointerParseErrorNone) { *this = rhs; } @@ -520,6 +511,70 @@ public: //@} + //!@name Compute URI + //@{ + + //! Compute the in-scope URI for a subtree. + // For use with JSON pointers into JSON schema documents. + /*! + \param root Root value of a DOM sub-tree to be resolved. It can be any value other than document root. + \param rootUri Root URI + \param unresolvedTokenIndex If the pointer cannot resolve a token in the pointer, this parameter can obtain the index of unresolved token. + \param allocator Allocator for Uris + \return Uri if it can be resolved. Otherwise null. + + \note + There are only 3 situations when a URI cannot be resolved: + 1. A value in the path is not an array nor object. + 2. An object value does not contain the token. + 3. A token is out of range of an array value. + + Use unresolvedTokenIndex to retrieve the token index. + */ + UriType GetUri(ValueType& root, const UriType& rootUri, size_t* unresolvedTokenIndex = 0, Allocator* allocator = 0) const { + static const Ch kIdString[] = { 'i', 'd', '\0' }; + static const ValueType kIdValue(kIdString, 2); + UriType base = UriType(rootUri, allocator); + RAPIDJSON_ASSERT(IsValid()); + ValueType* v = &root; + for (const Token *t = tokens_; t != tokens_ + tokenCount_; ++t) { + switch (v->GetType()) { + case kObjectType: + { + // See if we have an id, and if so resolve with the current base + typename ValueType::MemberIterator m = v->FindMember(kIdValue); + if (m != v->MemberEnd() && (m->value).IsString()) { + UriType here = UriType(m->value, allocator).Resolve(base, allocator); + base = here; + } + m = v->FindMember(GenericValue(GenericStringRef(t->name, t->length))); + if (m == v->MemberEnd()) + break; + v = &m->value; + } + continue; + case kArrayType: + if (t->index == kPointerInvalidIndex || t->index >= v->Size()) + break; + v = &((*v)[t->index]); + continue; + default: + break; + } + + // Error: unresolved token + if (unresolvedTokenIndex) + *unresolvedTokenIndex = static_cast(t - tokens_); + return UriType(allocator); + } + return base; + } + + UriType GetUri(const ValueType& root, const UriType& rootUri, size_t* unresolvedTokenIndex = 0, Allocator* allocator = 0) const { + return GetUri(const_cast(root), rootUri, unresolvedTokenIndex, allocator); + } + + //!@name Query value //@{ @@ -634,7 +689,7 @@ public: ValueType& GetWithDefault(GenericDocument& document, const Ch* defaultValue) const { return GetWithDefault(document, defaultValue, document.GetAllocator()); } - + #if RAPIDJSON_HAS_STDSTRING //! Query a value in a document with default std::basic_string. template @@ -835,10 +890,16 @@ private: std::memcpy(nameBuffer_, rhs.nameBuffer_, nameBufferSize * sizeof(Ch)); } - // Adjust pointers to name buffer - std::ptrdiff_t diff = nameBuffer_ - rhs.nameBuffer_; - for (Token *t = tokens_; t != tokens_ + rhs.tokenCount_; ++t) - t->name += diff; + // The names of each token point to a string in the nameBuffer_. The + // previous memcpy copied over string pointers into the rhs.nameBuffer_, + // but they should point to the strings in the new nameBuffer_. + for (size_t i = 0; i < rhs.tokenCount_; ++i) { + // The offset between the string address and the name buffer should + // still be constant, so we can just get this offset and set each new + // token name according the new buffer start + the known offset. + std::ptrdiff_t name_offset = rhs.tokens_[i].name - rhs.nameBuffer_; + tokens_[i].name = nameBuffer_ + name_offset; + } return nameBuffer_ + nameBufferSize; } @@ -928,7 +989,7 @@ private: } i++; - + // Escaping "~0" -> '~', "~1" -> '/' if (c == '~') { if (i < length) { diff --git a/contrib/rapidjson/include/rapidjson/rapidjson.h b/contrib/rapidjson/include/rapidjson/rapidjson.h index 78aa89a0e..5ea694795 100644 --- a/contrib/rapidjson/include/rapidjson/rapidjson.h +++ b/contrib/rapidjson/include/rapidjson/rapidjson.h @@ -1,5 +1,5 @@ // Tencent is pleased to support the open source community by making RapidJSON available. -// +// // Copyright (C) 2015 THL A29 Limited, a Tencent company, and Milo Yip. // // Licensed under the MIT License (the "License"); you may not use this file except @@ -7,9 +7,9 @@ // // http://opensource.org/licenses/MIT // -// Unless required by applicable law or agreed to in writing, software distributed -// under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR -// CONDITIONS OF ANY KIND, either express or implied. See the License for the +// Unless required by applicable law or agreed to in writing, software distributed +// under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR +// CONDITIONS OF ANY KIND, either express or implied. See the License for the // specific language governing permissions and limitations under the License. #ifndef RAPIDJSON_RAPIDJSON_H_ @@ -17,7 +17,7 @@ /*!\file rapidjson.h \brief common definitions and configuration - + \see RAPIDJSON_CONFIG */ @@ -124,6 +124,19 @@ #define RAPIDJSON_NAMESPACE_END } #endif +/////////////////////////////////////////////////////////////////////////////// +// __cplusplus macro + +//!@cond RAPIDJSON_HIDDEN_FROM_DOXYGEN + +#if defined(_MSC_VER) +#define RAPIDJSON_CPLUSPLUS _MSVC_LANG +#else +#define RAPIDJSON_CPLUSPLUS __cplusplus +#endif + +//!@endcond + /////////////////////////////////////////////////////////////////////////////// // RAPIDJSON_HAS_STDSTRING @@ -149,6 +162,24 @@ #include #endif // RAPIDJSON_HAS_STDSTRING +/////////////////////////////////////////////////////////////////////////////// +// RAPIDJSON_USE_MEMBERSMAP + +/*! \def RAPIDJSON_USE_MEMBERSMAP + \ingroup RAPIDJSON_CONFIG + \brief Enable RapidJSON support for object members handling in a \c std::multimap + + By defining this preprocessor symbol to \c 1, \ref rapidjson::GenericValue object + members are stored in a \c std::multimap for faster lookup and deletion times, a + trade off with a slightly slower insertion time and a small object allocat(or)ed + memory overhead. + + \hideinitializer +*/ +#ifndef RAPIDJSON_USE_MEMBERSMAP +#define RAPIDJSON_USE_MEMBERSMAP 0 // not by default +#endif + /////////////////////////////////////////////////////////////////////////////// // RAPIDJSON_NO_INT64DEFINE @@ -164,7 +195,7 @@ */ #ifndef RAPIDJSON_NO_INT64DEFINE //!@cond RAPIDJSON_HIDDEN_FROM_DOXYGEN -#if defined(_MSC_VER) && (_MSC_VER < 1800) // Visual Studio 2013 +#if defined(_MSC_VER) && (_MSC_VER < 1800) // Visual Studio 2013 #include "msinttypes/stdint.h" #include "msinttypes/inttypes.h" #else @@ -246,7 +277,7 @@ # elif defined(RAPIDJSON_DOXYGEN_RUNNING) # define RAPIDJSON_ENDIAN # else -# error Unknown machine endianness detected. User needs to define RAPIDJSON_ENDIAN. +# error Unknown machine endianness detected. User needs to define RAPIDJSON_ENDIAN. # endif #endif // RAPIDJSON_ENDIAN @@ -411,7 +442,7 @@ RAPIDJSON_NAMESPACE_END // Prefer C++11 static_assert, if available #ifndef RAPIDJSON_STATIC_ASSERT -#if __cplusplus >= 201103L || ( defined(_MSC_VER) && _MSC_VER >= 1800 ) +#if RAPIDJSON_CPLUSPLUS >= 201103L || ( defined(_MSC_VER) && _MSC_VER >= 1800 ) #define RAPIDJSON_STATIC_ASSERT(x) \ static_assert(x, RAPIDJSON_STRINGIFY(x)) #endif // C++11 @@ -482,7 +513,7 @@ RAPIDJSON_NAMESPACE_END //!@cond RAPIDJSON_HIDDEN_FROM_DOXYGEN -#define RAPIDJSON_MULTILINEMACRO_BEGIN do { +#define RAPIDJSON_MULTILINEMACRO_BEGIN do { #define RAPIDJSON_MULTILINEMACRO_END \ } while((void)0, 0) @@ -541,8 +572,14 @@ RAPIDJSON_NAMESPACE_END /////////////////////////////////////////////////////////////////////////////// // C++11 features +#ifndef RAPIDJSON_HAS_CXX11 +#define RAPIDJSON_HAS_CXX11 (RAPIDJSON_CPLUSPLUS >= 201103L) +#endif + #ifndef RAPIDJSON_HAS_CXX11_RVALUE_REFS -#if defined(__clang__) +#if RAPIDJSON_HAS_CXX11 +#define RAPIDJSON_HAS_CXX11_RVALUE_REFS 1 +#elif defined(__clang__) #if __has_feature(cxx_rvalue_references) && \ (defined(_MSC_VER) || defined(_LIBCPP_VERSION) || defined(__GLIBCXX__) && __GLIBCXX__ >= 20080306) #define RAPIDJSON_HAS_CXX11_RVALUE_REFS 1 @@ -559,8 +596,14 @@ RAPIDJSON_NAMESPACE_END #endif #endif // RAPIDJSON_HAS_CXX11_RVALUE_REFS +#if RAPIDJSON_HAS_CXX11_RVALUE_REFS +#include // std::move +#endif + #ifndef RAPIDJSON_HAS_CXX11_NOEXCEPT -#if defined(__clang__) +#if RAPIDJSON_HAS_CXX11 +#define RAPIDJSON_HAS_CXX11_NOEXCEPT 1 +#elif defined(__clang__) #define RAPIDJSON_HAS_CXX11_NOEXCEPT __has_feature(cxx_noexcept) #elif (defined(RAPIDJSON_GNUC) && (RAPIDJSON_GNUC >= RAPIDJSON_VERSION_CODE(4,6,0)) && defined(__GXX_EXPERIMENTAL_CXX0X__)) || \ (defined(_MSC_VER) && _MSC_VER >= 1900) || \ @@ -570,11 +613,13 @@ RAPIDJSON_NAMESPACE_END #define RAPIDJSON_HAS_CXX11_NOEXCEPT 0 #endif #endif +#ifndef RAPIDJSON_NOEXCEPT #if RAPIDJSON_HAS_CXX11_NOEXCEPT #define RAPIDJSON_NOEXCEPT noexcept #else -#define RAPIDJSON_NOEXCEPT /* noexcept */ +#define RAPIDJSON_NOEXCEPT throw() #endif // RAPIDJSON_HAS_CXX11_NOEXCEPT +#endif // no automatic detection, yet #ifndef RAPIDJSON_HAS_CXX11_TYPETRAITS @@ -600,9 +645,17 @@ RAPIDJSON_NAMESPACE_END /////////////////////////////////////////////////////////////////////////////// // C++17 features -#if defined(__has_cpp_attribute) -# if __has_cpp_attribute(fallthrough) -# define RAPIDJSON_DELIBERATE_FALLTHROUGH [[fallthrough]] +#ifndef RAPIDJSON_HAS_CXX17 +#define RAPIDJSON_HAS_CXX17 (RAPIDJSON_CPLUSPLUS >= 201703L) +#endif + +#if RAPIDJSON_HAS_CXX17 +# define RAPIDJSON_DELIBERATE_FALLTHROUGH [[fallthrough]] +#elif defined(__has_cpp_attribute) +# if __has_cpp_attribute(clang::fallthrough) +# define RAPIDJSON_DELIBERATE_FALLTHROUGH [[clang::fallthrough]] +# elif __has_cpp_attribute(fallthrough) +# define RAPIDJSON_DELIBERATE_FALLTHROUGH __attribute__((fallthrough)) # else # define RAPIDJSON_DELIBERATE_FALLTHROUGH # endif @@ -628,12 +681,8 @@ RAPIDJSON_NAMESPACE_END #ifndef RAPIDJSON_NOEXCEPT_ASSERT #ifdef RAPIDJSON_ASSERT_THROWS -#if RAPIDJSON_HAS_CXX11_NOEXCEPT -#define RAPIDJSON_NOEXCEPT_ASSERT(x) -#else #include #define RAPIDJSON_NOEXCEPT_ASSERT(x) assert(x) -#endif // RAPIDJSON_HAS_CXX11_NOEXCEPT #else #define RAPIDJSON_NOEXCEPT_ASSERT(x) RAPIDJSON_ASSERT(x) #endif // RAPIDJSON_ASSERT_THROWS @@ -682,7 +731,7 @@ enum Type { kFalseType = 1, //!< false kTrueType = 2, //!< true kObjectType = 3, //!< object - kArrayType = 4, //!< array + kArrayType = 4, //!< array kStringType = 5, //!< string kNumberType = 6 //!< number }; diff --git a/contrib/rapidjson/include/rapidjson/reader.h b/contrib/rapidjson/include/rapidjson/reader.h index 09ace4eba..55546601e 100644 --- a/contrib/rapidjson/include/rapidjson/reader.h +++ b/contrib/rapidjson/include/rapidjson/reader.h @@ -1404,11 +1404,11 @@ private: } #endif // RAPIDJSON_NEON - template + template class NumberStream; - template - class NumberStream { + template + class NumberStream { public: typedef typename InputStream::Ch Ch; @@ -1421,7 +1421,7 @@ private: size_t Tell() { return is.Tell(); } size_t Length() { return 0; } - const char* Pop() { return 0; } + const StackCharacter* Pop() { return 0; } protected: NumberStream& operator=(const NumberStream&); @@ -1429,45 +1429,47 @@ private: InputStream& is; }; - template - class NumberStream : public NumberStream { - typedef NumberStream Base; + template + class NumberStream : public NumberStream { + typedef NumberStream Base; public: - NumberStream(GenericReader& reader, InputStream& is) : Base(reader, is), stackStream(reader.stack_) {} + NumberStream(GenericReader& reader, InputStream& s) : Base(reader, s), stackStream(reader.stack_) {} RAPIDJSON_FORCEINLINE Ch TakePush() { - stackStream.Put(static_cast(Base::is.Peek())); + stackStream.Put(static_cast(Base::is.Peek())); return Base::is.Take(); } - RAPIDJSON_FORCEINLINE void Push(char c) { + RAPIDJSON_FORCEINLINE void Push(StackCharacter c) { stackStream.Put(c); } size_t Length() { return stackStream.Length(); } - const char* Pop() { + const StackCharacter* Pop() { stackStream.Put('\0'); return stackStream.Pop(); } private: - StackStream stackStream; + StackStream stackStream; }; - template - class NumberStream : public NumberStream { - typedef NumberStream Base; + template + class NumberStream : public NumberStream { + typedef NumberStream Base; public: - NumberStream(GenericReader& reader, InputStream& is) : Base(reader, is) {} + NumberStream(GenericReader& reader, InputStream& s) : Base(reader, s) {} RAPIDJSON_FORCEINLINE Ch Take() { return Base::TakePush(); } }; template void ParseNumber(InputStream& is, Handler& handler) { + typedef typename internal::SelectIf, typename TargetEncoding::Ch, char>::Type NumberCharacter; + internal::StreamLocalCopy copy(is); - NumberStream(s.Length()); - StringStream srcStream(s.Pop()); + GenericStringStream > srcStream(s.Pop()); StackStream dstStream(stack_); while (numCharsToCopy--) { - Transcoder, TargetEncoding>::Transcode(srcStream, dstStream); + Transcoder, TargetEncoding>::Transcode(srcStream, dstStream); } dstStream.Put('\0'); const typename TargetEncoding::Ch* str = dstStream.Pop(); @@ -1705,7 +1707,7 @@ private: } else { size_t length = s.Length(); - const char* decimal = s.Pop(); // Pop stack no matter if it will be used or not. + const NumberCharacter* decimal = s.Pop(); // Pop stack no matter if it will be used or not. if (useDouble) { int p = exp + expFrac; diff --git a/contrib/rapidjson/include/rapidjson/schema.h b/contrib/rapidjson/include/rapidjson/schema.h index 11f716096..02a6d0f9e 100644 --- a/contrib/rapidjson/include/rapidjson/schema.h +++ b/contrib/rapidjson/include/rapidjson/schema.h @@ -1,5 +1,5 @@ // Tencent is pleased to support the open source community by making RapidJSON available-> -// +// // Copyright (C) 2015 THL A29 Limited, a Tencent company, and Milo Yip-> All rights reserved-> // // Licensed under the MIT License (the "License"); you may not use this file except @@ -7,9 +7,9 @@ // // http://opensource->org/licenses/MIT // -// Unless required by applicable law or agreed to in writing, software distributed -// under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR -// CONDITIONS OF ANY KIND, either express or implied-> See the License for the +// Unless required by applicable law or agreed to in writing, software distributed +// under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR +// CONDITIONS OF ANY KIND, either express or implied-> See the License for the // specific language governing permissions and limitations under the License-> #ifndef RAPIDJSON_SCHEMA_H_ @@ -19,17 +19,14 @@ #include "pointer.h" #include "stringbuffer.h" #include "error/en.h" +#include "uri.h" #include // abs, floor #if !defined(RAPIDJSON_SCHEMA_USE_INTERNALREGEX) #define RAPIDJSON_SCHEMA_USE_INTERNALREGEX 1 -#else -#define RAPIDJSON_SCHEMA_USE_INTERNALREGEX 0 #endif -#if !RAPIDJSON_SCHEMA_USE_INTERNALREGEX && defined(RAPIDJSON_SCHEMA_USE_STDREGEX) && (__cplusplus >=201103L || (defined(_MSC_VER) && _MSC_VER >= 1800)) -#define RAPIDJSON_SCHEMA_USE_STDREGEX 1 -#else +#if !defined(RAPIDJSON_SCHEMA_USE_STDREGEX) || !(__cplusplus >=201103L || (defined(_MSC_VER) && _MSC_VER >= 1800)) #define RAPIDJSON_SCHEMA_USE_STDREGEX 0 #endif @@ -49,10 +46,6 @@ #define RAPIDJSON_SCHEMA_VERBOSE 0 #endif -#if RAPIDJSON_SCHEMA_VERBOSE -#include "stringbuffer.h" -#endif - RAPIDJSON_DIAG_PUSH #if defined(__GNUC__) @@ -77,48 +70,94 @@ RAPIDJSON_NAMESPACE_BEGIN namespace internal { -inline void PrintInvalidKeyword(const char* keyword) { - printf("Fail keyword: %s\n", keyword); +inline void PrintInvalidKeywordData(const char* keyword) { + printf(" Fail keyword: '%s'\n", keyword); } -inline void PrintInvalidKeyword(const wchar_t* keyword) { - wprintf(L"Fail keyword: %ls\n", keyword); +inline void PrintInvalidKeywordData(const wchar_t* keyword) { + wprintf(L" Fail keyword: '%ls'\n", keyword); } -inline void PrintInvalidDocument(const char* document) { - printf("Fail document: %s\n\n", document); +inline void PrintInvalidDocumentData(const char* document) { + printf(" Fail document: '%s'\n", document); } -inline void PrintInvalidDocument(const wchar_t* document) { - wprintf(L"Fail document: %ls\n\n", document); +inline void PrintInvalidDocumentData(const wchar_t* document) { + wprintf(L" Fail document: '%ls'\n", document); } -inline void PrintValidatorPointers(unsigned depth, const char* s, const char* d) { - printf("S: %*s%s\nD: %*s%s\n\n", depth * 4, " ", s, depth * 4, " ", d); +inline void PrintValidatorPointersData(const char* s, const char* d, unsigned depth) { + printf(" Sch: %*s'%s'\n Doc: %*s'%s'\n", depth * 4, " ", s, depth * 4, " ", d); } -inline void PrintValidatorPointers(unsigned depth, const wchar_t* s, const wchar_t* d) { - wprintf(L"S: %*ls%ls\nD: %*ls%ls\n\n", depth * 4, L" ", s, depth * 4, L" ", d); +inline void PrintValidatorPointersData(const wchar_t* s, const wchar_t* d, unsigned depth) { + wprintf(L" Sch: %*ls'%ls'\n Doc: %*ls'%ls'\n", depth * 4, L" ", s, depth * 4, L" ", d); +} + +inline void PrintSchemaIdsData(const char* base, const char* local, const char* resolved) { + printf(" Resolving id: Base: '%s', Local: '%s', Resolved: '%s'\n", base, local, resolved); +} + +inline void PrintSchemaIdsData(const wchar_t* base, const wchar_t* local, const wchar_t* resolved) { + wprintf(L" Resolving id: Base: '%ls', Local: '%ls', Resolved: '%ls'\n", base, local, resolved); +} + +inline void PrintMethodData(const char* method) { + printf("%s\n", method); +} + +inline void PrintMethodData(const char* method, bool b) { + printf("%s, Data: '%s'\n", method, b ? "true" : "false"); +} + +inline void PrintMethodData(const char* method, int64_t i) { + printf("%s, Data: '%" PRId64 "'\n", method, i); +} + +inline void PrintMethodData(const char* method, uint64_t u) { + printf("%s, Data: '%" PRIu64 "'\n", method, u); +} + +inline void PrintMethodData(const char* method, double d) { + printf("%s, Data: '%lf'\n", method, d); +} + +inline void PrintMethodData(const char* method, const char* s) { + printf("%s, Data: '%s'\n", method, s); +} + +inline void PrintMethodData(const char* method, const wchar_t* s) { + wprintf(L"%hs, Data: '%ls'\n", method, s); +} + +inline void PrintMethodData(const char* method, const char* s1, const char* s2) { + printf("%s, Data: '%s', '%s'\n", method, s1, s2); +} + +inline void PrintMethodData(const char* method, const wchar_t* s1, const wchar_t* s2) { + wprintf(L"%hs, Data: '%ls', '%ls'\n", method, s1, s2); } } // namespace internal #endif // RAPIDJSON_SCHEMA_VERBOSE +#ifndef RAPIDJSON_SCHEMA_PRINT +#if RAPIDJSON_SCHEMA_VERBOSE +#define RAPIDJSON_SCHEMA_PRINT(name, ...) internal::Print##name##Data(__VA_ARGS__) +#else +#define RAPIDJSON_SCHEMA_PRINT(name, ...) +#endif +#endif + /////////////////////////////////////////////////////////////////////////////// // RAPIDJSON_INVALID_KEYWORD_RETURN -#if RAPIDJSON_SCHEMA_VERBOSE -#define RAPIDJSON_INVALID_KEYWORD_VERBOSE(keyword) internal::PrintInvalidKeyword(keyword) -#else -#define RAPIDJSON_INVALID_KEYWORD_VERBOSE(keyword) -#endif - #define RAPIDJSON_INVALID_KEYWORD_RETURN(code)\ RAPIDJSON_MULTILINEMACRO_BEGIN\ context.invalidCode = code;\ context.invalidKeyword = SchemaType::GetValidateErrorKeyword(code).GetString();\ - RAPIDJSON_INVALID_KEYWORD_VERBOSE(context.invalidKeyword);\ + RAPIDJSON_SCHEMA_PRINT(InvalidKeyword, context.invalidKeyword);\ return false;\ RAPIDJSON_MULTILINEMACRO_END @@ -136,14 +175,56 @@ RAPIDJSON_MULTILINEMACRO_END #endif //! Combination of validate flags -/*! \see - */ enum ValidateFlag { kValidateNoFlags = 0, //!< No flags are set. kValidateContinueOnErrorFlag = 1, //!< Don't stop after first validation error. + kValidateReadFlag = 2, //!< Validation is for a read semantic. + kValidateWriteFlag = 4, //!< Validation is for a write semantic. kValidateDefaultFlags = RAPIDJSON_VALIDATE_DEFAULT_FLAGS //!< Default validate flags. Can be customized by defining RAPIDJSON_VALIDATE_DEFAULT_FLAGS }; +/////////////////////////////////////////////////////////////////////////////// +// Specification +enum SchemaDraft { + kDraftUnknown = -1, + kDraftNone = 0, + kDraft03 = 3, + kDraftMin = 4, //!< Current minimum supported draft + kDraft04 = 4, + kDraft05 = 5, + kDraftMax = 5, //!< Current maximum supported draft + kDraft06 = 6, + kDraft07 = 7, + kDraft2019_09 = 8, + kDraft2020_12 = 9 +}; + +enum OpenApiVersion { + kVersionUnknown = -1, + kVersionNone = 0, + kVersionMin = 2, //!< Current minimum supported version + kVersion20 = 2, + kVersion30 = 3, + kVersionMax = 3, //!< Current maximum supported version + kVersion31 = 4, +}; + +struct Specification { + Specification(SchemaDraft d) : draft(d), oapi(kVersionNone) {} + Specification(OpenApiVersion o) : oapi(o) { + if (oapi == kVersion20) draft = kDraft04; + else if (oapi == kVersion30) draft = kDraft05; + else if (oapi == kVersion31) draft = kDraft2020_12; + else draft = kDraft04; + } + ~Specification() {} + bool IsSupported() const { + return ((draft >= kDraftMin && draft <= kDraftMax) && ((oapi == kVersionNone) || (oapi >= kVersionMin && oapi <= kVersionMax))); + } + SchemaDraft draft; + OpenApiVersion oapi; +}; + /////////////////////////////////////////////////////////////////////////////// // Forward declarations @@ -233,8 +314,11 @@ public: virtual void EndDisallowedType(const typename SchemaType::ValueType& actualType) = 0; virtual void NotAllOf(ISchemaValidator** subvalidators, SizeType count) = 0; virtual void NoneOf(ISchemaValidator** subvalidators, SizeType count) = 0; - virtual void NotOneOf(ISchemaValidator** subvalidators, SizeType count, bool matched) = 0; + virtual void NotOneOf(ISchemaValidator** subvalidators, SizeType count) = 0; + virtual void MultipleOneOf(SizeType index1, SizeType index2) = 0; virtual void Disallowed() = 0; + virtual void DisallowedWhenWriting() = 0; + virtual void DisallowedWhenReading() = 0; }; @@ -255,10 +339,10 @@ public: bool Uint(unsigned u) { Number n; n.u.u = u; n.d = static_cast(u); return WriteNumber(n); } bool Int64(int64_t i) { Number n; n.u.i = i; n.d = static_cast(i); return WriteNumber(n); } bool Uint64(uint64_t u) { Number n; n.u.u = u; n.d = static_cast(u); return WriteNumber(n); } - bool Double(double d) { - Number n; + bool Double(double d) { + Number n; if (d < 0) n.u.i = static_cast(d); - else n.u.u = static_cast(d); + else n.u.u = static_cast(d); n.d = d; return WriteNumber(n); } @@ -279,7 +363,9 @@ public: uint64_t h = Hash(0, kObjectType); uint64_t* kv = stack_.template Pop(memberCount * 2); for (SizeType i = 0; i < memberCount; i++) - h ^= Hash(kv[i * 2], kv[i * 2 + 1]); // Use xor to achieve member order insensitive + // Issue #2205 + // Hasing the key to avoid key=value cases with bug-prone zero-value hash + h ^= Hash(Hash(0, kv[i * 2]), kv[i * 2 + 1]); // Use xor to achieve member order insensitive *stack_.template Push() = h; return true; } @@ -317,7 +403,7 @@ private: bool WriteBuffer(Type type, const void* data, size_t len) { // FNV-1a from http://isthe.com/chongo/tech/comp/fnv/ - uint64_t h = Hash(RAPIDJSON_UINT64_C2(0x84222325, 0xcbf29ce4), type); + uint64_t h = Hash(RAPIDJSON_UINT64_C2(0xcbf29ce4, 0x84222325), type); const unsigned char* d = static_cast(data); for (size_t i = 0; i < len; i++) h = Hash(h, d[i]); @@ -352,10 +438,11 @@ struct SchemaValidationContext { kPatternValidatorWithAdditionalProperty }; - SchemaValidationContext(SchemaValidatorFactoryType& f, ErrorHandlerType& eh, const SchemaType* s) : + SchemaValidationContext(SchemaValidatorFactoryType& f, ErrorHandlerType& eh, const SchemaType* s, unsigned fl = 0) : factory(f), error_handler(eh), schema(s), + flags(fl), valueSchema(), invalidKeyword(), invalidCode(), @@ -379,13 +466,19 @@ struct SchemaValidationContext { if (hasher) factory.DestroryHasher(hasher); if (validators) { - for (SizeType i = 0; i < validatorCount; i++) - factory.DestroySchemaValidator(validators[i]); + for (SizeType i = 0; i < validatorCount; i++) { + if (validators[i]) { + factory.DestroySchemaValidator(validators[i]); + } + } factory.FreeState(validators); } if (patternPropertiesValidators) { - for (SizeType i = 0; i < patternPropertiesValidatorCount; i++) - factory.DestroySchemaValidator(patternPropertiesValidators[i]); + for (SizeType i = 0; i < patternPropertiesValidatorCount; i++) { + if (patternPropertiesValidators[i]) { + factory.DestroySchemaValidator(patternPropertiesValidators[i]); + } + } factory.FreeState(patternPropertiesValidators); } if (patternPropertiesSchemas) @@ -397,6 +490,7 @@ struct SchemaValidationContext { SchemaValidatorFactoryType& factory; ErrorHandlerType& error_handler; const SchemaType* schema; + unsigned flags; const SchemaType* valueSchema; const Ch* invalidKeyword; ValidateErrorCode invalidCode; @@ -432,11 +526,14 @@ public: typedef Schema SchemaType; typedef GenericValue SValue; typedef IValidationErrorHandler ErrorHandler; + typedef GenericUri UriType; friend class GenericSchemaDocument; - Schema(SchemaDocumentType* schemaDocument, const PointerType& p, const ValueType& value, const ValueType& document, AllocatorType* allocator) : + Schema(SchemaDocumentType* schemaDocument, const PointerType& p, const ValueType& value, const ValueType& document, AllocatorType* allocator, const UriType& id = UriType()) : allocator_(allocator), uri_(schemaDocument->GetURI(), *allocator), + id_(id, allocator), + spec_(schemaDocument->GetSpecification()), pointer_(p, allocator), typeless_(schemaDocument->GetTypeless()), enum_(), @@ -469,14 +566,43 @@ public: maxLength_(~SizeType(0)), exclusiveMinimum_(false), exclusiveMaximum_(false), - defaultValueLength_(0) + defaultValueLength_(0), + readOnly_(false), + writeOnly_(false), + nullable_(false) { + GenericStringBuffer sb; + p.StringifyUriFragment(sb); + RAPIDJSON_SCHEMA_PRINT(Method, "Schema::Schema", sb.GetString(), id.GetString()); + typedef typename ValueType::ConstValueIterator ConstValueIterator; typedef typename ValueType::ConstMemberIterator ConstMemberIterator; + // PR #1393 + // Early add this Schema and its $ref(s) in schemaDocument's map to avoid infinite + // recursion (with recursive schemas), since schemaDocument->getSchema() is always + // checked before creating a new one. Don't cache typeless_, though. + if (this != typeless_) { + typedef typename SchemaDocumentType::SchemaEntry SchemaEntry; + SchemaEntry *entry = schemaDocument->schemaMap_.template Push(); + new (entry) SchemaEntry(pointer_, this, true, allocator_); + schemaDocument->AddSchemaRefs(this); + } + if (!value.IsObject()) return; + // If we have an id property, resolve it with the in-scope id + // Not supported for open api 2.0 or 3.0 + if (spec_.oapi != kVersion20 && spec_.oapi != kVersion30) + if (const ValueType* v = GetMember(value, GetIdString())) { + if (v->IsString()) { + UriType local(*v, allocator); + id_ = local.Resolve(id_, allocator); + RAPIDJSON_SCHEMA_PRINT(SchemaIds, id.GetString(), v->GetString(), id_.GetString()); + } + } + if (const ValueType* v = GetMember(value, GetTypeString())) { type_ = 0; if (v->IsString()) @@ -490,9 +616,9 @@ public: if (v->IsArray() && v->Size() > 0) { enum_ = static_cast(allocator_->Malloc(sizeof(uint64_t) * v->Size())); for (ConstValueIterator itr = v->Begin(); itr != v->End(); ++itr) { - typedef Hasher > EnumHasherType; + typedef Hasher > EnumHasherType; char buffer[256u + 24]; - MemoryPoolAllocator<> hasherAllocator(buffer, sizeof(buffer)); + MemoryPoolAllocator hasherAllocator(buffer, sizeof(buffer)); EnumHasherType h(&hasherAllocator, 256); itr->Accept(h); enum_[enumCount_++] = h.GetHashCode(); @@ -500,16 +626,19 @@ public: } } - if (schemaDocument) { + if (schemaDocument) AssignIfExist(allOf_, *schemaDocument, p, value, GetAllOfString(), document); + + // AnyOf, OneOf, Not not supported for open api 2.0 + if (schemaDocument && spec_.oapi != kVersion20) { AssignIfExist(anyOf_, *schemaDocument, p, value, GetAnyOfString(), document); AssignIfExist(oneOf_, *schemaDocument, p, value, GetOneOfString(), document); - } - if (const ValueType* v = GetMember(value, GetNotString())) { - schemaDocument->CreateSchema(¬_, p.Append(GetNotString(), allocator_), *v, document); - notValidatorIndex_ = validatorCount_; - validatorCount_++; + if (const ValueType* v = GetMember(value, GetNotString())) { + schemaDocument->CreateSchema(¬_, p.Append(GetNotString(), allocator_), *v, document, id_); + notValidatorIndex_ = validatorCount_; + validatorCount_++; + } } // Object @@ -524,12 +653,14 @@ public: if (properties && properties->IsObject()) for (ConstMemberIterator itr = properties->MemberBegin(); itr != properties->MemberEnd(); ++itr) AddUniqueElement(allProperties, itr->name); - + if (required && required->IsArray()) for (ConstValueIterator itr = required->Begin(); itr != required->End(); ++itr) if (itr->IsString()) AddUniqueElement(allProperties, *itr); + // Dependencies not supported for open api 2.0 and 3.0 + if (spec_.oapi != kVersion20 && spec_.oapi != kVersion30) if (dependencies && dependencies->IsObject()) for (ConstMemberIterator itr = dependencies->MemberBegin(); itr != dependencies->MemberEnd(); ++itr) { AddUniqueElement(allProperties, itr->name); @@ -555,10 +686,12 @@ public: for (ConstMemberIterator itr = properties->MemberBegin(); itr != properties->MemberEnd(); ++itr) { SizeType index; if (FindPropertyIndex(itr->name, &index)) - schemaDocument->CreateSchema(&properties_[index].schema, q.Append(itr->name, allocator_), itr->value, document); + schemaDocument->CreateSchema(&properties_[index].schema, q.Append(itr->name, allocator_), itr->value, document, id_); } } + // PatternProperties not supported for open api 2.0 and 3.0 + if (spec_.oapi != kVersion20 && spec_.oapi != kVersion30) if (const ValueType* v = GetMember(value, GetPatternPropertiesString())) { PointerType q = p.Append(GetPatternPropertiesString(), allocator_); patternProperties_ = static_cast(allocator_->Malloc(sizeof(PatternProperty) * v->MemberCount())); @@ -566,8 +699,9 @@ public: for (ConstMemberIterator itr = v->MemberBegin(); itr != v->MemberEnd(); ++itr) { new (&patternProperties_[patternPropertyCount_]) PatternProperty(); - patternProperties_[patternPropertyCount_].pattern = CreatePattern(itr->name); - schemaDocument->CreateSchema(&patternProperties_[patternPropertyCount_].schema, q.Append(itr->name, allocator_), itr->value, document); + PointerType r = q.Append(itr->name, allocator_); + patternProperties_[patternPropertyCount_].pattern = CreatePattern(itr->name, schemaDocument, r); + schemaDocument->CreateSchema(&patternProperties_[patternPropertyCount_].schema, r, itr->value, document, id_); patternPropertyCount_++; } } @@ -582,6 +716,8 @@ public: } } + // Dependencies not supported for open api 2.0 and 3.0 + if (spec_.oapi != kVersion20 && spec_.oapi != kVersion30) if (dependencies && dependencies->IsObject()) { PointerType q = p.Append(GetDependenciesString(), allocator_); hasDependencies_ = true; @@ -599,7 +735,7 @@ public: } else if (itr->value.IsObject()) { hasSchemaDependencies_ = true; - schemaDocument->CreateSchema(&properties_[sourceIndex].dependenciesSchema, q.Append(itr->name, allocator_), itr->value, document); + schemaDocument->CreateSchema(&properties_[sourceIndex].dependenciesSchema, q.Append(itr->name, allocator_), itr->value, document, id_); properties_[sourceIndex].dependenciesValidatorIndex = validatorCount_; validatorCount_++; } @@ -611,7 +747,7 @@ public: if (v->IsBool()) additionalProperties_ = v->GetBool(); else if (v->IsObject()) - schemaDocument->CreateSchema(&additionalPropertiesSchema_, p.Append(GetAdditionalPropertiesString(), allocator_), *v, document); + schemaDocument->CreateSchema(&additionalPropertiesSchema_, p.Append(GetAdditionalPropertiesString(), allocator_), *v, document, id_); } AssignIfExist(minProperties_, value, GetMinPropertiesString()); @@ -621,23 +757,25 @@ public: if (const ValueType* v = GetMember(value, GetItemsString())) { PointerType q = p.Append(GetItemsString(), allocator_); if (v->IsObject()) // List validation - schemaDocument->CreateSchema(&itemsList_, q, *v, document); + schemaDocument->CreateSchema(&itemsList_, q, *v, document, id_); else if (v->IsArray()) { // Tuple validation itemsTuple_ = static_cast(allocator_->Malloc(sizeof(const Schema*) * v->Size())); SizeType index = 0; for (ConstValueIterator itr = v->Begin(); itr != v->End(); ++itr, index++) - schemaDocument->CreateSchema(&itemsTuple_[itemsTupleCount_++], q.Append(index, allocator_), *itr, document); + schemaDocument->CreateSchema(&itemsTuple_[itemsTupleCount_++], q.Append(index, allocator_), *itr, document, id_); } } AssignIfExist(minItems_, value, GetMinItemsString()); AssignIfExist(maxItems_, value, GetMaxItemsString()); + // AdditionalItems not supported for openapi 2.0 and 3.0 + if (spec_.oapi != kVersion20 && spec_.oapi != kVersion30) if (const ValueType* v = GetMember(value, GetAdditionalItemsString())) { if (v->IsBool()) additionalItems_ = v->GetBool(); else if (v->IsObject()) - schemaDocument->CreateSchema(&additionalItemsSchema_, p.Append(GetAdditionalItemsString(), allocator_), *v, document); + schemaDocument->CreateSchema(&additionalItemsSchema_, p.Append(GetAdditionalItemsString(), allocator_), *v, document, id_); } AssignIfExist(uniqueItems_, value, GetUniqueItemsString()); @@ -647,7 +785,7 @@ public: AssignIfExist(maxLength_, value, GetMaxLengthString()); if (const ValueType* v = GetMember(value, GetPatternString())) - pattern_ = CreatePattern(*v); + pattern_ = CreatePattern(*v, schemaDocument, p.Append(GetPatternString(), allocator_)); // Number if (const ValueType* v = GetMember(value, GetMinimumString())) @@ -670,6 +808,23 @@ public: if (v->IsString()) defaultValueLength_ = v->GetStringLength(); + // ReadOnly - open api only (until draft 7 supported) + // WriteOnly - open api 3 only (until draft 7 supported) + // Both can't be true + if (spec_.oapi != kVersionNone) + AssignIfExist(readOnly_, value, GetReadOnlyString()); + if (spec_.oapi >= kVersion30) + AssignIfExist(writeOnly_, value, GetWriteOnlyString()); + if (readOnly_ && writeOnly_) + schemaDocument->SchemaError(kSchemaErrorReadOnlyAndWriteOnly, p); + + // Nullable - open api 3 only + // If true add 'null' as allowable type + if (spec_.oapi >= kVersion30) { + AssignIfExist(nullable_, value, GetNullableString()); + if (nullable_) + AddType(GetNullString()); + } } ~Schema() { @@ -697,11 +852,20 @@ public: return uri_; } + const UriType& GetId() const { + return id_; + } + + const Specification& GetSpecification() const { + return spec_; + } + const PointerType& GetPointer() const { return pointer_; } bool BeginValue(Context& context) const { + RAPIDJSON_SCHEMA_PRINT(Method, "Schema::BeginValue"); if (context.inArray) { if (uniqueItems_) context.valueUniqueness = true; @@ -733,6 +897,8 @@ public: } RAPIDJSON_FORCEINLINE bool EndValue(Context& context) const { + RAPIDJSON_SCHEMA_PRINT(Method, "Schema::EndValue"); + // Only check pattern properties if we have validators if (context.patternPropertiesValidatorCount > 0) { bool otherValid = false; SizeType count = context.patternPropertiesValidatorCount; @@ -775,87 +941,98 @@ public: foundEnum:; } - if (allOf_.schemas) - for (SizeType i = allOf_.begin; i < allOf_.begin + allOf_.count; i++) - if (!context.validators[i]->IsValid()) { - context.error_handler.NotAllOf(&context.validators[allOf_.begin], allOf_.count); - RAPIDJSON_INVALID_KEYWORD_RETURN(kValidateErrorAllOf); - } - - if (anyOf_.schemas) { - for (SizeType i = anyOf_.begin; i < anyOf_.begin + anyOf_.count; i++) - if (context.validators[i]->IsValid()) - goto foundAny; - context.error_handler.NoneOf(&context.validators[anyOf_.begin], anyOf_.count); - RAPIDJSON_INVALID_KEYWORD_RETURN(kValidateErrorAnyOf); - foundAny:; - } + // Only check allOf etc if we have validators + if (context.validatorCount > 0) { + if (allOf_.schemas) + for (SizeType i = allOf_.begin; i < allOf_.begin + allOf_.count; i++) + if (!context.validators[i]->IsValid()) { + context.error_handler.NotAllOf(&context.validators[allOf_.begin], allOf_.count); + RAPIDJSON_INVALID_KEYWORD_RETURN(kValidateErrorAllOf); + } - if (oneOf_.schemas) { - bool oneValid = false; - for (SizeType i = oneOf_.begin; i < oneOf_.begin + oneOf_.count; i++) - if (context.validators[i]->IsValid()) { - if (oneValid) { - context.error_handler.NotOneOf(&context.validators[oneOf_.begin], oneOf_.count, true); - RAPIDJSON_INVALID_KEYWORD_RETURN(kValidateErrorOneOfMatch); - } else - oneValid = true; - } - if (!oneValid) { - context.error_handler.NotOneOf(&context.validators[oneOf_.begin], oneOf_.count, false); - RAPIDJSON_INVALID_KEYWORD_RETURN(kValidateErrorOneOf); + if (anyOf_.schemas) { + for (SizeType i = anyOf_.begin; i < anyOf_.begin + anyOf_.count; i++) + if (context.validators[i]->IsValid()) + goto foundAny; + context.error_handler.NoneOf(&context.validators[anyOf_.begin], anyOf_.count); + RAPIDJSON_INVALID_KEYWORD_RETURN(kValidateErrorAnyOf); + foundAny:; } - } - if (not_ && context.validators[notValidatorIndex_]->IsValid()) { - context.error_handler.Disallowed(); - RAPIDJSON_INVALID_KEYWORD_RETURN(kValidateErrorNot); + if (oneOf_.schemas) { + bool oneValid = false; + SizeType firstMatch = 0; + for (SizeType i = oneOf_.begin; i < oneOf_.begin + oneOf_.count; i++) + if (context.validators[i]->IsValid()) { + if (oneValid) { + context.error_handler.MultipleOneOf(firstMatch, i - oneOf_.begin); + RAPIDJSON_INVALID_KEYWORD_RETURN(kValidateErrorOneOfMatch); + } else { + oneValid = true; + firstMatch = i - oneOf_.begin; + } + } + if (!oneValid) { + context.error_handler.NotOneOf(&context.validators[oneOf_.begin], oneOf_.count); + RAPIDJSON_INVALID_KEYWORD_RETURN(kValidateErrorOneOf); + } + } + + if (not_ && context.validators[notValidatorIndex_]->IsValid()) { + context.error_handler.Disallowed(); + RAPIDJSON_INVALID_KEYWORD_RETURN(kValidateErrorNot); + } } return true; } bool Null(Context& context) const { + RAPIDJSON_SCHEMA_PRINT(Method, "Schema::Null"); if (!(type_ & (1 << kNullSchemaType))) { DisallowedType(context, GetNullString()); RAPIDJSON_INVALID_KEYWORD_RETURN(kValidateErrorType); } return CreateParallelValidator(context); } - - bool Bool(Context& context, bool) const { - if (!(type_ & (1 << kBooleanSchemaType))) { - DisallowedType(context, GetBooleanString()); - RAPIDJSON_INVALID_KEYWORD_RETURN(kValidateErrorType); - } + + bool Bool(Context& context, bool b) const { + RAPIDJSON_SCHEMA_PRINT(Method, "Schema::Bool", b); + if (!CheckBool(context, b)) + return false; return CreateParallelValidator(context); } bool Int(Context& context, int i) const { + RAPIDJSON_SCHEMA_PRINT(Method, "Schema::Int", (int64_t)i); if (!CheckInt(context, i)) return false; return CreateParallelValidator(context); } bool Uint(Context& context, unsigned u) const { + RAPIDJSON_SCHEMA_PRINT(Method, "Schema::Uint", (uint64_t)u); if (!CheckUint(context, u)) return false; return CreateParallelValidator(context); } bool Int64(Context& context, int64_t i) const { + RAPIDJSON_SCHEMA_PRINT(Method, "Schema::Int64", i); if (!CheckInt(context, i)) return false; return CreateParallelValidator(context); } bool Uint64(Context& context, uint64_t u) const { + RAPIDJSON_SCHEMA_PRINT(Method, "Schema::Uint64", u); if (!CheckUint(context, u)) return false; return CreateParallelValidator(context); } bool Double(Context& context, double d) const { + RAPIDJSON_SCHEMA_PRINT(Method, "Schema::Double", d); if (!(type_ & (1 << kNumberSchemaType))) { DisallowedType(context, GetNumberString()); RAPIDJSON_INVALID_KEYWORD_RETURN(kValidateErrorType); @@ -866,14 +1043,15 @@ public: if (!maximum_.IsNull() && !CheckDoubleMaximum(context, d)) return false; - + if (!multipleOf_.IsNull() && !CheckDoubleMultipleOf(context, d)) return false; - + return CreateParallelValidator(context); } - + bool String(Context& context, const Ch* str, SizeType length, bool) const { + RAPIDJSON_SCHEMA_PRINT(Method, "Schema::String", str); if (!(type_ & (1 << kStringSchemaType))) { DisallowedType(context, GetStringString()); RAPIDJSON_INVALID_KEYWORD_RETURN(kValidateErrorType); @@ -902,6 +1080,7 @@ public: } bool StartObject(Context& context) const { + RAPIDJSON_SCHEMA_PRINT(Method, "Schema::StartObject"); if (!(type_ & (1 << kObjectSchemaType))) { DisallowedType(context, GetObjectString()); RAPIDJSON_INVALID_KEYWORD_RETURN(kValidateErrorType); @@ -921,8 +1100,10 @@ public: return CreateParallelValidator(context); } - + bool Key(Context& context, const Ch* str, SizeType len, bool) const { + RAPIDJSON_SCHEMA_PRINT(Method, "Schema::Key", str); + if (patternProperties_) { context.patternPropertiesSchemaCount = 0; for (SizeType i = 0; i < patternPropertyCount_; i++) @@ -949,7 +1130,7 @@ public: } if (additionalPropertiesSchema_) { - if (additionalPropertiesSchema_ && context.patternPropertiesSchemaCount > 0) { + if (context.patternPropertiesSchemaCount > 0) { context.patternPropertiesSchemas[context.patternPropertiesSchemaCount++] = additionalPropertiesSchema_; context.valueSchema = typeless_; context.valuePatternValidatorType = Context::kPatternValidatorWithAdditionalProperty; @@ -974,6 +1155,7 @@ public: } bool EndObject(Context& context, SizeType memberCount) const { + RAPIDJSON_SCHEMA_PRINT(Method, "Schema::EndObject"); if (hasRequired_) { context.error_handler.StartMissingProperties(); for (SizeType index = 0; index < propertyCount_; index++) @@ -1014,13 +1196,14 @@ public: } } if (context.error_handler.EndDependencyErrors()) - RAPIDJSON_INVALID_KEYWORD_RETURN(kValidateErrorDependencies); + RAPIDJSON_INVALID_KEYWORD_RETURN(kValidateErrorDependencies); } return true; } bool StartArray(Context& context) const { + RAPIDJSON_SCHEMA_PRINT(Method, "Schema::StartArray"); context.arrayElementIndex = 0; context.inArray = true; // Ensure we note that we are in an array @@ -1033,13 +1216,14 @@ public: } bool EndArray(Context& context, SizeType elementCount) const { + RAPIDJSON_SCHEMA_PRINT(Method, "Schema::EndArray"); context.inArray = false; - + if (elementCount < minItems_) { context.error_handler.TooFewItems(elementCount, minItems_); RAPIDJSON_INVALID_KEYWORD_RETURN(kValidateErrorMinItems); } - + if (elementCount > maxItems_) { context.error_handler.TooManyItems(elementCount, maxItems_); RAPIDJSON_INVALID_KEYWORD_RETURN(kValidateErrorMaxItems); @@ -1081,6 +1265,9 @@ public: case kValidateErrorAnyOf: return GetAnyOfString(); case kValidateErrorNot: return GetNotString(); + case kValidateErrorReadOnly: return GetReadOnlyString(); + case kValidateErrorWriteOnly: return GetWriteOnlyString(); + default: return GetNullString(); } } @@ -1128,6 +1315,14 @@ public: RAPIDJSON_STRING_(ExclusiveMaximum, 'e', 'x', 'c', 'l', 'u', 's', 'i', 'v', 'e', 'M', 'a', 'x', 'i', 'm', 'u', 'm') RAPIDJSON_STRING_(MultipleOf, 'm', 'u', 'l', 't', 'i', 'p', 'l', 'e', 'O', 'f') RAPIDJSON_STRING_(DefaultValue, 'd', 'e', 'f', 'a', 'u', 'l', 't') + RAPIDJSON_STRING_(Schema, '$', 's', 'c', 'h', 'e', 'm', 'a') + RAPIDJSON_STRING_(Ref, '$', 'r', 'e', 'f') + RAPIDJSON_STRING_(Id, 'i', 'd') + RAPIDJSON_STRING_(Swagger, 's', 'w', 'a', 'g', 'g', 'e', 'r') + RAPIDJSON_STRING_(OpenApi, 'o', 'p', 'e', 'n', 'a', 'p', 'i') + RAPIDJSON_STRING_(ReadOnly, 'r', 'e', 'a', 'd', 'O', 'n', 'l', 'y') + RAPIDJSON_STRING_(WriteOnly, 'w', 'r', 'i', 't', 'e', 'O', 'n', 'l', 'y') + RAPIDJSON_STRING_(Nullable, 'n', 'u', 'l', 'l', 'a', 'b', 'l', 'e') #undef RAPIDJSON_STRING_ @@ -1193,7 +1388,7 @@ private: out.schemas = static_cast(allocator_->Malloc(out.count * sizeof(const Schema*))); memset(out.schemas, 0, sizeof(Schema*)* out.count); for (SizeType i = 0; i < out.count; i++) - schemaDocument.CreateSchema(&out.schemas[i], q.Append(i, allocator_), (*v)[i], document); + schemaDocument.CreateSchema(&out.schemas[i], q.Append(i, allocator_), (*v)[i], document, id_); out.begin = validatorCount_; validatorCount_ += out.count; } @@ -1202,10 +1397,11 @@ private: #if RAPIDJSON_SCHEMA_USE_INTERNALREGEX template - RegexType* CreatePattern(const ValueType& value) { + RegexType* CreatePattern(const ValueType& value, SchemaDocumentType* sd, const PointerType& p) { if (value.IsString()) { RegexType* r = new (allocator_->Malloc(sizeof(RegexType))) RegexType(value.GetString(), allocator_); if (!r->IsValid()) { + sd->SchemaErrorValue(kSchemaErrorRegexInvalid, p, value.GetString(), value.GetStringLength()); r->~RegexType(); AllocatorType::Free(r); r = 0; @@ -1221,13 +1417,14 @@ private: } #elif RAPIDJSON_SCHEMA_USE_STDREGEX template - RegexType* CreatePattern(const ValueType& value) { + RegexType* CreatePattern(const ValueType& value, SchemaDocumentType* sd, const PointerType& p) { if (value.IsString()) { RegexType *r = static_cast(allocator_->Malloc(sizeof(RegexType))); try { return new (r) RegexType(value.GetString(), std::size_t(value.GetStringLength()), std::regex_constants::ECMAScript); } - catch (const std::regex_error&) { + catch (const std::regex_error& e) { + sd->SchemaErrorValue(kSchemaErrorRegexInvalid, p, value.GetString(), value.GetStringLength()); AllocatorType::Free(r); } } @@ -1240,7 +1437,9 @@ private: } #else template - RegexType* CreatePattern(const ValueType&) { return 0; } + RegexType* CreatePattern(const ValueType&) { + return 0; + } static bool IsPatternMatch(const RegexType*, const Ch *, SizeType) { return true; } #endif // RAPIDJSON_SCHEMA_USE_STDREGEX @@ -1255,6 +1454,9 @@ private: else if (type == GetNumberString() ) type_ |= (1 << kNumberSchemaType) | (1 << kIntegerSchemaType); } + // Creates parallel validators for allOf, anyOf, oneOf, not and schema dependencies, if required. + // Also creates a hasher for enums and array uniqueness, if required. + // Also a useful place to add type-independent error checks. bool CreateParallelValidator(Context& context) const { if (enum_ || context.arrayUniqueness) context.hasher = context.factory.CreateHasher(); @@ -1262,6 +1464,7 @@ private: if (validatorCount_) { RAPIDJSON_ASSERT(context.validators == 0); context.validators = static_cast(context.factory.MallocState(sizeof(ISchemaValidator*) * validatorCount_)); + std::memset(context.validators, 0, sizeof(ISchemaValidator*) * validatorCount_); context.validatorCount = validatorCount_; // Always return after first failure for these sub-validators @@ -1270,10 +1473,10 @@ private: if (anyOf_.schemas) CreateSchemaValidators(context, anyOf_, false); - + if (oneOf_.schemas) CreateSchemaValidators(context, oneOf_, false); - + if (not_) context.validators[notValidatorIndex_] = context.factory.CreateSchemaValidator(*not_, false); @@ -1284,6 +1487,16 @@ private: } } + // Add any other type-independent checks here + if (readOnly_ && (context.flags & kValidateWriteFlag)) { + context.error_handler.DisallowedWhenWriting(); + RAPIDJSON_INVALID_KEYWORD_RETURN(kValidateErrorReadOnly); + } + if (writeOnly_ && (context.flags & kValidateReadFlag)) { + context.error_handler.DisallowedWhenReading(); + RAPIDJSON_INVALID_KEYWORD_RETURN(kValidateErrorWriteOnly); + } + return true; } @@ -1297,7 +1510,7 @@ private: SizeType len = name.GetStringLength(); const Ch* str = name.GetString(); for (SizeType index = 0; index < propertyCount_; index++) - if (properties_[index].name.GetStringLength() == len && + if (properties_[index].name.GetStringLength() == len && (std::memcmp(properties_[index].name.GetString(), str, sizeof(Ch) * len) == 0)) { *outIndex = index; @@ -1306,6 +1519,14 @@ private: return false; } + bool CheckBool(Context& context, bool) const { + if (!(type_ & (1 << kBooleanSchemaType))) { + DisallowedType(context, GetBooleanString()); + RAPIDJSON_INVALID_KEYWORD_RETURN(kValidateErrorType); + } + return true; + } + bool CheckInt(Context& context, int64_t i) const { if (!(type_ & ((1 << kIntegerSchemaType) | (1 << kNumberSchemaType)))) { DisallowedType(context, GetIntegerString()); @@ -1420,9 +1641,13 @@ private: bool CheckDoubleMultipleOf(Context& context, double d) const { double a = std::abs(d), b = std::abs(multipleOf_.GetDouble()); - double q = std::floor(a / b); - double r = a - q * b; - if (r > 0.0) { + double q = a / b; + double qRounded = std::floor(q + 0.5); + double scaledEpsilon = (q + qRounded) * std::numeric_limits::epsilon(); + double difference = std::abs(qRounded - q); + bool isMultiple = (difference <= scaledEpsilon) + || (difference < std::numeric_limits::min()); + if (!isMultiple) { context.error_handler.NotMultipleOf(d, multipleOf_); RAPIDJSON_INVALID_KEYWORD_RETURN(kValidateErrorMultipleOf); } @@ -1458,7 +1683,7 @@ private: struct PatternProperty { PatternProperty() : schema(), pattern() {} - ~PatternProperty() { + ~PatternProperty() { if (pattern) { pattern->~RegexType(); AllocatorType::Free(pattern); @@ -1470,6 +1695,8 @@ private: AllocatorType* allocator_; SValue uri_; + UriType id_; + Specification spec_; PointerType pointer_; const SchemaType* typeless_; uint64_t* enum_; @@ -1512,8 +1739,12 @@ private: SValue multipleOf_; bool exclusiveMinimum_; bool exclusiveMaximum_; - + SizeType defaultValueLength_; + + bool readOnly_; + bool writeOnly_; + bool nullable_; }; template @@ -1555,9 +1786,18 @@ template class IGenericRemoteSchemaDocumentProvider { public: typedef typename SchemaDocumentType::Ch Ch; + typedef typename SchemaDocumentType::ValueType ValueType; + typedef typename SchemaDocumentType::AllocatorType AllocatorType; virtual ~IGenericRemoteSchemaDocumentProvider() {} virtual const SchemaDocumentType* GetRemoteDocument(const Ch* uri, SizeType length) = 0; + virtual const SchemaDocumentType* GetRemoteDocument(const GenericUri uri, Specification& spec) { + // Default implementation just calls through for compatibility + // Following line suppresses unused parameter warning + (void)spec; + // printf("GetRemoteDocument: %d %d\n", spec.draft, spec.oapi); + return GetRemoteDocument(uri.GetBaseString(), uri.GetBaseStringLength()); + } }; /////////////////////////////////////////////////////////////////////////////// @@ -1582,7 +1822,9 @@ public: typedef typename EncodingType::Ch Ch; typedef internal::Schema SchemaType; typedef GenericPointer PointerType; - typedef GenericValue URIType; + typedef GenericValue GValue; + typedef GenericUri UriType; + typedef GenericStringRef StringRefType; friend class internal::Schema; template friend class GenericSchemaValidator; @@ -1596,46 +1838,53 @@ public: \param uriLength Length of \c name, in code points. \param remoteProvider An optional remote schema document provider for resolving remote reference. Can be null. \param allocator An optional allocator instance for allocating memory. Can be null. + \param pointer An optional JSON pointer to the start of the schema document + \param spec Optional schema draft or OpenAPI version. Used if no specification in document. Defaults to draft-04. */ explicit GenericSchemaDocument(const ValueType& document, const Ch* uri = 0, SizeType uriLength = 0, - IRemoteSchemaDocumentProviderType* remoteProvider = 0, Allocator* allocator = 0) : + IRemoteSchemaDocumentProviderType* remoteProvider = 0, Allocator* allocator = 0, + const PointerType& pointer = PointerType(), // PR #1393 + const Specification& spec = Specification(kDraft04)) : remoteProvider_(remoteProvider), allocator_(allocator), ownAllocator_(), root_(), typeless_(), schemaMap_(allocator, kInitialSchemaMapSize), - schemaRef_(allocator, kInitialSchemaRefSize) + schemaRef_(allocator, kInitialSchemaRefSize), + spec_(spec), + error_(kObjectType), + currentError_() { + RAPIDJSON_SCHEMA_PRINT(Method, "GenericSchemaDocument::GenericSchemaDocument"); if (!allocator_) ownAllocator_ = allocator_ = RAPIDJSON_NEW(Allocator)(); Ch noUri[1] = {0}; uri_.SetString(uri ? uri : noUri, uriLength, *allocator_); + docId_ = UriType(uri_, allocator_); typeless_ = static_cast(allocator_->Malloc(sizeof(SchemaType))); - new (typeless_) SchemaType(this, PointerType(), ValueType(kObjectType).Move(), ValueType(kObjectType).Move(), allocator_); + new (typeless_) SchemaType(this, PointerType(), ValueType(kObjectType).Move(), ValueType(kObjectType).Move(), allocator_, docId_); + + // Establish the schema draft or open api version. + // We only ever look for '$schema' or 'swagger' or 'openapi' at the root of the document. + SetSchemaSpecification(document); // Generate root schema, it will call CreateSchema() to create sub-schemas, - // And call AddRefSchema() if there are $ref. - CreateSchemaRecursive(&root_, PointerType(), document, document); - - // Resolve $ref - while (!schemaRef_.Empty()) { - SchemaRefEntry* refEntry = schemaRef_.template Pop(1); - if (const SchemaType* s = GetSchema(refEntry->target)) { - if (refEntry->schema) - *refEntry->schema = s; - - // Create entry in map if not exist - if (!GetSchema(refEntry->source)) { - new (schemaMap_.template Push()) SchemaEntry(refEntry->source, const_cast(s), false, allocator_); - } - } - else if (refEntry->schema) - *refEntry->schema = typeless_; - - refEntry->~SchemaRefEntry(); + // And call HandleRefSchema() if there are $ref. + // PR #1393 use input pointer if supplied + root_ = typeless_; + if (pointer.GetTokenCount() == 0) { + CreateSchemaRecursive(&root_, pointer, document, document, docId_); + } + else if (const ValueType* v = pointer.Get(document)) { + CreateSchema(&root_, pointer, *v, document, docId_); + } + else { + GenericStringBuffer sb; + pointer.StringifyUriFragment(sb); + SchemaErrorValue(kSchemaErrorStartUnknown, PointerType(), sb.GetString(), static_cast(sb.GetSize() / sizeof(Ch))); } RAPIDJSON_ASSERT(root_ != 0); @@ -1653,7 +1902,11 @@ public: typeless_(rhs.typeless_), schemaMap_(std::move(rhs.schemaMap_)), schemaRef_(std::move(rhs.schemaRef_)), - uri_(std::move(rhs.uri_)) + uri_(std::move(rhs.uri_)), + docId_(std::move(rhs.docId_)), + spec_(rhs.spec_), + error_(std::move(rhs.error_)), + currentError_(std::move(rhs.currentError_)) { rhs.remoteProvider_ = 0; rhs.allocator_ = 0; @@ -1672,26 +1925,87 @@ public: Allocator::Free(typeless_); } + // these may contain some allocator data so clear before deleting ownAllocator_ + uri_.SetNull(); + error_.SetNull(); + currentError_.SetNull(); + RAPIDJSON_DELETE(ownAllocator_); } - const URIType& GetURI() const { return uri_; } + const GValue& GetURI() const { return uri_; } + + const Specification& GetSpecification() const { return spec_; } + bool IsSupportedSpecification() const { return spec_.IsSupported(); } + + //! Static method to get the specification of any schema document + // Returns kDraftNone if document is silent + static const Specification GetSpecification(const ValueType& document) { + SchemaDraft draft = GetSchemaDraft(document); + if (draft != kDraftNone) + return Specification(draft); + else { + OpenApiVersion oapi = GetOpenApiVersion(document); + if (oapi != kVersionNone) + return Specification(oapi); + } + return Specification(kDraftNone); + } //! Get the root schema. const SchemaType& GetRoot() const { return *root_; } -private: + //! Gets the error object. + GValue& GetError() { return error_; } + const GValue& GetError() const { return error_; } + + static const StringRefType& GetSchemaErrorKeyword(SchemaErrorCode schemaErrorCode) { + switch (schemaErrorCode) { + case kSchemaErrorStartUnknown: return GetStartUnknownString(); + case kSchemaErrorRefPlainName: return GetRefPlainNameString(); + case kSchemaErrorRefInvalid: return GetRefInvalidString(); + case kSchemaErrorRefPointerInvalid: return GetRefPointerInvalidString(); + case kSchemaErrorRefUnknown: return GetRefUnknownString(); + case kSchemaErrorRefCyclical: return GetRefCyclicalString(); + case kSchemaErrorRefNoRemoteProvider: return GetRefNoRemoteProviderString(); + case kSchemaErrorRefNoRemoteSchema: return GetRefNoRemoteSchemaString(); + case kSchemaErrorRegexInvalid: return GetRegexInvalidString(); + case kSchemaErrorSpecUnknown: return GetSpecUnknownString(); + case kSchemaErrorSpecUnsupported: return GetSpecUnsupportedString(); + case kSchemaErrorSpecIllegal: return GetSpecIllegalString(); + case kSchemaErrorReadOnlyAndWriteOnly: return GetReadOnlyAndWriteOnlyString(); + default: return GetNullString(); + } + } + + //! Default error method + void SchemaError(const SchemaErrorCode code, const PointerType& location) { + currentError_ = GValue(kObjectType); + AddCurrentError(code, location); + } + + //! Method for error with single string value insert + void SchemaErrorValue(const SchemaErrorCode code, const PointerType& location, const Ch* value, SizeType length) { + currentError_ = GValue(kObjectType); + currentError_.AddMember(GetValueString(), GValue(value, length, *allocator_).Move(), *allocator_); + AddCurrentError(code, location); + } + + //! Method for error with invalid pointer + void SchemaErrorPointer(const SchemaErrorCode code, const PointerType& location, const Ch* value, SizeType length, const PointerType& pointer) { + currentError_ = GValue(kObjectType); + currentError_.AddMember(GetValueString(), GValue(value, length, *allocator_).Move(), *allocator_); + currentError_.AddMember(GetOffsetString(), static_cast(pointer.GetParseErrorOffset() / sizeof(Ch)), *allocator_); + AddCurrentError(code, location); + } + + private: //! Prohibit copying GenericSchemaDocument(const GenericSchemaDocument&); //! Prohibit assignment GenericSchemaDocument& operator=(const GenericSchemaDocument&); - struct SchemaRefEntry { - SchemaRefEntry(const PointerType& s, const PointerType& t, const SchemaType** outSchema, Allocator *allocator) : source(s, allocator), target(t, allocator), schema(outSchema) {} - PointerType source; - PointerType target; - const SchemaType** schema; - }; + typedef const PointerType* SchemaRefPtr; // PR #1393 struct SchemaEntry { SchemaEntry(const PointerType& p, SchemaType* s, bool o, Allocator* allocator) : pointer(p, allocator), schema(s), owned(o) {} @@ -1706,79 +2020,361 @@ private: bool owned; }; - void CreateSchemaRecursive(const SchemaType** schema, const PointerType& pointer, const ValueType& v, const ValueType& document) { - if (schema) - *schema = typeless_; + void AddErrorInstanceLocation(GValue& result, const PointerType& location) { + GenericStringBuffer sb; + location.StringifyUriFragment(sb); + GValue instanceRef(sb.GetString(), static_cast(sb.GetSize() / sizeof(Ch)), *allocator_); + result.AddMember(GetInstanceRefString(), instanceRef, *allocator_); + } + void AddError(GValue& keyword, GValue& error) { + typename GValue::MemberIterator member = error_.FindMember(keyword); + if (member == error_.MemberEnd()) + error_.AddMember(keyword, error, *allocator_); + else { + if (member->value.IsObject()) { + GValue errors(kArrayType); + errors.PushBack(member->value, *allocator_); + member->value = errors; + } + member->value.PushBack(error, *allocator_); + } + } + + void AddCurrentError(const SchemaErrorCode code, const PointerType& location) { + RAPIDJSON_SCHEMA_PRINT(InvalidKeyword, GetSchemaErrorKeyword(code)); + currentError_.AddMember(GetErrorCodeString(), code, *allocator_); + AddErrorInstanceLocation(currentError_, location); + AddError(GValue(GetSchemaErrorKeyword(code)).Move(), currentError_); + } + +#define RAPIDJSON_STRING_(name, ...) \ + static const StringRefType& Get##name##String() {\ + static const Ch s[] = { __VA_ARGS__, '\0' };\ + static const StringRefType v(s, static_cast(sizeof(s) / sizeof(Ch) - 1)); \ + return v;\ + } + + RAPIDJSON_STRING_(InstanceRef, 'i', 'n', 's', 't', 'a', 'n', 'c', 'e', 'R', 'e', 'f') + RAPIDJSON_STRING_(ErrorCode, 'e', 'r', 'r', 'o', 'r', 'C', 'o', 'd', 'e') + RAPIDJSON_STRING_(Value, 'v', 'a', 'l', 'u', 'e') + RAPIDJSON_STRING_(Offset, 'o', 'f', 'f', 's', 'e', 't') + + RAPIDJSON_STRING_(Null, 'n', 'u', 'l', 'l') + RAPIDJSON_STRING_(SpecUnknown, 'S', 'p', 'e', 'c', 'U', 'n', 'k', 'n', 'o', 'w', 'n') + RAPIDJSON_STRING_(SpecUnsupported, 'S', 'p', 'e', 'c', 'U', 'n', 's', 'u', 'p', 'p', 'o', 'r', 't', 'e', 'd') + RAPIDJSON_STRING_(SpecIllegal, 'S', 'p', 'e', 'c', 'I', 'l', 'l', 'e', 'g', 'a', 'l') + RAPIDJSON_STRING_(StartUnknown, 'S', 't', 'a', 'r', 't', 'U', 'n', 'k', 'n', 'o', 'w', 'n') + RAPIDJSON_STRING_(RefPlainName, 'R', 'e', 'f', 'P', 'l', 'a', 'i', 'n', 'N', 'a', 'm', 'e') + RAPIDJSON_STRING_(RefInvalid, 'R', 'e', 'f', 'I', 'n', 'v', 'a', 'l', 'i', 'd') + RAPIDJSON_STRING_(RefPointerInvalid, 'R', 'e', 'f', 'P', 'o', 'i', 'n', 't', 'e', 'r', 'I', 'n', 'v', 'a', 'l', 'i', 'd') + RAPIDJSON_STRING_(RefUnknown, 'R', 'e', 'f', 'U', 'n', 'k', 'n', 'o', 'w', 'n') + RAPIDJSON_STRING_(RefCyclical, 'R', 'e', 'f', 'C', 'y', 'c', 'l', 'i', 'c', 'a', 'l') + RAPIDJSON_STRING_(RefNoRemoteProvider, 'R', 'e', 'f', 'N', 'o', 'R', 'e', 'm', 'o', 't', 'e', 'P', 'r', 'o', 'v', 'i', 'd', 'e', 'r') + RAPIDJSON_STRING_(RefNoRemoteSchema, 'R', 'e', 'f', 'N', 'o', 'R', 'e', 'm', 'o', 't', 'e', 'S', 'c', 'h', 'e', 'm', 'a') + RAPIDJSON_STRING_(ReadOnlyAndWriteOnly, 'R', 'e', 'a', 'd', 'O', 'n', 'l', 'y', 'A', 'n', 'd', 'W', 'r', 'i', 't', 'e', 'O', 'n', 'l', 'y') + RAPIDJSON_STRING_(RegexInvalid, 'R', 'e', 'g', 'e', 'x', 'I', 'n', 'v', 'a', 'l', 'i', 'd') + +#undef RAPIDJSON_STRING_ + + // Static method to get schema draft of any schema document + static SchemaDraft GetSchemaDraft(const ValueType& document) { + static const Ch kDraft03String[] = { 'h', 't', 't', 'p', ':', '/', '/', 'j', 's', 'o', 'n', '-', 's', 'c', 'h', 'e', 'm', 'a', '.', 'o', 'r', 'g', '/', 'd', 'r', 'a', 'f', 't', '-', '0', '3', '/', 's', 'c', 'h', 'e', 'm', 'a', '#', '\0' }; + static const Ch kDraft04String[] = { 'h', 't', 't', 'p', ':', '/', '/', 'j', 's', 'o', 'n', '-', 's', 'c', 'h', 'e', 'm', 'a', '.', 'o', 'r', 'g', '/', 'd', 'r', 'a', 'f', 't', '-', '0', '4', '/', 's', 'c', 'h', 'e', 'm', 'a', '#', '\0' }; + static const Ch kDraft05String[] = { 'h', 't', 't', 'p', ':', '/', '/', 'j', 's', 'o', 'n', '-', 's', 'c', 'h', 'e', 'm', 'a', '.', 'o', 'r', 'g', '/', 'd', 'r', 'a', 'f', 't', '-', '0', '5', '/', 's', 'c', 'h', 'e', 'm', 'a', '#', '\0' }; + static const Ch kDraft06String[] = { 'h', 't', 't', 'p', ':', '/', '/', 'j', 's', 'o', 'n', '-', 's', 'c', 'h', 'e', 'm', 'a', '.', 'o', 'r', 'g', '/', 'd', 'r', 'a', 'f', 't', '-', '0', '6', '/', 's', 'c', 'h', 'e', 'm', 'a', '#', '\0' }; + static const Ch kDraft07String[] = { 'h', 't', 't', 'p', ':', '/', '/', 'j', 's', 'o', 'n', '-', 's', 'c', 'h', 'e', 'm', 'a', '.', 'o', 'r', 'g', '/', 'd', 'r', 'a', 'f', 't', '-', '0', '7', '/', 's', 'c', 'h', 'e', 'm', 'a', '#', '\0' }; + static const Ch kDraft2019_09String[] = { 'h', 't', 't', 'p', 's', ':', '/', '/', 'j', 's', 'o', 'n', '-', 's', 'c', 'h', 'e', 'm', 'a', '.', 'o', 'r', 'g', '/', 'd', 'r', 'a', 'f', 't', '/', '2', '0', '1', '9', '-', '0', '9', '/', 's', 'c', 'h', 'e', 'm', 'a', '\0' }; + static const Ch kDraft2020_12String[] = { 'h', 't', 't', 'p', 's', ':', '/', '/', 'j', 's', 'o', 'n', '-', 's', 'c', 'h', 'e', 'm', 'a', '.', 'o', 'r', 'g', '/', 'd', 'r', 'a', 'f', 't', '/', '2', '0', '2', '0', '-', '1', '2', '/', 's', 'c', 'h', 'e', 'm', 'a', '\0' }; + + if (!document.IsObject()) { + return kDraftNone; + } + + // Get the schema draft from the $schema keyword at the supplied location + typename ValueType::ConstMemberIterator itr = document.FindMember(SchemaType::GetSchemaString()); + if (itr != document.MemberEnd()) { + if (!itr->value.IsString()) return kDraftUnknown; + const UriType draftUri(itr->value); + // Check base uri for match + if (draftUri.Match(UriType(kDraft04String), false)) return kDraft04; + if (draftUri.Match(UriType(kDraft05String), false)) return kDraft05; + if (draftUri.Match(UriType(kDraft06String), false)) return kDraft06; + if (draftUri.Match(UriType(kDraft07String), false)) return kDraft07; + if (draftUri.Match(UriType(kDraft03String), false)) return kDraft03; + if (draftUri.Match(UriType(kDraft2019_09String), false)) return kDraft2019_09; + if (draftUri.Match(UriType(kDraft2020_12String), false)) return kDraft2020_12; + return kDraftUnknown; + } + // $schema not found + return kDraftNone; + } + + + // Get open api version of any schema document + static OpenApiVersion GetOpenApiVersion(const ValueType& document) { + static const Ch kVersion20String[] = { '2', '.', '0', '\0' }; + static const Ch kVersion30String[] = { '3', '.', '0', '.', '\0' }; // ignore patch level + static const Ch kVersion31String[] = { '3', '.', '1', '.', '\0' }; // ignore patch level + static SizeType len = internal::StrLen(kVersion30String); + + if (!document.IsObject()) { + return kVersionNone; + } + + // Get the open api version from the swagger / openapi keyword at the supplied location + typename ValueType::ConstMemberIterator itr = document.FindMember(SchemaType::GetSwaggerString()); + if (itr == document.MemberEnd()) itr = document.FindMember(SchemaType::GetOpenApiString()); + if (itr != document.MemberEnd()) { + if (!itr->value.IsString()) return kVersionUnknown; + const ValueType kVersion20Value(kVersion20String); + if (kVersion20Value == itr->value) return kVersion20; // must match 2.0 exactly + const ValueType kVersion30Value(kVersion30String); + if (itr->value.GetStringLength() > len && kVersion30Value == ValueType(itr->value.GetString(), len)) return kVersion30; // must match 3.0.x + const ValueType kVersion31Value(kVersion31String); + if (itr->value.GetStringLength() > len && kVersion31Value == ValueType(itr->value.GetString(), len)) return kVersion31; // must match 3.1.x + return kVersionUnknown; + } + // swagger or openapi not found + return kVersionNone; + } + + // Get the draft of the schema or the open api version (which implies the draft). + // Report an error if schema draft or open api version not supported or not recognized, or both in document, and carry on. + void SetSchemaSpecification(const ValueType& document) { + // Look for '$schema', 'swagger' or 'openapi' keyword at document root + SchemaDraft docDraft = GetSchemaDraft(document); + OpenApiVersion docOapi = GetOpenApiVersion(document); + // Error if both in document + if (docDraft != kDraftNone && docOapi != kVersionNone) + SchemaError(kSchemaErrorSpecIllegal, PointerType()); + // Use document draft or open api version if present or use spec from constructor + if (docDraft != kDraftNone) + spec_ = Specification(docDraft); + else if (docOapi != kVersionNone) + spec_ = Specification(docOapi); + // Error if draft or version unknown + if (spec_.draft == kDraftUnknown || spec_.oapi == kVersionUnknown) + SchemaError(kSchemaErrorSpecUnknown, PointerType()); + else if (!spec_.IsSupported()) + SchemaError(kSchemaErrorSpecUnsupported, PointerType()); + } + + // Changed by PR #1393 + void CreateSchemaRecursive(const SchemaType** schema, const PointerType& pointer, const ValueType& v, const ValueType& document, const UriType& id) { if (v.GetType() == kObjectType) { - const SchemaType* s = GetSchema(pointer); - if (!s) - CreateSchema(schema, pointer, v, document); + UriType newid = UriType(CreateSchema(schema, pointer, v, document, id), allocator_); for (typename ValueType::ConstMemberIterator itr = v.MemberBegin(); itr != v.MemberEnd(); ++itr) - CreateSchemaRecursive(0, pointer.Append(itr->name, allocator_), itr->value, document); + CreateSchemaRecursive(0, pointer.Append(itr->name, allocator_), itr->value, document, newid); } else if (v.GetType() == kArrayType) for (SizeType i = 0; i < v.Size(); i++) - CreateSchemaRecursive(0, pointer.Append(i, allocator_), v[i], document); + CreateSchemaRecursive(0, pointer.Append(i, allocator_), v[i], document, id); } - void CreateSchema(const SchemaType** schema, const PointerType& pointer, const ValueType& v, const ValueType& document) { + // Changed by PR #1393 + const UriType& CreateSchema(const SchemaType** schema, const PointerType& pointer, const ValueType& v, const ValueType& document, const UriType& id) { RAPIDJSON_ASSERT(pointer.IsValid()); + GenericStringBuffer sb; + pointer.StringifyUriFragment(sb); + RAPIDJSON_SCHEMA_PRINT(Method, "GenericSchemaDocument::CreateSchema", sb.GetString(), id.GetString()); if (v.IsObject()) { - if (!HandleRefSchema(pointer, schema, v, document)) { - SchemaType* s = new (allocator_->Malloc(sizeof(SchemaType))) SchemaType(this, pointer, v, document, allocator_); - new (schemaMap_.template Push()) SchemaEntry(pointer, s, true, allocator_); + if (const SchemaType* sc = GetSchema(pointer)) { + if (schema) + *schema = sc; + AddSchemaRefs(const_cast(sc)); + } + else if (!HandleRefSchema(pointer, schema, v, document, id)) { + // The new schema constructor adds itself and its $ref(s) to schemaMap_ + SchemaType* s = new (allocator_->Malloc(sizeof(SchemaType))) SchemaType(this, pointer, v, document, allocator_, id); if (schema) *schema = s; + return s->GetId(); } } + else { + if (schema) + *schema = typeless_; + AddSchemaRefs(typeless_); + } + return id; } - bool HandleRefSchema(const PointerType& source, const SchemaType** schema, const ValueType& v, const ValueType& document) { - static const Ch kRefString[] = { '$', 'r', 'e', 'f', '\0' }; - static const ValueType kRefValue(kRefString, 4); - - typename ValueType::ConstMemberIterator itr = v.FindMember(kRefValue); + // Changed by PR #1393 + // TODO should this return a UriType& ? + bool HandleRefSchema(const PointerType& source, const SchemaType** schema, const ValueType& v, const ValueType& document, const UriType& id) { + typename ValueType::ConstMemberIterator itr = v.FindMember(SchemaType::GetRefString()); if (itr == v.MemberEnd()) return false; + GenericStringBuffer sb; + source.StringifyUriFragment(sb); + RAPIDJSON_SCHEMA_PRINT(Method, "GenericSchemaDocument::HandleRefSchema", sb.GetString(), id.GetString()); + // Resolve the source pointer to the $ref'ed schema (finally) + new (schemaRef_.template Push()) SchemaRefPtr(&source); + if (itr->value.IsString()) { SizeType len = itr->value.GetStringLength(); - if (len > 0) { - const Ch* s = itr->value.GetString(); - SizeType i = 0; - while (i < len && s[i] != '#') // Find the first # - i++; - - if (i > 0) { // Remote reference, resolve immediately - if (remoteProvider_) { - if (const GenericSchemaDocument* remoteDocument = remoteProvider_->GetRemoteDocument(s, i)) { - PointerType pointer(&s[i], len - i, allocator_); - if (pointer.IsValid()) { - if (const SchemaType* sc = remoteDocument->GetSchema(pointer)) { - if (schema) - *schema = sc; - new (schemaMap_.template Push()) SchemaEntry(source, const_cast(sc), false, allocator_); - return true; + if (len == 0) + SchemaError(kSchemaErrorRefInvalid, source); + else { + // First resolve $ref against the in-scope id + UriType scopeId = UriType(id, allocator_); + UriType ref = UriType(itr->value, allocator_).Resolve(scopeId, allocator_); + RAPIDJSON_SCHEMA_PRINT(SchemaIds, id.GetString(), itr->value.GetString(), ref.GetString()); + // See if the resolved $ref minus the fragment matches a resolved id in this document + // Search from the root. Returns the subschema in the document and its absolute JSON pointer. + PointerType basePointer = PointerType(); + const ValueType *base = FindId(document, ref, basePointer, docId_, false); + if (!base) { + // Remote reference - call the remote document provider + if (!remoteProvider_) + SchemaError(kSchemaErrorRefNoRemoteProvider, source); + else { + if (const GenericSchemaDocument* remoteDocument = remoteProvider_->GetRemoteDocument(ref, spec_)) { + const Ch* s = ref.GetFragString(); + len = ref.GetFragStringLength(); + if (len <= 1 || s[1] == '/') { + // JSON pointer fragment, absolute in the remote schema + const PointerType pointer(s, len, allocator_); + if (!pointer.IsValid()) + SchemaErrorPointer(kSchemaErrorRefPointerInvalid, source, s, len, pointer); + else { + // Get the subschema + if (const SchemaType *sc = remoteDocument->GetSchema(pointer)) { + if (schema) + *schema = sc; + AddSchemaRefs(const_cast(sc)); + return true; + } else + SchemaErrorValue(kSchemaErrorRefUnknown, source, ref.GetString(), ref.GetStringLength()); } - } - } + } else + // Plain name fragment, not allowed in remote schema + SchemaErrorValue(kSchemaErrorRefPlainName, source, s, len); + } else + SchemaErrorValue(kSchemaErrorRefNoRemoteSchema, source, ref.GetString(), ref.GetStringLength()); } } - else if (s[i] == '#') { // Local reference, defer resolution - PointerType pointer(&s[i], len - i, allocator_); - if (pointer.IsValid()) { - if (const ValueType* nv = pointer.Get(document)) - if (HandleRefSchema(source, schema, *nv, document)) + else { // Local reference + const Ch* s = ref.GetFragString(); + len = ref.GetFragStringLength(); + if (len <= 1 || s[1] == '/') { + // JSON pointer fragment, relative to the resolved URI + const PointerType relPointer(s, len, allocator_); + if (!relPointer.IsValid()) + SchemaErrorPointer(kSchemaErrorRefPointerInvalid, source, s, len, relPointer); + else { + // Get the subschema + if (const ValueType *pv = relPointer.Get(*base)) { + // Now get the absolute JSON pointer by adding relative to base + PointerType pointer(basePointer, allocator_); + for (SizeType i = 0; i < relPointer.GetTokenCount(); i++) + pointer = pointer.Append(relPointer.GetTokens()[i], allocator_); + if (IsCyclicRef(pointer)) + SchemaErrorValue(kSchemaErrorRefCyclical, source, ref.GetString(), ref.GetStringLength()); + else { + // Call CreateSchema recursively, but first compute the in-scope id for the $ref target as we have jumped there + // TODO: cache pointer <-> id mapping + size_t unresolvedTokenIndex; + scopeId = pointer.GetUri(document, docId_, &unresolvedTokenIndex, allocator_); + CreateSchema(schema, pointer, *pv, document, scopeId); + return true; + } + } else + SchemaErrorValue(kSchemaErrorRefUnknown, source, ref.GetString(), ref.GetStringLength()); + } + } else { + // Plain name fragment, relative to the resolved URI + // Not supported in open api 2.0 and 3.0 + PointerType pointer(allocator_); + if (spec_.oapi == kVersion20 || spec_.oapi == kVersion30) + SchemaErrorValue(kSchemaErrorRefPlainName, source, s, len); + // See if the fragment matches an id in this document. + // Search from the base we just established. Returns the subschema in the document and its absolute JSON pointer. + else if (const ValueType *pv = FindId(*base, ref, pointer, UriType(ref.GetBaseString(), ref.GetBaseStringLength(), allocator_), true, basePointer)) { + if (IsCyclicRef(pointer)) + SchemaErrorValue(kSchemaErrorRefCyclical, source, ref.GetString(), ref.GetStringLength()); + else { + // Call CreateSchema recursively, but first compute the in-scope id for the $ref target as we have jumped there + // TODO: cache pointer <-> id mapping + size_t unresolvedTokenIndex; + scopeId = pointer.GetUri(document, docId_, &unresolvedTokenIndex, allocator_); + CreateSchema(schema, pointer, *pv, document, scopeId); return true; - - new (schemaRef_.template Push()) SchemaRefEntry(source, pointer, schema, allocator_); - return true; + } + } else + SchemaErrorValue(kSchemaErrorRefUnknown, source, ref.GetString(), ref.GetStringLength()); } } } } + + // Invalid/Unknown $ref + if (schema) + *schema = typeless_; + AddSchemaRefs(typeless_); + return true; + } + + //! Find the first subschema with a resolved 'id' that matches the specified URI. + // If full specified use all URI else ignore fragment. + // If found, return a pointer to the subschema and its JSON pointer. + // TODO cache pointer <-> id mapping + ValueType* FindId(const ValueType& doc, const UriType& finduri, PointerType& resptr, const UriType& baseuri, bool full, const PointerType& here = PointerType()) const { + SizeType i = 0; + ValueType* resval = 0; + UriType tempuri = UriType(finduri, allocator_); + UriType localuri = UriType(baseuri, allocator_); + if (doc.GetType() == kObjectType) { + // Establish the base URI of this object + typename ValueType::ConstMemberIterator m = doc.FindMember(SchemaType::GetIdString()); + if (m != doc.MemberEnd() && m->value.GetType() == kStringType) { + localuri = UriType(m->value, allocator_).Resolve(baseuri, allocator_); + } + // See if it matches + if (localuri.Match(finduri, full)) { + RAPIDJSON_SCHEMA_PRINT(Method, "GenericSchemaDocument::FindId (match)", full ? localuri.GetString() : localuri.GetBaseString()); + resval = const_cast(&doc); + resptr = here; + return resval; + } + // No match, continue looking + for (m = doc.MemberBegin(); m != doc.MemberEnd(); ++m) { + if (m->value.GetType() == kObjectType || m->value.GetType() == kArrayType) { + resval = FindId(m->value, finduri, resptr, localuri, full, here.Append(m->name.GetString(), m->name.GetStringLength(), allocator_)); + } + if (resval) break; + } + } else if (doc.GetType() == kArrayType) { + // Continue looking + for (typename ValueType::ConstValueIterator v = doc.Begin(); v != doc.End(); ++v) { + if (v->GetType() == kObjectType || v->GetType() == kArrayType) { + resval = FindId(*v, finduri, resptr, localuri, full, here.Append(i, allocator_)); + } + if (resval) break; + i++; + } + } + return resval; + } + + // Added by PR #1393 + void AddSchemaRefs(SchemaType* schema) { + RAPIDJSON_SCHEMA_PRINT(Method, "GenericSchemaDocument::AddSchemaRefs"); + while (!schemaRef_.Empty()) { + SchemaRefPtr *ref = schemaRef_.template Pop(1); + SchemaEntry *entry = schemaMap_.template Push(); + new (entry) SchemaEntry(**ref, schema, false, allocator_); + } + } + + // Added by PR #1393 + bool IsCyclicRef(const PointerType& pointer) const { + for (const SchemaRefPtr* ref = schemaRef_.template Bottom(); ref != schemaRef_.template End(); ++ref) + if (pointer == **ref) + return true; return false; } @@ -1807,8 +2403,12 @@ private: const SchemaType* root_; //!< Root schema. SchemaType* typeless_; internal::Stack schemaMap_; // Stores created Pointer -> Schemas - internal::Stack schemaRef_; // Stores Pointer from $ref and schema which holds the $ref - URIType uri_; + internal::Stack schemaRef_; // Stores Pointer(s) from $ref(s) until resolved + GValue uri_; // Schema document URI + UriType docId_; + Specification spec_; + GValue error_; + GValue currentError_; }; //! GenericSchemaDocument using Value type. @@ -1872,11 +2472,10 @@ public: currentError_(), missingDependents_(), valid_(true), - flags_(kValidateDefaultFlags) -#if RAPIDJSON_SCHEMA_VERBOSE - , depth_(0) -#endif + flags_(kValidateDefaultFlags), + depth_(0) { + RAPIDJSON_SCHEMA_PRINT(Method, "GenericSchemaValidator::GenericSchemaValidator"); } //! Constructor with output handler. @@ -1904,11 +2503,10 @@ public: currentError_(), missingDependents_(), valid_(true), - flags_(kValidateDefaultFlags) -#if RAPIDJSON_SCHEMA_VERBOSE - , depth_(0) -#endif + flags_(kValidateDefaultFlags), + depth_(0) { + RAPIDJSON_SCHEMA_PRINT(Method, "GenericSchemaValidator::GenericSchemaValidator (output handler)"); } //! Destructor. @@ -1941,13 +2539,12 @@ public: return flags_; } - //! Checks whether the current state is valid. - // Implementation of ISchemaValidator virtual bool IsValid() const { if (!valid_) return false; if (GetContinueOnErrors() && !error_.ObjectEmpty()) return false; return true; } + //! End of Implementation of ISchemaValidator //! Gets the error object. ValueType& GetError() { return error_; } @@ -1963,7 +2560,7 @@ public: // If reporting all errors, the stack will be empty, so return "errors". const Ch* GetInvalidSchemaKeyword() const { if (!schemaStack_.Empty()) return CurrentContext().invalidKeyword; - if (GetContinueOnErrors() && !error_.ObjectEmpty()) return (const Ch*)GetErrorsString(); + if (GetContinueOnErrors() && !error_.ObjectEmpty()) return static_cast(GetErrorsString()); return 0; } @@ -2155,13 +2752,29 @@ public: void NoneOf(ISchemaValidator** subvalidators, SizeType count) { AddErrorArray(kValidateErrorAnyOf, subvalidators, count); } - void NotOneOf(ISchemaValidator** subvalidators, SizeType count, bool matched = false) { - AddErrorArray(matched ? kValidateErrorOneOfMatch : kValidateErrorOneOf, subvalidators, count); + void NotOneOf(ISchemaValidator** subvalidators, SizeType count) { + AddErrorArray(kValidateErrorOneOf, subvalidators, count); + } + void MultipleOneOf(SizeType index1, SizeType index2) { + ValueType matches(kArrayType); + matches.PushBack(index1, GetStateAllocator()); + matches.PushBack(index2, GetStateAllocator()); + currentError_.SetObject(); + currentError_.AddMember(GetMatchesString(), matches, GetStateAllocator()); + AddCurrentError(kValidateErrorOneOfMatch); } void Disallowed() { currentError_.SetObject(); AddCurrentError(kValidateErrorNot); } + void DisallowedWhenWriting() { + currentError_.SetObject(); + AddCurrentError(kValidateErrorReadOnly); + } + void DisallowedWhenReading() { + currentError_.SetObject(); + AddCurrentError(kValidateErrorWriteOnly); + } #define RAPIDJSON_STRING_(name, ...) \ static const StringRefType& Get##name##String() {\ @@ -2180,25 +2793,18 @@ public: RAPIDJSON_STRING_(ErrorCode, 'e', 'r', 'r', 'o', 'r', 'C', 'o', 'd', 'e') RAPIDJSON_STRING_(ErrorMessage, 'e', 'r', 'r', 'o', 'r', 'M', 'e', 's', 's', 'a', 'g', 'e') RAPIDJSON_STRING_(Duplicates, 'd', 'u', 'p', 'l', 'i', 'c', 'a', 't', 'e', 's') + RAPIDJSON_STRING_(Matches, 'm', 'a', 't', 'c', 'h', 'e', 's') #undef RAPIDJSON_STRING_ -#if RAPIDJSON_SCHEMA_VERBOSE -#define RAPIDJSON_SCHEMA_HANDLE_BEGIN_VERBOSE_() \ -RAPIDJSON_MULTILINEMACRO_BEGIN\ - *documentStack_.template Push() = '\0';\ - documentStack_.template Pop(1);\ - internal::PrintInvalidDocument(documentStack_.template Bottom());\ -RAPIDJSON_MULTILINEMACRO_END -#else -#define RAPIDJSON_SCHEMA_HANDLE_BEGIN_VERBOSE_() -#endif - #define RAPIDJSON_SCHEMA_HANDLE_BEGIN_(method, arg1)\ if (!valid_) return false; \ if ((!BeginValue() && !GetContinueOnErrors()) || (!CurrentSchema().method arg1 && !GetContinueOnErrors())) {\ - RAPIDJSON_SCHEMA_HANDLE_BEGIN_VERBOSE_();\ - return valid_ = false;\ + *documentStack_.template Push() = '\0';\ + documentStack_.template Pop(1);\ + RAPIDJSON_SCHEMA_PRINT(InvalidDocument, documentStack_.template Bottom());\ + valid_ = false;\ + return valid_;\ } #define RAPIDJSON_SCHEMA_HANDLE_PARALLEL_(method, arg2)\ @@ -2235,52 +2841,68 @@ RAPIDJSON_MULTILINEMACRO_END { RAPIDJSON_SCHEMA_HANDLE_VALUE_(String, (CurrentContext(), str, length, copy), (str, length, copy)); } bool StartObject() { + RAPIDJSON_SCHEMA_PRINT(Method, "GenericSchemaValidator::StartObject"); RAPIDJSON_SCHEMA_HANDLE_BEGIN_(StartObject, (CurrentContext())); RAPIDJSON_SCHEMA_HANDLE_PARALLEL_(StartObject, ()); - return valid_ = !outputHandler_ || outputHandler_->StartObject(); + valid_ = !outputHandler_ || outputHandler_->StartObject(); + return valid_; } bool Key(const Ch* str, SizeType len, bool copy) { + RAPIDJSON_SCHEMA_PRINT(Method, "GenericSchemaValidator::Key", str); if (!valid_) return false; AppendToken(str, len); - if (!CurrentSchema().Key(CurrentContext(), str, len, copy) && !GetContinueOnErrors()) return valid_ = false; + if (!CurrentSchema().Key(CurrentContext(), str, len, copy) && !GetContinueOnErrors()) { + valid_ = false; + return valid_; + } RAPIDJSON_SCHEMA_HANDLE_PARALLEL_(Key, (str, len, copy)); - return valid_ = !outputHandler_ || outputHandler_->Key(str, len, copy); + valid_ = !outputHandler_ || outputHandler_->Key(str, len, copy); + return valid_; } bool EndObject(SizeType memberCount) { + RAPIDJSON_SCHEMA_PRINT(Method, "GenericSchemaValidator::EndObject"); if (!valid_) return false; RAPIDJSON_SCHEMA_HANDLE_PARALLEL_(EndObject, (memberCount)); - if (!CurrentSchema().EndObject(CurrentContext(), memberCount) && !GetContinueOnErrors()) return valid_ = false; + if (!CurrentSchema().EndObject(CurrentContext(), memberCount) && !GetContinueOnErrors()) { + valid_ = false; + return valid_; + } RAPIDJSON_SCHEMA_HANDLE_END_(EndObject, (memberCount)); } bool StartArray() { + RAPIDJSON_SCHEMA_PRINT(Method, "GenericSchemaValidator::StartArray"); RAPIDJSON_SCHEMA_HANDLE_BEGIN_(StartArray, (CurrentContext())); RAPIDJSON_SCHEMA_HANDLE_PARALLEL_(StartArray, ()); - return valid_ = !outputHandler_ || outputHandler_->StartArray(); + valid_ = !outputHandler_ || outputHandler_->StartArray(); + return valid_; } bool EndArray(SizeType elementCount) { + RAPIDJSON_SCHEMA_PRINT(Method, "GenericSchemaValidator::EndArray"); if (!valid_) return false; RAPIDJSON_SCHEMA_HANDLE_PARALLEL_(EndArray, (elementCount)); - if (!CurrentSchema().EndArray(CurrentContext(), elementCount) && !GetContinueOnErrors()) return valid_ = false; + if (!CurrentSchema().EndArray(CurrentContext(), elementCount) && !GetContinueOnErrors()) { + valid_ = false; + return valid_; + } RAPIDJSON_SCHEMA_HANDLE_END_(EndArray, (elementCount)); } -#undef RAPIDJSON_SCHEMA_HANDLE_BEGIN_VERBOSE_ #undef RAPIDJSON_SCHEMA_HANDLE_BEGIN_ #undef RAPIDJSON_SCHEMA_HANDLE_PARALLEL_ #undef RAPIDJSON_SCHEMA_HANDLE_VALUE_ // Implementation of ISchemaStateFactory virtual ISchemaValidator* CreateSchemaValidator(const SchemaType& root, const bool inheritContinueOnErrors) { + *documentStack_.template Push() = '\0'; + documentStack_.template Pop(1); ISchemaValidator* sv = new (GetStateAllocator().Malloc(sizeof(GenericSchemaValidator))) GenericSchemaValidator(*schemaDocument_, root, documentStack_.template Bottom(), documentStack_.GetSize(), -#if RAPIDJSON_SCHEMA_VERBOSE depth_ + 1, -#endif &GetStateAllocator()); - sv->SetValidateFlags(inheritContinueOnErrors ? GetValidateFlags() : GetValidateFlags() & ~(unsigned)kValidateContinueOnErrorFlag); + sv->SetValidateFlags(inheritContinueOnErrors ? GetValidateFlags() : GetValidateFlags() & ~static_cast(kValidateContinueOnErrorFlag)); return sv; } @@ -2311,6 +2933,7 @@ RAPIDJSON_MULTILINEMACRO_END virtual void FreeState(void* p) { StateAllocator::Free(p); } + // End of implementation of ISchemaStateFactory private: typedef typename SchemaType::Context Context; @@ -2321,9 +2944,7 @@ private: const SchemaDocumentType& schemaDocument, const SchemaType& root, const char* basePath, size_t basePathSize, -#if RAPIDJSON_SCHEMA_VERBOSE unsigned depth, -#endif StateAllocator* allocator = 0, size_t schemaStackCapacity = kDefaultSchemaStackCapacity, size_t documentStackCapacity = kDefaultDocumentStackCapacity) @@ -2339,11 +2960,10 @@ private: currentError_(), missingDependents_(), valid_(true), - flags_(kValidateDefaultFlags) -#if RAPIDJSON_SCHEMA_VERBOSE - , depth_(depth) -#endif + flags_(kValidateDefaultFlags), + depth_(depth) { + RAPIDJSON_SCHEMA_PRINT(Method, "GenericSchemaValidator::GenericSchemaValidator (internal)", basePath && basePathSize ? basePath : ""); if (basePath && basePathSize) memcpy(documentStack_.template Push(basePathSize), basePath, basePathSize); } @@ -2359,6 +2979,7 @@ private: } bool BeginValue() { + RAPIDJSON_SCHEMA_PRINT(Method, "GenericSchemaValidator::BeginValue"); if (schemaStack_.Empty()) PushSchema(root_); else { @@ -2380,6 +3001,7 @@ private: ISchemaValidator**& va = CurrentContext().patternPropertiesValidators; SizeType& validatorCount = CurrentContext().patternPropertiesValidatorCount; va = static_cast(MallocState(sizeof(ISchemaValidator*) * count)); + std::memset(va, 0, sizeof(ISchemaValidator*) * count); for (SizeType i = 0; i < count; i++) va[validatorCount++] = CreateSchemaValidator(*sa[i], true); // Inherit continueOnError } @@ -2390,17 +3012,15 @@ private: } bool EndValue() { + RAPIDJSON_SCHEMA_PRINT(Method, "GenericSchemaValidator::EndValue"); if (!CurrentSchema().EndValue(CurrentContext()) && !GetContinueOnErrors()) return false; -#if RAPIDJSON_SCHEMA_VERBOSE GenericStringBuffer sb; - schemaDocument_->GetPointer(&CurrentSchema()).Stringify(sb); - + schemaDocument_->GetPointer(&CurrentSchema()).StringifyUriFragment(sb); *documentStack_.template Push() = '\0'; documentStack_.template Pop(1); - internal::PrintValidatorPointers(depth_, sb.GetString(), documentStack_.template Bottom()); -#endif + RAPIDJSON_SCHEMA_PRINT(ValidatorPointers, sb.GetString(), documentStack_.template Bottom(), depth_); void* hasher = CurrentContext().hasher; uint64_t h = hasher && CurrentContext().arrayUniqueness ? static_cast(hasher)->GetHashCode() : 0; @@ -2451,7 +3071,7 @@ private: } } - RAPIDJSON_FORCEINLINE void PushSchema(const SchemaType& schema) { new (schemaStack_.template Push()) Context(*this, *this, &schema); } + RAPIDJSON_FORCEINLINE void PushSchema(const SchemaType& schema) { new (schemaStack_.template Push()) Context(*this, *this, &schema, flags_); } RAPIDJSON_FORCEINLINE void PopSchema() { Context* c = schemaStack_.template Pop(1); @@ -2553,9 +3173,7 @@ private: ValueType missingDependents_; bool valid_; unsigned flags_; -#if RAPIDJSON_SCHEMA_VERBOSE unsigned depth_; -#endif }; typedef GenericSchemaValidator SchemaValidator; diff --git a/contrib/rapidjson/include/rapidjson/uri.h b/contrib/rapidjson/include/rapidjson/uri.h new file mode 100644 index 000000000..f93e508a4 --- /dev/null +++ b/contrib/rapidjson/include/rapidjson/uri.h @@ -0,0 +1,481 @@ +// Tencent is pleased to support the open source community by making RapidJSON available. +// +// (C) Copyright IBM Corporation 2021 +// +// Licensed under the MIT License (the "License"); you may not use this file except +// in compliance with the License. You may obtain a copy of the License at +// +// http://opensource.org/licenses/MIT +// +// Unless required by applicable law or agreed to in writing, software distributed +// under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR +// CONDITIONS OF ANY KIND, either express or implied. See the License for the +// specific language governing permissions and limitations under the License. + +#ifndef RAPIDJSON_URI_H_ +#define RAPIDJSON_URI_H_ + +#include "internal/strfunc.h" + +#if defined(__clang__) +RAPIDJSON_DIAG_PUSH +RAPIDJSON_DIAG_OFF(c++98-compat) +#elif defined(_MSC_VER) +RAPIDJSON_DIAG_OFF(4512) // assignment operator could not be generated +#endif + +RAPIDJSON_NAMESPACE_BEGIN + +/////////////////////////////////////////////////////////////////////////////// +// GenericUri + +template +class GenericUri { +public: + typedef typename ValueType::Ch Ch; +#if RAPIDJSON_HAS_STDSTRING + typedef std::basic_string String; +#endif + + //! Constructors + GenericUri(Allocator* allocator = 0) : uri_(), base_(), scheme_(), auth_(), path_(), query_(), frag_(), allocator_(allocator), ownAllocator_() { + } + + GenericUri(const Ch* uri, SizeType len, Allocator* allocator = 0) : uri_(), base_(), scheme_(), auth_(), path_(), query_(), frag_(), allocator_(allocator), ownAllocator_() { + Parse(uri, len); + } + + GenericUri(const Ch* uri, Allocator* allocator = 0) : uri_(), base_(), scheme_(), auth_(), path_(), query_(), frag_(), allocator_(allocator), ownAllocator_() { + Parse(uri, internal::StrLen(uri)); + } + + // Use with specializations of GenericValue + template GenericUri(const T& uri, Allocator* allocator = 0) : uri_(), base_(), scheme_(), auth_(), path_(), query_(), frag_(), allocator_(allocator), ownAllocator_() { + const Ch* u = uri.template Get(); // TypeHelper from document.h + Parse(u, internal::StrLen(u)); + } + +#if RAPIDJSON_HAS_STDSTRING + GenericUri(const String& uri, Allocator* allocator = 0) : uri_(), base_(), scheme_(), auth_(), path_(), query_(), frag_(), allocator_(allocator), ownAllocator_() { + Parse(uri.c_str(), internal::StrLen(uri.c_str())); + } +#endif + + //! Copy constructor + GenericUri(const GenericUri& rhs) : uri_(), base_(), scheme_(), auth_(), path_(), query_(), frag_(), allocator_(), ownAllocator_() { + *this = rhs; + } + + //! Copy constructor + GenericUri(const GenericUri& rhs, Allocator* allocator) : uri_(), base_(), scheme_(), auth_(), path_(), query_(), frag_(), allocator_(allocator), ownAllocator_() { + *this = rhs; + } + + //! Destructor. + ~GenericUri() { + Free(); + RAPIDJSON_DELETE(ownAllocator_); + } + + //! Assignment operator + GenericUri& operator=(const GenericUri& rhs) { + if (this != &rhs) { + // Do not delete ownAllocator + Free(); + Allocate(rhs.GetStringLength()); + auth_ = CopyPart(scheme_, rhs.scheme_, rhs.GetSchemeStringLength()); + path_ = CopyPart(auth_, rhs.auth_, rhs.GetAuthStringLength()); + query_ = CopyPart(path_, rhs.path_, rhs.GetPathStringLength()); + frag_ = CopyPart(query_, rhs.query_, rhs.GetQueryStringLength()); + base_ = CopyPart(frag_, rhs.frag_, rhs.GetFragStringLength()); + uri_ = CopyPart(base_, rhs.base_, rhs.GetBaseStringLength()); + CopyPart(uri_, rhs.uri_, rhs.GetStringLength()); + } + return *this; + } + + //! Getters + // Use with specializations of GenericValue + template void Get(T& uri, Allocator& allocator) { + uri.template Set(this->GetString(), allocator); // TypeHelper from document.h + } + + const Ch* GetString() const { return uri_; } + SizeType GetStringLength() const { return uri_ == 0 ? 0 : internal::StrLen(uri_); } + const Ch* GetBaseString() const { return base_; } + SizeType GetBaseStringLength() const { return base_ == 0 ? 0 : internal::StrLen(base_); } + const Ch* GetSchemeString() const { return scheme_; } + SizeType GetSchemeStringLength() const { return scheme_ == 0 ? 0 : internal::StrLen(scheme_); } + const Ch* GetAuthString() const { return auth_; } + SizeType GetAuthStringLength() const { return auth_ == 0 ? 0 : internal::StrLen(auth_); } + const Ch* GetPathString() const { return path_; } + SizeType GetPathStringLength() const { return path_ == 0 ? 0 : internal::StrLen(path_); } + const Ch* GetQueryString() const { return query_; } + SizeType GetQueryStringLength() const { return query_ == 0 ? 0 : internal::StrLen(query_); } + const Ch* GetFragString() const { return frag_; } + SizeType GetFragStringLength() const { return frag_ == 0 ? 0 : internal::StrLen(frag_); } + +#if RAPIDJSON_HAS_STDSTRING + static String Get(const GenericUri& uri) { return String(uri.GetString(), uri.GetStringLength()); } + static String GetBase(const GenericUri& uri) { return String(uri.GetBaseString(), uri.GetBaseStringLength()); } + static String GetScheme(const GenericUri& uri) { return String(uri.GetSchemeString(), uri.GetSchemeStringLength()); } + static String GetAuth(const GenericUri& uri) { return String(uri.GetAuthString(), uri.GetAuthStringLength()); } + static String GetPath(const GenericUri& uri) { return String(uri.GetPathString(), uri.GetPathStringLength()); } + static String GetQuery(const GenericUri& uri) { return String(uri.GetQueryString(), uri.GetQueryStringLength()); } + static String GetFrag(const GenericUri& uri) { return String(uri.GetFragString(), uri.GetFragStringLength()); } +#endif + + //! Equality operators + bool operator==(const GenericUri& rhs) const { + return Match(rhs, true); + } + + bool operator!=(const GenericUri& rhs) const { + return !Match(rhs, true); + } + + bool Match(const GenericUri& uri, bool full = true) const { + Ch* s1; + Ch* s2; + if (full) { + s1 = uri_; + s2 = uri.uri_; + } else { + s1 = base_; + s2 = uri.base_; + } + if (s1 == s2) return true; + if (s1 == 0 || s2 == 0) return false; + return internal::StrCmp(s1, s2) == 0; + } + + //! Resolve this URI against another (base) URI in accordance with URI resolution rules. + // See https://tools.ietf.org/html/rfc3986 + // Use for resolving an id or $ref with an in-scope id. + // Returns a new GenericUri for the resolved URI. + GenericUri Resolve(const GenericUri& baseuri, Allocator* allocator = 0) { + GenericUri resuri; + resuri.allocator_ = allocator; + // Ensure enough space for combining paths + resuri.Allocate(GetStringLength() + baseuri.GetStringLength() + 1); // + 1 for joining slash + + if (!(GetSchemeStringLength() == 0)) { + // Use all of this URI + resuri.auth_ = CopyPart(resuri.scheme_, scheme_, GetSchemeStringLength()); + resuri.path_ = CopyPart(resuri.auth_, auth_, GetAuthStringLength()); + resuri.query_ = CopyPart(resuri.path_, path_, GetPathStringLength()); + resuri.frag_ = CopyPart(resuri.query_, query_, GetQueryStringLength()); + resuri.RemoveDotSegments(); + } else { + // Use the base scheme + resuri.auth_ = CopyPart(resuri.scheme_, baseuri.scheme_, baseuri.GetSchemeStringLength()); + if (!(GetAuthStringLength() == 0)) { + // Use this auth, path, query + resuri.path_ = CopyPart(resuri.auth_, auth_, GetAuthStringLength()); + resuri.query_ = CopyPart(resuri.path_, path_, GetPathStringLength()); + resuri.frag_ = CopyPart(resuri.query_, query_, GetQueryStringLength()); + resuri.RemoveDotSegments(); + } else { + // Use the base auth + resuri.path_ = CopyPart(resuri.auth_, baseuri.auth_, baseuri.GetAuthStringLength()); + if (GetPathStringLength() == 0) { + // Use the base path + resuri.query_ = CopyPart(resuri.path_, baseuri.path_, baseuri.GetPathStringLength()); + if (GetQueryStringLength() == 0) { + // Use the base query + resuri.frag_ = CopyPart(resuri.query_, baseuri.query_, baseuri.GetQueryStringLength()); + } else { + // Use this query + resuri.frag_ = CopyPart(resuri.query_, query_, GetQueryStringLength()); + } + } else { + if (path_[0] == '/') { + // Absolute path - use all of this path + resuri.query_ = CopyPart(resuri.path_, path_, GetPathStringLength()); + resuri.RemoveDotSegments(); + } else { + // Relative path - append this path to base path after base path's last slash + size_t pos = 0; + if (!(baseuri.GetAuthStringLength() == 0) && baseuri.GetPathStringLength() == 0) { + resuri.path_[pos] = '/'; + pos++; + } + size_t lastslashpos = baseuri.GetPathStringLength(); + while (lastslashpos > 0) { + if (baseuri.path_[lastslashpos - 1] == '/') break; + lastslashpos--; + } + std::memcpy(&resuri.path_[pos], baseuri.path_, lastslashpos * sizeof(Ch)); + pos += lastslashpos; + resuri.query_ = CopyPart(&resuri.path_[pos], path_, GetPathStringLength()); + resuri.RemoveDotSegments(); + } + // Use this query + resuri.frag_ = CopyPart(resuri.query_, query_, GetQueryStringLength()); + } + } + } + // Always use this frag + resuri.base_ = CopyPart(resuri.frag_, frag_, GetFragStringLength()); + + // Re-constitute base_ and uri_ + resuri.SetBase(); + resuri.uri_ = resuri.base_ + resuri.GetBaseStringLength() + 1; + resuri.SetUri(); + return resuri; + } + + //! Get the allocator of this GenericUri. + Allocator& GetAllocator() { return *allocator_; } + +private: + // Allocate memory for a URI + // Returns total amount allocated + std::size_t Allocate(std::size_t len) { + // Create own allocator if user did not supply. + if (!allocator_) + ownAllocator_ = allocator_ = RAPIDJSON_NEW(Allocator)(); + + // Allocate one block containing each part of the URI (5) plus base plus full URI, all null terminated. + // Order: scheme, auth, path, query, frag, base, uri + // Note need to set, increment, assign in 3 stages to avoid compiler warning bug. + size_t total = (3 * len + 7) * sizeof(Ch); + scheme_ = static_cast(allocator_->Malloc(total)); + *scheme_ = '\0'; + auth_ = scheme_; + auth_++; + *auth_ = '\0'; + path_ = auth_; + path_++; + *path_ = '\0'; + query_ = path_; + query_++; + *query_ = '\0'; + frag_ = query_; + frag_++; + *frag_ = '\0'; + base_ = frag_; + base_++; + *base_ = '\0'; + uri_ = base_; + uri_++; + *uri_ = '\0'; + return total; + } + + // Free memory for a URI + void Free() { + if (scheme_) { + Allocator::Free(scheme_); + scheme_ = 0; + } + } + + // Parse a URI into constituent scheme, authority, path, query, & fragment parts + // Supports URIs that match regex ^(([^:/?#]+):)?(//([^/?#]*))?([^?#]*)(\?([^#]*))?(#(.*))? as per + // https://tools.ietf.org/html/rfc3986 + void Parse(const Ch* uri, std::size_t len) { + std::size_t start = 0, pos1 = 0, pos2 = 0; + Allocate(len); + + // Look for scheme ([^:/?#]+):)? + if (start < len) { + while (pos1 < len) { + if (uri[pos1] == ':') break; + pos1++; + } + if (pos1 != len) { + while (pos2 < len) { + if (uri[pos2] == '/') break; + if (uri[pos2] == '?') break; + if (uri[pos2] == '#') break; + pos2++; + } + if (pos1 < pos2) { + pos1++; + std::memcpy(scheme_, &uri[start], pos1 * sizeof(Ch)); + scheme_[pos1] = '\0'; + start = pos1; + } + } + } + // Look for auth (//([^/?#]*))? + // Note need to set, increment, assign in 3 stages to avoid compiler warning bug. + auth_ = scheme_ + GetSchemeStringLength(); + auth_++; + *auth_ = '\0'; + if (start < len - 1 && uri[start] == '/' && uri[start + 1] == '/') { + pos2 = start + 2; + while (pos2 < len) { + if (uri[pos2] == '/') break; + if (uri[pos2] == '?') break; + if (uri[pos2] == '#') break; + pos2++; + } + std::memcpy(auth_, &uri[start], (pos2 - start) * sizeof(Ch)); + auth_[pos2 - start] = '\0'; + start = pos2; + } + // Look for path ([^?#]*) + // Note need to set, increment, assign in 3 stages to avoid compiler warning bug. + path_ = auth_ + GetAuthStringLength(); + path_++; + *path_ = '\0'; + if (start < len) { + pos2 = start; + while (pos2 < len) { + if (uri[pos2] == '?') break; + if (uri[pos2] == '#') break; + pos2++; + } + if (start != pos2) { + std::memcpy(path_, &uri[start], (pos2 - start) * sizeof(Ch)); + path_[pos2 - start] = '\0'; + if (path_[0] == '/') + RemoveDotSegments(); // absolute path - normalize + start = pos2; + } + } + // Look for query (\?([^#]*))? + // Note need to set, increment, assign in 3 stages to avoid compiler warning bug. + query_ = path_ + GetPathStringLength(); + query_++; + *query_ = '\0'; + if (start < len && uri[start] == '?') { + pos2 = start + 1; + while (pos2 < len) { + if (uri[pos2] == '#') break; + pos2++; + } + if (start != pos2) { + std::memcpy(query_, &uri[start], (pos2 - start) * sizeof(Ch)); + query_[pos2 - start] = '\0'; + start = pos2; + } + } + // Look for fragment (#(.*))? + // Note need to set, increment, assign in 3 stages to avoid compiler warning bug. + frag_ = query_ + GetQueryStringLength(); + frag_++; + *frag_ = '\0'; + if (start < len && uri[start] == '#') { + std::memcpy(frag_, &uri[start], (len - start) * sizeof(Ch)); + frag_[len - start] = '\0'; + } + + // Re-constitute base_ and uri_ + base_ = frag_ + GetFragStringLength() + 1; + SetBase(); + uri_ = base_ + GetBaseStringLength() + 1; + SetUri(); + } + + // Reconstitute base + void SetBase() { + Ch* next = base_; + std::memcpy(next, scheme_, GetSchemeStringLength() * sizeof(Ch)); + next+= GetSchemeStringLength(); + std::memcpy(next, auth_, GetAuthStringLength() * sizeof(Ch)); + next+= GetAuthStringLength(); + std::memcpy(next, path_, GetPathStringLength() * sizeof(Ch)); + next+= GetPathStringLength(); + std::memcpy(next, query_, GetQueryStringLength() * sizeof(Ch)); + next+= GetQueryStringLength(); + *next = '\0'; + } + + // Reconstitute uri + void SetUri() { + Ch* next = uri_; + std::memcpy(next, base_, GetBaseStringLength() * sizeof(Ch)); + next+= GetBaseStringLength(); + std::memcpy(next, frag_, GetFragStringLength() * sizeof(Ch)); + next+= GetFragStringLength(); + *next = '\0'; + } + + // Copy a part from one GenericUri to another + // Return the pointer to the next part to be copied to + Ch* CopyPart(Ch* to, Ch* from, std::size_t len) { + RAPIDJSON_ASSERT(to != 0); + RAPIDJSON_ASSERT(from != 0); + std::memcpy(to, from, len * sizeof(Ch)); + to[len] = '\0'; + Ch* next = to + len + 1; + return next; + } + + // Remove . and .. segments from the path_ member. + // https://tools.ietf.org/html/rfc3986 + // This is done in place as we are only removing segments. + void RemoveDotSegments() { + std::size_t pathlen = GetPathStringLength(); + std::size_t pathpos = 0; // Position in path_ + std::size_t newpos = 0; // Position in new path_ + + // Loop through each segment in original path_ + while (pathpos < pathlen) { + // Get next segment, bounded by '/' or end + size_t slashpos = 0; + while ((pathpos + slashpos) < pathlen) { + if (path_[pathpos + slashpos] == '/') break; + slashpos++; + } + // Check for .. and . segments + if (slashpos == 2 && path_[pathpos] == '.' && path_[pathpos + 1] == '.') { + // Backup a .. segment in the new path_ + // We expect to find a previously added slash at the end or nothing + RAPIDJSON_ASSERT(newpos == 0 || path_[newpos - 1] == '/'); + size_t lastslashpos = newpos; + // Make sure we don't go beyond the start segment + if (lastslashpos > 1) { + // Find the next to last slash and back up to it + lastslashpos--; + while (lastslashpos > 0) { + if (path_[lastslashpos - 1] == '/') break; + lastslashpos--; + } + // Set the new path_ position + newpos = lastslashpos; + } + } else if (slashpos == 1 && path_[pathpos] == '.') { + // Discard . segment, leaves new path_ unchanged + } else { + // Move any other kind of segment to the new path_ + RAPIDJSON_ASSERT(newpos <= pathpos); + std::memmove(&path_[newpos], &path_[pathpos], slashpos * sizeof(Ch)); + newpos += slashpos; + // Add slash if not at end + if ((pathpos + slashpos) < pathlen) { + path_[newpos] = '/'; + newpos++; + } + } + // Move to next segment + pathpos += slashpos + 1; + } + path_[newpos] = '\0'; + } + + Ch* uri_; // Everything + Ch* base_; // Everything except fragment + Ch* scheme_; // Includes the : + Ch* auth_; // Includes the // + Ch* path_; // Absolute if starts with / + Ch* query_; // Includes the ? + Ch* frag_; // Includes the # + + Allocator* allocator_; //!< The current allocator. It is either user-supplied or equal to ownAllocator_. + Allocator* ownAllocator_; //!< Allocator owned by this Uri. +}; + +//! GenericUri for Value (UTF-8, default allocator). +typedef GenericUri Uri; + +RAPIDJSON_NAMESPACE_END + +#if defined(__clang__) +RAPIDJSON_DIAG_POP +#endif + +#endif // RAPIDJSON_URI_H_ diff --git a/contrib/rapidjson/include/rapidjson/writer.h b/contrib/rapidjson/include/rapidjson/writer.h index 8b389219a..632e02ce7 100644 --- a/contrib/rapidjson/include/rapidjson/writer.h +++ b/contrib/rapidjson/include/rapidjson/writer.h @@ -67,6 +67,7 @@ enum WriteFlag { kWriteNoFlags = 0, //!< No flags are set. kWriteValidateEncodingFlag = 1, //!< Validate encoding of JSON strings. kWriteNanAndInfFlag = 2, //!< Allow writing of Infinity, -Infinity and NaN. + kWriteNanAndInfNullFlag = 4, //!< Allow writing of Infinity, -Infinity and NaN as null. kWriteDefaultFlags = RAPIDJSON_WRITE_DEFAULT_FLAGS //!< Default write flags. Can be customized by defining RAPIDJSON_WRITE_DEFAULT_FLAGS }; @@ -348,8 +349,13 @@ protected: bool WriteDouble(double d) { if (internal::Double(d).IsNanOrInf()) { - if (!(writeFlags & kWriteNanAndInfFlag)) + if (!(writeFlags & kWriteNanAndInfFlag) && !(writeFlags & kWriteNanAndInfNullFlag)) return false; + if (writeFlags & kWriteNanAndInfNullFlag) { + PutReserve(*os_, 4); + PutUnsafe(*os_, 'n'); PutUnsafe(*os_, 'u'); PutUnsafe(*os_, 'l'); PutUnsafe(*os_, 'l'); + return true; + } if (internal::Double(d).IsNan()) { PutReserve(*os_, 3); PutUnsafe(*os_, 'N'); PutUnsafe(*os_, 'a'); PutUnsafe(*os_, 'N'); @@ -548,6 +554,11 @@ inline bool Writer::WriteDouble(double d) { // Note: This code path can only be reached if (RAPIDJSON_WRITE_DEFAULT_FLAGS & kWriteNanAndInfFlag). if (!(kWriteDefaultFlags & kWriteNanAndInfFlag)) return false; + if (kWriteDefaultFlags & kWriteNanAndInfNullFlag) { + PutReserve(*os_, 4); + PutUnsafe(*os_, 'n'); PutUnsafe(*os_, 'u'); PutUnsafe(*os_, 'l'); PutUnsafe(*os_, 'l'); + return true; + } if (internal::Double(d).IsNan()) { PutReserve(*os_, 3); PutUnsafe(*os_, 'N'); PutUnsafe(*os_, 'a'); PutUnsafe(*os_, 'N'); diff --git a/contrib/rapidjson/readme.md b/contrib/rapidjson/readme.md index b833a98e8..ac683b051 100644 --- a/contrib/rapidjson/readme.md +++ b/contrib/rapidjson/readme.md @@ -6,7 +6,7 @@ Tencent is pleased to support the open source community by making RapidJSON available. -Copyright (C) 2015 THL A29 Limited, a Tencent company, and Milo Yip. All rights reserved. +Copyright (C) 2015 THL A29 Limited, a Tencent company, and Milo Yip. * [RapidJSON GitHub](https://github.com/Tencent/rapidjson/) * RapidJSON Documentation @@ -43,7 +43,7 @@ RapidJSON is a JSON parser and generator for C++. It was inspired by [RapidXml]( More features can be read [here](doc/features.md). -JSON(JavaScript Object Notation) is a light-weight data exchange format. RapidJSON should be in fully compliance with RFC7159/ECMA-404, with optional support of relaxed syntax. More information about JSON can be obtained at +JSON(JavaScript Object Notation) is a light-weight data exchange format. RapidJSON should be in full compliance with RFC7159/ECMA-404, with optional support of relaxed syntax. More information about JSON can be obtained at * [Introducing JSON](http://json.org/) * [RFC7159: The JavaScript Object Notation (JSON) Data Interchange Format](https://tools.ietf.org/html/rfc7159) * [Standard ECMA-404: The JSON Data Interchange Format](https://www.ecma-international.org/publications/standards/Ecma-404.htm) @@ -72,6 +72,9 @@ Users can build and run the unit tests on their platform/compiler. RapidJSON is a header-only C++ library. Just copy the `include/rapidjson` folder to system or project's include path. +Alternatively, if you are using the [vcpkg](https://github.com/Microsoft/vcpkg/) dependency manager you can download and install rapidjson with CMake integration in a single command: +* vcpkg install rapidjson + RapidJSON uses following software as its dependencies: * [CMake](https://cmake.org/) as a general build tool * (optional) [Doxygen](http://www.doxygen.org) to build documentation @@ -158,3 +161,50 @@ More [examples](https://github.com/Tencent/rapidjson/tree/master/example) are av * [parsebyparts](https://github.com/Tencent/rapidjson/blob/master/example/parsebyparts/parsebyparts.cpp): Implements an `AsyncDocumentParser` which can parse JSON in parts, using C++11 thread. * [filterkey](https://github.com/Tencent/rapidjson/blob/master/example/filterkey/filterkey.cpp): A command line tool to remove all values with user-specified key. * [filterkeydom](https://github.com/Tencent/rapidjson/blob/master/example/filterkeydom/filterkeydom.cpp): Same tool as above, but it demonstrates how to use a generator to populate a `Document`. + +## Contributing + +RapidJSON welcomes contributions. When contributing, please follow the code below. + +### Issues + +Feel free to submit issues and enhancement requests. + +Please help us by providing **minimal reproducible examples**, because source code is easier to let other people understand what happens. +For crash problems on certain platforms, please bring stack dump content with the detail of the OS, compiler, etc. + +Please try breakpoint debugging first, tell us what you found, see if we can start exploring based on more information been prepared. + +### Workflow + +In general, we follow the "fork-and-pull" Git workflow. + + 1. **Fork** the repo on GitHub + 2. **Clone** the project to your own machine + 3. **Checkout** a new branch on your fork, start developing on the branch + 4. **Test** the change before commit, Make sure the changes pass all the tests, including `unittest` and `preftest`, please add test case for each new feature or bug-fix if needed. + 5. **Commit** changes to your own branch + 6. **Push** your work back up to your fork + 7. Submit a **Pull request** so that we can review your changes + +NOTE: Be sure to merge the latest from "upstream" before making a pull request! + +### Copyright and Licensing + +You can copy and paste the license summary from below. + +``` +Tencent is pleased to support the open source community by making RapidJSON available. + +Copyright (C) 2015 THL A29 Limited, a Tencent company, and Milo Yip. + +Licensed under the MIT License (the "License"); you may not use this file except +in compliance with the License. You may obtain a copy of the License at + +http://opensource.org/licenses/MIT + +Unless required by applicable law or agreed to in writing, software distributed +under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR +CONDITIONS OF ANY KIND, either express or implied. See the License for the +specific language governing permissions and limitations under the License. +``` From b41ffa556184b471912319a790d2fefc9f0c8fe2 Mon Sep 17 00:00:00 2001 From: Kim Kulling Date: Sun, 7 Apr 2024 20:42:52 +0100 Subject: [PATCH 63/77] Remove default destructor definitions from cpp files (#5528) --- code/Common/BaseImporter.cpp | 4 --- code/Common/BaseProcess.cpp | 4 --- code/Common/BaseProcess.h | 6 ++-- code/Common/Importer.h | 16 +++++---- code/Common/SGSpatialSort.cpp | 9 ++--- code/Common/ScenePreprocessor.h | 6 ++-- code/Common/StackAllocator.h | 5 +-- code/Common/StackAllocator.inl | 3 +- code/Common/Subdivision.cpp | 1 - code/Common/TargetAnimation.cpp | 1 - code/Common/TargetAnimation.h | 5 ++- code/Common/VertexTriangleAdjacency.cpp | 2 -- code/Common/ZipArchiveIOSystem.cpp | 48 ++++++++++++++++++++++--- include/assimp/BaseImporter.h | 2 +- include/assimp/ByteSwapper.h | 8 ++--- include/assimp/IOStream.hpp | 13 ++----- include/assimp/IOStreamBuffer.h | 5 +-- include/assimp/Importer.hpp | 2 -- include/assimp/LineSplitter.h | 4 +-- include/assimp/SGSpatialSort.h | 7 ++-- include/assimp/aabb.h | 10 ++---- include/assimp/anim.h | 1 + 22 files changed, 82 insertions(+), 80 deletions(-) diff --git a/code/Common/BaseImporter.cpp b/code/Common/BaseImporter.cpp index 18f08be8b..3a4c7c329 100644 --- a/code/Common/BaseImporter.cpp +++ b/code/Common/BaseImporter.cpp @@ -93,10 +93,6 @@ BaseImporter::BaseImporter() AI_NO_EXCEPT // empty } -// ------------------------------------------------------------------------------------------------ -// Destructor, private as well -BaseImporter::~BaseImporter() = default; - void BaseImporter::UpdateImporterScale(Importer *pImp) { ai_assert(pImp != nullptr); ai_assert(importerScale != 0.0); diff --git a/code/Common/BaseProcess.cpp b/code/Common/BaseProcess.cpp index 4d42037be..560ee7b94 100644 --- a/code/Common/BaseProcess.cpp +++ b/code/Common/BaseProcess.cpp @@ -57,10 +57,6 @@ BaseProcess::BaseProcess() AI_NO_EXCEPT // empty } -// ------------------------------------------------------------------------------------------------ -// Destructor, private as well -BaseProcess::~BaseProcess() = default; - // ------------------------------------------------------------------------------------------------ void BaseProcess::ExecuteOnScene(Importer *pImp) { ai_assert( nullptr != pImp ); diff --git a/code/Common/BaseProcess.h b/code/Common/BaseProcess.h index 01c1d1d22..a945ad542 100644 --- a/code/Common/BaseProcess.h +++ b/code/Common/BaseProcess.h @@ -179,11 +179,11 @@ class ASSIMP_API BaseProcess { friend class Importer; public: - /** @brief onstructor to be privately used by Importer */ + /** @brief Constructor to be privately used by Importer */ BaseProcess() AI_NO_EXCEPT; - /** @brief Destructor, private as well */ - virtual ~BaseProcess(); + /** @brief Destructor */ + virtual ~BaseProcess() = default; // ------------------------------------------------------------------- /** diff --git a/code/Common/Importer.h b/code/Common/Importer.h index 2aa6d9bda..2da55f173 100644 --- a/code/Common/Importer.h +++ b/code/Common/Importer.h @@ -74,11 +74,11 @@ public: typedef unsigned int KeyType; // typedefs for our configuration maps. - typedef std::map IntPropertyMap; - typedef std::map FloatPropertyMap; - typedef std::map StringPropertyMap; - typedef std::map MatrixPropertyMap; - typedef std::map PointerPropertyMap; + using IntPropertyMap = std::map; + using FloatPropertyMap = std::map; + using StringPropertyMap = std::map; + using MatrixPropertyMap = std::map; + using PointerPropertyMap = std::map; /** IO handler to use for all file accesses. */ IOSystem* mIOHandler; @@ -128,10 +128,12 @@ public: /// The default class constructor. ImporterPimpl() AI_NO_EXCEPT; + + /// The class destructor. + ~ImporterPimpl() = default; }; -inline -ImporterPimpl::ImporterPimpl() AI_NO_EXCEPT : +inline ImporterPimpl::ImporterPimpl() AI_NO_EXCEPT : mIOHandler( nullptr ), mIsDefaultHandler( false ), mProgressHandler( nullptr ), diff --git a/code/Common/SGSpatialSort.cpp b/code/Common/SGSpatialSort.cpp index 4cf1ac50f..d24ecf1b4 100644 --- a/code/Common/SGSpatialSort.cpp +++ b/code/Common/SGSpatialSort.cpp @@ -5,8 +5,6 @@ Open Asset Import Library (assimp) Copyright (c) 2006-2024, assimp team - - All rights reserved. Redistribution and use of this software in source and binary forms, @@ -50,16 +48,13 @@ the 3ds loader handling smooth groups correctly */ using namespace Assimp; // ------------------------------------------------------------------------------------------------ -SGSpatialSort::SGSpatialSort() -{ +SGSpatialSort::SGSpatialSort() { // define the reference plane. We choose some arbitrary vector away from all basic axes // in the hope that no model spreads all its vertices along this plane. mPlaneNormal.Set( 0.8523f, 0.34321f, 0.5736f); mPlaneNormal.Normalize(); } -// ------------------------------------------------------------------------------------------------ -// Destructor -SGSpatialSort::~SGSpatialSort() = default; + // ------------------------------------------------------------------------------------------------ void SGSpatialSort::Add(const aiVector3D& vPosition, unsigned int index, unsigned int smoothingGroup) diff --git a/code/Common/ScenePreprocessor.h b/code/Common/ScenePreprocessor.h index 2f491e9a8..6ffd7f8bd 100644 --- a/code/Common/ScenePreprocessor.h +++ b/code/Common/ScenePreprocessor.h @@ -4,7 +4,6 @@ Open Asset Import Library (assimp) Copyright (c) 2006-2024, assimp team - All rights reserved. Redistribution and use of this software in source and binary forms, @@ -56,7 +55,7 @@ class ScenePreprocessorTest; namespace Assimp { // ---------------------------------------------------------------------------------- -/** ScenePreprocessor: Preprocess a scene before any post-processing +/** ScenePreprocessor: Pre-process a scene before any post-processing * steps are executed. * * The step computes data that needn't necessarily be provided by the @@ -79,6 +78,9 @@ public: ScenePreprocessor(aiScene *_scene) : scene(_scene) {} + /// @brief The class destructor. + ~ScenePreprocessor() = default; + // ---------------------------------------------------------------- /** Assign a (new) scene to the object. * diff --git a/code/Common/StackAllocator.h b/code/Common/StackAllocator.h index b9123b608..a5d97c22d 100644 --- a/code/Common/StackAllocator.h +++ b/code/Common/StackAllocator.h @@ -61,9 +61,10 @@ namespace Assimp { class StackAllocator { public: /// @brief Constructs the allocator - inline StackAllocator(); + StackAllocator(); + /// @brief Destructs the allocator and frees all memory - inline ~StackAllocator(); + ~StackAllocator(); // non copyable StackAllocator(const StackAllocator &) = delete; diff --git a/code/Common/StackAllocator.inl b/code/Common/StackAllocator.inl index 80ad7ec45..44f15edbc 100644 --- a/code/Common/StackAllocator.inl +++ b/code/Common/StackAllocator.inl @@ -45,8 +45,7 @@ OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. using namespace Assimp; -inline StackAllocator::StackAllocator() { -} +inline StackAllocator::StackAllocator() : m_storageBlocks() {} inline StackAllocator::~StackAllocator() { FreeAll(); diff --git a/code/Common/Subdivision.cpp b/code/Common/Subdivision.cpp index 782fe8a21..fc8ab2099 100644 --- a/code/Common/Subdivision.cpp +++ b/code/Common/Subdivision.cpp @@ -4,7 +4,6 @@ Open Asset Import Library (assimp) Copyright (c) 2006-2024, assimp team - All rights reserved. Redistribution and use of this software in source and binary forms, diff --git a/code/Common/TargetAnimation.cpp b/code/Common/TargetAnimation.cpp index 52924a3b9..9ef4e5d6c 100644 --- a/code/Common/TargetAnimation.cpp +++ b/code/Common/TargetAnimation.cpp @@ -4,7 +4,6 @@ Open Asset Import Library (assimp) Copyright (c) 2006-2024, assimp team - All rights reserved. Redistribution and use of this software in source and binary forms, diff --git a/code/Common/TargetAnimation.h b/code/Common/TargetAnimation.h index 96d2b1bc8..116b55d2a 100644 --- a/code/Common/TargetAnimation.h +++ b/code/Common/TargetAnimation.h @@ -4,7 +4,6 @@ Open Asset Import Library (assimp) Copyright (c) 2006-2024, assimp team - All rights reserved. Redistribution and use of this software in source and binary forms, @@ -119,12 +118,16 @@ private: * look-at target */ class TargetAnimationHelper { public: + /// @brief The class constructor. TargetAnimationHelper() : targetPositions(nullptr), objectPositions(nullptr) { // empty } + /// @brief The class destructor. + ~TargetAnimationHelper() = default; + // ------------------------------------------------------------------ /** Sets the target animation channel * diff --git a/code/Common/VertexTriangleAdjacency.cpp b/code/Common/VertexTriangleAdjacency.cpp index 84344c907..616e7e797 100644 --- a/code/Common/VertexTriangleAdjacency.cpp +++ b/code/Common/VertexTriangleAdjacency.cpp @@ -5,8 +5,6 @@ Open Asset Import Library (assimp) Copyright (c) 2006-2024, assimp team - - All rights reserved. Redistribution and use of this software in source and binary forms, diff --git a/code/Common/ZipArchiveIOSystem.cpp b/code/Common/ZipArchiveIOSystem.cpp index c8babd4cb..23d7db15d 100644 --- a/code/Common/ZipArchiveIOSystem.cpp +++ b/code/Common/ZipArchiveIOSystem.cpp @@ -62,13 +62,13 @@ namespace Assimp { // ---------------------------------------------------------------- // A read-only file inside a ZIP -class ZipFile : public IOStream { +class ZipFile final : public IOStream { friend class ZipFileInfo; explicit ZipFile(std::string &filename, size_t size); public: std::string m_Filename; - virtual ~ZipFile() override; + ~ZipFile() override = default; // IOStream interface size_t Read(void *pvBuffer, size_t pSize, size_t pCount) override; @@ -89,6 +89,8 @@ private: // Wraps an existing Assimp::IOSystem for unzip class IOSystem2Unzip { public: + IOSystem2Unzip() = default; + ~IOSystem2Unzip() = default; static voidpf open(voidpf opaque, const char *filename, int mode); static voidpf opendisk(voidpf opaque, voidpf stream, uint32_t number_disk, int mode); static uLong read(voidpf opaque, voidpf stream, void *buf, uLong size); @@ -100,6 +102,7 @@ public: static zlib_filefunc_def get(IOSystem *pIOHandler); }; +// ---------------------------------------------------------------- voidpf IOSystem2Unzip::open(voidpf opaque, const char *filename, int mode) { IOSystem *io_system = reinterpret_cast(opaque); @@ -119,6 +122,7 @@ voidpf IOSystem2Unzip::open(voidpf opaque, const char *filename, int mode) { return (voidpf)io_system->Open(filename, mode_fopen); } +// ---------------------------------------------------------------- voidpf IOSystem2Unzip::opendisk(voidpf opaque, voidpf stream, uint32_t number_disk, int mode) { ZipFile *io_stream = (ZipFile *)stream; voidpf ret = nullptr; @@ -141,24 +145,28 @@ voidpf IOSystem2Unzip::opendisk(voidpf opaque, voidpf stream, uint32_t number_di return ret; } +// ---------------------------------------------------------------- uLong IOSystem2Unzip::read(voidpf /*opaque*/, voidpf stream, void *buf, uLong size) { IOStream *io_stream = (IOStream *)stream; return static_cast(io_stream->Read(buf, 1, size)); } +// ---------------------------------------------------------------- uLong IOSystem2Unzip::write(voidpf /*opaque*/, voidpf stream, const void *buf, uLong size) { IOStream *io_stream = (IOStream *)stream; return static_cast(io_stream->Write(buf, 1, size)); } +// ---------------------------------------------------------------- long IOSystem2Unzip::tell(voidpf /*opaque*/, voidpf stream) { IOStream *io_stream = (IOStream *)stream; return static_cast(io_stream->Tell()); } +// ---------------------------------------------------------------- long IOSystem2Unzip::seek(voidpf /*opaque*/, voidpf stream, uLong offset, int origin) { IOStream *io_stream = (IOStream *)stream; @@ -179,6 +187,7 @@ long IOSystem2Unzip::seek(voidpf /*opaque*/, voidpf stream, uLong offset, int or return (io_stream->Seek(offset, assimp_origin) == aiReturn_SUCCESS ? 0 : -1); } +// ---------------------------------------------------------------- int IOSystem2Unzip::close(voidpf opaque, voidpf stream) { IOSystem *io_system = (IOSystem *)opaque; IOStream *io_stream = (IOStream *)stream; @@ -188,10 +197,12 @@ int IOSystem2Unzip::close(voidpf opaque, voidpf stream) { return 0; } +// ---------------------------------------------------------------- int IOSystem2Unzip::testerror(voidpf /*opaque*/, voidpf /*stream*/) { return 0; } +// ---------------------------------------------------------------- zlib_filefunc_def IOSystem2Unzip::get(IOSystem *pIOHandler) { zlib_filefunc_def mapping; @@ -213,9 +224,10 @@ zlib_filefunc_def IOSystem2Unzip::get(IOSystem *pIOHandler) { // ---------------------------------------------------------------- // Info about a read-only file inside a ZIP -class ZipFileInfo { +class ZipFileInfo final { public: explicit ZipFileInfo(unzFile zip_handle, size_t size); + ~ZipFileInfo() = default; // Allocate and Extract data from the ZIP ZipFile *Extract(std::string &filename, unzFile zip_handle) const; @@ -225,6 +237,7 @@ private: unz_file_pos_s m_ZipFilePos; }; +// ---------------------------------------------------------------- ZipFileInfo::ZipFileInfo(unzFile zip_handle, size_t size) : m_Size(size) { ai_assert(m_Size != 0); @@ -234,6 +247,7 @@ ZipFileInfo::ZipFileInfo(unzFile zip_handle, size_t size) : unzGetFilePos(zip_handle, &(m_ZipFilePos)); } +// ---------------------------------------------------------------- ZipFile *ZipFileInfo::Extract(std::string &filename, unzFile zip_handle) const { // Find in the ZIP. This cannot fail unz_file_pos_s *filepos = const_cast(&(m_ZipFilePos)); @@ -273,14 +287,14 @@ ZipFile *ZipFileInfo::Extract(std::string &filename, unzFile zip_handle) const { return zip_file; } +// ---------------------------------------------------------------- ZipFile::ZipFile(std::string &filename, size_t size) : m_Filename(filename), m_Size(size) { ai_assert(m_Size != 0); m_Buffer = std::unique_ptr(new uint8_t[m_Size]); } -ZipFile::~ZipFile() = default; - +// ---------------------------------------------------------------- size_t ZipFile::Read(void *pvBuffer, size_t pSize, size_t pCount) { // Should be impossible ai_assert(m_Buffer != nullptr); @@ -305,10 +319,12 @@ size_t ZipFile::Read(void *pvBuffer, size_t pSize, size_t pCount) { return pCount; } +// ---------------------------------------------------------------- size_t ZipFile::FileSize() const { return m_Size; } +// ---------------------------------------------------------------- aiReturn ZipFile::Seek(size_t pOffset, aiOrigin pOrigin) { switch (pOrigin) { case aiOrigin_SET: { @@ -334,6 +350,7 @@ aiReturn ZipFile::Seek(size_t pOffset, aiOrigin pOrigin) { return aiReturn_FAILURE; } +// ---------------------------------------------------------------- size_t ZipFile::Tell() const { return m_SeekPtr; } @@ -365,6 +382,7 @@ private: ZipFileInfoMap m_ArchiveMap; }; +// ---------------------------------------------------------------- ZipArchiveIOSystem::Implement::Implement(IOSystem *pIOHandler, const char *pFilename, const char *pMode) { ai_assert(strcmp(pMode, "r") == 0); ai_assert(pFilename != nullptr); @@ -376,12 +394,14 @@ ZipArchiveIOSystem::Implement::Implement(IOSystem *pIOHandler, const char *pFile m_ZipFileHandle = unzOpen2(pFilename, &mapping); } +// ---------------------------------------------------------------- ZipArchiveIOSystem::Implement::~Implement() { if (m_ZipFileHandle != nullptr) { unzClose(m_ZipFileHandle); } } +// ---------------------------------------------------------------- void ZipArchiveIOSystem::Implement::MapArchive() { if (m_ZipFileHandle == nullptr) return; @@ -408,10 +428,12 @@ void ZipArchiveIOSystem::Implement::MapArchive() { } while (unzGoToNextFile(m_ZipFileHandle) != UNZ_END_OF_LIST_OF_FILE); } +// ---------------------------------------------------------------- bool ZipArchiveIOSystem::Implement::isOpen() const { return (m_ZipFileHandle != nullptr); } +// ---------------------------------------------------------------- void ZipArchiveIOSystem::Implement::getFileList(std::vector &rFileList) { MapArchive(); rFileList.clear(); @@ -421,6 +443,7 @@ void ZipArchiveIOSystem::Implement::getFileList(std::vector &rFileL } } +// ---------------------------------------------------------------- void ZipArchiveIOSystem::Implement::getFileListExtension(std::vector &rFileList, const std::string &extension) { MapArchive(); rFileList.clear(); @@ -431,6 +454,7 @@ void ZipArchiveIOSystem::Implement::getFileListExtension(std::vectorExists(filename); } +// ---------------------------------------------------------------- // This is always '/' in a ZIP char ZipArchiveIOSystem::getOsSeparator() const { return '/'; } +// ---------------------------------------------------------------- // Only supports Reading IOStream *ZipArchiveIOSystem::Open(const char *pFilename, const char *pMode) { ai_assert(pFilename != nullptr); @@ -536,22 +569,27 @@ IOStream *ZipArchiveIOSystem::Open(const char *pFilename, const char *pMode) { return pImpl->OpenFile(filename); } +// ---------------------------------------------------------------- void ZipArchiveIOSystem::Close(IOStream *pFile) { delete pFile; } +// ---------------------------------------------------------------- bool ZipArchiveIOSystem::isOpen() const { return (pImpl->isOpen()); } +// ---------------------------------------------------------------- void ZipArchiveIOSystem::getFileList(std::vector &rFileList) const { return pImpl->getFileList(rFileList); } +// ---------------------------------------------------------------- void ZipArchiveIOSystem::getFileListExtension(std::vector &rFileList, const std::string &extension) const { return pImpl->getFileListExtension(rFileList, extension); } +// ---------------------------------------------------------------- bool ZipArchiveIOSystem::isZipArchive(IOSystem *pIOHandler, const char *pFilename) { Implement tmp(pIOHandler, pFilename, "r"); return tmp.isOpen(); diff --git a/include/assimp/BaseImporter.h b/include/assimp/BaseImporter.h index b82ddd70d..447784e75 100644 --- a/include/assimp/BaseImporter.h +++ b/include/assimp/BaseImporter.h @@ -95,7 +95,7 @@ public: BaseImporter() AI_NO_EXCEPT; /** Destructor, private as well */ - virtual ~BaseImporter(); + virtual ~BaseImporter() = default; // ------------------------------------------------------------------- /** Returns whether the class can handle the format of the given file. diff --git a/include/assimp/ByteSwapper.h b/include/assimp/ByteSwapper.h index f738ae701..73c115b8a 100644 --- a/include/assimp/ByteSwapper.h +++ b/include/assimp/ByteSwapper.h @@ -4,7 +4,6 @@ Open Asset Import Library (assimp) Copyright (c) 2006-2024, assimp team - All rights reserved. Redistribution and use of this software in source and binary forms, @@ -66,10 +65,10 @@ namespace Assimp { * and vice versa. Direct use of this class is DEPRECATED. Use #StreamReader instead. */ // -------------------------------------------------------------------------------------- class ByteSwap { - ByteSwap() AI_NO_EXCEPT {} + ByteSwap() AI_NO_EXCEPT = default; + ~ByteSwap() = default; public: - // ---------------------------------------------------------------------- /** Swap two bytes of data * @param[inout] _szOut A void* to save the reintcasts for the caller. */ @@ -89,8 +88,7 @@ public: // ---------------------------------------------------------------------- /** Swap four bytes of data * @param[inout] _szOut A void* to save the reintcasts for the caller. */ - static inline void Swap4(void* _szOut) - { + static inline void Swap4(void* _szOut) { ai_assert(_szOut); #if _MSC_VER >= 1400 diff --git a/include/assimp/IOStream.hpp b/include/assimp/IOStream.hpp index bbc41ab21..1866a3d72 100644 --- a/include/assimp/IOStream.hpp +++ b/include/assimp/IOStream.hpp @@ -73,14 +73,14 @@ class ASSIMP_API IOStream { protected: /** Constructor protected, use IOSystem::Open() to create an instance. */ - IOStream() AI_NO_EXCEPT; + IOStream() AI_NO_EXCEPT = default; public: // ------------------------------------------------------------------- /** @brief Destructor. Deleting the object closes the underlying file, * alternatively you may use IOSystem::Close() to release the file. */ - virtual ~IOStream(); + virtual ~IOStream() = default; // ------------------------------------------------------------------- /** @brief Read from the file @@ -126,15 +126,6 @@ public: virtual void Flush() = 0; }; //! class IOStream -// ---------------------------------------------------------------------------------- -AI_FORCE_INLINE -IOStream::IOStream() AI_NO_EXCEPT = default; - -// ---------------------------------------------------------------------------------- -AI_FORCE_INLINE -IOStream::~IOStream() = default; -// ---------------------------------------------------------------------------------- - } //!namespace Assimp #endif //!!AI_IOSTREAM_H_INC diff --git a/include/assimp/IOStreamBuffer.h b/include/assimp/IOStreamBuffer.h index 2d3bcb730..5a6924a09 100644 --- a/include/assimp/IOStreamBuffer.h +++ b/include/assimp/IOStreamBuffer.h @@ -66,7 +66,7 @@ public: IOStreamBuffer(size_t cache = 4096 * 4096); /// @brief The class destructor. - ~IOStreamBuffer(); + ~IOStreamBuffer() = default; /// @brief Will open the cached access for a given stream. /// @param stream The stream to cache. @@ -140,9 +140,6 @@ AI_FORCE_INLINE IOStreamBuffer::IOStreamBuffer(size_t cache) : std::fill(m_cache.begin(), m_cache.end(), '\n'); } -template -AI_FORCE_INLINE IOStreamBuffer::~IOStreamBuffer() = default; - template AI_FORCE_INLINE bool IOStreamBuffer::open(IOStream *stream) { // file still opened! diff --git a/include/assimp/Importer.hpp b/include/assimp/Importer.hpp index ed12deb75..a3a0d9eae 100644 --- a/include/assimp/Importer.hpp +++ b/include/assimp/Importer.hpp @@ -5,8 +5,6 @@ Open Asset Import Library (assimp) Copyright (c) 2006-2024, assimp team - - All rights reserved. Redistribution and use of this software in source and binary forms, diff --git a/include/assimp/LineSplitter.h b/include/assimp/LineSplitter.h index 5d75294dd..635349dc0 100644 --- a/include/assimp/LineSplitter.h +++ b/include/assimp/LineSplitter.h @@ -86,7 +86,7 @@ public: */ LineSplitter(StreamReaderLE& stream, bool skip_empty_lines = true, bool trim = true); - ~LineSplitter(); + ~LineSplitter() = default; // ----------------------------------------- /** pseudo-iterator increment */ @@ -160,8 +160,6 @@ AI_FORCE_INLINE LineSplitter::LineSplitter(StreamReaderLE& stream, bool skip_emp mIdx = 0; } -AI_FORCE_INLINE LineSplitter::~LineSplitter() = default; - AI_FORCE_INLINE LineSplitter& LineSplitter::operator++() { if (mSwallow) { mSwallow = false; diff --git a/include/assimp/SGSpatialSort.h b/include/assimp/SGSpatialSort.h index ea774a9d9..13a214d44 100644 --- a/include/assimp/SGSpatialSort.h +++ b/include/assimp/SGSpatialSort.h @@ -4,7 +4,6 @@ Open Asset Import Library (assimp) Copyright (c) 2006-2024, assimp team - All rights reserved. Redistribution and use of this software in source and binary forms, @@ -63,10 +62,8 @@ namespace Assimp { * implementation to handle all details of its file format correctly. */ // ---------------------------------------------------------------------------------- -class ASSIMP_API SGSpatialSort -{ +class ASSIMP_API SGSpatialSort { public: - SGSpatialSort(); // ------------------------------------------------------------------- @@ -90,7 +87,7 @@ public: void Prepare(); /** Destructor */ - ~SGSpatialSort(); + ~SGSpatialSort() = default; // ------------------------------------------------------------------- /** Returns an iterator for all positions close to the given position. diff --git a/include/assimp/aabb.h b/include/assimp/aabb.h index 4d117e473..bd78e67a6 100644 --- a/include/assimp/aabb.h +++ b/include/assimp/aabb.h @@ -59,18 +59,12 @@ struct aiAABB { #ifdef __cplusplus /// @brief The default class constructor. - aiAABB() : - mMin(), mMax() { - // empty - } + aiAABB() = default; /// @brief The class constructor with the minimum and maximum. /// @param min The minimum dimension. /// @param max The maximum dimension. - aiAABB(const aiVector3D &min, const aiVector3D &max) : - mMin(min), mMax(max) { - // empty - } + aiAABB(const aiVector3D &min, const aiVector3D &max) : mMin(min), mMax(max) {} /// @brief The class destructor. ~aiAABB() = default; diff --git a/include/assimp/anim.h b/include/assimp/anim.h index 871207576..4e29fa0c0 100644 --- a/include/assimp/anim.h +++ b/include/assimp/anim.h @@ -90,6 +90,7 @@ struct aiVectorKey { bool operator==(const aiVectorKey &rhs) const { return rhs.mValue == this->mValue; } + bool operator!=(const aiVectorKey &rhs) const { return rhs.mValue != this->mValue; } From 8b9ed34eaa3e6ad24254cb7e058fb9150f66b865 Mon Sep 17 00:00:00 2001 From: Kim Kulling Date: Sun, 7 Apr 2024 22:14:12 +0100 Subject: [PATCH 64/77] Update CMakeLists.txt (#5531) * Update CMakeLists.txt * Update Version.cpp * Update CMakeLists.txt Update minimum version of cmake * Update utVersion.cpp Adapt unittest --- CMakeLists.txt | 24 ++++++++++++------------ code/CMakeLists.txt | 2 +- code/Common/Version.cpp | 2 +- test/unit/utVersion.cpp | 10 +++++----- 4 files changed, 19 insertions(+), 19 deletions(-) diff --git a/CMakeLists.txt b/CMakeLists.txt index a19bad32e..31c5e6615 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -38,9 +38,9 @@ SET(CMAKE_POLICY_DEFAULT_CMP0012 NEW) SET(CMAKE_POLICY_DEFAULT_CMP0074 NEW) SET(CMAKE_POLICY_DEFAULT_CMP0092 NEW) -CMAKE_MINIMUM_REQUIRED( VERSION 3.10 ) +CMAKE_MINIMUM_REQUIRED( VERSION 3.22 ) -# Disabled importers: m3d for 5.1 +# Disabled importers: m3d for 5.1 or later ADD_DEFINITIONS( -DASSIMP_BUILD_NO_M3D_IMPORTER) ADD_DEFINITIONS( -DASSIMP_BUILD_NO_M3D_EXPORTER) # Toggles the use of the hunter package manager @@ -55,7 +55,7 @@ IF(ASSIMP_HUNTER_ENABLED) add_definitions(-DASSIMP_USE_HUNTER) ENDIF() -PROJECT(Assimp VERSION 5.3.0) +PROJECT(Assimp VERSION 5.4.0) # All supported options ############################################### @@ -131,18 +131,18 @@ OPTION ( ASSIMP_IGNORE_GIT_HASH IF (WIN32) OPTION( ASSIMP_BUILD_ZLIB - "Build your own zlib" + "Build your zlib" ON ) ELSE() OPTION( ASSIMP_BUILD_ZLIB - "Build your own zlib" + "Build your zlib" OFF ) ENDIF() IF (WIN32) - # Use subset of Windows.h + # Use a subset of Windows.h ADD_DEFINITIONS( -DWIN32_LEAN_AND_MEAN ) IF(MSVC) @@ -150,16 +150,16 @@ IF (WIN32) "Install MSVC debug files." ON ) IF(NOT (MSVC_VERSION LESS 1900)) - # Multibyte character set is deprecated since at least MSVC2015 (possibly earlier) + # Multibyte character set has been deprecated since at least MSVC2015 (possibly earlier) ADD_DEFINITIONS( -DUNICODE -D_UNICODE ) ENDIF() - # Link statically against c/c++ lib to avoid missing redistriburable such as + # Link statically against c/c++ lib to avoid missing redistributable such as # "VCRUNTIME140.dll not found. Try reinstalling the app.", but give users # a choice to opt for the shared runtime if they want. option(USE_STATIC_CRT "Link against the static runtime libraries." OFF) - # The CMAKE_CXX_FLAGS vars can be overriden by some Visual Studio generators, so we use an alternative + # The CMAKE_CXX_FLAGS vars can be overridden by some Visual Studio generators, so we use an alternative # global method here: if (${USE_STATIC_CRT}) add_compile_options( @@ -249,9 +249,9 @@ SET(ASSIMP_LIBRARY_SUFFIX "" CACHE STRING "Suffix to append to library names") IF( UNIX ) # Use GNUInstallDirs for Unix predefined directories INCLUDE(GNUInstallDirs) - # Ensure that we do not run into issues like http://www.tcm.phy.cam.ac.uk/sw/inodes64.html on 32 bit linux + # Ensure that we do not run into issues like http://www.tcm.phy.cam.ac.uk/sw/inodes64.html on 32 bit Linux IF(NOT ${OPERATING_SYSTEM} MATCHES "Android") - IF ( CMAKE_SIZEOF_VOID_P EQUAL 4) # only necessary for 32-bit linux + IF ( CMAKE_SIZEOF_VOID_P EQUAL 4) # only necessary for 32-bit Linux ADD_DEFINITIONS(-D_FILE_OFFSET_BITS=64 ) ENDIF() ENDIF() @@ -289,7 +289,7 @@ ELSEIF(MSVC) IF(MSVC12) ADD_COMPILE_OPTIONS(/wd4351) ENDIF() - # supress warning for double to float conversion if Double precission is activated + # supress warning for double to float conversion if Double precision is activated ADD_COMPILE_OPTIONS(/wd4244) SET(CMAKE_CXX_FLAGS_DEBUG "${CMAKE_CXX_FLAGS_DEBUG} /D_DEBUG /Zi /Od") SET(CMAKE_CXX_FLAGS_RELEASE "${CMAKE_CXX_FLAGS_RELEASE}") diff --git a/code/CMakeLists.txt b/code/CMakeLists.txt index 28e2d40c6..0a7be6247 100644 --- a/code/CMakeLists.txt +++ b/code/CMakeLists.txt @@ -42,7 +42,7 @@ # 3) Add libassimp using the file lists (eliminates duplication of file names between # source groups and library command) # -cmake_minimum_required( VERSION 3.10 ) +cmake_minimum_required( VERSION 3.22 ) SET( HEADER_PATH ../include/assimp ) if(NOT ANDROID AND ASSIMP_ANDROID_JNIIOSYSTEM) diff --git a/code/Common/Version.cpp b/code/Common/Version.cpp index 24a5f5250..10ccf58e7 100644 --- a/code/Common/Version.cpp +++ b/code/Common/Version.cpp @@ -52,7 +52,7 @@ OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. static constexpr char LEGAL_INFORMATION[] = "Open Asset Import Library (Assimp).\n" "A free C/C++ library to import various 3D file formats into applications\n\n" - "(c) 2006-2023, Assimp team\n" + "(c) 2006-2024, Assimp team\n" "License under the terms and conditions of the 3-clause BSD license\n" "https://www.assimp.org\n"; diff --git a/test/unit/utVersion.cpp b/test/unit/utVersion.cpp index bba97a135..838d2dd7f 100644 --- a/test/unit/utVersion.cpp +++ b/test/unit/utVersion.cpp @@ -48,18 +48,18 @@ TEST_F( utVersion, aiGetLegalStringTest ) { EXPECT_NE( lv, nullptr ); std::string text( lv ); - size_t pos = text.find(std::string("2023")); + size_t pos = text.find(std::string("2024")); EXPECT_NE(pos, std::string::npos); } -TEST_F( utVersion, aiGetVersionMinorTest ) { - EXPECT_EQ(aiGetVersionMinor(), 3U); -} - TEST_F( utVersion, aiGetVersionMajorTest ) { EXPECT_EQ( aiGetVersionMajor(), 5U ); } +TEST_F( utVersion, aiGetVersionMinorTest ) { + EXPECT_EQ(aiGetVersionMinor(), 4U); +} + TEST_F( utVersion, aiGetVersionPatchTest ) { EXPECT_EQ(aiGetVersionPatch(), 0U ); } From b8aa68a080f98661c19e7c820fb24342492f9377 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Alex=20R=C3=B8nne=20Petersen?= Date: Mon, 8 Apr 2024 23:28:37 +0200 Subject: [PATCH 65/77] CMake: Allow linking draco statically if ASSIMP_BUILD_DRACO_STATIC is set. (#5535) * CMake: Mark draco as a private dependency since assimp does not publicly expose its interface. * CMake: Allow linking draco statically if ASSIMP_BUILD_DRACO_STATIC is set. --- CMakeLists.txt | 25 ++++++++++++++++++------- code/CMakeLists.txt | 2 +- 2 files changed, 19 insertions(+), 8 deletions(-) diff --git a/CMakeLists.txt b/CMakeLists.txt index 31c5e6615..670f29f86 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -621,6 +621,10 @@ ELSE () ADD_DEFINITIONS( -DASSIMP_BUILD_NO_C4D_IMPORTER ) ENDIF () +if(ASSIMP_BUILD_DRACO_STATIC) + set(ASSIMP_BUILD_DRACO ON) +endif() + # Draco requires cmake 3.12 IF (DEFINED CMAKE_VERSION AND "${CMAKE_VERSION}" VERSION_LESS "3.12") message(NOTICE "draco requires cmake 3.12 or newer, cmake is ${CMAKE_VERSION} . Draco is disabled") @@ -656,22 +660,29 @@ ELSE() "-Wno-sign-compare" "-Wno-unused-local-typedefs" ) - # Draco 1.4.1 does not explicitly export any symbols under GCC/clang - list(APPEND DRACO_CXX_FLAGS - "-fvisibility=default" - ) + + if(NOT ASSIMP_BUILD_DRACO_STATIC) + # Draco 1.4.1 does not explicitly export any symbols under GCC/clang + list(APPEND DRACO_CXX_FLAGS + "-fvisibility=default" + ) + endif() ENDIF() # Don't build or install all of Draco by default ADD_SUBDIRECTORY( "contrib/draco" EXCLUDE_FROM_ALL ) + if(ASSIMP_BUILD_DRACO_STATIC) + set_property(DIRECTORY "contrib/draco" PROPERTY BUILD_SHARED_LIBS OFF) + endif() + if(MSVC OR WIN32) set(draco_LIBRARIES "draco") else() - if(BUILD_SHARED_LIBS) - set(draco_LIBRARIES "draco_shared") - else() + if(ASSIMP_BUILD_DRACO_STATIC) set(draco_LIBRARIES "draco_static") + else() + set(draco_LIBRARIES "draco_shared") endif() endif() diff --git a/code/CMakeLists.txt b/code/CMakeLists.txt index 0a7be6247..a521c9fb8 100644 --- a/code/CMakeLists.txt +++ b/code/CMakeLists.txt @@ -1286,7 +1286,7 @@ IF(ASSIMP_HUNTER_ENABLED) endif() if (ASSIMP_BUILD_DRACO) - target_link_libraries(assimp PUBLIC ${draco_LIBRARIES}) + target_link_libraries(assimp PRIVATE ${draco_LIBRARIES}) endif() ELSE() TARGET_LINK_LIBRARIES(assimp ${ZLIB_LIBRARIES} ${OPENDDL_PARSER_LIBRARIES}) From 64d88276ef7117c09165e468dbb9acd999e324ac Mon Sep 17 00:00:00 2001 From: mosfet80 Date: Tue, 9 Apr 2024 00:08:38 +0200 Subject: [PATCH 66/77] updated minizip to last version (#5498) Version 1.3.1 has these key changes: Reject overflows of zip header fields in minizip Fix bug in inflateSync() for data held in bit buffer Add LIT_MEM define to use more memory for a small deflate speedup Fix decision on the emission of Zip64 end records in minizip Add bounds checking to ERR_MSG() macro, used by zError() Neutralize zip file traversal attacks in miniunz Fix a bug in ZLIB_DEBUG compiles in check_match() Version 1.3 has these key changes: Building using K&R (pre-ANSI) function definitions is no longer supported. Fixed a bug in deflateBound() for level 0 and memLevel 9. Fixed a bug when gzungetc() is used immediately after gzopen(). Fixed a bug when using gzflush() with a very small buffer. Fixed a crash when gzsetparams() is attempted for a transparent write. Fixed test/example.c to work with FORCE_STORED. Fixed minizip to allow it to open an empty zip file. Fixed reading disk number start on zip64 files in minizip. Fixed a logic error in minizip argument processing. Co-authored-by: Kim Kulling --- contrib/unzip/crypt.h | 12 +- contrib/unzip/ioapi.c | 61 ++--- contrib/unzip/ioapi.h | 38 +-- contrib/unzip/unzip.c | 527 +++++++++++++++--------------------------- contrib/unzip/unzip.h | 136 +++++------ 5 files changed, 300 insertions(+), 474 deletions(-) diff --git a/contrib/unzip/crypt.h b/contrib/unzip/crypt.h index 1cc41f19d..f4b93b78d 100644 --- a/contrib/unzip/crypt.h +++ b/contrib/unzip/crypt.h @@ -32,8 +32,7 @@ /*********************************************************************** * Return the next byte in the pseudo-random sequence */ -static int decrypt_byte(unsigned long* pkeys, const z_crc_t* pcrc_32_tab) -{ +static int decrypt_byte(unsigned long* pkeys, const z_crc_t* pcrc_32_tab) { unsigned temp; /* POTENTIAL BUG: temp*(temp^1) may overflow in an * unpredictable manner on 16-bit systems; not a problem * with any known compiler so far, though */ @@ -46,8 +45,7 @@ static int decrypt_byte(unsigned long* pkeys, const z_crc_t* pcrc_32_tab) /*********************************************************************** * Update the encryption keys with the next byte of plain text */ -static int update_keys(unsigned long* pkeys,const z_crc_t* pcrc_32_tab,int c) -{ +static int update_keys(unsigned long* pkeys, const z_crc_t* pcrc_32_tab, int c) { (*(pkeys+0)) = CRC32((*(pkeys+0)), c); (*(pkeys+1)) += (*(pkeys+0)) & 0xff; (*(pkeys+1)) = (*(pkeys+1)) * 134775813L + 1; @@ -63,8 +61,7 @@ static int update_keys(unsigned long* pkeys,const z_crc_t* pcrc_32_tab,int c) * Initialize the encryption keys and the random header according to * the given password. */ -static void init_keys(const char* passwd,unsigned long* pkeys,const z_crc_t* pcrc_32_tab) -{ +static void init_keys(const char* passwd, unsigned long* pkeys, const z_crc_t* pcrc_32_tab) { *(pkeys+0) = 305419896L; *(pkeys+1) = 591751049L; *(pkeys+2) = 878082192L; @@ -93,8 +90,7 @@ static unsigned crypthead(const char* passwd, /* password string */ int bufSize, unsigned long* pkeys, const z_crc_t* pcrc_32_tab, - unsigned long crcForCrypting) -{ + unsigned long crcForCrypting) { unsigned n; /* index in random header */ int t; /* temporary */ int c; /* random byte */ diff --git a/contrib/unzip/ioapi.c b/contrib/unzip/ioapi.c index 0ca29db6a..782d32469 100644 --- a/contrib/unzip/ioapi.c +++ b/contrib/unzip/ioapi.c @@ -14,7 +14,7 @@ #define _CRT_SECURE_NO_WARNINGS #endif -#if defined(__APPLE__) || defined(IOAPI_NO_64) +#if defined(__APPLE__) || defined(IOAPI_NO_64) || defined(__HAIKU__) || defined(MINIZIP_FOPEN_NO_64) // In darwin and perhaps other BSD variants off_t is a 64 bit value, hence no need for specific 64 bit functions #define FOPEN_FUNC(filename, mode) fopen(filename, mode) #define FTELLO_FUNC(stream) ftello(stream) @@ -28,8 +28,7 @@ #include "ioapi.h" -voidpf call_zopen64 (const zlib_filefunc64_32_def* pfilefunc,const void*filename,int mode) -{ +voidpf call_zopen64 (const zlib_filefunc64_32_def* pfilefunc, const void*filename, int mode) { if (pfilefunc->zfile_func64.zopen64_file != NULL) return (*(pfilefunc->zfile_func64.zopen64_file)) (pfilefunc->zfile_func64.opaque,filename,mode); else @@ -38,8 +37,7 @@ voidpf call_zopen64 (const zlib_filefunc64_32_def* pfilefunc,const void*filename } } -long call_zseek64 (const zlib_filefunc64_32_def* pfilefunc,voidpf filestream, ZPOS64_T offset, int origin) -{ +long call_zseek64 (const zlib_filefunc64_32_def* pfilefunc,voidpf filestream, ZPOS64_T offset, int origin) { if (pfilefunc->zfile_func64.zseek64_file != NULL) return (*(pfilefunc->zfile_func64.zseek64_file)) (pfilefunc->zfile_func64.opaque,filestream,offset,origin); else @@ -52,8 +50,7 @@ long call_zseek64 (const zlib_filefunc64_32_def* pfilefunc,voidpf filestream, ZP } } -ZPOS64_T call_ztell64 (const zlib_filefunc64_32_def* pfilefunc,voidpf filestream) -{ +ZPOS64_T call_ztell64 (const zlib_filefunc64_32_def* pfilefunc, voidpf filestream) { if (pfilefunc->zfile_func64.zseek64_file != NULL) return (*(pfilefunc->zfile_func64.ztell64_file)) (pfilefunc->zfile_func64.opaque,filestream); else @@ -66,11 +63,9 @@ ZPOS64_T call_ztell64 (const zlib_filefunc64_32_def* pfilefunc,voidpf filestream } } -void fill_zlib_filefunc64_32_def_from_filefunc32(zlib_filefunc64_32_def* p_filefunc64_32,const zlib_filefunc_def* p_filefunc32) -{ +void fill_zlib_filefunc64_32_def_from_filefunc32(zlib_filefunc64_32_def* p_filefunc64_32, const zlib_filefunc_def* p_filefunc32) { p_filefunc64_32->zfile_func64.zopen64_file = NULL; p_filefunc64_32->zopen32_file = p_filefunc32->zopen_file; - p_filefunc64_32->zfile_func64.zerror_file = p_filefunc32->zerror_file; p_filefunc64_32->zfile_func64.zread_file = p_filefunc32->zread_file; p_filefunc64_32->zfile_func64.zwrite_file = p_filefunc32->zwrite_file; p_filefunc64_32->zfile_func64.ztell64_file = NULL; @@ -84,16 +79,7 @@ void fill_zlib_filefunc64_32_def_from_filefunc32(zlib_filefunc64_32_def* p_filef -static voidpf ZCALLBACK fopen_file_func OF((voidpf opaque, const char* filename, int mode)); -static uLong ZCALLBACK fread_file_func OF((voidpf opaque, voidpf stream, void* buf, uLong size)); -static uLong ZCALLBACK fwrite_file_func OF((voidpf opaque, voidpf stream, const void* buf,uLong size)); -static ZPOS64_T ZCALLBACK ftell64_file_func OF((voidpf opaque, voidpf stream)); -static long ZCALLBACK fseek64_file_func OF((voidpf opaque, voidpf stream, ZPOS64_T offset, int origin)); -static int ZCALLBACK fclose_file_func OF((voidpf opaque, voidpf stream)); -static int ZCALLBACK ferror_file_func OF((voidpf opaque, voidpf stream)); - -static voidpf ZCALLBACK fopen_file_func (voidpf opaque, const char* filename, int mode) -{ +static voidpf ZCALLBACK fopen_file_func(voidpf opaque, const char* filename, int mode) { FILE* file = NULL; const char* mode_fopen = NULL; (void)opaque; @@ -111,8 +97,7 @@ static voidpf ZCALLBACK fopen_file_func (voidpf opaque, const char* filename, in return file; } -static voidpf ZCALLBACK fopen64_file_func (voidpf opaque, const void* filename, int mode) -{ +static voidpf ZCALLBACK fopen64_file_func(voidpf opaque, const void* filename, int mode) { FILE* file = NULL; const char* mode_fopen = NULL; (void)opaque; @@ -131,24 +116,21 @@ static voidpf ZCALLBACK fopen64_file_func (voidpf opaque, const void* filename, } -static uLong ZCALLBACK fread_file_func (voidpf opaque, voidpf stream, void* buf, uLong size) -{ +static uLong ZCALLBACK fread_file_func(voidpf opaque, voidpf stream, void* buf, uLong size) { uLong ret; (void)opaque; ret = (uLong)fread(buf, 1, (size_t)size, (FILE *)stream); return ret; } -static uLong ZCALLBACK fwrite_file_func (voidpf opaque, voidpf stream, const void* buf, uLong size) -{ +static uLong ZCALLBACK fwrite_file_func(voidpf opaque, voidpf stream, const void* buf, uLong size) { uLong ret; (void)opaque; ret = (uLong)fwrite(buf, 1, (size_t)size, (FILE *)stream); return ret; } -static long ZCALLBACK ftell_file_func (voidpf opaque, voidpf stream) -{ +static long ZCALLBACK ftell_file_func(voidpf opaque, voidpf stream) { long ret; (void)opaque; ret = ftell((FILE *)stream); @@ -156,16 +138,14 @@ static long ZCALLBACK ftell_file_func (voidpf opaque, voidpf stream) } -static ZPOS64_T ZCALLBACK ftell64_file_func (voidpf opaque, voidpf stream) -{ +static ZPOS64_T ZCALLBACK ftell64_file_func(voidpf opaque, voidpf stream) { ZPOS64_T ret; (void)opaque; ret = (ZPOS64_T)FTELLO_FUNC((FILE *)stream); return ret; } -static long ZCALLBACK fseek_file_func (voidpf opaque, voidpf stream, uLong offset, int origin) -{ +static long ZCALLBACK fseek_file_func(voidpf opaque, voidpf stream, uLong offset, int origin) { int fseek_origin=0; long ret; (void)opaque; @@ -188,8 +168,7 @@ static long ZCALLBACK fseek_file_func (voidpf opaque, voidpf stream, uLong offs return ret; } -static long ZCALLBACK fseek64_file_func (voidpf opaque, voidpf stream, ZPOS64_T offset, int origin) -{ +static long ZCALLBACK fseek64_file_func(voidpf opaque, voidpf stream, ZPOS64_T offset, int origin) { int fseek_origin=0; long ret; (void)opaque; @@ -208,31 +187,28 @@ static long ZCALLBACK fseek64_file_func (voidpf opaque, voidpf stream, ZPOS64_T } ret = 0; - if(FSEEKO_FUNC((FILE *)stream, (z_off_t)offset, fseek_origin) != 0) + if(FSEEKO_FUNC((FILE *)stream, (z_off64_t)offset, fseek_origin) != 0) ret = -1; return ret; } -static int ZCALLBACK fclose_file_func (voidpf opaque, voidpf stream) -{ +static int ZCALLBACK fclose_file_func(voidpf opaque, voidpf stream) { int ret; (void)opaque; ret = fclose((FILE *)stream); return ret; } -static int ZCALLBACK ferror_file_func (voidpf opaque, voidpf stream) -{ +static int ZCALLBACK ferror_file_func(voidpf opaque, voidpf stream) { int ret; (void)opaque; ret = ferror((FILE *)stream); return ret; } -void fill_fopen_filefunc (zlib_filefunc_def* pzlib_filefunc_def) -{ +void fill_fopen_filefunc(zlib_filefunc_def* pzlib_filefunc_def) { pzlib_filefunc_def->zopen_file = fopen_file_func; pzlib_filefunc_def->zread_file = fread_file_func; pzlib_filefunc_def->zwrite_file = fwrite_file_func; @@ -243,8 +219,7 @@ void fill_fopen_filefunc (zlib_filefunc_def* pzlib_filefunc_def) pzlib_filefunc_def->opaque = NULL; } -void fill_fopen64_filefunc (zlib_filefunc64_def* pzlib_filefunc_def) -{ +void fill_fopen64_filefunc(zlib_filefunc64_def* pzlib_filefunc_def) { pzlib_filefunc_def->zopen64_file = fopen64_file_func; pzlib_filefunc_def->zread_file = fread_file_func; pzlib_filefunc_def->zwrite_file = fwrite_file_func; diff --git a/contrib/unzip/ioapi.h b/contrib/unzip/ioapi.h index 548dafb5e..a2d2e6e60 100644 --- a/contrib/unzip/ioapi.h +++ b/contrib/unzip/ioapi.h @@ -50,7 +50,7 @@ #define ftello64 ftell #define fseeko64 fseek #else -#if defined(__FreeBSD__) || defined(__OpenBSD__) || defined(__NetBSD__) || defined(__HAIKU__) +#if defined(__FreeBSD__) || defined(__OpenBSD__) || defined(__NetBSD__) || defined(__HAIKU__) || defined(MINIZIP_FOPEN_NO_64) #define fopen64 fopen #define ftello64 ftello #define fseeko64 fseeko @@ -82,7 +82,7 @@ #include "mz64conf.h" #endif -/* a type choosen by DEFINE */ +/* a type chosen by DEFINE */ #ifdef HAVE_64BIT_INT_CUSTOM typedef 64BIT_INT_CUSTOM_TYPE ZPOS64_T; #else @@ -134,17 +134,17 @@ extern "C" { -typedef voidpf (ZCALLBACK *open_file_func) OF((voidpf opaque, const char* filename, int mode)); -typedef uLong (ZCALLBACK *read_file_func) OF((voidpf opaque, voidpf stream, void* buf, uLong size)); -typedef uLong (ZCALLBACK *write_file_func) OF((voidpf opaque, voidpf stream, const void* buf, uLong size)); -typedef int (ZCALLBACK *close_file_func) OF((voidpf opaque, voidpf stream)); -typedef int (ZCALLBACK *testerror_file_func) OF((voidpf opaque, voidpf stream)); +typedef voidpf (ZCALLBACK *open_file_func) (voidpf opaque, const char* filename, int mode); +typedef uLong (ZCALLBACK *read_file_func) (voidpf opaque, voidpf stream, void* buf, uLong size); +typedef uLong (ZCALLBACK *write_file_func) (voidpf opaque, voidpf stream, const void* buf, uLong size); +typedef int (ZCALLBACK *close_file_func) (voidpf opaque, voidpf stream); +typedef int (ZCALLBACK *testerror_file_func) (voidpf opaque, voidpf stream); -typedef long (ZCALLBACK *tell_file_func) OF((voidpf opaque, voidpf stream)); -typedef long (ZCALLBACK *seek_file_func) OF((voidpf opaque, voidpf stream, uLong offset, int origin)); +typedef long (ZCALLBACK *tell_file_func) (voidpf opaque, voidpf stream); +typedef long (ZCALLBACK *seek_file_func) (voidpf opaque, voidpf stream, uLong offset, int origin); -/* here is the "old" 32 bits structure structure */ +/* here is the "old" 32 bits structure */ typedef struct zlib_filefunc_def_s { open_file_func zopen_file; @@ -157,9 +157,9 @@ typedef struct zlib_filefunc_def_s voidpf opaque; } zlib_filefunc_def; -typedef ZPOS64_T (ZCALLBACK *tell64_file_func) OF((voidpf opaque, voidpf stream)); -typedef long (ZCALLBACK *seek64_file_func) OF((voidpf opaque, voidpf stream, ZPOS64_T offset, int origin)); -typedef voidpf (ZCALLBACK *open64_file_func) OF((voidpf opaque, const void* filename, int mode)); +typedef ZPOS64_T (ZCALLBACK *tell64_file_func) (voidpf opaque, voidpf stream); +typedef long (ZCALLBACK *seek64_file_func) (voidpf opaque, voidpf stream, ZPOS64_T offset, int origin); +typedef voidpf (ZCALLBACK *open64_file_func) (voidpf opaque, const void* filename, int mode); typedef struct zlib_filefunc64_def_s { @@ -173,8 +173,8 @@ typedef struct zlib_filefunc64_def_s voidpf opaque; } zlib_filefunc64_def; -void fill_fopen64_filefunc OF((zlib_filefunc64_def* pzlib_filefunc_def)); -void fill_fopen_filefunc OF((zlib_filefunc_def* pzlib_filefunc_def)); +void fill_fopen64_filefunc(zlib_filefunc64_def* pzlib_filefunc_def); +void fill_fopen_filefunc(zlib_filefunc_def* pzlib_filefunc_def); /* now internal definition, only for zip.c and unzip.h */ typedef struct zlib_filefunc64_32_def_s @@ -193,11 +193,11 @@ typedef struct zlib_filefunc64_32_def_s #define ZCLOSE64(filefunc,filestream) ((*((filefunc).zfile_func64.zclose_file)) ((filefunc).zfile_func64.opaque,filestream)) #define ZERROR64(filefunc,filestream) ((*((filefunc).zfile_func64.zerror_file)) ((filefunc).zfile_func64.opaque,filestream)) -voidpf call_zopen64 OF((const zlib_filefunc64_32_def* pfilefunc,const void*filename,int mode)); -long call_zseek64 OF((const zlib_filefunc64_32_def* pfilefunc,voidpf filestream, ZPOS64_T offset, int origin)); -ZPOS64_T call_ztell64 OF((const zlib_filefunc64_32_def* pfilefunc,voidpf filestream)); +voidpf call_zopen64(const zlib_filefunc64_32_def* pfilefunc,const void*filename,int mode); +long call_zseek64(const zlib_filefunc64_32_def* pfilefunc,voidpf filestream, ZPOS64_T offset, int origin); +ZPOS64_T call_ztell64(const zlib_filefunc64_32_def* pfilefunc,voidpf filestream); -void fill_zlib_filefunc64_32_def_from_filefunc32(zlib_filefunc64_32_def* p_filefunc64_32,const zlib_filefunc_def* p_filefunc32); +void fill_zlib_filefunc64_32_def_from_filefunc32(zlib_filefunc64_32_def* p_filefunc64_32,const zlib_filefunc_def* p_filefunc32); #define ZOPEN64(filefunc,filename,mode) (call_zopen64((&(filefunc)),(filename),(mode))) #define ZTELL64(filefunc,filestream) (call_ztell64((&(filefunc)),(filestream))) diff --git a/contrib/unzip/unzip.c b/contrib/unzip/unzip.c index e703549d2..ea05b7d62 100644 --- a/contrib/unzip/unzip.c +++ b/contrib/unzip/unzip.c @@ -49,12 +49,12 @@ Copyright (C) 2007-2008 Even Rouault - Oct-2009 - Mathias Svensson - Removed cpl_* from symbol names (Even Rouault added them but since this is now moved to a new project (minizip64) I renamed them again). + Oct-2009 - Mathias Svensson - Removed cpl_* from symbol names (Even Rouault added them but since this is now moved to a new project (minizip64) I renamed them again). Oct-2009 - Mathias Svensson - Fixed problem if uncompressed size was > 4G and compressed size was <4G should only read the compressed/uncompressed size from the Zip64 format if the size from normal header was 0xFFFFFFFF - Oct-2009 - Mathias Svensson - Applied some bug fixes from paches recived from Gilles Vollant - Oct-2009 - Mathias Svensson - Applied support to unzip files with compression mathod BZIP2 (bzip2 lib is required) + Oct-2009 - Mathias Svensson - Applied some bug fixes from patches received from Gilles Vollant + Oct-2009 - Mathias Svensson - Applied support to unzip files with compression method BZIP2 (bzip2 lib is required) Patch created by Daniel Borca Jan-2010 - back to unzip and minizip 1.0 name scheme, with compatibility layer @@ -77,8 +77,6 @@ #ifdef STDC # include -# include -# include #endif #ifdef NO_ERRNO_H extern int errno; @@ -111,9 +109,6 @@ #ifndef ALLOC # define ALLOC(size) (malloc(size)) #endif -#ifndef TRYFREE -# define TRYFREE(p) { free(p);} -#endif #define SIZECENTRALDIRITEM (0x2e) #define SIZEZIPLOCALHEADER (0x1e) @@ -122,7 +117,7 @@ const char unz_copyright[] = " unzip 1.01 Copyright 1998-2004 Gilles Vollant - http://www.winimage.com/zLibDll"; -/* unz_file_info_interntal contain internal info about a file in zipfile*/ +/* unz_file_info64_internal contain internal info about a file in zipfile*/ typedef struct unz_file_info64_internal_s { ZPOS64_T offset_curfile;/* relative offset of local header 8 bytes */ @@ -153,7 +148,7 @@ typedef struct ZPOS64_T rest_read_compressed; /* number of byte to be decompressed */ ZPOS64_T rest_read_uncompressed;/*number of byte to be obtained after decomp*/ zlib_filefunc64_32_def z_filefunc; - voidpf filestream; /* io structore of the zipfile */ + voidpf filestream; /* io structure of the zipfile */ uLong compression_method; /* compression method (0==store) */ ZPOS64_T byte_before_the_zipfile;/* byte before the zipfile, (>0 for sfx)*/ int raw; @@ -166,7 +161,7 @@ typedef struct { zlib_filefunc64_32_def z_filefunc; int is64bitOpenFunction; - voidpf filestream; /* io structore of the zipfile */ + voidpf filestream; /* io structure of the zipfile */ unz_global_info64 gi; /* public global information */ ZPOS64_T byte_before_the_zipfile;/* byte before the zipfile, (>0 for sfx)*/ ZPOS64_T num_file; /* number of the current file in the zipfile*/ @@ -197,29 +192,44 @@ typedef struct #include "crypt.h" #endif + /* =========================================================================== - Read a byte from a gz_stream; update next_in and avail_in. Return EOF - for end of file. - IN assertion: the stream s has been successfully opened for reading. + Reads a long in LSB order from the given gz_stream. Sets */ - -local int unz64local_getByte OF(( - const zlib_filefunc64_32_def* pzlib_filefunc_def, - voidpf filestream, - int *pi)); - -local int unz64local_getByte(const zlib_filefunc64_32_def* pzlib_filefunc_def, voidpf filestream, int *pi) -{ - unsigned char c; - int err = (int)ZREAD64(*pzlib_filefunc_def,filestream,&c,1); - if (err==1) +local int unz64local_getShort(const zlib_filefunc64_32_def* pzlib_filefunc_def, + voidpf filestream, + uLong *pX) { + unsigned char c[2]; + int err = (int)ZREAD64(*pzlib_filefunc_def,filestream,c,2); + if (err==2) { - *pi = (int)c; + *pX = c[0] | ((uLong)c[1] << 8); return UNZ_OK; } else { + *pX = 0; + if (ZERROR64(*pzlib_filefunc_def,filestream)) + return UNZ_ERRNO; + else + return UNZ_EOF; + } +} + +local int unz64local_getLong(const zlib_filefunc64_32_def* pzlib_filefunc_def, + voidpf filestream, + uLong *pX) { + unsigned char c[4]; + int err = (int)ZREAD64(*pzlib_filefunc_def,filestream,c,4); + if (err==4) + { + *pX = c[0] | ((uLong)c[1] << 8) | ((uLong)c[2] << 16) | ((uLong)c[3] << 24); + return UNZ_OK; + } + else + { + *pX = 0; if (ZERROR64(*pzlib_filefunc_def,filestream)) return UNZ_ERRNO; else @@ -228,126 +238,29 @@ local int unz64local_getByte(const zlib_filefunc64_32_def* pzlib_filefunc_def, v } -/* =========================================================================== - Reads a long in LSB order from the given gz_stream. Sets -*/ -local int unz64local_getShort OF(( - const zlib_filefunc64_32_def* pzlib_filefunc_def, - voidpf filestream, - uLong *pX)); - -local int unz64local_getShort (const zlib_filefunc64_32_def* pzlib_filefunc_def, - voidpf filestream, - uLong *pX) -{ - uLong x ; - int i = 0; - int err; - - err = unz64local_getByte(pzlib_filefunc_def,filestream,&i); - x = (uLong)i; - - if (err==UNZ_OK) - err = unz64local_getByte(pzlib_filefunc_def,filestream,&i); - x |= ((uLong)i)<<8; - - if (err==UNZ_OK) - *pX = x; +local int unz64local_getLong64(const zlib_filefunc64_32_def* pzlib_filefunc_def, + voidpf filestream, + ZPOS64_T *pX) { + unsigned char c[8]; + int err = (int)ZREAD64(*pzlib_filefunc_def,filestream,c,8); + if (err==8) + { + *pX = c[0] | ((ZPOS64_T)c[1] << 8) | ((ZPOS64_T)c[2] << 16) | ((ZPOS64_T)c[3] << 24) + | ((ZPOS64_T)c[4] << 32) | ((ZPOS64_T)c[5] << 40) | ((ZPOS64_T)c[6] << 48) | ((ZPOS64_T)c[7] << 56); + return UNZ_OK; + } else + { *pX = 0; - return err; -} - -local int unz64local_getLong OF(( - const zlib_filefunc64_32_def* pzlib_filefunc_def, - voidpf filestream, - uLong *pX)); - -local int unz64local_getLong (const zlib_filefunc64_32_def* pzlib_filefunc_def, - voidpf filestream, - uLong *pX) -{ - uLong x ; - int i = 0; - int err; - - err = unz64local_getByte(pzlib_filefunc_def,filestream,&i); - x = (uLong)i; - - if (err==UNZ_OK) - err = unz64local_getByte(pzlib_filefunc_def,filestream,&i); - x |= ((uLong)i)<<8; - - if (err==UNZ_OK) - err = unz64local_getByte(pzlib_filefunc_def,filestream,&i); - x |= ((uLong)i)<<16; - - if (err==UNZ_OK) - err = unz64local_getByte(pzlib_filefunc_def,filestream,&i); - x += ((uLong)i)<<24; - - if (err==UNZ_OK) - *pX = x; - else - *pX = 0; - return err; -} - -local int unz64local_getLong64 OF(( - const zlib_filefunc64_32_def* pzlib_filefunc_def, - voidpf filestream, - ZPOS64_T *pX)); - - -local int unz64local_getLong64 (const zlib_filefunc64_32_def* pzlib_filefunc_def, - voidpf filestream, - ZPOS64_T *pX) -{ - ZPOS64_T x ; - int i = 0; - int err; - - err = unz64local_getByte(pzlib_filefunc_def,filestream,&i); - x = (ZPOS64_T)i; - - if (err==UNZ_OK) - err = unz64local_getByte(pzlib_filefunc_def,filestream,&i); - x |= ((ZPOS64_T)i)<<8; - - if (err==UNZ_OK) - err = unz64local_getByte(pzlib_filefunc_def,filestream,&i); - x |= ((ZPOS64_T)i)<<16; - - if (err==UNZ_OK) - err = unz64local_getByte(pzlib_filefunc_def,filestream,&i); - x |= ((ZPOS64_T)i)<<24; - - if (err==UNZ_OK) - err = unz64local_getByte(pzlib_filefunc_def,filestream,&i); - x |= ((ZPOS64_T)i)<<32; - - if (err==UNZ_OK) - err = unz64local_getByte(pzlib_filefunc_def,filestream,&i); - x |= ((ZPOS64_T)i)<<40; - - if (err==UNZ_OK) - err = unz64local_getByte(pzlib_filefunc_def,filestream,&i); - x |= ((ZPOS64_T)i)<<48; - - if (err==UNZ_OK) - err = unz64local_getByte(pzlib_filefunc_def,filestream,&i); - x |= ((ZPOS64_T)i)<<56; - - if (err==UNZ_OK) - *pX = x; - else - *pX = 0; - return err; + if (ZERROR64(*pzlib_filefunc_def,filestream)) + return UNZ_ERRNO; + else + return UNZ_EOF; + } } /* My own strcmpi / strcasecmp */ -local int strcmpcasenosensitive_internal (const char* fileName1, const char* fileName2) -{ +local int strcmpcasenosensitive_internal(const char* fileName1, const char* fileName2) { for (;;) { char c1=*(fileName1++); @@ -379,19 +292,17 @@ local int strcmpcasenosensitive_internal (const char* fileName1, const char* fil #endif /* - Compare two filename (fileName1,fileName2). - If iCaseSenisivity = 1, comparision is case sensitivity (like strcmp) - If iCaseSenisivity = 2, comparision is not case sensitivity (like strcmpi + Compare two filenames (fileName1,fileName2). + If iCaseSensitivity = 1, comparison is case sensitive (like strcmp) + If iCaseSensitivity = 2, comparison is not case sensitive (like strcmpi or strcasecmp) - If iCaseSenisivity = 0, case sensitivity is defaut of your operating system + If iCaseSensitivity = 0, case sensitivity is default of your operating system (like 1 on Unix, 2 on Windows) */ extern int ZEXPORT unzStringFileNameCompare (const char* fileName1, - const char* fileName2, - int iCaseSensitivity) - -{ + const char* fileName2, + int iCaseSensitivity) { if (iCaseSensitivity==0) iCaseSensitivity=CASESENSITIVITYDEFAULTVALUE; @@ -405,21 +316,23 @@ extern int ZEXPORT unzStringFileNameCompare (const char* fileName1, #define BUFREADCOMMENT (0x400) #endif +#ifndef CENTRALDIRINVALID +#define CENTRALDIRINVALID ((ZPOS64_T)(-1)) +#endif + /* Locate the Central directory of a zipfile (at the end, just before the global comment) */ -local ZPOS64_T unz64local_SearchCentralDir OF((const zlib_filefunc64_32_def* pzlib_filefunc_def, voidpf filestream)); -local ZPOS64_T unz64local_SearchCentralDir(const zlib_filefunc64_32_def* pzlib_filefunc_def, voidpf filestream) -{ +local ZPOS64_T unz64local_SearchCentralDir(const zlib_filefunc64_32_def* pzlib_filefunc_def, voidpf filestream) { unsigned char* buf; ZPOS64_T uSizeFile; ZPOS64_T uBackRead; ZPOS64_T uMaxBack=0xffff; /* maximum size of global comment */ - ZPOS64_T uPosFound=0; + ZPOS64_T uPosFound=CENTRALDIRINVALID; if (ZSEEK64(*pzlib_filefunc_def,filestream,0,ZLIB_FILEFUNC_SEEK_END) != 0) - return 0; + return CENTRALDIRINVALID; uSizeFile = ZTELL64(*pzlib_filefunc_def,filestream); @@ -429,7 +342,7 @@ local ZPOS64_T unz64local_SearchCentralDir(const zlib_filefunc64_32_def* pzlib_f buf = (unsigned char*)ALLOC(BUFREADCOMMENT+4); if (buf==NULL) - return 0; + return CENTRALDIRINVALID; uBackRead = 4; while (uBackReadz_filefunc, s->filestream); - TRYFREE(s); + free(s); return UNZ_OK; } @@ -825,8 +727,7 @@ extern int ZEXPORT unzClose (unzFile file) Write info about the ZipFile in the *pglobal_info structure. No preparation of the structure is needed return UNZ_OK if there is no problem. */ -extern int ZEXPORT unzGetGlobalInfo64 (unzFile file, unz_global_info64* pglobal_info) -{ +extern int ZEXPORT unzGetGlobalInfo64(unzFile file, unz_global_info64* pglobal_info) { unz64_s* s; if (file==NULL) return UNZ_PARAMERROR; @@ -835,8 +736,7 @@ extern int ZEXPORT unzGetGlobalInfo64 (unzFile file, unz_global_info64* pglobal_ return UNZ_OK; } -extern int ZEXPORT unzGetGlobalInfo (unzFile file, unz_global_info* pglobal_info32) -{ +extern int ZEXPORT unzGetGlobalInfo(unzFile file, unz_global_info* pglobal_info32) { unz64_s* s; if (file==NULL) return UNZ_PARAMERROR; @@ -847,10 +747,9 @@ extern int ZEXPORT unzGetGlobalInfo (unzFile file, unz_global_info* pglobal_info return UNZ_OK; } /* - Translate date/time from Dos format to tm_unz (readable more easilty) + Translate date/time from Dos format to tm_unz (readable more easily) */ -local void unz64local_DosDateToTmuDate (ZPOS64_T ulDosDate, tm_unz* ptm) -{ +local void unz64local_DosDateToTmuDate(ZPOS64_T ulDosDate, tm_unz* ptm) { ZPOS64_T uDate; uDate = (ZPOS64_T)(ulDosDate>>16); ptm->tm_mday = (int)(uDate&0x1f) ; @@ -865,28 +764,16 @@ local void unz64local_DosDateToTmuDate (ZPOS64_T ulDosDate, tm_unz* ptm) /* Get Info about the current file in the zipfile, with internal only info */ -local int unz64local_GetCurrentFileInfoInternal OF((unzFile file, - unz_file_info64 *pfile_info, - unz_file_info64_internal - *pfile_info_internal, - char *szFileName, - uLong fileNameBufferSize, - void *extraField, - uLong extraFieldBufferSize, - char *szComment, - uLong commentBufferSize)); - -local int unz64local_GetCurrentFileInfoInternal (unzFile file, - unz_file_info64 *pfile_info, - unz_file_info64_internal - *pfile_info_internal, - char *szFileName, - uLong fileNameBufferSize, - void *extraField, - uLong extraFieldBufferSize, - char *szComment, - uLong commentBufferSize) -{ +local int unz64local_GetCurrentFileInfoInternal(unzFile file, + unz_file_info64 *pfile_info, + unz_file_info64_internal + *pfile_info_internal, + char *szFileName, + uLong fileNameBufferSize, + void *extraField, + uLong extraFieldBufferSize, + char *szComment, + uLong commentBufferSize) { unz64_s* s; unz_file_info64 file_info; unz_file_info64_internal file_info_internal; @@ -1038,33 +925,31 @@ local int unz64local_GetCurrentFileInfoInternal (unzFile file, /* ZIP64 extra fields */ if (headerId == 0x0001) { - uLong uL1; + if(file_info.uncompressed_size == MAXU32) + { + if (unz64local_getLong64(&s->z_filefunc, s->filestream,&file_info.uncompressed_size) != UNZ_OK) + err=UNZ_ERRNO; + } - if(file_info.uncompressed_size == MAXU32) - { - if (unz64local_getLong64(&s->z_filefunc, s->filestream,&file_info.uncompressed_size) != UNZ_OK) - err=UNZ_ERRNO; - } + if(file_info.compressed_size == MAXU32) + { + if (unz64local_getLong64(&s->z_filefunc, s->filestream,&file_info.compressed_size) != UNZ_OK) + err=UNZ_ERRNO; + } - if(file_info.compressed_size == MAXU32) - { - if (unz64local_getLong64(&s->z_filefunc, s->filestream,&file_info.compressed_size) != UNZ_OK) - err=UNZ_ERRNO; - } + if(file_info_internal.offset_curfile == MAXU32) + { + /* Relative Header offset */ + if (unz64local_getLong64(&s->z_filefunc, s->filestream,&file_info_internal.offset_curfile) != UNZ_OK) + err=UNZ_ERRNO; + } - if(file_info_internal.offset_curfile == MAXU32) - { - /* Relative Header offset */ - if (unz64local_getLong64(&s->z_filefunc, s->filestream,&file_info_internal.offset_curfile) != UNZ_OK) - err=UNZ_ERRNO; - } - - if(file_info.disk_num_start == MAXU32) - { - /* Disk Start Number */ - if (unz64local_getLong(&s->z_filefunc, s->filestream,&uL1) != UNZ_OK) - err=UNZ_ERRNO; - } + if(file_info.disk_num_start == 0xffff) + { + /* Disk Start Number */ + if (unz64local_getLong(&s->z_filefunc, s->filestream,&file_info.disk_num_start) != UNZ_OK) + err=UNZ_ERRNO; + } } else @@ -1121,24 +1006,22 @@ local int unz64local_GetCurrentFileInfoInternal (unzFile file, No preparation of the structure is needed return UNZ_OK if there is no problem. */ -extern int ZEXPORT unzGetCurrentFileInfo64 (unzFile file, - unz_file_info64 * pfile_info, - char * szFileName, uLong fileNameBufferSize, - void *extraField, uLong extraFieldBufferSize, - char* szComment, uLong commentBufferSize) -{ +extern int ZEXPORT unzGetCurrentFileInfo64(unzFile file, + unz_file_info64 * pfile_info, + char * szFileName, uLong fileNameBufferSize, + void *extraField, uLong extraFieldBufferSize, + char* szComment, uLong commentBufferSize) { return unz64local_GetCurrentFileInfoInternal(file,pfile_info,NULL, - szFileName,fileNameBufferSize, - extraField,extraFieldBufferSize, - szComment,commentBufferSize); + szFileName,fileNameBufferSize, + extraField,extraFieldBufferSize, + szComment,commentBufferSize); } -extern int ZEXPORT unzGetCurrentFileInfo (unzFile file, - unz_file_info * pfile_info, - char * szFileName, uLong fileNameBufferSize, - void *extraField, uLong extraFieldBufferSize, - char* szComment, uLong commentBufferSize) -{ +extern int ZEXPORT unzGetCurrentFileInfo(unzFile file, + unz_file_info * pfile_info, + char * szFileName, uLong fileNameBufferSize, + void *extraField, uLong extraFieldBufferSize, + char* szComment, uLong commentBufferSize) { int err; unz_file_info64 file_info64; err = unz64local_GetCurrentFileInfoInternal(file,&file_info64,NULL, @@ -1162,7 +1045,7 @@ extern int ZEXPORT unzGetCurrentFileInfo (unzFile file, pfile_info->internal_fa = file_info64.internal_fa; pfile_info->external_fa = file_info64.external_fa; - pfile_info->tmu_date = file_info64.tmu_date, + pfile_info->tmu_date = file_info64.tmu_date; pfile_info->compressed_size = (uLong)file_info64.compressed_size; @@ -1175,8 +1058,7 @@ extern int ZEXPORT unzGetCurrentFileInfo (unzFile file, Set the current file of the zipfile to the first file. return UNZ_OK if there is no problem */ -extern int ZEXPORT unzGoToFirstFile (unzFile file) -{ +extern int ZEXPORT unzGoToFirstFile(unzFile file) { int err=UNZ_OK; unz64_s* s; if (file==NULL) @@ -1196,8 +1078,7 @@ extern int ZEXPORT unzGoToFirstFile (unzFile file) return UNZ_OK if there is no problem return UNZ_END_OF_LIST_OF_FILE if the actual file was the latest. */ -extern int ZEXPORT unzGoToNextFile (unzFile file) -{ +extern int ZEXPORT unzGoToNextFile(unzFile file) { unz64_s* s; int err; @@ -1229,8 +1110,7 @@ extern int ZEXPORT unzGoToNextFile (unzFile file) UNZ_OK if the file is found. It becomes the current file. UNZ_END_OF_LIST_OF_FILE if the file is not found */ -extern int ZEXPORT unzLocateFile (unzFile file, const char *szFileName, int iCaseSensitivity) -{ +extern int ZEXPORT unzLocateFile(unzFile file, const char *szFileName, int iCaseSensitivity) { unz64_s* s; int err; @@ -1305,8 +1185,7 @@ typedef struct unz_file_pos_s } unz_file_pos; */ -extern int ZEXPORT unzGetFilePos64(unzFile file, unz64_file_pos* file_pos) -{ +extern int ZEXPORT unzGetFilePos64(unzFile file, unz64_file_pos* file_pos) { unz64_s* s; if (file==NULL || file_pos==NULL) @@ -1321,10 +1200,7 @@ extern int ZEXPORT unzGetFilePos64(unzFile file, unz64_file_pos* file_pos) return UNZ_OK; } -extern int ZEXPORT unzGetFilePos( - unzFile file, - unz_file_pos* file_pos) -{ +extern int ZEXPORT unzGetFilePos(unzFile file, unz_file_pos* file_pos) { unz64_file_pos file_pos64; int err = unzGetFilePos64(file,&file_pos64); if (err==UNZ_OK) @@ -1335,8 +1211,7 @@ extern int ZEXPORT unzGetFilePos( return err; } -extern int ZEXPORT unzGoToFilePos64(unzFile file, const unz64_file_pos* file_pos) -{ +extern int ZEXPORT unzGoToFilePos64(unzFile file, const unz64_file_pos* file_pos) { unz64_s* s; int err; @@ -1357,10 +1232,7 @@ extern int ZEXPORT unzGoToFilePos64(unzFile file, const unz64_file_pos* file_pos return err; } -extern int ZEXPORT unzGoToFilePos( - unzFile file, - unz_file_pos* file_pos) -{ +extern int ZEXPORT unzGoToFilePos(unzFile file, unz_file_pos* file_pos) { unz64_file_pos file_pos64; if (file_pos == NULL) return UNZ_PARAMERROR; @@ -1382,10 +1254,9 @@ extern int ZEXPORT unzGoToFilePos( store in *piSizeVar the size of extra info in local header (filename and size of extra field data) */ -local int unz64local_CheckCurrentFileCoherencyHeader (unz64_s* s, uInt* piSizeVar, - ZPOS64_T * poffset_local_extrafield, - uInt * psize_local_extrafield) -{ +local int unz64local_CheckCurrentFileCoherencyHeader(unz64_s* s, uInt* piSizeVar, + ZPOS64_T * poffset_local_extrafield, + uInt * psize_local_extrafield) { uLong uMagic,uData,uFlags; uLong size_filename; uLong size_extra_field; @@ -1469,9 +1340,8 @@ local int unz64local_CheckCurrentFileCoherencyHeader (unz64_s* s, uInt* piSizeVa Open for reading data the current file in the zipfile. If there is no error and the file is opened, the return value is UNZ_OK. */ -extern int ZEXPORT unzOpenCurrentFile3 (unzFile file, int* method, - int* level, int raw, const char* password) -{ +extern int ZEXPORT unzOpenCurrentFile3(unzFile file, int* method, + int* level, int raw, const char* password) { int err=UNZ_OK; uInt iSizeVar; unz64_s* s; @@ -1509,7 +1379,7 @@ extern int ZEXPORT unzOpenCurrentFile3 (unzFile file, int* method, if (pfile_in_zip_read_info->read_buffer==NULL) { - TRYFREE(pfile_in_zip_read_info); + free(pfile_in_zip_read_info); return UNZ_INTERNALERROR; } @@ -1566,8 +1436,8 @@ extern int ZEXPORT unzOpenCurrentFile3 (unzFile file, int* method, pfile_in_zip_read_info->stream_initialised=Z_BZIP2ED; else { - TRYFREE(pfile_in_zip_read_info->read_buffer); - TRYFREE(pfile_in_zip_read_info); + free(pfile_in_zip_read_info->read_buffer); + free(pfile_in_zip_read_info); return err; } #else @@ -1587,8 +1457,8 @@ extern int ZEXPORT unzOpenCurrentFile3 (unzFile file, int* method, pfile_in_zip_read_info->stream_initialised=Z_DEFLATED; else { - TRYFREE(pfile_in_zip_read_info->read_buffer); - TRYFREE(pfile_in_zip_read_info); + free(pfile_in_zip_read_info->read_buffer); + free(pfile_in_zip_read_info); return err; } /* windowBits is passed < 0 to tell that there is no zlib header. @@ -1640,25 +1510,21 @@ extern int ZEXPORT unzOpenCurrentFile3 (unzFile file, int* method, return UNZ_OK; } -extern int ZEXPORT unzOpenCurrentFile (unzFile file) -{ +extern int ZEXPORT unzOpenCurrentFile(unzFile file) { return unzOpenCurrentFile3(file, NULL, NULL, 0, NULL); } -extern int ZEXPORT unzOpenCurrentFilePassword (unzFile file, const char* password) -{ +extern int ZEXPORT unzOpenCurrentFilePassword(unzFile file, const char* password) { return unzOpenCurrentFile3(file, NULL, NULL, 0, password); } -extern int ZEXPORT unzOpenCurrentFile2 (unzFile file, int* method, int* level, int raw) -{ +extern int ZEXPORT unzOpenCurrentFile2(unzFile file, int* method, int* level, int raw) { return unzOpenCurrentFile3(file, method, level, raw, NULL); } /** Addition for GDAL : START */ -extern ZPOS64_T ZEXPORT unzGetCurrentFileZStreamPos64( unzFile file) -{ +extern ZPOS64_T ZEXPORT unzGetCurrentFileZStreamPos64(unzFile file) { unz64_s* s; file_in_zip64_read_info_s* pfile_in_zip_read_info; s=(unz64_s*)file; @@ -1678,13 +1544,12 @@ extern ZPOS64_T ZEXPORT unzGetCurrentFileZStreamPos64( unzFile file) buf contain buffer where data must be copied len the size of buf. - return the number of byte copied if somes bytes are copied + return the number of byte copied if some bytes are copied return 0 if the end of file was reached return <0 with error code if there is an error (UNZ_ERRNO for IO error, or zLib error for uncompress error) */ -extern int ZEXPORT unzReadCurrentFile (unzFile file, voidp buf, unsigned len) -{ +extern int ZEXPORT unzReadCurrentFile(unzFile file, voidp buf, unsigned len) { int err=UNZ_OK; uInt iRead = 0; unz64_s* s; @@ -1891,8 +1756,7 @@ extern int ZEXPORT unzReadCurrentFile (unzFile file, voidp buf, unsigned len) /* Give the current position in uncompressed data */ -extern z_off_t ZEXPORT unztell (unzFile file) -{ +extern z_off_t ZEXPORT unztell(unzFile file) { unz64_s* s; file_in_zip64_read_info_s* pfile_in_zip_read_info; if (file==NULL) @@ -1906,8 +1770,7 @@ extern z_off_t ZEXPORT unztell (unzFile file) return (z_off_t)pfile_in_zip_read_info->stream.total_out; } -extern ZPOS64_T ZEXPORT unztell64 (unzFile file) -{ +extern ZPOS64_T ZEXPORT unztell64(unzFile file) { unz64_s* s; file_in_zip64_read_info_s* pfile_in_zip_read_info; @@ -1926,8 +1789,7 @@ extern ZPOS64_T ZEXPORT unztell64 (unzFile file) /* return 1 if the end of file was reached, 0 elsewhere */ -extern int ZEXPORT unzeof (unzFile file) -{ +extern int ZEXPORT unzeof(unzFile file) { unz64_s* s; file_in_zip64_read_info_s* pfile_in_zip_read_info; if (file==NULL) @@ -1958,8 +1820,7 @@ more info in the local-header version than in the central-header) the return value is the number of bytes copied in buf, or (if <0) the error code */ -extern int ZEXPORT unzGetLocalExtrafield (unzFile file, voidp buf, unsigned len) -{ +extern int ZEXPORT unzGetLocalExtrafield(unzFile file, voidp buf, unsigned len) { unz64_s* s; file_in_zip64_read_info_s* pfile_in_zip_read_info; uInt read_now; @@ -2006,8 +1867,7 @@ extern int ZEXPORT unzGetLocalExtrafield (unzFile file, voidp buf, unsigned len) Close the file in zip opened with unzOpenCurrentFile Return UNZ_CRCERROR if all the file was read but the CRC is not good */ -extern int ZEXPORT unzCloseCurrentFile (unzFile file) -{ +extern int ZEXPORT unzCloseCurrentFile(unzFile file) { int err=UNZ_OK; unz64_s* s; @@ -2029,7 +1889,7 @@ extern int ZEXPORT unzCloseCurrentFile (unzFile file) } - TRYFREE(pfile_in_zip_read_info->read_buffer); + free(pfile_in_zip_read_info->read_buffer); pfile_in_zip_read_info->read_buffer = NULL; if (pfile_in_zip_read_info->stream_initialised == Z_DEFLATED) inflateEnd(&pfile_in_zip_read_info->stream); @@ -2040,7 +1900,7 @@ extern int ZEXPORT unzCloseCurrentFile (unzFile file) pfile_in_zip_read_info->stream_initialised = 0; - TRYFREE(pfile_in_zip_read_info); + free(pfile_in_zip_read_info); s->pfile_in_zip_read=NULL; @@ -2053,8 +1913,7 @@ extern int ZEXPORT unzCloseCurrentFile (unzFile file) uSizeBuf is the size of the szComment buffer. return the number of byte copied or an error code <0 */ -extern int ZEXPORT unzGetGlobalComment (unzFile file, char * szComment, uLong uSizeBuf) -{ +extern int ZEXPORT unzGetGlobalComment(unzFile file, char * szComment, uLong uSizeBuf) { unz64_s* s; uLong uReadThis ; if (file==NULL) @@ -2081,8 +1940,7 @@ extern int ZEXPORT unzGetGlobalComment (unzFile file, char * szComment, uLong uS } /* Additions by RX '2004 */ -extern ZPOS64_T ZEXPORT unzGetOffset64(unzFile file) -{ +extern ZPOS64_T ZEXPORT unzGetOffset64(unzFile file) { unz64_s* s; if (file==NULL) @@ -2096,8 +1954,7 @@ extern ZPOS64_T ZEXPORT unzGetOffset64(unzFile file) return s->pos_in_central_dir; } -extern uLong ZEXPORT unzGetOffset (unzFile file) -{ +extern uLong ZEXPORT unzGetOffset(unzFile file) { ZPOS64_T offset64; if (file==NULL) @@ -2106,8 +1963,7 @@ extern uLong ZEXPORT unzGetOffset (unzFile file) return (uLong)offset64; } -extern int ZEXPORT unzSetOffset64(unzFile file, ZPOS64_T pos) -{ +extern int ZEXPORT unzSetOffset64(unzFile file, ZPOS64_T pos) { unz64_s* s; int err; @@ -2124,7 +1980,6 @@ extern int ZEXPORT unzSetOffset64(unzFile file, ZPOS64_T pos) return err; } -extern int ZEXPORT unzSetOffset (unzFile file, uLong pos) -{ +extern int ZEXPORT unzSetOffset (unzFile file, uLong pos) { return unzSetOffset64(file,pos); } diff --git a/contrib/unzip/unzip.h b/contrib/unzip/unzip.h index 6f95e94d7..5cfc9c627 100644 --- a/contrib/unzip/unzip.h +++ b/contrib/unzip/unzip.h @@ -150,21 +150,21 @@ typedef struct unz_file_info_s tm_unz tmu_date; } unz_file_info; -extern int ZEXPORT unzStringFileNameCompare OF ((const char* fileName1, - const char* fileName2, - int iCaseSensitivity)); +extern int ZEXPORT unzStringFileNameCompare(const char* fileName1, + const char* fileName2, + int iCaseSensitivity); /* - Compare two filename (fileName1,fileName2). - If iCaseSenisivity = 1, comparision is case sensitivity (like strcmp) - If iCaseSenisivity = 2, comparision is not case sensitivity (like strcmpi + Compare two filenames (fileName1,fileName2). + If iCaseSensitivity = 1, comparison is case sensitive (like strcmp) + If iCaseSensitivity = 2, comparison is not case sensitive (like strcmpi or strcasecmp) - If iCaseSenisivity = 0, case sensitivity is defaut of your operating system + If iCaseSensitivity = 0, case sensitivity is default of your operating system (like 1 on Unix, 2 on Windows) */ -extern unzFile ZEXPORT unzOpen OF((const char *path)); -extern unzFile ZEXPORT unzOpen64 OF((const void *path)); +extern unzFile ZEXPORT unzOpen(const char *path); +extern unzFile ZEXPORT unzOpen64(const void *path); /* Open a Zip file. path contain the full pathname (by example, on a Windows XP computer "c:\\zlib\\zlib113.zip" or on an Unix computer @@ -181,41 +181,41 @@ extern unzFile ZEXPORT unzOpen64 OF((const void *path)); */ -extern unzFile ZEXPORT unzOpen2 OF((const char *path, - zlib_filefunc_def* pzlib_filefunc_def)); +extern unzFile ZEXPORT unzOpen2(const char *path, + zlib_filefunc_def* pzlib_filefunc_def); /* Open a Zip file, like unzOpen, but provide a set of file low level API for read/write the zip file (see ioapi.h) */ -extern unzFile ZEXPORT unzOpen2_64 OF((const void *path, - zlib_filefunc64_def* pzlib_filefunc_def)); +extern unzFile ZEXPORT unzOpen2_64(const void *path, + zlib_filefunc64_def* pzlib_filefunc_def); /* Open a Zip file, like unz64Open, but provide a set of file low level API for read/write the zip file (see ioapi.h) */ -extern int ZEXPORT unzClose OF((unzFile file)); +extern int ZEXPORT unzClose(unzFile file); /* Close a ZipFile opened with unzOpen. If there is files inside the .Zip opened with unzOpenCurrentFile (see later), these files MUST be closed with unzCloseCurrentFile before call unzClose. return UNZ_OK if there is no problem. */ -extern int ZEXPORT unzGetGlobalInfo OF((unzFile file, - unz_global_info *pglobal_info)); +extern int ZEXPORT unzGetGlobalInfo(unzFile file, + unz_global_info *pglobal_info); -extern int ZEXPORT unzGetGlobalInfo64 OF((unzFile file, - unz_global_info64 *pglobal_info)); +extern int ZEXPORT unzGetGlobalInfo64(unzFile file, + unz_global_info64 *pglobal_info); /* Write info about the ZipFile in the *pglobal_info structure. No preparation of the structure is needed return UNZ_OK if there is no problem. */ -extern int ZEXPORT unzGetGlobalComment OF((unzFile file, - char *szComment, - uLong uSizeBuf)); +extern int ZEXPORT unzGetGlobalComment(unzFile file, + char *szComment, + uLong uSizeBuf); /* Get the global comment string of the ZipFile, in the szComment buffer. uSizeBuf is the size of the szComment buffer. @@ -226,22 +226,22 @@ extern int ZEXPORT unzGetGlobalComment OF((unzFile file, /***************************************************************************/ /* Unzip package allow you browse the directory of the zipfile */ -extern int ZEXPORT unzGoToFirstFile OF((unzFile file)); +extern int ZEXPORT unzGoToFirstFile(unzFile file); /* Set the current file of the zipfile to the first file. return UNZ_OK if there is no problem */ -extern int ZEXPORT unzGoToNextFile OF((unzFile file)); +extern int ZEXPORT unzGoToNextFile(unzFile file); /* Set the current file of the zipfile to the next file. return UNZ_OK if there is no problem return UNZ_END_OF_LIST_OF_FILE if the actual file was the latest. */ -extern int ZEXPORT unzLocateFile OF((unzFile file, - const char *szFileName, - int iCaseSensitivity)); +extern int ZEXPORT unzLocateFile(unzFile file, + const char *szFileName, + int iCaseSensitivity); /* Try locate the file szFileName in the zipfile. For the iCaseSensitivity signification, see unzStringFileNameCompare @@ -285,28 +285,28 @@ extern int ZEXPORT unzGoToFilePos64( /* ****************************************** */ -extern int ZEXPORT unzGetCurrentFileInfo64 OF((unzFile file, - unz_file_info64 *pfile_info, - char *szFileName, - uLong fileNameBufferSize, - void *extraField, - uLong extraFieldBufferSize, - char *szComment, - uLong commentBufferSize)); +extern int ZEXPORT unzGetCurrentFileInfo64(unzFile file, + unz_file_info64 *pfile_info, + char *szFileName, + uLong fileNameBufferSize, + void *extraField, + uLong extraFieldBufferSize, + char *szComment, + uLong commentBufferSize); -extern int ZEXPORT unzGetCurrentFileInfo OF((unzFile file, - unz_file_info *pfile_info, - char *szFileName, - uLong fileNameBufferSize, - void *extraField, - uLong extraFieldBufferSize, - char *szComment, - uLong commentBufferSize)); +extern int ZEXPORT unzGetCurrentFileInfo(unzFile file, + unz_file_info *pfile_info, + char *szFileName, + uLong fileNameBufferSize, + void *extraField, + uLong extraFieldBufferSize, + char *szComment, + uLong commentBufferSize); /* Get Info about the current file - if pfile_info!=NULL, the *pfile_info structure will contain somes info about + if pfile_info!=NULL, the *pfile_info structure will contain some info about the current file - if szFileName!=NULL, the filemane string will be copied in szFileName + if szFileName!=NULL, the filename string will be copied in szFileName (fileNameBufferSize is the size of the buffer) if extraField!=NULL, the extra field information will be copied in extraField (extraFieldBufferSize is the size of the buffer). @@ -318,7 +318,7 @@ extern int ZEXPORT unzGetCurrentFileInfo OF((unzFile file, /** Addition for GDAL : START */ -extern ZPOS64_T ZEXPORT unzGetCurrentFileZStreamPos64 OF((unzFile file)); +extern ZPOS64_T ZEXPORT unzGetCurrentFileZStreamPos64(unzFile file); /** Addition for GDAL : END */ @@ -328,24 +328,24 @@ extern ZPOS64_T ZEXPORT unzGetCurrentFileZStreamPos64 OF((unzFile file)); from it, and close it (you can close it before reading all the file) */ -extern int ZEXPORT unzOpenCurrentFile OF((unzFile file)); +extern int ZEXPORT unzOpenCurrentFile(unzFile file); /* Open for reading data the current file in the zipfile. If there is no error, the return value is UNZ_OK. */ -extern int ZEXPORT unzOpenCurrentFilePassword OF((unzFile file, - const char* password)); +extern int ZEXPORT unzOpenCurrentFilePassword(unzFile file, + const char* password); /* Open for reading data the current file in the zipfile. password is a crypting password If there is no error, the return value is UNZ_OK. */ -extern int ZEXPORT unzOpenCurrentFile2 OF((unzFile file, - int* method, - int* level, - int raw)); +extern int ZEXPORT unzOpenCurrentFile2(unzFile file, + int* method, + int* level, + int raw); /* Same than unzOpenCurrentFile, but open for read raw the file (not uncompress) if raw==1 @@ -355,11 +355,11 @@ extern int ZEXPORT unzOpenCurrentFile2 OF((unzFile file, but you CANNOT set method parameter as NULL */ -extern int ZEXPORT unzOpenCurrentFile3 OF((unzFile file, - int* method, - int* level, - int raw, - const char* password)); +extern int ZEXPORT unzOpenCurrentFile3(unzFile file, + int* method, + int* level, + int raw, + const char* password); /* Same than unzOpenCurrentFile, but open for read raw the file (not uncompress) if raw==1 @@ -370,41 +370,41 @@ extern int ZEXPORT unzOpenCurrentFile3 OF((unzFile file, */ -extern int ZEXPORT unzCloseCurrentFile OF((unzFile file)); +extern int ZEXPORT unzCloseCurrentFile(unzFile file); /* Close the file in zip opened with unzOpenCurrentFile Return UNZ_CRCERROR if all the file was read but the CRC is not good */ -extern int ZEXPORT unzReadCurrentFile OF((unzFile file, - voidp buf, - unsigned len)); +extern int ZEXPORT unzReadCurrentFile(unzFile file, + voidp buf, + unsigned len); /* Read bytes from the current file (opened by unzOpenCurrentFile) buf contain buffer where data must be copied len the size of buf. - return the number of byte copied if somes bytes are copied + return the number of byte copied if some bytes are copied return 0 if the end of file was reached return <0 with error code if there is an error (UNZ_ERRNO for IO error, or zLib error for uncompress error) */ -extern z_off_t ZEXPORT unztell OF((unzFile file)); +extern z_off_t ZEXPORT unztell(unzFile file); -extern ZPOS64_T ZEXPORT unztell64 OF((unzFile file)); +extern ZPOS64_T ZEXPORT unztell64(unzFile file); /* Give the current position in uncompressed data */ -extern int ZEXPORT unzeof OF((unzFile file)); +extern int ZEXPORT unzeof(unzFile file); /* return 1 if the end of file was reached, 0 elsewhere */ -extern int ZEXPORT unzGetLocalExtrafield OF((unzFile file, - voidp buf, - unsigned len)); +extern int ZEXPORT unzGetLocalExtrafield(unzFile file, + voidp buf, + unsigned len); /* Read extra field from the current file (opened by unzOpenCurrentFile) This is the local-header version of the extra field (sometimes, there is From 3ff7851ff9ad3004bb934fedaf657ffad0572573 Mon Sep 17 00:00:00 2001 From: mosfet80 Date: Tue, 9 Apr 2024 23:31:10 +0200 Subject: [PATCH 67/77] updated STBIMAGElib (#5500) 2.29 (2023-05-xx) optimizations Co-authored-by: Kim Kulling --- contrib/stb/stb_image.h | 348 ++++++++++++++++++++-------------------- 1 file changed, 173 insertions(+), 175 deletions(-) diff --git a/contrib/stb/stb_image.h b/contrib/stb/stb_image.h index 5e807a0a6..a632d5435 100644 --- a/contrib/stb/stb_image.h +++ b/contrib/stb/stb_image.h @@ -1,4 +1,4 @@ -/* stb_image - v2.28 - public domain image loader - http://nothings.org/stb +/* stb_image - v2.29 - public domain image loader - http://nothings.org/stb no warranty implied; use at your own risk Do this: @@ -48,6 +48,7 @@ LICENSE RECENT REVISION HISTORY: + 2.29 (2023-05-xx) optimizations 2.28 (2023-01-29) many error fixes, security errors, just tons of stuff 2.27 (2021-07-11) document stbi_info better, 16-bit PNM support, bug fixes 2.26 (2020-07-13) many minor fixes @@ -1072,8 +1073,8 @@ static int stbi__addints_valid(int a, int b) return a <= INT_MAX - b; } -// returns 1 if the product of two signed shorts is valid, 0 on overflow. -static int stbi__mul2shorts_valid(short a, short b) +// returns 1 if the product of two ints fits in a signed short, 0 on overflow. +static int stbi__mul2shorts_valid(int a, int b) { if (b == 0 || b == -1) return 1; // multiplication by 0 is always 0; check for -1 so SHRT_MIN/b doesn't overflow if ((a >= 0) == (b >= 0)) return a <= SHRT_MAX/b; // product is positive, so similar to mul2sizes_valid @@ -3384,13 +3385,13 @@ static int stbi__decode_jpeg_header(stbi__jpeg *z, int scan) return 1; } -static int stbi__skip_jpeg_junk_at_end(stbi__jpeg *j) +static stbi_uc stbi__skip_jpeg_junk_at_end(stbi__jpeg *j) { // some JPEGs have junk at end, skip over it but if we find what looks // like a valid marker, resume there while (!stbi__at_eof(j->s)) { - int x = stbi__get8(j->s); - while (x == 255) { // might be a marker + stbi_uc x = stbi__get8(j->s); + while (x == 0xff) { // might be a marker if (stbi__at_eof(j->s)) return STBI__MARKER_none; x = stbi__get8(j->s); if (x != 0x00 && x != 0xff) { @@ -4176,6 +4177,7 @@ typedef struct { stbi_uc *zbuffer, *zbuffer_end; int num_bits; + int hit_zeof_once; stbi__uint32 code_buffer; char *zout; @@ -4242,9 +4244,20 @@ stbi_inline static int stbi__zhuffman_decode(stbi__zbuf *a, stbi__zhuffman *z) int b,s; if (a->num_bits < 16) { if (stbi__zeof(a)) { - return -1; /* report error for unexpected end of data. */ + if (!a->hit_zeof_once) { + // This is the first time we hit eof, insert 16 extra padding btis + // to allow us to keep going; if we actually consume any of them + // though, that is invalid data. This is caught later. + a->hit_zeof_once = 1; + a->num_bits += 16; // add 16 implicit zero bits + } else { + // We already inserted our extra 16 padding bits and are again + // out, this stream is actually prematurely terminated. + return -1; + } + } else { + stbi__fill_bits(a); } - stbi__fill_bits(a); } b = z->fast[a->code_buffer & STBI__ZFAST_MASK]; if (b) { @@ -4309,6 +4322,13 @@ static int stbi__parse_huffman_block(stbi__zbuf *a) int len,dist; if (z == 256) { a->zout = zout; + if (a->hit_zeof_once && a->num_bits < 16) { + // The first time we hit zeof, we inserted 16 extra zero bits into our bit + // buffer so the decoder can just do its speculative decoding. But if we + // actually consumed any of those bits (which is the case when num_bits < 16), + // the stream actually read past the end so it is malformed. + return stbi__err("unexpected end","Corrupt PNG"); + } return 1; } if (z >= 286) return stbi__err("bad huffman code","Corrupt PNG"); // per DEFLATE, length codes 286 and 287 must not appear in compressed data @@ -4320,7 +4340,7 @@ static int stbi__parse_huffman_block(stbi__zbuf *a) dist = stbi__zdist_base[z]; if (stbi__zdist_extra[z]) dist += stbi__zreceive(a, stbi__zdist_extra[z]); if (zout - a->zout_start < dist) return stbi__err("bad dist","Corrupt PNG"); - if (zout + len > a->zout_end) { + if (len > a->zout_end - zout) { if (!stbi__zexpand(a, zout, len)) return 0; zout = a->zout; } @@ -4464,6 +4484,7 @@ static int stbi__parse_zlib(stbi__zbuf *a, int parse_header) if (!stbi__parse_zlib_header(a)) return 0; a->num_bits = 0; a->code_buffer = 0; + a->hit_zeof_once = 0; do { final = stbi__zreceive(a,1); type = stbi__zreceive(a,2); @@ -4619,9 +4640,8 @@ enum { STBI__F_up=2, STBI__F_avg=3, STBI__F_paeth=4, - // synthetic filters used for first scanline to avoid needing a dummy row of 0s - STBI__F_avg_first, - STBI__F_paeth_first + // synthetic filter used for first scanline to avoid needing a dummy row of 0s + STBI__F_avg_first }; static stbi_uc first_row_filter[5] = @@ -4630,29 +4650,56 @@ static stbi_uc first_row_filter[5] = STBI__F_sub, STBI__F_none, STBI__F_avg_first, - STBI__F_paeth_first + STBI__F_sub // Paeth with b=c=0 turns out to be equivalent to sub }; static int stbi__paeth(int a, int b, int c) { - int p = a + b - c; - int pa = abs(p-a); - int pb = abs(p-b); - int pc = abs(p-c); - if (pa <= pb && pa <= pc) return a; - if (pb <= pc) return b; - return c; + // This formulation looks very different from the reference in the PNG spec, but is + // actually equivalent and has favorable data dependencies and admits straightforward + // generation of branch-free code, which helps performance significantly. + int thresh = c*3 - (a + b); + int lo = a < b ? a : b; + int hi = a < b ? b : a; + int t0 = (hi <= thresh) ? lo : c; + int t1 = (thresh <= lo) ? hi : t0; + return t1; } static const stbi_uc stbi__depth_scale_table[9] = { 0, 0xff, 0x55, 0, 0x11, 0,0,0, 0x01 }; +// adds an extra all-255 alpha channel +// dest == src is legal +// img_n must be 1 or 3 +static void stbi__create_png_alpha_expand8(stbi_uc *dest, stbi_uc *src, stbi__uint32 x, int img_n) +{ + int i; + // must process data backwards since we allow dest==src + if (img_n == 1) { + for (i=x-1; i >= 0; --i) { + dest[i*2+1] = 255; + dest[i*2+0] = src[i]; + } + } else { + STBI_ASSERT(img_n == 3); + for (i=x-1; i >= 0; --i) { + dest[i*4+3] = 255; + dest[i*4+2] = src[i*3+2]; + dest[i*4+1] = src[i*3+1]; + dest[i*4+0] = src[i*3+0]; + } + } +} + // create the png data from post-deflated data static int stbi__create_png_image_raw(stbi__png *a, stbi_uc *raw, stbi__uint32 raw_len, int out_n, stbi__uint32 x, stbi__uint32 y, int depth, int color) { - int bytes = (depth == 16? 2 : 1); + int bytes = (depth == 16 ? 2 : 1); stbi__context *s = a->s; stbi__uint32 i,j,stride = x*out_n*bytes; stbi__uint32 img_len, img_width_bytes; + stbi_uc *filter_buf; + int all_ok = 1; int k; int img_n = s->img_n; // copy it into a local for later @@ -4664,8 +4711,11 @@ static int stbi__create_png_image_raw(stbi__png *a, stbi_uc *raw, stbi__uint32 r a->out = (stbi_uc *) stbi__malloc_mad3(x, y, output_bytes, 0); // extra bytes to write off the end into if (!a->out) return stbi__err("outofmem", "Out of memory"); + // note: error exits here don't need to clean up a->out individually, + // stbi__do_png always does on error. if (!stbi__mad3sizes_valid(img_n, x, depth, 7)) return stbi__err("too large", "Corrupt PNG"); img_width_bytes = (((img_n * x * depth) + 7) >> 3); + if (!stbi__mad2sizes_valid(img_width_bytes, y, img_width_bytes)) return stbi__err("too large", "Corrupt PNG"); img_len = (img_width_bytes + 1) * y; // we used to check for exact match between raw_len and img_len on non-interlaced PNGs, @@ -4673,189 +4723,137 @@ static int stbi__create_png_image_raw(stbi__png *a, stbi_uc *raw, stbi__uint32 r // so just check for raw_len < img_len always. if (raw_len < img_len) return stbi__err("not enough pixels","Corrupt PNG"); + // Allocate two scan lines worth of filter workspace buffer. + filter_buf = (stbi_uc *) stbi__malloc_mad2(img_width_bytes, 2, 0); + if (!filter_buf) return stbi__err("outofmem", "Out of memory"); + + // Filtering for low-bit-depth images + if (depth < 8) { + filter_bytes = 1; + width = img_width_bytes; + } + for (j=0; j < y; ++j) { - stbi_uc *cur = a->out + stride*j; - stbi_uc *prior; + // cur/prior filter buffers alternate + stbi_uc *cur = filter_buf + (j & 1)*img_width_bytes; + stbi_uc *prior = filter_buf + (~j & 1)*img_width_bytes; + stbi_uc *dest = a->out + stride*j; + int nk = width * filter_bytes; int filter = *raw++; - if (filter > 4) - return stbi__err("invalid filter","Corrupt PNG"); - - if (depth < 8) { - if (img_width_bytes > x) return stbi__err("invalid width","Corrupt PNG"); - cur += x*out_n - img_width_bytes; // store output to the rightmost img_len bytes, so we can decode in place - filter_bytes = 1; - width = img_width_bytes; + // check filter type + if (filter > 4) { + all_ok = stbi__err("invalid filter","Corrupt PNG"); + break; } - prior = cur - stride; // bugfix: need to compute this after 'cur +=' computation above // if first row, use special filter that doesn't sample previous row if (j == 0) filter = first_row_filter[filter]; - // handle first byte explicitly - for (k=0; k < filter_bytes; ++k) { - switch (filter) { - case STBI__F_none : cur[k] = raw[k]; break; - case STBI__F_sub : cur[k] = raw[k]; break; - case STBI__F_up : cur[k] = STBI__BYTECAST(raw[k] + prior[k]); break; - case STBI__F_avg : cur[k] = STBI__BYTECAST(raw[k] + (prior[k]>>1)); break; - case STBI__F_paeth : cur[k] = STBI__BYTECAST(raw[k] + stbi__paeth(0,prior[k],0)); break; - case STBI__F_avg_first : cur[k] = raw[k]; break; - case STBI__F_paeth_first: cur[k] = raw[k]; break; - } + // perform actual filtering + switch (filter) { + case STBI__F_none: + memcpy(cur, raw, nk); + break; + case STBI__F_sub: + memcpy(cur, raw, filter_bytes); + for (k = filter_bytes; k < nk; ++k) + cur[k] = STBI__BYTECAST(raw[k] + cur[k-filter_bytes]); + break; + case STBI__F_up: + for (k = 0; k < nk; ++k) + cur[k] = STBI__BYTECAST(raw[k] + prior[k]); + break; + case STBI__F_avg: + for (k = 0; k < filter_bytes; ++k) + cur[k] = STBI__BYTECAST(raw[k] + (prior[k]>>1)); + for (k = filter_bytes; k < nk; ++k) + cur[k] = STBI__BYTECAST(raw[k] + ((prior[k] + cur[k-filter_bytes])>>1)); + break; + case STBI__F_paeth: + for (k = 0; k < filter_bytes; ++k) + cur[k] = STBI__BYTECAST(raw[k] + prior[k]); // prior[k] == stbi__paeth(0,prior[k],0) + for (k = filter_bytes; k < nk; ++k) + cur[k] = STBI__BYTECAST(raw[k] + stbi__paeth(cur[k-filter_bytes], prior[k], prior[k-filter_bytes])); + break; + case STBI__F_avg_first: + memcpy(cur, raw, filter_bytes); + for (k = filter_bytes; k < nk; ++k) + cur[k] = STBI__BYTECAST(raw[k] + (cur[k-filter_bytes] >> 1)); + break; } - if (depth == 8) { - if (img_n != out_n) - cur[img_n] = 255; // first pixel - raw += img_n; - cur += out_n; - prior += out_n; - } else if (depth == 16) { - if (img_n != out_n) { - cur[filter_bytes] = 255; // first pixel top byte - cur[filter_bytes+1] = 255; // first pixel bottom byte - } - raw += filter_bytes; - cur += output_bytes; - prior += output_bytes; - } else { - raw += 1; - cur += 1; - prior += 1; - } + raw += nk; - // this is a little gross, so that we don't switch per-pixel or per-component - if (depth < 8 || img_n == out_n) { - int nk = (width - 1)*filter_bytes; - #define STBI__CASE(f) \ - case f: \ - for (k=0; k < nk; ++k) - switch (filter) { - // "none" filter turns into a memcpy here; make that explicit. - case STBI__F_none: memcpy(cur, raw, nk); break; - STBI__CASE(STBI__F_sub) { cur[k] = STBI__BYTECAST(raw[k] + cur[k-filter_bytes]); } break; - STBI__CASE(STBI__F_up) { cur[k] = STBI__BYTECAST(raw[k] + prior[k]); } break; - STBI__CASE(STBI__F_avg) { cur[k] = STBI__BYTECAST(raw[k] + ((prior[k] + cur[k-filter_bytes])>>1)); } break; - STBI__CASE(STBI__F_paeth) { cur[k] = STBI__BYTECAST(raw[k] + stbi__paeth(cur[k-filter_bytes],prior[k],prior[k-filter_bytes])); } break; - STBI__CASE(STBI__F_avg_first) { cur[k] = STBI__BYTECAST(raw[k] + (cur[k-filter_bytes] >> 1)); } break; - STBI__CASE(STBI__F_paeth_first) { cur[k] = STBI__BYTECAST(raw[k] + stbi__paeth(cur[k-filter_bytes],0,0)); } break; - } - #undef STBI__CASE - raw += nk; - } else { - STBI_ASSERT(img_n+1 == out_n); - #define STBI__CASE(f) \ - case f: \ - for (i=x-1; i >= 1; --i, cur[filter_bytes]=255,raw+=filter_bytes,cur+=output_bytes,prior+=output_bytes) \ - for (k=0; k < filter_bytes; ++k) - switch (filter) { - STBI__CASE(STBI__F_none) { cur[k] = raw[k]; } break; - STBI__CASE(STBI__F_sub) { cur[k] = STBI__BYTECAST(raw[k] + cur[k- output_bytes]); } break; - STBI__CASE(STBI__F_up) { cur[k] = STBI__BYTECAST(raw[k] + prior[k]); } break; - STBI__CASE(STBI__F_avg) { cur[k] = STBI__BYTECAST(raw[k] + ((prior[k] + cur[k- output_bytes])>>1)); } break; - STBI__CASE(STBI__F_paeth) { cur[k] = STBI__BYTECAST(raw[k] + stbi__paeth(cur[k- output_bytes],prior[k],prior[k- output_bytes])); } break; - STBI__CASE(STBI__F_avg_first) { cur[k] = STBI__BYTECAST(raw[k] + (cur[k- output_bytes] >> 1)); } break; - STBI__CASE(STBI__F_paeth_first) { cur[k] = STBI__BYTECAST(raw[k] + stbi__paeth(cur[k- output_bytes],0,0)); } break; - } - #undef STBI__CASE - - // the loop above sets the high byte of the pixels' alpha, but for - // 16 bit png files we also need the low byte set. we'll do that here. - if (depth == 16) { - cur = a->out + stride*j; // start at the beginning of the row again - for (i=0; i < x; ++i,cur+=output_bytes) { - cur[filter_bytes+1] = 255; - } - } - } - } - - // we make a separate pass to expand bits to pixels; for performance, - // this could run two scanlines behind the above code, so it won't - // intefere with filtering but will still be in the cache. - if (depth < 8) { - for (j=0; j < y; ++j) { - stbi_uc *cur = a->out + stride*j; - stbi_uc *in = a->out + stride*j + x*out_n - img_width_bytes; - // unpack 1/2/4-bit into a 8-bit buffer. allows us to keep the common 8-bit path optimal at minimal cost for 1/2/4-bit - // png guarante byte alignment, if width is not multiple of 8/4/2 we'll decode dummy trailing data that will be skipped in the later loop + // expand decoded bits in cur to dest, also adding an extra alpha channel if desired + if (depth < 8) { stbi_uc scale = (color == 0) ? stbi__depth_scale_table[depth] : 1; // scale grayscale values to 0..255 range + stbi_uc *in = cur; + stbi_uc *out = dest; + stbi_uc inb = 0; + stbi__uint32 nsmp = x*img_n; - // note that the final byte might overshoot and write more data than desired. - // we can allocate enough data that this never writes out of memory, but it - // could also overwrite the next scanline. can it overwrite non-empty data - // on the next scanline? yes, consider 1-pixel-wide scanlines with 1-bit-per-pixel. - // so we need to explicitly clamp the final ones - + // expand bits to bytes first if (depth == 4) { - for (k=x*img_n; k >= 2; k-=2, ++in) { - *cur++ = scale * ((*in >> 4) ); - *cur++ = scale * ((*in ) & 0x0f); + for (i=0; i < nsmp; ++i) { + if ((i & 1) == 0) inb = *in++; + *out++ = scale * (inb >> 4); + inb <<= 4; } - if (k > 0) *cur++ = scale * ((*in >> 4) ); } else if (depth == 2) { - for (k=x*img_n; k >= 4; k-=4, ++in) { - *cur++ = scale * ((*in >> 6) ); - *cur++ = scale * ((*in >> 4) & 0x03); - *cur++ = scale * ((*in >> 2) & 0x03); - *cur++ = scale * ((*in ) & 0x03); + for (i=0; i < nsmp; ++i) { + if ((i & 3) == 0) inb = *in++; + *out++ = scale * (inb >> 6); + inb <<= 2; } - if (k > 0) *cur++ = scale * ((*in >> 6) ); - if (k > 1) *cur++ = scale * ((*in >> 4) & 0x03); - if (k > 2) *cur++ = scale * ((*in >> 2) & 0x03); - } else if (depth == 1) { - for (k=x*img_n; k >= 8; k-=8, ++in) { - *cur++ = scale * ((*in >> 7) ); - *cur++ = scale * ((*in >> 6) & 0x01); - *cur++ = scale * ((*in >> 5) & 0x01); - *cur++ = scale * ((*in >> 4) & 0x01); - *cur++ = scale * ((*in >> 3) & 0x01); - *cur++ = scale * ((*in >> 2) & 0x01); - *cur++ = scale * ((*in >> 1) & 0x01); - *cur++ = scale * ((*in ) & 0x01); + } else { + STBI_ASSERT(depth == 1); + for (i=0; i < nsmp; ++i) { + if ((i & 7) == 0) inb = *in++; + *out++ = scale * (inb >> 7); + inb <<= 1; } - if (k > 0) *cur++ = scale * ((*in >> 7) ); - if (k > 1) *cur++ = scale * ((*in >> 6) & 0x01); - if (k > 2) *cur++ = scale * ((*in >> 5) & 0x01); - if (k > 3) *cur++ = scale * ((*in >> 4) & 0x01); - if (k > 4) *cur++ = scale * ((*in >> 3) & 0x01); - if (k > 5) *cur++ = scale * ((*in >> 2) & 0x01); - if (k > 6) *cur++ = scale * ((*in >> 1) & 0x01); } - if (img_n != out_n) { - int q; - // insert alpha = 255 - cur = a->out + stride*j; + + // insert alpha=255 values if desired + if (img_n != out_n) + stbi__create_png_alpha_expand8(dest, dest, x, img_n); + } else if (depth == 8) { + if (img_n == out_n) + memcpy(dest, cur, x*img_n); + else + stbi__create_png_alpha_expand8(dest, cur, x, img_n); + } else if (depth == 16) { + // convert the image data from big-endian to platform-native + stbi__uint16 *dest16 = (stbi__uint16*)dest; + stbi__uint32 nsmp = x*img_n; + + if (img_n == out_n) { + for (i = 0; i < nsmp; ++i, ++dest16, cur += 2) + *dest16 = (cur[0] << 8) | cur[1]; + } else { + STBI_ASSERT(img_n+1 == out_n); if (img_n == 1) { - for (q=x-1; q >= 0; --q) { - cur[q*2+1] = 255; - cur[q*2+0] = cur[q]; + for (i = 0; i < x; ++i, dest16 += 2, cur += 2) { + dest16[0] = (cur[0] << 8) | cur[1]; + dest16[1] = 0xffff; } } else { STBI_ASSERT(img_n == 3); - for (q=x-1; q >= 0; --q) { - cur[q*4+3] = 255; - cur[q*4+2] = cur[q*3+2]; - cur[q*4+1] = cur[q*3+1]; - cur[q*4+0] = cur[q*3+0]; + for (i = 0; i < x; ++i, dest16 += 4, cur += 6) { + dest16[0] = (cur[0] << 8) | cur[1]; + dest16[1] = (cur[2] << 8) | cur[3]; + dest16[2] = (cur[4] << 8) | cur[5]; + dest16[3] = 0xffff; } } } } - } else if (depth == 16) { - // force the image data from big-endian to platform-native. - // this is done in a separate pass due to the decoding relying - // on the data being untouched, but could probably be done - // per-line during decode if care is taken. - stbi_uc *cur = a->out; - stbi__uint16 *cur16 = (stbi__uint16*)cur; - - for(i=0; i < x*y*out_n; ++i,cur16++,cur+=2) { - *cur16 = (cur[0] << 8) | cur[1]; - } } + STBI_FREE(filter_buf); + if (!all_ok) return 0; + return 1; } From 08c1adc01584b09edf68653e12c67308ea78ca11 Mon Sep 17 00:00:00 2001 From: Stephen Gold Date: Tue, 9 Apr 2024 15:22:57 -0700 Subject: [PATCH 68/77] fix issue #5461 (segfault after removing redundant materials) (#5467) * fix issue #5641 (segfault after removing redundant materials) * Update RemoveRedundantMaterials.cpp - Fix 2 possible memleaks. --------- Co-authored-by: Kim Kulling --- .../RemoveRedundantMaterials.cpp | 18 +++++++++--------- 1 file changed, 9 insertions(+), 9 deletions(-) diff --git a/code/PostProcessing/RemoveRedundantMaterials.cpp b/code/PostProcessing/RemoveRedundantMaterials.cpp index e32fe21ac..828fcd0ac 100644 --- a/code/PostProcessing/RemoveRedundantMaterials.cpp +++ b/code/PostProcessing/RemoveRedundantMaterials.cpp @@ -81,27 +81,26 @@ void RemoveRedundantMatsProcess::Execute( aiScene* pScene) { // Find out which materials are referenced by meshes std::vector abReferenced(pScene->mNumMaterials,false); - for (unsigned int i = 0;i < pScene->mNumMeshes;++i) + for (unsigned int i = 0;i < pScene->mNumMeshes;++i) { abReferenced[pScene->mMeshes[i]->mMaterialIndex] = true; + } // If a list of materials to be excluded was given, match the list with // our imported materials and 'salt' all positive matches to ensure that // we get unique hashes later. if (mConfigFixedMaterials.length()) { - std::list strings; ConvertListToStrings(mConfigFixedMaterials,strings); for (unsigned int i = 0; i < pScene->mNumMaterials;++i) { aiMaterial* mat = pScene->mMaterials[i]; - + ai_assert(mat != nullptr); aiString name; mat->Get(AI_MATKEY_NAME,name); - if (name.length) { + if (name.length != 0) { std::list::const_iterator it = std::find(strings.begin(), strings.end(), name.data); if (it != strings.end()) { - // Our brilliant 'salt': A single material property with ~ as first // character to mark it as internal and temporary. const int dummy = 1; @@ -126,7 +125,7 @@ void RemoveRedundantMatsProcess::Execute( aiScene* pScene) { // store all hashes in a list and so a quick search whether // we do already have a specific hash. This allows us to // determine which materials are identical. - uint32_t *aiHashes = new uint32_t[ pScene->mNumMaterials ];; + uint32_t *aiHashes = new uint32_t[ pScene->mNumMaterials ]; for (unsigned int i = 0; i < pScene->mNumMaterials;++i) { // No mesh is referencing this material, remove it. if (!abReferenced[i]) { @@ -157,15 +156,16 @@ void RemoveRedundantMatsProcess::Execute( aiScene* pScene) { // If the new material count differs from the original, // we need to rebuild the material list and remap mesh material indexes. if (iNewNum < 1) { - //throw DeadlyImportError("No materials remaining"); + delete [] aiMappingTable; + delete [] aiHashes; + pScene->mNumMaterials = 0; return; } if (iNewNum != pScene->mNumMaterials) { ai_assert(iNewNum > 0); aiMaterial** ppcMaterials = new aiMaterial*[iNewNum]; ::memset(ppcMaterials,0,sizeof(void*)*iNewNum); - for (unsigned int p = 0; p < pScene->mNumMaterials;++p) - { + for (unsigned int p = 0; p < pScene->mNumMaterials;++p) { // if the material is not referenced ... remove it if (!abReferenced[p]) { continue; From 85f084a4ce3b2186d25a3a6fb0482a4bfb1cd363 Mon Sep 17 00:00:00 2001 From: Kim Kulling Date: Thu, 11 Apr 2024 11:30:36 +0100 Subject: [PATCH 69/77] Update ComputeUVMappingProcess.cpp (#5541) * Update ComputeUVMappingProcess.cpp - closes https://github.com/assimp/assimp/issues/5540 * Update ComputeUVMappingProcess.cpp Add missing token. --- code/PostProcessing/ComputeUVMappingProcess.cpp | 10 +++++++--- 1 file changed, 7 insertions(+), 3 deletions(-) diff --git a/code/PostProcessing/ComputeUVMappingProcess.cpp b/code/PostProcessing/ComputeUVMappingProcess.cpp index 2aa34de28..cac51e8d0 100644 --- a/code/PostProcessing/ComputeUVMappingProcess.cpp +++ b/code/PostProcessing/ComputeUVMappingProcess.cpp @@ -346,16 +346,20 @@ void ComputeUVMappingProcess::Execute(aiScene *pScene) { ASSIMP_LOG_DEBUG("GenUVCoordsProcess begin"); char buffer[1024]; - if (pScene->mFlags & AI_SCENE_FLAGS_NON_VERBOSE_FORMAT) + if (pScene->mFlags & AI_SCENE_FLAGS_NON_VERBOSE_FORMAT) { throw DeadlyImportError("Post-processing order mismatch: expecting pseudo-indexed (\"verbose\") vertices here"); + } std::list mappingStack; - /* Iterate through all materials and search for non-UV mapped textures - */ + // Iterate through all materials and search for non-UV mapped textures for (unsigned int i = 0; i < pScene->mNumMaterials; ++i) { mappingStack.clear(); aiMaterial *mat = pScene->mMaterials[i]; + if (mat == nullptr) { + ASSIMP_LOG_INFO("Material pointer in nullptr, skipping."); + continue; + } for (unsigned int a = 0; a < mat->mNumProperties; ++a) { aiMaterialProperty *prop = mat->mProperties[a]; if (!::strcmp(prop->mKey.data, "$tex.mapping")) { From b71b8f77ee641c8322a33791d13ef35b486314ad Mon Sep 17 00:00:00 2001 From: Zeun <95558717+ZeunO8@users.noreply.github.com> Date: Wed, 17 Apr 2024 09:41:21 +1200 Subject: [PATCH 70/77] add some ASSIMP_INSTALL checks (#5545) --- CMakeLists.txt | 46 ++++++++++++++++++++----------------- code/CMakeLists.txt | 25 ++++++++++---------- contrib/zlib/CMakeLists.txt | 14 ++++++----- 3 files changed, 46 insertions(+), 39 deletions(-) diff --git a/CMakeLists.txt b/CMakeLists.txt index 670f29f86..05b722c2c 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -452,18 +452,20 @@ configure_package_config_file( INSTALL_DESTINATION "${CONFIG_INSTALL_DIR}" ) -install( - FILES "${PROJECT_CONFIG}" "${VERSION_CONFIG}" - DESTINATION "${CONFIG_INSTALL_DIR}" - COMPONENT ${LIBASSIMP-DEV_COMPONENT} -) +if(ASSIMP_INSTALL) + install( + FILES "${PROJECT_CONFIG}" "${VERSION_CONFIG}" + DESTINATION "${CONFIG_INSTALL_DIR}" + COMPONENT ${LIBASSIMP-DEV_COMPONENT} + ) -install( - EXPORT "${TARGETS_EXPORT_NAME}" - NAMESPACE "${NAMESPACE}" - DESTINATION "${CONFIG_INSTALL_DIR}" - COMPONENT ${LIBASSIMP-DEV_COMPONENT} -) + install( + EXPORT "${TARGETS_EXPORT_NAME}" + NAMESPACE "${NAMESPACE}" + DESTINATION "${CONFIG_INSTALL_DIR}" + COMPONENT ${LIBASSIMP-DEV_COMPONENT} + ) +endif() IF( ASSIMP_BUILD_DOCS ) ADD_SUBDIRECTORY(doc) @@ -481,7 +483,7 @@ IF(ASSIMP_HUNTER_ENABLED) set(ASSIMP_BUILD_MINIZIP TRUE) ELSE() # If the zlib is already found outside, add an export in case assimpTargets can't find it. - IF( ZLIB_FOUND ) + IF( ZLIB_FOUND AND ASSIMP_INSTALL) INSTALL( TARGETS zlib zlibstatic EXPORT "${TARGETS_EXPORT_NAME}") ENDIF() @@ -705,15 +707,17 @@ ELSE() set(draco_INCLUDE_DIRS "${CMAKE_CURRENT_SOURCE_DIR}/contrib/draco/src") # This is probably wrong - INSTALL( TARGETS ${draco_LIBRARIES} - EXPORT "${TARGETS_EXPORT_NAME}" - LIBRARY DESTINATION ${ASSIMP_LIB_INSTALL_DIR} - ARCHIVE DESTINATION ${ASSIMP_LIB_INSTALL_DIR} - RUNTIME DESTINATION ${ASSIMP_BIN_INSTALL_DIR} - FRAMEWORK DESTINATION ${ASSIMP_LIB_INSTALL_DIR} - COMPONENT ${LIBASSIMP_COMPONENT} - INCLUDES DESTINATION include - ) + if (ASSIMP_INSTALL) + INSTALL( TARGETS ${draco_LIBRARIES} + EXPORT "${TARGETS_EXPORT_NAME}" + LIBRARY DESTINATION ${ASSIMP_LIB_INSTALL_DIR} + ARCHIVE DESTINATION ${ASSIMP_LIB_INSTALL_DIR} + RUNTIME DESTINATION ${ASSIMP_BIN_INSTALL_DIR} + FRAMEWORK DESTINATION ${ASSIMP_LIB_INSTALL_DIR} + COMPONENT ${LIBASSIMP_COMPONENT} + INCLUDES DESTINATION include + ) + endif() ENDIF() ENDIF() ENDIF() diff --git a/code/CMakeLists.txt b/code/CMakeLists.txt index a521c9fb8..b397d5ec4 100644 --- a/code/CMakeLists.txt +++ b/code/CMakeLists.txt @@ -1400,19 +1400,20 @@ IF (RT_FOUND AND ASSIMP_IMPORTER_GLTF_USE_OPEN3DGC) TARGET_LINK_LIBRARIES(assimp rt) ENDIF () +IF(ASSIMP_INSTALL) + INSTALL( TARGETS assimp + EXPORT "${TARGETS_EXPORT_NAME}" + LIBRARY DESTINATION ${ASSIMP_LIB_INSTALL_DIR} COMPONENT ${LIBASSIMP_COMPONENT} + ARCHIVE DESTINATION ${ASSIMP_LIB_INSTALL_DIR} COMPONENT ${LIBASSIMP-DEV_COMPONENT} + RUNTIME DESTINATION ${ASSIMP_BIN_INSTALL_DIR} COMPONENT ${LIBASSIMP_COMPONENT} + FRAMEWORK DESTINATION ${ASSIMP_LIB_INSTALL_DIR} COMPONENT ${LIBASSIMP_COMPONENT} + INCLUDES DESTINATION ${ASSIMP_INCLUDE_INSTALL_DIR} + ) + INSTALL( FILES ${PUBLIC_HEADERS} DESTINATION ${ASSIMP_INCLUDE_INSTALL_DIR}/assimp COMPONENT assimp-dev) + INSTALL( FILES ${COMPILER_HEADERS} DESTINATION ${ASSIMP_INCLUDE_INSTALL_DIR}/assimp/Compiler COMPONENT assimp-dev) +ENDIF() -INSTALL( TARGETS assimp - EXPORT "${TARGETS_EXPORT_NAME}" - LIBRARY DESTINATION ${ASSIMP_LIB_INSTALL_DIR} COMPONENT ${LIBASSIMP_COMPONENT} - ARCHIVE DESTINATION ${ASSIMP_LIB_INSTALL_DIR} COMPONENT ${LIBASSIMP-DEV_COMPONENT} - RUNTIME DESTINATION ${ASSIMP_BIN_INSTALL_DIR} COMPONENT ${LIBASSIMP_COMPONENT} - FRAMEWORK DESTINATION ${ASSIMP_LIB_INSTALL_DIR} COMPONENT ${LIBASSIMP_COMPONENT} - INCLUDES DESTINATION ${ASSIMP_INCLUDE_INSTALL_DIR} -) -INSTALL( FILES ${PUBLIC_HEADERS} DESTINATION ${ASSIMP_INCLUDE_INSTALL_DIR}/assimp COMPONENT assimp-dev) -INSTALL( FILES ${COMPILER_HEADERS} DESTINATION ${ASSIMP_INCLUDE_INSTALL_DIR}/assimp/Compiler COMPONENT assimp-dev) - -if (ASSIMP_ANDROID_JNIIOSYSTEM) +if (ASSIMP_ANDROID_JNIIOSYSTEM AND ASSIMP_INSTALL) INSTALL(FILES ${HEADER_PATH}/${ASSIMP_ANDROID_JNIIOSYSTEM_PATH}/AndroidJNIIOSystem.h DESTINATION ${ASSIMP_INCLUDE_INSTALL_DIR} COMPONENT assimp-dev) diff --git a/contrib/zlib/CMakeLists.txt b/contrib/zlib/CMakeLists.txt index e7897d6a1..0e4906cea 100644 --- a/contrib/zlib/CMakeLists.txt +++ b/contrib/zlib/CMakeLists.txt @@ -198,9 +198,11 @@ endif(MINGW) add_library(zlibstatic STATIC ${ZLIB_SRCS} ${ZLIB_ASMS} ${ZLIB_PUBLIC_HDRS} ${ZLIB_PRIVATE_HDRS}) -INSTALL( TARGETS zlibstatic - EXPORT "${TARGETS_EXPORT_NAME}" - LIBRARY DESTINATION ${ASSIMP_LIB_INSTALL_DIR} - ARCHIVE DESTINATION ${ASSIMP_LIB_INSTALL_DIR} - RUNTIME DESTINATION ${ASSIMP_BIN_INSTALL_DIR} - COMPONENT ${LIBASSIMP_COMPONENT}) +IF(ASSIMP_INSTALL) + INSTALL( TARGETS zlibstatic + EXPORT "${TARGETS_EXPORT_NAME}" + LIBRARY DESTINATION ${ASSIMP_LIB_INSTALL_DIR} + ARCHIVE DESTINATION ${ASSIMP_LIB_INSTALL_DIR} + RUNTIME DESTINATION ${ASSIMP_BIN_INSTALL_DIR} + COMPONENT ${LIBASSIMP_COMPONENT}) +ENDIF() From 7bda0f88ca56806aea6c51d0e29113a83275f4b8 Mon Sep 17 00:00:00 2001 From: Succ3s <42254469+Succ3s@users.noreply.github.com> Date: Tue, 23 Apr 2024 16:40:06 -0300 Subject: [PATCH 71/77] SplitByBoneCount had a minor typo that prevented updates to nodes indices (#5550) --- code/PostProcessing/SplitByBoneCountProcess.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/code/PostProcessing/SplitByBoneCountProcess.cpp b/code/PostProcessing/SplitByBoneCountProcess.cpp index ea50f8f7f..f63478767 100644 --- a/code/PostProcessing/SplitByBoneCountProcess.cpp +++ b/code/PostProcessing/SplitByBoneCountProcess.cpp @@ -394,7 +394,7 @@ void SplitByBoneCountProcess::SplitMesh( const aiMesh* pMesh, std::vectormNumMeshes == 0 ) { + if( pNode->mNumMeshes != 0 ) { IndexArray newMeshList; for( unsigned int a = 0; a < pNode->mNumMeshes; ++a) { unsigned int srcIndex = pNode->mMeshes[a]; From c05895f3c73717a4df96e1d1391d499c1187d620 Mon Sep 17 00:00:00 2001 From: Kim Kulling Date: Fri, 26 Apr 2024 10:11:19 +0100 Subject: [PATCH 72/77] Q3DLoader: Fix possible material string overflow (#5556) - closes https://github.com/assimp/assimp/issues/5555 --- code/AssetLib/Q3D/Q3DLoader.cpp | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/code/AssetLib/Q3D/Q3DLoader.cpp b/code/AssetLib/Q3D/Q3DLoader.cpp index 435b92e82..ac6b17ec6 100644 --- a/code/AssetLib/Q3D/Q3DLoader.cpp +++ b/code/AssetLib/Q3D/Q3DLoader.cpp @@ -250,6 +250,10 @@ void Q3DImporter::InternReadFile(const std::string &pFile, c = stream.GetI1(); while (c) { mat.name.data[mat.name.length++] = c; + if (mat.name.length == MAXLEN) { + ASSIMP_LOG_ERROR("String ouverflow detected, skipped material name parsing."); + break; + } c = stream.GetI1(); } From 47ef79672e58417899a3dbf1361691059e9f5dd8 Mon Sep 17 00:00:00 2001 From: Johannes Unterguggenberger Date: Mon, 29 Apr 2024 21:03:57 +0200 Subject: [PATCH 73/77] Reverts the changes introduced by commit ad766cb in February 2022. (#5542) * Reverts the changes introduced by commit ad766cb in February 2022. Explanation why the old code was just fine is given in Q&A #5512. * Added that missing ; --------- Co-authored-by: Kim Kulling --- code/PostProcessing/CalcTangentsProcess.cpp | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/code/PostProcessing/CalcTangentsProcess.cpp b/code/PostProcessing/CalcTangentsProcess.cpp index 82fde1348..abd0aee47 100644 --- a/code/PostProcessing/CalcTangentsProcess.cpp +++ b/code/PostProcessing/CalcTangentsProcess.cpp @@ -185,9 +185,9 @@ bool CalcTangentsProcess::ProcessMesh(aiMesh *pMesh, unsigned int meshIndex) { tangent.x = (w.x * sy - v.x * ty) * dirCorrection; tangent.y = (w.y * sy - v.y * ty) * dirCorrection; tangent.z = (w.z * sy - v.z * ty) * dirCorrection; - bitangent.x = (- w.x * sx + v.x * tx) * dirCorrection; - bitangent.y = (- w.y * sx + v.y * tx) * dirCorrection; - bitangent.z = (- w.z * sx + v.z * tx) * dirCorrection; + bitangent.x = (w.x * sx - v.x * tx) * dirCorrection; + bitangent.y = (w.y * sx - v.y * tx) * dirCorrection; + bitangent.z = (w.z * sx - v.z * tx) * dirCorrection; // store for every vertex of that face for (unsigned int b = 0; b < face.mNumIndices; ++b) { @@ -195,7 +195,7 @@ bool CalcTangentsProcess::ProcessMesh(aiMesh *pMesh, unsigned int meshIndex) { // project tangent and bitangent into the plane formed by the vertex' normal aiVector3D localTangent = tangent - meshNorm[p] * (tangent * meshNorm[p]); - aiVector3D localBitangent = bitangent - meshNorm[p] * (bitangent * meshNorm[p]) - localTangent * (bitangent * localTangent); + aiVector3D localBitangent = bitangent - meshNorm[p] * (bitangent * meshNorm[p]); localTangent.NormalizeSafe(); localBitangent.NormalizeSafe(); From 4621676424b80969ed6126efc441adc7360c1649 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E9=99=88=E7=91=9E=E9=94=8B?= <48576544+xiaoxiaopifu@users.noreply.github.com> Date: Thu, 2 May 2024 21:32:12 +0800 Subject: [PATCH 74/77] fix a collada import bug (#5561) --- code/AssetLib/Collada/ColladaLoader.cpp | 4 +++- code/AssetLib/Collada/ColladaParser.cpp | 3 ++- 2 files changed, 5 insertions(+), 2 deletions(-) diff --git a/code/AssetLib/Collada/ColladaLoader.cpp b/code/AssetLib/Collada/ColladaLoader.cpp index 17c4f4b28..2574fd2ea 100644 --- a/code/AssetLib/Collada/ColladaLoader.cpp +++ b/code/AssetLib/Collada/ColladaLoader.cpp @@ -247,7 +247,9 @@ aiNode *ColladaLoader::BuildHierarchy(const ColladaParser &pParser, const Collad // add children. first the *real* ones node->mNumChildren = static_cast(pNode->mChildren.size() + instances.size()); - node->mChildren = new aiNode *[node->mNumChildren]; + if (node->mNumChildren != 0) { + node->mChildren = new aiNode * [node->mNumChildren]; + } for (size_t a = 0; a < pNode->mChildren.size(); ++a) { node->mChildren[a] = BuildHierarchy(pParser, pNode->mChildren[a]); diff --git a/code/AssetLib/Collada/ColladaParser.cpp b/code/AssetLib/Collada/ColladaParser.cpp index c5163fe39..a563f6f9c 100644 --- a/code/AssetLib/Collada/ColladaParser.cpp +++ b/code/AssetLib/Collada/ColladaParser.cpp @@ -635,7 +635,8 @@ void ColladaParser::ReadController(XmlNode &node, Collada::Controller &controlle const std::string ¤tName = currentNode.name(); if (currentName == "morph") { controller.mType = Morph; - controller.mMeshId = currentNode.attribute("source").as_string(); + std::string id = currentNode.attribute("source").as_string(); + controller.mMeshId = id.substr(1, id.size() - 1); int methodIndex = currentNode.attribute("method").as_int(); if (methodIndex > 0) { std::string method; From 00b6db86ab243c132d9291939dbdb7ad637287a8 Mon Sep 17 00:00:00 2001 From: Garux Date: Thu, 2 May 2024 19:34:47 +0500 Subject: [PATCH 75/77] mention IQM loader in Fileformats.md (#5560) Co-authored-by: Kim Kulling --- doc/Fileformats.md | 1 + 1 file changed, 1 insertion(+) diff --git a/doc/Fileformats.md b/doc/Fileformats.md index 5e7983812..6fc0fe34c 100644 --- a/doc/Fileformats.md +++ b/doc/Fileformats.md @@ -28,6 +28,7 @@ __Importers__: + KHR_texture_transform ( 5.1 under test ) - HMB - IFC-STEP +- IQM - IRR / IRRMESH - [LWO](https://en.wikipedia.org/wiki/LightWave_3D) - LWS From c9537394876931880b6d71d27519c0baeb637c46 Mon Sep 17 00:00:00 2001 From: Kim Kulling Date: Mon, 6 May 2024 21:38:29 +0200 Subject: [PATCH 76/77] Kimkulling/fix pyassimp compatibility (#5563) * Use correct exception message access * Add missing docs --- code/Geometry/GeometryUtils.h | 4 ++++ port/PyAssimp/scripts/3d_viewer.py | 4 ++-- 2 files changed, 6 insertions(+), 2 deletions(-) diff --git a/code/Geometry/GeometryUtils.h b/code/Geometry/GeometryUtils.h index 2e205c872..ae88d376b 100644 --- a/code/Geometry/GeometryUtils.h +++ b/code/Geometry/GeometryUtils.h @@ -49,6 +49,10 @@ namespace Assimp { // --------------------------------------------------------------------------- class ASSIMP_API GeometryUtils { public: + /// @brief Will calculate the area of a triangle. + /// @param a The first vertex of the triangle. + /// @param b The first vertex of the triangle. + /// @param c The first vertex of the triangle. static ai_real heron( ai_real a, ai_real b, ai_real c ); /// @brief Will compute the distance between 2 3D-vectors diff --git a/port/PyAssimp/scripts/3d_viewer.py b/port/PyAssimp/scripts/3d_viewer.py index 08a62660b..3bf790e05 100755 --- a/port/PyAssimp/scripts/3d_viewer.py +++ b/port/PyAssimp/scripts/3d_viewer.py @@ -466,8 +466,8 @@ class PyAssimp3DViewer: try: self.set_shaders_v130() self.prepare_shaders() - except RuntimeError, message: - sys.stderr.write("%s\n" % message) + except RuntimeError as e: + sys.stderr.write("%s\n" % e.message) sys.stdout.write("Could not compile shaders in version 1.30, trying version 1.20\n") if not shader_compilation_succeeded: From 47dbabadcd683724be26109c757ad86f4645d280 Mon Sep 17 00:00:00 2001 From: Garux Date: Wed, 8 May 2024 13:43:43 +0500 Subject: [PATCH 77/77] fix ASE loader crash when *MATERIAL_COUNT or *NUMSUBMTLS is not specified or is 0 (#5559) code was doing vector[0u - 1] dereference in this case Co-authored-by: Kim Kulling --- code/AssetLib/ASE/ASEParser.cpp | 13 +++++++++++++ 1 file changed, 13 insertions(+) diff --git a/code/AssetLib/ASE/ASEParser.cpp b/code/AssetLib/ASE/ASEParser.cpp index e3c358aa5..7efab0da3 100644 --- a/code/AssetLib/ASE/ASEParser.cpp +++ b/code/AssetLib/ASE/ASEParser.cpp @@ -500,6 +500,13 @@ void Parser::ParseLV1MaterialListBlock() { continue; } if (TokenMatch(filePtr, "MATERIAL", 8)) { + // ensure we have at least one material allocated + if (iMaterialCount == 0) { + LogWarning("*MATERIAL_COUNT unspecified or 0"); + iMaterialCount = 1; + m_vMaterials.resize(iOldMaterialCount + iMaterialCount, Material("INVALID")); + } + unsigned int iIndex = 0; ParseLV4MeshLong(iIndex); @@ -653,6 +660,12 @@ void Parser::ParseLV2MaterialBlock(ASE::Material &mat) { } // submaterial chunks if (TokenMatch(filePtr, "SUBMATERIAL", 11)) { + // ensure we have at least one material allocated + if (iNumSubMaterials == 0) { + LogWarning("*NUMSUBMTLS unspecified or 0"); + iNumSubMaterials = 1; + mat.avSubMaterials.resize(iNumSubMaterials, Material("INVALID SUBMATERIAL")); + } unsigned int iIndex = 0; ParseLV4MeshLong(iIndex);