From 6cbeca5518d8be6f91d4803427f0dd6d670bbd54 Mon Sep 17 00:00:00 2001 From: Krishty Date: Fri, 16 Apr 2021 20:44:40 +0200 Subject: [PATCH 01/12] fixed glTF export stuff being pulled into the EXE even if building with ASSIMP_BUILD_NO_EXPORT MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit “LazyDictBase::WriteObjects()” in the two glTF implementations is only used for export. Since it’s a virtual method, and many compilers have trouble removing unreferenced virtual methods, glTF export stuff is pulled into the binary even if compiling without exports. This commit removes said virtual function if only compiling for import. This removes 75 KiB of useless code when compiled with Visual Studio for x64. --- code/AssetLib/glTF/glTFAsset.h | 4 ++++ code/AssetLib/glTF/glTFImporter.cpp | 2 ++ code/AssetLib/glTF2/glTF2Asset.h | 4 ++++ code/AssetLib/glTF2/glTF2Importer.cpp | 2 ++ 4 files changed, 12 insertions(+) diff --git a/code/AssetLib/glTF/glTFAsset.h b/code/AssetLib/glTF/glTFAsset.h index 1da70832b..623f18173 100644 --- a/code/AssetLib/glTF/glTFAsset.h +++ b/code/AssetLib/glTF/glTFAsset.h @@ -954,7 +954,9 @@ namespace glTF virtual void AttachToDocument(Document& doc) = 0; virtual void DetachFromDocument() = 0; +#if !defined(ASSIMP_BUILD_NO_EXPORT) virtual void WriteObjects(AssetWriter& writer) = 0; +#endif }; @@ -986,8 +988,10 @@ namespace glTF void AttachToDocument(Document& doc); void DetachFromDocument(); +#if !defined(ASSIMP_BUILD_NO_EXPORT) void WriteObjects(AssetWriter& writer) { WriteLazyDict(*this, writer); } +#endif Ref Add(T* obj); diff --git a/code/AssetLib/glTF/glTFImporter.cpp b/code/AssetLib/glTF/glTFImporter.cpp index 3335fc109..5e072dd2a 100644 --- a/code/AssetLib/glTF/glTFImporter.cpp +++ b/code/AssetLib/glTF/glTFImporter.cpp @@ -43,7 +43,9 @@ OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. #include "AssetLib/glTF/glTFImporter.h" #include "AssetLib/glTF/glTFAsset.h" +#if !defined(ASSIMP_BUILD_NO_EXPORT) #include "AssetLib/glTF/glTFAssetWriter.h" +#endif #include "PostProcessing/MakeVerboseFormat.h" #include diff --git a/code/AssetLib/glTF2/glTF2Asset.h b/code/AssetLib/glTF2/glTF2Asset.h index 53b079117..fad5cba83 100644 --- a/code/AssetLib/glTF2/glTF2Asset.h +++ b/code/AssetLib/glTF2/glTF2Asset.h @@ -997,7 +997,9 @@ public: virtual void AttachToDocument(Document &doc) = 0; virtual void DetachFromDocument() = 0; +#if !defined(ASSIMP_BUILD_NO_EXPORT) virtual void WriteObjects(AssetWriter &writer) = 0; +#endif }; template @@ -1030,7 +1032,9 @@ class LazyDict : public LazyDictBase { void AttachToDocument(Document &doc); void DetachFromDocument(); +#if !defined(ASSIMP_BUILD_NO_EXPORT) void WriteObjects(AssetWriter &writer) { WriteLazyDict(*this, writer); } +#endif Ref Add(T *obj); diff --git a/code/AssetLib/glTF2/glTF2Importer.cpp b/code/AssetLib/glTF2/glTF2Importer.cpp index dca6fcb2d..ab1f01bf8 100644 --- a/code/AssetLib/glTF2/glTF2Importer.cpp +++ b/code/AssetLib/glTF2/glTF2Importer.cpp @@ -44,7 +44,9 @@ OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. #include "AssetLib/glTF2/glTF2Importer.h" #include "PostProcessing/MakeVerboseFormat.h" #include "AssetLib/glTF2/glTF2Asset.h" +#if !defined(ASSIMP_BUILD_NO_EXPORT) #include "AssetLib/glTF2/glTF2AssetWriter.h" +#endif #include #include From f761dc72f426444d56dbe9ed12b2823b08a68aa9 Mon Sep 17 00:00:00 2001 From: Krishty Date: Fri, 16 Apr 2021 23:43:56 +0200 Subject: [PATCH 02/12] style fix - initializing and assigning empty std::string properly MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit std::string s(""); s = ""; calls the copy constructor, which in turn calls strlen(), … assigning a default-constructed string generates fewer instructions and is therefore preferred. With C++11 uniform initialization, you’d simply write s = { } instead. --- code/AssetLib/3DS/3DSConverter.cpp | 2 +- code/AssetLib/3DS/3DSLoader.cpp | 2 +- code/AssetLib/3MF/D3MFOpcPackage.cpp | 2 +- code/AssetLib/AC/ACLoader.h | 4 ++-- code/AssetLib/ASE/ASEParser.cpp | 2 +- code/AssetLib/Collada/ColladaLoader.cpp | 2 +- code/AssetLib/FBX/FBXMeshGeometry.cpp | 2 +- code/AssetLib/FBX/FBXParser.cpp | 8 ++++---- code/AssetLib/FBX/FBXProperties.cpp | 2 +- code/AssetLib/IFC/IFCLoader.cpp | 4 ++-- code/AssetLib/Irr/IRRLoader.cpp | 2 +- code/AssetLib/Irr/IRRMeshLoader.cpp | 2 +- code/AssetLib/LWO/LWOFileData.h | 2 +- code/AssetLib/LWS/LWSLoader.h | 2 +- .../MDL/HalfLife/UniqueNameGenerator.cpp | 2 +- code/AssetLib/MMD/MMDImporter.cpp | 2 +- code/AssetLib/MMD/MMDPmxParser.cpp | 2 +- code/AssetLib/OpenGEX/OpenGEXImporter.cpp | 2 +- code/AssetLib/OpenGEX/OpenGEXImporter.h | 2 +- code/AssetLib/Q3BSP/Q3BSPFileData.h | 2 +- code/AssetLib/Q3BSP/Q3BSPFileImporter.cpp | 16 ++++++++-------- code/AssetLib/X/XFileHelper.h | 2 +- code/AssetLib/XGL/XGLLoader.cpp | 2 +- code/AssetLib/glTF/glTFAsset.h | 2 +- code/AssetLib/glTF2/glTF2Asset.h | 2 +- code/Common/BaseImporter.cpp | 2 +- code/Common/FileSystemFilter.h | 2 +- code/Common/Importer.cpp | 6 +++--- code/Common/scene.cpp | 2 +- code/PostProcessing/RemoveRedundantMaterials.h | 2 +- include/assimp/DefaultIOStream.h | 2 +- include/assimp/IOSystem.hpp | 2 +- include/assimp/Importer.hpp | 2 +- include/assimp/XmlParser.h | 2 +- 34 files changed, 48 insertions(+), 48 deletions(-) diff --git a/code/AssetLib/3DS/3DSConverter.cpp b/code/AssetLib/3DS/3DSConverter.cpp index 12ac7e69e..c977867c0 100644 --- a/code/AssetLib/3DS/3DSConverter.cpp +++ b/code/AssetLib/3DS/3DSConverter.cpp @@ -212,7 +212,7 @@ void Discreet3DSImporter::ConvertMaterial(D3DS::Material &oldMat, mat.AddProperty(&tex, AI_MATKEY_GLOBAL_BACKGROUND_IMAGE); // Be sure this is only done for the first material - mBackgroundImage = std::string(""); + mBackgroundImage = std::string(); } // At first add the base ambient color of the scene to the material diff --git a/code/AssetLib/3DS/3DSLoader.cpp b/code/AssetLib/3DS/3DSLoader.cpp index 0a64f6870..10aa10786 100644 --- a/code/AssetLib/3DS/3DSLoader.cpp +++ b/code/AssetLib/3DS/3DSLoader.cpp @@ -164,7 +164,7 @@ void Discreet3DSImporter::InternReadFile(const std::string &pFile, mRootNode->mHierarchyIndex = -1; mRootNode->mParent = nullptr; mMasterScale = 1.0f; - mBackgroundImage = ""; + mBackgroundImage = std::string(); bHasBG = false; bIsPrj = false; diff --git a/code/AssetLib/3MF/D3MFOpcPackage.cpp b/code/AssetLib/3MF/D3MFOpcPackage.cpp index 514e3c2f3..ec0861fc1 100644 --- a/code/AssetLib/3MF/D3MFOpcPackage.cpp +++ b/code/AssetLib/3MF/D3MFOpcPackage.cpp @@ -188,7 +188,7 @@ bool D3MFOpcPackage::validate() { std::string D3MFOpcPackage::ReadPackageRootRelationship(IOStream *stream) { XmlParser xmlParser; if (!xmlParser.parse(stream)) { - return ""; + return std::string(); } OpcPackageRelationshipReader reader(xmlParser); diff --git a/code/AssetLib/AC/ACLoader.h b/code/AssetLib/AC/ACLoader.h index 77de16b8b..5ae2e80bb 100644 --- a/code/AssetLib/AC/ACLoader.h +++ b/code/AssetLib/AC/ACLoader.h @@ -123,9 +123,9 @@ public: struct Object { Object() : type(World), - name(""), + name(), children(), - texture(""), + texture(), texRepeat(1.f, 1.f), texOffset(0.0f, 0.0f), rotation(), diff --git a/code/AssetLib/ASE/ASEParser.cpp b/code/AssetLib/ASE/ASEParser.cpp index 21ec26593..530766730 100644 --- a/code/AssetLib/ASE/ASEParser.cpp +++ b/code/AssetLib/ASE/ASEParser.cpp @@ -685,7 +685,7 @@ void Parser::ParseLV3MapBlock(Texture &map) { // Files with 'None' as map name are produced by // an Maja to ASE exporter which name I forgot .. ASSIMP_LOG_WARN("ASE: Skipping invalid map entry"); - map.mMapName = ""; + map.mMapName = std::string(); } continue; diff --git a/code/AssetLib/Collada/ColladaLoader.cpp b/code/AssetLib/Collada/ColladaLoader.cpp index 902eebc4b..faaa7cdba 100644 --- a/code/AssetLib/Collada/ColladaLoader.cpp +++ b/code/AssetLib/Collada/ColladaLoader.cpp @@ -1241,7 +1241,7 @@ void ColladaLoader::CreateAnimation(aiScene *pScene, const ColladaParser &pParse continue; } entry.mTargetId = entry.mTransformId; - entry.mTransformId = ""; + entry.mTransformId = std::string(); } entry.mChannel = &(*cit); diff --git a/code/AssetLib/FBX/FBXMeshGeometry.cpp b/code/AssetLib/FBX/FBXMeshGeometry.cpp index fd8a0ff98..2bca8dff2 100644 --- a/code/AssetLib/FBX/FBXMeshGeometry.cpp +++ b/code/AssetLib/FBX/FBXMeshGeometry.cpp @@ -330,7 +330,7 @@ void MeshGeometry::ReadVertexData(const std::string& type, int index, const Scop } const Element* Name = source["Name"]; - m_uvNames[index] = ""; + m_uvNames[index] = std::string(); if(Name) { m_uvNames[index] = ParseTokenAsString(GetRequiredToken(*Name,0)); } diff --git a/code/AssetLib/FBX/FBXParser.cpp b/code/AssetLib/FBX/FBXParser.cpp index 046d26c95..37cf83cf9 100644 --- a/code/AssetLib/FBX/FBXParser.cpp +++ b/code/AssetLib/FBX/FBXParser.cpp @@ -462,7 +462,7 @@ std::string ParseTokenAsString(const Token& t, const char*& err_out) if (t.Type() != TokenType_DATA) { err_out = "expected TOK_DATA token"; - return ""; + return std::string(); } if(t.IsBinary()) @@ -470,7 +470,7 @@ std::string ParseTokenAsString(const Token& t, const char*& err_out) const char* data = t.begin(); if (data[0] != 'S') { err_out = "failed to parse S(tring), unexpected data type (binary)"; - return ""; + return std::string(); } // read string length @@ -484,13 +484,13 @@ std::string ParseTokenAsString(const Token& t, const char*& err_out) const size_t length = static_cast(t.end() - t.begin()); if(length < 2) { err_out = "token is too short to hold a string"; - return ""; + return std::string(); } const char* s = t.begin(), *e = t.end() - 1; if (*s != '\"' || *e != '\"') { err_out = "expected double quoted string"; - return ""; + return std::string(); } return std::string(s+1,length-2); diff --git a/code/AssetLib/FBX/FBXProperties.cpp b/code/AssetLib/FBX/FBXProperties.cpp index 2f39fc7dc..1e4cd0ead 100644 --- a/code/AssetLib/FBX/FBXProperties.cpp +++ b/code/AssetLib/FBX/FBXProperties.cpp @@ -155,7 +155,7 @@ std::string PeekPropertyName(const Element& element) ai_assert(element.KeyToken().StringContents() == "P"); const TokenList& tok = element.Tokens(); if(tok.size() < 4) { - return ""; + return std::string(); } return ParseTokenAsString(*tok[0]); diff --git a/code/AssetLib/IFC/IFCLoader.cpp b/code/AssetLib/IFC/IFCLoader.cpp index be100df57..df1ca32de 100644 --- a/code/AssetLib/IFC/IFCLoader.cpp +++ b/code/AssetLib/IFC/IFCLoader.cpp @@ -567,7 +567,7 @@ typedef std::map Metadata; // ------------------------------------------------------------------------------------------------ void ProcessMetadata(const Schema_2x3::ListOf, 1, 0> &set, ConversionData &conv, Metadata &properties, - const std::string &prefix = "", + const std::string &prefix = std::string(), unsigned int nest = 0) { for (const Schema_2x3::IfcProperty &property : set) { const std::string &key = prefix.length() > 0 ? (prefix + "." + property.Name) : property.Name; @@ -618,7 +618,7 @@ void ProcessMetadata(const Schema_2x3::ListOfHasProperties, conv, properties, key, nest + 1); } } else { - properties[key] = ""; + properties[key] = std::string(); } } } diff --git a/code/AssetLib/Irr/IRRLoader.cpp b/code/AssetLib/Irr/IRRLoader.cpp index 9c1136499..ed92c93bb 100644 --- a/code/AssetLib/Irr/IRRLoader.cpp +++ b/code/AssetLib/Irr/IRRLoader.cpp @@ -859,7 +859,7 @@ void IRRImporter::InternReadFile(const std::string &pFile, aiScene *pScene, IOSy // Check whether we can read from the file if (file.get() == nullptr) { - throw DeadlyImportError("Failed to open IRR file " + pFile + ""); + throw DeadlyImportError("Failed to open IRR file " + pFile); } // Construct the irrXML parser diff --git a/code/AssetLib/Irr/IRRMeshLoader.cpp b/code/AssetLib/Irr/IRRMeshLoader.cpp index 97d74026f..edcff6c83 100644 --- a/code/AssetLib/Irr/IRRMeshLoader.cpp +++ b/code/AssetLib/Irr/IRRMeshLoader.cpp @@ -135,7 +135,7 @@ void IRRMeshImporter::InternReadFile(const std::string &pFile, // Check whether we can read from the file if (file.get() == NULL) - throw DeadlyImportError("Failed to open IRRMESH file " + pFile + ""); + throw DeadlyImportError("Failed to open IRRMESH file " + pFile); // Construct the irrXML parser XmlParser parser; diff --git a/code/AssetLib/LWO/LWOFileData.h b/code/AssetLib/LWO/LWOFileData.h index 70642c537..93ac1a236 100644 --- a/code/AssetLib/LWO/LWOFileData.h +++ b/code/AssetLib/LWO/LWOFileData.h @@ -502,7 +502,7 @@ struct Surface { Surface() : mColor(0.78431f, 0.78431f, 0.78431f), bDoubleSided(false), mDiffuseValue(1.f), mSpecularValue(0.f), mTransparency(0.f), mGlossiness(0.4f), mLuminosity(0.f), mColorHighlights(0.f), mMaximumSmoothAngle(0.f) // 0 == not specified, no smoothing , - mVCMap(""), + mVCMap(), mVCMapType(AI_LWO_RGBA), mIOR(1.f) // vakuum , diff --git a/code/AssetLib/LWS/LWSLoader.h b/code/AssetLib/LWS/LWSLoader.h index 93251cd5d..cd7a0543e 100644 --- a/code/AssetLib/LWS/LWSLoader.h +++ b/code/AssetLib/LWS/LWSLoader.h @@ -88,7 +88,7 @@ struct NodeDesc { id(), number(0), parent(0), - name(""), + name(), isPivotSet(false), lightColor(1.f, 1.f, 1.f), lightIntensity(1.f), diff --git a/code/AssetLib/MDL/HalfLife/UniqueNameGenerator.cpp b/code/AssetLib/MDL/HalfLife/UniqueNameGenerator.cpp index 72081ea73..dde81454b 100644 --- a/code/AssetLib/MDL/HalfLife/UniqueNameGenerator.cpp +++ b/code/AssetLib/MDL/HalfLife/UniqueNameGenerator.cpp @@ -95,7 +95,7 @@ void UniqueNameGenerator::make_unique(std::vector &names) { auto generate_unique_name = [&](const std::string &base_name) -> std::string { auto *duplicate_info = &names_to_duplicates[base_name]; - std::string new_name = ""; + std::string new_name; bool found_identical_name; bool tried_with_base_name_only = false; diff --git a/code/AssetLib/MMD/MMDImporter.cpp b/code/AssetLib/MMD/MMDImporter.cpp index e4ecc1445..2895c3879 100644 --- a/code/AssetLib/MMD/MMDImporter.cpp +++ b/code/AssetLib/MMD/MMDImporter.cpp @@ -75,7 +75,7 @@ using namespace std; // Default constructor MMDImporter::MMDImporter() : m_Buffer(), - m_strAbsPath("") { + m_strAbsPath() { DefaultIOSystem io; m_strAbsPath = io.getOsSeparator(); } diff --git a/code/AssetLib/MMD/MMDPmxParser.cpp b/code/AssetLib/MMD/MMDPmxParser.cpp index 320182c3d..cb4787efd 100644 --- a/code/AssetLib/MMD/MMDPmxParser.cpp +++ b/code/AssetLib/MMD/MMDPmxParser.cpp @@ -91,7 +91,7 @@ namespace pmx std::vector buffer; if (size == 0) { - return std::string(""); + return std::string(); } buffer.reserve(size); stream->read((char*) buffer.data(), size); diff --git a/code/AssetLib/OpenGEX/OpenGEXImporter.cpp b/code/AssetLib/OpenGEX/OpenGEXImporter.cpp index 14c9ea37f..b29aeeeb1 100644 --- a/code/AssetLib/OpenGEX/OpenGEXImporter.cpp +++ b/code/AssetLib/OpenGEX/OpenGEXImporter.cpp @@ -206,7 +206,7 @@ USE_ODDLPARSER_NS //------------------------------------------------------------------------------------------------ static void propId2StdString(Property *prop, std::string &name, std::string &key) { - name = key = ""; + name = key = std::string(); if (nullptr == prop) { return; } diff --git a/code/AssetLib/OpenGEX/OpenGEXImporter.h b/code/AssetLib/OpenGEX/OpenGEXImporter.h index 677ef73aa..3c26a4a30 100644 --- a/code/AssetLib/OpenGEX/OpenGEXImporter.h +++ b/code/AssetLib/OpenGEX/OpenGEXImporter.h @@ -79,7 +79,7 @@ struct MetricInfo { int m_intValue; MetricInfo() - : m_stringValue( "" ) + : m_stringValue( ) , m_floatValue( 0.0f ) , m_intValue( -1 ) { // empty diff --git a/code/AssetLib/Q3BSP/Q3BSPFileData.h b/code/AssetLib/Q3BSP/Q3BSPFileData.h index ba826d541..a121cdbcd 100644 --- a/code/AssetLib/Q3BSP/Q3BSPFileData.h +++ b/code/AssetLib/Q3BSP/Q3BSPFileData.h @@ -178,7 +178,7 @@ struct Q3BSPModel { m_Textures(), m_Lightmaps(), m_EntityData(), - m_ModelName( "" ) + m_ModelName() { // empty } diff --git a/code/AssetLib/Q3BSP/Q3BSPFileImporter.cpp b/code/AssetLib/Q3BSP/Q3BSPFileImporter.cpp index c66582fea..85e79a12c 100644 --- a/code/AssetLib/Q3BSP/Q3BSPFileImporter.cpp +++ b/code/AssetLib/Q3BSP/Q3BSPFileImporter.cpp @@ -113,7 +113,7 @@ static void extractIds(const std::string &key, int &id1, int &id2) { // ------------------------------------------------------------------------------------------------ // Local helper function to normalize filenames. static void normalizePathName(const std::string &rPath, std::string &normalizedPath) { - normalizedPath = ""; + normalizedPath = std::string(); if (rPath.empty()) { return; } @@ -183,7 +183,7 @@ void Q3BSPFileImporter::InternReadFile(const std::string &rFile, aiScene *scene, throw DeadlyImportError("Failed to open file ", rFile, "."); } - std::string archiveName(""), mapName(""); + std::string archiveName, mapName; separateMapName(rFile, archiveName, mapName); if (mapName.empty()) { @@ -202,8 +202,8 @@ void Q3BSPFileImporter::InternReadFile(const std::string &rFile, aiScene *scene, // ------------------------------------------------------------------------------------------------ // Separates the map name from the import name. void Q3BSPFileImporter::separateMapName(const std::string &importName, std::string &archiveName, std::string &mapName) { - archiveName = ""; - mapName = ""; + archiveName = std::string(); + mapName = std::string(); if (importName.empty()) { return; } @@ -221,7 +221,7 @@ void Q3BSPFileImporter::separateMapName(const std::string &importName, std::stri // ------------------------------------------------------------------------------------------------ // Returns the first map in the map archive. bool Q3BSPFileImporter::findFirstMapInArchive(ZipArchiveIOSystem &bspArchive, std::string &mapName) { - mapName = ""; + mapName = std::string(); std::vector fileList; bspArchive.getFileListExtension(fileList, "bsp"); if (fileList.empty()) { @@ -440,7 +440,7 @@ void Q3BSPFileImporter::createMaterials(const Q3BSP::Q3BSPModel *pModel, aiScene if (-1 != textureId) { sQ3BSPTexture *pTexture = pModel->m_Textures[textureId]; if (nullptr != pTexture) { - std::string tmp("*"), texName(""); + std::string tmp("*"), texName; tmp += pTexture->strName; tmp += ".jpg"; normalizePathName(tmp, texName); @@ -512,7 +512,7 @@ size_t Q3BSPFileImporter::countTriangles(const std::vector // ------------------------------------------------------------------------------------------------ // Creates the faces-to-material map. void Q3BSPFileImporter::createMaterialMap(const Q3BSP::Q3BSPModel *pModel) { - std::string key(""); + std::string key; std::vector *pCurFaceArray = nullptr; for (size_t idx = 0; idx < pModel->m_Faces.size(); idx++) { Q3BSP::sQ3BSPFace *pQ3BSPFace = pModel->m_Faces[idx]; @@ -660,7 +660,7 @@ bool Q3BSPFileImporter::expandFile(ZipArchiveIOSystem *pArchive, const std::stri if (rExtList.empty()) { rFile = rFilename; - rExt = ""; + rExt = std::string(); return true; } diff --git a/code/AssetLib/X/XFileHelper.h b/code/AssetLib/X/XFileHelper.h index 8ba166350..5bdaf4d35 100644 --- a/code/AssetLib/X/XFileHelper.h +++ b/code/AssetLib/X/XFileHelper.h @@ -130,7 +130,7 @@ struct Mesh { std::vector mBones; - explicit Mesh(const std::string &pName = "") AI_NO_EXCEPT + explicit Mesh(const std::string &pName = std::string()) AI_NO_EXCEPT : mName( pName ) , mPositions() , mPosFaces() diff --git a/code/AssetLib/XGL/XGLLoader.cpp b/code/AssetLib/XGL/XGLLoader.cpp index 824f0c2c3..00e8bafb2 100644 --- a/code/AssetLib/XGL/XGLLoader.cpp +++ b/code/AssetLib/XGL/XGLLoader.cpp @@ -142,7 +142,7 @@ void XGLImporter::InternReadFile(const std::string &pFile, aiScene *pScene, IOSy // check whether we can read from the file if (stream.get() == NULL) { - throw DeadlyImportError("Failed to open XGL/ZGL file " + pFile + ""); + throw DeadlyImportError("Failed to open XGL/ZGL file " + pFile); } // see if its compressed, if so uncompress it diff --git a/code/AssetLib/glTF/glTFAsset.h b/code/AssetLib/glTF/glTFAsset.h index 1da70832b..8e4f1ff8f 100644 --- a/code/AssetLib/glTF/glTFAsset.h +++ b/code/AssetLib/glTF/glTFAsset.h @@ -1029,7 +1029,7 @@ namespace glTF AssetMetadata() : premultipliedAlpha(false) - , version("") + , version() { } }; diff --git a/code/AssetLib/glTF2/glTF2Asset.h b/code/AssetLib/glTF2/glTF2Asset.h index 53b079117..af48aa01b 100644 --- a/code/AssetLib/glTF2/glTF2Asset.h +++ b/code/AssetLib/glTF2/glTF2Asset.h @@ -1067,7 +1067,7 @@ struct AssetMetadata { void Read(Document &doc); AssetMetadata() : - version("") {} + version() {} }; // diff --git a/code/Common/BaseImporter.cpp b/code/Common/BaseImporter.cpp index 0657216cf..7da615ac4 100644 --- a/code/Common/BaseImporter.cpp +++ b/code/Common/BaseImporter.cpp @@ -271,7 +271,7 @@ std::string BaseImporter::GetExtension(const std::string &file) { // no file extension at all if (pos == std::string::npos) { - return ""; + return std::string(); } // thanks to Andy Maloney for the hint diff --git a/code/Common/FileSystemFilter.h b/code/Common/FileSystemFilter.h index 1440cf97d..92f199870 100644 --- a/code/Common/FileSystemFilter.h +++ b/code/Common/FileSystemFilter.h @@ -76,7 +76,7 @@ public: if (std::string::npos != (ss2 = mBase.find_last_of("\\/"))) { mBase.erase(ss2,mBase.length()-ss2); } else { - mBase = ""; + mBase = std::string(); } // make sure the directory is terminated properly diff --git a/code/Common/Importer.cpp b/code/Common/Importer.cpp index db7fc9e1c..8cea2cd09 100644 --- a/code/Common/Importer.cpp +++ b/code/Common/Importer.cpp @@ -149,7 +149,7 @@ void AllocateFromAssimpHeap::operator delete[] ( void* data) { Importer::Importer() : pimpl( new ImporterPimpl ) { pimpl->mScene = nullptr; - pimpl->mErrorString = ""; + pimpl->mErrorString = std::string(); // Allocate a default IO handler pimpl->mIOHandler = new DefaultIOSystem; @@ -387,7 +387,7 @@ void Importer::FreeScene( ) { delete pimpl->mScene; pimpl->mScene = nullptr; - pimpl->mErrorString = ""; + pimpl->mErrorString = std::string(); pimpl->mException = std::exception_ptr(); ASSIMP_END_EXCEPTION_REGION(void); } @@ -434,7 +434,7 @@ aiScene* Importer::GetOrphanedScene() { ASSIMP_BEGIN_EXCEPTION_REGION(); pimpl->mScene = nullptr; - pimpl->mErrorString = ""; // reset error string + pimpl->mErrorString = std::string(); pimpl->mException = std::exception_ptr(); ASSIMP_END_EXCEPTION_REGION(aiScene*); diff --git a/code/Common/scene.cpp b/code/Common/scene.cpp index 82430f5fc..67feb7afb 100644 --- a/code/Common/scene.cpp +++ b/code/Common/scene.cpp @@ -43,7 +43,7 @@ OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. #include aiNode::aiNode() -: mName("") +: mName() , mParent(nullptr) , mNumChildren(0) , mChildren(nullptr) diff --git a/code/PostProcessing/RemoveRedundantMaterials.h b/code/PostProcessing/RemoveRedundantMaterials.h index 6b4f8b1fb..4210a7fe2 100644 --- a/code/PostProcessing/RemoveRedundantMaterials.h +++ b/code/PostProcessing/RemoveRedundantMaterials.h @@ -81,7 +81,7 @@ public: /** @brief Set list of fixed (inmutable) materials * @param fixed See #AI_CONFIG_PP_RRM_EXCLUDE_LIST */ - void SetFixedMaterialsString(const std::string& fixed = "") { + void SetFixedMaterialsString(const std::string& fixed = std::string()) { mConfigFixedMaterials = fixed; } diff --git a/include/assimp/DefaultIOStream.h b/include/assimp/DefaultIOStream.h index b1bb66902..6d0e13149 100644 --- a/include/assimp/DefaultIOStream.h +++ b/include/assimp/DefaultIOStream.h @@ -119,7 +119,7 @@ private: AI_FORCE_INLINE DefaultIOStream::DefaultIOStream() AI_NO_EXCEPT : mFile(nullptr) -, mFilename("") +, mFilename() , mCachedSize(SIZE_MAX) { // empty } diff --git a/include/assimp/IOSystem.hpp b/include/assimp/IOSystem.hpp index b05eebce6..76f876440 100644 --- a/include/assimp/IOSystem.hpp +++ b/include/assimp/IOSystem.hpp @@ -294,7 +294,7 @@ bool IOSystem::PushDirectory( const std::string &path ) { AI_FORCE_INLINE const std::string &IOSystem::CurrentDirectory() const { if ( m_pathStack.empty() ) { - static const std::string Dummy(""); + static const std::string Dummy; return Dummy; } return m_pathStack[ m_pathStack.size()-1 ]; diff --git a/include/assimp/Importer.hpp b/include/assimp/Importer.hpp index 18734c302..09b5b6883 100644 --- a/include/assimp/Importer.hpp +++ b/include/assimp/Importer.hpp @@ -286,7 +286,7 @@ public: * @see GetPropertyInteger() */ std::string GetPropertyString(const char *szName, - const std::string &sErrorReturn = "") const; + const std::string &sErrorReturn = std::string()) const; // ------------------------------------------------------------------- /** Get a matrix configuration property diff --git a/include/assimp/XmlParser.h b/include/assimp/XmlParser.h index 15c4ff9ff..f525d3549 100644 --- a/include/assimp/XmlParser.h +++ b/include/assimp/XmlParser.h @@ -239,7 +239,7 @@ public: } static inline bool getValueAsString( XmlNode &node, std::string &text ) { - text = ""; + text = std::string(); if (node.empty()) { return false; } From a19299d501e1130bc69fc2bf1d7a3cb466b1998d Mon Sep 17 00:00:00 2001 From: Krishty Date: Sat, 17 Apr 2021 00:32:04 +0200 Subject: [PATCH 03/12] moved MD2/MDC tables from BSS to const data Visual C++ is unable to identify them as constant data during optimization, so explicitly declare them const. --- code/AssetLib/MD2/MD2NormalTable.h | 2 +- code/AssetLib/MDC/MDCNormalTable.h | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/code/AssetLib/MD2/MD2NormalTable.h b/code/AssetLib/MD2/MD2NormalTable.h index 3eff0d666..b2330d862 100644 --- a/code/AssetLib/MD2/MD2NormalTable.h +++ b/code/AssetLib/MD2/MD2NormalTable.h @@ -51,7 +51,7 @@ OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. #define AI_MDL_NORMALTABLE_H_INC -float g_avNormals[162][3] = { +const float g_avNormals[162][3] = { { -0.525731f, 0.000000f, 0.850651f }, { -0.442863f, 0.238856f, 0.864188f }, { -0.295242f, 0.000000f, 0.955423f }, diff --git a/code/AssetLib/MDC/MDCNormalTable.h b/code/AssetLib/MDC/MDCNormalTable.h index f47e97f33..c96eba7bd 100644 --- a/code/AssetLib/MDC/MDCNormalTable.h +++ b/code/AssetLib/MDC/MDCNormalTable.h @@ -36,7 +36,7 @@ SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. #define MDC_NORMAL_TABLE_INCLUDED /* mdc decoding normal table */ -float mdcNormals[ 256 ][ 3 ] = +const float mdcNormals[ 256 ][ 3 ] = { { 1.000000f, 0.000000f, 0.000000f }, { 0.980785f, 0.195090f, 0.000000f }, From 55dd5faafb4b80dd5f58147d56e69cd442eee29f Mon Sep 17 00:00:00 2001 From: Krishty Date: Mon, 19 Apr 2021 19:33:41 +0200 Subject: [PATCH 04/12] fixed export exceptions on import Ogre and 3MF imports threw DeadlyExportErrors under some circumstances. Bad for people who assumed that they only needed to catch DeadlyImportErrors. Changed them to DeadlyImportErrors. --- code/AssetLib/3MF/D3MFOpcPackage.cpp | 2 +- code/AssetLib/Ogre/OgreBinarySerializer.cpp | 8 ++++---- 2 files changed, 5 insertions(+), 5 deletions(-) diff --git a/code/AssetLib/3MF/D3MFOpcPackage.cpp b/code/AssetLib/3MF/D3MFOpcPackage.cpp index 514e3c2f3..16e659ea3 100644 --- a/code/AssetLib/3MF/D3MFOpcPackage.cpp +++ b/code/AssetLib/3MF/D3MFOpcPackage.cpp @@ -156,7 +156,7 @@ D3MFOpcPackage::D3MFOpcPackage(IOSystem *pIOHandler, const std::string &rFile) : mRootStream = mZipArchive->Open(rootFile.c_str()); ai_assert(mRootStream != nullptr); if (nullptr == mRootStream) { - throw DeadlyExportError("Cannot open root-file in archive : " + rootFile); + throw DeadlyImportError("Cannot open root-file in archive : " + rootFile); } } else if (file == D3MF::XmlTag::CONTENT_TYPES_ARCHIVE) { diff --git a/code/AssetLib/Ogre/OgreBinarySerializer.cpp b/code/AssetLib/Ogre/OgreBinarySerializer.cpp index 13bf54e9f..0fc18feb9 100644 --- a/code/AssetLib/Ogre/OgreBinarySerializer.cpp +++ b/code/AssetLib/Ogre/OgreBinarySerializer.cpp @@ -181,13 +181,13 @@ Mesh *OgreBinarySerializer::ImportMesh(MemoryStreamReader *stream) { uint16_t id = serializer.ReadHeader(false); if (id != HEADER_CHUNK_ID) { - throw DeadlyExportError("Invalid Ogre Mesh file header."); + throw DeadlyImportError("Invalid Ogre Mesh file header."); } /// @todo Check what we can actually support. std::string version = serializer.ReadLine(); if (version != MESH_VERSION_1_8) { - throw DeadlyExportError("Mesh version ", version, " not supported by this importer. Run OgreMeshUpgrader tool on the file and try again.", + throw DeadlyImportError("Mesh version ", version, " not supported by this importer. Run OgreMeshUpgrader tool on the file and try again.", " Supported versions: ", MESH_VERSION_1_8); } @@ -797,13 +797,13 @@ MemoryStreamReaderPtr OgreBinarySerializer::OpenReader(Assimp::IOSystem *pIOHand void OgreBinarySerializer::ReadSkeleton(Skeleton *skeleton) { uint16_t id = ReadHeader(false); if (id != HEADER_CHUNK_ID) { - throw DeadlyExportError("Invalid Ogre Skeleton file header."); + throw DeadlyImportError("Invalid Ogre Skeleton file header."); } // This deserialization supports both versions of the skeleton spec std::string version = ReadLine(); if (version != SKELETON_VERSION_1_8 && version != SKELETON_VERSION_1_1) { - throw DeadlyExportError("Skeleton version ", version, " not supported by this importer.", + throw DeadlyImportError("Skeleton version ", version, " not supported by this importer.", " Supported versions: ", SKELETON_VERSION_1_8, " and ", SKELETON_VERSION_1_1); } From 746d5cf964120967a72322ad98723390707f15f4 Mon Sep 17 00:00:00 2001 From: "Max Vollmer (Microsoft Havok)" <60260460+ms-maxvollmer@users.noreply.github.com> Date: Wed, 21 Apr 2021 16:17:03 +0100 Subject: [PATCH 05/12] * Throw instead of assert on invalid file input * Check JSON object type before accessing members * Ensure samplers input and output references are set before accessing them --- code/AssetLib/glTF2/glTF2Asset.inl | 27 ++++++++++++++++++++-- code/AssetLib/glTF2/glTF2Importer.cpp | 6 ++--- code/PostProcessing/SortByPTypeProcess.cpp | 4 +++- 3 files changed, 31 insertions(+), 6 deletions(-) diff --git a/code/AssetLib/glTF2/glTF2Asset.inl b/code/AssetLib/glTF2/glTF2Asset.inl index 77537028f..8a793c144 100644 --- a/code/AssetLib/glTF2/glTF2Asset.inl +++ b/code/AssetLib/glTF2/glTF2Asset.inl @@ -162,6 +162,9 @@ inline static bool ReadValue(Value &val, T &out) { template inline static bool ReadMember(Value &obj, const char *id, T &out) { + if (!obj.IsObject()) { + return false; + } Value::MemberIterator it = obj.FindMember(id); if (it != obj.MemberEnd()) { return ReadHelper::Read(it->value, out); @@ -176,6 +179,9 @@ inline static T MemberOrDefault(Value &obj, const char *id, T defaultValue) { } inline Value *FindMember(Value &val, const char *id) { + if (!val.IsObject()) { + return nullptr; + } Value::MemberIterator it = val.FindMember(id); return (it != val.MemberEnd()) ? &it->value : nullptr; } @@ -193,6 +199,9 @@ inline void throwUnexpectedTypeError(const char (&expectedTypeName)[N], const ch // Look-up functions with type checks. Context and extra context help the user identify the problem if there's an error. inline Value *FindStringInContext(Value &val, const char *memberId, const char* context, const char* extraContext = nullptr) { + if (!val.IsObject()) { + return nullptr; + } Value::MemberIterator it = val.FindMember(memberId); if (it == val.MemberEnd()) { return nullptr; @@ -204,6 +213,9 @@ inline Value *FindStringInContext(Value &val, const char *memberId, const char* } inline Value *FindNumberInContext(Value &val, const char *memberId, const char* context, const char* extraContext = nullptr) { + if (!val.IsObject()) { + return nullptr; + } Value::MemberIterator it = val.FindMember(memberId); if (it == val.MemberEnd()) { return nullptr; @@ -215,6 +227,9 @@ inline Value *FindNumberInContext(Value &val, const char *memberId, const char* } inline Value *FindUIntInContext(Value &val, const char *memberId, const char* context, const char* extraContext = nullptr) { + if (!val.IsObject()) { + return nullptr; + } Value::MemberIterator it = val.FindMember(memberId); if (it == val.MemberEnd()) { return nullptr; @@ -226,6 +241,9 @@ inline Value *FindUIntInContext(Value &val, const char *memberId, const char* co } inline Value *FindArrayInContext(Value &val, const char *memberId, const char* context, const char* extraContext = nullptr) { + if (!val.IsObject()) { + return nullptr; + } Value::MemberIterator it = val.FindMember(memberId); if (it == val.MemberEnd()) { return nullptr; @@ -237,6 +255,9 @@ inline Value *FindArrayInContext(Value &val, const char *memberId, const char* c } inline Value *FindObjectInContext(Value &val, const char *memberId, const char* context, const char* extraContext = nullptr) { + if (!val.IsObject()) { + return nullptr; + } Value::MemberIterator it = val.FindMember(memberId); if (it == val.MemberEnd()) { return nullptr; @@ -886,7 +907,7 @@ inline void Accessor::Read(Value &obj, Asset &r) { componentType = MemberOrDefault(obj, "componentType", ComponentType_BYTE); { const Value* countValue = FindUInt(obj, "count"); - if (!countValue || countValue->GetInt() < 1) + if (!countValue || countValue->GetUint() < 1) { throw DeadlyImportError("A strictly positive count value is required, when reading ", id.c_str(), name.empty() ? "" : " (" + name + ")"); } @@ -1105,7 +1126,9 @@ inline Accessor::Indexer::Indexer(Accessor &acc) : template T Accessor::Indexer::GetValue(int i) { ai_assert(data); - ai_assert(i * stride < accessor.GetMaxByteSize()); + if (i * stride >= accessor.GetMaxByteSize()) { + throw DeadlyImportError("GLTF: Invalid index ", i, ", count out of range for buffer with stride ", stride, " and size ", accessor.GetMaxByteSize(), "."); + } // Ensure that the memcpy doesn't overwrite the local. const size_t sizeToCopy = std::min(elemSize, sizeof(T)); T value = T(); diff --git a/code/AssetLib/glTF2/glTF2Importer.cpp b/code/AssetLib/glTF2/glTF2Importer.cpp index dca6fcb2d..b6b6a364c 100644 --- a/code/AssetLib/glTF2/glTF2Importer.cpp +++ b/code/AssetLib/glTF2/glTF2Importer.cpp @@ -1170,7 +1170,7 @@ aiNodeAnim *CreateNodeAnim(glTF2::Asset&, Node &node, AnimationSamplers &sampler static const float kMillisecondsFromSeconds = 1000.f; - if (samplers.translation) { + if (samplers.translation && samplers.translation->input && samplers.translation->output) { float *times = nullptr; samplers.translation->input->ExtractData(times); aiVector3D *values = nullptr; @@ -1194,7 +1194,7 @@ aiNodeAnim *CreateNodeAnim(glTF2::Asset&, Node &node, AnimationSamplers &sampler anim->mPositionKeys->mValue.z = node.translation.value[2]; } - if (samplers.rotation) { + if (samplers.rotation && samplers.rotation->input && samplers.rotation->output) { float *times = nullptr; samplers.rotation->input->ExtractData(times); aiQuaternion *values = nullptr; @@ -1222,7 +1222,7 @@ aiNodeAnim *CreateNodeAnim(glTF2::Asset&, Node &node, AnimationSamplers &sampler anim->mRotationKeys->mValue.w = node.rotation.value[3]; } - if (samplers.scale) { + if (samplers.scale && samplers.scale->input && samplers.scale->output) { float *times = nullptr; samplers.scale->input->ExtractData(times); aiVector3D *values = nullptr; diff --git a/code/PostProcessing/SortByPTypeProcess.cpp b/code/PostProcessing/SortByPTypeProcess.cpp index dd6902692..38549b9a0 100644 --- a/code/PostProcessing/SortByPTypeProcess.cpp +++ b/code/PostProcessing/SortByPTypeProcess.cpp @@ -135,7 +135,9 @@ void SortByPTypeProcess::Execute(aiScene *pScene) { std::vector::iterator meshIdx = replaceMeshIndex.begin(); for (unsigned int i = 0; i < pScene->mNumMeshes; ++i) { aiMesh *const mesh = pScene->mMeshes[i]; - ai_assert(0 != mesh->mPrimitiveTypes); + if (mesh->mPrimitiveTypes == 0) { + throw DeadlyImportError("GLTF: Mesh with invalid primitive type: ", mesh->mName.C_Str()); + } // if there's just one primitive type in the mesh there's nothing to do for us unsigned int num = 0; From 44dc08f128c97667104a5dc6a85bf1ea645ce1b5 Mon Sep 17 00:00:00 2001 From: "Max Vollmer (Microsoft Havok)" <60260460+ms-maxvollmer@users.noreply.github.com> Date: Wed, 21 Apr 2021 16:20:58 +0100 Subject: [PATCH 06/12] Remove GLTF tag, postprocessing is format independent --- code/PostProcessing/SortByPTypeProcess.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/code/PostProcessing/SortByPTypeProcess.cpp b/code/PostProcessing/SortByPTypeProcess.cpp index 38549b9a0..20ab63249 100644 --- a/code/PostProcessing/SortByPTypeProcess.cpp +++ b/code/PostProcessing/SortByPTypeProcess.cpp @@ -136,7 +136,7 @@ void SortByPTypeProcess::Execute(aiScene *pScene) { for (unsigned int i = 0; i < pScene->mNumMeshes; ++i) { aiMesh *const mesh = pScene->mMeshes[i]; if (mesh->mPrimitiveTypes == 0) { - throw DeadlyImportError("GLTF: Mesh with invalid primitive type: ", mesh->mName.C_Str()); + throw DeadlyImportError("Mesh with invalid primitive type: ", mesh->mName.C_Str()); } // if there's just one primitive type in the mesh there's nothing to do for us From 31438a03a6430ee35c686b2bb7b3294fb55588cb Mon Sep 17 00:00:00 2001 From: Kim Kulling Date: Fri, 23 Apr 2021 14:52:31 +0200 Subject: [PATCH 07/12] Add Codacy Badge - Add assimp to codacy - Add batch to readme --- Readme.md | 1 + 1 file changed, 1 insertion(+) diff --git a/Readme.md b/Readme.md index 9fecfedf5..e6c5fdbac 100644 --- a/Readme.md +++ b/Readme.md @@ -8,6 +8,7 @@ A library to import and export various 3d-model-formats including scene-post-pro Coverity Scan Build Status +[![Codacy Badge](https://app.codacy.com/project/badge/Grade/9973693b7bdd4543b07084d5d9cf4745)](https://www.codacy.com/gh/assimp/assimp/dashboard?utm_source=github.com&utm_medium=referral&utm_content=assimp/assimp&utm_campaign=Badge_Grade) [![Coverage Status](https://coveralls.io/repos/github/assimp/assimp/badge.svg?branch=master)](https://coveralls.io/github/assimp/assimp?branch=master) [![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) [![Average time to resolve an issue](http://isitmaintained.com/badge/resolution/assimp/assimp.svg)](http://isitmaintained.com/project/assimp/assimp "Average time to resolve an issue") From 4db4e7206da36f80136f85912beb2110866edb0d Mon Sep 17 00:00:00 2001 From: Kim Kulling Date: Fri, 23 Apr 2021 15:14:38 +0200 Subject: [PATCH 08/12] Update Readme.md --- Readme.md | 1 - 1 file changed, 1 deletion(-) diff --git a/Readme.md b/Readme.md index e6c5fdbac..81fd9fd9d 100644 --- a/Readme.md +++ b/Readme.md @@ -12,7 +12,6 @@ A library to import and export various 3d-model-formats including scene-post-pro [![Coverage Status](https://coveralls.io/repos/github/assimp/assimp/badge.svg?branch=master)](https://coveralls.io/github/assimp/assimp?branch=master) [![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) [![Average time to resolve an issue](http://isitmaintained.com/badge/resolution/assimp/assimp.svg)](http://isitmaintained.com/project/assimp/assimp "Average time to resolve an issue") -[![Codacy Badge](https://api.codacy.com/project/badge/Grade/5be56faac64f46fc941ac890fb4febef)](https://www.codacy.com/app/kimkulling/assimp?utm_source=github.com&utm_medium=referral&utm_content=assimp/assimp&utm_campaign=Badge_Grade) [![Total alerts](https://img.shields.io/lgtm/alerts/g/assimp/assimp.svg?logo=lgtm&logoWidth=18)](https://lgtm.com/projects/g/assimp/assimp/alerts/)
From 708d124745a4256e8e8850dd9cbce4853a971e9f Mon Sep 17 00:00:00 2001 From: Jason C Date: Mon, 26 Apr 2021 19:42:22 -0400 Subject: [PATCH 09/12] Update aiProcess_PreTransformVertices docs to match behavior. Addresses #3820, the easy way. --- include/assimp/postprocess.h | 11 ++++++++--- 1 file changed, 8 insertions(+), 3 deletions(-) diff --git a/include/assimp/postprocess.h b/include/assimp/postprocess.h index 01eabaef9..ca2c2c22d 100644 --- a/include/assimp/postprocess.h +++ b/include/assimp/postprocess.h @@ -209,9 +209,14 @@ enum aiPostProcessSteps /**
Removes the node graph and pre-transforms all vertices with * the local transformation matrices of their nodes. * - * The output scene still contains nodes, however there is only a - * root node with children, each one referencing only one mesh, - * and each mesh referencing one material. For rendering, you can + * If the resulting scene can be reduced to a single mesh, with a single + * material, no lights, and no cameras, then the output scene will contain + * only a root node (with no children) that references the single mesh. + * Otherwise, the output scene will be reduced to a root node with a single + * level of child nodes, each one referencing one mesh, and each mesh + * referencing one material. + * + * In either case, for rendering, you can * simply render all meshes in order - you don't need to pay * attention to local transformations and the node hierarchy. * Animations are removed during this step. From 3acd42c22ed48225919cf03a092262a2e706fbdd Mon Sep 17 00:00:00 2001 From: Jason C Date: Mon, 26 Apr 2021 20:27:28 -0400 Subject: [PATCH 10/12] Remove newline from name of Blender importer. Addresses #3797. Re-submitting this as a quick fix to the immediate issue while I think about the website field. --- code/AssetLib/Blender/BlenderLoader.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/code/AssetLib/Blender/BlenderLoader.cpp b/code/AssetLib/Blender/BlenderLoader.cpp index 989e9d59a..71ab67721 100644 --- a/code/AssetLib/Blender/BlenderLoader.cpp +++ b/code/AssetLib/Blender/BlenderLoader.cpp @@ -88,7 +88,7 @@ using namespace Assimp::Blender; using namespace Assimp::Formatter; static const aiImporterDesc blenderDesc = { - "Blender 3D Importer \nhttp://www.blender3d.org", + "Blender 3D Importer (http://www.blender3d.org)", "", "", "No animation support yet", From 6abdd0cd3e5f199f0c3bd5f4b08eb3c296edce81 Mon Sep 17 00:00:00 2001 From: Kim Kulling Date: Wed, 28 Apr 2021 16:38:22 +0200 Subject: [PATCH 11/12] Fix crash when reading 0 bytes - This is a valid option so crash shall not happen --- code/Common/DefaultIOStream.cpp | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/code/Common/DefaultIOStream.cpp b/code/Common/DefaultIOStream.cpp index 115fea63c..ba9b9d625 100644 --- a/code/Common/DefaultIOStream.cpp +++ b/code/Common/DefaultIOStream.cpp @@ -90,10 +90,12 @@ DefaultIOStream::~DefaultIOStream() { size_t DefaultIOStream::Read(void *pvBuffer, size_t pSize, size_t pCount) { + if (0 == pCount) { + return 0; + } ai_assert(nullptr != pvBuffer); ai_assert(0 != pSize); - ai_assert(0 != pCount); - + return (mFile ? ::fread(pvBuffer, pSize, pCount, mFile) : 0); } From feeb89a1dd4b572f6380fa075e67efbe7d3dee1e Mon Sep 17 00:00:00 2001 From: Kim Kulling Date: Fri, 30 Apr 2021 16:49:15 +0200 Subject: [PATCH 12/12] closes https://github.com/assimp/assimp/issues/3831 : update zip --- contrib/zip/.gitignore | 58 -- contrib/zip/CMakeLists.txt | 44 +- contrib/zip/README.md | 149 ++++- contrib/zip/src/miniz.h | 74 ++- contrib/zip/src/zip.c | 1094 ++++++++++++++++++++++++------- contrib/zip/src/zip.h | 136 +++- contrib/zip/test/CMakeLists.txt | 41 +- 7 files changed, 1219 insertions(+), 377 deletions(-) delete mode 100644 contrib/zip/.gitignore diff --git a/contrib/zip/.gitignore b/contrib/zip/.gitignore deleted file mode 100644 index 49b2cb2fd..000000000 --- a/contrib/zip/.gitignore +++ /dev/null @@ -1,58 +0,0 @@ -/build/ -/test/build/ -/xcodeproj/ -.vscode/ - -# Object files -*.o -*.ko -*.obj -*.elf - -# Precompiled Headers -*.gch -*.pch - -# Libraries -*.lib -*.a -*.la -*.lo - -# Shared objects (inc. Windows DLLs) -*.dll -*.so -*.so.* -*.dylib -*.suo - -# Executables -*.exe -*.out -*.app -*.i*86 -*.x86_64 -*.hex - -# Temporary -*.swp -.DS_Store - -# CMake -CMakeScripts -*.cmake - -# Xcode -*.build -*.xcodeproj -zip.sln -zip.vcxproj.filters -zip.vcxproj -ALL_BUILD.vcxproj.filters -ALL_BUILD.vcxproj -CMakeFiles/ -zip.dir/ -test/test.exe.vcxproj.filters -test/test.exe.vcxproj -test/test.exe.dir/ - diff --git a/contrib/zip/CMakeLists.txt b/contrib/zip/CMakeLists.txt index cdfa94b3b..bba4e7bde 100644 --- a/contrib/zip/CMakeLists.txt +++ b/contrib/zip/CMakeLists.txt @@ -1,26 +1,29 @@ -cmake_minimum_required(VERSION 3.10) +cmake_minimum_required(VERSION 3.4) project(zip LANGUAGES C - VERSION "0.1.18") + VERSION "0.1.19") set(CMAKE_MODULE_PATH "${PROJECT_SOURCE_DIR}/cmake" ${CMAKE_MODULE_PATH}) - +set(CMAKE_VERBOSE_MAKEFILE ON) option(CMAKE_DISABLE_TESTING "Disable test creation" OFF) -if (MSVC) - # Use secure functions by default and suppress warnings about "deprecated" functions - set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} /D _CRT_SECURE_CPP_OVERLOAD_STANDARD_NAMES=1") - set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} /D _CRT_SECURE_CPP_OVERLOAD_STANDARD_NAMES_COUNT=1") - set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} /D _CRT_NONSTDC_NO_WARNINGS=1 /D _CRT_SECURE_NO_WARNINGS=1") -elseif ("${CMAKE_C_COMPILER_ID}" STREQUAL "GNU" OR - "${CMAKE_C_COMPILER_ID}" STREQUAL "Clang" OR - "${CMAKE_C_COMPILER_ID}" STREQUAL "AppleClang") - set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -std=c99 -Wall -Wextra -Werror -pedantic") -endif (MSVC) - # zip set(SRC src/miniz.h src/zip.h src/zip.c) -add_library(${PROJECT_NAME} ${SRC}) + +# this is the "object library" target: compiles the sources only once +add_library(OBJLIB OBJECT ${SRC}) +# shared libraries need PIC +set_property(TARGET OBJLIB PROPERTY POSITION_INDEPENDENT_CODE 1) + +# static and shared libraries built from the same object files +if (BUILD_SHARED_LIBS) + add_library(${PROJECT_NAME} SHARED $) + include(GenerateExportHeader) + generate_export_header(${PROJECT_NAME}) +else() + add_library(${PROJECT_NAME} STATIC $) +endif() + target_include_directories(${PROJECT_NAME} PUBLIC $ $ @@ -34,6 +37,17 @@ if (NOT CMAKE_DISABLE_TESTING) add_sanitizers(${PROJECT_NAME} ${test_out}) endif() +if (MSVC) + # Use secure functions by default and suppress warnings about "deprecated" functions + set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} /D _CRT_SECURE_CPP_OVERLOAD_STANDARD_NAMES=1") + set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} /D _CRT_SECURE_CPP_OVERLOAD_STANDARD_NAMES_COUNT=1") + set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} /D _CRT_NONSTDC_NO_WARNINGS=1 /D _CRT_SECURE_NO_WARNINGS=1") +elseif ("${CMAKE_C_COMPILER_ID}" STREQUAL "GNU" OR + "${CMAKE_C_COMPILER_ID}" STREQUAL "Clang" OR + "${CMAKE_C_COMPILER_ID}" STREQUAL "AppleClang") + set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -std=gnu99 -Wall -Wextra -Werror -pedantic -Wno-deprecated") +endif (MSVC) + #### # Installation (https://github.com/forexample/package-example) { diff --git a/contrib/zip/README.md b/contrib/zip/README.md index bdd0822b6..308327a3f 100644 --- a/contrib/zip/README.md +++ b/contrib/zip/README.md @@ -2,7 +2,6 @@ This is done by hacking awesome [miniz](https://code.google.com/p/miniz) library and layering functions on top of the miniz v1.15 API. [![Build](https://github.com/kuba--/zip/workflows/build/badge.svg)](https://github.com/kuba--/zip/actions?query=workflow%3Abuild) -[![Version](https://badge.fury.io/gh/kuba--%2Fzip.svg)](https://github.com/kuba--/zip/releases) # The Idea @@ -155,10 +154,52 @@ struct zip_t *zip = zip_open("foo.zip", 0, 'r'); zip_close(zip); ``` +* Create a new zip archive in memory (stream API). + +```c +char *outbuf = NULL; +size_t outbufsize = 0; + +const char *inbuf = "Append some data here...\0"; +struct zip_t *zip = zip_stream_open(NULL, 0, ZIP_DEFAULT_COMPRESSION_LEVEL, 'w'); +{ + zip_entry_open(zip, "foo-1.txt"); + { + zip_entry_write(zip, inbuf, strlen(inbuf)); + } + zip_entry_close(zip); + + /* copy compressed stream into outbuf */ + zip_stream_copy(zip, (void **)&outbuf, &outbufsize); +} +zip_stream_close(zip); + +free(outbuf); +``` + +* Extract a zip entry into a memory (stream API). + +```c +char *buf = NULL; +ssize_t bufsize = 0; + +struct zip_t *zip = zip_stream_open(zipstream, zipstreamsize, 0, 'r'); +{ + zip_entry_open(zip, "foo-1.txt"); + { + zip_entry_read(zip, (void **)&buf, &bufsize); + } + zip_entry_close(zip); +} +zip_stream_close(zip); + +free(buf); +``` + * List of all zip entries ```c struct zip_t *zip = zip_open("foo.zip", 0, 'r'); -int i, n = zip_total_entries(zip); +int i, n = zip_entries_total(zip); for (i = 0; i < n; ++i) { zip_entry_openbyindex(zip, i); { @@ -172,6 +213,49 @@ for (i = 0; i < n; ++i) { zip_close(zip); ``` +* Compress folder (recursively) +```c +void zip_walk(struct zip_t *zip, const char *path) { + DIR *dir; + struct dirent *entry; + char fullpath[MAX_PATH]; + struct stat s; + + memset(fullpath, 0, MAX_PATH); + dir = opendir(path); + assert(dir); + + while ((entry = readdir(dir))) { + // skip "." and ".." + if (!strcmp(entry->d_name, ".\0") || !strcmp(entry->d_name, "..\0")) + continue; + + snprintf(fullpath, sizeof(fullpath), "%s/%s", path, entry->d_name); + stat(fullpath, &s); + if (S_ISDIR(s.st_mode)) + zip_walk(zip, fullpath); + else { + zip_entry_open(zip, fullpath); + zip_entry_fwrite(zip, fullpath); + zip_entry_close(zip); + } + } + + closedir(dir); +} +``` + +* Deletes zip archive entries. +```c +char *entries[] = {"unused.txt", "remove.ini", "delete.me"}; + +struct zip_t *zip = zip_open("foo.zip", 0, 'd'); +{ + zip_entries_delete(zip, entries, 3); +} +zip_close(zip); +``` + # Bindings Compile zip library as a dynamic library. ```shell @@ -181,7 +265,7 @@ $ cmake -DBUILD_SHARED_LIBS=true .. $ make ``` -### Go (cgo) +### [Go](https://golang.org) (cgo) ```go package main @@ -211,7 +295,7 @@ func main() { } ``` -### Rust (ffi) +### [Rust](https://www.rust-lang.org) (ffi) ```rust extern crate libc; use std::ffi::CString; @@ -236,7 +320,7 @@ extern "C" { } fn main() { - let path = CString::new("/tmp/test.zip").unwrap(); + let path = CString::new("/tmp/rust.zip").unwrap(); let mode: libc::c_char = 'w' as libc::c_char; let entryname = CString::new("test.txt").unwrap(); @@ -258,7 +342,7 @@ fn main() { } ``` -### Ruby (ffi) +### [Ruby](http://www.ruby-lang.org) (ffi) Install _ffi_ gem. ```shell $ gem install ffi @@ -291,7 +375,7 @@ Zip.zip_entry_close(ptr) Zip.zip_close(ptr) ``` -### Python (cffi) +### [Python](https://www.python.org) (cffi) Install _cffi_ package ```shell $ pip install cffi @@ -325,7 +409,36 @@ Zip.zip_entry_close(ptr) Zip.zip_close(ptr) ``` -### Ring +### [Never](https://never-lang.readthedocs.io/) (ffi) +```never +extern "libzip.so" func zip_open(zipname: string, level: int, mode: char) -> c_ptr +extern "libzip.so" func zip_close(zip: c_ptr) -> void + +extern "libzip.so" func zip_entry_open(zip: c_ptr, entryname: string) -> int +extern "libzip.so" func zip_entry_close(zip: c_ptr) -> int +extern "libzip.so" func zip_entry_write(zip: c_ptr, buf: string, bufsize: int) -> int +extern "libzip.so" func zip_entry_fwrite(zip: c_ptr, filename: string) -> int + +func main() -> int +{ + let content = "Test content" + + let zip = zip_open("/tmp/never.zip", 6, 'w'); + + zip_entry_open(zip, "test.file"); + zip_entry_fwrite(zip, "/tmp/test.txt"); + zip_entry_close(zip); + + zip_entry_open(zip, "test.content"); + zip_entry_write(zip, content, length(content)); + zip_entry_close(zip); + + zip_close(zip); + 0 +} +``` + +### [Ring](http://ring-lang.net) The language comes with RingZip based on this library ```ring load "ziplib.ring" @@ -342,13 +455,15 @@ new Zip { } ``` -# Contribution Rules/Coding Standards -No need to throw away your coding style, just do your best to follow default clang-format style. -Apply `clang-format` to the source files before commit: -```sh -for file in $(git ls-files | \grep -E '\.(c|h)$' | \grep -v -- '#') -do - clang-format -i $file -done -``` +# Check out more cool projects which use this library: +- [Filament](https://github.com/google/filament): Filament is a real-time physically based rendering engine for Android, iOS, Linux, macOS, Windows, and WebGL. It is designed to be as small as possible and as efficient as possible on Android. +- [Hermes JS Engine](https://github.com/facebook/hermes): Hermes is a JavaScript engine optimized for fast start-up of React Native apps on Android. It features ahead-of-time static optimization and compact bytecode. +- [Open Asset Import Library](https://github.com/assimp/assimp): A library to import and export various 3d-model-formats including scene-post-processing to generate missing render data. +- [PowerToys](https://github.com/microsoft/PowerToys): Set of utilities for power users to tune and streamline their Windows 10 experience for greater productivity. +- [The Ring Programming Language](https://ring-lang.github.io): Innovative and practical general-purpose multi-paradigm language. +- [The V Programming Language](https://github.com/vlang/v): Simple, fast, safe, compiled. For developing maintainable software. +- [TIC-80](https://github.com/nesbox/TIC-80): TIC-80 is a FREE and OPEN SOURCE fantasy computer for making, playing and sharing tiny games. +- [Urho3D](https://github.com/urho3d/Urho3D): Urho3D is a free lightweight, cross-platform 2D and 3D game engine implemented in C++ and released under the MIT license. Greatly inspired by OGRE and Horde3D. +- [Vcpkg](https://github.com/microsoft/vcpkg): Vcpkg helps you manage C and C++ libraries on Windows, Linux and MacOS. +- [and more...](https://grep.app/search?q=kuba--/zip) diff --git a/contrib/zip/src/miniz.h b/contrib/zip/src/miniz.h index 7570ae929..0a5560b24 100644 --- a/contrib/zip/src/miniz.h +++ b/contrib/zip/src/miniz.h @@ -400,7 +400,7 @@ typedef enum { #ifndef MINIZ_NO_ZLIB_APIS // Heap allocation callbacks. -// Note that mz_alloc_func parameter types purpsosely differ from zlib's: +// Note that mz_alloc_func parameter types purposely differ from zlib's: // items/size is size_t, not unsigned long. typedef void *(*mz_alloc_func)(void *opaque, size_t items, size_t size); typedef void (*mz_free_func)(void *opaque, void *address); @@ -2194,7 +2194,8 @@ tinfl_status tinfl_decompress(tinfl_decompressor *r, } else tree_cur = pTable->m_tree[-tree_cur - 1]; } - tree_cur -= ((rev_code >>= 1) & 1); + rev_code >>= 1; + tree_cur -= (rev_code & 1); pTable->m_tree[-tree_cur - 1] = (mz_int16)sym_index; } if (r->m_type == 2) { @@ -3970,6 +3971,7 @@ mz_uint tdefl_create_comp_flags_from_zip_params(int level, int window_bits, #ifdef _MSC_VER #pragma warning(push) +#pragma warning(disable : 4121 4127 4244) #pragma warning(disable : 4204) // nonstandard extension used : non-constant // aggregate initializer (also supported by GNU // C and C99, so no big deal) @@ -4098,10 +4100,6 @@ void *tdefl_write_image_to_png_file_in_memory(const void *pImage, int w, int h, pLen_out, 6, MZ_FALSE); } -#ifdef _MSC_VER -#pragma warning(pop) -#endif - // ------------------- .ZIP archive reading #ifndef MINIZ_NO_ARCHIVE_APIS @@ -4112,18 +4110,39 @@ void *tdefl_write_image_to_png_file_in_memory(const void *pImage, int w, int h, #include #include -#if defined(_MSC_VER) +#if defined(_MSC_VER) || defined(__MINGW32__) + +#include + +static wchar_t *str2wstr(const char *str) { + int len = (int) strlen(str) + 1; + wchar_t *wstr = malloc(len * sizeof(wchar_t)); + MultiByteToWideChar(CP_UTF8, 0, str, len * sizeof(char), wstr, len); + return wstr; +} + static FILE *mz_fopen(const char *pFilename, const char *pMode) { - FILE *pFile = NULL; - fopen_s(&pFile, pFilename, pMode); + wchar_t *wFilename = str2wstr(pFilename); + wchar_t *wMode = str2wstr(pMode); + FILE *pFile = _wfopen(wFilename, wMode); + + free(wFilename); + free(wMode); + return pFile; } + static FILE *mz_freopen(const char *pPath, const char *pMode, FILE *pStream) { - FILE *pFile = NULL; - if (freopen_s(&pFile, pPath, pMode, pStream)) - return NULL; + wchar_t *wPath = str2wstr(pPath); + wchar_t *wMode = str2wstr(pMode); + FILE *pFile = _wfreopen(wPath, wMode, pStream); + + free(wPath); + free(wMode); + return pFile; } + #ifndef MINIZ_NO_TIME #include #endif @@ -4144,7 +4163,7 @@ static FILE *mz_freopen(const char *pPath, const char *pMode, FILE *pStream) { #include #endif #define MZ_FILE FILE -#define MZ_FOPEN(f, m) fopen(f, m) +#define MZ_FOPEN(f, m) mz_fopen #define MZ_FCLOSE fclose #define MZ_FREAD fread #define MZ_FWRITE fwrite @@ -4153,7 +4172,7 @@ static FILE *mz_freopen(const char *pPath, const char *pMode, FILE *pStream) { #define MZ_FILE_STAT_STRUCT _stat #define MZ_FILE_STAT _stat #define MZ_FFLUSH fflush -#define MZ_FREOPEN(f, m, s) freopen(f, m, s) +#define MZ_FREOPEN(f, m, s) mz_freopen #define MZ_DELETE_FILE remove #elif defined(__TINYC__) #ifndef MINIZ_NO_TIME @@ -5361,13 +5380,9 @@ mz_bool mz_zip_reader_extract_to_mem_no_alloc(mz_zip_archive *pZip, } else { // Temporarily allocate a read buffer. read_buf_size = MZ_MIN(file_stat.m_comp_size, MZ_ZIP_MAX_IO_BUF_SIZE); -#if defined(_MSC_VER) && !defined(__clang__) - if (((0, sizeof(size_t) == sizeof(mz_uint32))) && - (read_buf_size > 0x7FFFFFFF)) -#else if (((sizeof(size_t) == sizeof(mz_uint32))) && (read_buf_size > 0x7FFFFFFF)) -#endif return MZ_FALSE; + if (NULL == (pRead_buf = pZip->m_pAlloc(pZip->m_pAlloc_opaque, 1, (size_t)read_buf_size))) return MZ_FALSE; @@ -5454,11 +5469,7 @@ void *mz_zip_reader_extract_to_heap(mz_zip_archive *pZip, mz_uint file_index, uncomp_size = MZ_READ_LE32(p + MZ_ZIP_CDH_DECOMPRESSED_SIZE_OFS); alloc_size = (flags & MZ_ZIP_FLAG_COMPRESSED_DATA) ? comp_size : uncomp_size; -#if defined(_MSC_VER) && !defined(__clang__) - if (((0, sizeof(size_t) == sizeof(mz_uint32))) && (alloc_size > 0x7FFFFFFF)) -#else if (((sizeof(size_t) == sizeof(mz_uint32))) && (alloc_size > 0x7FFFFFFF)) -#endif return NULL; if (NULL == (pBuf = pZip->m_pAlloc(pZip->m_pAlloc_opaque, 1, (size_t)alloc_size))) @@ -5560,14 +5571,10 @@ mz_bool mz_zip_reader_extract_to_callback(mz_zip_archive *pZip, if ((flags & MZ_ZIP_FLAG_COMPRESSED_DATA) || (!file_stat.m_method)) { // The file is stored or the caller has requested the compressed data. if (pZip->m_pState->m_pMem) { -#if defined (_MSC_VER) && !defined(__clang__) - if (((0, sizeof(size_t) == sizeof(mz_uint32))) && - (file_stat.m_comp_size > 0xFFFFFFFF)) -#else if (((sizeof(size_t) == sizeof(mz_uint32))) && (file_stat.m_comp_size > 0xFFFFFFFF)) -#endif return MZ_FALSE; + if (pCallback(pOpaque, out_buf_ofs, pRead_buf, (size_t)file_stat.m_comp_size) != file_stat.m_comp_size) status = TINFL_STATUS_FAILED; @@ -6085,7 +6092,7 @@ mz_zip_writer_compute_padding_needed_for_file_alignment(mz_zip_archive *pZip) { if (!pZip->m_file_offset_alignment) return 0; n = (mz_uint32)(pZip->m_archive_size & (pZip->m_file_offset_alignment - 1)); - return (mz_uint)(pZip->m_file_offset_alignment - n) & + return (pZip->m_file_offset_alignment - n) & (pZip->m_file_offset_alignment - 1); } @@ -6289,7 +6296,10 @@ mz_bool mz_zip_writer_add_file(mz_zip_archive *pZip, const char *pArchive_name, mz_uint32 ext_attributes) { mz_uint uncomp_crc32 = MZ_CRC32_INIT, level, num_alignment_padding_bytes; mz_uint16 method = 0, dos_time = 0, dos_date = 0; +#ifndef MINIZ_NO_TIME time_t file_modified_time; +#endif + mz_uint64 local_dir_header_ofs, cur_archive_file_ofs, uncomp_size = 0, comp_size = 0; size_t archive_name_size; @@ -6326,10 +6336,12 @@ mz_bool mz_zip_writer_add_file(mz_zip_archive *pZip, const char *pArchive_name, comment_size + archive_name_size) > 0xFFFFFFFF)) return MZ_FALSE; +#ifndef MINIZ_NO_TIME memset(&file_modified_time, 0, sizeof(file_modified_time)); if (!mz_zip_get_file_modified_time(pSrc_filename, &file_modified_time)) return MZ_FALSE; mz_zip_time_t_to_dos_time(file_modified_time, &dos_time, &dos_date); +#endif pSrc_file = MZ_FOPEN(pSrc_filename, "rb"); if (!pSrc_file) @@ -6814,6 +6826,10 @@ void *mz_zip_extract_archive_file_to_heap(const char *pZip_filename, return p; } +#ifdef _MSC_VER +#pragma warning(pop) +#endif + #endif // #ifndef MINIZ_NO_STDIO #endif // #ifndef MINIZ_NO_ARCHIVE_WRITING_APIS diff --git a/contrib/zip/src/zip.c b/contrib/zip/src/zip.c index 83e8e2a41..1f7fa8b76 100644 --- a/contrib/zip/src/zip.c +++ b/contrib/zip/src/zip.c @@ -18,11 +18,6 @@ /* Win32, DOS, MSVC, MSVS */ #include -#ifdef _MSC_VER -#pragma warning(push) -#pragma warning(disable : 4706) -#endif // _MSC_VER - #define MKDIR(DIRNAME) _mkdir(DIRNAME) #define STRCLONE(STR) ((STR) ? _strdup(STR) : NULL) #define HAS_DEVICE(P) \ @@ -32,17 +27,29 @@ #else -#include // needed for symlink() on BSD -int symlink(const char *target, const char *linkpath); // needed on Linux +#include // needed for symlink() #define MKDIR(DIRNAME) mkdir(DIRNAME, 0755) #define STRCLONE(STR) ((STR) ? strdup(STR) : NULL) #endif +#ifdef __MINGW32__ +#include +#include +#endif + #include "miniz.h" #include "zip.h" +#ifdef _MSC_VER +#include +#pragma warning(disable : 4706) + +#define ftruncate(fd, sz) (-(_chsize_s((fd), (sz)) != 0)) +#define fileno _fileno +#endif + #ifndef HAS_DEVICE #define HAS_DEVICE(P) 0 #endif @@ -63,7 +70,84 @@ int symlink(const char *target, const char *linkpath); // needed on Linux } \ } while (0) -static const char *base_name(const char *name) { +struct zip_entry_t { + int index; + char *name; + mz_uint64 uncomp_size; + mz_uint64 comp_size; + mz_uint32 uncomp_crc32; + mz_uint64 offset; + mz_uint8 header[MZ_ZIP_LOCAL_DIR_HEADER_SIZE]; + mz_uint64 header_offset; + mz_uint16 method; + mz_zip_writer_add_state state; + tdefl_compressor comp; + mz_uint32 external_attr; + time_t m_time; +}; + +struct zip_t { + mz_zip_archive archive; + mz_uint level; + struct zip_entry_t entry; +}; + +enum zip_modify_t { + MZ_KEEP = 0, + MZ_DELETE = 1, + MZ_MOVE = 2, +}; + +struct zip_entry_mark_t { + int file_index; + enum zip_modify_t type; + mz_uint64 m_local_header_ofs; + mz_uint64 lf_length; +}; + +static const char *const zip_errlist[30] = { + NULL, + "not initialized\0", + "invalid entry name\0", + "entry not found\0", + "invalid zip mode\0", + "invalid compression level\0", + "no zip 64 support\0", + "memset error\0", + "cannot write data to entry\0", + "cannot initialize tdefl compressor\0", + "invalid index\0", + "header not found\0", + "cannot flush tdefl buffer\0", + "cannot write entry header\0", + "cannot create entry header\0", + "cannot write to central dir\0", + "cannot open file\0", + "invalid entry type\0", + "extracting data using no memory allocation\0", + "file not found\0", + "no permission\0", + "out of memory\0", + "invalid zip archive name\0", + "make dir error\0" + "symlink error\0" + "close archive error\0" + "capacity size too small\0", + "fseek error\0", + "fread error\0", + "fwrite error\0", +}; + +const char *zip_strerror(int errnum) { + errnum = -errnum; + if (errnum <= 0 || errnum >= 30) { + return NULL; + } + + return zip_errlist[errnum]; +} + +static const char *zip_basename(const char *name) { char const *p; char const *base = name += FILESYSTEM_PREFIX_LEN(name); int all_slashes = 1; @@ -82,7 +166,7 @@ static const char *base_name(const char *name) { return base; } -static int mkpath(char *path) { +static int zip_mkpath(char *path) { char *p; char npath[MAX_PATH + 1]; int len = 0; @@ -107,7 +191,7 @@ static int mkpath(char *path) { if (MKDIR(npath) == -1) { if (errno != EEXIST) { - return -1; + return ZIP_EMKDIR; } } } @@ -117,7 +201,7 @@ static int mkpath(char *path) { return 0; } -static char *strrpl(const char *str, size_t n, char oldchar, char newchar) { +static char *zip_strrpl(const char *str, size_t n, char oldchar, char newchar) { char c; size_t i; char *rpl = (char *)calloc((1 + n), sizeof(char)); @@ -136,27 +220,562 @@ static char *strrpl(const char *str, size_t n, char oldchar, char newchar) { return begin; } -struct zip_entry_t { - int index; - char *name; - mz_uint64 uncomp_size; - mz_uint64 comp_size; - mz_uint32 uncomp_crc32; - mz_uint64 offset; - mz_uint8 header[MZ_ZIP_LOCAL_DIR_HEADER_SIZE]; - mz_uint64 header_offset; - mz_uint16 method; - mz_zip_writer_add_state state; - tdefl_compressor comp; - mz_uint32 external_attr; - time_t m_time; -}; +static char *zip_name_normalize(char *name, char *const nname, size_t len) { + size_t offn = 0; + size_t offnn = 0, ncpy = 0; -struct zip_t { - mz_zip_archive archive; - mz_uint level; - struct zip_entry_t entry; -}; + if (name == NULL || nname == NULL || len <= 0) { + return NULL; + } + // skip trailing '/' + while (ISSLASH(*name)) + name++; + + for (; offn < len; offn++) { + if (ISSLASH(name[offn])) { + if (ncpy > 0 && strcmp(&nname[offnn], ".\0") && + strcmp(&nname[offnn], "..\0")) { + offnn += ncpy; + nname[offnn++] = name[offn]; // append '/' + } + ncpy = 0; + } else { + nname[offnn + ncpy] = name[offn]; + ncpy++; + } + } + + // at the end, extra check what we've already copied + if (ncpy == 0 || !strcmp(&nname[offnn], ".\0") || + !strcmp(&nname[offnn], "..\0")) { + nname[offnn] = 0; + } + return nname; +} + +static mz_bool zip_name_match(const char *name1, const char *name2) { + int len2 = (int) strlen(name2); + char *nname2 = zip_strrpl(name2, len2, '\\', '/'); + if (!nname2) { + return MZ_FALSE; + } + + mz_bool res = (strcmp(name1, nname2) == 0) ? MZ_TRUE : MZ_FALSE; + CLEANUP(nname2); + return res; +} + +static int zip_archive_truncate(mz_zip_archive *pzip) { + mz_zip_internal_state *pState = pzip->m_pState; + mz_uint64 file_size = pzip->m_archive_size; + if ((pzip->m_pWrite == mz_zip_heap_write_func) && (pState->m_pMem)) { + return 0; + } + if (pzip->m_zip_mode == MZ_ZIP_MODE_WRITING_HAS_BEEN_FINALIZED) { + if (pState->m_pFile) { + int fd = fileno(pState->m_pFile); + return ftruncate(fd, file_size); + } + } + return 0; +} + +static int zip_archive_extract(mz_zip_archive *zip_archive, const char *dir, + int (*on_extract)(const char *filename, + void *arg), + void *arg) { + int err = 0; + mz_uint i, n; + char path[MAX_PATH + 1]; + char symlink_to[MAX_PATH + 1]; + mz_zip_archive_file_stat info; + size_t dirlen = 0; + mz_uint32 xattr = 0; + + memset(path, 0, sizeof(path)); + memset(symlink_to, 0, sizeof(symlink_to)); + + dirlen = strlen(dir); + if (dirlen + 1 > MAX_PATH) { + return ZIP_EINVENTNAME; + } + + memset((void *)&info, 0, sizeof(mz_zip_archive_file_stat)); + +#if defined(_MSC_VER) + strcpy_s(path, MAX_PATH, dir); +#else + strcpy(path, dir); +#endif + + if (!ISSLASH(path[dirlen - 1])) { +#if defined(_WIN32) || defined(__WIN32__) + path[dirlen] = '\\'; +#else + path[dirlen] = '/'; +#endif + ++dirlen; + } + + // Get and print information about each file in the archive. + n = mz_zip_reader_get_num_files(zip_archive); + for (i = 0; i < n; ++i) { + if (!mz_zip_reader_file_stat(zip_archive, i, &info)) { + // Cannot get information about zip archive; + err = ZIP_ENOENT; + goto out; + } + + if (!zip_name_normalize(info.m_filename, info.m_filename, + strlen(info.m_filename))) { + // Cannot normalize file name; + err = ZIP_EINVENTNAME; + goto out; + } +#if defined(_MSC_VER) + strncpy_s(&path[dirlen], MAX_PATH - dirlen, info.m_filename, + MAX_PATH - dirlen); +#else + strncpy(&path[dirlen], info.m_filename, MAX_PATH - dirlen); +#endif + err = zip_mkpath(path); + if (err < 0) { + // Cannot make a path + goto out; + } + + if ((((info.m_version_made_by >> 8) == 3) || + ((info.m_version_made_by >> 8) == + 19)) // if zip is produced on Unix or macOS (3 and 19 from + // section 4.4.2.2 of zip standard) + && info.m_external_attr & + (0x20 << 24)) { // and has sym link attribute (0x80 is file, 0x40 + // is directory) +#if defined(_WIN32) || defined(__WIN32__) || defined(_MSC_VER) || \ + defined(__MINGW32__) +#else + if (info.m_uncomp_size > MAX_PATH || + !mz_zip_reader_extract_to_mem_no_alloc(zip_archive, i, symlink_to, + MAX_PATH, 0, NULL, 0)) { + err = ZIP_EMEMNOALLOC; + goto out; + } + symlink_to[info.m_uncomp_size] = '\0'; + if (symlink(symlink_to, path) != 0) { + err = ZIP_ESYMLINK; + goto out; + } +#endif + } else { + if (!mz_zip_reader_is_file_a_directory(zip_archive, i)) { + if (!mz_zip_reader_extract_to_file(zip_archive, i, path, 0)) { + // Cannot extract zip archive to file + err = ZIP_ENOFILE; + goto out; + } + } + +#if defined(_MSC_VER) + (void)xattr; // unused +#else + xattr = (info.m_external_attr >> 16) & 0xFFFF; + if (xattr > 0) { + if (chmod(path, (mode_t)xattr) < 0) { + err = ZIP_ENOPERM; + goto out; + } + } +#endif + } + + if (on_extract) { + if (on_extract(path, arg) < 0) { + goto out; + } + } + } + +out: + // Close the archive, freeing any resources it was using + if (!mz_zip_reader_end(zip_archive)) { + // Cannot end zip reader + err = ZIP_ECLSZIP; + } + return err; +} + +static inline void zip_archive_finalize(mz_zip_archive *pzip) { + mz_zip_writer_finalize_archive(pzip); + zip_archive_truncate(pzip); +} + +static int zip_entry_mark(struct zip_t *zip, + struct zip_entry_mark_t *entry_mark, int n, + char *const entries[], const size_t len) { + int err = 0; + if (!zip || !entry_mark || !entries) { + return ZIP_ENOINIT; + } + + mz_zip_archive_file_stat file_stat; + mz_uint64 d_pos = (mz_uint64) ~0; + for (int i = 0; i < n; ++i) { + err = zip_entry_openbyindex(zip, i); + if (err) { + return err; + } + + mz_bool name_matches = MZ_FALSE; + for (int j = 0; j < (const int)len; ++j) { + if (zip_name_match(zip->entry.name, entries[j])) { + name_matches = MZ_TRUE; + break; + } + } + if (name_matches) { + entry_mark[i].type = MZ_DELETE; + } else { + entry_mark[i].type = MZ_KEEP; + } + + if (!mz_zip_reader_file_stat(&zip->archive, i, &file_stat)) { + return ZIP_ENOENT; + } + + zip_entry_close(zip); + + entry_mark[i].m_local_header_ofs = file_stat.m_local_header_ofs; + entry_mark[i].file_index = -1; + entry_mark[i].lf_length = 0; + if ((entry_mark[i].type) == MZ_DELETE && + (d_pos > entry_mark[i].m_local_header_ofs)) { + d_pos = entry_mark[i].m_local_header_ofs; + } + } + for (int i = 0; i < n; ++i) { + if ((entry_mark[i].m_local_header_ofs > d_pos) && + (entry_mark[i].type != MZ_DELETE)) { + entry_mark[i].type = MZ_MOVE; + } + } + return err; +} + +static int zip_index_next(mz_uint64 *local_header_ofs_array, int cur_index) { + int new_index = 0; + for (int i = cur_index - 1; i >= 0; --i) { + if (local_header_ofs_array[cur_index] > local_header_ofs_array[i]) { + new_index = i + 1; + return new_index; + } + } + return new_index; +} + +static int zip_sort(mz_uint64 *local_header_ofs_array, int cur_index) { + int nxt_index = zip_index_next(local_header_ofs_array, cur_index); + + if (nxt_index != cur_index) { + mz_uint64 temp = local_header_ofs_array[cur_index]; + for (int i = cur_index; i > nxt_index; i--) { + local_header_ofs_array[i] = local_header_ofs_array[i - 1]; + } + local_header_ofs_array[nxt_index] = temp; + } + return nxt_index; +} + +static int zip_index_update(struct zip_entry_mark_t *entry_mark, int last_index, + int nxt_index) { + for (int j = 0; j < last_index; j++) { + if (entry_mark[j].file_index >= nxt_index) { + entry_mark[j].file_index += 1; + } + } + entry_mark[nxt_index].file_index = last_index; + return 0; +} + +static int zip_entry_finalize(struct zip_t *zip, + struct zip_entry_mark_t *entry_mark, + const int n) { + + mz_uint64 *local_header_ofs_array = (mz_uint64 *)calloc(n, sizeof(mz_uint64)); + if (!local_header_ofs_array) { + return ZIP_EOOMEM; + } + + for (int i = 0; i < n; ++i) { + local_header_ofs_array[i] = entry_mark[i].m_local_header_ofs; + int index = zip_sort(local_header_ofs_array, i); + + if (index != i) { + zip_index_update(entry_mark, i, index); + } + entry_mark[i].file_index = index; + } + + mz_uint64 *length = (mz_uint64 *)calloc(n, sizeof(mz_uint64)); + if (!length) { + CLEANUP(local_header_ofs_array); + return ZIP_EOOMEM; + } + for (int i = 0; i < n - 1; i++) { + length[i] = local_header_ofs_array[i + 1] - local_header_ofs_array[i]; + } + length[n - 1] = zip->archive.m_archive_size - local_header_ofs_array[n - 1]; + + for (int i = 0; i < n; i++) { + entry_mark[i].lf_length = length[entry_mark[i].file_index]; + } + + CLEANUP(length); + CLEANUP(local_header_ofs_array); + return 0; +} + +static int zip_entry_set(struct zip_t *zip, struct zip_entry_mark_t *entry_mark, + int n, char *const entries[], const size_t len) { + int err = 0; + + if ((err = zip_entry_mark(zip, entry_mark, n, entries, len)) < 0) { + return err; + } + if ((err = zip_entry_finalize(zip, entry_mark, n)) < 0) { + return err; + } + return 0; +} + +static mz_int64 zip_file_move(MZ_FILE *m_pFile, const mz_uint64 to, + const mz_uint64 from, const mz_uint64 length, + mz_uint8 *move_buf, + const mz_int64 capacity_size) { + if ((mz_int64)length > capacity_size) { + return ZIP_ECAPSIZE; + } + if (MZ_FSEEK64(m_pFile, from, SEEK_SET)) { + MZ_FCLOSE(m_pFile); + return ZIP_EFSEEK; + } + + if (fread(move_buf, 1, length, m_pFile) != length) { + MZ_FCLOSE(m_pFile); + return ZIP_EFREAD; + } + if (MZ_FSEEK64(m_pFile, to, SEEK_SET)) { + MZ_FCLOSE(m_pFile); + return ZIP_EFSEEK; + } + if (fwrite(move_buf, 1, length, m_pFile) != length) { + MZ_FCLOSE(m_pFile); + return ZIP_EFWRITE; + } + return (mz_int64)length; +} + +static mz_int64 zip_files_move(MZ_FILE *m_pFile, mz_uint64 writen_num, + mz_uint64 read_num, mz_uint64 length) { + int n = 0; + const mz_int64 page_size = 1 << 12; // 4K + mz_uint8 *move_buf = (mz_uint8 *)calloc(1, page_size); + if (move_buf == NULL) { + return ZIP_EOOMEM; + } + + mz_int64 moved_length = 0; + mz_int64 move_count = 0; + while ((mz_int64)length > 0) { + move_count = ((mz_int64)length >= page_size) ? page_size : (mz_int64)length; + n = (int) zip_file_move(m_pFile, writen_num, read_num, move_count, move_buf, + page_size); + if (n < 0) { + moved_length = n; + goto cleanup; + } + + if (n != move_count) { + goto cleanup; + } + + writen_num += move_count; + read_num += move_count; + length -= move_count; + moved_length += move_count; + } + +cleanup: + CLEANUP(move_buf); + return moved_length; +} + +static int zip_central_dir_move(mz_zip_internal_state *pState, int begin, + int end, int entry_num) { + if (begin == entry_num) { + return 0; + } + + mz_uint64 l_size = 0; + mz_uint64 r_size = 0; + mz_uint64 d_size = 0; + mz_uint8 *next = NULL; + mz_uint8 *deleted = &MZ_ZIP_ARRAY_ELEMENT( + &pState->m_central_dir, mz_uint8, + MZ_ZIP_ARRAY_ELEMENT(&pState->m_central_dir_offsets, mz_uint32, begin)); + l_size = (mz_uint32)(deleted - (mz_uint8 *)(pState->m_central_dir.m_p)); + if (end == entry_num) { + r_size = 0; + } else { + next = &MZ_ZIP_ARRAY_ELEMENT( + &pState->m_central_dir, mz_uint8, + MZ_ZIP_ARRAY_ELEMENT(&pState->m_central_dir_offsets, mz_uint32, end)); + r_size = pState->m_central_dir.m_size - + (mz_uint32)(next - (mz_uint8 *)(pState->m_central_dir.m_p)); + d_size = next - deleted; + } + + if (l_size == 0) { + memmove(pState->m_central_dir.m_p, next, r_size); + pState->m_central_dir.m_p = MZ_REALLOC(pState->m_central_dir.m_p, r_size); + for (int i = end; i < entry_num; i++) { + MZ_ZIP_ARRAY_ELEMENT(&pState->m_central_dir_offsets, mz_uint64, i) -= + d_size; + } + } + + if (l_size * r_size != 0) { + memmove(deleted, next, r_size); + for (int i = end; i < entry_num; i++) { + MZ_ZIP_ARRAY_ELEMENT(&pState->m_central_dir_offsets, mz_uint64, i) -= + d_size; + } + } + + pState->m_central_dir.m_size = l_size + r_size; + return 0; +} + +static int zip_central_dir_delete(mz_zip_internal_state *pState, + int *deleted_entry_index_array, + int entry_num) { + int i = 0; + int begin = 0; + int end = 0; + int d_num = 0; + while (i < entry_num) { + while ((!deleted_entry_index_array[i]) && (i < entry_num)) { + i++; + } + begin = i; + + while ((deleted_entry_index_array[i]) && (i < entry_num)) { + i++; + } + end = i; + zip_central_dir_move(pState, begin, end, entry_num); + } + + i = 0; + while (i < entry_num) { + while ((!deleted_entry_index_array[i]) && (i < entry_num)) { + i++; + } + begin = i; + if (begin == entry_num) { + break; + } + while ((deleted_entry_index_array[i]) && (i < entry_num)) { + i++; + } + end = i; + int k = 0; + for (int j = end; j < entry_num; j++) { + MZ_ZIP_ARRAY_ELEMENT(&pState->m_central_dir_offsets, mz_uint32, + begin + k) = + (mz_uint32)MZ_ZIP_ARRAY_ELEMENT(&pState->m_central_dir_offsets, + mz_uint32, j); + k++; + } + d_num += end - begin; + } + + pState->m_central_dir_offsets.m_size = + sizeof(mz_uint32) * (entry_num - d_num); + return 0; +} + +static int zip_entries_delete_mark(struct zip_t *zip, + struct zip_entry_mark_t *entry_mark, + int entry_num) { + mz_uint64 writen_num = 0; + mz_uint64 read_num = 0; + mz_uint64 deleted_length = 0; + mz_uint64 move_length = 0; + int i = 0; + int deleted_entry_num = 0; + int n = 0; + + mz_bool *deleted_entry_flag_array = + (mz_bool *)calloc(entry_num, sizeof(mz_bool)); + if (deleted_entry_flag_array == NULL) { + return ZIP_EOOMEM; + } + + mz_zip_internal_state *pState = zip->archive.m_pState; + zip->archive.m_zip_mode = MZ_ZIP_MODE_WRITING; + + if (MZ_FSEEK64(pState->m_pFile, 0, SEEK_SET)) { + CLEANUP(deleted_entry_flag_array); + return ZIP_ENOENT; + } + + while (i < entry_num) { + while ((entry_mark[i].type == MZ_KEEP) && (i < entry_num)) { + writen_num += entry_mark[i].lf_length; + read_num = writen_num; + i++; + } + + while ((entry_mark[i].type == MZ_DELETE) && (i < entry_num)) { + deleted_entry_flag_array[i] = MZ_TRUE; + read_num += entry_mark[i].lf_length; + deleted_length += entry_mark[i].lf_length; + i++; + deleted_entry_num++; + } + + while ((entry_mark[i].type == MZ_MOVE) && (i < entry_num)) { + move_length += entry_mark[i].lf_length; + mz_uint8 *p = &MZ_ZIP_ARRAY_ELEMENT( + &pState->m_central_dir, mz_uint8, + MZ_ZIP_ARRAY_ELEMENT(&pState->m_central_dir_offsets, mz_uint32, i)); + if (!p) { + CLEANUP(deleted_entry_flag_array); + return ZIP_ENOENT; + } + mz_uint32 offset = MZ_READ_LE32(p + MZ_ZIP_CDH_LOCAL_HEADER_OFS); + offset -= (mz_uint32)deleted_length; + MZ_WRITE_LE32(p + MZ_ZIP_CDH_LOCAL_HEADER_OFS, offset); + i++; + } + + n = (int) zip_files_move(pState->m_pFile, writen_num, read_num, move_length); + if (n != (mz_int64)move_length) { + CLEANUP(deleted_entry_flag_array); + return n; + } + writen_num += move_length; + read_num += move_length; + } + + zip->archive.m_archive_size -= deleted_length; + zip->archive.m_total_files = entry_num - deleted_entry_num; + + zip_central_dir_delete(pState, deleted_entry_flag_array, entry_num); + CLEANUP(deleted_entry_flag_array); + + return deleted_entry_num; +} struct zip_t *zip_open(const char *zipname, int level, char mode) { struct zip_t *zip = NULL; @@ -189,6 +808,7 @@ struct zip_t *zip_open(const char *zipname, int level, char mode) { case 'r': case 'a': + case 'd': if (!mz_zip_reader_init_file( &(zip->archive), zipname, zip->level | MZ_ZIP_FLAG_DO_NOT_SORT_CENTRAL_DIRECTORY)) { @@ -196,7 +816,7 @@ struct zip_t *zip_open(const char *zipname, int level, char mode) { // zip_archive reader goto cleanup; } - if (mode == 'a' && + if ((mode == 'a' || mode == 'd') && !mz_zip_writer_init_from_reader(&(zip->archive), zipname)) { mz_zip_reader_end(&(zip->archive)); goto cleanup; @@ -219,7 +839,7 @@ void zip_close(struct zip_t *zip) { // Always finalize, even if adding failed for some reason, so we have a // valid central directory. mz_zip_writer_finalize_archive(&(zip->archive)); - + zip_archive_truncate(&(zip->archive)); mz_zip_writer_end(&(zip->archive)); mz_zip_reader_end(&(zip->archive)); @@ -228,14 +848,9 @@ void zip_close(struct zip_t *zip) { } int zip_is64(struct zip_t *zip) { - if (!zip) { - // zip_t handler is not initialized - return -1; - } - - if (!zip->archive.m_pState) { - // zip state is not initialized - return -1; + if (!zip || !zip->archive.m_pState) { + // zip_t handler or zip state is not initialized + return ZIP_ENOINIT; } return (int)zip->archive.m_pState->m_zip64; @@ -246,14 +861,19 @@ int zip_entry_open(struct zip_t *zip, const char *entryname) { mz_zip_archive *pzip = NULL; mz_uint num_alignment_padding_bytes, level; mz_zip_archive_file_stat stats; + int err = 0; - if (!zip || !entryname) { - return -1; + if (!zip) { + return ZIP_ENOINIT; + } + + if (!entryname) { + return ZIP_EINVENTNAME; } entrylen = strlen(entryname); - if (entrylen < 1) { - return -1; + if (entrylen == 0) { + return ZIP_EINVENTNAME; } /* @@ -267,10 +887,13 @@ int zip_entry_open(struct zip_t *zip, const char *entryname) { and UNIX file systems etc. If input came from standard input, there is no file name field. */ - zip->entry.name = strrpl(entryname, entrylen, '\\', '/'); + if (zip->entry.name) { + CLEANUP(zip->entry.name); + } + zip->entry.name = zip_strrpl(entryname, entrylen, '\\', '/'); if (!zip->entry.name) { // Cannot parse zip entry name - return -1; + return ZIP_EINVENTNAME; } pzip = &(zip->archive); @@ -278,10 +901,12 @@ int zip_entry_open(struct zip_t *zip, const char *entryname) { zip->entry.index = mz_zip_reader_locate_file(pzip, zip->entry.name, NULL, 0); if (zip->entry.index < 0) { + err = ZIP_ENOENT; goto cleanup; } if (!mz_zip_reader_file_stat(pzip, (mz_uint)zip->entry.index, &stats)) { + err = ZIP_ENOENT; goto cleanup; } @@ -292,7 +917,9 @@ int zip_entry_open(struct zip_t *zip, const char *entryname) { zip->entry.header_offset = stats.m_local_header_ofs; zip->entry.method = stats.m_method; zip->entry.external_attr = stats.m_external_attr; +#ifndef MINIZ_NO_TIME zip->entry.m_time = stats.m_time; +#endif return 0; } @@ -318,11 +945,13 @@ int zip_entry_open(struct zip_t *zip, const char *entryname) { mz_zip_writer_compute_padding_needed_for_file_alignment(pzip); if (!pzip->m_pState || (pzip->m_zip_mode != MZ_ZIP_MODE_WRITING)) { - // Wrong zip mode + // Invalid zip mode + err = ZIP_EINVMODE; goto cleanup; } if (zip->level & MZ_ZIP_FLAG_COMPRESSED_DATA) { - // Wrong zip compression level + // Invalid zip compression level + err = ZIP_EINVLVL; goto cleanup; } // no zip64 support yet @@ -331,12 +960,14 @@ int zip_entry_open(struct zip_t *zip, const char *entryname) { MZ_ZIP_LOCAL_DIR_HEADER_SIZE + MZ_ZIP_CENTRAL_DIR_HEADER_SIZE + entrylen) > 0xFFFFFFFF)) { // No zip64 support yet + err = ZIP_ENOSUP64; goto cleanup; } if (!mz_zip_writer_write_zeros(pzip, zip->entry.offset, num_alignment_padding_bytes + sizeof(zip->entry.header))) { // Cannot memset zip entry header + err = ZIP_EMEMSET; goto cleanup; } @@ -350,6 +981,7 @@ int zip_entry_open(struct zip_t *zip, const char *entryname) { if (pzip->m_pWrite(pzip->m_pIO_opaque, zip->entry.offset, zip->entry.name, entrylen) != entrylen) { // Cannot write data to zip entry + err = ZIP_EWRTENT; goto cleanup; } @@ -366,6 +998,7 @@ int zip_entry_open(struct zip_t *zip, const char *entryname) { (int)level, -15, MZ_DEFAULT_STRATEGY)) != TDEFL_STATUS_OKAY) { // Cannot initialize the zip compressor + err = ZIP_ETDEFLINIT; goto cleanup; } } @@ -376,7 +1009,7 @@ int zip_entry_open(struct zip_t *zip, const char *entryname) { cleanup: CLEANUP(zip->entry.name); - return -1; + return err; } int zip_entry_openbyindex(struct zip_t *zip, int index) { @@ -388,28 +1021,26 @@ int zip_entry_openbyindex(struct zip_t *zip, int index) { if (!zip) { // zip_t handler is not initialized - return -1; + return ZIP_ENOINIT; } pZip = &(zip->archive); if (pZip->m_zip_mode != MZ_ZIP_MODE_READING) { // open by index requires readonly mode - return -1; + return ZIP_EINVMODE; } if (index < 0 || (mz_uint)index >= pZip->m_total_files) { // index out of range - return -1; + return ZIP_EINVIDX; } - if (!(pHeader = &MZ_ZIP_ARRAY_ELEMENT( &pZip->m_pState->m_central_dir, mz_uint8, MZ_ZIP_ARRAY_ELEMENT(&pZip->m_pState->m_central_dir_offsets, mz_uint32, index)))) { // cannot find header in central directory - return -1; + return ZIP_ENOHDR; } - namelen = MZ_READ_LE16(pHeader + MZ_ZIP_CDH_FILENAME_LEN_OFS); pFilename = (const char *)pHeader + MZ_ZIP_CENTRAL_DIR_HEADER_SIZE; @@ -424,14 +1055,17 @@ int zip_entry_openbyindex(struct zip_t *zip, int index) { and UNIX file systems etc. If input came from standard input, there is no file name field. */ - zip->entry.name = strrpl(pFilename, namelen, '\\', '/'); + if (zip->entry.name) { + CLEANUP(zip->entry.name); + } + zip->entry.name = zip_strrpl(pFilename, namelen, '\\', '/'); if (!zip->entry.name) { // local entry name is NULL - return -1; + return ZIP_EINVENTNAME; } if (!mz_zip_reader_file_stat(pZip, (mz_uint)index, &stats)) { - return -1; + return ZIP_ENOENT; } zip->entry.index = index; @@ -442,7 +1076,9 @@ int zip_entry_openbyindex(struct zip_t *zip, int index) { zip->entry.header_offset = stats.m_local_header_ofs; zip->entry.method = stats.m_method; zip->entry.external_attr = stats.m_external_attr; +#ifndef MINIZ_NO_TIME zip->entry.m_time = stats.m_time; +#endif return 0; } @@ -452,17 +1088,17 @@ int zip_entry_close(struct zip_t *zip) { mz_uint level; tdefl_status done; mz_uint16 entrylen; - mz_uint16 dos_time, dos_date; - int status = -1; + mz_uint16 dos_time = 0, dos_date = 0; + int err = 0; if (!zip) { // zip_t handler is not initialized + err = ZIP_ENOINIT; goto cleanup; } pzip = &(zip->archive); if (pzip->m_zip_mode == MZ_ZIP_MODE_READING) { - status = 0; goto cleanup; } @@ -471,6 +1107,7 @@ int zip_entry_close(struct zip_t *zip) { done = tdefl_compress_buffer(&(zip->entry.comp), "", 0, TDEFL_FINISH); if (done != TDEFL_STATUS_DONE && done != TDEFL_STATUS_OKAY) { // Cannot flush compressed buffer + err = ZIP_ETDEFLBUF; goto cleanup; } zip->entry.comp_size = zip->entry.state.m_comp_size; @@ -479,18 +1116,22 @@ int zip_entry_close(struct zip_t *zip) { } entrylen = (mz_uint16)strlen(zip->entry.name); - // no zip64 support yet if ((zip->entry.comp_size > 0xFFFFFFFF) || (zip->entry.offset > 0xFFFFFFFF)) { // No zip64 support, yet + err = ZIP_ENOSUP64; goto cleanup; } +#ifndef MINIZ_NO_TIME mz_zip_time_t_to_dos_time(zip->entry.m_time, &dos_time, &dos_date); +#endif + if (!mz_zip_writer_create_local_dir_header( pzip, zip->entry.header, entrylen, 0, zip->entry.uncomp_size, zip->entry.comp_size, zip->entry.uncomp_crc32, zip->entry.method, 0, dos_time, dos_date)) { // Cannot create zip entry header + err = ZIP_ECRTHDR; goto cleanup; } @@ -498,6 +1139,7 @@ int zip_entry_close(struct zip_t *zip) { zip->entry.header, sizeof(zip->entry.header)) != sizeof(zip->entry.header)) { // Cannot write zip entry header + err = ZIP_EWRTHDR; goto cleanup; } @@ -507,19 +1149,19 @@ int zip_entry_close(struct zip_t *zip) { zip->entry.method, 0, dos_time, dos_date, zip->entry.header_offset, zip->entry.external_attr)) { // Cannot write to zip central dir + err = ZIP_EWRTDIR; goto cleanup; } pzip->m_total_files++; pzip->m_archive_size = zip->entry.offset; - status = 0; cleanup: if (zip) { zip->entry.m_time = 0; CLEANUP(zip->entry.name); } - return status; + return err; } const char *zip_entry_name(struct zip_t *zip) { @@ -534,7 +1176,7 @@ const char *zip_entry_name(struct zip_t *zip) { int zip_entry_index(struct zip_t *zip) { if (!zip) { // zip_t handler is not initialized - return -1; + return ZIP_ENOINIT; } return zip->entry.index; @@ -543,12 +1185,12 @@ int zip_entry_index(struct zip_t *zip) { int zip_entry_isdir(struct zip_t *zip) { if (!zip) { // zip_t handler is not initialized - return -1; + return ZIP_ENOINIT; } if (zip->entry.index < 0) { // zip entry is not opened - return -1; + return ZIP_EINVIDX; } return (int)mz_zip_reader_is_file_a_directory(&zip->archive, @@ -570,7 +1212,7 @@ int zip_entry_write(struct zip_t *zip, const void *buf, size_t bufsize) { if (!zip) { // zip_t handler is not initialized - return -1; + return ZIP_ENOINIT; } pzip = &(zip->archive); @@ -584,7 +1226,7 @@ int zip_entry_write(struct zip_t *zip, const void *buf, size_t bufsize) { if ((pzip->m_pWrite(pzip->m_pIO_opaque, zip->entry.offset, buf, bufsize) != bufsize)) { // Cannot write buffer - return -1; + return ZIP_EWRTENT; } zip->entry.offset += bufsize; zip->entry.comp_size += bufsize; @@ -593,7 +1235,7 @@ int zip_entry_write(struct zip_t *zip, const void *buf, size_t bufsize) { TDEFL_NO_FLUSH); if (status != TDEFL_STATUS_DONE && status != TDEFL_STATUS_OKAY) { // Cannot compress buffer - return -1; + return ZIP_ETDEFLBUF; } } } @@ -602,7 +1244,7 @@ int zip_entry_write(struct zip_t *zip, const void *buf, size_t bufsize) { } int zip_entry_fwrite(struct zip_t *zip, const char *filename) { - int status = 0; + int err = 0; size_t n = 0; FILE *stream = NULL; mz_uint8 buf[MZ_ZIP_MAX_IO_BUF_SIZE]; @@ -610,14 +1252,14 @@ int zip_entry_fwrite(struct zip_t *zip, const char *filename) { if (!zip) { // zip_t handler is not initialized - return -1; + return ZIP_ENOINIT; } memset(buf, 0, MZ_ZIP_MAX_IO_BUF_SIZE); memset((void *)&file_stat, 0, sizeof(struct MZ_FILE_STAT_STRUCT)); if (MZ_FILE_STAT(filename, &file_stat) != 0) { // problem getting information - check errno - return -1; + return ZIP_ENOENT; } if ((file_stat.st_mode & 0200) == 0) { @@ -634,19 +1276,19 @@ int zip_entry_fwrite(struct zip_t *zip, const char *filename) { #endif { // Cannot open filename - return -1; + return ZIP_EOPNFILE; } while ((n = fread(buf, sizeof(mz_uint8), MZ_ZIP_MAX_IO_BUF_SIZE, stream)) > 0) { if (zip_entry_write(zip, buf, n) < 0) { - status = -1; + err = ZIP_EWRTENT; break; } } fclose(stream); - return status; + return err; } ssize_t zip_entry_read(struct zip_t *zip, void **buf, size_t *bufsize) { @@ -656,19 +1298,19 @@ ssize_t zip_entry_read(struct zip_t *zip, void **buf, size_t *bufsize) { if (!zip) { // zip_t handler is not initialized - return -1; + return ZIP_ENOINIT; } pzip = &(zip->archive); if (pzip->m_zip_mode != MZ_ZIP_MODE_READING || zip->entry.index < 0) { // the entry is not found or we do not have read access - return -1; + return ZIP_ENOENT; } idx = (mz_uint)zip->entry.index; if (mz_zip_reader_is_file_a_directory(pzip, idx)) { // the entry is a directory - return -1; + return ZIP_EINVENTTYPE; } *buf = mz_zip_reader_extract_to_heap(pzip, idx, &size, 0); @@ -683,18 +1325,18 @@ ssize_t zip_entry_noallocread(struct zip_t *zip, void *buf, size_t bufsize) { if (!zip) { // zip_t handler is not initialized - return -1; + return ZIP_ENOINIT; } pzip = &(zip->archive); if (pzip->m_zip_mode != MZ_ZIP_MODE_READING || zip->entry.index < 0) { // the entry is not found or we do not have read access - return -1; + return ZIP_ENOENT; } if (!mz_zip_reader_extract_to_mem_no_alloc(pzip, (mz_uint)zip->entry.index, buf, bufsize, 0, NULL, 0)) { - return -1; + return ZIP_EMEMNOALLOC; } return (ssize_t)zip->entry.uncomp_size; @@ -703,45 +1345,43 @@ ssize_t zip_entry_noallocread(struct zip_t *zip, void *buf, size_t bufsize) { int zip_entry_fread(struct zip_t *zip, const char *filename) { mz_zip_archive *pzip = NULL; mz_uint idx; -#if defined(_MSC_VER) -#else mz_uint32 xattr = 0; -#endif mz_zip_archive_file_stat info; if (!zip) { // zip_t handler is not initialized - return -1; + return ZIP_ENOINIT; } memset((void *)&info, 0, sizeof(mz_zip_archive_file_stat)); pzip = &(zip->archive); if (pzip->m_zip_mode != MZ_ZIP_MODE_READING || zip->entry.index < 0) { // the entry is not found or we do not have read access - return -1; + return ZIP_ENOENT; } idx = (mz_uint)zip->entry.index; if (mz_zip_reader_is_file_a_directory(pzip, idx)) { // the entry is a directory - return -1; + return ZIP_EINVENTTYPE; } if (!mz_zip_reader_extract_to_file(pzip, idx, filename, 0)) { - return -1; + return ZIP_ENOFILE; } #if defined(_MSC_VER) + (void)xattr; // unused #else if (!mz_zip_reader_file_stat(pzip, idx, &info)) { // Cannot get information about zip archive; - return -1; + return ZIP_ENOFILE; } xattr = (info.m_external_attr >> 16) & 0xFFFF; if (xattr > 0) { if (chmod(filename, (mode_t)xattr) < 0) { - return -1; + return ZIP_ENOPERM; } } #endif @@ -758,32 +1398,147 @@ int zip_entry_extract(struct zip_t *zip, if (!zip) { // zip_t handler is not initialized - return -1; + return ZIP_ENOINIT; } pzip = &(zip->archive); if (pzip->m_zip_mode != MZ_ZIP_MODE_READING || zip->entry.index < 0) { // the entry is not found or we do not have read access - return -1; + return ZIP_ENOENT; } idx = (mz_uint)zip->entry.index; return (mz_zip_reader_extract_to_callback(pzip, idx, on_extract, arg, 0)) ? 0 - : -1; + : ZIP_EINVIDX; } -int zip_total_entries(struct zip_t *zip) { +int zip_entries_total(struct zip_t *zip) { if (!zip) { // zip_t handler is not initialized - return -1; + return ZIP_ENOINIT; } return (int)zip->archive.m_total_files; } +int zip_entries_delete(struct zip_t *zip, char *const entries[], + const size_t len) { + int n = 0; + int err = 0; + struct zip_entry_mark_t *entry_mark = NULL; + + if (zip == NULL || (entries == NULL && len != 0)) { + return ZIP_ENOINIT; + } + + if (entries == NULL && len == 0) { + return 0; + } + + n = zip_entries_total(zip); + + entry_mark = + (struct zip_entry_mark_t *)calloc(n, sizeof(struct zip_entry_mark_t)); + if (!entry_mark) { + return ZIP_EOOMEM; + } + + zip->archive.m_zip_mode = MZ_ZIP_MODE_READING; + + err = zip_entry_set(zip, entry_mark, n, entries, len); + if (err < 0) { + CLEANUP(entry_mark); + return err; + } + + err = zip_entries_delete_mark(zip, entry_mark, n); + CLEANUP(entry_mark); + return err; +} + +int zip_stream_extract(const char *stream, size_t size, const char *dir, + int (*on_extract)(const char *filename, void *arg), + void *arg) { + mz_zip_archive zip_archive; + if (!stream || !dir) { + // Cannot parse zip archive stream + return ZIP_ENOINIT; + } + if (!memset(&zip_archive, 0, sizeof(mz_zip_archive))) { + // Cannot memset zip archive + return ZIP_EMEMSET; + } + if (!mz_zip_reader_init_mem(&zip_archive, stream, size, 0)) { + // Cannot initialize zip_archive reader + return ZIP_ENOINIT; + } + + return zip_archive_extract(&zip_archive, dir, on_extract, arg); +} + +struct zip_t *zip_stream_open(const char *stream, size_t size, int level, + char mode) { + struct zip_t *zip = (struct zip_t *)calloc((size_t)1, sizeof(struct zip_t)); + if (!zip) { + return NULL; + } + + if (level < 0) { + level = MZ_DEFAULT_LEVEL; + } + if ((level & 0xF) > MZ_UBER_COMPRESSION) { + // Wrong compression level + goto cleanup; + } + zip->level = (mz_uint)level; + + if ((stream != NULL) && (size > 0) && (mode == 'r')) { + if (!mz_zip_reader_init_mem(&(zip->archive), stream, size, 0)) { + goto cleanup; + } + } else if ((stream == NULL) && (size == 0) && (mode == 'w')) { + // Create a new archive. + if (!mz_zip_writer_init_heap(&(zip->archive), 0, 1024)) { + // Cannot initialize zip_archive writer + goto cleanup; + } + } else { + goto cleanup; + } + return zip; + +cleanup: + CLEANUP(zip); + return NULL; +} + +ssize_t zip_stream_copy(struct zip_t *zip, void **buf, ssize_t *bufsize) { + if (!zip) { + return ZIP_ENOINIT; + } + + zip_archive_finalize(&(zip->archive)); + + if (bufsize != NULL) { + *bufsize = zip->archive.m_archive_size; + } + *buf = calloc(sizeof(unsigned char), zip->archive.m_archive_size); + memcpy(*buf, zip->archive.m_pState->m_pMem, zip->archive.m_archive_size); + + return zip->archive.m_archive_size; +} + +void zip_stream_close(struct zip_t *zip) { + if (zip) { + mz_zip_writer_end(&(zip->archive)); + mz_zip_reader_end(&(zip->archive)); + CLEANUP(zip); + } +} + int zip_create(const char *zipname, const char *filenames[], size_t len) { - int status = 0; + int err = 0; size_t i; mz_zip_archive zip_archive; struct MZ_FILE_STAT_STRUCT file_stat; @@ -791,32 +1546,34 @@ int zip_create(const char *zipname, const char *filenames[], size_t len) { if (!zipname || strlen(zipname) < 1) { // zip_t archive name is empty or NULL - return -1; + return ZIP_EINVZIPNAME; } // Create a new archive. if (!memset(&(zip_archive), 0, sizeof(zip_archive))) { // Cannot memset zip archive - return -1; + return ZIP_EMEMSET; } if (!mz_zip_writer_init_file(&zip_archive, zipname, 0)) { // Cannot initialize zip_archive writer - return -1; + return ZIP_ENOINIT; } - memset((void *)&file_stat, 0, sizeof(struct MZ_FILE_STAT_STRUCT)); + if (!memset((void *)&file_stat, 0, sizeof(struct MZ_FILE_STAT_STRUCT))) { + return ZIP_EMEMSET; + } for (i = 0; i < len; ++i) { const char *name = filenames[i]; if (!name) { - status = -1; + err = ZIP_EINVENTNAME; break; } if (MZ_FILE_STAT(name, &file_stat) != 0) { // problem getting information - check errno - status = -1; + err = ZIP_ENOFILE; break; } @@ -826,150 +1583,39 @@ int zip_create(const char *zipname, const char *filenames[], size_t len) { } ext_attributes |= (mz_uint32)((file_stat.st_mode & 0xFFFF) << 16); - if (!mz_zip_writer_add_file(&zip_archive, base_name(name), name, "", 0, + if (!mz_zip_writer_add_file(&zip_archive, zip_basename(name), name, "", 0, ZIP_DEFAULT_COMPRESSION_LEVEL, ext_attributes)) { // Cannot add file to zip_archive - status = -1; + err = ZIP_ENOFILE; break; } } mz_zip_writer_finalize_archive(&zip_archive); mz_zip_writer_end(&zip_archive); - return status; + return err; } int zip_extract(const char *zipname, const char *dir, int (*on_extract)(const char *filename, void *arg), void *arg) { - int status = -1; - mz_uint i, n; - char path[MAX_PATH + 1]; - char symlink_to[MAX_PATH + 1]; mz_zip_archive zip_archive; - mz_zip_archive_file_stat info; - size_t dirlen = 0; -#if defined(_MSC_VER) -#else - mz_uint32 xattr = 0; -#endif - - - memset(path, 0, sizeof(path)); - memset(symlink_to, 0, sizeof(symlink_to)); - if (!memset(&(zip_archive), 0, sizeof(zip_archive))) { - // Cannot memset zip archive - return -1; - } if (!zipname || !dir) { // Cannot parse zip archive name - return -1; + return ZIP_EINVZIPNAME; } - dirlen = strlen(dir); - if (dirlen + 1 > MAX_PATH) { - return -1; + if (!memset(&zip_archive, 0, sizeof(mz_zip_archive))) { + // Cannot memset zip archive + return ZIP_EMEMSET; } // Now try to open the archive. if (!mz_zip_reader_init_file(&zip_archive, zipname, 0)) { // Cannot initialize zip_archive reader - return -1; + return ZIP_ENOINIT; } - memset((void *)&info, 0, sizeof(mz_zip_archive_file_stat)); - -#if defined(_MSC_VER) - strcpy_s(path, MAX_PATH, dir); -#else - strcpy(path, dir); -#endif - - if (!ISSLASH(path[dirlen - 1])) { -#if defined(_WIN32) || defined(__WIN32__) - path[dirlen] = '\\'; -#else - path[dirlen] = '/'; -#endif - ++dirlen; - } - - // Get and print information about each file in the archive. - n = mz_zip_reader_get_num_files(&zip_archive); - for (i = 0; i < n; ++i) { - if (!mz_zip_reader_file_stat(&zip_archive, i, &info)) { - // Cannot get information about zip archive; - goto out; - } -#if defined(_MSC_VER) - strncpy_s(&path[dirlen], MAX_PATH - dirlen, info.m_filename, - MAX_PATH - dirlen); -#else - strncpy(&path[dirlen], info.m_filename, MAX_PATH - dirlen); -#endif - if (mkpath(path) < 0) { - // Cannot make a path - goto out; - } - - if ((((info.m_version_made_by >> 8) == 3) || - ((info.m_version_made_by >> 8) == - 19)) // if zip is produced on Unix or macOS (3 and 19 from - // section 4.4.2.2 of zip standard) - && info.m_external_attr & - (0x20 << 24)) { // and has sym link attribute (0x80 is file, 0x40 - // is directory) -#if defined(_WIN32) || defined(__WIN32__) || defined(_MSC_VER) || \ - defined(__MINGW32__) -#else - if (info.m_uncomp_size > MAX_PATH || - !mz_zip_reader_extract_to_mem_no_alloc(&zip_archive, i, symlink_to, - MAX_PATH, 0, NULL, 0)) { - goto out; - } - symlink_to[info.m_uncomp_size] = '\0'; - if (symlink(symlink_to, path) != 0) { - goto out; - } -#endif - } else { - if (!mz_zip_reader_is_file_a_directory(&zip_archive, i)) { - if (!mz_zip_reader_extract_to_file(&zip_archive, i, path, 0)) { - // Cannot extract zip archive to file - goto out; - } - } - -#if defined(_MSC_VER) -#else - xattr = (info.m_external_attr >> 16) & 0xFFFF; - if (xattr > 0) { - if (chmod(path, (mode_t)xattr) < 0) { - goto out; - } - } -#endif - } - - if (on_extract) { - if (on_extract(path, arg) < 0) { - goto out; - } - } - } - status = 0; - -out: - // Close the archive, freeing any resources it was using - if (!mz_zip_reader_end(&zip_archive)) { - // Cannot end zip reader - status = -1; - } - - return status; + return zip_archive_extract(&zip_archive, dir, on_extract, arg); } - -#ifdef _MSC_VER -#pragma warning(pop) -#endif // _MSC_VER diff --git a/contrib/zip/src/zip.h b/contrib/zip/src/zip.h index 87f3654f4..70ab2cee6 100644 --- a/contrib/zip/src/zip.h +++ b/contrib/zip/src/zip.h @@ -15,19 +15,11 @@ #include #include -#ifdef _MSC_VER -#pragma warning(push) -#pragma warning(disable : 4127 ) -#endif //_MSC_VER - #ifdef __cplusplus extern "C" { #endif -#if !defined(_SSIZE_T_DEFINED) && !defined(_SSIZE_T_DEFINED_) && \ - !defined(__DEFINED_ssize_t) && !defined(__ssize_t_defined) && \ - !defined(_SSIZE_T) && !defined(_SSIZE_T_) && !defined(_SSIZE_T_DECLARED) - +#if !defined(_POSIX_C_SOURCE) && defined(_MSC_VER) // 64-bit Windows is the only mainstream platform // where sizeof(long) != sizeof(void*) #ifdef _WIN64 @@ -35,15 +27,6 @@ typedef long long ssize_t; /* byte count or error */ #else typedef long ssize_t; /* byte count or error */ #endif - -#define _SSIZE_T_DEFINED -#define _SSIZE_T_DEFINED_ -#define __DEFINED_ssize_t -#define __ssize_t_defined -#define _SSIZE_T -#define _SSIZE_T_ -#define _SSIZE_T_DECLARED - #endif #ifndef MAX_PATH @@ -64,9 +47,49 @@ typedef long ssize_t; /* byte count or error */ /** * Default zip compression level. */ - #define ZIP_DEFAULT_COMPRESSION_LEVEL 6 +/** + * Error codes + */ +#define ZIP_ENOINIT -1 // not initialized +#define ZIP_EINVENTNAME -2 // invalid entry name +#define ZIP_ENOENT -3 // entry not found +#define ZIP_EINVMODE -4 // invalid zip mode +#define ZIP_EINVLVL -5 // invalid compression level +#define ZIP_ENOSUP64 -6 // no zip 64 support +#define ZIP_EMEMSET -7 // memset error +#define ZIP_EWRTENT -8 // cannot write data to entry +#define ZIP_ETDEFLINIT -9 // cannot initialize tdefl compressor +#define ZIP_EINVIDX -10 // invalid index +#define ZIP_ENOHDR -11 // header not found +#define ZIP_ETDEFLBUF -12 // cannot flush tdefl buffer +#define ZIP_ECRTHDR -13 // cannot create entry header +#define ZIP_EWRTHDR -14 // cannot write entry header +#define ZIP_EWRTDIR -15 // cannot write to central dir +#define ZIP_EOPNFILE -16 // cannot open file +#define ZIP_EINVENTTYPE -17 // invalid entry type +#define ZIP_EMEMNOALLOC -18 // extracting data using no memory allocation +#define ZIP_ENOFILE -19 // file not found +#define ZIP_ENOPERM -20 // no permission +#define ZIP_EOOMEM -21 // out of memory +#define ZIP_EINVZIPNAME -22 // invalid zip archive name +#define ZIP_EMKDIR -23 // make dir error +#define ZIP_ESYMLINK -24 // symlink error +#define ZIP_ECLSZIP -25 // close archive error +#define ZIP_ECAPSIZE -26 // capacity size too small +#define ZIP_EFSEEK -27 // fseek error +#define ZIP_EFREAD -28 // fread error +#define ZIP_EFWRITE -29 // fwrite error + +/** + * Looks up the error message string coresponding to an error number. + * @param errnum error number + * @return error message string coresponding to errnum or NULL if error is not + * found. + */ +extern const char *zip_strerror(int errnum); + /** * @struct zip_t * @@ -242,8 +265,8 @@ extern ssize_t zip_entry_read(struct zip_t *zip, void **buf, size_t *bufsize); * * @note ensure supplied output buffer is large enough. * zip_entry_size function (returns uncompressed size for the current - * entry) can be handy to estimate how big buffer is needed. for large - * entries, please take a look at zip_entry_extract function. + * entry) can be handy to estimate how big buffer is needed. + * For large entries, please take a look at zip_entry_extract function. * * @return the return code - the number of bytes actually read on success. * Otherwise a -1 on error (e.g. bufsize is not large enough). @@ -285,7 +308,71 @@ zip_entry_extract(struct zip_t *zip, * @return the return code - the number of entries on success, negative number * (< 0) on error. */ -extern int zip_total_entries(struct zip_t *zip); +extern int zip_entries_total(struct zip_t *zip); + +/** + * Deletes zip archive entries. + * + * @param zip zip archive handler. + * @param entries array of zip archive entries to be deleted. + * @param len the number of entries to be deleted. + * @return the number of deleted entries, or negative number (< 0) on error. + */ +extern int zip_entries_delete(struct zip_t *zip, char *const entries[], + size_t len); + +/** + * Extracts a zip archive stream into directory. + * + * If on_extract is not NULL, the callback will be called after + * successfully extracted each zip entry. + * Returning a negative value from the callback will cause abort and return an + * error. The last argument (void *arg) is optional, which you can use to pass + * data to the on_extract callback. + * + * @param stream zip archive stream. + * @param size stream size. + * @param dir output directory. + * @param on_extract on extract callback. + * @param arg opaque pointer. + * + * @return the return code - 0 on success, negative number (< 0) on error. + */ +extern int zip_stream_extract(const char *stream, size_t size, const char *dir, + int (*on_extract)(const char *filename, + void *arg), + void *arg); + +/** + * Opens zip archive stream into memory. + * + * @param stream zip archive stream. + * @param size stream size. + * + * @return the zip archive handler or NULL on error + */ +extern struct zip_t *zip_stream_open(const char *stream, size_t size, int level, + char mode); + +/** + * Copy zip archive stream output buffer. + * + * @param zip zip archive handler. + * @param buf output buffer. User should free buf. + * @param bufsize output buffer size (in bytes). + * + * @return copy size + */ +extern ssize_t zip_stream_copy(struct zip_t *zip, void **buf, ssize_t *bufsize); + +/** + * Close zip archive releases resources. + * + * @param zip zip archive handler. + * + * @return + */ +extern void zip_stream_close(struct zip_t *zip); /** * Creates a new archive and puts files into a single zip archive. @@ -319,11 +406,6 @@ extern int zip_extract(const char *zipname, const char *dir, void *arg); /** @} */ - -#ifdef _MSC_VER -#pragma warning(pop) -#endif //_MSC_VER - #ifdef __cplusplus } #endif diff --git a/contrib/zip/test/CMakeLists.txt b/contrib/zip/test/CMakeLists.txt index a7c3650f7..0da1684d4 100644 --- a/contrib/zip/test/CMakeLists.txt +++ b/contrib/zip/test/CMakeLists.txt @@ -1,11 +1,38 @@ -cmake_minimum_required(VERSION 3.10) +cmake_minimum_required(VERSION 3.4) -# test -set(test_out test.out) +# tests +set(test_write_out test_write.out) +add_executable(${test_write_out} test_write.c) +target_link_libraries(${test_write_out} zip) +add_test(NAME ${test_write_out} COMMAND ${test_write_out}) +set(test_write_out ${test_write_out} PARENT_SCOPE) -add_executable(${test_out} test.c) -target_link_libraries(${test_out} zip) +set(test_append_out test_append.out) +add_executable(${test_append_out} test_append.c) +target_link_libraries(${test_append_out} zip) +add_test(NAME ${test_append_out} COMMAND ${test_append_out}) +set(test_append_out ${test_append_out} PARENT_SCOPE) -add_test(NAME ${test_out} COMMAND ${test_out}) +set(test_read_out test_read.out) +add_executable(${test_read_out} test_read.c) +target_link_libraries(${test_read_out} zip) +add_test(NAME ${test_read_out} COMMAND ${test_read_out}) +set(test_read_out ${test_read_out} PARENT_SCOPE) -set(test_out ${test_out} PARENT_SCOPE) +set(test_extract_out test_extract.out) +add_executable(${test_extract_out} test_extract.c) +target_link_libraries(${test_extract_out} zip) +add_test(NAME ${test_extract_out} COMMAND ${test_extract_out}) +set(test_extract_out ${test_extract_out} PARENT_SCOPE) + +set(test_entry_out test_entry.out) +add_executable(${test_entry_out} test_entry.c) +target_link_libraries(${test_entry_out} zip) +add_test(NAME ${test_entry_out} COMMAND ${test_entry_out}) +set(test_entry_out ${test_entry_out} PARENT_SCOPE) + +set(test_permissions_out test_permissions.out) +add_executable(${test_permissions_out} test_permissions.c) +target_link_libraries(${test_permissions_out} zip) +add_test(NAME ${test_permissions_out} COMMAND ${test_permissions_out}) +set(test_permissions_out ${test_permissions_out} PARENT_SCOPE)