Merge branch 'master' into kimkulling/add_windows_clang_issue-5519
commit
f499d947ff
|
@ -0,0 +1,51 @@
|
|||
name: Build Windows Installer
|
||||
on:
|
||||
push:
|
||||
branches: [ master ]
|
||||
pull_request:
|
||||
branches: [ master ]
|
||||
jobs:
|
||||
build:
|
||||
name: Build the Inno Setup Installer
|
||||
runs-on: windows-latest
|
||||
steps:
|
||||
- uses: actions/checkout@v4
|
||||
- uses: lukka/get-cmake@latest
|
||||
- uses: ilammy/msvc-dev-cmd@v1
|
||||
|
||||
|
||||
- name: Cache DX SDK
|
||||
id: dxcache
|
||||
uses: actions/cache@v4
|
||||
with:
|
||||
path: '${{ github.workspace }}/DX_SDK'
|
||||
key: ${{ runner.os }}-DX_SDK
|
||||
restore-keys: |
|
||||
${{ runner.os }}-DX_SDK
|
||||
|
||||
- name: Download DXSetup
|
||||
run: |
|
||||
curl -s -o DXSDK_Jun10.exe --location https://download.microsoft.com/download/A/E/7/AE743F1F-632B-4809-87A9-AA1BB3458E31/DXSDK_Jun10.exe
|
||||
cmd.exe /c start /wait .\DXSDK_Jun10.exe /U /O /F /S /P "${{ github.workspace }}\DX_SDK"
|
||||
|
||||
- name: Set Windows specific CMake arguments
|
||||
id: windows_extra_cmake_args
|
||||
run: echo "::set-output name=args::-DASSIMP_BUILD_ASSIMP_TOOLS=1 -DASSIMP_BUILD_ASSIMP_VIEW=1 -DASSIMP_BUILD_ZLIB=1"
|
||||
|
||||
- name: configure and build
|
||||
uses: lukka/run-cmake@v3
|
||||
env:
|
||||
DXSDK_DIR: '${{ github.workspace }}/DX_SDK'
|
||||
|
||||
with:
|
||||
cmakeListsOrSettingsJson: CMakeListsTxtAdvanced
|
||||
cmakeListsTxtPath: '${{ github.workspace }}/CMakeLists.txt'
|
||||
cmakeAppendedArgs: '-GNinja -DCMAKE_BUILD_TYPE=Release ${{ steps.windows_extra_cmake_args.outputs.args }} ${{ steps.hunter_extra_cmake_args.outputs.args }}'
|
||||
buildWithCMakeArgs: '--parallel 24 -v'
|
||||
buildDirectory: '${{ github.workspace }}/build/'
|
||||
|
||||
- name: Compile .ISS to .EXE Installer
|
||||
uses: Minionguyjpro/Inno-Setup-Action@v1.2.2
|
||||
with:
|
||||
path: packaging/windows-innosetup/script_x64.iss
|
||||
options: /O+
|
|
@ -55,7 +55,7 @@ IF(ASSIMP_HUNTER_ENABLED)
|
|||
add_definitions(-DASSIMP_USE_HUNTER)
|
||||
ENDIF()
|
||||
|
||||
PROJECT(Assimp VERSION 5.4.0)
|
||||
PROJECT(Assimp VERSION 5.4.1)
|
||||
|
||||
# All supported options ###############################################
|
||||
|
||||
|
@ -761,8 +761,8 @@ IF ( ASSIMP_INSTALL )
|
|||
ENDIF()
|
||||
|
||||
CONFIGURE_FILE(
|
||||
${CMAKE_CURRENT_LIST_DIR}/revision.h.in
|
||||
${CMAKE_CURRENT_BINARY_DIR}/revision.h
|
||||
${CMAKE_CURRENT_LIST_DIR}/include/assimp/revision.h.in
|
||||
${CMAKE_CURRENT_BINARY_DIR}/include/assimp/revision.h
|
||||
)
|
||||
|
||||
CONFIGURE_FILE(
|
||||
|
|
|
@ -1,6 +1,6 @@
|
|||
FROM ubuntu:22.04
|
||||
|
||||
RUN apt-get update && apt-get install -y ninja-build \
|
||||
RUN apt-get update && apt-get install --no-install-recommends -y ninja-build \
|
||||
git cmake build-essential software-properties-common
|
||||
|
||||
RUN add-apt-repository ppa:ubuntu-toolchain-r/test && apt-get update
|
||||
|
|
|
@ -22,38 +22,9 @@
|
|||
# OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
|
||||
# OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
|
||||
# This is a gate file to Hunter package manager.
|
||||
# Include this file using `include` command and add package you need, example:
|
||||
#
|
||||
# cmake_minimum_required(VERSION 3.2)
|
||||
#
|
||||
# include("cmake/HunterGate.cmake")
|
||||
# HunterGate(
|
||||
# URL "https://github.com/path/to/hunter/archive.tar.gz"
|
||||
# SHA1 "798501e983f14b28b10cda16afa4de69eee1da1d"
|
||||
# )
|
||||
#
|
||||
# project(MyProject)
|
||||
#
|
||||
# hunter_add_package(Foo)
|
||||
# hunter_add_package(Boo COMPONENTS Bar Baz)
|
||||
#
|
||||
# Projects:
|
||||
# * https://github.com/hunter-packages/gate/
|
||||
# * https://github.com/ruslo/hunter
|
||||
|
||||
option(HUNTER_ENABLED "Enable Hunter package manager support" ON)
|
||||
|
||||
if(HUNTER_ENABLED)
|
||||
if(CMAKE_VERSION VERSION_LESS "3.2")
|
||||
message(
|
||||
FATAL_ERROR
|
||||
"At least CMake version 3.2 required for Hunter dependency management."
|
||||
" Update CMake or set HUNTER_ENABLED to OFF."
|
||||
)
|
||||
endif()
|
||||
endif()
|
||||
|
||||
include(CMakeParseArguments) # cmake_parse_arguments
|
||||
|
||||
option(HUNTER_STATUS_PRINT "Print working status" ON)
|
||||
|
|
|
@ -709,7 +709,7 @@ void Discreet3DSImporter::GenerateNodeGraph(aiScene *pcOut) {
|
|||
pcNode->mNumMeshes = 1;
|
||||
|
||||
// Build a name for the node
|
||||
pcNode->mName.length = ai_snprintf(pcNode->mName.data, MAXLEN, "3DSMesh_%u", i);
|
||||
pcNode->mName.length = ai_snprintf(pcNode->mName.data, AI_MAXLEN, "3DSMesh_%u", i);
|
||||
}
|
||||
|
||||
// Build dummy nodes for all cameras
|
||||
|
|
|
@ -57,8 +57,8 @@ static constexpr size_t ColRGBA_Len = 9;
|
|||
static constexpr size_t ColRGB_Len = 7;
|
||||
|
||||
// format of the color string: #RRGGBBAA or #RRGGBB (3MF Core chapter 5.1.1)
|
||||
bool validateColorString(const char *color) {
|
||||
const size_t len = strlen(color);
|
||||
bool validateColorString(const std::string color) {
|
||||
const size_t len = color.size();
|
||||
if (ColRGBA_Len != len && ColRGB_Len != len) {
|
||||
return false;
|
||||
}
|
||||
|
@ -157,8 +157,8 @@ aiMatrix4x4 parseTransformMatrix(const std::string& matrixStr) {
|
|||
return transformMatrix;
|
||||
}
|
||||
|
||||
bool parseColor(const char *color, aiColor4D &diffuse) {
|
||||
if (nullptr == color) {
|
||||
bool parseColor(const std::string &color, aiColor4D &diffuse) {
|
||||
if (color.empty()) {
|
||||
return false;
|
||||
}
|
||||
|
||||
|
@ -178,7 +178,7 @@ bool parseColor(const char *color, aiColor4D &diffuse) {
|
|||
|
||||
char b[3] = { color[5], color[6], '\0' };
|
||||
diffuse.b = static_cast<ai_real>(strtol(b, nullptr, 16)) / ai_real(255.0);
|
||||
const size_t len = strlen(color);
|
||||
const size_t len = color.size();
|
||||
if (ColRGB_Len == len) {
|
||||
return true;
|
||||
}
|
||||
|
|
|
@ -193,7 +193,7 @@ bool AC3DImporter::LoadObjectSection(std::vector<Object> &objects) {
|
|||
|
||||
// Generate a default name for both the light source and the node
|
||||
// FIXME - what's the right way to print a size_t? Is 'zu' universally available? stick with the safe version.
|
||||
light->mName.length = ::ai_snprintf(light->mName.data, MAXLEN, "ACLight_%i", static_cast<unsigned int>(mLights->size()) - 1);
|
||||
light->mName.length = ::ai_snprintf(light->mName.data, AI_MAXLEN, "ACLight_%i", static_cast<unsigned int>(mLights->size()) - 1);
|
||||
obj.name = std::string(light->mName.data);
|
||||
|
||||
ASSIMP_LOG_VERBOSE_DEBUG("AC3D: Light source encountered");
|
||||
|
@ -696,18 +696,18 @@ aiNode *AC3DImporter::ConvertObjectSection(Object &object,
|
|||
// generate a name depending on the type of the node
|
||||
switch (object.type) {
|
||||
case Object::Group:
|
||||
node->mName.length = ::ai_snprintf(node->mName.data, MAXLEN, "ACGroup_%i", mGroupsCounter++);
|
||||
node->mName.length = ::ai_snprintf(node->mName.data, AI_MAXLEN, "ACGroup_%i", mGroupsCounter++);
|
||||
break;
|
||||
case Object::Poly:
|
||||
node->mName.length = ::ai_snprintf(node->mName.data, MAXLEN, "ACPoly_%i", mPolysCounter++);
|
||||
node->mName.length = ::ai_snprintf(node->mName.data, AI_MAXLEN, "ACPoly_%i", mPolysCounter++);
|
||||
break;
|
||||
case Object::Light:
|
||||
node->mName.length = ::ai_snprintf(node->mName.data, MAXLEN, "ACLight_%i", mLightsCounter++);
|
||||
node->mName.length = ::ai_snprintf(node->mName.data, AI_MAXLEN, "ACLight_%i", mLightsCounter++);
|
||||
break;
|
||||
|
||||
// there shouldn't be more than one world, but we don't care
|
||||
case Object::World:
|
||||
node->mName.length = ::ai_snprintf(node->mName.data, MAXLEN, "ACWorld_%i", mWorldsCounter++);
|
||||
node->mName.length = ::ai_snprintf(node->mName.data, AI_MAXLEN, "ACWorld_%i", mWorldsCounter++);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -178,28 +178,6 @@ bool AMFImporter::XML_SearchNode(const std::string &nodeName) {
|
|||
return nullptr != mXmlParser->findNode(nodeName);
|
||||
}
|
||||
|
||||
void AMFImporter::ParseHelper_FixTruncatedFloatString(const char *pInStr, std::string &pOutString) {
|
||||
size_t instr_len;
|
||||
|
||||
pOutString.clear();
|
||||
instr_len = strlen(pInStr);
|
||||
if (!instr_len) return;
|
||||
|
||||
pOutString.reserve(instr_len * 3 / 2);
|
||||
// check and correct floats in format ".x". Must be "x.y".
|
||||
if (pInStr[0] == '.') pOutString.push_back('0');
|
||||
|
||||
pOutString.push_back(pInStr[0]);
|
||||
for (size_t ci = 1; ci < instr_len; ci++) {
|
||||
if ((pInStr[ci] == '.') && ((pInStr[ci - 1] == ' ') || (pInStr[ci - 1] == '-') || (pInStr[ci - 1] == '+') || (pInStr[ci - 1] == '\t'))) {
|
||||
pOutString.push_back('0');
|
||||
pOutString.push_back('.');
|
||||
} else {
|
||||
pOutString.push_back(pInStr[ci]);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
static bool ParseHelper_Decode_Base64_IsBase64(const char pChar) {
|
||||
return (isalnum((unsigned char)pChar) || (pChar == '+') || (pChar == '/'));
|
||||
}
|
||||
|
@ -213,7 +191,10 @@ void AMFImporter::ParseHelper_Decode_Base64(const std::string &pInputBase64, std
|
|||
uint8_t arr4[4], arr3[3];
|
||||
|
||||
// check input data
|
||||
if (pInputBase64.size() % 4) throw DeadlyImportError("Base64-encoded data must have size multiply of four.");
|
||||
if (pInputBase64.size() % 4) {
|
||||
throw DeadlyImportError("Base64-encoded data must have size multiply of four.");
|
||||
}
|
||||
|
||||
// prepare output place
|
||||
pOutputData.clear();
|
||||
pOutputData.reserve(pInputBase64.size() / 4 * 3);
|
||||
|
|
|
@ -168,7 +168,6 @@ public:
|
|||
AI_WONT_RETURN void Throw_ID_NotFound(const std::string &pID) const AI_WONT_RETURN_SUFFIX;
|
||||
void XML_CheckNode_MustHaveChildren(pugi::xml_node &node);
|
||||
bool XML_SearchNode(const std::string &nodeName);
|
||||
void ParseHelper_FixTruncatedFloatString(const char *pInStr, std::string &pOutString);
|
||||
AMFImporter(const AMFImporter &pScene) = delete;
|
||||
AMFImporter &operator=(const AMFImporter &pScene) = delete;
|
||||
|
||||
|
|
|
@ -56,7 +56,6 @@ OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
|||
#include <string>
|
||||
#include <vector>
|
||||
|
||||
/// \class CAMFImporter_NodeElement
|
||||
/// Base class for elements of nodes.
|
||||
class AMFNodeElementBase {
|
||||
public:
|
||||
|
@ -106,7 +105,6 @@ protected:
|
|||
}
|
||||
}; // class IAMFImporter_NodeElement
|
||||
|
||||
/// \struct CAMFImporter_NodeElement_Constellation
|
||||
/// A collection of objects or constellations with specific relative locations.
|
||||
struct AMFConstellation : public AMFNodeElementBase {
|
||||
/// Constructor.
|
||||
|
@ -116,7 +114,6 @@ struct AMFConstellation : public AMFNodeElementBase {
|
|||
|
||||
}; // struct CAMFImporter_NodeElement_Constellation
|
||||
|
||||
/// \struct CAMFImporter_NodeElement_Instance
|
||||
/// Part of constellation.
|
||||
struct AMFInstance : public AMFNodeElementBase {
|
||||
|
||||
|
@ -135,7 +132,6 @@ struct AMFInstance : public AMFNodeElementBase {
|
|||
AMFNodeElementBase(ENET_Instance, pParent) {}
|
||||
};
|
||||
|
||||
/// \struct CAMFImporter_NodeElement_Metadata
|
||||
/// Structure that define metadata node.
|
||||
struct AMFMetadata : public AMFNodeElementBase {
|
||||
|
||||
|
@ -148,7 +144,6 @@ struct AMFMetadata : public AMFNodeElementBase {
|
|||
AMFNodeElementBase(ENET_Metadata, pParent) {}
|
||||
};
|
||||
|
||||
/// \struct CAMFImporter_NodeElement_Root
|
||||
/// Structure that define root node.
|
||||
struct AMFRoot : public AMFNodeElementBase {
|
||||
|
||||
|
@ -161,7 +156,6 @@ struct AMFRoot : public AMFNodeElementBase {
|
|||
AMFNodeElementBase(ENET_Root, pParent) {}
|
||||
};
|
||||
|
||||
/// \struct CAMFImporter_NodeElement_Color
|
||||
/// Structure that define object node.
|
||||
struct AMFColor : public AMFNodeElementBase {
|
||||
bool Composed; ///< Type of color stored: if true then look for formula in \ref Color_Composed[4], else - in \ref Color.
|
||||
|
@ -177,7 +171,6 @@ struct AMFColor : public AMFNodeElementBase {
|
|||
}
|
||||
};
|
||||
|
||||
/// \struct CAMFImporter_NodeElement_Material
|
||||
/// Structure that define material node.
|
||||
struct AMFMaterial : public AMFNodeElementBase {
|
||||
|
||||
|
@ -187,7 +180,6 @@ struct AMFMaterial : public AMFNodeElementBase {
|
|||
AMFNodeElementBase(ENET_Material, pParent) {}
|
||||
};
|
||||
|
||||
/// \struct CAMFImporter_NodeElement_Object
|
||||
/// Structure that define object node.
|
||||
struct AMFObject : public AMFNodeElementBase {
|
||||
|
||||
|
@ -206,7 +198,6 @@ struct AMFMesh : public AMFNodeElementBase {
|
|||
AMFNodeElementBase(ENET_Mesh, pParent) {}
|
||||
};
|
||||
|
||||
/// \struct CAMFImporter_NodeElement_Vertex
|
||||
/// Structure that define vertex node.
|
||||
struct AMFVertex : public AMFNodeElementBase {
|
||||
/// Constructor.
|
||||
|
@ -215,7 +206,6 @@ struct AMFVertex : public AMFNodeElementBase {
|
|||
AMFNodeElementBase(ENET_Vertex, pParent) {}
|
||||
};
|
||||
|
||||
/// \struct CAMFImporter_NodeElement_Edge
|
||||
/// Structure that define edge node.
|
||||
struct AMFEdge : public AMFNodeElementBase {
|
||||
/// Constructor.
|
||||
|
@ -224,7 +214,6 @@ struct AMFEdge : public AMFNodeElementBase {
|
|||
AMFNodeElementBase(ENET_Edge, pParent) {}
|
||||
};
|
||||
|
||||
/// \struct CAMFImporter_NodeElement_Vertices
|
||||
/// Structure that define vertices node.
|
||||
struct AMFVertices : public AMFNodeElementBase {
|
||||
/// Constructor.
|
||||
|
@ -233,7 +222,6 @@ struct AMFVertices : public AMFNodeElementBase {
|
|||
AMFNodeElementBase(ENET_Vertices, pParent) {}
|
||||
};
|
||||
|
||||
/// \struct CAMFImporter_NodeElement_Volume
|
||||
/// Structure that define volume node.
|
||||
struct AMFVolume : public AMFNodeElementBase {
|
||||
std::string MaterialID; ///< Which material to use.
|
||||
|
@ -245,7 +233,6 @@ struct AMFVolume : public AMFNodeElementBase {
|
|||
AMFNodeElementBase(ENET_Volume, pParent) {}
|
||||
};
|
||||
|
||||
/// \struct CAMFImporter_NodeElement_Coordinates
|
||||
/// Structure that define coordinates node.
|
||||
struct AMFCoordinates : public AMFNodeElementBase {
|
||||
aiVector3D Coordinate; ///< Coordinate.
|
||||
|
@ -256,7 +243,6 @@ struct AMFCoordinates : public AMFNodeElementBase {
|
|||
AMFNodeElementBase(ENET_Coordinates, pParent) {}
|
||||
};
|
||||
|
||||
/// \struct CAMFImporter_NodeElement_TexMap
|
||||
/// Structure that define texture coordinates node.
|
||||
struct AMFTexMap : public AMFNodeElementBase {
|
||||
aiVector3D TextureCoordinate[3]; ///< Texture coordinates.
|
||||
|
@ -273,7 +259,6 @@ struct AMFTexMap : public AMFNodeElementBase {
|
|||
}
|
||||
};
|
||||
|
||||
/// \struct CAMFImporter_NodeElement_Triangle
|
||||
/// Structure that define triangle node.
|
||||
struct AMFTriangle : public AMFNodeElementBase {
|
||||
size_t V[3]; ///< Triangle vertices.
|
||||
|
|
|
@ -224,7 +224,8 @@ size_t AMFImporter::PostprocessHelper_GetTextureID_Or_Create(const std::string &
|
|||
}
|
||||
|
||||
// Create format hint.
|
||||
strcpy(converted_texture.FormatHint, "rgba0000"); // copy initial string.
|
||||
constexpr char templateColor[] = "rgba0000";
|
||||
memcpy(converted_texture.FormatHint, templateColor, 8);
|
||||
if (!r.empty()) converted_texture.FormatHint[4] = '8';
|
||||
if (!g.empty()) converted_texture.FormatHint[5] = '8';
|
||||
if (!b.empty()) converted_texture.FormatHint[6] = '8';
|
||||
|
@ -867,7 +868,7 @@ nl_clean_loop:
|
|||
pScene->mTextures[idx]->mHeight = static_cast<unsigned int>(tex_convd.Height);
|
||||
pScene->mTextures[idx]->pcData = (aiTexel *)tex_convd.Data;
|
||||
// texture format description.
|
||||
strcpy(pScene->mTextures[idx]->achFormatHint, tex_convd.FormatHint);
|
||||
strncpy(pScene->mTextures[idx]->achFormatHint, tex_convd.FormatHint, HINTMAXTEXTURELEN);
|
||||
idx++;
|
||||
} // for(const SPP_Texture& tex_convd: mTexture_Converted)
|
||||
|
||||
|
|
|
@ -124,7 +124,7 @@ void ASEImporter::InternReadFile(const std::string &pFile,
|
|||
// Allocate storage and copy the contents of the file to a memory buffer
|
||||
std::vector<char> mBuffer2;
|
||||
TextFileToBuffer(file.get(), mBuffer2);
|
||||
|
||||
const size_t fileSize = mBuffer2.size();
|
||||
this->mBuffer = &mBuffer2[0];
|
||||
this->pcScene = pScene;
|
||||
|
||||
|
@ -146,7 +146,7 @@ void ASEImporter::InternReadFile(const std::string &pFile,
|
|||
};
|
||||
|
||||
// Construct an ASE parser and parse the file
|
||||
ASE::Parser parser(mBuffer, defaultFormat);
|
||||
ASE::Parser parser(mBuffer, fileSize, defaultFormat);
|
||||
mParser = &parser;
|
||||
mParser->Parse();
|
||||
|
||||
|
@ -446,10 +446,9 @@ void ASEImporter::BuildLights() {
|
|||
}
|
||||
|
||||
// ------------------------------------------------------------------------------------------------
|
||||
void ASEImporter::AddNodes(const std::vector<BaseNode *> &nodes,
|
||||
aiNode *pcParent, const char *szName) {
|
||||
void ASEImporter::AddNodes(const std::vector<BaseNode *> &nodes, aiNode *pcParent, const std::string &name) {
|
||||
aiMatrix4x4 m;
|
||||
AddNodes(nodes, pcParent, szName, m);
|
||||
AddNodes(nodes, pcParent, name, m);
|
||||
}
|
||||
|
||||
// ------------------------------------------------------------------------------------------------
|
||||
|
@ -506,10 +505,9 @@ void ASEImporter::AddMeshes(const ASE::BaseNode *snode, aiNode *node) {
|
|||
|
||||
// ------------------------------------------------------------------------------------------------
|
||||
// Add child nodes to a given parent node
|
||||
void ASEImporter::AddNodes(const std::vector<BaseNode *> &nodes,
|
||||
aiNode *pcParent, const char *szName,
|
||||
void ASEImporter::AddNodes(const std::vector<BaseNode *> &nodes, aiNode *pcParent, const std::string &name,
|
||||
const aiMatrix4x4 &mat) {
|
||||
const size_t len = szName ? ::strlen(szName) : 0;
|
||||
const size_t len = name.size();
|
||||
ai_assert(4 <= AI_MAX_NUMBER_OF_COLOR_SETS);
|
||||
|
||||
// Receives child nodes for the pcParent node
|
||||
|
@ -519,16 +517,18 @@ void ASEImporter::AddNodes(const std::vector<BaseNode *> &nodes,
|
|||
// which has *us* as parent.
|
||||
for (std::vector<BaseNode *>::const_iterator it = nodes.begin(), end = nodes.end(); it != end; ++it) {
|
||||
const BaseNode *snode = *it;
|
||||
if (szName) {
|
||||
if (len != snode->mParent.length() || ::strcmp(szName, snode->mParent.c_str()))
|
||||
if (!name.empty()) {
|
||||
if (len != snode->mParent.length() || name != snode->mParent.c_str()) {
|
||||
continue;
|
||||
} else if (snode->mParent.length())
|
||||
}
|
||||
} else if (snode->mParent.length()) {
|
||||
continue;
|
||||
}
|
||||
|
||||
(*it)->mProcessed = true;
|
||||
|
||||
// Allocate a new node and add it to the output data structure
|
||||
apcNodes.push_back(new aiNode());
|
||||
apcNodes.push_back(new aiNode);
|
||||
aiNode *node = apcNodes.back();
|
||||
|
||||
node->mName.Set((snode->mName.length() ? snode->mName.c_str() : "Unnamed_Node"));
|
||||
|
@ -541,7 +541,7 @@ void ASEImporter::AddNodes(const std::vector<BaseNode *> &nodes,
|
|||
|
||||
// Add sub nodes - prevent stack overflow due to recursive parenting
|
||||
if (node->mName != node->mParent->mName && node->mName != node->mParent->mParent->mName) {
|
||||
AddNodes(nodes, node, node->mName.data, snode->mTransform);
|
||||
AddNodes(nodes, node, node->mName.C_Str(), snode->mTransform);
|
||||
}
|
||||
|
||||
// Further processing depends on the type of the node
|
||||
|
@ -619,7 +619,8 @@ void ASEImporter::BuildNodes(std::vector<BaseNode *> &nodes) {
|
|||
}
|
||||
|
||||
// add all nodes
|
||||
AddNodes(nodes, ch, nullptr);
|
||||
static const std::string none = "";
|
||||
AddNodes(nodes, ch, none);
|
||||
|
||||
// now iterate through al nodes and find those that have not yet
|
||||
// been added to the nodegraph (= their parent could not be recognized)
|
||||
|
|
|
@ -153,13 +153,13 @@ private:
|
|||
* \param matrix Current transform
|
||||
*/
|
||||
void AddNodes(const std::vector<ASE::BaseNode*>& nodes,
|
||||
aiNode* pcParent,const char* szName);
|
||||
aiNode* pcParent, const std::string &name);
|
||||
|
||||
void AddNodes(const std::vector<ASE::BaseNode*>& nodes,
|
||||
aiNode* pcParent,const char* szName,
|
||||
aiNode* pcParent, const std::string &name,
|
||||
const aiMatrix4x4& matrix);
|
||||
|
||||
void AddMeshes(const ASE::BaseNode* snode,aiNode* node);
|
||||
void AddMeshes(const ASE::BaseNode* snode, aiNode* node);
|
||||
|
||||
// -------------------------------------------------------------------
|
||||
/** Generate a default material and add it to the parser's list
|
||||
|
@ -188,5 +188,4 @@ protected:
|
|||
|
||||
} // end of namespace Assimp
|
||||
|
||||
|
||||
#endif // AI_3DSIMPORTER_H_INC
|
||||
|
|
File diff suppressed because it is too large
Load Diff
|
@ -391,11 +391,11 @@ public:
|
|||
// -------------------------------------------------------------------
|
||||
//! Construct a parser from a given input file which is
|
||||
//! guaranteed to be terminated with zero.
|
||||
//! @param szFile Input file
|
||||
//! @param file The name of the input file.
|
||||
//! @param fileFormatDefault Assumed file format version. If the
|
||||
//! file format is specified in the file the new value replaces
|
||||
//! the default value.
|
||||
Parser(const char *szFile, unsigned int fileFormatDefault);
|
||||
Parser(const char *file, size_t fileLen, unsigned int fileFormatDefault);
|
||||
|
||||
// -------------------------------------------------------------------
|
||||
//! Parses the file into the parsers internal representation
|
||||
|
@ -617,11 +617,8 @@ private:
|
|||
bool ParseString(std::string &out, const char *szName);
|
||||
|
||||
public:
|
||||
//! Pointer to current data
|
||||
const char *filePtr;
|
||||
|
||||
/// The end pointer of the file data
|
||||
const char *mEnd;
|
||||
const char *mFilePtr; ////< Pointer to current data
|
||||
const char *mEnd; ///< The end pointer of the file data
|
||||
|
||||
//! background color to be passed to the viewer
|
||||
//! QNAN if none was found
|
||||
|
|
|
@ -359,7 +359,7 @@ void BlenderImporter::ResolveImage(aiMaterial *out, const Material *mat, const M
|
|||
// check if the file contents are bundled with the BLEND file
|
||||
if (img->packedfile) {
|
||||
name.data[0] = '*';
|
||||
name.length = 1 + ASSIMP_itoa10(name.data + 1, static_cast<unsigned int>(MAXLEN - 1), static_cast<int32_t>(conv_data.textures->size()));
|
||||
name.length = 1 + ASSIMP_itoa10(name.data + 1, static_cast<unsigned int>(AI_MAXLEN - 1), static_cast<int32_t>(conv_data.textures->size()));
|
||||
|
||||
conv_data.textures->push_back(new aiTexture());
|
||||
aiTexture *curTex = conv_data.textures->back();
|
||||
|
@ -433,7 +433,7 @@ void BlenderImporter::AddSentinelTexture(aiMaterial *out, const Material *mat, c
|
|||
(void)conv_data;
|
||||
|
||||
aiString name;
|
||||
name.length = ai_snprintf(name.data, MAXLEN, "Procedural,num=%i,type=%s", conv_data.sentinel_cnt++,
|
||||
name.length = ai_snprintf(name.data, AI_MAXLEN, "Procedural,num=%i,type=%s", conv_data.sentinel_cnt++,
|
||||
GetTextureTypeDisplayString(tex->tex->type));
|
||||
out->AddProperty(&name, AI_MATKEY_TEXTURE_DIFFUSE(
|
||||
conv_data.next_texture[aiTextureType_DIFFUSE]++));
|
||||
|
|
|
@ -247,7 +247,9 @@ aiNode *ColladaLoader::BuildHierarchy(const ColladaParser &pParser, const Collad
|
|||
|
||||
// add children. first the *real* ones
|
||||
node->mNumChildren = static_cast<unsigned int>(pNode->mChildren.size() + instances.size());
|
||||
node->mChildren = new aiNode *[node->mNumChildren];
|
||||
if (node->mNumChildren != 0) {
|
||||
node->mChildren = new aiNode * [node->mNumChildren];
|
||||
}
|
||||
|
||||
for (size_t a = 0; a < pNode->mChildren.size(); ++a) {
|
||||
node->mChildren[a] = BuildHierarchy(pParser, pNode->mChildren[a]);
|
||||
|
|
|
@ -635,7 +635,8 @@ void ColladaParser::ReadController(XmlNode &node, Collada::Controller &controlle
|
|||
const std::string ¤tName = currentNode.name();
|
||||
if (currentName == "morph") {
|
||||
controller.mType = Morph;
|
||||
controller.mMeshId = currentNode.attribute("source").as_string();
|
||||
std::string id = currentNode.attribute("source").as_string();
|
||||
controller.mMeshId = id.substr(1, id.size() - 1);
|
||||
int methodIndex = currentNode.attribute("method").as_int();
|
||||
if (methodIndex > 0) {
|
||||
std::string method;
|
||||
|
@ -2292,9 +2293,9 @@ void ColladaParser::ReadNodeGeometry(XmlNode &node, Node *pNode) {
|
|||
urlMat++;
|
||||
|
||||
s.mMatName = urlMat;
|
||||
ReadMaterialVertexInputBinding(instanceMatNode, s);
|
||||
// store the association
|
||||
instance.mMaterials[group] = s;
|
||||
ReadMaterialVertexInputBinding(instanceMatNode, s);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1860,7 +1860,7 @@ aiString FBXConverter::GetTexturePath(const Texture *tex) {
|
|||
// We need to load all textures before referencing them, as FBX file format order may reference a texture before loading it
|
||||
// This may occur on this case too, it has to be studied
|
||||
path.data[0] = '*';
|
||||
path.length = 1 + ASSIMP_itoa10(path.data + 1, MAXLEN - 1, index);
|
||||
path.length = 1 + ASSIMP_itoa10(path.data + 1, AI_MAXLEN - 1, index);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -2440,7 +2440,7 @@ void FBXConverter::SetShadingPropertiesRaw(aiMaterial *out_mat, const PropertyTa
|
|||
|
||||
// setup texture reference string (copied from ColladaLoader::FindFilenameForEffectTexture)
|
||||
path.data[0] = '*';
|
||||
path.length = 1 + ASSIMP_itoa10(path.data + 1, MAXLEN - 1, index);
|
||||
path.length = 1 + ASSIMP_itoa10(path.data + 1, AI_MAXLEN - 1, index);
|
||||
}
|
||||
|
||||
out_mat->AddProperty(&path, (name + "|file").c_str(), aiTextureType_UNKNOWN, 0);
|
||||
|
@ -2806,7 +2806,7 @@ void FBXConverter::ProcessMorphAnimDatas(std::map<std::string, morphAnimData *>
|
|||
auto geoIt = std::find(model->GetGeometry().begin(), model->GetGeometry().end(), geo);
|
||||
auto geoIndex = static_cast<unsigned int>(std::distance(model->GetGeometry().begin(), geoIt));
|
||||
auto name = aiString(FixNodeName(model->Name() + "*"));
|
||||
name.length = 1 + ASSIMP_itoa10(name.data + name.length, MAXLEN - 1, geoIndex);
|
||||
name.length = 1 + ASSIMP_itoa10(name.data + name.length, AI_MAXLEN - 1, geoIndex);
|
||||
morphAnimData *animData;
|
||||
auto animIt = morphAnimDatas->find(name.C_Str());
|
||||
if (animIt == morphAnimDatas->end()) {
|
||||
|
|
|
@ -1051,7 +1051,7 @@ aiNode* get_node_for_mesh(unsigned int meshIndex, aiNode* node)
|
|||
aiMatrix4x4 get_world_transform(const aiNode* node, const aiScene* scene)
|
||||
{
|
||||
std::vector<const aiNode*> node_chain;
|
||||
while (node != scene->mRootNode) {
|
||||
while (node != scene->mRootNode && node != nullptr) {
|
||||
node_chain.push_back(node);
|
||||
node = node->mParent;
|
||||
}
|
||||
|
@ -1868,33 +1868,26 @@ void FBXExporter::WriteObjects ()
|
|||
// one sticky point is that the number of vertices may not match,
|
||||
// because assimp splits vertices by normal, uv, etc.
|
||||
|
||||
// functor for aiNode sorting
|
||||
struct SortNodeByName
|
||||
{
|
||||
bool operator()(const aiNode *lhs, const aiNode *rhs) const
|
||||
{
|
||||
return strcmp(lhs->mName.C_Str(), rhs->mName.C_Str()) < 0;
|
||||
}
|
||||
};
|
||||
|
||||
// first we should mark the skeleton for each mesh.
|
||||
// the skeleton must include not only the aiBones,
|
||||
// but also all their parent nodes.
|
||||
// anything that affects the position of any bone node must be included.
|
||||
// Use SorNodeByName to make sure the exported result will be the same across all systems
|
||||
// Otherwise the aiNodes of the skeleton would be sorted based on the pointer address, which isn't consistent
|
||||
std::vector<std::set<const aiNode*, SortNodeByName>> skeleton_by_mesh(mScene->mNumMeshes);
|
||||
|
||||
// note that we want to preserve input order as much as possible here.
|
||||
// previously, sorting by name lead to consistent output across systems, but was not
|
||||
// suitable for downstream consumption by some applications.
|
||||
std::vector<std::vector<const aiNode*>> skeleton_by_mesh(mScene->mNumMeshes);
|
||||
// at the same time we can build a list of all the skeleton nodes,
|
||||
// which will be used later to mark them as type "limbNode".
|
||||
std::unordered_set<const aiNode*> limbnodes;
|
||||
|
||||
//actual bone nodes in fbx, without parenting-up
|
||||
std::unordered_set<std::string> setAllBoneNamesInScene;
|
||||
for(unsigned int m = 0; m < mScene->mNumMeshes; ++ m)
|
||||
{
|
||||
std::vector<std::string> allBoneNames;
|
||||
for(unsigned int m = 0; m < mScene->mNumMeshes; ++ m) {
|
||||
aiMesh* pMesh = mScene->mMeshes[m];
|
||||
for(unsigned int b = 0; b < pMesh->mNumBones; ++ b)
|
||||
setAllBoneNamesInScene.insert(pMesh->mBones[b]->mName.data);
|
||||
allBoneNames.push_back(pMesh->mBones[b]->mName.data);
|
||||
}
|
||||
aiMatrix4x4 mxTransIdentity;
|
||||
|
||||
|
@ -1902,7 +1895,7 @@ void FBXExporter::WriteObjects ()
|
|||
std::map<std::string,aiNode*> node_by_bone;
|
||||
for (size_t mi = 0; mi < mScene->mNumMeshes; ++mi) {
|
||||
const aiMesh* m = mScene->mMeshes[mi];
|
||||
std::set<const aiNode*, SortNodeByName> skeleton;
|
||||
std::vector<const aiNode*> skeleton;
|
||||
for (size_t bi =0; bi < m->mNumBones; ++bi) {
|
||||
const aiBone* b = m->mBones[bi];
|
||||
const std::string name(b->mName.C_Str());
|
||||
|
@ -1921,7 +1914,7 @@ void FBXExporter::WriteObjects ()
|
|||
node_by_bone[name] = n;
|
||||
limbnodes.insert(n);
|
||||
}
|
||||
skeleton.insert(n);
|
||||
skeleton.push_back(n);
|
||||
// mark all parent nodes as skeleton as well,
|
||||
// up until we find the root node,
|
||||
// or else the node containing the mesh,
|
||||
|
@ -1932,7 +1925,7 @@ void FBXExporter::WriteObjects ()
|
|||
parent = parent->mParent
|
||||
) {
|
||||
// if we've already done this node we can skip it all
|
||||
if (skeleton.count(parent)) {
|
||||
if (std::find(skeleton.begin(), skeleton.end(), parent) != skeleton.end()) {
|
||||
break;
|
||||
}
|
||||
// ignore fbx transform nodes as these will be collapsed later
|
||||
|
@ -1942,7 +1935,7 @@ void FBXExporter::WriteObjects ()
|
|||
continue;
|
||||
}
|
||||
//not a bone in scene && no effect in transform
|
||||
if(setAllBoneNamesInScene.find(node_name)==setAllBoneNamesInScene.end()
|
||||
if (std::find(allBoneNames.begin(), allBoneNames.end(), node_name) == allBoneNames.end()
|
||||
&& parent->mTransformation == mxTransIdentity) {
|
||||
continue;
|
||||
}
|
||||
|
@ -2027,7 +2020,7 @@ void FBXExporter::WriteObjects ()
|
|||
aiMatrix4x4 mesh_xform = get_world_transform(mesh_node, mScene);
|
||||
|
||||
// now make a subdeformer for each bone in the skeleton
|
||||
const std::set<const aiNode*, SortNodeByName> skeleton= skeleton_by_mesh[mi];
|
||||
const auto & skeleton= skeleton_by_mesh[mi];
|
||||
for (const aiNode* bone_node : skeleton) {
|
||||
// if there's a bone for this node, find it
|
||||
const aiBone* b = nullptr;
|
||||
|
|
|
@ -644,10 +644,12 @@ void MeshGeometry::ReadVertexDataMaterials(std::vector<int>& materials_out, cons
|
|||
return;
|
||||
}
|
||||
|
||||
if (source["Materials"]) {
|
||||
// materials are handled separately. First of all, they are assigned per-face
|
||||
// and not per polyvert. Secondly, ReferenceInformationType=IndexToDirect
|
||||
// has a slightly different meaning for materials.
|
||||
ParseVectorDataArray(materials_out,GetRequiredElement(source,"Materials"));
|
||||
ParseVectorDataArray(materials_out, GetRequiredElement(source, "Materials"));
|
||||
}
|
||||
|
||||
if (MappingInformationType == "AllSame") {
|
||||
// easy - same material for all faces
|
||||
|
|
|
@ -63,7 +63,6 @@ class Scope;
|
|||
class Parser;
|
||||
class Element;
|
||||
|
||||
// XXX should use C++11's unique_ptr - but assimp's need to keep working with 03
|
||||
using ScopeList = std::vector<Scope*>;
|
||||
using ElementMap = std::fbx_unordered_multimap< std::string, Element*>;
|
||||
using ElementCollection = std::pair<ElementMap::const_iterator,ElementMap::const_iterator>;
|
||||
|
@ -135,7 +134,7 @@ public:
|
|||
const char* elementNameCStr = elementName.c_str();
|
||||
for (auto element = elements.begin(); element != elements.end(); ++element)
|
||||
{
|
||||
if (!ASSIMP_strincmp(element->first.c_str(), elementNameCStr, MAXLEN)) {
|
||||
if (!ASSIMP_strincmp(element->first.c_str(), elementNameCStr, AI_MAXLEN)) {
|
||||
return element->second;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -243,7 +243,6 @@ DirectPropertyMap PropertyTable::GetUnparsedProperties() const
|
|||
|
||||
// Read the element's value.
|
||||
// Wrap the naked pointer (since the call site is required to acquire ownership)
|
||||
// std::unique_ptr from C++11 would be preferred both as a wrapper and a return value.
|
||||
std::shared_ptr<Property> prop = std::shared_ptr<Property>(ReadTypedProperty(*currentElement.second));
|
||||
|
||||
// Element could not be read. Skip it.
|
||||
|
|
|
@ -220,7 +220,7 @@ void IFCImporter::InternReadFile(const std::string &pFile, aiScene *pScene, IOSy
|
|||
std::unique_ptr<STEP::DB> db(STEP::ReadFileHeader(std::move(stream)));
|
||||
const STEP::HeaderInfo &head = static_cast<const STEP::DB &>(*db).GetHeader();
|
||||
|
||||
if (!head.fileSchema.size() || head.fileSchema.substr(0, 3) != "IFC") {
|
||||
if (!head.fileSchema.size() || head.fileSchema.substr(0, 4) != "IFC2") {
|
||||
ThrowException("Unrecognized file schema: " + head.fileSchema);
|
||||
}
|
||||
|
||||
|
@ -260,6 +260,8 @@ void IFCImporter::InternReadFile(const std::string &pFile, aiScene *pScene, IOSy
|
|||
ThrowException("missing IfcProject entity");
|
||||
}
|
||||
|
||||
|
||||
|
||||
ConversionData conv(*db, proj->To<Schema_2x3::IfcProject>(), pScene, settings);
|
||||
SetUnits(conv);
|
||||
SetCoordinateSpace(conv);
|
||||
|
@ -352,6 +354,11 @@ void ConvertUnit(const ::Assimp::STEP::EXPRESS::DataType &dt, ConversionData &co
|
|||
|
||||
// ------------------------------------------------------------------------------------------------
|
||||
void SetUnits(ConversionData &conv) {
|
||||
if (conv.proj.UnitsInContext == nullptr) {
|
||||
IFCImporter::LogError("Skipping conversion data, nullptr.");
|
||||
return;
|
||||
}
|
||||
|
||||
// see if we can determine the coordinate space used to express.
|
||||
for (size_t i = 0; i < conv.proj.UnitsInContext->Units.size(); ++i) {
|
||||
ConvertUnit(*conv.proj.UnitsInContext->Units[i], conv);
|
||||
|
|
|
@ -168,7 +168,7 @@ void IRRImporter::BuildSkybox(std::vector<aiMesh *> &meshes, std::vector<aiMater
|
|||
aiMaterial *out = (aiMaterial *)(*(materials.end() - (6 - i)));
|
||||
|
||||
aiString s;
|
||||
s.length = ::ai_snprintf(s.data, MAXLEN, "SkyboxSide_%u", i);
|
||||
s.length = ::ai_snprintf(s.data, AI_MAXLEN, "SkyboxSide_%u", i);
|
||||
out->AddProperty(&s, AI_MATKEY_NAME);
|
||||
|
||||
int shading = aiShadingMode_NoShading;
|
||||
|
@ -316,7 +316,7 @@ void IRRImporter::ComputeAnimations(Node *root, aiNode *real, std::vector<aiNode
|
|||
if (cur != total - 1) {
|
||||
// Build a new name - a prefix instead of a suffix because it is
|
||||
// easier to check against
|
||||
anim->mNodeName.length = ::ai_snprintf(anim->mNodeName.data, MAXLEN,
|
||||
anim->mNodeName.length = ::ai_snprintf(anim->mNodeName.data, AI_MAXLEN,
|
||||
"$INST_DUMMY_%i_%s", total - 1,
|
||||
(root->name.length() ? root->name.c_str() : ""));
|
||||
|
||||
|
|
|
@ -305,14 +305,14 @@ void LWSImporter::SetupNodeName(aiNode *nd, LWS::NodeDesc &src) {
|
|||
}
|
||||
std::string::size_type t = src.path.substr(s).find_last_of('.');
|
||||
|
||||
nd->mName.length = ::ai_snprintf(nd->mName.data, MAXLEN, "%s_(%08X)", src.path.substr(s).substr(0, t).c_str(), combined);
|
||||
if (nd->mName.length > MAXLEN) {
|
||||
nd->mName.length = MAXLEN;
|
||||
nd->mName.length = ::ai_snprintf(nd->mName.data, AI_MAXLEN, "%s_(%08X)", src.path.substr(s).substr(0, t).c_str(), combined);
|
||||
if (nd->mName.length > AI_MAXLEN) {
|
||||
nd->mName.length = AI_MAXLEN;
|
||||
}
|
||||
return;
|
||||
}
|
||||
}
|
||||
nd->mName.length = ::ai_snprintf(nd->mName.data, MAXLEN, "%s_(%08X)", src.name, combined);
|
||||
nd->mName.length = ::ai_snprintf(nd->mName.data, AI_MAXLEN, "%s_(%08X)", src.name, combined);
|
||||
}
|
||||
|
||||
// ------------------------------------------------------------------------------------------------
|
||||
|
|
|
@ -707,7 +707,7 @@ void MD5Importer::LoadMD5CameraFile() {
|
|||
for (std::vector<unsigned int>::const_iterator it = cuts.begin(); it != cuts.end() - 1; ++it) {
|
||||
|
||||
aiAnimation *anim = *tmp++ = new aiAnimation();
|
||||
anim->mName.length = ::ai_snprintf(anim->mName.data, MAXLEN, "anim%u_from_%u_to_%u", (unsigned int)(it - cuts.begin()), (*it), *(it + 1));
|
||||
anim->mName.length = ::ai_snprintf(anim->mName.data, AI_MAXLEN, "anim%u_from_%u_to_%u", (unsigned int)(it - cuts.begin()), (*it), *(it + 1));
|
||||
|
||||
anim->mTicksPerSecond = cameraParser.fFrameRate;
|
||||
anim->mChannels = new aiNodeAnim *[anim->mNumChannels = 1];
|
||||
|
|
|
@ -234,8 +234,12 @@ inline void AI_MD5_READ_TRIPLE(aiVector3D &vec, const char **sz, const char *buf
|
|||
AI_MD5_SKIP_SPACES(sz, bufferEnd, linenumber);
|
||||
if ('(' != **sz) {
|
||||
MD5Parser::ReportWarning("Unexpected token: ( was expected", linenumber);
|
||||
if (*sz == bufferEnd)
|
||||
return;
|
||||
++*sz;
|
||||
}
|
||||
if (*sz == bufferEnd)
|
||||
return;
|
||||
++*sz;
|
||||
AI_MD5_SKIP_SPACES(sz, bufferEnd, linenumber);
|
||||
*sz = fast_atoreal_move<float>(*sz, (float &)vec.x);
|
||||
|
@ -247,6 +251,8 @@ inline void AI_MD5_READ_TRIPLE(aiVector3D &vec, const char **sz, const char *buf
|
|||
if (')' != **sz) {
|
||||
MD5Parser::ReportWarning("Unexpected token: ) was expected", linenumber);
|
||||
}
|
||||
if (*sz == bufferEnd)
|
||||
return;
|
||||
++*sz;
|
||||
}
|
||||
|
||||
|
|
|
@ -962,7 +962,7 @@ void MDLImporter::CalcAbsBoneMatrices_3DGS_MDL7(MDL::IntBone_MDL7 **apcOutBones)
|
|||
|
||||
if (AI_MDL7_BONE_STRUCT_SIZE__NAME_IS_NOT_THERE == pcHeader->bone_stc_size) {
|
||||
// no real name for our poor bone is specified :-(
|
||||
pcOutBone->mName.length = ai_snprintf(pcOutBone->mName.data, MAXLEN,
|
||||
pcOutBone->mName.length = ai_snprintf(pcOutBone->mName.data, AI_MAXLEN,
|
||||
"UnnamedBone_%i", iBone);
|
||||
} else {
|
||||
// Make sure we won't run over the buffer's end if there is no
|
||||
|
@ -1567,7 +1567,7 @@ void MDLImporter::InternReadFile_3DGS_MDL7() {
|
|||
} else {
|
||||
pcNode->mName.length = (ai_uint32)::strlen(szBuffer);
|
||||
}
|
||||
::strncpy(pcNode->mName.data, szBuffer, MAXLEN - 1);
|
||||
::strncpy(pcNode->mName.data, szBuffer, AI_MAXLEN - 1);
|
||||
++p;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -494,7 +494,7 @@ void MDLImporter::ParseSkinLump_3DGS_MDL7(
|
|||
|
||||
aiString szFile;
|
||||
const size_t iLen = strlen((const char *)szCurrent);
|
||||
size_t iLen2 = iLen > (MAXLEN - 1) ? (MAXLEN - 1) : iLen;
|
||||
size_t iLen2 = iLen > (AI_MAXLEN - 1) ? (AI_MAXLEN - 1) : iLen;
|
||||
memcpy(szFile.data, (const char *)szCurrent, iLen2);
|
||||
szFile.data[iLen2] = '\0';
|
||||
szFile.length = static_cast<ai_uint32>(iLen2);
|
||||
|
@ -730,7 +730,8 @@ void MDLImporter::SkipSkinLump_3DGS_MDL7(
|
|||
// if an ASCII effect description (HLSL?) is contained in the file,
|
||||
// we can simply ignore it ...
|
||||
if (iType & AI_MDL7_SKINTYPE_MATERIAL_ASCDEF) {
|
||||
int32_t iMe = *((int32_t *)szCurrent);
|
||||
int32_t iMe = 0;
|
||||
::memcpy(&iMe, szCurrent, sizeof(int32_t));
|
||||
AI_SWAP4(iMe);
|
||||
szCurrent += sizeof(char) * iMe + sizeof(int32_t);
|
||||
}
|
||||
|
|
|
@ -193,7 +193,7 @@ void ObjFileImporter::CreateDataFromImport(const ObjFile::Model *pModel, aiScene
|
|||
pScene->mRootNode->mChildren = new aiNode *[childCount];
|
||||
|
||||
// Create nodes for the whole scene
|
||||
std::vector<aiMesh *> MeshArray;
|
||||
std::vector<std::unique_ptr<aiMesh>> MeshArray;
|
||||
MeshArray.reserve(meshCount);
|
||||
for (size_t index = 0; index < pModel->mObjects.size(); ++index) {
|
||||
createNodes(pModel, pModel->mObjects[index], pScene->mRootNode, pScene, MeshArray);
|
||||
|
@ -205,7 +205,7 @@ void ObjFileImporter::CreateDataFromImport(const ObjFile::Model *pModel, aiScene
|
|||
if (pScene->mNumMeshes > 0) {
|
||||
pScene->mMeshes = new aiMesh *[MeshArray.size()];
|
||||
for (size_t index = 0; index < MeshArray.size(); ++index) {
|
||||
pScene->mMeshes[index] = MeshArray[index];
|
||||
pScene->mMeshes[index] = MeshArray[index].release();
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -257,7 +257,7 @@ void ObjFileImporter::CreateDataFromImport(const ObjFile::Model *pModel, aiScene
|
|||
// Creates all nodes of the model
|
||||
aiNode *ObjFileImporter::createNodes(const ObjFile::Model *pModel, const ObjFile::Object *pObject,
|
||||
aiNode *pParent, aiScene *pScene,
|
||||
std::vector<aiMesh *> &MeshArray) {
|
||||
std::vector<std::unique_ptr<aiMesh>> &MeshArray) {
|
||||
ai_assert(nullptr != pModel);
|
||||
if (nullptr == pObject) {
|
||||
return nullptr;
|
||||
|
@ -275,12 +275,10 @@ aiNode *ObjFileImporter::createNodes(const ObjFile::Model *pModel, const ObjFile
|
|||
|
||||
for (size_t i = 0; i < pObject->m_Meshes.size(); ++i) {
|
||||
unsigned int meshId = pObject->m_Meshes[i];
|
||||
aiMesh *pMesh = createTopology(pModel, pObject, meshId);
|
||||
std::unique_ptr<aiMesh> pMesh = createTopology(pModel, pObject, meshId);
|
||||
if (pMesh != nullptr) {
|
||||
if (pMesh->mNumFaces > 0) {
|
||||
MeshArray.push_back(pMesh);
|
||||
} else {
|
||||
delete pMesh;
|
||||
MeshArray.push_back(std::move(pMesh));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -312,7 +310,7 @@ aiNode *ObjFileImporter::createNodes(const ObjFile::Model *pModel, const ObjFile
|
|||
|
||||
// ------------------------------------------------------------------------------------------------
|
||||
// Create topology data
|
||||
aiMesh *ObjFileImporter::createTopology(const ObjFile::Model *pModel, const ObjFile::Object *pData, unsigned int meshIndex) {
|
||||
std::unique_ptr<aiMesh> ObjFileImporter::createTopology(const ObjFile::Model *pModel, const ObjFile::Object *pData, unsigned int meshIndex) {
|
||||
// Checking preconditions
|
||||
ai_assert(nullptr != pModel);
|
||||
|
||||
|
@ -394,7 +392,7 @@ aiMesh *ObjFileImporter::createTopology(const ObjFile::Model *pModel, const ObjF
|
|||
// Create mesh vertices
|
||||
createVertexArray(pModel, pData, meshIndex, pMesh.get(), uiIdxCount);
|
||||
|
||||
return pMesh.release();
|
||||
return pMesh;
|
||||
}
|
||||
|
||||
// ------------------------------------------------------------------------------------------------
|
||||
|
|
|
@ -44,6 +44,7 @@ OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
|||
|
||||
#include <assimp/BaseImporter.h>
|
||||
#include <assimp/material.h>
|
||||
#include <memory>
|
||||
#include <vector>
|
||||
|
||||
struct aiMesh;
|
||||
|
@ -84,10 +85,10 @@ protected:
|
|||
|
||||
//! \brief Creates all nodes stored in imported content.
|
||||
aiNode *createNodes(const ObjFile::Model *pModel, const ObjFile::Object *pData,
|
||||
aiNode *pParent, aiScene *pScene, std::vector<aiMesh *> &MeshArray);
|
||||
aiNode *pParent, aiScene *pScene, std::vector<std::unique_ptr<aiMesh>> &MeshArray);
|
||||
|
||||
//! \brief Creates topology data like faces and meshes for the geometry.
|
||||
aiMesh *createTopology(const ObjFile::Model *pModel, const ObjFile::Object *pData,
|
||||
std::unique_ptr<aiMesh> createTopology(const ObjFile::Model *pModel, const ObjFile::Object *pData,
|
||||
unsigned int uiMeshIndex);
|
||||
|
||||
//! \brief Creates vertices from model.
|
||||
|
|
|
@ -343,7 +343,7 @@ void ObjFileMtlImporter::createMaterial() {
|
|||
}
|
||||
}
|
||||
|
||||
name = trim_whitespaces(name);
|
||||
name = ai_trim(name);
|
||||
|
||||
std::map<std::string, ObjFile::Material *>::iterator it = m_pModel->mMaterialMap.find(name);
|
||||
if (m_pModel->mMaterialMap.end() == it) {
|
||||
|
|
|
@ -577,16 +577,18 @@ void ObjFileParser::getMaterialDesc() {
|
|||
|
||||
// Get name
|
||||
std::string strName(pStart, &(*m_DataIt));
|
||||
strName = trim_whitespaces(strName);
|
||||
strName = ai_trim(strName);
|
||||
if (strName.empty()) {
|
||||
skip = true;
|
||||
}
|
||||
|
||||
// If the current mesh has the same material, we simply ignore that 'usemtl' command
|
||||
// If the current mesh has the same material, we will ignore that 'usemtl' command
|
||||
// There is no need to create another object or even mesh here
|
||||
if (!skip) {
|
||||
if (m_pModel->mCurrentMaterial && m_pModel->mCurrentMaterial->MaterialName == aiString(strName)) {
|
||||
skip = true;
|
||||
}
|
||||
}
|
||||
|
||||
if (!skip) {
|
||||
// Search for material
|
||||
|
|
|
@ -247,22 +247,6 @@ inline char_t getFloat(char_t it, char_t end, ai_real &value) {
|
|||
return it;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Will remove white-spaces for a string.
|
||||
* @param[in] str The string to clean
|
||||
* @return The trimmed string.
|
||||
*/
|
||||
template <class string_type>
|
||||
inline string_type trim_whitespaces(string_type str) {
|
||||
while (!str.empty() && IsSpace(str[0])) {
|
||||
str.erase(0);
|
||||
}
|
||||
while (!str.empty() && IsSpace(str[str.length() - 1])) {
|
||||
str.erase(str.length() - 1);
|
||||
}
|
||||
return str;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Checks for a line-end.
|
||||
* @param[in] it Current iterator in string.
|
||||
|
|
|
@ -346,10 +346,22 @@ void PlyExporter::WriteMeshVertsBinary(const aiMesh* m, unsigned int components)
|
|||
|
||||
for (unsigned int n = PLY_EXPORT_HAS_COLORS, c = 0; (components & n) && c != AI_MAX_NUMBER_OF_COLOR_SETS; n <<= 1, ++c) {
|
||||
if (m->HasVertexColors(c)) {
|
||||
mOutput.write(reinterpret_cast<const char*>(&m->mColors[c][i].r), 16);
|
||||
unsigned char rgba[4] = {
|
||||
static_cast<unsigned char>(m->mColors[c][i].r * 255),
|
||||
static_cast<unsigned char>(m->mColors[c][i].g * 255),
|
||||
static_cast<unsigned char>(m->mColors[c][i].b * 255),
|
||||
static_cast<unsigned char>(m->mColors[c][i].a * 255)
|
||||
};
|
||||
mOutput.write(reinterpret_cast<const char*>(&rgba), 4);
|
||||
}
|
||||
else {
|
||||
mOutput.write(reinterpret_cast<const char*>(&defaultColor.r), 16);
|
||||
unsigned char rgba[4] = {
|
||||
static_cast<unsigned char>(defaultColor.r * 255),
|
||||
static_cast<unsigned char>(defaultColor.g * 255),
|
||||
static_cast<unsigned char>(defaultColor.b * 255),
|
||||
static_cast<unsigned char>(defaultColor.a * 255)
|
||||
};
|
||||
mOutput.write(reinterpret_cast<const char*>(&rgba), 4);
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -564,6 +564,10 @@ void PLYImporter::LoadFace(const PLY::Element *pcElement, const PLY::ElementInst
|
|||
if (mGeneratedMesh->mFaces == nullptr) {
|
||||
mGeneratedMesh->mNumFaces = pcElement->NumOccur;
|
||||
mGeneratedMesh->mFaces = new aiFace[mGeneratedMesh->mNumFaces];
|
||||
} else {
|
||||
if (mGeneratedMesh->mNumFaces < pcElement->NumOccur) {
|
||||
throw DeadlyImportError("Invalid .ply file: Too many faces");
|
||||
}
|
||||
}
|
||||
|
||||
if (!bIsTriStrip) {
|
||||
|
|
|
@ -588,7 +588,7 @@ bool Q3BSPFileImporter::importTextureFromArchive(const Q3BSP::Q3BSPModel *model,
|
|||
|
||||
aiString name;
|
||||
name.data[0] = '*';
|
||||
name.length = 1 + ASSIMP_itoa10(name.data + 1, static_cast<unsigned int>(MAXLEN - 1), static_cast<int32_t>(mTextures.size()));
|
||||
name.length = 1 + ASSIMP_itoa10(name.data + 1, static_cast<unsigned int>(AI_MAXLEN - 1), static_cast<int32_t>(mTextures.size()));
|
||||
|
||||
archive->Close(pTextureStream);
|
||||
|
||||
|
@ -641,7 +641,7 @@ bool Q3BSPFileImporter::importLightmap(const Q3BSP::Q3BSPModel *pModel, aiScene
|
|||
|
||||
aiString name;
|
||||
name.data[0] = '*';
|
||||
name.length = 1 + ASSIMP_itoa10(name.data + 1, static_cast<unsigned int>(MAXLEN - 1), static_cast<int32_t>(mTextures.size()));
|
||||
name.length = 1 + ASSIMP_itoa10(name.data + 1, static_cast<unsigned int>(AI_MAXLEN - 1), static_cast<int32_t>(mTextures.size()));
|
||||
|
||||
pMatHelper->AddProperty(&name, AI_MATKEY_TEXTURE_LIGHTMAP(1));
|
||||
mTextures.push_back(pTexture);
|
||||
|
|
|
@ -250,6 +250,10 @@ void Q3DImporter::InternReadFile(const std::string &pFile,
|
|||
c = stream.GetI1();
|
||||
while (c) {
|
||||
mat.name.data[mat.name.length++] = c;
|
||||
if (mat.name.length == AI_MAXLEN) {
|
||||
ASSIMP_LOG_ERROR("String ouverflow detected, skipped material name parsing.");
|
||||
break;
|
||||
}
|
||||
c = stream.GetI1();
|
||||
}
|
||||
|
||||
|
|
|
@ -589,12 +589,12 @@ void SMDImporter::CreateOutputMaterials() {
|
|||
pScene->mMaterials[iMat] = pcMat;
|
||||
|
||||
aiString szName;
|
||||
szName.length = static_cast<ai_uint32>(ai_snprintf(szName.data,MAXLEN,"Texture_%u",iMat));
|
||||
szName.length = static_cast<ai_uint32>(ai_snprintf(szName.data, AI_MAXLEN, "Texture_%u", iMat));
|
||||
pcMat->AddProperty(&szName,AI_MATKEY_NAME);
|
||||
|
||||
if (aszTextures[iMat].length())
|
||||
{
|
||||
::strncpy(szName.data, aszTextures[iMat].c_str(),MAXLEN-1);
|
||||
::strncpy(szName.data, aszTextures[iMat].c_str(), AI_MAXLEN - 1);
|
||||
szName.length = static_cast<ai_uint32>( aszTextures[iMat].length() );
|
||||
pcMat->AddProperty(&szName,AI_MATKEY_TEXTURE_DIFFUSE(0));
|
||||
}
|
||||
|
|
|
@ -257,7 +257,7 @@ void STLImporter::LoadASCIIFile(aiNode *root) {
|
|||
size_t temp = (size_t)(sz - szMe);
|
||||
// setup the name of the node
|
||||
if (temp) {
|
||||
if (temp >= MAXLEN) {
|
||||
if (temp >= AI_MAXLEN) {
|
||||
throw DeadlyImportError("STL: Node name too long");
|
||||
}
|
||||
std::string name(szMe, temp);
|
||||
|
|
|
@ -82,8 +82,6 @@ OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
|||
// this is intended as stress test - by default, entities are evaluated
|
||||
// lazily and therefore not unless needed.
|
||||
|
||||
//#define ASSIMP_IFC_TEST
|
||||
|
||||
namespace Assimp {
|
||||
|
||||
// ********************************************************************************
|
||||
|
@ -531,6 +529,7 @@ public:
|
|||
|
||||
template <typename T>
|
||||
const T &To() const {
|
||||
|
||||
return dynamic_cast<const T &>(**this);
|
||||
}
|
||||
|
||||
|
@ -581,12 +580,12 @@ private:
|
|||
};
|
||||
|
||||
template <typename T>
|
||||
inline bool operator==(const std::shared_ptr<LazyObject> &lo, T whatever) {
|
||||
inline bool operator == (const std::shared_ptr<LazyObject> &lo, T whatever) {
|
||||
return *lo == whatever; // XXX use std::forward if we have 0x
|
||||
}
|
||||
|
||||
template <typename T>
|
||||
inline bool operator==(const std::pair<uint64_t, std::shared_ptr<LazyObject>> &lo, T whatever) {
|
||||
inline bool operator == (const std::pair<uint64_t, std::shared_ptr<LazyObject>> &lo, T whatever) {
|
||||
return *(lo.second) == whatever; // XXX use std::forward if we have 0x
|
||||
}
|
||||
|
||||
|
@ -599,18 +598,30 @@ struct Lazy {
|
|||
Lazy(const LazyObject *obj = nullptr) : obj(obj) {}
|
||||
|
||||
operator const T *() const {
|
||||
if (obj == nullptr) {
|
||||
throw TypeError("Obj type is nullptr.");
|
||||
}
|
||||
return obj->ToPtr<T>();
|
||||
}
|
||||
|
||||
operator const T &() const {
|
||||
if (obj == nullptr) {
|
||||
throw TypeError("Obj type is nullptr.");
|
||||
}
|
||||
return obj->To<T>();
|
||||
}
|
||||
|
||||
const T &operator*() const {
|
||||
if (obj == nullptr) {
|
||||
throw TypeError("Obj type is nullptr.");
|
||||
}
|
||||
return obj->To<T>();
|
||||
}
|
||||
|
||||
const T *operator->() const {
|
||||
if (obj == nullptr) {
|
||||
throw TypeError("Obj type is nullptr.");
|
||||
}
|
||||
return &obj->To<T>();
|
||||
}
|
||||
|
||||
|
|
|
@ -452,7 +452,7 @@ void UnrealImporter::InternReadFile(const std::string &pFile,
|
|||
aiColor3D color(1.f, 1.f, 1.f);
|
||||
|
||||
aiString s;
|
||||
::ai_snprintf(s.data, MAXLEN, "mat%u_tx%u_", i, materials[i].tex);
|
||||
::ai_snprintf(s.data, AI_MAXLEN, "mat%u_tx%u_", i, materials[i].tex);
|
||||
|
||||
// set the two-sided flag
|
||||
if (materials[i].type == Unreal::MF_NORMAL_TS) {
|
||||
|
@ -472,7 +472,7 @@ void UnrealImporter::InternReadFile(const std::string &pFile,
|
|||
|
||||
// a special name for the weapon attachment point
|
||||
if (materials[i].type == Unreal::MF_WEAPON_PLACEHOLDER) {
|
||||
s.length = ::ai_snprintf(s.data, MAXLEN, "$WeaponTag$");
|
||||
s.length = ::ai_snprintf(s.data, AI_MAXLEN, "$WeaponTag$");
|
||||
color = aiColor3D(0.f, 0.f, 0.f);
|
||||
}
|
||||
|
||||
|
|
|
@ -109,7 +109,7 @@ inline void SetMaterialColorProperty(std::vector<int> &embeddedTexIdxs, Asset &
|
|||
if (texIdx != -1) { // embedded
|
||||
// setup texture reference string (copied from ColladaLoader::FindFilenameForEffectTexture)
|
||||
uri.data[0] = '*';
|
||||
uri.length = 1 + ASSIMP_itoa10(uri.data + 1, MAXLEN - 1, texIdx);
|
||||
uri.length = 1 + ASSIMP_itoa10(uri.data + 1, AI_MAXLEN - 1, texIdx);
|
||||
}
|
||||
|
||||
mat->AddProperty(&uri, _AI_MATKEY_TEXTURE_BASE, texType, 0);
|
||||
|
@ -242,7 +242,7 @@ void glTFImporter::ImportMeshes(glTF::Asset &r) {
|
|||
if (mesh.primitives.size() > 1) {
|
||||
ai_uint32 &len = aim->mName.length;
|
||||
aim->mName.data[len] = '-';
|
||||
len += 1 + ASSIMP_itoa10(aim->mName.data + len + 1, unsigned(MAXLEN - len - 1), p);
|
||||
len += 1 + ASSIMP_itoa10(aim->mName.data + len + 1, unsigned(AI_MAXLEN - len - 1), p);
|
||||
}
|
||||
|
||||
switch (prim.mode) {
|
||||
|
|
|
@ -1440,7 +1440,7 @@ inline void MaterialSheen::SetDefaults() {
|
|||
inline void MaterialVolume::SetDefaults() {
|
||||
//KHR_materials_volume properties
|
||||
thicknessFactor = 0.f;
|
||||
attenuationDistance = INFINITY;
|
||||
attenuationDistance = std::numeric_limits<float>::infinity();
|
||||
SetVector(attenuationColor, defaultAttenuationColor);
|
||||
}
|
||||
|
||||
|
|
|
@ -507,7 +507,7 @@ namespace glTF2 {
|
|||
|
||||
WriteTex(materialVolume, volume.thicknessTexture, "thicknessTexture", w.mAl);
|
||||
|
||||
if (volume.attenuationDistance != INFINITY) {
|
||||
if (volume.attenuationDistance != std::numeric_limits<float>::infinity()) {
|
||||
WriteFloat(materialVolume, volume.attenuationDistance, "attenuationDistance", w.mAl);
|
||||
}
|
||||
|
||||
|
|
|
@ -92,7 +92,7 @@ static constexpr aiImporterDesc desc = {
|
|||
0,
|
||||
0,
|
||||
0,
|
||||
"gltf glb"
|
||||
"gltf glb vrm"
|
||||
};
|
||||
|
||||
glTF2Importer::glTF2Importer() :
|
||||
|
@ -106,7 +106,7 @@ const aiImporterDesc *glTF2Importer::GetInfo() const {
|
|||
|
||||
bool glTF2Importer::CanRead(const std::string &filename, IOSystem *pIOHandler, bool checkSig) const {
|
||||
const std::string extension = GetExtension(filename);
|
||||
if (!checkSig && (extension != "gltf") && (extension != "glb")) {
|
||||
if (!checkSig && (extension != "gltf") && (extension != "glb") && (extension != "vrm")) {
|
||||
return false;
|
||||
}
|
||||
|
||||
|
@ -161,7 +161,7 @@ static void SetMaterialTextureProperty(std::vector<int> &embeddedTexIdxs, Asset
|
|||
if (texIdx != -1) { // embedded
|
||||
// setup texture reference string (copied from ColladaLoader::FindFilenameForEffectTexture)
|
||||
uri.data[0] = '*';
|
||||
uri.length = 1 + ASSIMP_itoa10(uri.data + 1, MAXLEN - 1, texIdx);
|
||||
uri.length = 1 + ASSIMP_itoa10(uri.data + 1, AI_MAXLEN - 1, texIdx);
|
||||
}
|
||||
|
||||
mat->AddProperty(&uri, AI_MATKEY_TEXTURE(texType, texSlot));
|
||||
|
@ -539,7 +539,7 @@ void glTF2Importer::ImportMeshes(glTF2::Asset &r) {
|
|||
if (mesh.primitives.size() > 1) {
|
||||
ai_uint32 &len = aim->mName.length;
|
||||
aim->mName.data[len] = '-';
|
||||
len += 1 + ASSIMP_itoa10(aim->mName.data + len + 1, unsigned(MAXLEN - len - 1), p);
|
||||
len += 1 + ASSIMP_itoa10(aim->mName.data + len + 1, unsigned(AI_MAXLEN - len - 1), p);
|
||||
}
|
||||
|
||||
switch (prim.mode) {
|
||||
|
|
|
@ -471,6 +471,14 @@ ADD_ASSIMP_IMPORTER( MDL
|
|||
AssetLib/MDL/HalfLife/UniqueNameGenerator.h
|
||||
)
|
||||
|
||||
IF(((CMAKE_CXX_COMPILER_ID MATCHES "GNU") AND NOT MINGW AND NOT HAIKU) AND CMAKE_CXX_COMPILER_VERSION GREATER_EQUAL 13)
|
||||
message(STATUS "GCC13 detected disabling \"-Warray-bounds and -Wstringop-overflow\" for"
|
||||
" AssetLib/MDL/MDLLoader.cpp as it appears to be a false positive")
|
||||
set_source_files_properties(AssetLib/MDL/MDLLoader.cpp PROPERTIES
|
||||
COMPILE_FLAGS "-Wno-array-bounds -Wno-stringop-overflow"
|
||||
)
|
||||
endif()
|
||||
|
||||
SET( MaterialSystem_SRCS
|
||||
Material/MaterialSystem.cpp
|
||||
Material/MaterialSystem.h
|
||||
|
@ -503,6 +511,14 @@ ADD_ASSIMP_IMPORTER( OBJ
|
|||
AssetLib/Obj/ObjTools.h
|
||||
)
|
||||
|
||||
IF(((CMAKE_CXX_COMPILER_ID MATCHES "GNU") AND NOT MINGW AND NOT HAIKU) AND CMAKE_CXX_COMPILER_VERSION EQUAL 14)
|
||||
message(STATUS "GCC14 detected disabling \"-Wmaybe-uninitialized\" for"
|
||||
" AssetLib/Obj/ObjFileParser.cpp as it appears to be a false positive")
|
||||
set_source_files_properties(AssetLib/Obj/ObjFileParser.cpp PROPERTIES
|
||||
COMPILE_FLAGS "-Wno-maybe-uninitialized"
|
||||
)
|
||||
endif()
|
||||
|
||||
ADD_ASSIMP_IMPORTER( OGRE
|
||||
AssetLib/Ogre/OgreImporter.h
|
||||
AssetLib/Ogre/OgreStructs.h
|
||||
|
|
|
@ -233,8 +233,13 @@ const aiScene *aiImportFileFromMemoryWithProperties(
|
|||
unsigned int pFlags,
|
||||
const char *pHint,
|
||||
const aiPropertyStore *props) {
|
||||
ai_assert(nullptr != pBuffer);
|
||||
ai_assert(0 != pLength);
|
||||
if (pBuffer == nullptr) {
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
if (pLength == 0u) {
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
const aiScene *scene = nullptr;
|
||||
ASSIMP_BEGIN_EXCEPTION_REGION();
|
||||
|
|
|
@ -148,9 +148,11 @@ void Bitmap::WriteData(aiTexture *texture, IOStream *file) {
|
|||
|
||||
file->Write(pixel, mBytesPerPixel, 1);
|
||||
}
|
||||
|
||||
// When padding is 0, passing it as an argument will cause an assertion failure in DefaultIOStream::Write.
|
||||
if (padding) {
|
||||
file->Write(padding_data, padding, 1);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
} // namespace Assimp
|
||||
|
|
|
@ -78,7 +78,7 @@ inline void PrefixString(aiString &string, const char *prefix, unsigned int len)
|
|||
if (string.length >= 1 && string.data[0] == '$')
|
||||
return;
|
||||
|
||||
if (len + string.length >= MAXLEN - 1) {
|
||||
if (len + string.length >= AI_MAXLEN - 1) {
|
||||
ASSIMP_LOG_VERBOSE_DEBUG("Can't add an unique prefix because the string is too long");
|
||||
ai_assert(false);
|
||||
return;
|
||||
|
@ -408,7 +408,7 @@ void SceneCombiner::MergeScenes(aiScene **_dest, aiScene *master, std::vector<At
|
|||
// where n is the index of the texture.
|
||||
// Copy here because we overwrite the string data in-place and the buffer inside of aiString
|
||||
// will be a lie if we just reinterpret from prop->mData. The size of mData is not guaranteed to be
|
||||
// MAXLEN in size.
|
||||
// AI_MAXLEN in size.
|
||||
aiString s(*(aiString *)prop->mData);
|
||||
if ('*' == s.data[0]) {
|
||||
// Offset the index and write it back ..
|
||||
|
|
|
@ -88,6 +88,11 @@ private:
|
|||
|
||||
} // namespace Assimp
|
||||
|
||||
/// @brief Fixes an undefined reference error when linking in certain build environments.
|
||||
// May throw warnings about needing stdc++17, but should compile without issues on modern compilers.
|
||||
inline const size_t Assimp::StackAllocator::g_maxBytesPerBlock;
|
||||
inline const size_t Assimp::StackAllocator::g_startBytesPerBlock;
|
||||
|
||||
#include "StackAllocator.inl"
|
||||
|
||||
#endif // include guard
|
||||
|
|
|
@ -524,6 +524,10 @@ void CatmullClarkSubdivider::InternSubdivide(
|
|||
}
|
||||
}
|
||||
|
||||
if (mp == nullptr) {
|
||||
continue;
|
||||
}
|
||||
|
||||
ai_assert(adj[o] - moffsets[nidx].first < mp->mNumFaces);
|
||||
const aiFace &f = mp->mFaces[adj[o] - moffsets[nidx].first];
|
||||
bool haveit = false;
|
||||
|
|
|
@ -44,8 +44,7 @@ OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
|||
#include "ScenePrivate.h"
|
||||
#include <assimp/scene.h>
|
||||
#include <assimp/version.h>
|
||||
|
||||
#include "revision.h"
|
||||
#include <assimp/revision.h>
|
||||
|
||||
// --------------------------------------------------------------------------------
|
||||
// Legal information string - don't remove this.
|
||||
|
@ -118,83 +117,3 @@ ASSIMP_API const char *aiGetBranchName() {
|
|||
return GitBranch;
|
||||
}
|
||||
|
||||
// ------------------------------------------------------------------------------------------------
|
||||
ASSIMP_API aiScene::aiScene() :
|
||||
mFlags(0),
|
||||
mRootNode(nullptr),
|
||||
mNumMeshes(0),
|
||||
mMeshes(nullptr),
|
||||
mNumMaterials(0),
|
||||
mMaterials(nullptr),
|
||||
mNumAnimations(0),
|
||||
mAnimations(nullptr),
|
||||
mNumTextures(0),
|
||||
mTextures(nullptr),
|
||||
mNumLights(0),
|
||||
mLights(nullptr),
|
||||
mNumCameras(0),
|
||||
mCameras(nullptr),
|
||||
mMetaData(nullptr),
|
||||
mName(),
|
||||
mNumSkeletons(0),
|
||||
mSkeletons(nullptr),
|
||||
mPrivate(new Assimp::ScenePrivateData()) {
|
||||
// empty
|
||||
}
|
||||
|
||||
// ------------------------------------------------------------------------------------------------
|
||||
ASSIMP_API aiScene::~aiScene() {
|
||||
// delete all sub-objects recursively
|
||||
delete mRootNode;
|
||||
|
||||
// To make sure we won't crash if the data is invalid it's
|
||||
// much better to check whether both mNumXXX and mXXX are
|
||||
// valid instead of relying on just one of them.
|
||||
if (mNumMeshes && mMeshes) {
|
||||
for (unsigned int a = 0; a < mNumMeshes; ++a) {
|
||||
delete mMeshes[a];
|
||||
}
|
||||
}
|
||||
delete[] mMeshes;
|
||||
|
||||
if (mNumMaterials && mMaterials) {
|
||||
for (unsigned int a = 0; a < mNumMaterials; ++a) {
|
||||
delete mMaterials[a];
|
||||
}
|
||||
}
|
||||
delete[] mMaterials;
|
||||
|
||||
if (mNumAnimations && mAnimations) {
|
||||
for (unsigned int a = 0; a < mNumAnimations; ++a) {
|
||||
delete mAnimations[a];
|
||||
}
|
||||
}
|
||||
delete[] mAnimations;
|
||||
|
||||
if (mNumTextures && mTextures) {
|
||||
for (unsigned int a = 0; a < mNumTextures; ++a) {
|
||||
delete mTextures[a];
|
||||
}
|
||||
}
|
||||
delete[] mTextures;
|
||||
|
||||
if (mNumLights && mLights) {
|
||||
for (unsigned int a = 0; a < mNumLights; ++a) {
|
||||
delete mLights[a];
|
||||
}
|
||||
}
|
||||
delete[] mLights;
|
||||
|
||||
if (mNumCameras && mCameras) {
|
||||
for (unsigned int a = 0; a < mNumCameras; ++a) {
|
||||
delete mCameras[a];
|
||||
}
|
||||
}
|
||||
delete[] mCameras;
|
||||
|
||||
aiMetadata::Dealloc(mMetaData);
|
||||
|
||||
delete[] mSkeletons;
|
||||
|
||||
delete static_cast<Assimp::ScenePrivateData *>(mPrivate);
|
||||
}
|
||||
|
|
|
@ -40,6 +40,87 @@ OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
|||
*/
|
||||
#include <assimp/scene.h>
|
||||
|
||||
#include "ScenePrivate.h"
|
||||
|
||||
aiScene::aiScene() :
|
||||
mFlags(0),
|
||||
mRootNode(nullptr),
|
||||
mNumMeshes(0),
|
||||
mMeshes(nullptr),
|
||||
mNumMaterials(0),
|
||||
mMaterials(nullptr),
|
||||
mNumAnimations(0),
|
||||
mAnimations(nullptr),
|
||||
mNumTextures(0),
|
||||
mTextures(nullptr),
|
||||
mNumLights(0),
|
||||
mLights(nullptr),
|
||||
mNumCameras(0),
|
||||
mCameras(nullptr),
|
||||
mMetaData(nullptr),
|
||||
mName(),
|
||||
mNumSkeletons(0),
|
||||
mSkeletons(nullptr),
|
||||
mPrivate(new Assimp::ScenePrivateData()) {
|
||||
// empty
|
||||
}
|
||||
|
||||
aiScene::~aiScene() {
|
||||
// delete all sub-objects recursively
|
||||
delete mRootNode;
|
||||
|
||||
// To make sure we won't crash if the data is invalid it's
|
||||
// much better to check whether both mNumXXX and mXXX are
|
||||
// valid instead of relying on just one of them.
|
||||
if (mNumMeshes && mMeshes) {
|
||||
for (unsigned int a = 0; a < mNumMeshes; ++a) {
|
||||
delete mMeshes[a];
|
||||
}
|
||||
}
|
||||
delete[] mMeshes;
|
||||
|
||||
if (mNumMaterials && mMaterials) {
|
||||
for (unsigned int a = 0; a < mNumMaterials; ++a) {
|
||||
delete mMaterials[a];
|
||||
}
|
||||
}
|
||||
delete[] mMaterials;
|
||||
|
||||
if (mNumAnimations && mAnimations) {
|
||||
for (unsigned int a = 0; a < mNumAnimations; ++a) {
|
||||
delete mAnimations[a];
|
||||
}
|
||||
}
|
||||
delete[] mAnimations;
|
||||
|
||||
if (mNumTextures && mTextures) {
|
||||
for (unsigned int a = 0; a < mNumTextures; ++a) {
|
||||
delete mTextures[a];
|
||||
}
|
||||
}
|
||||
delete[] mTextures;
|
||||
|
||||
if (mNumLights && mLights) {
|
||||
for (unsigned int a = 0; a < mNumLights; ++a) {
|
||||
delete mLights[a];
|
||||
}
|
||||
}
|
||||
delete[] mLights;
|
||||
|
||||
if (mNumCameras && mCameras) {
|
||||
for (unsigned int a = 0; a < mNumCameras; ++a) {
|
||||
delete mCameras[a];
|
||||
}
|
||||
}
|
||||
delete[] mCameras;
|
||||
|
||||
aiMetadata::Dealloc(mMetaData);
|
||||
|
||||
delete[] mSkeletons;
|
||||
|
||||
delete static_cast<Assimp::ScenePrivateData *>(mPrivate);
|
||||
}
|
||||
|
||||
aiNode::aiNode() :
|
||||
mName(""),
|
||||
mParent(nullptr),
|
||||
|
|
|
@ -49,6 +49,10 @@ namespace Assimp {
|
|||
// ---------------------------------------------------------------------------
|
||||
class ASSIMP_API GeometryUtils {
|
||||
public:
|
||||
/// @brief Will calculate the area of a triangle.
|
||||
/// @param a The first vertex of the triangle.
|
||||
/// @param b The first vertex of the triangle.
|
||||
/// @param c The first vertex of the triangle.
|
||||
static ai_real heron( ai_real a, ai_real b, ai_real c );
|
||||
|
||||
/// @brief Will compute the distance between 2 3D-vectors
|
||||
|
|
|
@ -486,7 +486,7 @@ aiReturn aiMaterial::AddBinaryProperty(const void *pInput,
|
|||
memcpy(pcNew->mData, pInput, pSizeInBytes);
|
||||
|
||||
pcNew->mKey.length = static_cast<ai_uint32>(::strlen(pKey));
|
||||
ai_assert(MAXLEN > pcNew->mKey.length);
|
||||
ai_assert(AI_MAXLEN > pcNew->mKey.length);
|
||||
strcpy(pcNew->mKey.data, pKey);
|
||||
|
||||
if (UINT_MAX != iOutIndex) {
|
||||
|
|
|
@ -185,9 +185,9 @@ bool CalcTangentsProcess::ProcessMesh(aiMesh *pMesh, unsigned int meshIndex) {
|
|||
tangent.x = (w.x * sy - v.x * ty) * dirCorrection;
|
||||
tangent.y = (w.y * sy - v.y * ty) * dirCorrection;
|
||||
tangent.z = (w.z * sy - v.z * ty) * dirCorrection;
|
||||
bitangent.x = (- w.x * sx + v.x * tx) * dirCorrection;
|
||||
bitangent.y = (- w.y * sx + v.y * tx) * dirCorrection;
|
||||
bitangent.z = (- w.z * sx + v.z * tx) * dirCorrection;
|
||||
bitangent.x = (w.x * sx - v.x * tx) * dirCorrection;
|
||||
bitangent.y = (w.y * sx - v.y * tx) * dirCorrection;
|
||||
bitangent.z = (w.z * sx - v.z * tx) * dirCorrection;
|
||||
|
||||
// store for every vertex of that face
|
||||
for (unsigned int b = 0; b < face.mNumIndices; ++b) {
|
||||
|
@ -195,7 +195,7 @@ bool CalcTangentsProcess::ProcessMesh(aiMesh *pMesh, unsigned int meshIndex) {
|
|||
|
||||
// project tangent and bitangent into the plane formed by the vertex' normal
|
||||
aiVector3D localTangent = tangent - meshNorm[p] * (tangent * meshNorm[p]);
|
||||
aiVector3D localBitangent = bitangent - meshNorm[p] * (bitangent * meshNorm[p]) - localTangent * (bitangent * localTangent);
|
||||
aiVector3D localBitangent = bitangent - meshNorm[p] * (bitangent * meshNorm[p]);
|
||||
localTangent.NormalizeSafe();
|
||||
localBitangent.NormalizeSafe();
|
||||
|
||||
|
|
|
@ -53,7 +53,8 @@ namespace Assimp {
|
|||
|
||||
// ------------------------------------------------------------------------------------------------
|
||||
// Constructor to be privately used by Importer
|
||||
LimitBoneWeightsProcess::LimitBoneWeightsProcess() : mMaxWeights(AI_LMW_MAX_WEIGHTS) {
|
||||
LimitBoneWeightsProcess::LimitBoneWeightsProcess() :
|
||||
mMaxWeights(AI_LMW_MAX_WEIGHTS), mRemoveEmptyBones(true) {
|
||||
// empty
|
||||
}
|
||||
|
||||
|
|
|
@ -164,7 +164,7 @@ void OptimizeGraphProcess::CollectNewChildren(aiNode *nd, std::list<aiNode *> &n
|
|||
++it;
|
||||
}
|
||||
if (join_master && !join.empty()) {
|
||||
join_master->mName.length = ::ai_snprintf(join_master->mName.data, MAXLEN, "$MergedNode_%u", count_merged++);
|
||||
join_master->mName.length = ::ai_snprintf(join_master->mName.data, AI_MAXLEN, "$MergedNode_%u", count_merged++);
|
||||
|
||||
unsigned int out_meshes = 0;
|
||||
for (std::list<aiNode *>::const_iterator it = join.cbegin(); it != join.cend(); ++it) {
|
||||
|
|
|
@ -635,7 +635,7 @@ void PretransformVertices::Execute(aiScene *pScene) {
|
|||
aiNode *pcNode = new aiNode();
|
||||
*nodes = pcNode;
|
||||
pcNode->mParent = pScene->mRootNode;
|
||||
pcNode->mName.length = ai_snprintf(pcNode->mName.data, MAXLEN, "light_%u", i);
|
||||
pcNode->mName.length = ai_snprintf(pcNode->mName.data, AI_MAXLEN, "light_%u", i);
|
||||
pScene->mLights[i]->mName = pcNode->mName;
|
||||
}
|
||||
// generate camera nodes
|
||||
|
@ -643,7 +643,7 @@ void PretransformVertices::Execute(aiScene *pScene) {
|
|||
aiNode *pcNode = new aiNode();
|
||||
*nodes = pcNode;
|
||||
pcNode->mParent = pScene->mRootNode;
|
||||
pcNode->mName.length = ::ai_snprintf(pcNode->mName.data, MAXLEN, "cam_%u", i);
|
||||
pcNode->mName.length = ::ai_snprintf(pcNode->mName.data, AI_MAXLEN, "cam_%u", i);
|
||||
pScene->mCameras[i]->mName = pcNode->mName;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -176,7 +176,7 @@ void RemoveRedundantMatsProcess::Execute( aiScene* pScene) {
|
|||
if (ppcMaterials[idx]) {
|
||||
aiString sz;
|
||||
if( ppcMaterials[idx]->Get(AI_MATKEY_NAME, sz) != AI_SUCCESS ) {
|
||||
sz.length = ::ai_snprintf(sz.data,MAXLEN,"JoinedMaterial_#%u",p);
|
||||
sz.length = ::ai_snprintf(sz.data, AI_MAXLEN,"JoinedMaterial_#%u",p);
|
||||
((aiMaterial*)ppcMaterials[idx])->AddProperty(&sz,AI_MATKEY_NAME);
|
||||
}
|
||||
} else {
|
||||
|
|
|
@ -394,7 +394,7 @@ void SplitByBoneCountProcess::SplitMesh( const aiMesh* pMesh, std::vector<aiMesh
|
|||
// Recursively updates the node's mesh list to account for the changed mesh list
|
||||
void SplitByBoneCountProcess::UpdateNode( aiNode* pNode) const {
|
||||
// rebuild the node's mesh index list
|
||||
if( pNode->mNumMeshes == 0 ) {
|
||||
if( pNode->mNumMeshes != 0 ) {
|
||||
IndexArray newMeshList;
|
||||
for( unsigned int a = 0; a < pNode->mNumMeshes; ++a) {
|
||||
unsigned int srcIndex = pNode->mMeshes[a];
|
||||
|
|
|
@ -390,8 +390,8 @@ void TextureTransformStep::Execute( aiScene* pScene) {
|
|||
cnt = 0;
|
||||
for (it = trafo.begin();it != trafo.end(); ++it,++cnt) {
|
||||
if ((*it).lockedPos != AI_TT_UV_IDX_LOCK_NONE && (*it).lockedPos != cnt) {
|
||||
it2 = trafo.begin();unsigned int t = 0;
|
||||
while (t != (*it).lockedPos)
|
||||
it2 = trafo.begin();
|
||||
while ((*it2).lockedPos != (*it).lockedPos)
|
||||
++it2;
|
||||
|
||||
if ((*it2).lockedPos != AI_TT_UV_IDX_LOCK_NONE) {
|
||||
|
|
|
@ -909,9 +909,9 @@ void ValidateDSProcess::Validate(const aiNode *pNode) {
|
|||
|
||||
// ------------------------------------------------------------------------------------------------
|
||||
void ValidateDSProcess::Validate(const aiString *pString) {
|
||||
if (pString->length > MAXLEN) {
|
||||
if (pString->length > AI_MAXLEN) {
|
||||
ReportError("aiString::length is too large (%u, maximum is %lu)",
|
||||
pString->length, MAXLEN);
|
||||
pString->length, AI_MAXLEN);
|
||||
}
|
||||
const char *sz = pString->data;
|
||||
while (true) {
|
||||
|
@ -920,7 +920,7 @@ void ValidateDSProcess::Validate(const aiString *pString) {
|
|||
ReportError("aiString::data is invalid: the terminal zero is at a wrong offset");
|
||||
}
|
||||
break;
|
||||
} else if (sz >= &pString->data[MAXLEN]) {
|
||||
} else if (sz >= &pString->data[AI_MAXLEN]) {
|
||||
ReportError("aiString::data is invalid. There is no terminal character");
|
||||
}
|
||||
++sz;
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
#include "revision.h"
|
||||
#include <assimp/revision.h>
|
||||
#ifdef __GNUC__
|
||||
#include "winresrc.h"
|
||||
#else
|
||||
|
|
|
@ -1,21 +1,23 @@
|
|||
_**Contents**_
|
||||
|
||||
* [CMake Basics](#cmake-basics)
|
||||
* [Mac OS X](#mac-os-x)
|
||||
* [Windows](#windows)
|
||||
* [CMake Build Configuration](#cmake-build-configuration)
|
||||
* [Transcoder](#transcoder)
|
||||
* [Debugging and Optimization](#debugging-and-optimization)
|
||||
* [Googletest Integration](#googletest-integration)
|
||||
* [Third Party Libraries](#third-party-libraries)
|
||||
* [Javascript Encoder/Decoder](#javascript-encoderdecoder)
|
||||
* [WebAssembly Decoder](#webassembly-decoder)
|
||||
* [WebAssembly Mesh Only Decoder](#webassembly-mesh-only-decoder)
|
||||
* [WebAssembly Point Cloud Only Decoder](#webassembly-point-cloud-only-decoder)
|
||||
* [iOS Builds](#ios-builds)
|
||||
* [Android Studio Project Integration](#android-studio-project-integration)
|
||||
* [Native Android Builds](#native-android-builds)
|
||||
* [vcpkg](#vcpkg)
|
||||
- [Building](#building)
|
||||
- [CMake Basics](#cmake-basics)
|
||||
- [Mac OS X](#mac-os-x)
|
||||
- [Windows](#windows)
|
||||
- [CMake Build Configuration](#cmake-build-configuration)
|
||||
- [Transcoder](#transcoder)
|
||||
- [Debugging and Optimization](#debugging-and-optimization)
|
||||
- [Googletest Integration](#googletest-integration)
|
||||
- [Third Party Libraries](#third-party-libraries)
|
||||
- [WebAssembly Decoder](#webassembly-decoder)
|
||||
- [WebAssembly Mesh Only Decoder](#webassembly-mesh-only-decoder)
|
||||
- [WebAssembly Point Cloud Only Decoder](#webassembly-point-cloud-only-decoder)
|
||||
- [Javascript Encoder/Decoder](#javascript-encoderdecoder)
|
||||
- [iOS Builds](#ios-builds)
|
||||
- [Native Android Builds](#native-android-builds)
|
||||
- [Android Studio Project Integration](#android-studio-project-integration)
|
||||
- [Draco - Static Library](#draco---static-library)
|
||||
- [vcpkg](#vcpkg)
|
||||
|
||||
Building
|
||||
========
|
||||
|
@ -325,7 +327,7 @@ Draco - Static Library
|
|||
|
||||
To include Draco in an existing or new Android Studio project, reference it
|
||||
from the `cmake` file of an existing native project that has a minimum SDK
|
||||
version of 18 or higher. The project must support C++11.
|
||||
version of 18 or higher. The project must support C++11 at least.
|
||||
To add Draco to your project:
|
||||
|
||||
1. Create a new "Native C++" project.
|
||||
|
|
|
@ -0,0 +1 @@
|
|||
*.h linguist-language=C
|
|
@ -0,0 +1,60 @@
|
|||
/build/
|
||||
/test/build/
|
||||
/xcodeproj/
|
||||
/infer-out/
|
||||
.vscode/
|
||||
Testing/
|
||||
|
||||
# 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/
|
||||
|
|
@ -1,18 +0,0 @@
|
|||
#!/bin/bash
|
||||
#
|
||||
# Build script for travis-ci.org builds.
|
||||
#
|
||||
if [ $ANALYZE = "true" ] && [ "$CC" = "clang" ]; then
|
||||
# scan-build -h
|
||||
scan-build cmake -G "Unix Makefiles"
|
||||
scan-build -enable-checker security.FloatLoopCounter \
|
||||
-enable-checker security.insecureAPI.UncheckedReturn \
|
||||
--status-bugs -v \
|
||||
make -j 8 \
|
||||
make -j 8 test
|
||||
else
|
||||
cmake -DCMAKE_BUILD_TYPE=Debug -DSANITIZE_ADDRESS=On -DCMAKE_INSTALL_PREFIX=_install
|
||||
make -j 8
|
||||
make install
|
||||
ASAN_OPTIONS=detect_leaks=0 LSAN_OPTIONS=verbosity=1:log_threads=1 ctest -V
|
||||
fi
|
|
@ -1,22 +0,0 @@
|
|||
language: c
|
||||
addons:
|
||||
apt:
|
||||
packages: &1
|
||||
- lcov
|
||||
# Compiler selection
|
||||
compiler:
|
||||
- clang
|
||||
- gcc
|
||||
env:
|
||||
- ANALYZE=false
|
||||
- ANALYZE=true
|
||||
# Build steps
|
||||
script:
|
||||
- ./.travis.sh
|
||||
after_success:
|
||||
# Creating report
|
||||
- cmake -DENABLE_COVERAGE=ON
|
||||
- make
|
||||
- make test
|
||||
# Uploading report to CodeCov
|
||||
- bash <(curl -s https://codecov.io/bash)
|
|
@ -1,27 +1,47 @@
|
|||
cmake_minimum_required(VERSION 3.4)
|
||||
cmake_minimum_required(VERSION 3.14)
|
||||
|
||||
project(zip
|
||||
LANGUAGES C
|
||||
VERSION "0.1.19")
|
||||
VERSION "0.3.0")
|
||||
set(CMAKE_MODULE_PATH "${PROJECT_SOURCE_DIR}/cmake" ${CMAKE_MODULE_PATH})
|
||||
set(CMAKE_VERBOSE_MAKEFILE ON)
|
||||
option(CMAKE_DISABLE_TESTING "Disable test creation" OFF)
|
||||
|
||||
# Enable building tests only if the project is being built as a standalone one
|
||||
if (CMAKE_CURRENT_SOURCE_DIR STREQUAL CMAKE_SOURCE_DIR)
|
||||
option(CMAKE_DISABLE_TESTING "Disable test creation" OFF)
|
||||
else ()
|
||||
option(CMAKE_DISABLE_TESTING "Disable test creation" ON)
|
||||
endif ()
|
||||
|
||||
option(CMAKE_ENABLE_SANITIZERS "Enable zip sanitizers" OFF)
|
||||
option(ZIP_STATIC_PIC "Build static zip with PIC" ON)
|
||||
option(ZIP_BUILD_DOCS "Generate API documentation with Doxygen" OFF)
|
||||
|
||||
if(ZIP_ENABLE_SHARABLE_FILE_OPEN)
|
||||
add_definitions(-DZIP_ENABLE_SHARABLE_FILE_OPEN)
|
||||
endif()
|
||||
|
||||
if(CMAKE_SIZEOF_VOID_P EQUAL 4)
|
||||
# large file support
|
||||
add_definitions(-D_LARGEFILE_SOURCE -D_FILE_OFFSET_BITS=64)
|
||||
endif()
|
||||
|
||||
# zip
|
||||
set(SRC src/miniz.h src/zip.h src/zip.c)
|
||||
|
||||
# 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)
|
||||
add_library(${PROJECT_NAME} ${SRC})
|
||||
add_library(${PROJECT_NAME}::${PROJECT_NAME} ALIAS ${PROJECT_NAME})
|
||||
|
||||
# static and shared libraries built from the same object files
|
||||
if (BUILD_SHARED_LIBS)
|
||||
add_library(${PROJECT_NAME} SHARED $<TARGET_OBJECTS:OBJLIB>)
|
||||
include(GenerateExportHeader)
|
||||
generate_export_header(${PROJECT_NAME})
|
||||
else()
|
||||
add_library(${PROJECT_NAME} STATIC $<TARGET_OBJECTS:OBJLIB>)
|
||||
if(ZIP_STATIC_PIC)
|
||||
set_property(TARGET ${PROJECT_NAME} PROPERTY POSITION_INDEPENDENT_CODE 1)
|
||||
endif()
|
||||
|
||||
set_property(TARGET ${PROJECT_NAME} PROPERTY C_VISIBILITY_PRESET hidden)
|
||||
if(BUILD_SHARED_LIBS)
|
||||
target_compile_definitions(${PROJECT_NAME}
|
||||
PUBLIC ZIP_SHARED
|
||||
PRIVATE ZIP_BUILD_SHARED
|
||||
)
|
||||
endif()
|
||||
|
||||
target_include_directories(${PROJECT_NAME} PUBLIC
|
||||
|
@ -33,24 +53,26 @@ target_include_directories(${PROJECT_NAME} PUBLIC
|
|||
if (NOT CMAKE_DISABLE_TESTING)
|
||||
enable_testing()
|
||||
add_subdirectory(test)
|
||||
endif()
|
||||
if (CMAKE_ENABLE_SANITIZERS)
|
||||
find_package(Sanitizers)
|
||||
add_sanitizers(${PROJECT_NAME} ${test_out})
|
||||
add_sanitizers(${PROJECT_NAME})
|
||||
endif()
|
||||
|
||||
set(CMAKE_C_STANDARD 90)
|
||||
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")
|
||||
set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -Wall -Wextra -Werror -pedantic")
|
||||
endif (MSVC)
|
||||
|
||||
####
|
||||
# Installation (https://github.com/forexample/package-example) {
|
||||
|
||||
set(CONFIG_INSTALL_DIR "lib/cmake/${PROJECT_NAME}")
|
||||
set(INCLUDE_INSTALL_DIR "include")
|
||||
|
||||
|
@ -62,7 +84,7 @@ set(PROJECT_CONFIG "${GENERATED_DIR}/${PROJECT_NAME}Config.cmake")
|
|||
set(TARGETS_EXPORT_NAME "${PROJECT_NAME}Targets")
|
||||
set(NAMESPACE "${PROJECT_NAME}::")
|
||||
|
||||
# Include module with fuction 'write_basic_package_version_file'
|
||||
# Include module with function 'write_basic_package_version_file'
|
||||
include(CMakePackageConfigHelpers)
|
||||
|
||||
# Note: PROJECT_VERSION is used as a VERSION
|
||||
|
@ -90,8 +112,6 @@ install(
|
|||
DESTINATION "${CONFIG_INSTALL_DIR}"
|
||||
)
|
||||
|
||||
# }
|
||||
|
||||
install(TARGETS ${PROJECT_NAME}
|
||||
EXPORT ${TARGETS_EXPORT_NAME}
|
||||
RUNTIME DESTINATION bin
|
||||
|
@ -112,8 +132,8 @@ if(NOT TARGET uninstall)
|
|||
COMMAND ${CMAKE_COMMAND} -P ${CMAKE_CURRENT_BINARY_DIR}/cmake/cmake_uninstall.cmake)
|
||||
endif()
|
||||
|
||||
find_package(Doxygen)
|
||||
if(DOXYGEN_FOUND)
|
||||
if(ZIP_BUILD_DOCS)
|
||||
find_package(Doxygen REQUIRED)
|
||||
configure_file(${CMAKE_CURRENT_SOURCE_DIR}/Doxyfile.in ${CMAKE_CURRENT_BINARY_DIR}/Doxyfile @ONLY)
|
||||
add_custom_target(doc
|
||||
${DOXYGEN_EXECUTABLE} ${CMAKE_CURRENT_BINARY_DIR}/Doxyfile
|
||||
|
|
|
@ -0,0 +1,9 @@
|
|||
# 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
|
||||
```
|
File diff suppressed because it is too large
Load Diff
|
@ -1,23 +1,25 @@
|
|||
### A portable (OSX/Linux/Windows), simple zip library written in C
|
||||
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.
|
||||
## A portable (OSX/Linux/Windows/Android/iOS), simple zip library written in C
|
||||
|
||||
This is done by hacking awesome [miniz](https://github.com/richgel999/miniz) library and layering functions on top of the miniz v3.0.2 API.
|
||||
|
||||
[![Build](https://github.com/kuba--/zip/workflows/build/badge.svg)](https://github.com/kuba--/zip/actions?query=workflow%3Abuild)
|
||||
|
||||
### The Idea
|
||||
|
||||
# The Idea
|
||||
<img src="zip.png" name="zip" />
|
||||
... Some day, I was looking for zip library written in C for my project, but I could not find anything simple enough and lightweight.
|
||||
Everything what I tried required 'crazy mental gymnastics' to integrate or had some limitations or was too heavy.
|
||||
I hate frameworks, factories and adding new dependencies. If I must to install all those dependencies and link new library, I'm getting almost sick.
|
||||
I wanted something powerfull and small enough, so I could add just a few files and compile them into my project.
|
||||
I wanted something powerful and small enough, so I could add just a few files and compile them into my project.
|
||||
And finally I found miniz.
|
||||
Miniz is a lossless, high performance data compression library in a single source file. I only needed simple interface to append buffers or files to the current zip-entry. Thanks to this feature I'm able to merge many files/buffers and compress them on-the-fly.
|
||||
|
||||
It was the reason, why I decided to write zip module on top of the miniz. It required a little bit hacking and wrapping some functions, but I kept simplicity. So, you can grab these 3 files and compile them into your project. I hope that interface is also extremely simple, so you will not have any problems to understand it.
|
||||
|
||||
# Examples
|
||||
### Examples
|
||||
|
||||
* Create a new zip archive with default compression level.
|
||||
|
||||
```c
|
||||
struct zip_t *zip = zip_open("foo.zip", ZIP_DEFAULT_COMPRESSION_LEVEL, 'w');
|
||||
{
|
||||
|
@ -41,6 +43,7 @@ zip_close(zip);
|
|||
```
|
||||
|
||||
* Append to the existing zip archive.
|
||||
|
||||
```c
|
||||
struct zip_t *zip = zip_open("foo.zip", ZIP_DEFAULT_COMPRESSION_LEVEL, 'a');
|
||||
{
|
||||
|
@ -55,6 +58,7 @@ zip_close(zip);
|
|||
```
|
||||
|
||||
* Extract a zip archive into a folder.
|
||||
|
||||
```c
|
||||
int on_extract_entry(const char *filename, void *arg) {
|
||||
static int i = 0;
|
||||
|
@ -69,6 +73,7 @@ zip_extract("foo.zip", "/tmp", on_extract_entry, &arg);
|
|||
```
|
||||
|
||||
* Extract a zip entry into memory.
|
||||
|
||||
```c
|
||||
void *buf = NULL;
|
||||
size_t bufsize;
|
||||
|
@ -87,6 +92,7 @@ free(buf);
|
|||
```
|
||||
|
||||
* Extract a zip entry into memory (no internal allocation).
|
||||
|
||||
```c
|
||||
unsigned char *buf;
|
||||
size_t bufsize;
|
||||
|
@ -108,6 +114,7 @@ free(buf);
|
|||
```
|
||||
|
||||
* Extract a zip entry into memory using callback.
|
||||
|
||||
```c
|
||||
struct buffer_t {
|
||||
char *data;
|
||||
|
@ -140,8 +147,8 @@ zip_close(zip);
|
|||
free(buf.data);
|
||||
```
|
||||
|
||||
|
||||
* Extract a zip entry into a file.
|
||||
|
||||
```c
|
||||
struct zip_t *zip = zip_open("foo.zip", 0, 'r');
|
||||
{
|
||||
|
@ -181,7 +188,7 @@ free(outbuf);
|
|||
|
||||
```c
|
||||
char *buf = NULL;
|
||||
ssize_t bufsize = 0;
|
||||
size_t bufsize = 0;
|
||||
|
||||
struct zip_t *zip = zip_stream_open(zipstream, zipstreamsize, 0, 'r');
|
||||
{
|
||||
|
@ -197,6 +204,7 @@ free(buf);
|
|||
```
|
||||
|
||||
* List of all zip entries
|
||||
|
||||
```c
|
||||
struct zip_t *zip = zip_open("foo.zip", 0, 'r');
|
||||
int i, n = zip_entries_total(zip);
|
||||
|
@ -214,6 +222,7 @@ zip_close(zip);
|
|||
```
|
||||
|
||||
* Compress folder (recursively)
|
||||
|
||||
```c
|
||||
void zip_walk(struct zip_t *zip, const char *path) {
|
||||
DIR *dir;
|
||||
|
@ -245,27 +254,36 @@ void zip_walk(struct zip_t *zip, const char *path) {
|
|||
}
|
||||
```
|
||||
|
||||
* Deletes zip archive entries.
|
||||
* Delete zip archive entries.
|
||||
|
||||
```c
|
||||
char *entries[] = {"unused.txt", "remove.ini", "delete.me"};
|
||||
// size_t indices[] = {0, 1, 2};
|
||||
|
||||
struct zip_t *zip = zip_open("foo.zip", 0, 'd');
|
||||
{
|
||||
zip_entries_delete(zip, entries, 3);
|
||||
|
||||
// you can also delete by index, instead of by name
|
||||
// zip_entries_deletebyindex(zip, indices, 3);
|
||||
}
|
||||
zip_close(zip);
|
||||
```
|
||||
|
||||
# Bindings
|
||||
### Bindings
|
||||
|
||||
Compile zip library as a dynamic library.
|
||||
|
||||
```shell
|
||||
$ mkdir build
|
||||
$ cd build
|
||||
$ cmake -DBUILD_SHARED_LIBS=true ..
|
||||
$ make
|
||||
$ cmake --build .
|
||||
```
|
||||
|
||||
### [Go](https://golang.org) (cgo)
|
||||
#### [Go](https://golang.org) (cgo)
|
||||
> Third party binding: [kuba--/c-go-zip](https://github.com/kuba--/c-go-zip)
|
||||
|
||||
```go
|
||||
package main
|
||||
|
||||
|
@ -295,7 +313,8 @@ func main() {
|
|||
}
|
||||
```
|
||||
|
||||
### [Rust](https://www.rust-lang.org) (ffi)
|
||||
#### [Rust](https://www.rust-lang.org) (ffi)
|
||||
|
||||
```rust
|
||||
extern crate libc;
|
||||
use std::ffi::CString;
|
||||
|
@ -342,13 +361,16 @@ fn main() {
|
|||
}
|
||||
```
|
||||
|
||||
### [Ruby](http://www.ruby-lang.org) (ffi)
|
||||
#### [Ruby](http://www.ruby-lang.org) (ffi)
|
||||
|
||||
Install _ffi_ gem.
|
||||
|
||||
```shell
|
||||
$ gem install ffi
|
||||
```
|
||||
|
||||
Bind in your module.
|
||||
|
||||
```ruby
|
||||
require 'ffi'
|
||||
|
||||
|
@ -375,13 +397,16 @@ Zip.zip_entry_close(ptr)
|
|||
Zip.zip_close(ptr)
|
||||
```
|
||||
|
||||
### [Python](https://www.python.org) (cffi)
|
||||
#### [Python](https://www.python.org) (cffi)
|
||||
|
||||
Install _cffi_ package
|
||||
|
||||
```shell
|
||||
$ pip install cffi
|
||||
```
|
||||
|
||||
Bind in your package.
|
||||
|
||||
```python
|
||||
import ctypes.util
|
||||
from cffi import FFI
|
||||
|
@ -409,7 +434,8 @@ Zip.zip_entry_close(ptr)
|
|||
Zip.zip_close(ptr)
|
||||
```
|
||||
|
||||
### [Never](https://never-lang.readthedocs.io/) (ffi)
|
||||
#### [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
|
||||
|
@ -438,8 +464,10 @@ func main() -> int
|
|||
}
|
||||
```
|
||||
|
||||
### [Ring](http://ring-lang.net)
|
||||
#### [Ring](http://ring-lang.net)
|
||||
|
||||
The language comes with RingZip based on this library
|
||||
|
||||
```ring
|
||||
load "ziplib.ring"
|
||||
|
||||
|
@ -455,15 +483,159 @@ new Zip {
|
|||
}
|
||||
```
|
||||
|
||||
# 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)
|
||||
#### [Zig](https://ziglang.org)
|
||||
|
||||
```shell
|
||||
$ zig build-exe main.zig -lc -lzip
|
||||
```
|
||||
|
||||
```zig
|
||||
const c = @cImport({
|
||||
@cInclude("zip.h");
|
||||
});
|
||||
|
||||
pub fn main() void {
|
||||
var zip = c.zip_open("/tmp/zig.zip", 6, 'w');
|
||||
defer c.zip_close(zip);
|
||||
|
||||
_ = c.zip_entry_open(zip, "test");
|
||||
defer _ = c.zip_entry_close(zip);
|
||||
|
||||
const content = "test content";
|
||||
_ = c.zip_entry_write(zip, content, content.len);
|
||||
}
|
||||
```
|
||||
|
||||
#### [Odin](https://odin-lang.org)
|
||||
> Third party binding: [thechampagne/zip-odin](https://github.com/thechampagne/zip-odin)
|
||||
|
||||
```odin
|
||||
package main
|
||||
|
||||
foreign import lib "system:zip"
|
||||
|
||||
import "core:c"
|
||||
|
||||
foreign lib {
|
||||
zip_open :: proc(zipname : cstring, level : c.int, mode : c.char) -> rawptr ---
|
||||
|
||||
zip_close :: proc(zip : rawptr) ---
|
||||
|
||||
zip_entry_open :: proc(zip : rawptr, entryname : cstring) -> c.int ---
|
||||
|
||||
zip_entry_close :: proc(zip : rawptr) -> c.int ---
|
||||
|
||||
zip_entry_write :: proc(zip : rawptr, buf : rawptr, bufsize : c.size_t) -> c.int ---
|
||||
}
|
||||
|
||||
main :: proc() {
|
||||
zip_file := zip_open("odin.zip", 6, 'w')
|
||||
defer zip_close(zip_file)
|
||||
|
||||
zip_entry_open(zip_file, "test")
|
||||
defer zip_entry_close(zip_file)
|
||||
|
||||
content := "test content"
|
||||
zip_entry_write(zip_file, &content, len(content))
|
||||
}
|
||||
```
|
||||
|
||||
#### [Nim](https://nim-lang.org)
|
||||
> Third party binding: [thechampagne/nimzip](https://github.com/thechampagne/nimzip)
|
||||
|
||||
```shell
|
||||
$ nim c --passL:-lzip main.nim
|
||||
```
|
||||
|
||||
```nim
|
||||
proc zip_open(zipname: cstring, level: cint, mode: char): pointer {.importc.}
|
||||
proc zip_close(zip: pointer) {.importc.}
|
||||
proc zip_entry_open(zip: pointer, entryname: cstring): cint {.importc.}
|
||||
proc zip_entry_close(zip: pointer): cint {.importc.}
|
||||
proc zip_entry_write(zip: pointer, buf: pointer, bufsize: csize_t): cint {.importc.}
|
||||
|
||||
when isMainModule:
|
||||
var zip = zip_open("/tmp/nim.zip", 6, 'w')
|
||||
|
||||
discard zip_entry_open(zip, "test")
|
||||
|
||||
let content: cstring = "test content"
|
||||
discard zip_entry_write(zip, content, csize_t(len(content)))
|
||||
|
||||
discard zip_entry_close(zip)
|
||||
zip_close(zip)
|
||||
```
|
||||
|
||||
#### [D](https://dlang.org)
|
||||
> Third party binding: [thechampagne/zip-d](https://github.com/thechampagne/zip-d)
|
||||
|
||||
```shell
|
||||
$ dmd -L-lzip main.d
|
||||
```
|
||||
|
||||
```d
|
||||
extern(C) void* zip_open(const(char)* zipname, int level, char mode);
|
||||
extern(C) void zip_close(void* zip);
|
||||
extern(C) int zip_entry_open(void* zip, const(char)* entryname);
|
||||
extern(C) int zip_entry_close(void* zip);
|
||||
extern(C) int zip_entry_write(void* zip, const(void)* buf, size_t bufsize);
|
||||
|
||||
void main()
|
||||
{
|
||||
void* zip = zip_open("/tmp/d.zip", 6, 'w');
|
||||
scope(exit) zip_close(zip);
|
||||
|
||||
zip_entry_open(zip, "test");
|
||||
scope(exit) zip_entry_close(zip);
|
||||
|
||||
string content = "test content";
|
||||
zip_entry_write(zip, content.ptr, content.length);
|
||||
}
|
||||
```
|
||||
|
||||
#### [Pascal](https://en.wikipedia.org/wiki/Pascal_(programming_language))
|
||||
> Third party binding: [thechampagne/zip-pascal](https://github.com/thechampagne/zip-pascal)
|
||||
|
||||
```pas
|
||||
program main;
|
||||
|
||||
{$linklib c}
|
||||
{$linklib zip}
|
||||
|
||||
uses ctypes;
|
||||
|
||||
function zip_open(zipname:Pchar; level:longint; mode:char):pointer;cdecl;external;
|
||||
procedure zip_close(zip:pointer);cdecl;external;
|
||||
function zip_entry_open(zip:pointer; entryname:Pchar):longint;cdecl;external;
|
||||
function zip_entry_close(zip:pointer):longint;cdecl;external;
|
||||
function zip_entry_write(zip:pointer; buf:pointer; bufsize:csize_t):longint;cdecl;external;
|
||||
|
||||
const
|
||||
content: Pchar = 'test content';
|
||||
var
|
||||
zip : pointer;
|
||||
|
||||
begin
|
||||
zip := zip_open('/tmp/pascal.zip', 6, 'w');
|
||||
|
||||
zip_entry_open(zip, 'test');
|
||||
|
||||
zip_entry_write(zip, content, strlen(content));
|
||||
zip_entry_close(zip);
|
||||
zip_close(zip);
|
||||
end.
|
||||
```
|
||||
|
||||
### 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.
|
||||
* [Monster Mash](https://github.com/google/monster-mash): New Sketch-Based Modeling and Animation Tool.
|
||||
* [Object-Oriented Graphics Rendering Engine](https://github.com/OGRECave/ogre): OGRE is a scene-oriented, flexible 3D engine written in C++ designed to make it easier and more intuitive for developers to produce games and demos utilising 3D hardware.
|
||||
* [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.
|
||||
* [and more...](https://grep.app/search?q=kuba--/zip)
|
||||
|
|
|
@ -1,14 +0,0 @@
|
|||
version: zip-0.1.15.{build}
|
||||
build_script:
|
||||
- cmd: >-
|
||||
cd c:\projects\zip
|
||||
|
||||
mkdir build
|
||||
|
||||
cd build
|
||||
|
||||
cmake -G"Visual Studio 14" -DCMAKE_BUILD_TYPE=Debug ..
|
||||
|
||||
cmake --build . --config %CMAKE_BUILD_TYPE%
|
||||
|
||||
ctest --verbose -C "Debug"
|
|
@ -0,0 +1,4 @@
|
|||
@PACKAGE_INIT@
|
||||
|
||||
include("${CMAKE_CURRENT_LIST_DIR}/@TARGETS_EXPORT_NAME@.cmake")
|
||||
check_required_components("@PROJECT_NAME@")
|
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
|
@ -12,9 +12,24 @@
|
|||
#ifndef ZIP_H
|
||||
#define ZIP_H
|
||||
|
||||
#include <stdint.h>
|
||||
#include <string.h>
|
||||
#include <sys/types.h>
|
||||
|
||||
#ifndef ZIP_SHARED
|
||||
#define ZIP_EXPORT
|
||||
#else
|
||||
#ifdef _WIN32
|
||||
#ifdef ZIP_BUILD_SHARED
|
||||
#define ZIP_EXPORT __declspec(dllexport)
|
||||
#else
|
||||
#define ZIP_EXPORT __declspec(dllimport)
|
||||
#endif
|
||||
#else
|
||||
#define ZIP_EXPORT __attribute__((visibility("default")))
|
||||
#endif
|
||||
#endif
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
@ -29,14 +44,10 @@ typedef long ssize_t; /* byte count or error */
|
|||
#endif
|
||||
#endif
|
||||
|
||||
#ifndef MAX_PATH
|
||||
#define MAX_PATH 32767 /* # chars in a path name including NULL */
|
||||
#endif
|
||||
|
||||
/**
|
||||
* @mainpage
|
||||
*
|
||||
* Documenation for @ref zip.
|
||||
* Documentation for @ref zip.
|
||||
*/
|
||||
|
||||
/**
|
||||
|
@ -81,6 +92,9 @@ typedef long ssize_t; /* byte count or error */
|
|||
#define ZIP_EFSEEK -27 // fseek error
|
||||
#define ZIP_EFREAD -28 // fread error
|
||||
#define ZIP_EFWRITE -29 // fwrite error
|
||||
#define ZIP_ERINIT -30 // cannot initialize reader
|
||||
#define ZIP_EWINIT -31 // cannot initialize writer
|
||||
#define ZIP_EWRINIT -32 // cannot initialize writer from reader
|
||||
|
||||
/**
|
||||
* Looks up the error message string corresponding to an error number.
|
||||
|
@ -88,7 +102,7 @@ typedef long ssize_t; /* byte count or error */
|
|||
* @return error message string corresponding to errnum or NULL if error is not
|
||||
* found.
|
||||
*/
|
||||
extern const char *zip_strerror(int errnum);
|
||||
extern ZIP_EXPORT const char *zip_strerror(int errnum);
|
||||
|
||||
/**
|
||||
* @struct zip_t
|
||||
|
@ -110,14 +124,32 @@ struct zip_t;
|
|||
*
|
||||
* @return the zip archive handler or NULL on error
|
||||
*/
|
||||
extern struct zip_t *zip_open(const char *zipname, int level, char mode);
|
||||
extern ZIP_EXPORT struct zip_t *zip_open(const char *zipname, int level,
|
||||
char mode);
|
||||
|
||||
/**
|
||||
* Opens zip archive with compression level using the given mode.
|
||||
* The function additionally returns @param errnum -
|
||||
*
|
||||
* @param zipname zip archive file name.
|
||||
* @param level compression level (0-9 are the standard zlib-style levels).
|
||||
* @param mode file access mode.
|
||||
* - 'r': opens a file for reading/extracting (the file must exists).
|
||||
* - 'w': creates an empty file for writing.
|
||||
* - 'a': appends to an existing archive.
|
||||
* @param errnum 0 on success, negative number (< 0) on error.
|
||||
*
|
||||
* @return the zip archive handler or NULL on error
|
||||
*/
|
||||
extern ZIP_EXPORT struct zip_t *
|
||||
zip_openwitherror(const char *zipname, int level, char mode, int *errnum);
|
||||
|
||||
/**
|
||||
* Closes the zip archive, releases resources - always finalize.
|
||||
*
|
||||
* @param zip zip archive handler.
|
||||
*/
|
||||
extern void zip_close(struct zip_t *zip);
|
||||
extern ZIP_EXPORT void zip_close(struct zip_t *zip);
|
||||
|
||||
/**
|
||||
* Determines if the archive has a zip64 end of central directory headers.
|
||||
|
@ -127,7 +159,7 @@ extern void zip_close(struct zip_t *zip);
|
|||
* @return the return code - 1 (true), 0 (false), negative number (< 0) on
|
||||
* error.
|
||||
*/
|
||||
extern int zip_is64(struct zip_t *zip);
|
||||
extern ZIP_EXPORT int zip_is64(struct zip_t *zip);
|
||||
|
||||
/**
|
||||
* Opens an entry by name in the zip archive.
|
||||
|
@ -141,7 +173,22 @@ extern int zip_is64(struct zip_t *zip);
|
|||
*
|
||||
* @return the return code - 0 on success, negative number (< 0) on error.
|
||||
*/
|
||||
extern int zip_entry_open(struct zip_t *zip, const char *entryname);
|
||||
extern ZIP_EXPORT int zip_entry_open(struct zip_t *zip, const char *entryname);
|
||||
|
||||
/**
|
||||
* Opens an entry by name in the zip archive.
|
||||
*
|
||||
* For zip archive opened in 'w' or 'a' mode the function will append
|
||||
* a new entry. In readonly mode the function tries to locate the entry
|
||||
* in global dictionary (case sensitive).
|
||||
*
|
||||
* @param zip zip archive handler.
|
||||
* @param entryname an entry name in local dictionary (case sensitive).
|
||||
*
|
||||
* @return the return code - 0 on success, negative number (< 0) on error.
|
||||
*/
|
||||
extern ZIP_EXPORT int zip_entry_opencasesensitive(struct zip_t *zip,
|
||||
const char *entryname);
|
||||
|
||||
/**
|
||||
* Opens a new entry by index in the zip archive.
|
||||
|
@ -153,7 +200,7 @@ extern int zip_entry_open(struct zip_t *zip, const char *entryname);
|
|||
*
|
||||
* @return the return code - 0 on success, negative number (< 0) on error.
|
||||
*/
|
||||
extern int zip_entry_openbyindex(struct zip_t *zip, int index);
|
||||
extern ZIP_EXPORT int zip_entry_openbyindex(struct zip_t *zip, size_t index);
|
||||
|
||||
/**
|
||||
* Closes a zip entry, flushes buffer and releases resources.
|
||||
|
@ -162,7 +209,7 @@ extern int zip_entry_openbyindex(struct zip_t *zip, int index);
|
|||
*
|
||||
* @return the return code - 0 on success, negative number (< 0) on error.
|
||||
*/
|
||||
extern int zip_entry_close(struct zip_t *zip);
|
||||
extern ZIP_EXPORT int zip_entry_close(struct zip_t *zip);
|
||||
|
||||
/**
|
||||
* Returns a local name of the current zip entry.
|
||||
|
@ -178,7 +225,7 @@ extern int zip_entry_close(struct zip_t *zip);
|
|||
*
|
||||
* @return the pointer to the current zip entry name, or NULL on error.
|
||||
*/
|
||||
extern const char *zip_entry_name(struct zip_t *zip);
|
||||
extern ZIP_EXPORT const char *zip_entry_name(struct zip_t *zip);
|
||||
|
||||
/**
|
||||
* Returns an index of the current zip entry.
|
||||
|
@ -187,7 +234,7 @@ extern const char *zip_entry_name(struct zip_t *zip);
|
|||
*
|
||||
* @return the index on success, negative number (< 0) on error.
|
||||
*/
|
||||
extern int zip_entry_index(struct zip_t *zip);
|
||||
extern ZIP_EXPORT ssize_t zip_entry_index(struct zip_t *zip);
|
||||
|
||||
/**
|
||||
* Determines if the current zip entry is a directory entry.
|
||||
|
@ -197,16 +244,35 @@ extern int zip_entry_index(struct zip_t *zip);
|
|||
* @return the return code - 1 (true), 0 (false), negative number (< 0) on
|
||||
* error.
|
||||
*/
|
||||
extern int zip_entry_isdir(struct zip_t *zip);
|
||||
extern ZIP_EXPORT int zip_entry_isdir(struct zip_t *zip);
|
||||
|
||||
/**
|
||||
* Returns an uncompressed size of the current zip entry.
|
||||
* Returns the uncompressed size of the current zip entry.
|
||||
* Alias for zip_entry_uncomp_size (for backward compatibility).
|
||||
*
|
||||
* @param zip zip archive handler.
|
||||
*
|
||||
* @return the uncompressed size in bytes.
|
||||
*/
|
||||
extern unsigned long long zip_entry_size(struct zip_t *zip);
|
||||
extern ZIP_EXPORT unsigned long long zip_entry_size(struct zip_t *zip);
|
||||
|
||||
/**
|
||||
* Returns the uncompressed size of the current zip entry.
|
||||
*
|
||||
* @param zip zip archive handler.
|
||||
*
|
||||
* @return the uncompressed size in bytes.
|
||||
*/
|
||||
extern ZIP_EXPORT unsigned long long zip_entry_uncomp_size(struct zip_t *zip);
|
||||
|
||||
/**
|
||||
* Returns the compressed size of the current zip entry.
|
||||
*
|
||||
* @param zip zip archive handler.
|
||||
*
|
||||
* @return the compressed size in bytes.
|
||||
*/
|
||||
extern ZIP_EXPORT unsigned long long zip_entry_comp_size(struct zip_t *zip);
|
||||
|
||||
/**
|
||||
* Returns CRC-32 checksum of the current zip entry.
|
||||
|
@ -215,7 +281,26 @@ extern unsigned long long zip_entry_size(struct zip_t *zip);
|
|||
*
|
||||
* @return the CRC-32 checksum.
|
||||
*/
|
||||
extern unsigned int zip_entry_crc32(struct zip_t *zip);
|
||||
extern ZIP_EXPORT unsigned int zip_entry_crc32(struct zip_t *zip);
|
||||
|
||||
/**
|
||||
* Returns byte offset of the current zip entry
|
||||
* in the archive's central directory.
|
||||
*
|
||||
* @param zip zip archive handler.
|
||||
*
|
||||
* @return the offset in bytes.
|
||||
*/
|
||||
extern ZIP_EXPORT unsigned long long zip_entry_dir_offset(struct zip_t *zip);
|
||||
|
||||
/**
|
||||
* Returns the current zip entry's local header file offset in bytes.
|
||||
*
|
||||
* @param zip zip archive handler.
|
||||
*
|
||||
* @return the entry's local header file offset in bytes.
|
||||
*/
|
||||
extern ZIP_EXPORT unsigned long long zip_entry_header_offset(struct zip_t *zip);
|
||||
|
||||
/**
|
||||
* Compresses an input buffer for the current zip entry.
|
||||
|
@ -226,7 +311,8 @@ extern unsigned int zip_entry_crc32(struct zip_t *zip);
|
|||
*
|
||||
* @return the return code - 0 on success, negative number (< 0) on error.
|
||||
*/
|
||||
extern int zip_entry_write(struct zip_t *zip, const void *buf, size_t bufsize);
|
||||
extern ZIP_EXPORT int zip_entry_write(struct zip_t *zip, const void *buf,
|
||||
size_t bufsize);
|
||||
|
||||
/**
|
||||
* Compresses a file for the current zip entry.
|
||||
|
@ -236,7 +322,7 @@ extern int zip_entry_write(struct zip_t *zip, const void *buf, size_t bufsize);
|
|||
*
|
||||
* @return the return code - 0 on success, negative number (< 0) on error.
|
||||
*/
|
||||
extern int zip_entry_fwrite(struct zip_t *zip, const char *filename);
|
||||
extern ZIP_EXPORT int zip_entry_fwrite(struct zip_t *zip, const char *filename);
|
||||
|
||||
/**
|
||||
* Extracts the current zip entry into output buffer.
|
||||
|
@ -251,9 +337,10 @@ extern int zip_entry_fwrite(struct zip_t *zip, const char *filename);
|
|||
* 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.
|
||||
* Otherwise a negative number (< 0) on error.
|
||||
*/
|
||||
extern ssize_t zip_entry_read(struct zip_t *zip, void **buf, size_t *bufsize);
|
||||
extern ZIP_EXPORT ssize_t zip_entry_read(struct zip_t *zip, void **buf,
|
||||
size_t *bufsize);
|
||||
|
||||
/**
|
||||
* Extracts the current zip entry into a memory buffer using no memory
|
||||
|
@ -269,9 +356,10 @@ extern ssize_t zip_entry_read(struct zip_t *zip, void **buf, size_t *bufsize);
|
|||
* 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).
|
||||
* Otherwise a negative number (< 0) on error (e.g. bufsize is not large
|
||||
* enough).
|
||||
*/
|
||||
extern ssize_t zip_entry_noallocread(struct zip_t *zip, void *buf,
|
||||
extern ZIP_EXPORT ssize_t zip_entry_noallocread(struct zip_t *zip, void *buf,
|
||||
size_t bufsize);
|
||||
|
||||
/**
|
||||
|
@ -282,7 +370,7 @@ extern ssize_t zip_entry_noallocread(struct zip_t *zip, void *buf,
|
|||
*
|
||||
* @return the return code - 0 on success, negative number (< 0) on error.
|
||||
*/
|
||||
extern int zip_entry_fread(struct zip_t *zip, const char *filename);
|
||||
extern ZIP_EXPORT int zip_entry_fread(struct zip_t *zip, const char *filename);
|
||||
|
||||
/**
|
||||
* Extracts the current zip entry using a callback function (on_extract).
|
||||
|
@ -294,9 +382,9 @@ extern int zip_entry_fread(struct zip_t *zip, const char *filename);
|
|||
*
|
||||
* @return the return code - 0 on success, negative number (< 0) on error.
|
||||
*/
|
||||
extern int
|
||||
extern ZIP_EXPORT int
|
||||
zip_entry_extract(struct zip_t *zip,
|
||||
size_t (*on_extract)(void *arg, unsigned long long offset,
|
||||
size_t (*on_extract)(void *arg, uint64_t offset,
|
||||
const void *data, size_t size),
|
||||
void *arg);
|
||||
|
||||
|
@ -308,7 +396,7 @@ 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_entries_total(struct zip_t *zip);
|
||||
extern ZIP_EXPORT ssize_t zip_entries_total(struct zip_t *zip);
|
||||
|
||||
/**
|
||||
* Deletes zip archive entries.
|
||||
|
@ -318,7 +406,19 @@ extern int zip_entries_total(struct zip_t *zip);
|
|||
* @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[],
|
||||
extern ZIP_EXPORT ssize_t zip_entries_delete(struct zip_t *zip,
|
||||
char *const entries[], size_t len);
|
||||
|
||||
/**
|
||||
* Deletes zip archive entries.
|
||||
*
|
||||
* @param zip zip archive handler.
|
||||
* @param entries array of zip archive entries indices 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 ZIP_EXPORT ssize_t zip_entries_deletebyindex(struct zip_t *zip,
|
||||
size_t entries[],
|
||||
size_t len);
|
||||
|
||||
/**
|
||||
|
@ -338,9 +438,9 @@ extern int zip_entries_delete(struct zip_t *zip, char *const entries[],
|
|||
*
|
||||
* @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),
|
||||
extern ZIP_EXPORT int
|
||||
zip_stream_extract(const char *stream, size_t size, const char *dir,
|
||||
int (*on_extract)(const char *filename, void *arg),
|
||||
void *arg);
|
||||
|
||||
/**
|
||||
|
@ -348,11 +448,36 @@ extern int zip_stream_extract(const char *stream, size_t size, const char *dir,
|
|||
*
|
||||
* @param stream zip archive stream.
|
||||
* @param size stream size.
|
||||
* @param level compression level (0-9 are the standard zlib-style levels).
|
||||
* @param mode file access mode.
|
||||
* - 'r': opens a file for reading/extracting (the file must exists).
|
||||
* - 'w': creates an empty file for writing.
|
||||
* - 'a': appends to an existing archive.
|
||||
*
|
||||
* @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);
|
||||
extern ZIP_EXPORT struct zip_t *zip_stream_open(const char *stream, size_t size,
|
||||
int level, char mode);
|
||||
|
||||
/**
|
||||
* Opens zip archive stream into memory.
|
||||
* The function additionally returns @param errnum -
|
||||
*
|
||||
* @param stream zip archive stream.
|
||||
* @param size stream size.*
|
||||
* @param level compression level (0-9 are the standard zlib-style levels).
|
||||
* @param mode file access mode.
|
||||
* - 'r': opens a file for reading/extracting (the file must exists).
|
||||
* - 'w': creates an empty file for writing.
|
||||
* - 'a': appends to an existing archive.
|
||||
* @param errnum 0 on success, negative number (< 0) on error.
|
||||
*
|
||||
* @return the zip archive handler or NULL on error
|
||||
*/
|
||||
extern ZIP_EXPORT struct zip_t *zip_stream_openwitherror(const char *stream,
|
||||
size_t size, int level,
|
||||
char mode,
|
||||
int *errnum);
|
||||
|
||||
/**
|
||||
* Copy zip archive stream output buffer.
|
||||
|
@ -363,7 +488,8 @@ extern struct zip_t *zip_stream_open(const char *stream, size_t size, int level,
|
|||
*
|
||||
* @return copy size
|
||||
*/
|
||||
extern ssize_t zip_stream_copy(struct zip_t *zip, void **buf, ssize_t *bufsize);
|
||||
extern ZIP_EXPORT ssize_t zip_stream_copy(struct zip_t *zip, void **buf,
|
||||
size_t *bufsize);
|
||||
|
||||
/**
|
||||
* Close zip archive releases resources.
|
||||
|
@ -372,7 +498,7 @@ extern ssize_t zip_stream_copy(struct zip_t *zip, void **buf, ssize_t *bufsize);
|
|||
*
|
||||
* @return
|
||||
*/
|
||||
extern void zip_stream_close(struct zip_t *zip);
|
||||
extern ZIP_EXPORT void zip_stream_close(struct zip_t *zip);
|
||||
|
||||
/**
|
||||
* Creates a new archive and puts files into a single zip archive.
|
||||
|
@ -383,7 +509,8 @@ extern void zip_stream_close(struct zip_t *zip);
|
|||
*
|
||||
* @return the return code - 0 on success, negative number (< 0) on error.
|
||||
*/
|
||||
extern int zip_create(const char *zipname, const char *filenames[], size_t len);
|
||||
extern ZIP_EXPORT int zip_create(const char *zipname, const char *filenames[],
|
||||
size_t len);
|
||||
|
||||
/**
|
||||
* Extracts a zip archive file into directory.
|
||||
|
@ -401,10 +528,10 @@ extern int zip_create(const char *zipname, const char *filenames[], size_t len);
|
|||
*
|
||||
* @return the return code - 0 on success, negative number (< 0) on error.
|
||||
*/
|
||||
extern int zip_extract(const char *zipname, const char *dir,
|
||||
int (*on_extract_entry)(const char *filename, void *arg),
|
||||
extern ZIP_EXPORT int zip_extract(const char *zipname, const char *dir,
|
||||
int (*on_extract_entry)(const char *filename,
|
||||
void *arg),
|
||||
void *arg);
|
||||
|
||||
/** @} */
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
|
|
|
@ -1,38 +1,46 @@
|
|||
cmake_minimum_required(VERSION 3.4)
|
||||
cmake_minimum_required(VERSION 3.14)
|
||||
|
||||
find_package(Sanitizers)
|
||||
|
||||
# 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_sanitizers(${test_write_out})
|
||||
|
||||
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_sanitizers(${test_append_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)
|
||||
add_sanitizers(${test_read_out})
|
||||
|
||||
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)
|
||||
add_sanitizers(${test_extract_out})
|
||||
|
||||
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)
|
||||
add_sanitizers(${test_entry_out})
|
||||
|
||||
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)
|
||||
add_sanitizers(${test_permissions_out})
|
||||
|
||||
set(test_open_out test_open.out)
|
||||
add_executable(${test_open_out} test_open.c)
|
||||
target_link_libraries(${test_open_out} zip)
|
||||
add_test(NAME ${test_open_out} COMMAND ${test_open_out})
|
||||
add_sanitizers(${test_open_out})
|
||||
|
|
|
@ -0,0 +1,370 @@
|
|||
/*
|
||||
* Copyright (c) 2012 David Siñuela Pastor, siu.4coders@gmail.com
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person obtaining
|
||||
* a copy of this software and associated documentation files (the
|
||||
* "Software"), to deal in the Software without restriction, including
|
||||
* without limitation the rights to use, copy, modify, merge, publish,
|
||||
* distribute, sublicense, and/or sell copies of the Software, and to
|
||||
* permit persons to whom the Software is furnished to do so, subject to
|
||||
* the following conditions:
|
||||
*
|
||||
* The above copyright notice and this permission notice shall be
|
||||
* included in all copies or substantial portions of the Software.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
|
||||
* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
|
||||
* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
|
||||
* NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
|
||||
* LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
|
||||
* OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
|
||||
* WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
||||
*/
|
||||
#ifndef MINUNIT_MINUNIT_H
|
||||
#define MINUNIT_MINUNIT_H
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
#if defined(_WIN32)
|
||||
#include <Windows.h>
|
||||
#if defined(_MSC_VER) && _MSC_VER < 1900
|
||||
#define snprintf _snprintf
|
||||
#define __func__ __FUNCTION__
|
||||
#endif
|
||||
|
||||
#elif defined(__unix__) || defined(__unix) || defined(unix) || \
|
||||
(defined(__APPLE__) && defined(__MACH__))
|
||||
|
||||
/* Change POSIX C SOURCE version for pure c99 compilers */
|
||||
#if !defined(_POSIX_C_SOURCE) || _POSIX_C_SOURCE < 200112L
|
||||
#undef _POSIX_C_SOURCE
|
||||
#define _POSIX_C_SOURCE 200112L
|
||||
#endif
|
||||
|
||||
#include <string.h>
|
||||
#include <sys/resource.h>
|
||||
#include <sys/time.h> /* gethrtime(), gettimeofday() */
|
||||
#include <sys/times.h>
|
||||
#include <time.h> /* clock_gettime(), time() */
|
||||
#include <unistd.h> /* POSIX flags */
|
||||
|
||||
#if defined(__MACH__) && defined(__APPLE__)
|
||||
#include <mach/mach.h>
|
||||
#include <mach/mach_time.h>
|
||||
#endif
|
||||
|
||||
#if __GNUC__ >= 5 && !defined(__STDC_VERSION__)
|
||||
#define __func__ __extension__ __FUNCTION__
|
||||
#endif
|
||||
|
||||
#else
|
||||
#error "Unable to define timers for an unknown OS."
|
||||
#endif
|
||||
|
||||
#include <math.h>
|
||||
#include <stdio.h>
|
||||
|
||||
/* Maximum length of last message */
|
||||
#define MINUNIT_MESSAGE_LEN 1024
|
||||
/* Accuracy with which floats are compared */
|
||||
#define MINUNIT_EPSILON 1E-12
|
||||
|
||||
/* Misc. counters */
|
||||
static int minunit_run = 0;
|
||||
static int minunit_assert = 0;
|
||||
static int minunit_fail = 0;
|
||||
static int minunit_status = 0;
|
||||
|
||||
/* Timers */
|
||||
static double minunit_real_timer = 0;
|
||||
static double minunit_proc_timer = 0;
|
||||
|
||||
/* Last message */
|
||||
static char minunit_last_message[MINUNIT_MESSAGE_LEN];
|
||||
|
||||
/* Test setup and teardown function pointers */
|
||||
static void (*minunit_setup)(void) = NULL;
|
||||
static void (*minunit_teardown)(void) = NULL;
|
||||
|
||||
/* Definitions */
|
||||
#define MU_TEST(method_name) static void method_name(void)
|
||||
#define MU_TEST_SUITE(suite_name) static void suite_name(void)
|
||||
|
||||
#define MU__SAFE_BLOCK(block) \
|
||||
do { \
|
||||
block \
|
||||
} while (0)
|
||||
|
||||
/* Run test suite and unset setup and teardown functions */
|
||||
#define MU_RUN_SUITE(suite_name) \
|
||||
MU__SAFE_BLOCK(suite_name(); minunit_setup = NULL; minunit_teardown = NULL;)
|
||||
|
||||
/* Configure setup and teardown functions */
|
||||
#define MU_SUITE_CONFIGURE(setup_fun, teardown_fun) \
|
||||
MU__SAFE_BLOCK(minunit_setup = setup_fun; minunit_teardown = teardown_fun;)
|
||||
|
||||
/* Test runner */
|
||||
#define MU_RUN_TEST(test) \
|
||||
MU__SAFE_BLOCK( \
|
||||
if (minunit_real_timer == 0 && minunit_proc_timer == 0) { \
|
||||
minunit_real_timer = mu_timer_real(); \
|
||||
minunit_proc_timer = mu_timer_cpu(); \
|
||||
} if (minunit_setup) (*minunit_setup)(); \
|
||||
minunit_status = 0; test(); minunit_run++; if (minunit_status) { \
|
||||
minunit_fail++; \
|
||||
printf("F"); \
|
||||
printf("\n%s\n", minunit_last_message); \
|
||||
} fflush(stdout); \
|
||||
if (minunit_teardown)(*minunit_teardown)();)
|
||||
|
||||
/* Report */
|
||||
#define MU_REPORT() \
|
||||
MU__SAFE_BLOCK( \
|
||||
double minunit_end_real_timer; double minunit_end_proc_timer; \
|
||||
printf("\n\n%d tests, %d assertions, %d failures\n", minunit_run, \
|
||||
minunit_assert, minunit_fail); \
|
||||
minunit_end_real_timer = mu_timer_real(); \
|
||||
minunit_end_proc_timer = mu_timer_cpu(); \
|
||||
printf("\nFinished in %.8f seconds (real) %.8f seconds (proc)\n\n", \
|
||||
minunit_end_real_timer - minunit_real_timer, \
|
||||
minunit_end_proc_timer - minunit_proc_timer);)
|
||||
#define MU_EXIT_CODE minunit_fail
|
||||
|
||||
/* Assertions */
|
||||
#define mu_check(test) \
|
||||
MU__SAFE_BLOCK( \
|
||||
minunit_assert++; if (!(test)) { \
|
||||
snprintf(minunit_last_message, MINUNIT_MESSAGE_LEN, \
|
||||
"%s failed:\n\t%s:%d: %s", __func__, __FILE__, __LINE__, \
|
||||
#test); \
|
||||
minunit_status = 1; \
|
||||
return; \
|
||||
} else { printf("."); })
|
||||
|
||||
#define mu_fail(message) \
|
||||
MU__SAFE_BLOCK(minunit_assert++; \
|
||||
snprintf(minunit_last_message, MINUNIT_MESSAGE_LEN, \
|
||||
"%s failed:\n\t%s:%d: %s", __func__, __FILE__, \
|
||||
__LINE__, message); \
|
||||
minunit_status = 1; return;)
|
||||
|
||||
#define mu_assert(test, message) \
|
||||
MU__SAFE_BLOCK( \
|
||||
minunit_assert++; if (!(test)) { \
|
||||
snprintf(minunit_last_message, MINUNIT_MESSAGE_LEN, \
|
||||
"%s failed:\n\t%s:%d: %s", __func__, __FILE__, __LINE__, \
|
||||
message); \
|
||||
minunit_status = 1; \
|
||||
return; \
|
||||
} else { printf("."); })
|
||||
|
||||
#define mu_assert_int_eq(expected, result) \
|
||||
MU__SAFE_BLOCK( \
|
||||
int minunit_tmp_e; int minunit_tmp_r; minunit_assert++; \
|
||||
minunit_tmp_e = (expected); minunit_tmp_r = (result); \
|
||||
if (minunit_tmp_e != minunit_tmp_r) { \
|
||||
snprintf(minunit_last_message, MINUNIT_MESSAGE_LEN, \
|
||||
"%s failed:\n\t%s:%d: %d expected but was %d", __func__, \
|
||||
__FILE__, __LINE__, minunit_tmp_e, minunit_tmp_r); \
|
||||
minunit_status = 1; \
|
||||
return; \
|
||||
} else { printf("."); })
|
||||
|
||||
#define mu_assert_double_eq(expected, result) \
|
||||
MU__SAFE_BLOCK( \
|
||||
double minunit_tmp_e; double minunit_tmp_r; minunit_assert++; \
|
||||
minunit_tmp_e = (expected); minunit_tmp_r = (result); \
|
||||
if (fabs(minunit_tmp_e - minunit_tmp_r) > MINUNIT_EPSILON) { \
|
||||
int minunit_significant_figures = 1 - log10(MINUNIT_EPSILON); \
|
||||
snprintf(minunit_last_message, MINUNIT_MESSAGE_LEN, \
|
||||
"%s failed:\n\t%s:%d: %.*g expected but was %.*g", __func__, \
|
||||
__FILE__, __LINE__, minunit_significant_figures, \
|
||||
minunit_tmp_e, minunit_significant_figures, minunit_tmp_r); \
|
||||
minunit_status = 1; \
|
||||
return; \
|
||||
} else { printf("."); })
|
||||
|
||||
#define mu_assert_string_eq(expected, result) \
|
||||
MU__SAFE_BLOCK( \
|
||||
const char *minunit_tmp_e = expected; \
|
||||
const char *minunit_tmp_r = result; minunit_assert++; \
|
||||
if (!minunit_tmp_e) { \
|
||||
minunit_tmp_e = "<null pointer>"; \
|
||||
} if (!minunit_tmp_r) { \
|
||||
minunit_tmp_r = "<null pointer>"; \
|
||||
} if (strcmp(minunit_tmp_e, minunit_tmp_r)) { \
|
||||
snprintf(minunit_last_message, MINUNIT_MESSAGE_LEN, \
|
||||
"%s failed:\n\t%s:%d: '%s' expected but was '%s'", __func__, \
|
||||
__FILE__, __LINE__, minunit_tmp_e, minunit_tmp_r); \
|
||||
minunit_status = 1; \
|
||||
return; \
|
||||
} else { printf("."); })
|
||||
|
||||
/*
|
||||
* The following two functions were written by David Robert Nadeau
|
||||
* from http://NadeauSoftware.com/ and distributed under the
|
||||
* Creative Commons Attribution 3.0 Unported License
|
||||
*/
|
||||
|
||||
/**
|
||||
* Returns the real time, in seconds, or -1.0 if an error occurred.
|
||||
*
|
||||
* Time is measured since an arbitrary and OS-dependent start time.
|
||||
* The returned real time is only useful for computing an elapsed time
|
||||
* between two calls to this function.
|
||||
*/
|
||||
static double mu_timer_real(void) {
|
||||
#if defined(_WIN32)
|
||||
/* Windows 2000 and later. ---------------------------------- */
|
||||
LARGE_INTEGER Time;
|
||||
LARGE_INTEGER Frequency;
|
||||
|
||||
QueryPerformanceFrequency(&Frequency);
|
||||
QueryPerformanceCounter(&Time);
|
||||
|
||||
Time.QuadPart *= 1000000;
|
||||
Time.QuadPart /= Frequency.QuadPart;
|
||||
|
||||
return (double)Time.QuadPart / 1000000.0;
|
||||
|
||||
#elif (defined(__hpux) || defined(hpux)) || \
|
||||
((defined(__sun__) || defined(__sun) || defined(sun)) && \
|
||||
(defined(__SVR4) || defined(__svr4__)))
|
||||
/* HP-UX, Solaris. ------------------------------------------ */
|
||||
return (double)gethrtime() / 1000000000.0;
|
||||
|
||||
#elif defined(__MACH__) && defined(__APPLE__)
|
||||
/* OSX. ----------------------------------------------------- */
|
||||
static double timeConvert = 0.0;
|
||||
if (timeConvert == 0.0) {
|
||||
mach_timebase_info_data_t timeBase;
|
||||
(void)mach_timebase_info(&timeBase);
|
||||
timeConvert =
|
||||
(double)timeBase.numer / (double)timeBase.denom / 1000000000.0;
|
||||
}
|
||||
return (double)mach_absolute_time() * timeConvert;
|
||||
|
||||
#elif defined(_POSIX_VERSION)
|
||||
/* POSIX. --------------------------------------------------- */
|
||||
struct timeval tm;
|
||||
#if defined(_POSIX_TIMERS) && (_POSIX_TIMERS > 0)
|
||||
{
|
||||
struct timespec ts;
|
||||
#if defined(CLOCK_MONOTONIC_PRECISE)
|
||||
/* BSD. --------------------------------------------- */
|
||||
const clockid_t id = CLOCK_MONOTONIC_PRECISE;
|
||||
#elif defined(CLOCK_MONOTONIC_RAW)
|
||||
/* Linux. ------------------------------------------- */
|
||||
const clockid_t id = CLOCK_MONOTONIC_RAW;
|
||||
#elif defined(CLOCK_HIGHRES)
|
||||
/* Solaris. ----------------------------------------- */
|
||||
const clockid_t id = CLOCK_HIGHRES;
|
||||
#elif defined(CLOCK_MONOTONIC)
|
||||
/* AIX, BSD, Linux, POSIX, Solaris. ----------------- */
|
||||
const clockid_t id = CLOCK_MONOTONIC;
|
||||
#elif defined(CLOCK_REALTIME)
|
||||
/* AIX, BSD, HP-UX, Linux, POSIX. ------------------- */
|
||||
const clockid_t id = CLOCK_REALTIME;
|
||||
#else
|
||||
const clockid_t id = (clockid_t)-1; /* Unknown. */
|
||||
#endif /* CLOCK_* */
|
||||
if (id != (clockid_t)-1 && clock_gettime(id, &ts) != -1)
|
||||
return (double)ts.tv_sec + (double)ts.tv_nsec / 1000000000.0;
|
||||
/* Fall thru. */
|
||||
}
|
||||
#endif /* _POSIX_TIMERS */
|
||||
|
||||
/* AIX, BSD, Cygwin, HP-UX, Linux, OSX, POSIX, Solaris. ----- */
|
||||
gettimeofday(&tm, NULL);
|
||||
return (double)tm.tv_sec + (double)tm.tv_usec / 1000000.0;
|
||||
#else
|
||||
return -1.0; /* Failed. */
|
||||
#endif
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the amount of CPU time used by the current process,
|
||||
* in seconds, or -1.0 if an error occurred.
|
||||
*/
|
||||
static double mu_timer_cpu(void) {
|
||||
#if defined(_WIN32)
|
||||
/* Windows -------------------------------------------------- */
|
||||
FILETIME createTime;
|
||||
FILETIME exitTime;
|
||||
FILETIME kernelTime;
|
||||
FILETIME userTime;
|
||||
|
||||
/* This approach has a resolution of 1/64 second. Unfortunately, Windows' API
|
||||
* does not offer better */
|
||||
if (GetProcessTimes(GetCurrentProcess(), &createTime, &exitTime, &kernelTime,
|
||||
&userTime) != 0) {
|
||||
ULARGE_INTEGER userSystemTime;
|
||||
memcpy(&userSystemTime, &userTime, sizeof(ULARGE_INTEGER));
|
||||
return (double)userSystemTime.QuadPart / 10000000.0;
|
||||
}
|
||||
|
||||
#elif defined(__unix__) || defined(__unix) || defined(unix) || \
|
||||
(defined(__APPLE__) && defined(__MACH__))
|
||||
/* AIX, BSD, Cygwin, HP-UX, Linux, OSX, and Solaris --------- */
|
||||
|
||||
#if defined(_POSIX_TIMERS) && (_POSIX_TIMERS > 0)
|
||||
/* Prefer high-res POSIX timers, when available. */
|
||||
{
|
||||
clockid_t id;
|
||||
struct timespec ts;
|
||||
#if _POSIX_CPUTIME > 0
|
||||
/* Clock ids vary by OS. Query the id, if possible. */
|
||||
if (clock_getcpuclockid(0, &id) == -1)
|
||||
#endif
|
||||
#if defined(CLOCK_PROCESS_CPUTIME_ID)
|
||||
/* Use known clock id for AIX, Linux, or Solaris. */
|
||||
id = CLOCK_PROCESS_CPUTIME_ID;
|
||||
#elif defined(CLOCK_VIRTUAL)
|
||||
/* Use known clock id for BSD or HP-UX. */
|
||||
id = CLOCK_VIRTUAL;
|
||||
#else
|
||||
id = (clockid_t)-1;
|
||||
#endif
|
||||
if (id != (clockid_t)-1 && clock_gettime(id, &ts) != -1)
|
||||
return (double)ts.tv_sec + (double)ts.tv_nsec / 1000000000.0;
|
||||
}
|
||||
#endif
|
||||
|
||||
#if defined(RUSAGE_SELF)
|
||||
{
|
||||
struct rusage rusage;
|
||||
if (getrusage(RUSAGE_SELF, &rusage) != -1)
|
||||
return (double)rusage.ru_utime.tv_sec +
|
||||
(double)rusage.ru_utime.tv_usec / 1000000.0;
|
||||
}
|
||||
#endif
|
||||
|
||||
#if defined(_SC_CLK_TCK)
|
||||
{
|
||||
const double ticks = (double)sysconf(_SC_CLK_TCK);
|
||||
struct tms tms;
|
||||
if (times(&tms) != (clock_t)-1)
|
||||
return (double)tms.tms_utime / ticks;
|
||||
}
|
||||
#endif
|
||||
|
||||
#if defined(CLOCKS_PER_SEC)
|
||||
{
|
||||
clock_t cl = clock();
|
||||
if (cl != (clock_t)-1)
|
||||
return (double)cl / (double)CLOCKS_PER_SEC;
|
||||
}
|
||||
#endif
|
||||
|
||||
#endif
|
||||
|
||||
return -1; /* Failed. */
|
||||
}
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
||||
#endif /* MINUNIT_MINUNIT_H */
|
|
@ -1,495 +0,0 @@
|
|||
#include <zip.h>
|
||||
|
||||
#include <assert.h>
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
#include <sys/stat.h>
|
||||
|
||||
#if defined(_MSC_VER) || defined(__MINGW64__) || defined(__MINGW32__)
|
||||
#define MZ_FILE_STAT_STRUCT _stat
|
||||
#define MZ_FILE_STAT _stat
|
||||
#else
|
||||
#define MZ_FILE_STAT_STRUCT stat
|
||||
#define MZ_FILE_STAT stat
|
||||
#endif
|
||||
|
||||
#define ZIPNAME "test.zip\0"
|
||||
#define TESTDATA1 "Some test data 1...\0"
|
||||
#define CRC32DATA1 2220805626
|
||||
#define TESTDATA2 "Some test data 2...\0"
|
||||
#define CRC32DATA2 2532008468
|
||||
|
||||
#define RFILE "4.txt\0"
|
||||
#define RMODE 0100444
|
||||
|
||||
#define WFILE "6.txt\0"
|
||||
#define WMODE 0100666
|
||||
|
||||
#define XFILE "7.txt\0"
|
||||
#define XMODE 0100777
|
||||
|
||||
#define UNIXMODE 0100644
|
||||
|
||||
#define UNUSED(x) (void)x
|
||||
|
||||
static int total_entries = 0;
|
||||
|
||||
static void test_write(void) {
|
||||
struct zip_t *zip = zip_open(ZIPNAME, ZIP_DEFAULT_COMPRESSION_LEVEL, 'w');
|
||||
assert(zip != NULL);
|
||||
|
||||
assert(0 == zip_entry_open(zip, "test/test-1.txt"));
|
||||
assert(0 == zip_entry_write(zip, TESTDATA1, strlen(TESTDATA1)));
|
||||
assert(0 == strcmp(zip_entry_name(zip), "test/test-1.txt"));
|
||||
assert(total_entries == zip_entry_index(zip));
|
||||
assert(strlen(TESTDATA1) == zip_entry_size(zip));
|
||||
assert(CRC32DATA1 == zip_entry_crc32(zip));
|
||||
++total_entries;
|
||||
assert(0 == zip_entry_close(zip));
|
||||
assert(0 == zip_is64(zip));
|
||||
zip_close(zip);
|
||||
}
|
||||
|
||||
static void test_append(void) {
|
||||
struct zip_t *zip = zip_open(ZIPNAME, ZIP_DEFAULT_COMPRESSION_LEVEL, 'a');
|
||||
assert(zip != NULL);
|
||||
|
||||
assert(0 == zip_entry_open(zip, "test\\test-2.txt"));
|
||||
assert(0 == strcmp(zip_entry_name(zip), "test/test-2.txt"));
|
||||
assert(total_entries == zip_entry_index(zip));
|
||||
assert(0 == zip_entry_write(zip, TESTDATA2, strlen(TESTDATA2)));
|
||||
assert(strlen(TESTDATA2) == zip_entry_size(zip));
|
||||
assert(CRC32DATA2 == zip_entry_crc32(zip));
|
||||
|
||||
++total_entries;
|
||||
assert(0 == zip_entry_close(zip));
|
||||
|
||||
assert(0 == zip_entry_open(zip, "test\\empty/"));
|
||||
assert(0 == strcmp(zip_entry_name(zip), "test/empty/"));
|
||||
assert(0 == zip_entry_size(zip));
|
||||
assert(0 == zip_entry_crc32(zip));
|
||||
|
||||
assert(total_entries == zip_entry_index(zip));
|
||||
++total_entries;
|
||||
assert(0 == zip_entry_close(zip));
|
||||
|
||||
assert(0 == zip_entry_open(zip, "empty/"));
|
||||
assert(0 == strcmp(zip_entry_name(zip), "empty/"));
|
||||
assert(0 == zip_entry_size(zip));
|
||||
assert(0 == zip_entry_crc32(zip));
|
||||
|
||||
assert(total_entries == zip_entry_index(zip));
|
||||
++total_entries;
|
||||
assert(0 == zip_entry_close(zip));
|
||||
|
||||
zip_close(zip);
|
||||
}
|
||||
|
||||
static void test_read(void) {
|
||||
char *buf = NULL;
|
||||
ssize_t bufsize;
|
||||
size_t buftmp;
|
||||
struct zip_t *zip = zip_open(ZIPNAME, 0, 'r');
|
||||
assert(zip != NULL);
|
||||
assert(0 == zip_is64(zip));
|
||||
|
||||
assert(0 == zip_entry_open(zip, "test\\test-1.txt"));
|
||||
assert(strlen(TESTDATA1) == zip_entry_size(zip));
|
||||
assert(CRC32DATA1 == zip_entry_crc32(zip));
|
||||
|
||||
bufsize = zip_entry_read(zip, (void **)&buf, &buftmp);
|
||||
assert(bufsize == strlen(TESTDATA1));
|
||||
assert((size_t)bufsize == buftmp);
|
||||
assert(0 == strncmp(buf, TESTDATA1, bufsize));
|
||||
assert(0 == zip_entry_close(zip));
|
||||
free(buf);
|
||||
buf = NULL;
|
||||
bufsize = 0;
|
||||
|
||||
assert(0 == zip_entry_open(zip, "test/test-2.txt"));
|
||||
assert(strlen(TESTDATA2) == zip_entry_size(zip));
|
||||
assert(CRC32DATA2 == zip_entry_crc32(zip));
|
||||
|
||||
bufsize = zip_entry_read(zip, (void **)&buf, NULL);
|
||||
assert((size_t)bufsize == strlen(TESTDATA2));
|
||||
assert(0 == strncmp(buf, TESTDATA2, (size_t)bufsize));
|
||||
assert(0 == zip_entry_close(zip));
|
||||
free(buf);
|
||||
buf = NULL;
|
||||
bufsize = 0;
|
||||
|
||||
assert(0 == zip_entry_open(zip, "test\\empty/"));
|
||||
assert(0 == strcmp(zip_entry_name(zip), "test/empty/"));
|
||||
assert(0 == zip_entry_size(zip));
|
||||
assert(0 == zip_entry_crc32(zip));
|
||||
assert(0 == zip_entry_close(zip));
|
||||
|
||||
buftmp = strlen(TESTDATA2);
|
||||
buf = calloc(buftmp, sizeof(char));
|
||||
assert(0 == zip_entry_open(zip, "test/test-2.txt"));
|
||||
|
||||
bufsize = zip_entry_noallocread(zip, (void *)buf, buftmp);
|
||||
assert(buftmp == (size_t)bufsize);
|
||||
assert(0 == strncmp(buf, TESTDATA2, buftmp));
|
||||
assert(0 == zip_entry_close(zip));
|
||||
free(buf);
|
||||
buf = NULL;
|
||||
bufsize = 0;
|
||||
|
||||
buftmp = strlen(TESTDATA1);
|
||||
buf = calloc(buftmp, sizeof(char));
|
||||
assert(0 == zip_entry_open(zip, "test/test-1.txt"));
|
||||
|
||||
bufsize = zip_entry_noallocread(zip, (void *)buf, buftmp);
|
||||
assert(buftmp == (size_t)bufsize);
|
||||
assert(0 == strncmp(buf, TESTDATA1, buftmp));
|
||||
assert(0 == zip_entry_close(zip));
|
||||
free(buf);
|
||||
buf = NULL;
|
||||
bufsize = 0;
|
||||
|
||||
zip_close(zip);
|
||||
}
|
||||
|
||||
struct buffer_t {
|
||||
char *data;
|
||||
size_t size;
|
||||
};
|
||||
|
||||
static size_t on_extract(void *arg, unsigned long long offset, const void *data,
|
||||
size_t size) {
|
||||
UNUSED(offset);
|
||||
|
||||
struct buffer_t *buf = (struct buffer_t *)arg;
|
||||
buf->data = realloc(buf->data, buf->size + size + 1);
|
||||
assert(NULL != buf->data);
|
||||
|
||||
memcpy(&(buf->data[buf->size]), data, size);
|
||||
buf->size += size;
|
||||
buf->data[buf->size] = 0;
|
||||
|
||||
return size;
|
||||
}
|
||||
|
||||
static void test_extract(void) {
|
||||
struct buffer_t buf;
|
||||
|
||||
struct zip_t *zip = zip_open(ZIPNAME, 0, 'r');
|
||||
assert(zip != NULL);
|
||||
memset((void *)&buf, 0, sizeof(struct buffer_t));
|
||||
|
||||
assert(0 == zip_entry_open(zip, "test/test-1.txt"));
|
||||
assert(0 == zip_entry_extract(zip, on_extract, &buf));
|
||||
|
||||
assert(buf.size == strlen(TESTDATA1));
|
||||
assert(0 == strncmp(buf.data, TESTDATA1, buf.size));
|
||||
assert(0 == zip_entry_close(zip));
|
||||
free(buf.data);
|
||||
buf.data = NULL;
|
||||
buf.size = 0;
|
||||
|
||||
zip_close(zip);
|
||||
}
|
||||
|
||||
static void test_total_entries(void) {
|
||||
struct zip_t *zip = zip_open(ZIPNAME, 0, 'r');
|
||||
assert(zip != NULL);
|
||||
|
||||
int n = zip_total_entries(zip);
|
||||
zip_close(zip);
|
||||
|
||||
assert(n == total_entries);
|
||||
}
|
||||
|
||||
static void test_entry_name(void) {
|
||||
struct zip_t *zip = zip_open(ZIPNAME, 0, 'r');
|
||||
assert(zip != NULL);
|
||||
|
||||
assert(zip_entry_name(zip) == NULL);
|
||||
|
||||
assert(0 == zip_entry_open(zip, "test\\test-1.txt"));
|
||||
assert(NULL != zip_entry_name(zip));
|
||||
assert(0 == strcmp(zip_entry_name(zip), "test/test-1.txt"));
|
||||
assert(strlen(TESTDATA1) == zip_entry_size(zip));
|
||||
assert(CRC32DATA1 == zip_entry_crc32(zip));
|
||||
assert(0 == zip_entry_index(zip));
|
||||
|
||||
assert(0 == zip_entry_close(zip));
|
||||
|
||||
assert(0 == zip_entry_open(zip, "test/test-2.txt"));
|
||||
assert(NULL != zip_entry_name(zip));
|
||||
assert(0 == strcmp(zip_entry_name(zip), "test/test-2.txt"));
|
||||
assert(strlen(TESTDATA2) == zip_entry_size(zip));
|
||||
assert(CRC32DATA2 == zip_entry_crc32(zip));
|
||||
assert(1 == zip_entry_index(zip));
|
||||
|
||||
assert(0 == zip_entry_close(zip));
|
||||
|
||||
zip_close(zip);
|
||||
}
|
||||
|
||||
static void test_entry_index(void) {
|
||||
struct zip_t *zip = zip_open(ZIPNAME, 0, 'r');
|
||||
assert(zip != NULL);
|
||||
|
||||
assert(0 == zip_entry_open(zip, "test\\test-1.txt"));
|
||||
assert(0 == zip_entry_index(zip));
|
||||
assert(0 == strcmp(zip_entry_name(zip), "test/test-1.txt"));
|
||||
assert(strlen(TESTDATA1) == zip_entry_size(zip));
|
||||
assert(CRC32DATA1 == zip_entry_crc32(zip));
|
||||
assert(0 == zip_entry_close(zip));
|
||||
|
||||
assert(0 == zip_entry_open(zip, "test/test-2.txt"));
|
||||
assert(1 == zip_entry_index(zip));
|
||||
assert(0 == strcmp(zip_entry_name(zip), "test/test-2.txt"));
|
||||
assert(strlen(TESTDATA2) == zip_entry_size(zip));
|
||||
assert(CRC32DATA2 == zip_entry_crc32(zip));
|
||||
assert(0 == zip_entry_close(zip));
|
||||
|
||||
zip_close(zip);
|
||||
}
|
||||
|
||||
static void test_entry_openbyindex(void) {
|
||||
struct zip_t *zip = zip_open(ZIPNAME, 0, 'r');
|
||||
assert(zip != NULL);
|
||||
|
||||
assert(0 == zip_entry_openbyindex(zip, 1));
|
||||
assert(1 == zip_entry_index(zip));
|
||||
assert(strlen(TESTDATA2) == zip_entry_size(zip));
|
||||
assert(CRC32DATA2 == zip_entry_crc32(zip));
|
||||
assert(0 == strcmp(zip_entry_name(zip), "test/test-2.txt"));
|
||||
assert(0 == zip_entry_close(zip));
|
||||
|
||||
assert(0 == zip_entry_openbyindex(zip, 0));
|
||||
assert(0 == zip_entry_index(zip));
|
||||
assert(strlen(TESTDATA1) == zip_entry_size(zip));
|
||||
assert(CRC32DATA1 == zip_entry_crc32(zip));
|
||||
assert(0 == strcmp(zip_entry_name(zip), "test/test-1.txt"));
|
||||
assert(0 == zip_entry_close(zip));
|
||||
|
||||
zip_close(zip);
|
||||
}
|
||||
|
||||
static void test_list_entries(void) {
|
||||
struct zip_t *zip = zip_open(ZIPNAME, 0, 'r');
|
||||
assert(zip != NULL);
|
||||
|
||||
int i = 0, n = zip_total_entries(zip);
|
||||
for (; i < n; ++i) {
|
||||
assert(0 == zip_entry_openbyindex(zip, i));
|
||||
fprintf(stdout, "[%d]: %s", i, zip_entry_name(zip));
|
||||
if (zip_entry_isdir(zip)) {
|
||||
fprintf(stdout, " (DIR)");
|
||||
}
|
||||
fprintf(stdout, "\n");
|
||||
assert(0 == zip_entry_close(zip));
|
||||
}
|
||||
|
||||
zip_close(zip);
|
||||
}
|
||||
|
||||
static void test_fwrite(void) {
|
||||
const char *filename = WFILE;
|
||||
FILE *stream = NULL;
|
||||
struct zip_t *zip = NULL;
|
||||
#if defined(_MSC_VER)
|
||||
if (0 != fopen_s(&stream, filename, "w+"))
|
||||
#else
|
||||
if (!(stream = fopen(filename, "w+")))
|
||||
#endif
|
||||
{
|
||||
// Cannot open filename
|
||||
fprintf(stdout, "Cannot open filename\n");
|
||||
assert(0 == -1);
|
||||
}
|
||||
fwrite(TESTDATA1, sizeof(char), strlen(TESTDATA1), stream);
|
||||
assert(0 == fclose(stream));
|
||||
|
||||
zip = zip_open(ZIPNAME, 9, 'w');
|
||||
assert(zip != NULL);
|
||||
assert(0 == zip_entry_open(zip, WFILE));
|
||||
assert(0 == zip_entry_fwrite(zip, WFILE));
|
||||
assert(0 == zip_entry_close(zip));
|
||||
assert(0 == zip_is64(zip));
|
||||
|
||||
zip_close(zip);
|
||||
remove(WFILE);
|
||||
remove(ZIPNAME);
|
||||
}
|
||||
|
||||
static void test_exe_permissions(void) {
|
||||
#if defined(_WIN32) || defined(__WIN32__)
|
||||
#else
|
||||
struct MZ_FILE_STAT_STRUCT file_stats;
|
||||
const char *filenames[] = {XFILE};
|
||||
FILE *f = fopen(XFILE, "w");
|
||||
fclose(f);
|
||||
chmod(XFILE, XMODE);
|
||||
|
||||
remove(ZIPNAME);
|
||||
|
||||
assert(0 == zip_create(ZIPNAME, filenames, 1));
|
||||
|
||||
remove(XFILE);
|
||||
|
||||
assert(0 == zip_extract(ZIPNAME, ".", NULL, NULL));
|
||||
|
||||
assert(0 == MZ_FILE_STAT(XFILE, &file_stats));
|
||||
assert(XMODE == file_stats.st_mode);
|
||||
|
||||
remove(XFILE);
|
||||
remove(ZIPNAME);
|
||||
#endif
|
||||
}
|
||||
|
||||
static void test_read_permissions(void) {
|
||||
#if defined(_MSC_VER)
|
||||
#else
|
||||
|
||||
struct MZ_FILE_STAT_STRUCT file_stats;
|
||||
const char *filenames[] = {RFILE};
|
||||
FILE *f = fopen(RFILE, "w");
|
||||
fclose(f);
|
||||
chmod(RFILE, RMODE);
|
||||
|
||||
remove(ZIPNAME);
|
||||
|
||||
assert(0 == zip_create(ZIPNAME, filenames, 1));
|
||||
|
||||
// chmod from 444 to 666 to be able delete the file on windows
|
||||
chmod(RFILE, WMODE);
|
||||
remove(RFILE);
|
||||
|
||||
assert(0 == zip_extract(ZIPNAME, ".", NULL, NULL));
|
||||
|
||||
assert(0 == MZ_FILE_STAT(RFILE, &file_stats));
|
||||
assert(RMODE == file_stats.st_mode);
|
||||
|
||||
chmod(RFILE, WMODE);
|
||||
remove(RFILE);
|
||||
remove(ZIPNAME);
|
||||
#endif
|
||||
}
|
||||
|
||||
static void test_write_permissions(void) {
|
||||
#if defined(_MSC_VER)
|
||||
#else
|
||||
|
||||
struct MZ_FILE_STAT_STRUCT file_stats;
|
||||
const char *filenames[] = {WFILE};
|
||||
FILE *f = fopen(WFILE, "w");
|
||||
fclose(f);
|
||||
chmod(WFILE, WMODE);
|
||||
|
||||
remove(ZIPNAME);
|
||||
|
||||
assert(0 == zip_create(ZIPNAME, filenames, 1));
|
||||
|
||||
remove(WFILE);
|
||||
|
||||
assert(0 == zip_extract(ZIPNAME, ".", NULL, NULL));
|
||||
|
||||
assert(0 == MZ_FILE_STAT(WFILE, &file_stats));
|
||||
assert(WMODE == file_stats.st_mode);
|
||||
|
||||
remove(WFILE);
|
||||
remove(ZIPNAME);
|
||||
#endif
|
||||
}
|
||||
|
||||
static void test_mtime(void) {
|
||||
struct MZ_FILE_STAT_STRUCT file_stat1, file_stat2;
|
||||
|
||||
const char *filename = WFILE;
|
||||
FILE *stream = NULL;
|
||||
struct zip_t *zip = NULL;
|
||||
#if defined(_MSC_VER)
|
||||
if (0 != fopen_s(&stream, filename, "w+"))
|
||||
#else
|
||||
if (!(stream = fopen(filename, "w+")))
|
||||
#endif
|
||||
{
|
||||
// Cannot open filename
|
||||
fprintf(stdout, "Cannot open filename\n");
|
||||
assert(0 == -1);
|
||||
}
|
||||
fwrite(TESTDATA1, sizeof(char), strlen(TESTDATA1), stream);
|
||||
assert(0 == fclose(stream));
|
||||
|
||||
memset(&file_stat1, 0, sizeof(file_stat1));
|
||||
memset(&file_stat2, 0, sizeof(file_stat2));
|
||||
zip = zip_open(ZIPNAME, ZIP_DEFAULT_COMPRESSION_LEVEL, 'w');
|
||||
assert(zip != NULL);
|
||||
assert(0 == zip_entry_open(zip, filename));
|
||||
assert(0 == zip_entry_fwrite(zip, filename));
|
||||
assert(0 == zip_entry_close(zip));
|
||||
zip_close(zip);
|
||||
|
||||
assert(0 == MZ_FILE_STAT(filename, &file_stat1));
|
||||
|
||||
remove(filename);
|
||||
assert(0 == zip_extract(ZIPNAME, ".", NULL, NULL));
|
||||
assert(0 == MZ_FILE_STAT(filename, &file_stat2));
|
||||
fprintf(stdout, "file_stat1.st_mtime: %lu\n", file_stat1.st_mtime);
|
||||
fprintf(stdout, "file_stat2.st_mtime: %lu\n", file_stat2.st_mtime);
|
||||
assert(labs(file_stat1.st_mtime - file_stat2.st_mtime) <= 1);
|
||||
|
||||
remove(filename);
|
||||
remove(ZIPNAME);
|
||||
}
|
||||
|
||||
static void test_unix_permissions(void) {
|
||||
#if defined(_WIN64) || defined(_WIN32) || defined(__WIN32__)
|
||||
#else
|
||||
// UNIX or APPLE
|
||||
struct MZ_FILE_STAT_STRUCT file_stats;
|
||||
|
||||
remove(ZIPNAME);
|
||||
|
||||
struct zip_t *zip = zip_open(ZIPNAME, ZIP_DEFAULT_COMPRESSION_LEVEL, 'w');
|
||||
assert(zip != NULL);
|
||||
|
||||
assert(0 == zip_entry_open(zip, RFILE));
|
||||
assert(0 == zip_entry_write(zip, TESTDATA1, strlen(TESTDATA1)));
|
||||
assert(0 == zip_entry_close(zip));
|
||||
|
||||
zip_close(zip);
|
||||
|
||||
remove(RFILE);
|
||||
|
||||
assert(0 == zip_extract(ZIPNAME, ".", NULL, NULL));
|
||||
|
||||
assert(0 == MZ_FILE_STAT(RFILE, &file_stats));
|
||||
assert(UNIXMODE == file_stats.st_mode);
|
||||
|
||||
remove(RFILE);
|
||||
remove(ZIPNAME);
|
||||
#endif
|
||||
}
|
||||
|
||||
int main(int argc, char *argv[]) {
|
||||
UNUSED(argc);
|
||||
UNUSED(argv);
|
||||
|
||||
remove(ZIPNAME);
|
||||
|
||||
test_write();
|
||||
test_append();
|
||||
test_read();
|
||||
test_extract();
|
||||
test_total_entries();
|
||||
test_entry_name();
|
||||
test_entry_index();
|
||||
test_entry_openbyindex();
|
||||
test_list_entries();
|
||||
test_fwrite();
|
||||
test_read_permissions();
|
||||
test_write_permissions();
|
||||
test_exe_permissions();
|
||||
test_mtime();
|
||||
test_unix_permissions();
|
||||
|
||||
remove(ZIPNAME);
|
||||
return 0;
|
||||
}
|
|
@ -0,0 +1,104 @@
|
|||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
|
||||
#include <zip.h>
|
||||
|
||||
#include "minunit.h"
|
||||
|
||||
#if defined(_WIN32) || defined(_WIN64)
|
||||
#define MKTEMP _mktemp
|
||||
#define UNLINK _unlink
|
||||
#else
|
||||
#define MKTEMP mkstemp
|
||||
#define UNLINK unlink
|
||||
#endif
|
||||
|
||||
static char ZIPNAME[L_tmpnam + 1] = {0};
|
||||
static int total_entries = 0;
|
||||
|
||||
#define TESTDATA1 "Some test data 1...\0"
|
||||
|
||||
void test_setup(void) {
|
||||
strncpy(ZIPNAME, "z-XXXXXX\0", L_tmpnam);
|
||||
MKTEMP(ZIPNAME);
|
||||
|
||||
struct zip_t *zip = zip_open(ZIPNAME, ZIP_DEFAULT_COMPRESSION_LEVEL, 'w');
|
||||
|
||||
zip_entry_open(zip, "test/test-1.txt");
|
||||
zip_entry_write(zip, TESTDATA1, strlen(TESTDATA1));
|
||||
zip_entry_close(zip);
|
||||
++total_entries;
|
||||
|
||||
zip_close(zip);
|
||||
}
|
||||
|
||||
void test_teardown(void) { UNLINK(ZIPNAME); }
|
||||
|
||||
#define TESTDATA2 "Some test data 2...\0"
|
||||
#define CRC32DATA2 2532008468
|
||||
|
||||
MU_TEST(test_append) {
|
||||
struct zip_t *zip = zip_open(ZIPNAME, ZIP_DEFAULT_COMPRESSION_LEVEL, 'a');
|
||||
mu_check(zip != NULL);
|
||||
|
||||
mu_assert_int_eq(0, zip_entry_open(zip, "test\\test-2.txt"));
|
||||
mu_assert_int_eq(0, strcmp(zip_entry_name(zip), "test/test-2.txt"));
|
||||
mu_assert_int_eq(total_entries, zip_entry_index(zip));
|
||||
mu_assert_int_eq(0, zip_entry_write(zip, TESTDATA2, strlen(TESTDATA2)));
|
||||
mu_assert_int_eq(strlen(TESTDATA2), zip_entry_size(zip));
|
||||
mu_check(CRC32DATA2 == zip_entry_crc32(zip));
|
||||
mu_assert_int_eq(0, zip_entry_close(zip));
|
||||
++total_entries;
|
||||
zip_close(zip);
|
||||
|
||||
zip = zip_open(ZIPNAME, ZIP_DEFAULT_COMPRESSION_LEVEL, 'a');
|
||||
mu_assert_int_eq(0, zip_entry_open(zip, "test\\empty/"));
|
||||
mu_assert_int_eq(0, strcmp(zip_entry_name(zip), "test/empty/"));
|
||||
mu_assert_int_eq(0, zip_entry_size(zip));
|
||||
mu_assert_int_eq(0, zip_entry_crc32(zip));
|
||||
mu_assert_int_eq(total_entries, zip_entry_index(zip));
|
||||
mu_assert_int_eq(0, zip_entry_close(zip));
|
||||
++total_entries;
|
||||
zip_close(zip);
|
||||
|
||||
zip = zip_open(ZIPNAME, ZIP_DEFAULT_COMPRESSION_LEVEL, 'a');
|
||||
mu_assert_int_eq(0, zip_entry_open(zip, "empty/"));
|
||||
mu_assert_int_eq(0, strcmp(zip_entry_name(zip), "empty/"));
|
||||
mu_assert_int_eq(0, zip_entry_size(zip));
|
||||
mu_assert_int_eq(0, zip_entry_crc32(zip));
|
||||
mu_assert_int_eq(total_entries, zip_entry_index(zip));
|
||||
mu_assert_int_eq(0, zip_entry_close(zip));
|
||||
++total_entries;
|
||||
|
||||
mu_assert_int_eq(0, zip_entry_open(zip, "dotfiles/.test"));
|
||||
mu_assert_int_eq(0, strcmp(zip_entry_name(zip), "dotfiles/.test"));
|
||||
mu_assert_int_eq(0, zip_entry_size(zip));
|
||||
mu_assert_int_eq(0, zip_entry_crc32(zip));
|
||||
mu_assert_int_eq(0, zip_entry_write(zip, TESTDATA2, strlen(TESTDATA2)));
|
||||
mu_assert_int_eq(strlen(TESTDATA2), zip_entry_size(zip));
|
||||
mu_check(CRC32DATA2 == zip_entry_crc32(zip));
|
||||
mu_assert_int_eq(total_entries, zip_entry_index(zip));
|
||||
mu_assert_int_eq(0, zip_entry_close(zip));
|
||||
++total_entries;
|
||||
|
||||
mu_assert_int_eq(total_entries, zip_entries_total(zip));
|
||||
|
||||
zip_close(zip);
|
||||
}
|
||||
|
||||
MU_TEST_SUITE(test_append_suite) {
|
||||
MU_SUITE_CONFIGURE(&test_setup, &test_teardown);
|
||||
|
||||
MU_RUN_TEST(test_append);
|
||||
}
|
||||
|
||||
#define UNUSED(x) (void)x
|
||||
|
||||
int main(int argc, char *argv[]) {
|
||||
UNUSED(argc);
|
||||
UNUSED(argv);
|
||||
|
||||
MU_RUN_SUITE(test_append_suite);
|
||||
MU_REPORT();
|
||||
return MU_EXIT_CODE;
|
||||
}
|
|
@ -0,0 +1,438 @@
|
|||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
|
||||
#include <zip.h>
|
||||
|
||||
#include "minunit.h"
|
||||
|
||||
#if defined(_WIN32) || defined(_WIN64)
|
||||
#define MKTEMP _mktemp
|
||||
#define UNLINK _unlink
|
||||
#else
|
||||
#define MKTEMP mkstemp
|
||||
#define UNLINK unlink
|
||||
#endif
|
||||
|
||||
#define MZ_ZIP64_MAX_CENTRAL_EXTRA_FIELD_SIZE \
|
||||
(sizeof(unsigned short) * 2 + sizeof(unsigned long long) * 3)
|
||||
#define MZ_ZIP_LOCAL_DIR_HEADER_SIZE 30
|
||||
|
||||
static char ZIPNAME[L_tmpnam + 1] = {0};
|
||||
|
||||
#define CRC32DATA1 2220805626
|
||||
#define TESTDATA1 "Some test data 1...\0"
|
||||
|
||||
#define TESTDATA2 "Some test data 2...\0"
|
||||
#define CRC32DATA2 2532008468
|
||||
|
||||
static int total_entries = 0;
|
||||
|
||||
void test_setup(void) {
|
||||
strncpy(ZIPNAME, "z-XXXXXX\0", L_tmpnam);
|
||||
MKTEMP(ZIPNAME);
|
||||
|
||||
struct zip_t *zip = zip_open(ZIPNAME, ZIP_DEFAULT_COMPRESSION_LEVEL, 'w');
|
||||
|
||||
zip_entry_open(zip, "test/test-1.txt");
|
||||
zip_entry_write(zip, TESTDATA1, strlen(TESTDATA1));
|
||||
zip_entry_close(zip);
|
||||
++total_entries;
|
||||
|
||||
zip_entry_open(zip, "test\\test-2.txt");
|
||||
zip_entry_write(zip, TESTDATA2, strlen(TESTDATA2));
|
||||
zip_entry_close(zip);
|
||||
++total_entries;
|
||||
|
||||
zip_entry_open(zip, "test\\empty/");
|
||||
zip_entry_close(zip);
|
||||
++total_entries;
|
||||
|
||||
zip_entry_open(zip, "empty/");
|
||||
zip_entry_close(zip);
|
||||
++total_entries;
|
||||
|
||||
zip_entry_open(zip, "dotfiles/.test");
|
||||
zip_entry_write(zip, TESTDATA2, strlen(TESTDATA2));
|
||||
zip_entry_close(zip);
|
||||
++total_entries;
|
||||
|
||||
zip_entry_open(zip, "delete.me");
|
||||
zip_entry_write(zip, TESTDATA1, strlen(TESTDATA1));
|
||||
zip_entry_close(zip);
|
||||
++total_entries;
|
||||
|
||||
zip_entry_open(zip, "_");
|
||||
zip_entry_write(zip, TESTDATA2, strlen(TESTDATA2));
|
||||
zip_entry_close(zip);
|
||||
++total_entries;
|
||||
|
||||
zip_entry_open(zip, "delete/file.1");
|
||||
zip_entry_write(zip, TESTDATA1, strlen(TESTDATA1));
|
||||
zip_entry_close(zip);
|
||||
++total_entries;
|
||||
|
||||
zip_entry_open(zip, "delete/file.2");
|
||||
zip_entry_write(zip, TESTDATA2, strlen(TESTDATA2));
|
||||
zip_entry_close(zip);
|
||||
++total_entries;
|
||||
|
||||
zip_entry_open(zip, "deleteme/file.3");
|
||||
zip_entry_write(zip, TESTDATA1, strlen(TESTDATA1));
|
||||
zip_entry_close(zip);
|
||||
++total_entries;
|
||||
|
||||
zip_entry_open(zip, "delete/file.4");
|
||||
zip_entry_write(zip, TESTDATA2, strlen(TESTDATA2));
|
||||
zip_entry_close(zip);
|
||||
++total_entries;
|
||||
|
||||
zip_close(zip);
|
||||
}
|
||||
|
||||
void test_teardown(void) {
|
||||
total_entries = 0;
|
||||
|
||||
UNLINK(ZIPNAME);
|
||||
}
|
||||
|
||||
MU_TEST(test_entry_name) {
|
||||
struct zip_t *zip = zip_open(ZIPNAME, 0, 'r');
|
||||
mu_check(zip != NULL);
|
||||
|
||||
mu_check(zip_entry_name(zip) == NULL);
|
||||
|
||||
mu_assert_int_eq(0, zip_entry_open(zip, "test\\test-1.txt"));
|
||||
mu_check(NULL != zip_entry_name(zip));
|
||||
mu_assert_int_eq(0, strcmp(zip_entry_name(zip), "test/test-1.txt"));
|
||||
mu_assert_int_eq(strlen(TESTDATA1), zip_entry_size(zip));
|
||||
mu_check(CRC32DATA1 == zip_entry_crc32(zip));
|
||||
mu_assert_int_eq(0, zip_entry_index(zip));
|
||||
|
||||
mu_assert_int_eq(0, zip_entry_close(zip));
|
||||
|
||||
mu_assert_int_eq(0, zip_entry_open(zip, "test/test-2.txt"));
|
||||
mu_check(NULL != zip_entry_name(zip));
|
||||
mu_assert_int_eq(0, strcmp(zip_entry_name(zip), "test/test-2.txt"));
|
||||
mu_assert_int_eq(strlen(TESTDATA2), zip_entry_size(zip));
|
||||
mu_check(CRC32DATA2 == zip_entry_crc32(zip));
|
||||
mu_assert_int_eq(1, zip_entry_index(zip));
|
||||
mu_assert_int_eq(0, zip_entry_close(zip));
|
||||
|
||||
zip_close(zip);
|
||||
}
|
||||
|
||||
MU_TEST(test_entry_opencasesensitive) {
|
||||
struct zip_t *zip = zip_open(ZIPNAME, 0, 'r');
|
||||
mu_check(zip != NULL);
|
||||
|
||||
mu_check(zip_entry_name(zip) == NULL);
|
||||
|
||||
mu_assert_int_eq(0, zip_entry_open(zip, "test/TEST-1.TXT"));
|
||||
mu_check(NULL != zip_entry_name(zip));
|
||||
mu_assert_int_eq(0, zip_entry_close(zip));
|
||||
|
||||
mu_assert_int_eq(ZIP_ENOENT,
|
||||
zip_entry_opencasesensitive(zip, "test/TEST-1.TXT"));
|
||||
|
||||
zip_close(zip);
|
||||
}
|
||||
|
||||
MU_TEST(test_entry_index) {
|
||||
struct zip_t *zip = zip_open(ZIPNAME, 0, 'r');
|
||||
mu_check(zip != NULL);
|
||||
|
||||
mu_assert_int_eq(0, zip_entry_open(zip, "test\\test-1.txt"));
|
||||
mu_assert_int_eq(0, zip_entry_index(zip));
|
||||
mu_assert_int_eq(0, strcmp(zip_entry_name(zip), "test/test-1.txt"));
|
||||
mu_assert_int_eq(strlen(TESTDATA1), zip_entry_size(zip));
|
||||
mu_check(CRC32DATA1 == zip_entry_crc32(zip));
|
||||
mu_assert_int_eq(0, zip_entry_close(zip));
|
||||
|
||||
mu_assert_int_eq(0, zip_entry_open(zip, "test/test-2.txt"));
|
||||
mu_assert_int_eq(1, zip_entry_index(zip));
|
||||
mu_assert_int_eq(0, strcmp(zip_entry_name(zip), "test/test-2.txt"));
|
||||
mu_assert_int_eq(strlen(TESTDATA2), zip_entry_size(zip));
|
||||
mu_check(CRC32DATA2 == zip_entry_crc32(zip));
|
||||
mu_assert_int_eq(0, zip_entry_close(zip));
|
||||
|
||||
zip_close(zip);
|
||||
}
|
||||
|
||||
MU_TEST(test_entry_openbyindex) {
|
||||
struct zip_t *zip = zip_open(ZIPNAME, 0, 'r');
|
||||
mu_check(zip != NULL);
|
||||
|
||||
mu_assert_int_eq(0, zip_entry_openbyindex(zip, 1));
|
||||
mu_assert_int_eq(1, zip_entry_index(zip));
|
||||
|
||||
mu_assert_int_eq(strlen(TESTDATA2), zip_entry_size(zip));
|
||||
mu_check(CRC32DATA2 == zip_entry_crc32(zip));
|
||||
|
||||
mu_assert_int_eq(0, strcmp(zip_entry_name(zip), "test/test-2.txt"));
|
||||
mu_assert_int_eq(0, zip_entry_close(zip));
|
||||
|
||||
mu_assert_int_eq(0, zip_entry_openbyindex(zip, 0));
|
||||
mu_assert_int_eq(0, zip_entry_index(zip));
|
||||
mu_assert_int_eq(strlen(TESTDATA1), zip_entry_size(zip));
|
||||
mu_check(CRC32DATA1 == zip_entry_crc32(zip));
|
||||
|
||||
mu_assert_int_eq(0, strcmp(zip_entry_name(zip), "test/test-1.txt"));
|
||||
mu_assert_int_eq(0, zip_entry_close(zip));
|
||||
|
||||
zip_close(zip);
|
||||
}
|
||||
|
||||
MU_TEST(test_entry_read) {
|
||||
char *bufencode1 = NULL;
|
||||
char *bufencode2 = NULL;
|
||||
char *buf = NULL;
|
||||
size_t bufsize;
|
||||
|
||||
struct zip_t *zip =
|
||||
zip_stream_open(NULL, 0, ZIP_DEFAULT_COMPRESSION_LEVEL, 'w');
|
||||
mu_check(zip != NULL);
|
||||
|
||||
mu_assert_int_eq(0, zip_entry_open(zip, "test/test-1.txt"));
|
||||
mu_assert_int_eq(0, zip_entry_write(zip, TESTDATA1, strlen(TESTDATA1)));
|
||||
mu_assert_int_eq(0, zip_entry_close(zip));
|
||||
|
||||
ssize_t n = zip_stream_copy(zip, (void **)&bufencode1, NULL);
|
||||
zip_stream_copy(zip, (void **)&bufencode2, &bufsize);
|
||||
mu_assert_int_eq(0, strncmp(bufencode1, bufencode2, bufsize));
|
||||
|
||||
zip_stream_close(zip);
|
||||
|
||||
struct zip_t *zipstream = zip_stream_open(bufencode1, n, 0, 'r');
|
||||
mu_check(zipstream != NULL);
|
||||
|
||||
mu_assert_int_eq(0, zip_entry_open(zipstream, "test/test-1.txt"));
|
||||
n = zip_entry_read(zipstream, (void **)&buf, NULL);
|
||||
mu_assert_int_eq(0, strncmp(buf, TESTDATA1, (size_t)n));
|
||||
mu_assert_int_eq(0, zip_entry_close(zipstream));
|
||||
|
||||
zip_stream_close(zipstream);
|
||||
|
||||
free(buf);
|
||||
free(bufencode1);
|
||||
free(bufencode2);
|
||||
}
|
||||
|
||||
MU_TEST(test_list_entries) {
|
||||
struct zip_t *zip = zip_open(ZIPNAME, 0, 'r');
|
||||
mu_check(zip != NULL);
|
||||
|
||||
int i = 0, n = zip_entries_total(zip);
|
||||
for (; i < n; ++i) {
|
||||
mu_assert_int_eq(0, zip_entry_openbyindex(zip, i));
|
||||
fprintf(stdout, "[%d]: %s", i, zip_entry_name(zip));
|
||||
if (zip_entry_isdir(zip)) {
|
||||
fprintf(stdout, " (DIR)");
|
||||
}
|
||||
fprintf(stdout, "\n");
|
||||
mu_assert_int_eq(0, zip_entry_close(zip));
|
||||
}
|
||||
|
||||
zip_close(zip);
|
||||
}
|
||||
|
||||
MU_TEST(test_entries_deletebyindex) {
|
||||
size_t entries[] = {5, 6, 7, 9, 8};
|
||||
|
||||
struct zip_t *zip = zip_open(ZIPNAME, 0, 'd');
|
||||
mu_check(zip != NULL);
|
||||
|
||||
mu_assert_int_eq(5, zip_entries_deletebyindex(zip, entries, 5));
|
||||
|
||||
zip_close(zip);
|
||||
|
||||
zip = zip_open(ZIPNAME, 0, 'r');
|
||||
mu_check(zip != NULL);
|
||||
|
||||
mu_assert_int_eq(ZIP_ENOENT, zip_entry_open(zip, "delete.me"));
|
||||
mu_assert_int_eq(0, zip_entry_close(zip));
|
||||
fprintf(stdout, "delete.me: %s\n", zip_strerror(ZIP_ENOENT));
|
||||
|
||||
mu_assert_int_eq(ZIP_ENOENT, zip_entry_open(zip, "_"));
|
||||
mu_assert_int_eq(0, zip_entry_close(zip));
|
||||
fprintf(stdout, "_: %s\n", zip_strerror(ZIP_ENOENT));
|
||||
|
||||
mu_assert_int_eq(ZIP_ENOENT, zip_entry_open(zip, "delete/file.1"));
|
||||
mu_assert_int_eq(0, zip_entry_close(zip));
|
||||
fprintf(stdout, "delete/file.1: %s\n", zip_strerror(ZIP_ENOENT));
|
||||
|
||||
mu_assert_int_eq(ZIP_ENOENT, zip_entry_open(zip, "deleteme/file.3"));
|
||||
mu_assert_int_eq(0, zip_entry_close(zip));
|
||||
fprintf(stdout, "delete/file.3: %s\n", zip_strerror(ZIP_ENOENT));
|
||||
|
||||
mu_assert_int_eq(ZIP_ENOENT, zip_entry_open(zip, "delete/file.2"));
|
||||
mu_assert_int_eq(0, zip_entry_close(zip));
|
||||
fprintf(stdout, "delete/file.2: %s\n", zip_strerror(ZIP_ENOENT));
|
||||
|
||||
mu_assert_int_eq(total_entries - 5, zip_entries_total(zip));
|
||||
|
||||
mu_assert_int_eq(0, zip_entry_open(zip, "delete/file.4"));
|
||||
|
||||
size_t buftmp = 0;
|
||||
char *buf = NULL;
|
||||
ssize_t bufsize = zip_entry_read(zip, (void **)&buf, &buftmp);
|
||||
|
||||
mu_assert_int_eq(bufsize, strlen(TESTDATA2));
|
||||
mu_assert_int_eq((size_t)bufsize, buftmp);
|
||||
mu_assert_int_eq(0, strncmp(buf, TESTDATA2, bufsize));
|
||||
mu_assert_int_eq(0, zip_entry_close(zip));
|
||||
|
||||
free(buf);
|
||||
buf = NULL;
|
||||
|
||||
zip_close(zip);
|
||||
}
|
||||
|
||||
MU_TEST(test_entries_deleteinvalid) {
|
||||
size_t entries[] = {111, 222, 333, 444};
|
||||
|
||||
struct zip_t *zip = zip_open(ZIPNAME, 0, 'd');
|
||||
mu_check(zip != NULL);
|
||||
|
||||
mu_assert_int_eq(0, zip_entries_deletebyindex(zip, entries, 4));
|
||||
|
||||
zip_close(zip);
|
||||
|
||||
zip = zip_open(ZIPNAME, 0, 'r');
|
||||
mu_check(zip != NULL);
|
||||
|
||||
mu_assert_int_eq(0, zip_entry_open(zip, "delete.me"));
|
||||
mu_assert_int_eq(0, zip_entry_close(zip));
|
||||
|
||||
mu_assert_int_eq(0, zip_entry_open(zip, "_"));
|
||||
mu_assert_int_eq(0, zip_entry_close(zip));
|
||||
|
||||
mu_assert_int_eq(0, zip_entry_open(zip, "delete/file.1"));
|
||||
mu_assert_int_eq(0, zip_entry_close(zip));
|
||||
|
||||
mu_assert_int_eq(0, zip_entry_open(zip, "deleteme/file.3"));
|
||||
mu_assert_int_eq(0, zip_entry_close(zip));
|
||||
|
||||
mu_assert_int_eq(0, zip_entry_open(zip, "delete/file.2"));
|
||||
mu_assert_int_eq(0, zip_entry_close(zip));
|
||||
|
||||
mu_assert_int_eq(total_entries, zip_entries_total(zip));
|
||||
|
||||
mu_assert_int_eq(0, zip_entry_open(zip, "delete/file.4"));
|
||||
|
||||
size_t buftmp = 0;
|
||||
char *buf = NULL;
|
||||
ssize_t bufsize = zip_entry_read(zip, (void **)&buf, &buftmp);
|
||||
|
||||
mu_assert_int_eq(bufsize, strlen(TESTDATA2));
|
||||
mu_assert_int_eq((size_t)bufsize, buftmp);
|
||||
mu_assert_int_eq(0, strncmp(buf, TESTDATA2, bufsize));
|
||||
mu_assert_int_eq(0, zip_entry_close(zip));
|
||||
|
||||
free(buf);
|
||||
buf = NULL;
|
||||
|
||||
zip_close(zip);
|
||||
}
|
||||
|
||||
MU_TEST(test_entries_delete) {
|
||||
char *entries[] = {"delete.me", "_", "delete/file.1", "deleteme/file.3",
|
||||
"delete/file.2"};
|
||||
|
||||
struct zip_t *zip = zip_open(ZIPNAME, 0, 'd');
|
||||
mu_check(zip != NULL);
|
||||
|
||||
mu_assert_int_eq(5, zip_entries_delete(zip, entries, 5));
|
||||
|
||||
zip_close(zip);
|
||||
|
||||
zip = zip_open(ZIPNAME, 0, 'r');
|
||||
mu_check(zip != NULL);
|
||||
|
||||
mu_assert_int_eq(ZIP_ENOENT, zip_entry_open(zip, "delete.me"));
|
||||
mu_assert_int_eq(0, zip_entry_close(zip));
|
||||
fprintf(stdout, "delete.me: %s\n", zip_strerror(ZIP_ENOENT));
|
||||
|
||||
mu_assert_int_eq(ZIP_ENOENT, zip_entry_open(zip, "_"));
|
||||
mu_assert_int_eq(0, zip_entry_close(zip));
|
||||
fprintf(stdout, "_: %s\n", zip_strerror(ZIP_ENOENT));
|
||||
|
||||
mu_assert_int_eq(ZIP_ENOENT, zip_entry_open(zip, "delete/file.1"));
|
||||
mu_assert_int_eq(0, zip_entry_close(zip));
|
||||
fprintf(stdout, "delete/file.1: %s\n", zip_strerror(ZIP_ENOENT));
|
||||
|
||||
mu_assert_int_eq(ZIP_ENOENT, zip_entry_open(zip, "deleteme/file.3"));
|
||||
mu_assert_int_eq(0, zip_entry_close(zip));
|
||||
fprintf(stdout, "delete/file.3: %s\n", zip_strerror(ZIP_ENOENT));
|
||||
|
||||
mu_assert_int_eq(ZIP_ENOENT, zip_entry_open(zip, "delete/file.2"));
|
||||
mu_assert_int_eq(0, zip_entry_close(zip));
|
||||
fprintf(stdout, "delete/file.2: %s\n", zip_strerror(ZIP_ENOENT));
|
||||
|
||||
mu_assert_int_eq(total_entries - 5, zip_entries_total(zip));
|
||||
|
||||
mu_assert_int_eq(0, zip_entry_open(zip, "delete/file.4"));
|
||||
|
||||
size_t buftmp = 0;
|
||||
char *buf = NULL;
|
||||
ssize_t bufsize = zip_entry_read(zip, (void **)&buf, &buftmp);
|
||||
|
||||
mu_assert_int_eq(bufsize, strlen(TESTDATA2));
|
||||
mu_assert_int_eq((size_t)bufsize, buftmp);
|
||||
mu_assert_int_eq(0, strncmp(buf, TESTDATA2, bufsize));
|
||||
mu_assert_int_eq(0, zip_entry_close(zip));
|
||||
|
||||
free(buf);
|
||||
buf = NULL;
|
||||
|
||||
zip_close(zip);
|
||||
}
|
||||
|
||||
MU_TEST(test_entry_offset) {
|
||||
struct zip_t *zip = zip_open(ZIPNAME, 0, 'r');
|
||||
mu_check(zip != NULL);
|
||||
|
||||
unsigned long long off = 0ULL;
|
||||
int i = 0, n = zip_entries_total(zip);
|
||||
for (; i < n; i++) {
|
||||
mu_assert_int_eq(0, zip_entry_openbyindex(zip, i));
|
||||
mu_assert_int_eq(i, zip_entry_index(zip));
|
||||
|
||||
mu_assert_int_eq(off, zip_entry_header_offset(zip));
|
||||
|
||||
off = zip_entry_header_offset(zip) + MZ_ZIP_LOCAL_DIR_HEADER_SIZE +
|
||||
strlen(zip_entry_name(zip)) + MZ_ZIP64_MAX_CENTRAL_EXTRA_FIELD_SIZE +
|
||||
zip_entry_comp_size(zip);
|
||||
fprintf(stdout, "\n[%d: %s]: header: %llu, dir: %llu, size: %llu (%llu)\n",
|
||||
i, zip_entry_name(zip), zip_entry_header_offset(zip),
|
||||
zip_entry_dir_offset(zip), zip_entry_comp_size(zip), off);
|
||||
|
||||
mu_assert_int_eq(0, zip_entry_close(zip));
|
||||
}
|
||||
|
||||
zip_close(zip);
|
||||
}
|
||||
|
||||
MU_TEST_SUITE(test_entry_suite) {
|
||||
MU_SUITE_CONFIGURE(&test_setup, &test_teardown);
|
||||
|
||||
MU_RUN_TEST(test_entry_name);
|
||||
MU_RUN_TEST(test_entry_opencasesensitive);
|
||||
MU_RUN_TEST(test_entry_index);
|
||||
MU_RUN_TEST(test_entry_openbyindex);
|
||||
MU_RUN_TEST(test_entry_read);
|
||||
MU_RUN_TEST(test_list_entries);
|
||||
MU_RUN_TEST(test_entries_deletebyindex);
|
||||
MU_RUN_TEST(test_entries_delete);
|
||||
MU_RUN_TEST(test_entry_offset);
|
||||
}
|
||||
|
||||
#define UNUSED(x) (void)x
|
||||
|
||||
int main(int argc, char *argv[]) {
|
||||
UNUSED(argc);
|
||||
UNUSED(argv);
|
||||
|
||||
MU_RUN_SUITE(test_entry_suite);
|
||||
MU_REPORT();
|
||||
return MU_EXIT_CODE;
|
||||
}
|
|
@ -0,0 +1,161 @@
|
|||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
|
||||
#include <zip.h>
|
||||
|
||||
#include "minunit.h"
|
||||
|
||||
#if defined(_WIN32) || defined(_WIN64)
|
||||
#define MKTEMP _mktemp
|
||||
#define UNLINK _unlink
|
||||
#else
|
||||
#define MKTEMP mkstemp
|
||||
#define UNLINK unlink
|
||||
#endif
|
||||
|
||||
static char ZIPNAME[L_tmpnam + 1] = {0};
|
||||
|
||||
#define TESTDATA1 "Some test data 1...\0"
|
||||
#define TESTDATA2 "Some test data 2...\0"
|
||||
|
||||
void test_setup(void) {
|
||||
strncpy(ZIPNAME, "z-XXXXXX\0", L_tmpnam);
|
||||
MKTEMP(ZIPNAME);
|
||||
|
||||
struct zip_t *zip = zip_open(ZIPNAME, ZIP_DEFAULT_COMPRESSION_LEVEL, 'w');
|
||||
|
||||
zip_entry_open(zip, "test/test-1.txt");
|
||||
zip_entry_write(zip, TESTDATA1, strlen(TESTDATA1));
|
||||
zip_entry_close(zip);
|
||||
|
||||
zip_entry_open(zip, "test\\test-2.txt");
|
||||
zip_entry_write(zip, TESTDATA2, strlen(TESTDATA2));
|
||||
zip_entry_close(zip);
|
||||
|
||||
zip_entry_open(zip, "test\\empty/");
|
||||
zip_entry_close(zip);
|
||||
|
||||
zip_entry_open(zip, "empty/");
|
||||
zip_entry_close(zip);
|
||||
|
||||
zip_entry_open(zip, "dotfiles/.test");
|
||||
zip_entry_write(zip, TESTDATA2, strlen(TESTDATA2));
|
||||
zip_entry_close(zip);
|
||||
|
||||
zip_close(zip);
|
||||
}
|
||||
|
||||
void test_teardown(void) {
|
||||
UNLINK("test/test-1.txt");
|
||||
UNLINK("test/test-2.txt");
|
||||
UNLINK("test/empty");
|
||||
UNLINK("test");
|
||||
UNLINK("empty");
|
||||
UNLINK("dotfiles/.test");
|
||||
UNLINK("dotfiles");
|
||||
UNLINK(ZIPNAME);
|
||||
}
|
||||
|
||||
#define UNUSED(x) (void)x
|
||||
|
||||
struct buffer_t {
|
||||
char *data;
|
||||
size_t size;
|
||||
};
|
||||
|
||||
static size_t on_extract(void *arg, uint64_t offset, const void *data,
|
||||
size_t size) {
|
||||
UNUSED(offset);
|
||||
|
||||
struct buffer_t *buf = (struct buffer_t *)arg;
|
||||
buf->data = realloc(buf->data, buf->size + size + 1);
|
||||
|
||||
memcpy(&(buf->data[buf->size]), data, size);
|
||||
buf->size += size;
|
||||
buf->data[buf->size] = 0;
|
||||
|
||||
return size;
|
||||
}
|
||||
|
||||
MU_TEST(test_extract) {
|
||||
struct buffer_t buf;
|
||||
|
||||
struct zip_t *zip = zip_open(ZIPNAME, 0, 'r');
|
||||
mu_check(zip != NULL);
|
||||
|
||||
memset((void *)&buf, 0, sizeof(struct buffer_t));
|
||||
|
||||
mu_assert_int_eq(0, zip_entry_open(zip, "test/test-1.txt"));
|
||||
mu_assert_int_eq(0, zip_entry_extract(zip, on_extract, &buf));
|
||||
mu_assert_int_eq(strlen(TESTDATA1), buf.size);
|
||||
mu_assert_int_eq(0, strncmp(buf.data, TESTDATA1, buf.size));
|
||||
mu_assert_int_eq(0, zip_entry_close(zip));
|
||||
|
||||
free(buf.data);
|
||||
buf.data = NULL;
|
||||
buf.size = 0;
|
||||
|
||||
memset((void *)&buf, 0, sizeof(struct buffer_t));
|
||||
|
||||
mu_assert_int_eq(0, zip_entry_open(zip, "dotfiles/.test"));
|
||||
mu_assert_int_eq(0, zip_entry_extract(zip, on_extract, &buf));
|
||||
mu_assert_int_eq(strlen(TESTDATA2), buf.size);
|
||||
mu_assert_int_eq(0, strncmp(buf.data, TESTDATA2, buf.size));
|
||||
mu_assert_int_eq(0, zip_entry_close(zip));
|
||||
|
||||
free(buf.data);
|
||||
buf.data = NULL;
|
||||
buf.size = 0;
|
||||
|
||||
zip_close(zip);
|
||||
}
|
||||
|
||||
MU_TEST(test_extract_stream) {
|
||||
mu_assert_int_eq(
|
||||
ZIP_ENOINIT,
|
||||
zip_extract("non_existing_directory/non_existing_archive.zip", ".", NULL,
|
||||
NULL));
|
||||
mu_assert_int_eq(ZIP_ENOINIT, zip_stream_extract("", 0, ".", NULL, NULL));
|
||||
fprintf(stdout, "zip_stream_extract: %s\n", zip_strerror(ZIP_ENOINIT));
|
||||
|
||||
FILE *fp = NULL;
|
||||
#if defined(_MSC_VER)
|
||||
if (0 != fopen_s(&fp, ZIPNAME, "rb+"))
|
||||
#else
|
||||
if (!(fp = fopen(ZIPNAME, "rb+")))
|
||||
#endif
|
||||
{
|
||||
mu_fail("Cannot open filename\n");
|
||||
}
|
||||
|
||||
fseek(fp, 0L, SEEK_END);
|
||||
size_t filesize = ftell(fp);
|
||||
fseek(fp, 0L, SEEK_SET);
|
||||
|
||||
char *stream = (char *)malloc(filesize * sizeof(char));
|
||||
memset(stream, 0, filesize);
|
||||
|
||||
size_t size = fread(stream, sizeof(char), filesize, fp);
|
||||
mu_assert_int_eq(filesize, size);
|
||||
|
||||
mu_assert_int_eq(0, zip_stream_extract(stream, size, ".", NULL, NULL));
|
||||
|
||||
free(stream);
|
||||
fclose(fp);
|
||||
}
|
||||
|
||||
MU_TEST_SUITE(test_extract_suite) {
|
||||
MU_SUITE_CONFIGURE(&test_setup, &test_teardown);
|
||||
|
||||
MU_RUN_TEST(test_extract);
|
||||
MU_RUN_TEST(test_extract_stream);
|
||||
}
|
||||
|
||||
int main(int argc, char *argv[]) {
|
||||
UNUSED(argc);
|
||||
UNUSED(argv);
|
||||
|
||||
MU_RUN_SUITE(test_extract_suite);
|
||||
MU_REPORT();
|
||||
return MU_EXIT_CODE;
|
||||
}
|
|
@ -1,127 +0,0 @@
|
|||
// Demonstrates miniz.c's compress() and uncompress() functions
|
||||
// (same as zlib's). Public domain, May 15 2011, Rich Geldreich,
|
||||
// richgel99@gmail.com. See "unlicense" statement at the end of tinfl.c.
|
||||
|
||||
#include <miniz.h>
|
||||
#include <stdio.h>
|
||||
|
||||
typedef unsigned char uint8;
|
||||
typedef unsigned short uint16;
|
||||
typedef unsigned int uint;
|
||||
|
||||
// The string to compress.
|
||||
static const char *s_pStr =
|
||||
"Good morning Dr. Chandra. This is Hal. I am ready for my first lesson."
|
||||
"Good morning Dr. Chandra. This is Hal. I am ready for my first lesson."
|
||||
"Good morning Dr. Chandra. This is Hal. I am ready for my first lesson."
|
||||
"Good morning Dr. Chandra. This is Hal. I am ready for my first lesson."
|
||||
"Good morning Dr. Chandra. This is Hal. I am ready for my first lesson."
|
||||
"Good morning Dr. Chandra. This is Hal. I am ready for my first lesson."
|
||||
"Good morning Dr. Chandra. This is Hal. I am ready for my first lesson.";
|
||||
|
||||
int main(int argc, char *argv[]) {
|
||||
uint step = 0;
|
||||
int cmp_status;
|
||||
uLong src_len = (uLong)strlen(s_pStr);
|
||||
uLong uncomp_len = src_len;
|
||||
uLong cmp_len;
|
||||
uint8 *pCmp, *pUncomp;
|
||||
size_t sz;
|
||||
uint total_succeeded = 0;
|
||||
(void)argc, (void)argv;
|
||||
|
||||
printf("miniz.c version: %s\n", MZ_VERSION);
|
||||
|
||||
do {
|
||||
pCmp = (uint8 *)tdefl_compress_mem_to_heap(s_pStr, src_len, &cmp_len, 0);
|
||||
if (!pCmp) {
|
||||
printf("tdefl_compress_mem_to_heap failed\n");
|
||||
return EXIT_FAILURE;
|
||||
}
|
||||
if (src_len <= cmp_len) {
|
||||
printf("tdefl_compress_mem_to_heap failed: from %u to %u bytes\n",
|
||||
(mz_uint32)uncomp_len, (mz_uint32)cmp_len);
|
||||
free(pCmp);
|
||||
return EXIT_FAILURE;
|
||||
}
|
||||
|
||||
sz = tdefl_compress_mem_to_mem(pCmp, cmp_len, s_pStr, src_len, 0);
|
||||
if (sz != cmp_len) {
|
||||
printf("tdefl_compress_mem_to_mem failed: expected %u, got %u\n",
|
||||
(mz_uint32)cmp_len, (mz_uint32)sz);
|
||||
free(pCmp);
|
||||
return EXIT_FAILURE;
|
||||
}
|
||||
|
||||
// Allocate buffers to hold compressed and uncompressed data.
|
||||
free(pCmp);
|
||||
cmp_len = compressBound(src_len);
|
||||
pCmp = (mz_uint8 *)malloc((size_t)cmp_len);
|
||||
pUncomp = (mz_uint8 *)malloc((size_t)src_len);
|
||||
if ((!pCmp) || (!pUncomp)) {
|
||||
printf("Out of memory!\n");
|
||||
return EXIT_FAILURE;
|
||||
}
|
||||
|
||||
// Compress the string.
|
||||
cmp_status =
|
||||
compress(pCmp, &cmp_len, (const unsigned char *)s_pStr, src_len);
|
||||
if (cmp_status != Z_OK) {
|
||||
printf("compress() failed!\n");
|
||||
free(pCmp);
|
||||
free(pUncomp);
|
||||
return EXIT_FAILURE;
|
||||
}
|
||||
|
||||
printf("Compressed from %u to %u bytes\n", (mz_uint32)src_len,
|
||||
(mz_uint32)cmp_len);
|
||||
|
||||
if (step) {
|
||||
// Purposely corrupt the compressed data if fuzzy testing (this is a
|
||||
// very crude fuzzy test).
|
||||
uint n = 1 + (rand() % 3);
|
||||
while (n--) {
|
||||
uint i = rand() % cmp_len;
|
||||
pCmp[i] ^= (rand() & 0xFF);
|
||||
}
|
||||
}
|
||||
|
||||
// Decompress.
|
||||
cmp_status = uncompress(pUncomp, &uncomp_len, pCmp, cmp_len);
|
||||
total_succeeded += (cmp_status == Z_OK);
|
||||
|
||||
if (step) {
|
||||
printf("Simple fuzzy test: step %u total_succeeded: %u\n", step,
|
||||
total_succeeded);
|
||||
} else {
|
||||
if (cmp_status != Z_OK) {
|
||||
printf("uncompress failed!\n");
|
||||
free(pCmp);
|
||||
free(pUncomp);
|
||||
return EXIT_FAILURE;
|
||||
}
|
||||
|
||||
printf("Decompressed from %u to %u bytes\n", (mz_uint32)cmp_len,
|
||||
(mz_uint32)uncomp_len);
|
||||
|
||||
// Ensure uncompress() returned the expected data.
|
||||
if ((uncomp_len != src_len) ||
|
||||
(memcmp(pUncomp, s_pStr, (size_t)src_len))) {
|
||||
printf("Decompression failed!\n");
|
||||
free(pCmp);
|
||||
free(pUncomp);
|
||||
return EXIT_FAILURE;
|
||||
}
|
||||
}
|
||||
|
||||
free(pCmp);
|
||||
free(pUncomp);
|
||||
|
||||
step++;
|
||||
|
||||
// Keep on fuzzy testing if there's a non-empty command line.
|
||||
} while (argc >= 2);
|
||||
|
||||
printf("Success.\n");
|
||||
return EXIT_SUCCESS;
|
||||
}
|
|
@ -0,0 +1,68 @@
|
|||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
|
||||
#include <zip.h>
|
||||
|
||||
#include "minunit.h"
|
||||
|
||||
#if defined(_WIN32) || defined(_WIN64)
|
||||
#define MKTEMP _mktemp
|
||||
#else
|
||||
#define MKTEMP mkstemp
|
||||
#endif
|
||||
|
||||
static char ZIPNAME[L_tmpnam + 1] = {0};
|
||||
|
||||
void test_setup(void) {
|
||||
strncpy(ZIPNAME, "z-XXXXXX\0", L_tmpnam);
|
||||
MKTEMP(ZIPNAME);
|
||||
}
|
||||
|
||||
void test_teardown(void) { remove(ZIPNAME); }
|
||||
|
||||
MU_TEST(test_openwitherror) {
|
||||
int errnum;
|
||||
struct zip_t *zip =
|
||||
zip_openwitherror(ZIPNAME, ZIP_DEFAULT_COMPRESSION_LEVEL, 'r', &errnum);
|
||||
mu_check(zip == NULL);
|
||||
mu_assert_int_eq(ZIP_ERINIT, errnum);
|
||||
|
||||
zip = zip_openwitherror(ZIPNAME, ZIP_DEFAULT_COMPRESSION_LEVEL, 'w', &errnum);
|
||||
mu_check(zip != NULL);
|
||||
mu_assert_int_eq(0, errnum);
|
||||
|
||||
zip_close(zip);
|
||||
}
|
||||
|
||||
MU_TEST(test_stream_openwitherror) {
|
||||
int errnum;
|
||||
struct zip_t *zip = zip_stream_openwitherror(
|
||||
NULL, 0, ZIP_DEFAULT_COMPRESSION_LEVEL, 'r', &errnum);
|
||||
mu_check(zip == NULL);
|
||||
mu_assert_int_eq(ZIP_EINVMODE, errnum);
|
||||
|
||||
zip = zip_stream_openwitherror(NULL, 0, ZIP_DEFAULT_COMPRESSION_LEVEL, 'w',
|
||||
&errnum);
|
||||
mu_check(zip != NULL);
|
||||
mu_assert_int_eq(0, errnum);
|
||||
|
||||
zip_stream_close(zip);
|
||||
}
|
||||
|
||||
MU_TEST_SUITE(test_entry_suite) {
|
||||
MU_SUITE_CONFIGURE(&test_setup, &test_teardown);
|
||||
|
||||
MU_RUN_TEST(test_openwitherror);
|
||||
MU_RUN_TEST(test_stream_openwitherror);
|
||||
}
|
||||
|
||||
#define UNUSED(x) (void)x
|
||||
|
||||
int main(int argc, char *argv[]) {
|
||||
UNUSED(argc);
|
||||
UNUSED(argv);
|
||||
|
||||
MU_RUN_SUITE(test_entry_suite);
|
||||
MU_REPORT();
|
||||
return MU_EXIT_CODE;
|
||||
}
|
|
@ -0,0 +1,191 @@
|
|||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <sys/stat.h>
|
||||
|
||||
#include <zip.h>
|
||||
|
||||
#include "minunit.h"
|
||||
|
||||
#if defined(_WIN32) || defined(_WIN64)
|
||||
#define MKTEMP _mktemp
|
||||
#define UNLINK _unlink
|
||||
#else
|
||||
#define MKTEMP mkstemp
|
||||
#define UNLINK unlink
|
||||
#endif
|
||||
|
||||
static char ZIPNAME[L_tmpnam + 1] = {0};
|
||||
static char XFILE[L_tmpnam + 1] = {0};
|
||||
static char RFILE[L_tmpnam + 1] = {0};
|
||||
static char WFILE[L_tmpnam + 1] = {0};
|
||||
|
||||
void test_setup(void) {
|
||||
strncpy(ZIPNAME, "z-XXXXXX\0", L_tmpnam);
|
||||
strncpy(XFILE, "x-XXXXXX\0", L_tmpnam);
|
||||
strncpy(RFILE, "r-XXXXXX\0", L_tmpnam);
|
||||
strncpy(WFILE, "w-XXXXXX\0", L_tmpnam);
|
||||
|
||||
MKTEMP(ZIPNAME);
|
||||
MKTEMP(XFILE);
|
||||
MKTEMP(RFILE);
|
||||
MKTEMP(WFILE);
|
||||
}
|
||||
|
||||
void test_teardown(void) {
|
||||
UNLINK(WFILE);
|
||||
UNLINK(RFILE);
|
||||
UNLINK(XFILE);
|
||||
UNLINK(ZIPNAME);
|
||||
}
|
||||
|
||||
#if defined(_MSC_VER) || defined(__MINGW32__)
|
||||
#define MZ_FILE_STAT_STRUCT _stat
|
||||
#define MZ_FILE_STAT _stat
|
||||
#else
|
||||
#define MZ_FILE_STAT_STRUCT stat
|
||||
#define MZ_FILE_STAT stat
|
||||
#endif
|
||||
|
||||
#define XMODE 0100777
|
||||
#define RMODE 0100444
|
||||
#define WMODE 0100666
|
||||
#define UNIXMODE 0100600
|
||||
|
||||
MU_TEST(test_exe_permissions) {
|
||||
struct MZ_FILE_STAT_STRUCT file_stats;
|
||||
|
||||
const char *filenames[] = {XFILE};
|
||||
FILE *f = fopen(XFILE, "w");
|
||||
fclose(f);
|
||||
chmod(XFILE, XMODE);
|
||||
|
||||
mu_assert_int_eq(0, zip_create(ZIPNAME, filenames, 1));
|
||||
remove(XFILE);
|
||||
|
||||
mu_assert_int_eq(0, zip_extract(ZIPNAME, ".", NULL, NULL));
|
||||
|
||||
mu_assert_int_eq(0, MZ_FILE_STAT(XFILE, &file_stats));
|
||||
mu_assert_int_eq(XMODE, file_stats.st_mode);
|
||||
}
|
||||
|
||||
MU_TEST(test_read_permissions) {
|
||||
struct MZ_FILE_STAT_STRUCT file_stats;
|
||||
|
||||
const char *filenames[] = {RFILE};
|
||||
FILE *f = fopen(RFILE, "w");
|
||||
fclose(f);
|
||||
chmod(RFILE, RMODE);
|
||||
|
||||
mu_assert_int_eq(0, zip_create(ZIPNAME, filenames, 1));
|
||||
remove(RFILE);
|
||||
|
||||
mu_assert_int_eq(0, zip_extract(ZIPNAME, ".", NULL, NULL));
|
||||
mu_assert_int_eq(0, MZ_FILE_STAT(RFILE, &file_stats));
|
||||
mu_assert_int_eq(RMODE, file_stats.st_mode);
|
||||
|
||||
// chmod from 444 to 666 to be able delete the file on windows
|
||||
chmod(RFILE, WMODE);
|
||||
}
|
||||
|
||||
MU_TEST(test_write_permissions) {
|
||||
struct MZ_FILE_STAT_STRUCT file_stats;
|
||||
|
||||
const char *filenames[] = {WFILE};
|
||||
FILE *f = fopen(WFILE, "w");
|
||||
fclose(f);
|
||||
chmod(WFILE, WMODE);
|
||||
|
||||
mu_assert_int_eq(0, zip_create(ZIPNAME, filenames, 1));
|
||||
remove(WFILE);
|
||||
|
||||
mu_assert_int_eq(0, zip_extract(ZIPNAME, ".", NULL, NULL));
|
||||
mu_assert_int_eq(0, MZ_FILE_STAT(WFILE, &file_stats));
|
||||
mu_assert_int_eq(WMODE, file_stats.st_mode);
|
||||
}
|
||||
|
||||
#define TESTDATA1 "Some test data 1...\0"
|
||||
|
||||
MU_TEST(test_unix_permissions) {
|
||||
// UNIX or APPLE
|
||||
struct MZ_FILE_STAT_STRUCT file_stats;
|
||||
|
||||
struct zip_t *zip = zip_open(ZIPNAME, ZIP_DEFAULT_COMPRESSION_LEVEL, 'w');
|
||||
mu_check(zip != NULL);
|
||||
|
||||
mu_assert_int_eq(0, zip_entry_open(zip, RFILE));
|
||||
mu_assert_int_eq(0, zip_entry_write(zip, TESTDATA1, strlen(TESTDATA1)));
|
||||
mu_assert_int_eq(0, zip_entry_close(zip));
|
||||
|
||||
zip_close(zip);
|
||||
|
||||
mu_assert_int_eq(0, zip_extract(ZIPNAME, ".", NULL, NULL));
|
||||
|
||||
mu_assert_int_eq(0, MZ_FILE_STAT(RFILE, &file_stats));
|
||||
|
||||
mu_assert_int_eq(UNIXMODE, file_stats.st_mode);
|
||||
}
|
||||
|
||||
MU_TEST(test_mtime) {
|
||||
struct MZ_FILE_STAT_STRUCT file_stat1, file_stat2;
|
||||
|
||||
const char *filename = "test.data";
|
||||
FILE *stream = NULL;
|
||||
struct zip_t *zip = NULL;
|
||||
#if defined(_MSC_VER)
|
||||
if (0 != fopen_s(&stream, filename, "w+"))
|
||||
#else
|
||||
if (!(stream = fopen(filename, "w+")))
|
||||
#endif
|
||||
{
|
||||
mu_fail("Cannot open filename\n");
|
||||
}
|
||||
fwrite(TESTDATA1, sizeof(char), strlen(TESTDATA1), stream);
|
||||
mu_assert_int_eq(0, fclose(stream));
|
||||
|
||||
memset(&file_stat1, 0, sizeof(file_stat1));
|
||||
memset(&file_stat2, 0, sizeof(file_stat2));
|
||||
|
||||
zip = zip_open(ZIPNAME, ZIP_DEFAULT_COMPRESSION_LEVEL, 'w');
|
||||
mu_check(zip != NULL);
|
||||
|
||||
mu_assert_int_eq(0, zip_entry_open(zip, filename));
|
||||
mu_assert_int_eq(0, zip_entry_fwrite(zip, filename));
|
||||
mu_assert_int_eq(0, zip_entry_close(zip));
|
||||
|
||||
zip_close(zip);
|
||||
|
||||
mu_assert_int_eq(0, MZ_FILE_STAT(filename, &file_stat1));
|
||||
remove(filename);
|
||||
|
||||
mu_assert_int_eq(0, zip_extract(ZIPNAME, ".", NULL, NULL));
|
||||
mu_assert_int_eq(0, MZ_FILE_STAT(filename, &file_stat2));
|
||||
remove(filename);
|
||||
|
||||
fprintf(stdout, "file_stat1.st_mtime: %lu\n", file_stat1.st_mtime);
|
||||
fprintf(stdout, "file_stat2.st_mtime: %lu\n", file_stat2.st_mtime);
|
||||
mu_check(labs(file_stat1.st_mtime - file_stat2.st_mtime) <= 1);
|
||||
}
|
||||
|
||||
MU_TEST_SUITE(test_permissions_suite) {
|
||||
MU_SUITE_CONFIGURE(&test_setup, &test_teardown);
|
||||
|
||||
#if defined(_WIN32) || defined(__WIN32__)
|
||||
#else
|
||||
MU_RUN_TEST(test_exe_permissions);
|
||||
MU_RUN_TEST(test_read_permissions);
|
||||
MU_RUN_TEST(test_write_permissions);
|
||||
MU_RUN_TEST(test_unix_permissions);
|
||||
#endif
|
||||
MU_RUN_TEST(test_mtime);
|
||||
}
|
||||
|
||||
#define UNUSED(x) (void)x
|
||||
|
||||
int main(int argc, char *argv[]) {
|
||||
UNUSED(argc);
|
||||
UNUSED(argv);
|
||||
|
||||
MU_RUN_SUITE(test_permissions_suite);
|
||||
MU_REPORT();
|
||||
return MU_EXIT_CODE;
|
||||
}
|
|
@ -0,0 +1,146 @@
|
|||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
|
||||
#include <zip.h>
|
||||
|
||||
#include "minunit.h"
|
||||
|
||||
#if defined(_WIN32) || defined(_WIN64)
|
||||
#define MKTEMP _mktemp
|
||||
#else
|
||||
#define MKTEMP mkstemp
|
||||
#endif
|
||||
|
||||
static char ZIPNAME[L_tmpnam + 1] = {0};
|
||||
|
||||
#define CRC32DATA1 2220805626
|
||||
#define TESTDATA1 "Some test data 1...\0"
|
||||
|
||||
#define TESTDATA2 "Some test data 2...\0"
|
||||
#define CRC32DATA2 2532008468
|
||||
|
||||
void test_setup(void) {
|
||||
strncpy(ZIPNAME, "z-XXXXXX\0", L_tmpnam);
|
||||
MKTEMP(ZIPNAME);
|
||||
|
||||
struct zip_t *zip = zip_open(ZIPNAME, ZIP_DEFAULT_COMPRESSION_LEVEL, 'w');
|
||||
|
||||
zip_entry_open(zip, "test/test-1.txt");
|
||||
zip_entry_write(zip, TESTDATA1, strlen(TESTDATA1));
|
||||
zip_entry_close(zip);
|
||||
|
||||
zip_entry_open(zip, "test\\test-2.txt");
|
||||
zip_entry_write(zip, TESTDATA2, strlen(TESTDATA2));
|
||||
zip_entry_close(zip);
|
||||
|
||||
zip_entry_open(zip, "test\\empty/");
|
||||
zip_entry_close(zip);
|
||||
|
||||
zip_entry_open(zip, "empty/");
|
||||
zip_entry_close(zip);
|
||||
|
||||
zip_entry_open(zip, "dotfiles/.test");
|
||||
zip_entry_write(zip, TESTDATA2, strlen(TESTDATA2));
|
||||
zip_entry_close(zip);
|
||||
|
||||
zip_close(zip);
|
||||
}
|
||||
|
||||
void test_teardown(void) { remove(ZIPNAME); }
|
||||
|
||||
MU_TEST(test_read) {
|
||||
char *buf = NULL;
|
||||
ssize_t bufsize;
|
||||
size_t buftmp;
|
||||
|
||||
struct zip_t *zip = zip_open(ZIPNAME, 0, 'r');
|
||||
mu_check(zip != NULL);
|
||||
mu_assert_int_eq(1, zip_is64(zip));
|
||||
|
||||
mu_assert_int_eq(0, zip_entry_open(zip, "test\\test-1.txt"));
|
||||
mu_assert_int_eq(strlen(TESTDATA1), zip_entry_size(zip));
|
||||
mu_check(CRC32DATA1 == zip_entry_crc32(zip));
|
||||
bufsize = zip_entry_read(zip, (void **)&buf, &buftmp);
|
||||
mu_assert_int_eq(strlen(TESTDATA1), bufsize);
|
||||
mu_assert_int_eq((size_t)bufsize, buftmp);
|
||||
mu_assert_int_eq(0, strncmp(buf, TESTDATA1, bufsize));
|
||||
mu_assert_int_eq(0, zip_entry_close(zip));
|
||||
free(buf);
|
||||
buf = NULL;
|
||||
|
||||
mu_assert_int_eq(0, zip_entry_open(zip, "test/test-2.txt"));
|
||||
mu_assert_int_eq(strlen(TESTDATA2), zip_entry_size(zip));
|
||||
mu_check(CRC32DATA2 == zip_entry_crc32(zip));
|
||||
bufsize = zip_entry_read(zip, (void **)&buf, NULL);
|
||||
mu_assert_int_eq(strlen(TESTDATA2), (size_t)bufsize);
|
||||
mu_assert_int_eq(0, strncmp(buf, TESTDATA2, (size_t)bufsize));
|
||||
mu_assert_int_eq(0, zip_entry_close(zip));
|
||||
free(buf);
|
||||
buf = NULL;
|
||||
|
||||
mu_assert_int_eq(0, zip_entry_open(zip, "test\\empty/"));
|
||||
mu_assert_int_eq(0, strcmp(zip_entry_name(zip), "test/empty/"));
|
||||
mu_assert_int_eq(0, zip_entry_size(zip));
|
||||
mu_assert_int_eq(0, zip_entry_crc32(zip));
|
||||
mu_assert_int_eq(0, zip_entry_close(zip));
|
||||
|
||||
zip_close(zip);
|
||||
}
|
||||
|
||||
MU_TEST(test_noallocread) {
|
||||
ssize_t bufsize;
|
||||
size_t buftmp = strlen(TESTDATA2);
|
||||
char *buf = calloc(buftmp, sizeof(char));
|
||||
|
||||
struct zip_t *zip = zip_open(ZIPNAME, 0, 'r');
|
||||
mu_check(zip != NULL);
|
||||
mu_assert_int_eq(1, zip_is64(zip));
|
||||
|
||||
mu_assert_int_eq(0, zip_entry_open(zip, "test/test-2.txt"));
|
||||
bufsize = zip_entry_noallocread(zip, (void *)buf, buftmp);
|
||||
mu_assert_int_eq(buftmp, (size_t)bufsize);
|
||||
mu_assert_int_eq(0, strncmp(buf, TESTDATA2, buftmp));
|
||||
mu_assert_int_eq(0, zip_entry_close(zip));
|
||||
free(buf);
|
||||
buf = NULL;
|
||||
|
||||
buftmp = strlen(TESTDATA1);
|
||||
buf = calloc(buftmp, sizeof(char));
|
||||
mu_assert_int_eq(0, zip_entry_open(zip, "test/test-1.txt"));
|
||||
bufsize = zip_entry_noallocread(zip, (void *)buf, buftmp);
|
||||
mu_assert_int_eq(buftmp, (size_t)bufsize);
|
||||
mu_assert_int_eq(0, strncmp(buf, TESTDATA1, buftmp));
|
||||
mu_assert_int_eq(0, zip_entry_close(zip));
|
||||
free(buf);
|
||||
buf = NULL;
|
||||
|
||||
buftmp = strlen(TESTDATA2);
|
||||
buf = calloc(buftmp, sizeof(char));
|
||||
mu_assert_int_eq(0, zip_entry_open(zip, "dotfiles/.test"));
|
||||
bufsize = zip_entry_noallocread(zip, (void *)buf, buftmp);
|
||||
mu_assert_int_eq(buftmp, (size_t)bufsize);
|
||||
mu_assert_int_eq(0, strncmp(buf, TESTDATA2, buftmp));
|
||||
mu_assert_int_eq(0, zip_entry_close(zip));
|
||||
free(buf);
|
||||
buf = NULL;
|
||||
|
||||
zip_close(zip);
|
||||
}
|
||||
|
||||
MU_TEST_SUITE(test_read_suite) {
|
||||
MU_SUITE_CONFIGURE(&test_setup, &test_teardown);
|
||||
|
||||
MU_RUN_TEST(test_read);
|
||||
MU_RUN_TEST(test_noallocread);
|
||||
}
|
||||
|
||||
#define UNUSED(x) (void)x
|
||||
|
||||
int main(int argc, char *argv[]) {
|
||||
UNUSED(argc);
|
||||
UNUSED(argv);
|
||||
|
||||
MU_RUN_SUITE(test_read_suite);
|
||||
MU_REPORT();
|
||||
return MU_EXIT_CODE;
|
||||
}
|
|
@ -0,0 +1,113 @@
|
|||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
|
||||
#include <zip.h>
|
||||
|
||||
#include "minunit.h"
|
||||
|
||||
#if defined(_WIN32) || defined(_WIN64)
|
||||
#define MKTEMP _mktemp
|
||||
#define UNLINK _unlink
|
||||
#else
|
||||
#define MKTEMP mkstemp
|
||||
#define UNLINK unlink
|
||||
#endif
|
||||
|
||||
static char ZIPNAME[L_tmpnam + 1] = {0};
|
||||
static char WFILE[L_tmpnam + 1] = {0};
|
||||
|
||||
void test_setup(void) {
|
||||
strncpy(ZIPNAME, "z-XXXXXX\0", L_tmpnam);
|
||||
strncpy(WFILE, "w-XXXXXX\0", L_tmpnam);
|
||||
|
||||
MKTEMP(ZIPNAME);
|
||||
MKTEMP(WFILE);
|
||||
}
|
||||
|
||||
void test_teardown(void) {
|
||||
UNLINK(WFILE);
|
||||
UNLINK(ZIPNAME);
|
||||
}
|
||||
|
||||
#define CRC32DATA1 2220805626
|
||||
#define TESTDATA1 "Some test data 1...\0"
|
||||
|
||||
MU_TEST(test_write) {
|
||||
struct zip_t *zip = zip_open(ZIPNAME, ZIP_DEFAULT_COMPRESSION_LEVEL, 'w');
|
||||
mu_check(zip != NULL);
|
||||
|
||||
mu_assert_int_eq(0, zip_entry_open(zip, "test/test-1.txt"));
|
||||
mu_assert_int_eq(0, zip_entry_write(zip, TESTDATA1, strlen(TESTDATA1)));
|
||||
mu_assert_int_eq(0, strcmp(zip_entry_name(zip), "test/test-1.txt"));
|
||||
mu_assert_int_eq(0, zip_entry_index(zip));
|
||||
mu_assert_int_eq(strlen(TESTDATA1), zip_entry_size(zip));
|
||||
mu_check(CRC32DATA1 == zip_entry_crc32(zip));
|
||||
mu_assert_int_eq(0, zip_entry_close(zip));
|
||||
|
||||
mu_assert_int_eq(1, zip_is64(zip));
|
||||
|
||||
zip_close(zip);
|
||||
}
|
||||
|
||||
MU_TEST(test_write_utf) {
|
||||
struct zip_t *zip = zip_open(ZIPNAME, ZIP_DEFAULT_COMPRESSION_LEVEL, 'w');
|
||||
mu_check(zip != NULL);
|
||||
|
||||
mu_assert_int_eq(0, zip_entry_open(zip, "тест/Если-б-не-было-войны.txt"));
|
||||
mu_assert_int_eq(0, zip_entry_write(zip, TESTDATA1, strlen(TESTDATA1)));
|
||||
mu_assert_int_eq(
|
||||
0, strcmp(zip_entry_name(zip), "тест/Если-б-не-было-войны.txt"));
|
||||
mu_assert_int_eq(0, zip_entry_index(zip));
|
||||
mu_assert_int_eq(strlen(TESTDATA1), zip_entry_size(zip));
|
||||
mu_check(CRC32DATA1 == zip_entry_crc32(zip));
|
||||
mu_assert_int_eq(0, zip_entry_close(zip));
|
||||
|
||||
mu_assert_int_eq(1, zip_is64(zip));
|
||||
|
||||
zip_close(zip);
|
||||
}
|
||||
|
||||
MU_TEST(test_fwrite) {
|
||||
const char *filename = WFILE;
|
||||
FILE *stream = NULL;
|
||||
struct zip_t *zip = NULL;
|
||||
#if defined(_MSC_VER)
|
||||
if (0 != fopen_s(&stream, filename, "w+"))
|
||||
#else
|
||||
if (!(stream = fopen(filename, "w+")))
|
||||
#endif
|
||||
{
|
||||
// Cannot open filename
|
||||
mu_fail("Cannot open filename\n");
|
||||
}
|
||||
fwrite(TESTDATA1, sizeof(char), strlen(TESTDATA1), stream);
|
||||
mu_assert_int_eq(0, fclose(stream));
|
||||
|
||||
zip = zip_open(ZIPNAME, 9, 'w');
|
||||
mu_check(zip != NULL);
|
||||
mu_assert_int_eq(0, zip_entry_open(zip, WFILE));
|
||||
mu_assert_int_eq(0, zip_entry_fwrite(zip, WFILE));
|
||||
mu_assert_int_eq(0, zip_entry_close(zip));
|
||||
mu_assert_int_eq(1, zip_is64(zip));
|
||||
|
||||
zip_close(zip);
|
||||
}
|
||||
|
||||
MU_TEST_SUITE(test_write_suite) {
|
||||
MU_SUITE_CONFIGURE(&test_setup, &test_teardown);
|
||||
|
||||
MU_RUN_TEST(test_write);
|
||||
MU_RUN_TEST(test_write_utf);
|
||||
MU_RUN_TEST(test_fwrite);
|
||||
}
|
||||
|
||||
#define UNUSED(x) (void)x
|
||||
|
||||
int main(int argc, char *argv[]) {
|
||||
UNUSED(argc);
|
||||
UNUSED(argv);
|
||||
|
||||
MU_RUN_SUITE(test_write_suite);
|
||||
MU_REPORT();
|
||||
return MU_EXIT_CODE;
|
||||
}
|
|
@ -28,6 +28,7 @@ __Importers__:
|
|||
+ KHR_texture_transform ( 5.1 under test )
|
||||
- HMB
|
||||
- IFC-STEP
|
||||
- IQM
|
||||
- IRR / IRRMESH
|
||||
- [LWO](https://en.wikipedia.org/wiki/LightWave_3D)
|
||||
- LWS
|
||||
|
|
|
@ -57,9 +57,9 @@ OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
|||
#include <iomanip>
|
||||
|
||||
#if defined(_MSC_VER) && !defined(__clang__)
|
||||
#define AI_SIZEFMT "%Iu"
|
||||
# define AI_SIZEFMT "%Iu"
|
||||
#else
|
||||
#define AI_SIZEFMT "%zu"
|
||||
# define AI_SIZEFMT "%zu"
|
||||
#endif
|
||||
|
||||
// ---------------------------------------------------------------------------------
|
||||
|
@ -99,9 +99,9 @@ inline int ai_snprintf(char *outBuf, size_t size, const char *format, ...) {
|
|||
}
|
||||
|
||||
#elif defined(__MINGW32__)
|
||||
#define ai_snprintf __mingw_snprintf
|
||||
# define ai_snprintf __mingw_snprintf
|
||||
#else
|
||||
#define ai_snprintf snprintf
|
||||
# define ai_snprintf snprintf
|
||||
#endif
|
||||
|
||||
// ---------------------------------------------------------------------------------
|
||||
|
@ -185,6 +185,7 @@ AI_FORCE_INLINE std::string ai_rgba2hex(int r, int g, int b, int a, bool with_he
|
|||
// ---------------------------------------------------------------------------------
|
||||
/// @brief Performs a trim from start (in place)
|
||||
/// @param s string to trim.
|
||||
// ---------------------------------------------------------------------------------
|
||||
AI_FORCE_INLINE void ai_trim_left(std::string &s) {
|
||||
s.erase(s.begin(), std::find_if(s.begin(), s.end(), [](unsigned char ch) {
|
||||
return !std::isspace(ch);
|
||||
|
@ -195,7 +196,6 @@ AI_FORCE_INLINE void ai_trim_left(std::string &s) {
|
|||
/// @brief Performs a trim from end (in place).
|
||||
/// @param s string to trim.
|
||||
// ---------------------------------------------------------------------------------
|
||||
// ---------------------------------------------------------------------------------
|
||||
AI_FORCE_INLINE void ai_trim_right(std::string &s) {
|
||||
s.erase(std::find_if(s.rbegin(), s.rend(), [](unsigned char ch) {
|
||||
return !std::isspace(ch);
|
||||
|
@ -214,6 +214,10 @@ AI_FORCE_INLINE std::string ai_trim(std::string &s) {
|
|||
return out;
|
||||
}
|
||||
|
||||
// ---------------------------------------------------------------------------------
|
||||
/// @brief Performs a to lower operation onto on single character.
|
||||
/// @param in The character
|
||||
/// @return the character as lower-case.
|
||||
// ---------------------------------------------------------------------------------
|
||||
template <class char_t>
|
||||
AI_FORCE_INLINE char_t ai_tolower(char_t in) {
|
||||
|
@ -233,6 +237,10 @@ AI_FORCE_INLINE std::string ai_tolower(const std::string &in) {
|
|||
return out;
|
||||
}
|
||||
|
||||
// ---------------------------------------------------------------------------------
|
||||
/// @brief Performs a to upper operation onto on single character.
|
||||
/// @param in The character
|
||||
/// @return the character as upper-case.
|
||||
// ---------------------------------------------------------------------------------
|
||||
template <class char_t>
|
||||
AI_FORCE_INLINE char_t ai_toupper(char_t in) {
|
||||
|
@ -243,6 +251,7 @@ AI_FORCE_INLINE char_t ai_toupper(char_t in) {
|
|||
/// @brief Performs a ToLower-operation and return the upper-case string.
|
||||
/// @param in The incoming string.
|
||||
/// @return The string as uppercase.
|
||||
// ---------------------------------------------------------------------------------
|
||||
AI_FORCE_INLINE std::string ai_str_toupper(const std::string &in) {
|
||||
std::string out(in);
|
||||
std::transform(out.begin(), out.end(), out.begin(), [](char c) { return ai_toupper(c); });
|
||||
|
@ -255,6 +264,7 @@ AI_FORCE_INLINE std::string ai_str_toupper(const std::string &in) {
|
|||
/// @param in The incoming string.
|
||||
/// @param placeholder Placeholder character, default is a question mark.
|
||||
/// @return The string, with all non-printable characters replaced.
|
||||
// ---------------------------------------------------------------------------------
|
||||
AI_FORCE_INLINE std::string ai_str_toprintable(const std::string &in, char placeholder = '?') {
|
||||
std::string out(in);
|
||||
std::transform(out.begin(), out.end(), out.begin(), [placeholder] (unsigned char c) {
|
||||
|
@ -271,9 +281,9 @@ AI_FORCE_INLINE std::string ai_str_toprintable(const std::string &in, char place
|
|||
/// @param placeholder Placeholder character, default is a question mark.
|
||||
/// @return The string, with all non-printable characters replaced. Will return an
|
||||
/// empty string if in is null or len is <= 0.
|
||||
// ---------------------------------------------------------------------------------
|
||||
AI_FORCE_INLINE std::string ai_str_toprintable(const char *in, int len, char placeholder = '?') {
|
||||
return (in && len > 0) ? ai_str_toprintable(std::string(in, len), placeholder) : std::string();
|
||||
}
|
||||
|
||||
|
||||
#endif // INCLUDED_AI_STRINGUTILS_H
|
||||
|
|
|
@ -43,6 +43,7 @@ OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
|||
#define INCLUDED_AI_IRRXML_WRAPPER
|
||||
|
||||
#include <assimp/ai_assert.h>
|
||||
#include <assimp/StringUtils.h>
|
||||
#include <assimp/DefaultLogger.hpp>
|
||||
|
||||
#include "BaseImporter.h"
|
||||
|
@ -447,6 +448,7 @@ inline bool TXmlParser<TNodeType>::getValueAsString(XmlNode &node, std::string &
|
|||
}
|
||||
|
||||
text = node.text().as_string();
|
||||
text = ai_trim(text);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
|
|
@ -150,7 +150,7 @@ inline uint8_t HexOctetToDecimal(const char* in) {
|
|||
// ------------------------------------------------------------------------------------
|
||||
// signed variant of strtoul10
|
||||
// ------------------------------------------------------------------------------------
|
||||
inline int strtol10( const char* in, const char** out=0) {
|
||||
inline int strtol10( const char* in, const char** out = 0) {
|
||||
bool inv = (*in=='-');
|
||||
if ( inv || *in == '+' ) {
|
||||
++in;
|
||||
|
@ -158,7 +158,7 @@ inline int strtol10( const char* in, const char** out=0) {
|
|||
|
||||
int value = strtoul10(in,out);
|
||||
if (inv) {
|
||||
if (value < INT_MAX) {
|
||||
if (value < INT_MAX && value > INT_MIN) {
|
||||
value = -value;
|
||||
} else {
|
||||
ASSIMP_LOG_WARN( "Converting the string \"", in, "\" into an inverted value resulted in overflow." );
|
||||
|
|
|
@ -334,7 +334,12 @@ enum aiTextureType {
|
|||
#define AI_TEXTURE_TYPE_MAX aiTextureType_TRANSMISSION
|
||||
|
||||
// -------------------------------------------------------------------------------
|
||||
// Get a string for a given aiTextureType
|
||||
/**
|
||||
* @brief Get a string for a given aiTextureType
|
||||
*
|
||||
* @param in The texture type
|
||||
* @return The description string for the texture type.
|
||||
*/
|
||||
ASSIMP_API const char *aiTextureTypeToString(enum aiTextureType in);
|
||||
|
||||
// ---------------------------------------------------------------------------
|
||||
|
@ -425,7 +430,8 @@ enum aiShadingMode {
|
|||
};
|
||||
|
||||
// ---------------------------------------------------------------------------
|
||||
/** @brief Defines some mixed flags for a particular texture.
|
||||
/**
|
||||
* @brief Defines some mixed flags for a particular texture.
|
||||
*
|
||||
* Usually you'll instruct your cg artists how textures have to look like ...
|
||||
* and how they will be processed in your application. However, if you use
|
||||
|
@ -464,7 +470,8 @@ enum aiTextureFlags {
|
|||
};
|
||||
|
||||
// ---------------------------------------------------------------------------
|
||||
/** @brief Defines alpha-blend flags.
|
||||
/**
|
||||
* @brief Defines alpha-blend flags.
|
||||
*
|
||||
* If you're familiar with OpenGL or D3D, these flags aren't new to you.
|
||||
* They define *how* the final color value of a pixel is computed, basing
|
||||
|
@ -508,7 +515,8 @@ enum aiBlendMode {
|
|||
#include "./Compiler/pushpack1.h"
|
||||
|
||||
// ---------------------------------------------------------------------------
|
||||
/** @brief Defines how an UV channel is transformed.
|
||||
/**
|
||||
* @brief Defines how an UV channel is transformed.
|
||||
*
|
||||
* This is just a helper structure for the #AI_MATKEY_UVTRANSFORM key.
|
||||
* See its documentation for more details.
|
||||
|
@ -552,8 +560,8 @@ struct aiUVTransform {
|
|||
|
||||
//! @cond AI_DOX_INCLUDE_INTERNAL
|
||||
// ---------------------------------------------------------------------------
|
||||
/** @brief A very primitive RTTI system for the contents of material
|
||||
* properties.
|
||||
/**
|
||||
* @brief A very primitive RTTI system for the contents of material properties.
|
||||
*/
|
||||
enum aiPropertyTypeInfo {
|
||||
/** Array of single-precision (32 Bit) floats
|
||||
|
@ -698,7 +706,14 @@ struct aiMaterial
|
|||
#ifdef __cplusplus
|
||||
|
||||
public:
|
||||
/**
|
||||
* @brief The class constructor.
|
||||
*/
|
||||
aiMaterial();
|
||||
|
||||
/**
|
||||
* @brief The class destructor.
|
||||
*/
|
||||
~aiMaterial();
|
||||
|
||||
// -------------------------------------------------------------------
|
||||
|
|
|
@ -113,19 +113,19 @@ struct aiMetadata;
|
|||
*/
|
||||
// -------------------------------------------------------------------------------
|
||||
|
||||
inline aiMetadataType GetAiType(bool) {
|
||||
inline aiMetadataType GetAiType(const bool &) {
|
||||
return AI_BOOL;
|
||||
}
|
||||
inline aiMetadataType GetAiType(int32_t) {
|
||||
return AI_INT32;
|
||||
}
|
||||
inline aiMetadataType GetAiType(uint64_t) {
|
||||
inline aiMetadataType GetAiType(const uint64_t &) {
|
||||
return AI_UINT64;
|
||||
}
|
||||
inline aiMetadataType GetAiType(float) {
|
||||
inline aiMetadataType GetAiType(const float &) {
|
||||
return AI_FLOAT;
|
||||
}
|
||||
inline aiMetadataType GetAiType(double) {
|
||||
inline aiMetadataType GetAiType(const double &) {
|
||||
return AI_DOUBLE;
|
||||
}
|
||||
inline aiMetadataType GetAiType(const aiString &) {
|
||||
|
@ -137,10 +137,10 @@ inline aiMetadataType GetAiType(const aiVector3D &) {
|
|||
inline aiMetadataType GetAiType(const aiMetadata &) {
|
||||
return AI_AIMETADATA;
|
||||
}
|
||||
inline aiMetadataType GetAiType(int64_t) {
|
||||
inline aiMetadataType GetAiType(const int64_t &) {
|
||||
return AI_INT64;
|
||||
}
|
||||
inline aiMetadataType GetAiType(uint32_t) {
|
||||
inline aiMetadataType GetAiType(const uint32_t &) {
|
||||
return AI_UINT32;
|
||||
}
|
||||
|
||||
|
|
|
@ -379,7 +379,7 @@ enum aiPostProcessSteps
|
|||
* point primitives to separate meshes.
|
||||
* </li>
|
||||
* <li>Set the <tt>#AI_CONFIG_PP_SBP_REMOVE</tt> importer property to
|
||||
* @code aiPrimitiveType_POINTS | aiPrimitiveType_LINES
|
||||
* @code aiPrimitiveType_POINT | aiPrimitiveType_LINE
|
||||
* @endcode to cause SortByPType to reject point
|
||||
* and line meshes from the scene.
|
||||
* </li>
|
||||
|
|
|
@ -141,25 +141,28 @@ struct ASSIMP_API aiNode {
|
|||
/** Destructor */
|
||||
~aiNode();
|
||||
|
||||
/** Searches for a node with a specific name, beginning at this
|
||||
/**
|
||||
* @brief Searches for a node with a specific name, beginning at this
|
||||
* nodes. Normally you will call this method on the root node
|
||||
* of the scene.
|
||||
*
|
||||
* @param name Name to search for
|
||||
* @return nullptr or a valid Node if the search was successful.
|
||||
*/
|
||||
inline
|
||||
const aiNode* FindNode(const aiString& name) const {
|
||||
inline const aiNode* FindNode(const aiString& name) const {
|
||||
return FindNode(name.data);
|
||||
}
|
||||
|
||||
inline
|
||||
aiNode* FindNode(const aiString& name) {
|
||||
inline aiNode* FindNode(const aiString& name) {
|
||||
return FindNode(name.data);
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Will search for a node described by its name.
|
||||
* @param[in] name The name for the node to look for.
|
||||
* @return Pointer showing to the node or nullptr if not found.
|
||||
*/
|
||||
const aiNode* FindNode(const char* name) const;
|
||||
|
||||
aiNode* FindNode(const char* name);
|
||||
|
||||
/**
|
||||
|
@ -240,8 +243,7 @@ struct ASSIMP_API aiNode {
|
|||
* delete a given scene on your own.
|
||||
*/
|
||||
// -------------------------------------------------------------------------------
|
||||
struct aiScene
|
||||
{
|
||||
struct ASSIMP_API aiScene {
|
||||
/** Any combination of the AI_SCENE_FLAGS_XXX flags. By default
|
||||
* this value is 0, no flags are set. Most applications will
|
||||
* want to reject all scenes with the AI_SCENE_FLAGS_INCOMPLETE
|
||||
|
@ -355,10 +357,10 @@ struct aiScene
|
|||
#ifdef __cplusplus
|
||||
|
||||
//! Default constructor - set everything to 0/nullptr
|
||||
ASSIMP_API aiScene();
|
||||
aiScene();
|
||||
|
||||
//! Destructor
|
||||
ASSIMP_API ~aiScene();
|
||||
~aiScene();
|
||||
|
||||
//! Check whether the scene contains meshes
|
||||
//! Unless no special scene flags are set this will always be true.
|
||||
|
|
Some files were not shown because too many files have changed in this diff Show More
Loading…
Reference in New Issue