Merge branch 'master' into kimkulling/fix_artifact_export

pull/4938/head
Kim Kulling 2023-08-31 21:03:21 +02:00 committed by GitHub
commit 473318541b
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
206 changed files with 23576 additions and 11421 deletions

View File

@ -46,7 +46,7 @@ jobs:
CC: clang
- name: configure and build
uses: lukka/run-cmake@v2
uses: lukka/run-cmake@v3
with:
cmakeListsOrSettingsJson: CMakeListsTxtAdvanced
cmakeListsTxtPath: '${{ github.workspace }}/CMakeLists.txt'

View File

@ -49,8 +49,8 @@ option(ASSIMP_HUNTER_ENABLED "Enable Hunter package manager support" OFF)
IF(ASSIMP_HUNTER_ENABLED)
include("cmake-modules/HunterGate.cmake")
HunterGate(
URL "https://github.com/cpp-pm/hunter/archive/v0.24.0.tar.gz"
SHA1 "a3d7f4372b1dcd52faa6ff4a3bd5358e1d0e5efd"
URL "https://github.com/cpp-pm/hunter/archive/v0.24.17.tar.gz"
SHA1 "e6396699e414120e32557fe92db097b7655b760b"
)
add_definitions(-DASSIMP_USE_HUNTER)
@ -268,6 +268,11 @@ IF ((CMAKE_C_COMPILER_ID MATCHES "GNU") AND NOT MINGW)
SET(CMAKE_CXX_STANDARD 17)
SET(CMAKE_POSITION_INDEPENDENT_CODE ON)
ENDIF()
IF(CMAKE_CXX_COMPILER_VERSION GREATER_EQUAL 13)
MESSAGE(STATUS "GCC13 detected disabling \"-Wdangling-reference\" in Cpp files as it appears to be a false positive")
ADD_COMPILE_OPTIONS("$<$<COMPILE_LANGUAGE:CXX>:-Wno-dangling-reference>")
ENDIF()
# hide all not-exported symbols
IF(CMAKE_HOST_SYSTEM_PROCESSOR MATCHES "mips64" )
SET(CMAKE_CXX_FLAGS "-mxgot -fvisibility=hidden -fno-strict-aliasing -Wall ${CMAKE_CXX_FLAGS}")
@ -281,9 +286,9 @@ IF ((CMAKE_C_COMPILER_ID MATCHES "GNU") AND NOT MINGW)
ELSEIF(MSVC)
# enable multi-core compilation with MSVC
IF(CMAKE_CXX_COMPILER_ID MATCHES "Clang" ) # clang-cl
ADD_COMPILE_OPTIONS(/bigobj /W4 /WX )
ADD_COMPILE_OPTIONS(/bigobj)
ELSE() # msvc
ADD_COMPILE_OPTIONS(/MP /bigobj /W4 /WX)
ADD_COMPILE_OPTIONS(/MP /bigobj)
ENDIF()
# disable "elements of array '' will be default initialized" warning on MSVC2013

View File

@ -1,14 +1,9 @@
FROM ubuntu:14.04
FROM ubuntu:22.04
RUN apt-get update && apt-get install -y \
RUN apt-get update && apt-get install -y ninja-build \
git cmake build-essential software-properties-common
RUN add-apt-repository ppa:ubuntu-toolchain-r/test && apt-get update && apt-get install -y gcc-4.9 g++-4.9 && \
cd /usr/bin && \
rm gcc g++ cpp && \
ln -s gcc-4.9 gcc && \
ln -s g++-4.9 g++ && \
ln -s cpp-4.9 cpp
RUN add-apt-repository ppa:ubuntu-toolchain-r/test && apt-get update
WORKDIR /opt
@ -19,7 +14,8 @@ WORKDIR /opt/assimp
RUN git checkout master \
&& mkdir build && cd build && \
cmake \
cmake -G 'Ninja' \
-DCMAKE_BUILD_TYPE=Release \
-DASSIMP_BUILD_ASSIMP_TOOLS=ON \
.. && \
make && make install
ninja -j4 && ninja install

View File

@ -479,6 +479,11 @@ void Parser::ParseLV1MaterialListBlock() {
if (TokenMatch(filePtr, "MATERIAL_COUNT", 14)) {
ParseLV4MeshLong(iMaterialCount);
if (UINT_MAX - iOldMaterialCount < iMaterialCount) {
LogWarning("Out of range: material index is too large");
return;
}
// now allocate enough storage to hold all materials
m_vMaterials.resize(iOldMaterialCount + iMaterialCount, Material("INVALID"));
continue;

View File

@ -115,15 +115,12 @@ BlenderImporter::~BlenderImporter() {
delete modifier_cache;
}
static const char * const Tokens[] = { "BLENDER" };
static const char Token[] = "BLENDER";
// ------------------------------------------------------------------------------------------------
// Returns whether the class can handle the format of the given file.
bool BlenderImporter::CanRead(const std::string &pFile, IOSystem *pIOHandler, bool /*checkSig*/) const {
// note: this won't catch compressed files
static const char *tokens[] = { "<BLENDER", "blender" };
return SearchFileHeaderForToken(pIOHandler, pFile, tokens, AI_COUNT_OF(tokens));
return ParseMagicToken(pFile, pIOHandler).error.empty();
}
// ------------------------------------------------------------------------------------------------
@ -142,63 +139,21 @@ void BlenderImporter::SetupProperties(const Importer * /*pImp*/) {
// Imports the given file into the given scene structure.
void BlenderImporter::InternReadFile(const std::string &pFile,
aiScene *pScene, IOSystem *pIOHandler) {
#ifndef ASSIMP_BUILD_NO_COMPRESSED_BLEND
std::vector<char> uncompressed;
#endif
FileDatabase file;
std::shared_ptr<IOStream> stream(pIOHandler->Open(pFile, "rb"));
if (!stream) {
ThrowException("Could not open file for reading");
StreamOrError streamOrError = ParseMagicToken(pFile, pIOHandler);
if (!streamOrError.error.empty()) {
ThrowException(streamOrError.error);
}
std::shared_ptr<IOStream> stream = std::move(streamOrError.stream);
char magic[8] = { 0 };
stream->Read(magic, 7, 1);
if (strcmp(magic, Tokens[0])) {
// Check for presence of the gzip header. If yes, assume it is a
// compressed blend file and try uncompressing it, else fail. This is to
// avoid uncompressing random files which our loader might end up with.
#ifdef ASSIMP_BUILD_NO_COMPRESSED_BLEND
ThrowException("BLENDER magic bytes are missing, is this file compressed (Assimp was built without decompression support)?");
#else
if (magic[0] != 0x1f || static_cast<uint8_t>(magic[1]) != 0x8b) {
ThrowException("BLENDER magic bytes are missing, couldn't find GZIP header either");
}
char version[4] = { 0 };
file.i64bit = (stream->Read(version, 1, 1), version[0] == '-');
file.little = (stream->Read(version, 1, 1), version[0] == 'v');
LogDebug("Found no BLENDER magic word but a GZIP header, might be a compressed file");
if (magic[2] != 8) {
ThrowException("Unsupported GZIP compression method");
}
stream->Read(version, 3, 1);
version[3] = '\0';
// http://www.gzip.org/zlib/rfc-gzip.html#header-trailer
stream->Seek(0L, aiOrigin_SET);
std::shared_ptr<StreamReaderLE> reader = std::shared_ptr<StreamReaderLE>(new StreamReaderLE(stream));
size_t total = 0;
Compression compression;
if (compression.open(Compression::Format::Binary, Compression::FlushMode::NoFlush, 16 + Compression::MaxWBits)) {
total = compression.decompress((unsigned char *)reader->GetPtr(), reader->GetRemainingSize(), uncompressed);
compression.close();
}
// replace the input stream with a memory stream
stream = std::make_shared<MemoryIOStream>(reinterpret_cast<uint8_t *>(uncompressed.data()), total);
// .. and retry
stream->Read(magic, 7, 1);
if (strcmp(magic, "BLENDER")) {
ThrowException("Found no BLENDER magic word in decompressed GZIP file");
}
#endif
}
file.i64bit = (stream->Read(magic, 1, 1), magic[0] == '-');
file.little = (stream->Read(magic, 1, 1), magic[0] == 'v');
stream->Read(magic, 3, 1);
magic[3] = '\0';
LogInfo("Blender version is ", magic[0], ".", magic + 1,
LogInfo("Blender version is ", version[0], ".", version + 1,
" (64bit: ", file.i64bit ? "true" : "false",
", little endian: ", file.little ? "true" : "false", ")");
@ -1338,4 +1293,55 @@ aiNode *BlenderImporter::ConvertNode(const Scene &in, const Object *obj, Convers
return node.release();
}
BlenderImporter::StreamOrError BlenderImporter::ParseMagicToken(const std::string &pFile, IOSystem *pIOHandler) const {
std::shared_ptr<IOStream> stream(pIOHandler->Open(pFile, "rb"));
if (stream == nullptr) {
return {{}, {}, "Could not open file for reading"};
}
char magic[8] = { 0 };
stream->Read(magic, 7, 1);
if (strcmp(magic, Token) == 0) {
return {stream, {}, {}};
}
// Check for presence of the gzip header. If yes, assume it is a
// compressed blend file and try uncompressing it, else fail. This is to
// avoid uncompressing random files which our loader might end up with.
#ifdef ASSIMP_BUILD_NO_COMPRESSED_BLEND
return {{}, {}, "BLENDER magic bytes are missing, is this file compressed (Assimp was built without decompression support)?"};
#else
if (magic[0] != 0x1f || static_cast<uint8_t>(magic[1]) != 0x8b) {
return {{}, {}, "BLENDER magic bytes are missing, couldn't find GZIP header either"};
}
LogDebug("Found no BLENDER magic word but a GZIP header, might be a compressed file");
if (magic[2] != 8) {
return {{}, {}, "Unsupported GZIP compression method"};
}
// http://www.gzip.org/zlib/rfc-gzip.html#header-trailer
stream->Seek(0L, aiOrigin_SET);
std::shared_ptr<StreamReaderLE> reader = std::shared_ptr<StreamReaderLE>(new StreamReaderLE(stream));
size_t total = 0;
Compression compression;
auto uncompressed = std::make_shared<std::vector<char>>();
if (compression.open(Compression::Format::Binary, Compression::FlushMode::NoFlush, 16 + Compression::MaxWBits)) {
total = compression.decompress((unsigned char *)reader->GetPtr(), reader->GetRemainingSize(), *uncompressed);
compression.close();
}
// replace the input stream with a memory stream
stream = std::make_shared<MemoryIOStream>(reinterpret_cast<uint8_t *>(uncompressed->data()), total);
// .. and retry
stream->Read(magic, 7, 1);
if (strcmp(magic, Token) == 0) {
return {stream, uncompressed, {}};
}
return {{}, {}, "Found no BLENDER magic word in decompressed GZIP file"};
#endif
}
#endif // ASSIMP_BUILD_NO_BLEND_IMPORTER

View File

@ -180,6 +180,19 @@ private:
const Blender::MTex *tex,
Blender::ConversionData &conv_data);
// TODO: Move to a std::variant, once c++17 is supported.
struct StreamOrError {
std::shared_ptr<IOStream> stream;
std::shared_ptr<std::vector<char>> input;
std::string error;
};
// Returns either a stream (and optional input data for the stream) or
// an error if it can't parse the magic token.
StreamOrError ParseMagicToken(
const std::string &pFile,
IOSystem *pIOHandler) const;
private: // static stuff, mostly logging and error reporting.
// --------------------
static void CheckActualType(const Blender::ElemBase *dt,

View File

@ -95,6 +95,7 @@ ColladaLoader::ColladaLoader() :
noSkeletonMesh(false),
removeEmptyBones(false),
ignoreUpDirection(false),
ignoreUnitSize(false),
useColladaName(false),
mNodeNameCounter(0) {
// empty
@ -122,6 +123,7 @@ void ColladaLoader::SetupProperties(const Importer *pImp) {
noSkeletonMesh = pImp->GetPropertyInteger(AI_CONFIG_IMPORT_NO_SKELETON_MESHES, 0) != 0;
removeEmptyBones = pImp->GetPropertyInteger(AI_CONFIG_IMPORT_REMOVE_EMPTY_BONES, true) != 0;
ignoreUpDirection = pImp->GetPropertyInteger(AI_CONFIG_IMPORT_COLLADA_IGNORE_UP_DIRECTION, 0) != 0;
ignoreUnitSize = pImp->GetPropertyInteger(AI_CONFIG_IMPORT_COLLADA_IGNORE_UNIT_SIZE, 0) != 0;
useColladaName = pImp->GetPropertyInteger(AI_CONFIG_IMPORT_COLLADA_USE_COLLADA_NAMES, 0) != 0;
}
@ -170,12 +172,15 @@ void ColladaLoader::InternReadFile(const std::string &pFile, aiScene *pScene, IO
// ... then fill the materials with the now adjusted settings
FillMaterials(parser, pScene);
// Apply unit-size scale calculation
pScene->mRootNode->mTransformation *= aiMatrix4x4(parser.mUnitSize, 0, 0, 0,
0, parser.mUnitSize, 0, 0,
0, 0, parser.mUnitSize, 0,
0, 0, 0, 1);
if (!ignoreUnitSize) {
// Apply unit-size scale calculation
pScene->mRootNode->mTransformation *= aiMatrix4x4(
parser.mUnitSize, 0, 0, 0,
0, parser.mUnitSize, 0, 0,
0, 0, parser.mUnitSize, 0,
0, 0, 0, 1);
}
if (!ignoreUpDirection) {
// Convert to Y_UP, if different orientation
if (parser.mUpDirection == ColladaParser::UP_X) {

View File

@ -239,6 +239,7 @@ protected:
bool noSkeletonMesh;
bool removeEmptyBones;
bool ignoreUpDirection;
bool ignoreUnitSize;
bool useColladaName;
/** Used by FindNameForNode() to generate unique node names */

View File

@ -71,7 +71,7 @@ static const aiColor4D AI_DXF_DEFAULT_COLOR(aiColor4D(0.6f, 0.6f, 0.6f, 0.6f));
// color indices for DXF - 16 are supported, the table is
// taken directly from the DXF spec.
static aiColor4D g_aclrDxfIndexColors[] = {
aiColor4D (0.6f, 0.6f, 0.6f, 1.0f),
aiColor4D(0.6f, 0.6f, 0.6f, 1.0f),
aiColor4D (1.0f, 0.0f, 0.0f, 1.0f), // red
aiColor4D (0.0f, 1.0f, 0.0f, 1.0f), // green
aiColor4D (0.0f, 0.0f, 1.0f, 1.0f), // blue
@ -88,6 +88,7 @@ static aiColor4D g_aclrDxfIndexColors[] = {
aiColor4D (1.0f, 1.0f, 1.0f, 1.0f), // white
aiColor4D (0.6f, 0.0f, 1.0f, 1.0f) // violet
};
#define AI_DXF_NUM_INDEX_COLORS (sizeof(g_aclrDxfIndexColors)/sizeof(g_aclrDxfIndexColors[0]))
#define AI_DXF_ENTITIES_MAGIC_BLOCK "$ASSIMP_ENTITIES_MAGIC"
@ -109,14 +110,6 @@ static const aiImporterDesc desc = {
"dxf"
};
// ------------------------------------------------------------------------------------------------
// Constructor to be privately used by Importer
DXFImporter::DXFImporter() = default;
// ------------------------------------------------------------------------------------------------
// Destructor, private as well
DXFImporter::~DXFImporter() = default;
// ------------------------------------------------------------------------------------------------
// Returns whether the class can handle the format of the given file.
bool DXFImporter::CanRead( const std::string& filename, IOSystem* pIOHandler, bool /*checkSig*/ ) const {
@ -229,7 +222,7 @@ void DXFImporter::ConvertMeshes(aiScene* pScene, DXF::FileData& output) {
ASSIMP_LOG_VERBOSE_DEBUG("DXF: Unexpanded polycount is ", icount, ", vertex count is ", vcount);
}
if (! output.blocks.size() ) {
if (output.blocks.empty()) {
throw DeadlyImportError("DXF: no data blocks loaded");
}
@ -587,10 +580,11 @@ void DXFImporter::ParseInsertion(DXF::LineReader& reader, DXF::FileData& output)
}
}
#define DXF_POLYLINE_FLAG_CLOSED 0x1
#define DXF_POLYLINE_FLAG_3D_POLYLINE 0x8
#define DXF_POLYLINE_FLAG_3D_POLYMESH 0x10
#define DXF_POLYLINE_FLAG_POLYFACEMESH 0x40
static constexpr unsigned int DXF_POLYLINE_FLAG_CLOSED = 0x1;
// Currently unused
//static constexpr unsigned int DXF_POLYLINE_FLAG_3D_POLYLINE = 0x8;
//static constexpr unsigned int DXF_POLYLINE_FLAG_3D_POLYMESH = 0x10;
static constexpr unsigned int DXF_POLYLINE_FLAG_POLYFACEMESH = 0x40;
// ------------------------------------------------------------------------------------------------
void DXFImporter::ParsePolyLine(DXF::LineReader& reader, DXF::FileData& output) {
@ -639,12 +633,6 @@ void DXFImporter::ParsePolyLine(DXF::LineReader& reader, DXF::FileData& output)
reader++;
}
//if (!(line.flags & DXF_POLYLINE_FLAG_POLYFACEMESH)) {
// DefaultLogger::get()->warn((Formatter::format("DXF: polyline not currently supported: "),line.flags));
// output.blocks.back().lines.pop_back();
// return;
//}
if (vguess && line.positions.size() != vguess) {
ASSIMP_LOG_WARN("DXF: unexpected vertex count in polymesh: ",
line.positions.size(),", expected ", vguess );
@ -734,12 +722,18 @@ void DXFImporter::ParsePolyLineVertex(DXF::LineReader& reader, DXF::PolyLine& li
case 71:
case 72:
case 73:
case 74:
if (cnti == 4) {
ASSIMP_LOG_WARN("DXF: more than 4 indices per face not supported; ignoring");
break;
case 74: {
if (cnti == 4) {
ASSIMP_LOG_WARN("DXF: more than 4 indices per face not supported; ignoring");
break;
}
const int index = reader.ValueAsSignedInt();
if (index >= 0) {
indices[cnti++] = static_cast<unsigned int>(index);
} else {
ASSIMP_LOG_WARN("DXF: Skip invisible face.");
}
}
indices[cnti++] = reader.ValueAsUnsignedInt();
break;
// color
@ -777,8 +771,7 @@ void DXFImporter::ParsePolyLineVertex(DXF::LineReader& reader, DXF::PolyLine& li
}
// ------------------------------------------------------------------------------------------------
void DXFImporter::Parse3DFace(DXF::LineReader& reader, DXF::FileData& output)
{
void DXFImporter::Parse3DFace(DXF::LineReader& reader, DXF::FileData& output) {
// (note) this is also used for for parsing line entities, so we
// must handle the vertex_count == 2 case as well.
@ -795,8 +788,7 @@ void DXFImporter::Parse3DFace(DXF::LineReader& reader, DXF::FileData& output)
if (reader.GroupCode() == 0) {
break;
}
switch (reader.GroupCode())
{
switch (reader.GroupCode()) {
// 8 specifies the layer
case 8:

View File

@ -68,8 +68,8 @@ namespace DXF {
*/
class DXFImporter : public BaseImporter {
public:
DXFImporter();
~DXFImporter() override;
DXFImporter() = default;
~DXFImporter() override = default;
// -------------------------------------------------------------------
/** Returns whether the class can handle the format of the given file.

View File

@ -93,6 +93,8 @@ FBXConverter::FBXConverter(aiScene *out, const Document &doc, bool removeEmptyBo
mSceneOut(out),
doc(doc),
mRemoveEmptyBones(removeEmptyBones) {
// animations need to be converted first since this will
// populate the node_anim_chain_bits map, which is needed
// to determine which nodes need to be generated.
@ -427,12 +429,26 @@ void FBXConverter::ConvertCamera(const Camera &cam, const std::string &orig_name
out_camera->mLookAt = aiVector3D(1.0f, 0.0f, 0.0f);
out_camera->mUp = aiVector3D(0.0f, 1.0f, 0.0f);
out_camera->mHorizontalFOV = AI_DEG_TO_RAD(cam.FieldOfView());
// NOTE: Some software (maya) does not put FieldOfView in FBX, so we compute
// mHorizontalFOV from FocalLength and FilmWidth with unit conversion.
out_camera->mClipPlaneNear = cam.NearPlane();
out_camera->mClipPlaneFar = cam.FarPlane();
// TODO: This is not a complete solution for how FBX cameras can be stored.
// TODO: Incorporate non-square pixel aspect ratio.
// TODO: FBX aperture mode might be storing vertical FOV in need of conversion with aspect ratio.
float fov_deg = cam.FieldOfView();
// If FOV not specified in file, compute using FilmWidth and FocalLength.
if (fov_deg == kFovUnknown) {
float film_width_inches = cam.FilmWidth();
float focal_length_mm = cam.FocalLength();
ASSIMP_LOG_VERBOSE_DEBUG("FBX FOV unspecified. Computing from FilmWidth (", film_width_inches, "inches) and FocalLength (", focal_length_mm, "mm).");
double half_fov_rad = std::atan2(film_width_inches * 25.4 * 0.5, focal_length_mm);
out_camera->mHorizontalFOV = static_cast<float>(half_fov_rad);
} else {
// FBX fov is full-view degrees. We want half-view radians.
out_camera->mHorizontalFOV = AI_DEG_TO_RAD(fov_deg) * 0.5f;
}
out_camera->mHorizontalFOV = AI_DEG_TO_RAD(cam.FieldOfView());
out_camera->mClipPlaneNear = cam.NearPlane();
out_camera->mClipPlaneFar = cam.FarPlane();
}

View File

@ -55,9 +55,14 @@ OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
#define _AI_CONCAT(a,b) a ## b
#define AI_CONCAT(a,b) _AI_CONCAT(a,b)
namespace Assimp {
namespace FBX {
// Use an 'illegal' default FOV value to detect if the FBX camera has set the FOV.
static const float kFovUnknown = -1.0f;
class Parser;
class Object;
struct ImportSettings;
@ -247,7 +252,7 @@ public:
fbx_simple_property(FilmAspectRatio, float, 1.0f)
fbx_simple_property(ApertureMode, int, 0)
fbx_simple_property(FieldOfView, float, 1.0f)
fbx_simple_property(FieldOfView, float, kFovUnknown)
fbx_simple_property(FocalLength, float, 1.0f)
};

View File

@ -211,7 +211,7 @@ Scope::Scope(Parser& parser,bool topLevel)
elements.insert(ElementMap::value_type(str, element));
return;
}
delete element;
delete_Element(element);
ParseError("unexpected end of file",parser.LastToken());
} else {
elements.insert(ElementMap::value_type(str, element));

View File

@ -115,7 +115,9 @@ void HMPImporter::InternReadFile(const std::string &pFile,
throw DeadlyImportError("HMP File is too small.");
// Allocate storage and copy the contents of the file to a memory buffer
mBuffer = new uint8_t[fileSize];
auto deleter=[this](uint8_t* ptr){ delete[] ptr; mBuffer = nullptr; };
std::unique_ptr<uint8_t[], decltype(deleter)> buffer(new uint8_t[fileSize], deleter);
mBuffer = buffer.get();
file->Read((void *)mBuffer, 1, fileSize);
iFileSize = (unsigned int)fileSize;
@ -143,9 +145,6 @@ void HMPImporter::InternReadFile(const std::string &pFile,
// Print the magic word to the logger
std::string szBuffer = ai_str_toprintable((const char *)&iMagic, sizeof(iMagic));
delete[] mBuffer;
mBuffer = nullptr;
// We're definitely unable to load this file
throw DeadlyImportError("Unknown HMP subformat ", pFile,
". Magic word (", szBuffer, ") is not known");
@ -153,9 +152,6 @@ void HMPImporter::InternReadFile(const std::string &pFile,
// Set the AI_SCENE_FLAGS_TERRAIN bit
pScene->mFlags |= AI_SCENE_FLAGS_TERRAIN;
delete[] mBuffer;
mBuffer = nullptr;
}
// ------------------------------------------------------------------------------------------------
@ -445,11 +441,11 @@ void HMPImporter::ReadFirstSkin(unsigned int iNumSkins, const unsigned char *szC
szCursor += sizeof(uint32_t);
// allocate an output material
aiMaterial *pcMat = new aiMaterial();
std::unique_ptr<aiMaterial> pcMat(new aiMaterial());
// read the skin, this works exactly as for MDL7
ParseSkinLump_3DGS_MDL7(szCursor, &szCursor,
pcMat, iType, iWidth, iHeight);
pcMat.get(), iType, iWidth, iHeight);
// now we need to skip any other skins ...
for (unsigned int i = 1; i < iNumSkins; ++i) {
@ -468,7 +464,7 @@ void HMPImporter::ReadFirstSkin(unsigned int iNumSkins, const unsigned char *szC
// setup the material ...
pScene->mNumMaterials = 1;
pScene->mMaterials = new aiMaterial *[1];
pScene->mMaterials[0] = pcMat;
pScene->mMaterials[0] = pcMat.release();
*szCursorOut = szCursor;
}

File diff suppressed because it is too large Load Diff

View File

@ -53,7 +53,7 @@ OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
#include <assimp/StringUtils.h>
#include <assimp/anim.h>
namespace Assimp {
namespace Assimp {
// ---------------------------------------------------------------------------
/** Irr importer class.
@ -71,13 +71,13 @@ public:
/** Returns whether the class can handle the format of the given file.
* See BaseImporter::CanRead() for details.
*/
bool CanRead( const std::string& pFile, IOSystem* pIOHandler,
bool checkSig) const override;
bool CanRead(const std::string &pFile, IOSystem *pIOHandler,
bool checkSig) const override;
protected:
const aiImporterDesc* GetInfo () const override;
void InternReadFile( const std::string& pFile, aiScene* pScene, IOSystem* pIOHandler) override;
void SetupProperties(const Importer* pImp) override;
const aiImporterDesc *GetInfo() const override;
void InternReadFile(const std::string &pFile, aiScene *pScene, IOSystem *pIOHandler) override;
void SetupProperties(const Importer *pImp) override;
private:
/** Data structure for a scene-graph node animator
@ -85,27 +85,19 @@ private:
struct Animator {
// Type of the animator
enum AT {
UNKNOWN = 0x0,
ROTATION = 0x1,
FLY_CIRCLE = 0x2,
FLY_STRAIGHT = 0x3,
UNKNOWN = 0x0,
ROTATION = 0x1,
FLY_CIRCLE = 0x2,
FLY_STRAIGHT = 0x3,
FOLLOW_SPLINE = 0x4,
OTHER = 0x5
OTHER = 0x5
} type;
explicit Animator(AT t = UNKNOWN)
: type (t)
, speed ( ai_real( 0.001 ) )
, direction ( ai_real( 0.0 ), ai_real( 1.0 ), ai_real( 0.0 ) )
, circleRadius ( ai_real( 1.0) )
, tightness ( ai_real( 0.5 ) )
, loop (true)
, timeForWay (100)
{
explicit Animator(AT t = UNKNOWN) :
type(t), speed(ai_real(0.001)), direction(ai_real(0.0), ai_real(1.0), ai_real(0.0)), circleRadius(ai_real(1.0)), tightness(ai_real(0.5)), loop(true), timeForWay(100) {
}
// common parameters
ai_real speed;
aiVector3D direction;
@ -128,11 +120,9 @@ private:
/** Data structure for a scene-graph node in an IRR file
*/
struct Node
{
struct Node {
// Type of the node
enum ET
{
enum ET {
LIGHT,
CUBE,
MESH,
@ -144,21 +134,20 @@ private:
ANIMMESH
} type;
explicit Node(ET t)
: type (t)
, scaling (1.0,1.0,1.0) // assume uniform scaling by default
, parent()
, framesPerSecond (0.0)
, id()
, sphereRadius (1.0)
, spherePolyCountX (100)
, spherePolyCountY (100)
{
explicit Node(ET t) :
type(t), scaling(1.0, 1.0, 1.0) // assume uniform scaling by default
,
parent(),
framesPerSecond(0.0),
id(),
sphereRadius(1.0),
spherePolyCountX(100),
spherePolyCountY(100) {
// Generate a default name for the node
char buffer[128];
static int cnt;
ai_snprintf(buffer, 128, "IrrNode_%i",cnt++);
ai_snprintf(buffer, 128, "IrrNode_%i", cnt++);
name = std::string(buffer);
// reserve space for up to 5 materials
@ -175,10 +164,10 @@ private:
std::string name;
// List of all child nodes
std::vector<Node*> children;
std::vector<Node *> children;
// Parent node
Node* parent;
Node *parent;
// Animated meshes: frames per second
// 0.f if not specified
@ -190,13 +179,13 @@ private:
// Meshes: List of materials to be assigned
// along with their corresponding material flags
std::vector< std::pair<aiMaterial*, unsigned int> > materials;
std::vector<std::pair<aiMaterial *, unsigned int>> materials;
// Spheres: radius of the sphere to be generates
ai_real sphereRadius;
// Spheres: Number of polygons in the x,y direction
unsigned int spherePolyCountX,spherePolyCountY;
unsigned int spherePolyCountX, spherePolyCountY;
// List of all animators assigned to the node
std::list<Animator> animators;
@ -204,40 +193,54 @@ private:
/** Data structure for a vertex in an IRR skybox
*/
struct SkyboxVertex
{
struct SkyboxVertex {
SkyboxVertex() = default;
//! Construction from single vertex components
SkyboxVertex(ai_real px, ai_real py, ai_real pz,
ai_real nx, ai_real ny, ai_real nz,
ai_real uvx, ai_real uvy)
ai_real nx, ai_real ny, ai_real nz,
ai_real uvx, ai_real uvy)
: position (px,py,pz)
, normal (nx,ny,nz)
, uv (uvx,uvy,0.0)
{}
:
position(px, py, pz), normal(nx, ny, nz), uv(uvx, uvy, 0.0) {}
aiVector3D position, normal, uv;
};
// -------------------------------------------------------------------
// Parse <node> tag from XML file and extract child node
// @param node XML node
// @param guessedMeshesContained number of extra guessed meshes
IRRImporter::Node *ParseNode(pugi::xml_node &node, BatchLoader& batch);
// -------------------------------------------------------------------
// Parse <attributes> tags within <node> tags and apply to scene node
// @param attributeNode XML child node
// @param nd Attributed scene node
void ParseNodeAttributes(pugi::xml_node &attributeNode, IRRImporter::Node *nd, BatchLoader& batch);
// -------------------------------------------------------------------
// Parse an <animator> node and attach an animator to a node
// @param animatorNode XML animator node
// @param nd Animated scene node
void ParseAnimators(pugi::xml_node &animatorNode, IRRImporter::Node *nd);
// -------------------------------------------------------------------
/// Fill the scene-graph recursively
void GenerateGraph(Node* root,aiNode* rootOut ,aiScene* scene,
BatchLoader& batch,
std::vector<aiMesh*>& meshes,
std::vector<aiNodeAnim*>& anims,
std::vector<AttachmentInfo>& attach,
std::vector<aiMaterial*>& materials,
unsigned int& defaultMatIdx);
void GenerateGraph(Node *root, aiNode *rootOut, aiScene *scene,
BatchLoader &batch,
std::vector<aiMesh *> &meshes,
std::vector<aiNodeAnim *> &anims,
std::vector<AttachmentInfo> &attach,
std::vector<aiMaterial *> &materials,
unsigned int &defaultMatIdx);
// -------------------------------------------------------------------
/// Generate a mesh that consists of just a single quad
aiMesh* BuildSingleQuadMesh(const SkyboxVertex& v1,
const SkyboxVertex& v2,
const SkyboxVertex& v3,
const SkyboxVertex& v4);
aiMesh *BuildSingleQuadMesh(const SkyboxVertex &v1,
const SkyboxVertex &v2,
const SkyboxVertex &v3,
const SkyboxVertex &v4);
// -------------------------------------------------------------------
/// Build a sky-box
@ -245,8 +248,8 @@ private:
/// @param meshes Receives 6 output meshes
/// @param materials The last 6 materials are assigned to the newly
/// created meshes. The names of the materials are adjusted.
void BuildSkybox(std::vector<aiMesh*>& meshes,
std::vector<aiMaterial*> materials);
void BuildSkybox(std::vector<aiMesh *> &meshes,
std::vector<aiMaterial *> materials);
// -------------------------------------------------------------------
/** Copy a material for a mesh to the output material list
@ -256,10 +259,10 @@ private:
* @param defMatIdx Default material index - UINT_MAX if not present
* @param mesh Mesh to work on
*/
void CopyMaterial(std::vector<aiMaterial*>& materials,
std::vector< std::pair<aiMaterial*, unsigned int> >& inmaterials,
unsigned int& defMatIdx,
aiMesh* mesh);
void CopyMaterial(std::vector<aiMaterial *> &materials,
std::vector<std::pair<aiMaterial *, unsigned int>> &inmaterials,
unsigned int &defMatIdx,
aiMesh *mesh);
// -------------------------------------------------------------------
/** Compute animations for a specific node
@ -267,8 +270,8 @@ private:
* @param root Node to be processed
* @param anims The list of output animations
*/
void ComputeAnimations(Node* root, aiNode* real,
std::vector<aiNodeAnim*>& anims);
void ComputeAnimations(Node *root, aiNode *real,
std::vector<aiNodeAnim *> &anims);
private:
/// Configuration option: desired output FPS
@ -276,6 +279,12 @@ private:
/// Configuration option: speed flag was set?
bool configSpeedFlag;
std::vector<aiCamera*> cameras;
std::vector<aiLight*> lights;
unsigned int guessedMeshCnt;
unsigned int guessedMatCnt;
unsigned int guessedAnimCnt;
};
} // end of namespace Assimp

View File

@ -57,16 +57,16 @@ OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
using namespace Assimp;
static const aiImporterDesc desc = {
"Irrlicht Mesh Reader",
"",
"",
"http://irrlicht.sourceforge.net/",
aiImporterFlags_SupportTextFlavour,
0,
0,
0,
0,
"xml irrmesh"
"Irrlicht Mesh Reader",
"",
"",
"http://irrlicht.sourceforge.net/",
aiImporterFlags_SupportTextFlavour,
0,
0,
0,
0,
"xml irrmesh"
};
// ------------------------------------------------------------------------------------------------
@ -80,419 +80,443 @@ IRRMeshImporter::~IRRMeshImporter() = default;
// ------------------------------------------------------------------------------------------------
// Returns whether the class can handle the format of the given file.
bool IRRMeshImporter::CanRead(const std::string &pFile, IOSystem *pIOHandler, bool /*checkSig*/) const {
/* NOTE: A simple check for the file extension is not enough
* here. Irrmesh and irr are easy, but xml is too generic
* and could be collada, too. So we need to open the file and
* search for typical tokens.
*/
static const char *tokens[] = { "irrmesh" };
return SearchFileHeaderForToken(pIOHandler, pFile, tokens, AI_COUNT_OF(tokens));
/* NOTE: A simple check for the file extension is not enough
* here. Irrmesh and irr are easy, but xml is too generic
* and could be collada, too. So we need to open the file and
* search for typical tokens.
*/
static const char *tokens[] = { "irrmesh" };
return SearchFileHeaderForToken(pIOHandler, pFile, tokens, AI_COUNT_OF(tokens));
}
// ------------------------------------------------------------------------------------------------
// Get a list of all file extensions which are handled by this class
const aiImporterDesc *IRRMeshImporter::GetInfo() const {
return &desc;
return &desc;
}
static void releaseMaterial(aiMaterial **mat) {
if (*mat != nullptr) {
delete *mat;
*mat = nullptr;
}
if (*mat != nullptr) {
delete *mat;
*mat = nullptr;
}
}
static void releaseMesh(aiMesh **mesh) {
if (*mesh != nullptr) {
delete *mesh;
*mesh = nullptr;
}
if (*mesh != nullptr) {
delete *mesh;
*mesh = nullptr;
}
}
// ------------------------------------------------------------------------------------------------
// Imports the given file into the given scene structure.
void IRRMeshImporter::InternReadFile(const std::string &pFile,
aiScene *pScene, IOSystem *pIOHandler) {
std::unique_ptr<IOStream> file(pIOHandler->Open(pFile));
aiScene *pScene, IOSystem *pIOHandler) {
std::unique_ptr<IOStream> file(pIOHandler->Open(pFile));
// Check whether we can read from the file
if (file == nullptr)
throw DeadlyImportError("Failed to open IRRMESH file ", pFile);
// Check whether we can read from the file
if (file == nullptr)
throw DeadlyImportError("Failed to open IRRMESH file ", pFile);
// Construct the irrXML parser
XmlParser parser;
if (!parser.parse( file.get() )) {
throw DeadlyImportError("XML parse error while loading IRRMESH file ", pFile);
}
XmlNode root = parser.getRootNode();
// Construct the irrXML parser
XmlParser parser;
if (!parser.parse(file.get())) {
throw DeadlyImportError("XML parse error while loading IRRMESH file ", pFile);
}
XmlNode root = parser.getRootNode();
// final data
std::vector<aiMaterial *> materials;
std::vector<aiMesh *> meshes;
materials.reserve(5);
meshes.reserve(5);
// final data
std::vector<aiMaterial *> materials;
std::vector<aiMesh *> meshes;
materials.reserve(5);
meshes.reserve(5);
// temporary data - current mesh buffer
aiMaterial *curMat = nullptr;
aiMesh *curMesh = nullptr;
unsigned int curMatFlags = 0;
// temporary data - current mesh buffer
// TODO move all these to inside loop
aiMaterial *curMat = nullptr;
aiMesh *curMesh = nullptr;
unsigned int curMatFlags = 0;
std::vector<aiVector3D> curVertices, curNormals, curTangents, curBitangents;
std::vector<aiColor4D> curColors;
std::vector<aiVector3D> curUVs, curUV2s;
std::vector<aiVector3D> curVertices, curNormals, curTangents, curBitangents;
std::vector<aiColor4D> curColors;
std::vector<aiVector3D> curUVs, curUV2s;
// some temporary variables
int textMeaning = 0;
int vertexFormat = 0; // 0 = normal; 1 = 2 tcoords, 2 = tangents
bool useColors = false;
// some temporary variables
// textMeaning is a 15 year old variable, that could've been an enum
// int textMeaning = 0; // 0=none? 1=vertices 2=indices
// int vertexFormat = 0; // 0 = normal; 1 = 2 tcoords, 2 = tangents
bool useColors = false;
// Parse the XML file
for (pugi::xml_node child : root.children()) {
if (child.type() == pugi::node_element) {
if (!ASSIMP_stricmp(child.name(), "buffer") && (curMat || curMesh)) {
// end of previous buffer. A material and a mesh should be there
if (!curMat || !curMesh) {
ASSIMP_LOG_ERROR("IRRMESH: A buffer must contain a mesh and a material");
releaseMaterial(&curMat);
releaseMesh(&curMesh);
} else {
materials.push_back(curMat);
meshes.push_back(curMesh);
}
curMat = nullptr;
curMesh = nullptr;
/*
** irrmesh files have a top level <mesh> owning multiple <buffer> nodes.
** Each <buffer> contains <material>, <vertices>, and <indices>
** <material> tags here directly owns the material data specs
** <vertices> are a vertex per line, contains position, UV1 coords, maybe UV2, normal, tangent, bitangent
** <boundingbox> is ignored, I think assimp recalculates those?
*/
curVertices.clear();
curColors.clear();
curNormals.clear();
curUV2s.clear();
curUVs.clear();
curTangents.clear();
curBitangents.clear();
}
// Parse the XML file
pugi::xml_node const &meshNode = root.child("mesh");
for (pugi::xml_node bufferNode : meshNode.children()) {
if (ASSIMP_stricmp(bufferNode.name(), "buffer")) {
// Might be a useless warning
ASSIMP_LOG_WARN("IRRMESH: Ignoring non buffer node <", bufferNode.name(), "> in mesh declaration");
continue;
}
if (!ASSIMP_stricmp(child.name(), "material")) {
if (curMat) {
ASSIMP_LOG_WARN("IRRMESH: Only one material description per buffer, please");
releaseMaterial(&curMat);
}
curMat = ParseMaterial(curMatFlags);
}
/* no else here! */ if (!ASSIMP_stricmp(child.name(), "vertices")) {
pugi::xml_attribute attr = child.attribute("vertexCount");
int num = attr.as_int();
//int num = reader->getAttributeValueAsInt("vertexCount");
curMat = nullptr;
curMesh = nullptr;
if (!num) {
// This is possible ... remove the mesh from the list and skip further reading
ASSIMP_LOG_WARN("IRRMESH: Found mesh with zero vertices");
curVertices.clear();
curColors.clear();
curNormals.clear();
curUV2s.clear();
curUVs.clear();
curTangents.clear();
curBitangents.clear();
releaseMaterial(&curMat);
releaseMesh(&curMesh);
textMeaning = 0;
continue;
}
// TODO ensure all three nodes are present and populated
// before allocating everything
curVertices.reserve(num);
curNormals.reserve(num);
curColors.reserve(num);
curUVs.reserve(num);
// Get first material node
pugi::xml_node materialNode = bufferNode.child("material");
if (materialNode) {
curMat = ParseMaterial(materialNode, curMatFlags);
// Warn if there's more materials
if (materialNode.next_sibling("material")) {
ASSIMP_LOG_WARN("IRRMESH: Only one material description per buffer, please");
}
} else {
ASSIMP_LOG_ERROR("IRRMESH: Buffer must contain one material");
continue;
}
// Determine the file format
//const char *t = reader->getAttributeValueSafe("type");
pugi::xml_attribute t = child.attribute("type");
if (!ASSIMP_stricmp("2tcoords", t.name())) {
curUV2s.reserve(num);
vertexFormat = 1;
// Get first vertices node
pugi::xml_node verticesNode = bufferNode.child("vertices");
if (verticesNode) {
pugi::xml_attribute vertexCountAttrib = verticesNode.attribute("vertexCount");
int vertexCount = vertexCountAttrib.as_int();
if (vertexCount == 0) {
// This is possible ... remove the mesh from the list and skip further reading
ASSIMP_LOG_WARN("IRRMESH: Found mesh with zero vertices");
releaseMaterial(&curMat);
// releaseMesh(&curMesh);
continue; // Bail out early
};
if (curMatFlags & AI_IRRMESH_EXTRA_2ND_TEXTURE) {
// *********************************************************
// We have a second texture! So use this UV channel
// for it. The 2nd texture can be either a normal
// texture (solid_2layer or lightmap_xxx) or a normal
// map (normal_..., parallax_...)
// *********************************************************
int idx = 1;
aiMaterial *mat = (aiMaterial *)curMat;
curVertices.reserve(vertexCount);
curNormals.reserve(vertexCount);
curColors.reserve(vertexCount);
curUVs.reserve(vertexCount);
if (curMatFlags & AI_IRRMESH_MAT_lightmap) {
mat->AddProperty(&idx, 1, AI_MATKEY_UVWSRC_LIGHTMAP(0));
} else if (curMatFlags & AI_IRRMESH_MAT_normalmap_solid) {
mat->AddProperty(&idx, 1, AI_MATKEY_UVWSRC_NORMALS(0));
} else if (curMatFlags & AI_IRRMESH_MAT_solid_2layer) {
mat->AddProperty(&idx, 1, AI_MATKEY_UVWSRC_DIFFUSE(1));
}
}
} else if (!ASSIMP_stricmp("tangents", t.name())) {
curTangents.reserve(num);
curBitangents.reserve(num);
vertexFormat = 2;
} else if (ASSIMP_stricmp("standard", t.name())) {
releaseMaterial(&curMat);
ASSIMP_LOG_WARN("IRRMESH: Unknown vertex format");
} else
vertexFormat = 0;
textMeaning = 1;
} else if (!ASSIMP_stricmp(child.name(), "indices")) {
if (curVertices.empty() && curMat) {
releaseMaterial(&curMat);
throw DeadlyImportError("IRRMESH: indices must come after vertices");
}
VertexFormat vertexFormat;
// Determine the file format
pugi::xml_attribute typeAttrib = verticesNode.attribute("type");
if (!ASSIMP_stricmp("2tcoords", typeAttrib.value())) {
curUV2s.reserve(vertexCount);
vertexFormat = VertexFormat::t2coord;
if (curMatFlags & AI_IRRMESH_EXTRA_2ND_TEXTURE) {
// *********************************************************
// We have a second texture! So use this UV channel
// for it. The 2nd texture can be either a normal
// texture (solid_2layer or lightmap_xxx) or a normal
// map (normal_..., parallax_...)
// *********************************************************
int idx = 1;
aiMaterial *mat = (aiMaterial *)curMat;
textMeaning = 2;
if (curMatFlags & AI_IRRMESH_MAT_lightmap) {
mat->AddProperty(&idx, 1, AI_MATKEY_UVWSRC_LIGHTMAP(0));
} else if (curMatFlags & AI_IRRMESH_MAT_normalmap_solid) {
mat->AddProperty(&idx, 1, AI_MATKEY_UVWSRC_NORMALS(0));
} else if (curMatFlags & AI_IRRMESH_MAT_solid_2layer) {
mat->AddProperty(&idx, 1, AI_MATKEY_UVWSRC_DIFFUSE(1));
}
}
} else if (!ASSIMP_stricmp("tangents", typeAttrib.value())) {
curTangents.reserve(vertexCount);
curBitangents.reserve(vertexCount);
vertexFormat = VertexFormat::tangent;
} else if (!ASSIMP_stricmp("standard", typeAttrib.value())) {
vertexFormat = VertexFormat::standard;
} else {
// Unsupported format, discard whole buffer/mesh
// Assuming we have a correct material, then release it
// We don't have a correct mesh for sure here
releaseMaterial(&curMat);
ASSIMP_LOG_ERROR("IRRMESH: Unknown vertex format");
continue; // Skip rest of buffer
};
// start a new mesh
curMesh = new aiMesh();
// We know what format buffer is, collect numbers
ParseBufferVertices(verticesNode.text().get(), vertexFormat,
curVertices, curNormals,
curTangents, curBitangents,
curUVs, curUV2s, curColors, useColors);
}
// allocate storage for all faces
pugi::xml_attribute attr = child.attribute("indexCount");
curMesh->mNumVertices = attr.as_int();
if (!curMesh->mNumVertices) {
// This is possible ... remove the mesh from the list and skip further reading
ASSIMP_LOG_WARN("IRRMESH: Found mesh with zero indices");
// Get indices
// At this point we have some vertices and a valid material
// Collect indices and create aiMesh at the same time
pugi::xml_node indicesNode = bufferNode.child("indices");
if (indicesNode) {
// start a new mesh
curMesh = new aiMesh();
// mesh - away
releaseMesh(&curMesh);
// allocate storage for all faces
pugi::xml_attribute attr = indicesNode.attribute("indexCount");
curMesh->mNumVertices = attr.as_int();
if (!curMesh->mNumVertices) {
// This is possible ... remove the mesh from the list and skip further reading
ASSIMP_LOG_WARN("IRRMESH: Found mesh with zero indices");
// material - away
releaseMaterial(&curMat);
// mesh - away
releaseMesh(&curMesh);
textMeaning = 0;
continue;
}
// material - away
releaseMaterial(&curMat);
continue; // Go to next buffer
}
if (curMesh->mNumVertices % 3) {
ASSIMP_LOG_WARN("IRRMESH: Number if indices isn't divisible by 3");
}
if (curMesh->mNumVertices % 3) {
ASSIMP_LOG_WARN("IRRMESH: Number if indices isn't divisible by 3");
}
curMesh->mNumFaces = curMesh->mNumVertices / 3;
curMesh->mFaces = new aiFace[curMesh->mNumFaces];
curMesh->mNumFaces = curMesh->mNumVertices / 3;
curMesh->mFaces = new aiFace[curMesh->mNumFaces];
// setup some members
curMesh->mMaterialIndex = (unsigned int)materials.size();
curMesh->mPrimitiveTypes = aiPrimitiveType_TRIANGLE;
// setup some members
curMesh->mMaterialIndex = (unsigned int)materials.size();
curMesh->mPrimitiveTypes = aiPrimitiveType_TRIANGLE;
// allocate storage for all vertices
curMesh->mVertices = new aiVector3D[curMesh->mNumVertices];
// allocate storage for all vertices
curMesh->mVertices = new aiVector3D[curMesh->mNumVertices];
if (curNormals.size() == curVertices.size()) {
curMesh->mNormals = new aiVector3D[curMesh->mNumVertices];
}
if (curTangents.size() == curVertices.size()) {
curMesh->mTangents = new aiVector3D[curMesh->mNumVertices];
}
if (curBitangents.size() == curVertices.size()) {
curMesh->mBitangents = new aiVector3D[curMesh->mNumVertices];
}
if (curColors.size() == curVertices.size() && useColors) {
curMesh->mColors[0] = new aiColor4D[curMesh->mNumVertices];
}
if (curUVs.size() == curVertices.size()) {
curMesh->mTextureCoords[0] = new aiVector3D[curMesh->mNumVertices];
}
if (curUV2s.size() == curVertices.size()) {
curMesh->mTextureCoords[1] = new aiVector3D[curMesh->mNumVertices];
}
}
//break;
if (curNormals.size() == curVertices.size()) {
curMesh->mNormals = new aiVector3D[curMesh->mNumVertices];
}
if (curTangents.size() == curVertices.size()) {
curMesh->mTangents = new aiVector3D[curMesh->mNumVertices];
}
if (curBitangents.size() == curVertices.size()) {
curMesh->mBitangents = new aiVector3D[curMesh->mNumVertices];
}
if (curColors.size() == curVertices.size() && useColors) {
curMesh->mColors[0] = new aiColor4D[curMesh->mNumVertices];
}
if (curUVs.size() == curVertices.size()) {
curMesh->mTextureCoords[0] = new aiVector3D[curMesh->mNumVertices];
}
if (curUV2s.size() == curVertices.size()) {
curMesh->mTextureCoords[1] = new aiVector3D[curMesh->mNumVertices];
}
//case EXN_TEXT: {
const char *sz = child.child_value();
if (textMeaning == 1) {
textMeaning = 0;
// read indices
aiFace *curFace = curMesh->mFaces;
aiFace *const faceEnd = curMesh->mFaces + curMesh->mNumFaces;
// read vertices
do {
SkipSpacesAndLineEnd(&sz);
aiVector3D temp;
aiColor4D c;
aiVector3D *pcV = curMesh->mVertices;
aiVector3D *pcN = curMesh->mNormals;
aiVector3D *pcT = curMesh->mTangents;
aiVector3D *pcB = curMesh->mBitangents;
aiColor4D *pcC0 = curMesh->mColors[0];
aiVector3D *pcT0 = curMesh->mTextureCoords[0];
aiVector3D *pcT1 = curMesh->mTextureCoords[1];
// Read the vertex position
sz = fast_atoreal_move<float>(sz, (float &)temp.x);
SkipSpaces(&sz);
unsigned int curIdx = 0;
unsigned int total = 0;
sz = fast_atoreal_move<float>(sz, (float &)temp.y);
SkipSpaces(&sz);
// NOTE this might explode for UTF-16 and wchars
const char *sz = indicesNode.text().get();
// For each index loop over aiMesh faces
while (SkipSpacesAndLineEnd(&sz)) {
if (curFace >= faceEnd) {
ASSIMP_LOG_ERROR("IRRMESH: Too many indices");
break;
}
// if new face
if (!curIdx) {
curFace->mNumIndices = 3;
curFace->mIndices = new unsigned int[3];
}
sz = fast_atoreal_move<float>(sz, (float &)temp.z);
SkipSpaces(&sz);
curVertices.push_back(temp);
// Read index base 10
// function advances the pointer
unsigned int idx = strtoul10(sz, &sz);
if (idx >= curVertices.size()) {
ASSIMP_LOG_ERROR("IRRMESH: Index out of range");
idx = 0;
}
// Read the vertex normals
sz = fast_atoreal_move<float>(sz, (float &)temp.x);
SkipSpaces(&sz);
// make up our own indices?
curFace->mIndices[curIdx] = total++;
sz = fast_atoreal_move<float>(sz, (float &)temp.y);
SkipSpaces(&sz);
// Copy over data to aiMesh
*pcV++ = curVertices[idx];
if (pcN) *pcN++ = curNormals[idx];
if (pcT) *pcT++ = curTangents[idx];
if (pcB) *pcB++ = curBitangents[idx];
if (pcC0) *pcC0++ = curColors[idx];
if (pcT0) *pcT0++ = curUVs[idx];
if (pcT1) *pcT1++ = curUV2s[idx];
sz = fast_atoreal_move<float>(sz, (float &)temp.z);
SkipSpaces(&sz);
curNormals.push_back(temp);
// start new face
if (++curIdx == 3) {
++curFace;
curIdx = 0;
}
}
// We should be at the end of mFaces
if (curFace != faceEnd)
ASSIMP_LOG_ERROR("IRRMESH: Not enough indices");
}
// read the vertex colors
uint32_t clr = strtoul16(sz, &sz);
ColorFromARGBPacked(clr, c);
// Finish processing the mesh - do some small material workarounds
if (curMatFlags & AI_IRRMESH_MAT_trans_vertex_alpha && !useColors) {
// Take the opacity value of the current material
// from the common vertex color alpha
aiMaterial *mat = (aiMaterial *)curMat;
mat->AddProperty(&curColors[0].a, 1, AI_MATKEY_OPACITY);
}
// textMeaning = 2;
if (!curColors.empty() && c != *(curColors.end() - 1))
useColors = true;
// end of previous buffer. A material and a mesh should be there
if (!curMat || !curMesh) {
ASSIMP_LOG_ERROR("IRRMESH: A buffer must contain a mesh and a material");
releaseMaterial(&curMat);
releaseMesh(&curMesh);
} else {
materials.push_back(curMat);
meshes.push_back(curMesh);
}
}
curColors.push_back(c);
SkipSpaces(&sz);
// If one is empty then so is the other
if (materials.empty() || meshes.empty()) {
throw DeadlyImportError("IRRMESH: Unable to read a mesh from this file");
}
// read the first UV coordinate set
sz = fast_atoreal_move<float>(sz, (float &)temp.x);
SkipSpaces(&sz);
// now generate the output scene
pScene->mNumMeshes = (unsigned int)meshes.size();
pScene->mMeshes = new aiMesh *[pScene->mNumMeshes];
for (unsigned int i = 0; i < pScene->mNumMeshes; ++i) {
pScene->mMeshes[i] = meshes[i];
sz = fast_atoreal_move<float>(sz, (float &)temp.y);
SkipSpaces(&sz);
temp.z = 0.f;
temp.y = 1.f - temp.y; // DX to OGL
curUVs.push_back(temp);
// clean this value ...
pScene->mMeshes[i]->mNumUVComponents[3] = 0;
}
// read the (optional) second UV coordinate set
if (vertexFormat == 1) {
sz = fast_atoreal_move<float>(sz, (float &)temp.x);
SkipSpaces(&sz);
pScene->mNumMaterials = (unsigned int)materials.size();
pScene->mMaterials = new aiMaterial *[pScene->mNumMaterials];
::memcpy(pScene->mMaterials, &materials[0], sizeof(void *) * pScene->mNumMaterials);
sz = fast_atoreal_move<float>(sz, (float &)temp.y);
temp.y = 1.f - temp.y; // DX to OGL
curUV2s.push_back(temp);
}
// read optional tangent and bitangent vectors
else if (vertexFormat == 2) {
// tangents
sz = fast_atoreal_move<float>(sz, (float &)temp.x);
SkipSpaces(&sz);
pScene->mRootNode = new aiNode();
pScene->mRootNode->mName.Set("<IRRMesh>");
pScene->mRootNode->mNumMeshes = pScene->mNumMeshes;
pScene->mRootNode->mMeshes = new unsigned int[pScene->mNumMeshes];
sz = fast_atoreal_move<float>(sz, (float &)temp.z);
SkipSpaces(&sz);
for (unsigned int i = 0; i < pScene->mNumMeshes; ++i) {
pScene->mRootNode->mMeshes[i] = i;
};
}
sz = fast_atoreal_move<float>(sz, (float &)temp.y);
SkipSpaces(&sz);
temp.y *= -1.0f;
curTangents.push_back(temp);
void IRRMeshImporter::ParseBufferVertices(const char *sz, VertexFormat vertexFormat,
std::vector<aiVector3D> &vertices, std::vector<aiVector3D> &normals,
std::vector<aiVector3D> &tangents, std::vector<aiVector3D> &bitangents,
std::vector<aiVector3D> &UVs, std::vector<aiVector3D> &UV2s,
std::vector<aiColor4D> &colors, bool &useColors) {
// read vertices
do {
SkipSpacesAndLineEnd(&sz);
aiVector3D temp;
aiColor4D c;
// bitangents
sz = fast_atoreal_move<float>(sz, (float &)temp.x);
SkipSpaces(&sz);
// Read the vertex position
sz = fast_atoreal_move<float>(sz, (float &)temp.x);
SkipSpaces(&sz);
sz = fast_atoreal_move<float>(sz, (float &)temp.z);
SkipSpaces(&sz);
sz = fast_atoreal_move<float>(sz, (float &)temp.y);
SkipSpaces(&sz);
sz = fast_atoreal_move<float>(sz, (float &)temp.y);
SkipSpaces(&sz);
temp.y *= -1.0f;
curBitangents.push_back(temp);
}
}
sz = fast_atoreal_move<float>(sz, (float &)temp.z);
SkipSpaces(&sz);
vertices.push_back(temp);
/* IMPORTANT: We assume that each vertex is specified in one
line. So we can skip the rest of the line - unknown vertex
elements are ignored.
*/
// Read the vertex normals
sz = fast_atoreal_move<float>(sz, (float &)temp.x);
SkipSpaces(&sz);
while (SkipLine(&sz));
} else if (textMeaning == 2) {
textMeaning = 0;
sz = fast_atoreal_move<float>(sz, (float &)temp.y);
SkipSpaces(&sz);
// read indices
aiFace *curFace = curMesh->mFaces;
aiFace *const faceEnd = curMesh->mFaces + curMesh->mNumFaces;
sz = fast_atoreal_move<float>(sz, (float &)temp.z);
SkipSpaces(&sz);
normals.push_back(temp);
aiVector3D *pcV = curMesh->mVertices;
aiVector3D *pcN = curMesh->mNormals;
aiVector3D *pcT = curMesh->mTangents;
aiVector3D *pcB = curMesh->mBitangents;
aiColor4D *pcC0 = curMesh->mColors[0];
aiVector3D *pcT0 = curMesh->mTextureCoords[0];
aiVector3D *pcT1 = curMesh->mTextureCoords[1];
// read the vertex colors
uint32_t clr = strtoul16(sz, &sz);
ColorFromARGBPacked(clr, c);
unsigned int curIdx = 0;
unsigned int total = 0;
while (SkipSpacesAndLineEnd(&sz)) {
if (curFace >= faceEnd) {
ASSIMP_LOG_ERROR("IRRMESH: Too many indices");
break;
}
if (!curIdx) {
curFace->mNumIndices = 3;
curFace->mIndices = new unsigned int[3];
}
// If we're pushing more than one distinct color
if (!colors.empty() && c != *(colors.end() - 1))
useColors = true;
unsigned int idx = strtoul10(sz, &sz);
if (idx >= curVertices.size()) {
ASSIMP_LOG_ERROR("IRRMESH: Index out of range");
idx = 0;
}
colors.push_back(c);
SkipSpaces(&sz);
curFace->mIndices[curIdx] = total++;
// read the first UV coordinate set
sz = fast_atoreal_move<float>(sz, (float &)temp.x);
SkipSpaces(&sz);
*pcV++ = curVertices[idx];
if (pcN) *pcN++ = curNormals[idx];
if (pcT) *pcT++ = curTangents[idx];
if (pcB) *pcB++ = curBitangents[idx];
if (pcC0) *pcC0++ = curColors[idx];
if (pcT0) *pcT0++ = curUVs[idx];
if (pcT1) *pcT1++ = curUV2s[idx];
sz = fast_atoreal_move<float>(sz, (float &)temp.y);
SkipSpaces(&sz);
temp.z = 0.f;
temp.y = 1.f - temp.y; // DX to OGL
UVs.push_back(temp);
if (++curIdx == 3) {
++curFace;
curIdx = 0;
}
}
// NOTE these correspond to specific S3DVertex* structs in irr sourcecode
// So by definition, all buffers have either UV2 or tangents or neither
// read the (optional) second UV coordinate set
if (vertexFormat == VertexFormat::t2coord) {
sz = fast_atoreal_move<float>(sz, (float &)temp.x);
SkipSpaces(&sz);
if (curFace != faceEnd)
ASSIMP_LOG_ERROR("IRRMESH: Not enough indices");
sz = fast_atoreal_move<float>(sz, (float &)temp.y);
temp.y = 1.f - temp.y; // DX to OGL
UV2s.push_back(temp);
}
// read optional tangent and bitangent vectors
else if (vertexFormat == VertexFormat::tangent) {
// tangents
sz = fast_atoreal_move<float>(sz, (float &)temp.x);
SkipSpaces(&sz);
// Finish processing the mesh - do some small material workarounds
if (curMatFlags & AI_IRRMESH_MAT_trans_vertex_alpha && !useColors) {
// Take the opacity value of the current material
// from the common vertex color alpha
aiMaterial *mat = (aiMaterial *)curMat;
mat->AddProperty(&curColors[0].a, 1, AI_MATKEY_OPACITY);
}
}
}
}
sz = fast_atoreal_move<float>(sz, (float &)temp.z);
SkipSpaces(&sz);
// End of the last buffer. A material and a mesh should be there
if (curMat || curMesh) {
if (!curMat || !curMesh) {
ASSIMP_LOG_ERROR("IRRMESH: A buffer must contain a mesh and a material");
releaseMaterial(&curMat);
releaseMesh(&curMesh);
} else {
materials.push_back(curMat);
meshes.push_back(curMesh);
}
}
sz = fast_atoreal_move<float>(sz, (float &)temp.y);
SkipSpaces(&sz);
temp.y *= -1.0f;
tangents.push_back(temp);
if (materials.empty()) {
throw DeadlyImportError("IRRMESH: Unable to read a mesh from this file");
}
// bitangents
sz = fast_atoreal_move<float>(sz, (float &)temp.x);
SkipSpaces(&sz);
// now generate the output scene
pScene->mNumMeshes = (unsigned int)meshes.size();
pScene->mMeshes = new aiMesh *[pScene->mNumMeshes];
for (unsigned int i = 0; i < pScene->mNumMeshes; ++i) {
pScene->mMeshes[i] = meshes[i];
sz = fast_atoreal_move<float>(sz, (float &)temp.z);
SkipSpaces(&sz);
// clean this value ...
pScene->mMeshes[i]->mNumUVComponents[3] = 0;
}
pScene->mNumMaterials = (unsigned int)materials.size();
pScene->mMaterials = new aiMaterial *[pScene->mNumMaterials];
::memcpy(pScene->mMaterials, &materials[0], sizeof(void *) * pScene->mNumMaterials);
pScene->mRootNode = new aiNode();
pScene->mRootNode->mName.Set("<IRRMesh>");
pScene->mRootNode->mNumMeshes = pScene->mNumMeshes;
pScene->mRootNode->mMeshes = new unsigned int[pScene->mNumMeshes];
for (unsigned int i = 0; i < pScene->mNumMeshes; ++i) {
pScene->mRootNode->mMeshes[i] = i;
}
sz = fast_atoreal_move<float>(sz, (float &)temp.y);
SkipSpaces(&sz);
temp.y *= -1.0f;
bitangents.push_back(temp);
}
} while (SkipLine(&sz));
/* IMPORTANT: We assume that each vertex is specified in one
line. So we can skip the rest of the line - unknown vertex
elements are ignored.
*/
}
#endif // !! ASSIMP_BUILD_NO_IRRMESH_IMPORTER

View File

@ -85,6 +85,19 @@ protected:
*/
void InternReadFile(const std::string &pFile, aiScene *pScene,
IOSystem *pIOHandler) override;
private:
enum class VertexFormat {
standard = 0, // "standard" - also noted as 'normal' format elsewhere
t2coord = 1, // "2tcoord" - standard + 2 UV maps
tangent = 2, // "tangents" - standard + tangents and bitangents
};
void ParseBufferVertices(const char *sz, VertexFormat vertexFormat,
std::vector<aiVector3D> &vertices, std::vector<aiVector3D> &normals,
std::vector<aiVector3D> &tangents, std::vector<aiVector3D> &bitangents,
std::vector<aiVector3D> &UVs, std::vector<aiVector3D> &UV2s,
std::vector<aiColor4D> &colors, bool &useColors);
};
} // end of namespace Assimp

View File

@ -43,302 +43,302 @@ OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
* @brief Shared utilities for the IRR and IRRMESH loaders
*/
//This section should be excluded only if both the Irrlicht AND the Irrlicht Mesh importers were omitted.
// This section should be excluded only if both the Irrlicht AND the Irrlicht Mesh importers were omitted.
#if !(defined(ASSIMP_BUILD_NO_IRR_IMPORTER) && defined(ASSIMP_BUILD_NO_IRRMESH_IMPORTER))
#include "IRRShared.h"
#include <assimp/ParsingUtils.h>
#include <assimp/fast_atof.h>
#include <assimp/DefaultLogger.hpp>
#include <assimp/material.h>
#include <assimp/DefaultLogger.hpp>
using namespace Assimp;
// Transformation matrix to convert from Assimp to IRR space
const aiMatrix4x4 Assimp::AI_TO_IRR_MATRIX = aiMatrix4x4 (
1.0f, 0.0f, 0.0f, 0.0f,
0.0f, 0.0f, 1.0f, 0.0f,
0.0f, 1.0f, 0.0f, 0.0f,
0.0f, 0.0f, 0.0f, 1.0f);
const aiMatrix4x4 Assimp::AI_TO_IRR_MATRIX = aiMatrix4x4(
1.0f, 0.0f, 0.0f, 0.0f,
0.0f, 0.0f, 1.0f, 0.0f,
0.0f, 1.0f, 0.0f, 0.0f,
0.0f, 0.0f, 0.0f, 1.0f);
// ------------------------------------------------------------------------------------------------
// read a property in hexadecimal format (i.e. ffffffff)
void IrrlichtBase::ReadHexProperty(HexProperty &out ) {
for (pugi::xml_attribute attrib : mNode->attributes()) {
void IrrlichtBase::ReadHexProperty(HexProperty &out, pugi::xml_node& hexnode) {
for (pugi::xml_attribute attrib : hexnode.attributes()) {
if (!ASSIMP_stricmp(attrib.name(), "name")) {
out.name = std::string( attrib.value() );
} else if (!ASSIMP_stricmp(attrib.name(),"value")) {
out.name = std::string(attrib.value());
} else if (!ASSIMP_stricmp(attrib.name(), "value")) {
// parse the hexadecimal value
out.value = strtoul16(attrib.name());
out.value = strtoul16(attrib.value());
}
}
}
// ------------------------------------------------------------------------------------------------
// read a decimal property
void IrrlichtBase::ReadIntProperty(IntProperty & out) {
for (pugi::xml_attribute attrib : mNode->attributes()) {
if (!ASSIMP_stricmp(attrib.name(), "name")) {
out.name = std::string(attrib.value());
} else if (!ASSIMP_stricmp(attrib.value(),"value")) {
void IrrlichtBase::ReadIntProperty(IntProperty &out, pugi::xml_node& intnode) {
for (pugi::xml_attribute attrib : intnode.attributes()) {
if (!ASSIMP_stricmp(attrib.name(), "name")) {
out.name = std::string(attrib.value());
} else if (!ASSIMP_stricmp(attrib.name(), "value")) {
// parse the int value
out.value = strtol10(attrib.name());
out.value = strtol10(attrib.value());
}
}
}
// ------------------------------------------------------------------------------------------------
// read a string property
void IrrlichtBase::ReadStringProperty( StringProperty& out) {
for (pugi::xml_attribute attrib : mNode->attributes()) {
if (!ASSIMP_stricmp(attrib.name(), "name")) {
out.name = std::string(attrib.value());
} else if (!ASSIMP_stricmp(attrib.name(), "value")) {
void IrrlichtBase::ReadStringProperty(StringProperty &out, pugi::xml_node& stringnode) {
for (pugi::xml_attribute attrib : stringnode.attributes()) {
if (!ASSIMP_stricmp(attrib.name(), "name")) {
out.name = std::string(attrib.value());
} else if (!ASSIMP_stricmp(attrib.name(), "value")) {
// simple copy the string
out.value = std::string(attrib.value());
out.value = std::string(attrib.value());
}
}
}
// ------------------------------------------------------------------------------------------------
// read a boolean property
void IrrlichtBase::ReadBoolProperty(BoolProperty &out) {
for (pugi::xml_attribute attrib : mNode->attributes()) {
if (!ASSIMP_stricmp(attrib.name(), "name")){
out.name = std::string(attrib.value());
} else if (!ASSIMP_stricmp(attrib.name(), "value")) {
void IrrlichtBase::ReadBoolProperty(BoolProperty &out, pugi::xml_node& boolnode) {
for (pugi::xml_attribute attrib : boolnode.attributes()) {
if (!ASSIMP_stricmp(attrib.name(), "name")) {
out.name = std::string(attrib.value());
} else if (!ASSIMP_stricmp(attrib.name(), "value")) {
// true or false, case insensitive
out.value = (ASSIMP_stricmp(attrib.value(), "true") ? false : true);
out.value = (ASSIMP_stricmp(attrib.value(), "true") ? false : true);
}
}
}
// ------------------------------------------------------------------------------------------------
// read a float property
void IrrlichtBase::ReadFloatProperty(FloatProperty &out) {
for (pugi::xml_attribute attrib : mNode->attributes()) {
if (!ASSIMP_stricmp(attrib.name(), "name")) {
out.name = std::string(attrib.value());
} else if (!ASSIMP_stricmp(attrib.name(), "value")) {
void IrrlichtBase::ReadFloatProperty(FloatProperty &out, pugi::xml_node &floatnode) {
for (pugi::xml_attribute attrib : floatnode.attributes()) {
if (!ASSIMP_stricmp(attrib.name(), "name")) {
out.name = std::string(attrib.value());
} else if (!ASSIMP_stricmp(attrib.name(), "value")) {
// just parse the float
out.value = fast_atof(attrib.value());
out.value = fast_atof(attrib.value());
}
}
}
// ------------------------------------------------------------------------------------------------
// read a vector property
void IrrlichtBase::ReadVectorProperty( VectorProperty &out ) {
for (pugi::xml_attribute attrib : mNode->attributes()) {
if (!ASSIMP_stricmp(attrib.name(), "name")) {
out.name = std::string(attrib.value());
} else if (!ASSIMP_stricmp(attrib.name(), "value")) {
void IrrlichtBase::ReadVectorProperty(VectorProperty &out, pugi::xml_node& vectornode) {
for (pugi::xml_attribute attrib : vectornode.attributes()) {
if (!ASSIMP_stricmp(attrib.name(), "name")) {
out.name = std::string(attrib.value());
} else if (!ASSIMP_stricmp(attrib.name(), "value")) {
// three floats, separated with commas
const char *ptr = attrib.value();
SkipSpaces(&ptr);
ptr = fast_atoreal_move<float>( ptr,(float&)out.value.x );
ptr = fast_atoreal_move<float>(ptr, (float &)out.value.x);
SkipSpaces(&ptr);
if (',' != *ptr) {
ASSIMP_LOG_ERROR("IRR(MESH): Expected comma in vector definition");
} else {
SkipSpaces(ptr + 1, &ptr);
}
ptr = fast_atoreal_move<float>( ptr,(float&)out.value.y );
} else {
SkipSpaces(ptr + 1, &ptr);
}
ptr = fast_atoreal_move<float>(ptr, (float &)out.value.y);
SkipSpaces(&ptr);
if (',' != *ptr) {
ASSIMP_LOG_ERROR("IRR(MESH): Expected comma in vector definition");
} else {
SkipSpaces(ptr + 1, &ptr);
}
ptr = fast_atoreal_move<float>( ptr,(float&)out.value.z );
} else {
SkipSpaces(ptr + 1, &ptr);
}
ptr = fast_atoreal_move<float>(ptr, (float &)out.value.z);
}
}
}
// ------------------------------------------------------------------------------------------------
// Convert a string to a proper aiMappingMode
int ConvertMappingMode(const std::string& mode) {
int ConvertMappingMode(const std::string &mode) {
if (mode == "texture_clamp_repeat") {
return aiTextureMapMode_Wrap;
} else if (mode == "texture_clamp_mirror") {
return aiTextureMapMode_Mirror;
}
} else if (mode == "texture_clamp_mirror") {
return aiTextureMapMode_Mirror;
}
return aiTextureMapMode_Clamp;
}
// ------------------------------------------------------------------------------------------------
// Parse a material from the XML file
aiMaterial* IrrlichtBase::ParseMaterial(unsigned int& matFlags) {
aiMaterial* mat = new aiMaterial();
aiMaterial *IrrlichtBase::ParseMaterial(pugi::xml_node& materialNode, unsigned int &matFlags) {
aiMaterial *mat = new aiMaterial();
aiColor4D clr;
aiString s;
matFlags = 0; // zero output flags
int cnt = 0; // number of used texture channels
int cnt = 0; // number of used texture channels
unsigned int nd = 0;
for (pugi::xml_node child : mNode->children()) {
if (!ASSIMP_stricmp(child.name(), "color")) { // Hex properties
HexProperty prop;
ReadHexProperty(prop);
if (prop.name == "Diffuse") {
ColorFromARGBPacked(prop.value, clr);
mat->AddProperty(&clr, 1, AI_MATKEY_COLOR_DIFFUSE);
} else if (prop.name == "Ambient") {
ColorFromARGBPacked(prop.value, clr);
mat->AddProperty(&clr, 1, AI_MATKEY_COLOR_AMBIENT);
} else if (prop.name == "Specular") {
ColorFromARGBPacked(prop.value, clr);
mat->AddProperty(&clr, 1, AI_MATKEY_COLOR_SPECULAR);
}
for (pugi::xml_node child : materialNode.children()) {
if (!ASSIMP_stricmp(child.name(), "color")) { // Hex properties
HexProperty prop;
ReadHexProperty(prop, child);
if (prop.name == "Diffuse") {
ColorFromARGBPacked(prop.value, clr);
mat->AddProperty(&clr, 1, AI_MATKEY_COLOR_DIFFUSE);
} else if (prop.name == "Ambient") {
ColorFromARGBPacked(prop.value, clr);
mat->AddProperty(&clr, 1, AI_MATKEY_COLOR_AMBIENT);
} else if (prop.name == "Specular") {
ColorFromARGBPacked(prop.value, clr);
mat->AddProperty(&clr, 1, AI_MATKEY_COLOR_SPECULAR);
}
// NOTE: The 'emissive' property causes problems. It is
// often != 0, even if there is obviously no light
// emitted by the described surface. In fact I think
// IRRLICHT ignores this property, too.
// NOTE: The 'emissive' property causes problems. It is
// often != 0, even if there is obviously no light
// emitted by the described surface. In fact I think
// IRRLICHT ignores this property, too.
#if 0
else if (prop.name == "Emissive") {
ColorFromARGBPacked(prop.value,clr);
mat->AddProperty(&clr,1,AI_MATKEY_COLOR_EMISSIVE);
}
#endif
} else if (!ASSIMP_stricmp(child.name(), "float")) { // Float properties
FloatProperty prop;
ReadFloatProperty(prop);
if (prop.name == "Shininess") {
mat->AddProperty(&prop.value, 1, AI_MATKEY_SHININESS);
}
} else if (!ASSIMP_stricmp(child.name(), "bool")) { // Bool properties
BoolProperty prop;
ReadBoolProperty(prop);
if (prop.name == "Wireframe") {
int val = (prop.value ? true : false);
mat->AddProperty(&val, 1, AI_MATKEY_ENABLE_WIREFRAME);
} else if (prop.name == "GouraudShading") {
int val = (prop.value ? aiShadingMode_Gouraud : aiShadingMode_NoShading);
mat->AddProperty(&val, 1, AI_MATKEY_SHADING_MODEL);
} else if (prop.name == "BackfaceCulling") {
int val = (!prop.value);
mat->AddProperty(&val, 1, AI_MATKEY_TWOSIDED);
}
} else if (!ASSIMP_stricmp(child.name(), "texture") ||
!ASSIMP_stricmp(child.name(), "enum")) { // String properties - textures and texture related properties
StringProperty prop;
ReadStringProperty(prop);
if (prop.value.length()) {
// material type (shader)
if (prop.name == "Type") {
if (prop.value == "solid") {
// default material ...
} else if (prop.value == "trans_vertex_alpha") {
matFlags = AI_IRRMESH_MAT_trans_vertex_alpha;
} else if (prop.value == "lightmap") {
matFlags = AI_IRRMESH_MAT_lightmap;
} else if (prop.value == "solid_2layer") {
matFlags = AI_IRRMESH_MAT_solid_2layer;
} else if (prop.value == "lightmap_m2") {
matFlags = AI_IRRMESH_MAT_lightmap_m2;
} else if (prop.value == "lightmap_m4") {
matFlags = AI_IRRMESH_MAT_lightmap_m4;
} else if (prop.value == "lightmap_light") {
matFlags = AI_IRRMESH_MAT_lightmap_light;
} else if (prop.value == "lightmap_light_m2") {
matFlags = AI_IRRMESH_MAT_lightmap_light_m2;
} else if (prop.value == "lightmap_light_m4") {
matFlags = AI_IRRMESH_MAT_lightmap_light_m4;
} else if (prop.value == "lightmap_add") {
matFlags = AI_IRRMESH_MAT_lightmap_add;
} else if (prop.value == "normalmap_solid" ||
prop.value == "parallaxmap_solid") { // Normal and parallax maps are treated equally
matFlags = AI_IRRMESH_MAT_normalmap_solid;
} else if (prop.value == "normalmap_trans_vertex_alpha" ||
prop.value == "parallaxmap_trans_vertex_alpha") {
matFlags = AI_IRRMESH_MAT_normalmap_tva;
} else if (prop.value == "normalmap_trans_add" ||
prop.value == "parallaxmap_trans_add") {
matFlags = AI_IRRMESH_MAT_normalmap_ta;
} else {
ASSIMP_LOG_WARN("IRRMat: Unrecognized material type: ", prop.value);
}
}
} else if (!ASSIMP_stricmp(child.name(), "float")) { // Float properties
FloatProperty prop;
ReadFloatProperty(prop, child);
if (prop.name == "Shininess") {
mat->AddProperty(&prop.value, 1, AI_MATKEY_SHININESS);
}
} else if (!ASSIMP_stricmp(child.name(), "bool")) { // Bool properties
BoolProperty prop;
ReadBoolProperty(prop, child);
if (prop.name == "Wireframe") {
int val = (prop.value ? true : false);
mat->AddProperty(&val, 1, AI_MATKEY_ENABLE_WIREFRAME);
} else if (prop.name == "GouraudShading") {
int val = (prop.value ? aiShadingMode_Gouraud : aiShadingMode_NoShading);
mat->AddProperty(&val, 1, AI_MATKEY_SHADING_MODEL);
} else if (prop.name == "BackfaceCulling") {
int val = (!prop.value);
mat->AddProperty(&val, 1, AI_MATKEY_TWOSIDED);
}
} else if (!ASSIMP_stricmp(child.name(), "texture") ||
!ASSIMP_stricmp(child.name(), "enum")) { // String properties - textures and texture related properties
StringProperty prop;
ReadStringProperty(prop, child);
if (prop.value.length()) {
// material type (shader)
if (prop.name == "Type") {
if (prop.value == "solid") {
// default material ...
} else if (prop.value == "trans_vertex_alpha") {
matFlags = AI_IRRMESH_MAT_trans_vertex_alpha;
} else if (prop.value == "lightmap") {
matFlags = AI_IRRMESH_MAT_lightmap;
} else if (prop.value == "solid_2layer") {
matFlags = AI_IRRMESH_MAT_solid_2layer;
} else if (prop.value == "lightmap_m2") {
matFlags = AI_IRRMESH_MAT_lightmap_m2;
} else if (prop.value == "lightmap_m4") {
matFlags = AI_IRRMESH_MAT_lightmap_m4;
} else if (prop.value == "lightmap_light") {
matFlags = AI_IRRMESH_MAT_lightmap_light;
} else if (prop.value == "lightmap_light_m2") {
matFlags = AI_IRRMESH_MAT_lightmap_light_m2;
} else if (prop.value == "lightmap_light_m4") {
matFlags = AI_IRRMESH_MAT_lightmap_light_m4;
} else if (prop.value == "lightmap_add") {
matFlags = AI_IRRMESH_MAT_lightmap_add;
} else if (prop.value == "normalmap_solid" ||
prop.value == "parallaxmap_solid") { // Normal and parallax maps are treated equally
matFlags = AI_IRRMESH_MAT_normalmap_solid;
} else if (prop.value == "normalmap_trans_vertex_alpha" ||
prop.value == "parallaxmap_trans_vertex_alpha") {
matFlags = AI_IRRMESH_MAT_normalmap_tva;
} else if (prop.value == "normalmap_trans_add" ||
prop.value == "parallaxmap_trans_add") {
matFlags = AI_IRRMESH_MAT_normalmap_ta;
} else {
ASSIMP_LOG_WARN("IRRMat: Unrecognized material type: ", prop.value);
}
}
// Up to 4 texture channels are supported
if (prop.name == "Texture1") {
// Always accept the primary texture channel
++cnt;
s.Set(prop.value);
mat->AddProperty(&s, AI_MATKEY_TEXTURE_DIFFUSE(0));
} else if (prop.name == "Texture2" && cnt == 1) {
// 2-layer material lightmapped?
if (matFlags & AI_IRRMESH_MAT_lightmap) {
++cnt;
s.Set(prop.value);
mat->AddProperty(&s, AI_MATKEY_TEXTURE_LIGHTMAP(0));
// Up to 4 texture channels are supported
if (prop.name == "Texture1") {
// Always accept the primary texture channel
++cnt;
s.Set(prop.value);
mat->AddProperty(&s, AI_MATKEY_TEXTURE_DIFFUSE(0));
} else if (prop.name == "Texture2" && cnt == 1) {
// 2-layer material lightmapped?
if (matFlags & AI_IRRMESH_MAT_lightmap) {
++cnt;
s.Set(prop.value);
mat->AddProperty(&s, AI_MATKEY_TEXTURE_LIGHTMAP(0));
// set the corresponding material flag
matFlags |= AI_IRRMESH_EXTRA_2ND_TEXTURE;
} else if (matFlags & AI_IRRMESH_MAT_normalmap_solid) { // alternatively: normal or parallax mapping
++cnt;
s.Set(prop.value);
mat->AddProperty(&s, AI_MATKEY_TEXTURE_NORMALS(0));
// set the corresponding material flag
matFlags |= AI_IRRMESH_EXTRA_2ND_TEXTURE;
} else if (matFlags & AI_IRRMESH_MAT_normalmap_solid) { // alternatively: normal or parallax mapping
++cnt;
s.Set(prop.value);
mat->AddProperty(&s, AI_MATKEY_TEXTURE_NORMALS(0));
// set the corresponding material flag
matFlags |= AI_IRRMESH_EXTRA_2ND_TEXTURE;
} else if (matFlags & AI_IRRMESH_MAT_solid_2layer) { // or just as second diffuse texture
++cnt;
s.Set(prop.value);
mat->AddProperty(&s, AI_MATKEY_TEXTURE_DIFFUSE(1));
++nd;
// set the corresponding material flag
matFlags |= AI_IRRMESH_EXTRA_2ND_TEXTURE;
} else if (matFlags & AI_IRRMESH_MAT_solid_2layer) { // or just as second diffuse texture
++cnt;
s.Set(prop.value);
mat->AddProperty(&s, AI_MATKEY_TEXTURE_DIFFUSE(1));
++nd;
// set the corresponding material flag
matFlags |= AI_IRRMESH_EXTRA_2ND_TEXTURE;
} else {
ASSIMP_LOG_WARN("IRRmat: Skipping second texture");
}
} else if (prop.name == "Texture3" && cnt == 2) {
// Irrlicht does not seem to use these channels.
++cnt;
s.Set(prop.value);
mat->AddProperty(&s, AI_MATKEY_TEXTURE_DIFFUSE(nd + 1));
} else if (prop.name == "Texture4" && cnt == 3) {
// Irrlicht does not seem to use these channels.
++cnt;
s.Set(prop.value);
mat->AddProperty(&s, AI_MATKEY_TEXTURE_DIFFUSE(nd + 2));
}
// set the corresponding material flag
matFlags |= AI_IRRMESH_EXTRA_2ND_TEXTURE;
} else {
ASSIMP_LOG_WARN("IRRmat: Skipping second texture");
}
} else if (prop.name == "Texture3" && cnt == 2) {
// Irrlicht does not seem to use these channels.
++cnt;
s.Set(prop.value);
mat->AddProperty(&s, AI_MATKEY_TEXTURE_DIFFUSE(nd + 1));
} else if (prop.name == "Texture4" && cnt == 3) {
// Irrlicht does not seem to use these channels.
++cnt;
s.Set(prop.value);
mat->AddProperty(&s, AI_MATKEY_TEXTURE_DIFFUSE(nd + 2));
}
// Texture mapping options
if (prop.name == "TextureWrap1" && cnt >= 1) {
int map = ConvertMappingMode(prop.value);
mat->AddProperty(&map, 1, AI_MATKEY_MAPPINGMODE_U_DIFFUSE(0));
mat->AddProperty(&map, 1, AI_MATKEY_MAPPINGMODE_V_DIFFUSE(0));
} else if (prop.name == "TextureWrap2" && cnt >= 2) {
int map = ConvertMappingMode(prop.value);
if (matFlags & AI_IRRMESH_MAT_lightmap) {
mat->AddProperty(&map, 1, AI_MATKEY_MAPPINGMODE_U_LIGHTMAP(0));
mat->AddProperty(&map, 1, AI_MATKEY_MAPPINGMODE_V_LIGHTMAP(0));
} else if (matFlags & (AI_IRRMESH_MAT_normalmap_solid)) {
mat->AddProperty(&map, 1, AI_MATKEY_MAPPINGMODE_U_NORMALS(0));
mat->AddProperty(&map, 1, AI_MATKEY_MAPPINGMODE_V_NORMALS(0));
} else if (matFlags & AI_IRRMESH_MAT_solid_2layer) {
mat->AddProperty(&map, 1, AI_MATKEY_MAPPINGMODE_U_DIFFUSE(1));
mat->AddProperty(&map, 1, AI_MATKEY_MAPPINGMODE_V_DIFFUSE(1));
}
} else if (prop.name == "TextureWrap3" && cnt >= 3) {
int map = ConvertMappingMode(prop.value);
mat->AddProperty(&map, 1, AI_MATKEY_MAPPINGMODE_U_DIFFUSE(nd + 1));
mat->AddProperty(&map, 1, AI_MATKEY_MAPPINGMODE_V_DIFFUSE(nd + 1));
} else if (prop.name == "TextureWrap4" && cnt >= 4) {
int map = ConvertMappingMode(prop.value);
mat->AddProperty(&map, 1, AI_MATKEY_MAPPINGMODE_U_DIFFUSE(nd + 2));
mat->AddProperty(&map, 1, AI_MATKEY_MAPPINGMODE_V_DIFFUSE(nd + 2));
}
}
}
//break;
/*case EXN_ELEMENT_END:
// Texture mapping options
if (prop.name == "TextureWrap1" && cnt >= 1) {
int map = ConvertMappingMode(prop.value);
mat->AddProperty(&map, 1, AI_MATKEY_MAPPINGMODE_U_DIFFUSE(0));
mat->AddProperty(&map, 1, AI_MATKEY_MAPPINGMODE_V_DIFFUSE(0));
} else if (prop.name == "TextureWrap2" && cnt >= 2) {
int map = ConvertMappingMode(prop.value);
if (matFlags & AI_IRRMESH_MAT_lightmap) {
mat->AddProperty(&map, 1, AI_MATKEY_MAPPINGMODE_U_LIGHTMAP(0));
mat->AddProperty(&map, 1, AI_MATKEY_MAPPINGMODE_V_LIGHTMAP(0));
} else if (matFlags & (AI_IRRMESH_MAT_normalmap_solid)) {
mat->AddProperty(&map, 1, AI_MATKEY_MAPPINGMODE_U_NORMALS(0));
mat->AddProperty(&map, 1, AI_MATKEY_MAPPINGMODE_V_NORMALS(0));
} else if (matFlags & AI_IRRMESH_MAT_solid_2layer) {
mat->AddProperty(&map, 1, AI_MATKEY_MAPPINGMODE_U_DIFFUSE(1));
mat->AddProperty(&map, 1, AI_MATKEY_MAPPINGMODE_V_DIFFUSE(1));
}
} else if (prop.name == "TextureWrap3" && cnt >= 3) {
int map = ConvertMappingMode(prop.value);
mat->AddProperty(&map, 1, AI_MATKEY_MAPPINGMODE_U_DIFFUSE(nd + 1));
mat->AddProperty(&map, 1, AI_MATKEY_MAPPINGMODE_V_DIFFUSE(nd + 1));
} else if (prop.name == "TextureWrap4" && cnt >= 4) {
int map = ConvertMappingMode(prop.value);
mat->AddProperty(&map, 1, AI_MATKEY_MAPPINGMODE_U_DIFFUSE(nd + 2));
mat->AddProperty(&map, 1, AI_MATKEY_MAPPINGMODE_V_DIFFUSE(nd + 2));
}
}
}
// break;
/*case EXN_ELEMENT_END:
// Assume there are no further nested nodes in <material> elements
if ( !ASSIMP_stricmp(reader->getNodeName(),"material") ||
@ -378,8 +378,8 @@ aiMaterial* IrrlichtBase::ParseMaterial(unsigned int& matFlags) {
break;
}
}*/
}
ASSIMP_LOG_ERROR("IRRMESH: Unexpected end of file. Material is not complete");
}
//ASSIMP_LOG_ERROR("IRRMESH: Unexpected end of file. Material is not complete");
return mat;
}

View File

@ -1,8 +1,8 @@
/** @file IRRShared.h
* @brief Shared utilities for the IRR and IRRMESH loaders
*/
* @brief Shared utilities for the IRR and IRRMESH loaders
*/
#ifndef INCLUDED_AI_IRRSHARED_H
#define INCLUDED_AI_IRRSHARED_H
@ -58,8 +58,7 @@ extern const aiMatrix4x4 AI_TO_IRR_MATRIX;
*/
class IrrlichtBase {
protected:
IrrlichtBase() :
mNode(nullptr) {
IrrlichtBase() {
// empty
}
@ -82,25 +81,25 @@ protected:
/// XML reader instance
XmlParser mParser;
pugi::xml_node *mNode;
// -------------------------------------------------------------------
/** Parse a material description from the XML
* @return The created material
* @param matFlags Receives AI_IRRMESH_MAT_XX flags
*/
aiMaterial *ParseMaterial(unsigned int &matFlags);
aiMaterial *ParseMaterial(pugi::xml_node &materialNode, unsigned int &matFlags);
// -------------------------------------------------------------------
/** Read a property of the specified type from the current XML element.
* @param out Receives output data
* @param node XML attribute element containing data
*/
void ReadHexProperty(HexProperty &out);
void ReadStringProperty(StringProperty &out);
void ReadBoolProperty(BoolProperty &out);
void ReadFloatProperty(FloatProperty &out);
void ReadVectorProperty(VectorProperty &out);
void ReadIntProperty(IntProperty &out);
void ReadHexProperty(HexProperty &out, pugi::xml_node& hexnode);
void ReadStringProperty(StringProperty &out, pugi::xml_node& stringnode);
void ReadBoolProperty(BoolProperty &out, pugi::xml_node& boolnode);
void ReadFloatProperty(FloatProperty &out, pugi::xml_node& floatnode);
void ReadVectorProperty(VectorProperty &out, pugi::xml_node& vectornode);
void ReadIntProperty(IntProperty &out, pugi::xml_node& intnode);
};
// ------------------------------------------------------------------------------------------------

View File

@ -632,18 +632,17 @@ void LWSImporter::InternReadFile(const std::string &pFile, aiScene *pScene, IOSy
nodes.push_back(d);
}
ASSIMP_LOG_ERROR("LWS: Unexpected keyword: \'Channel\'");
} else {
// important: index of channel
nodes.back().channels.emplace_back();
LWO::Envelope &env = nodes.back().channels.back();
env.index = strtoul10(c);
// currently we can just interpret the standard channels 0...9
// (hack) assume that index-i yields the binary channel type from LWO
env.type = (LWO::EnvelopeType)(env.index + 1);
}
// important: index of channel
nodes.back().channels.emplace_back();
LWO::Envelope &env = nodes.back().channels.back();
env.index = strtoul10(c);
// currently we can just interpret the standard channels 0...9
// (hack) assume that index-i yields the binary channel type from LWO
env.type = (LWO::EnvelopeType)(env.index + 1);
}
// 'Envelope': a single animation channel
else if ((*it).tokens[0] == "Envelope") {

View File

@ -138,18 +138,31 @@ bool MD5Parser::ParseSection(Section &out) {
char *sz = buffer;
while (!IsSpaceOrNewLine(*buffer)) {
++buffer;
if (buffer == bufferEnd)
return false;
}
out.mName = std::string(sz, (uintptr_t)(buffer - sz));
SkipSpaces();
while (IsSpace(*buffer)) {
++buffer;
if (buffer == bufferEnd)
return false;
}
bool running = true;
while (running) {
if ('{' == *buffer) {
// it is a normal section so read all lines
++buffer;
if (buffer == bufferEnd)
return false;
bool run = true;
while (run) {
if (!SkipSpacesAndLineEnd()) {
while (IsSpaceOrNewLine(*buffer)) {
++buffer;
if (buffer == bufferEnd)
return false;
}
if ('\0' == *buffer) {
return false; // seems this was the last section
}
if ('}' == *buffer) {
@ -164,25 +177,39 @@ bool MD5Parser::ParseSection(Section &out) {
elem.szStart = buffer;
// terminate the line with zero
while (!IsLineEnd(*buffer))
while (!IsLineEnd(*buffer)) {
++buffer;
if (buffer == bufferEnd)
return false;
}
if (*buffer) {
++lineNumber;
*buffer++ = '\0';
if (buffer == bufferEnd)
return false;
}
}
break;
} else if (!IsSpaceOrNewLine(*buffer)) {
// it is an element at global scope. Parse its value and go on
sz = buffer;
while (!IsSpaceOrNewLine(*buffer++))
;
while (!IsSpaceOrNewLine(*buffer++)) {
if (buffer == bufferEnd)
return false;
}
out.mGlobalValue = std::string(sz, (uintptr_t)(buffer - sz));
continue;
}
break;
}
return SkipSpacesAndLineEnd();
if (buffer == bufferEnd)
return false;
while (IsSpaceOrNewLine(*buffer)) {
++buffer;
if (buffer == bufferEnd)
return false;
}
return '\0' != *buffer;
}
// ------------------------------------------------------------------------------------------------
@ -228,15 +255,20 @@ bool MD5Parser::ParseSection(Section &out) {
out.data[out.length] = '\0';
// parse a string, enclosed in quotation marks
#define AI_MD5_PARSE_STRING_IN_QUOTATION(out) \
while ('\"' != *sz) \
++sz; \
const char *szStart = ++sz; \
while ('\"' != *sz) \
++sz; \
const char *szEnd = (sz++); \
out.length = (ai_uint32)(szEnd - szStart); \
::memcpy(out.data, szStart, out.length); \
#define AI_MD5_PARSE_STRING_IN_QUOTATION(out) \
out.length = 0; \
while ('\"' != *sz && '\0' != *sz) \
++sz; \
if ('\0' != *sz) { \
const char *szStart = ++sz; \
while ('\"' != *sz && '\0' != *sz) \
++sz; \
if ('\0' != *sz) { \
const char *szEnd = (sz++); \
out.length = (ai_uint32)(szEnd - szStart); \
::memcpy(out.data, szStart, out.length); \
} \
} \
out.data[out.length] = '\0';
// ------------------------------------------------------------------------------------------------
// .MD5MESH parsing function

View File

@ -271,10 +271,16 @@ void MDLImporter::InternReadFile(const std::string &pFile,
}
}
// ------------------------------------------------------------------------------------------------
// Check whether we're still inside the valid file range
bool MDLImporter::IsPosValid(const void *szPos) const {
return szPos && (const unsigned char *)szPos <= this->mBuffer + this->iFileSize && szPos >= this->mBuffer;
}
// ------------------------------------------------------------------------------------------------
// Check whether we're still inside the valid file range
void MDLImporter::SizeCheck(const void *szPos) {
if (!szPos || (const unsigned char *)szPos > this->mBuffer + this->iFileSize) {
if (!IsPosValid(szPos)) {
throw DeadlyImportError("Invalid MDL file. The file is too small "
"or contains invalid data.");
}
@ -284,7 +290,7 @@ void MDLImporter::SizeCheck(const void *szPos) {
// Just for debugging purposes
void MDLImporter::SizeCheck(const void *szPos, const char *szFile, unsigned int iLine) {
ai_assert(nullptr != szFile);
if (!szPos || (const unsigned char *)szPos > mBuffer + iFileSize) {
if (!IsPosValid(szPos)) {
// remove a directory if there is one
const char *szFilePtr = ::strrchr(szFile, '\\');
if (!szFilePtr) {

View File

@ -150,6 +150,7 @@ protected:
*/
void SizeCheck(const void* szPos);
void SizeCheck(const void* szPos, const char* szFile, unsigned int iLine);
bool IsPosValid(const void* szPos) const;
// -------------------------------------------------------------------
/** Validate the header data structure of a game studio MDL7 file

View File

@ -481,6 +481,8 @@ void MDLImporter::ParseSkinLump_3DGS_MDL7(
pcNew->achFormatHint[2] = 's';
pcNew->achFormatHint[3] = '\0';
SizeCheck(szCurrent + pcNew->mWidth);
pcNew->pcData = (aiTexel *)new unsigned char[pcNew->mWidth];
memcpy(pcNew->pcData, szCurrent, pcNew->mWidth);
szCurrent += iWidth;
@ -493,12 +495,12 @@ void MDLImporter::ParseSkinLump_3DGS_MDL7(
aiString szFile;
const size_t iLen = strlen((const char *)szCurrent);
size_t iLen2 = iLen + 1;
iLen2 = iLen2 > MAXLEN ? MAXLEN : iLen2;
size_t iLen2 = iLen > (MAXLEN - 1) ? (MAXLEN - 1) : iLen;
memcpy(szFile.data, (const char *)szCurrent, iLen2);
szFile.data[iLen2] = '\0';
szFile.length = static_cast<ai_uint32>(iLen2);
szCurrent += iLen2;
szCurrent += iLen2 + 1;
// place this as diffuse texture
pcMatOut->AddProperty(&szFile, AI_MATKEY_TEXTURE_DIFFUSE(0));
@ -703,7 +705,14 @@ void MDLImporter::SkipSkinLump_3DGS_MDL7(
tex.pcData = bad_texel;
tex.mHeight = iHeight;
tex.mWidth = iWidth;
ParseTextureColorData(szCurrent, iMasked, &iSkip, &tex);
try {
ParseTextureColorData(szCurrent, iMasked, &iSkip, &tex);
} catch (...) {
// FIX: Important, otherwise the destructor will crash
tex.pcData = nullptr;
throw;
}
// FIX: Important, otherwise the destructor will crash
tex.pcData = nullptr;

View File

@ -52,6 +52,7 @@ OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
#include <assimp/importerdesc.h>
#include <assimp/StreamReader.h>
#include <map>
#include <limits>
using namespace Assimp;
@ -160,6 +161,9 @@ void NDOImporter::InternReadFile( const std::string& pFile,
temp = file_format >= 12 ? reader.GetU4() : reader.GetU2();
head = (const char*)reader.GetPtr();
if (std::numeric_limits<unsigned int>::max() - 76 < temp) {
throw DeadlyImportError("Invalid name length");
}
reader.IncPtr(temp + 76); /* skip unknown stuff */
obj.name = std::string(head, temp);

View File

@ -284,7 +284,7 @@ void OFFImporter::InternReadFile( const std::string& pFile, aiScene* pScene, IOS
for (unsigned int i = 0; i < numFaces; ) {
if(!GetNextLine(buffer,line)) {
ASSIMP_LOG_ERROR("OFF: The number of faces in the header is incorrect");
break;
throw DeadlyImportError("OFF: The number of faces in the header is incorrect");
}
unsigned int idx;
sz = line; SkipSpaces(&sz);

View File

@ -239,8 +239,6 @@ struct Mesh {
unsigned int m_uiMaterialIndex;
/// True, if normals are stored.
bool m_hasNormals;
/// True, if vertex colors are stored.
bool m_hasVertexColors;
/// Constructor
explicit Mesh(const std::string &name) :

View File

@ -323,7 +323,7 @@ aiMesh *ObjFileImporter::createTopology(const ObjFile::Model *pModel, const ObjF
return nullptr;
}
aiMesh *pMesh = new aiMesh;
std::unique_ptr<aiMesh> pMesh(new aiMesh);
if (!pObjMesh->m_name.empty()) {
pMesh->mName.Set(pObjMesh->m_name);
}
@ -385,9 +385,9 @@ aiMesh *ObjFileImporter::createTopology(const ObjFile::Model *pModel, const ObjF
}
// Create mesh vertices
createVertexArray(pModel, pData, meshIndex, pMesh, uiIdxCount);
createVertexArray(pModel, pData, meshIndex, pMesh.get(), uiIdxCount);
return pMesh;
return pMesh.release();
}
// ------------------------------------------------------------------------------------------------
@ -498,6 +498,10 @@ void ObjFileImporter::createVertexArray(const ObjFile::Model *pModel,
if (vertexIndex) {
if (!last) {
if (pMesh->mNumVertices <= newIndex + 1) {
throw DeadlyImportError("OBJ: bad vertex index");
}
pMesh->mVertices[newIndex + 1] = pMesh->mVertices[newIndex];
if (!sourceFace->m_normals.empty() && !pModel->mNormals.empty()) {
pMesh->mNormals[newIndex + 1] = pMesh->mNormals[newIndex];

View File

@ -252,9 +252,9 @@ void ObjFileMtlImporter::load() {
case 'a': // Anisotropy
{
++m_DataIt;
getFloatValue(m_pModel->mCurrentMaterial->anisotropy);
if (m_pModel->mCurrentMaterial != nullptr)
m_DataIt = skipLine<DataArrayIt>(m_DataIt, m_DataItEnd, m_uiLine);
getFloatValue(m_pModel->mCurrentMaterial->anisotropy);
m_DataIt = skipLine<DataArrayIt>(m_DataIt, m_DataItEnd, m_uiLine);
} break;
default: {
@ -371,6 +371,7 @@ void ObjFileMtlImporter::getTexture() {
if (m_pModel->mCurrentMaterial == nullptr) {
m_pModel->mCurrentMaterial = new ObjFile::Material();
m_pModel->mCurrentMaterial->MaterialName.Set("Empty_Material");
m_pModel->mMaterialMap["Empty_Material"] = m_pModel->mCurrentMaterial;
}
const char *pPtr(&(*m_DataIt));

View File

@ -156,9 +156,17 @@ void ObjFileParser::parseFile(IOStreamBuffer<char> &streamBuffer) {
// read in vertex definition (homogeneous coords)
getHomogeneousVector3(m_pModel->mVertices);
} else if (numComponents == 6) {
// fill previous omitted vertex-colors by default
if (m_pModel->mVertexColors.size() < m_pModel->mVertices.size()) {
m_pModel->mVertexColors.resize(m_pModel->mVertices.size(), aiVector3D(0, 0, 0));
}
// read vertex and vertex-color
getTwoVectors3(m_pModel->mVertices, m_pModel->mVertexColors);
}
// append omitted vertex-colors as default for the end if any vertex-color exists
if (!m_pModel->mVertexColors.empty() && m_pModel->mVertexColors.size() < m_pModel->mVertices.size()) {
m_pModel->mVertexColors.resize(m_pModel->mVertices.size(), aiVector3D(0, 0, 0));
}
} else if (*m_DataIt == 't') {
// read in texture coordinate ( 2D or 3D )
++m_DataIt;
@ -456,8 +464,19 @@ void ObjFileParser::getFace(aiPrimitiveType type) {
iPos = 0;
} else {
//OBJ USES 1 Base ARRAYS!!!!
const char *token = &(*m_DataIt);
const int iVal = ::atoi(token);
int iVal;
auto end = m_DataIt;
// find either the buffer end or the '\0'
while (end < m_DataItEnd && *end != '\0')
++end;
// avoid temporary string allocation if there is a zero
if (end != m_DataItEnd) {
iVal = ::atoi(&(*m_DataIt));
} else {
// otherwise make a zero terminated copy, which is safe to pass to atoi
std::string number(&(*m_DataIt), m_DataItEnd - m_DataIt);
iVal = ::atoi(number.c_str());
}
// increment iStep position based off of the sign and # of digits
int tmp = iVal;

View File

@ -837,7 +837,10 @@ void SMDImporter::ParseNodeInfo(const char* szCurrent, const char** szCurrentOut
unsigned int iBone = 0;
SkipSpacesAndLineEnd(szCurrent,&szCurrent);
if ( !ParseUnsignedInt(szCurrent,&szCurrent,iBone) || !SkipSpaces(szCurrent,&szCurrent)) {
LogErrorNoThrow("Unexpected EOF/EOL while parsing bone index");
throw DeadlyImportError("Unexpected EOF/EOL while parsing bone index");
}
if (iBone == UINT_MAX) {
LogErrorNoThrow("Invalid bone number while parsing bone index");
SMDI_PARSE_RETURN;
}
// add our bone to the list

View File

@ -93,7 +93,10 @@ const aiImporterDesc *glTFImporter::GetInfo() const {
bool glTFImporter::CanRead(const std::string &pFile, IOSystem *pIOHandler, bool /* checkSig */) const {
glTF::Asset asset(pIOHandler);
try {
asset.Load(pFile, GetExtension(pFile) == "glb");
asset.Load(pFile,
CheckMagicToken(
pIOHandler, pFile, AI_GLB_MAGIC_NUMBER, 1, 0,
static_cast<unsigned int>(strlen(AI_GLB_MAGIC_NUMBER))));
return asset.asset;
} catch (...) {
return false;
@ -697,7 +700,10 @@ void glTFImporter::InternReadFile(const std::string &pFile, aiScene *pScene, IOS
// read the asset file
glTF::Asset asset(pIOHandler);
asset.Load(pFile, GetExtension(pFile) == "glb");
asset.Load(pFile,
CheckMagicToken(
pIOHandler, pFile, AI_GLB_MAGIC_NUMBER, 1, 0,
static_cast<unsigned int>(strlen(AI_GLB_MAGIC_NUMBER))));
//
// Copy the data out

View File

@ -371,6 +371,15 @@ struct CustomExtension {
CustomExtension& operator=(const CustomExtension&) = default;
};
//! Represents metadata in an glTF2 object
struct Extras {
std::vector<CustomExtension> mValues;
inline bool HasExtras() const {
return !mValues.empty();
}
};
//! Base class for all glTF top-level objects
struct Object {
int index; //!< The index of this object within its property container
@ -379,7 +388,7 @@ struct Object {
std::string name; //!< The user-defined name of this object
CustomExtension customExtensions;
CustomExtension extras;
Extras extras;
//! Objects marked as special are not exported (used to emulate the binary body buffer)
virtual bool IsSpecial() const { return false; }

View File

@ -45,6 +45,9 @@ OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
#include <assimp/StringUtils.h>
#include <assimp/DefaultLogger.hpp>
#include <assimp/Base64.hpp>
#include <rapidjson/document.h>
#include <rapidjson/schema.h>
#include <rapidjson/stringbuffer.h>
// clang-format off
#ifdef ASSIMP_ENABLE_DRACO
@ -139,6 +142,18 @@ inline CustomExtension ReadExtensions(const char *name, Value &obj) {
return ret;
}
inline Extras ReadExtras(Value &obj) {
Extras ret;
ret.mValues.reserve(obj.MemberCount());
for (auto it = obj.MemberBegin(); it != obj.MemberEnd(); ++it) {
auto &val = it->value;
ret.mValues.emplace_back(ReadExtensions(it->name.GetString(), val));
}
return ret;
}
inline void CopyData(size_t count, const uint8_t *src, size_t src_stride,
uint8_t *dst, size_t dst_stride) {
if (src_stride == dst_stride) {
@ -248,7 +263,7 @@ inline void Object::ReadExtensions(Value &val) {
inline void Object::ReadExtras(Value &val) {
if (Value *curExtras = FindObject(val, "extras")) {
this->extras = glTF2::ReadExtensions("extras", *curExtras);
this->extras = glTF2::ReadExtras(*curExtras);
}
}

View File

@ -654,6 +654,44 @@ namespace glTF2 {
}
}
inline void WriteExtrasValue(Value &parent, const CustomExtension &value, AssetWriter &w) {
Value valueNode;
if (value.mStringValue.isPresent) {
MakeValue(valueNode, value.mStringValue.value.c_str(), w.mAl);
} else if (value.mDoubleValue.isPresent) {
MakeValue(valueNode, value.mDoubleValue.value, w.mAl);
} else if (value.mUint64Value.isPresent) {
MakeValue(valueNode, value.mUint64Value.value, w.mAl);
} else if (value.mInt64Value.isPresent) {
MakeValue(valueNode, value.mInt64Value.value, w.mAl);
} else if (value.mBoolValue.isPresent) {
MakeValue(valueNode, value.mBoolValue.value, w.mAl);
} else if (value.mValues.isPresent) {
valueNode.SetObject();
for (auto const &subvalue : value.mValues.value) {
WriteExtrasValue(valueNode, subvalue, w);
}
}
parent.AddMember(StringRef(value.name), valueNode, w.mAl);
}
inline void WriteExtras(Value &obj, const Extras &extras, AssetWriter &w) {
if (!extras.HasExtras()) {
return;
}
Value extrasNode;
extrasNode.SetObject();
for (auto const &value : extras.mValues) {
WriteExtrasValue(extrasNode, value, w);
}
obj.AddMember("extras", extrasNode, w.mAl);
}
inline void Write(Value& obj, Node& n, AssetWriter& w)
{
if (n.matrix.isPresent) {
@ -689,6 +727,8 @@ namespace glTF2 {
if(n.skeletons.size()) {
AddRefsVector(obj, "skeletons", n.skeletons, w.mAl);
}
WriteExtras(obj, n.extras, w);
}
inline void Write(Value& /*obj*/, Program& /*b*/, AssetWriter& /*w*/)
@ -762,7 +802,6 @@ namespace glTF2 {
}
}
inline AssetWriter::AssetWriter(Asset& a)
: mDoc()
, mAsset(a)

View File

@ -263,7 +263,7 @@ size_t NZDiff(void *data, void *dataBase, size_t count, unsigned int numCompsIn,
for (short idx = 0; bufferData_ptr < bufferData_end; idx += 1, bufferData_ptr += numCompsIn) {
bool bNonZero = false;
//for the data, check any component Non Zero
// for the data, check any component Non Zero
for (unsigned int j = 0; j < numCompsOut; j++) {
double valueData = bufferData_ptr[j];
double valueBase = bufferBase_ptr ? bufferBase_ptr[j] : 0;
@ -273,11 +273,11 @@ size_t NZDiff(void *data, void *dataBase, size_t count, unsigned int numCompsIn,
}
}
//all zeros, continue
// all zeros, continue
if (!bNonZero)
continue;
//non zero, store the data
// non zero, store the data
for (unsigned int j = 0; j < numCompsOut; j++) {
T valueData = bufferData_ptr[j];
T valueBase = bufferBase_ptr ? bufferBase_ptr[j] : 0;
@ -286,14 +286,14 @@ size_t NZDiff(void *data, void *dataBase, size_t count, unsigned int numCompsIn,
vNZIdx.push_back(idx);
}
//avoid all-0, put 1 item
// avoid all-0, put 1 item
if (vNZDiff.size() == 0) {
for (unsigned int j = 0; j < numCompsOut; j++)
vNZDiff.push_back(0);
vNZIdx.push_back(0);
}
//process data
// process data
outputNZDiff = new T[vNZDiff.size()];
memcpy(outputNZDiff, vNZDiff.data(), vNZDiff.size() * sizeof(T));
@ -361,7 +361,7 @@ inline Ref<Accessor> ExportDataSparse(Asset &a, std::string &meshName, Ref<Buffe
acc->sparse.reset(new Accessor::Sparse);
acc->sparse->count = nzCount;
//indices
// indices
unsigned int bytesPerIdx = sizeof(unsigned short);
size_t indices_offset = buffer->byteLength;
size_t indices_padding = indices_offset % bytesPerIdx;
@ -379,7 +379,7 @@ inline Ref<Accessor> ExportDataSparse(Asset &a, std::string &meshName, Ref<Buffe
acc->sparse->indicesByteOffset = 0;
acc->WriteSparseIndices(nzCount, nzIdx, 1 * bytesPerIdx);
//values
// values
size_t values_offset = buffer->byteLength;
size_t values_padding = values_offset % bytesPerComp;
values_offset += values_padding;
@ -395,9 +395,9 @@ inline Ref<Accessor> ExportDataSparse(Asset &a, std::string &meshName, Ref<Buffe
acc->sparse->valuesByteOffset = 0;
acc->WriteSparseValues(nzCount, nzDiff, numCompsIn * bytesPerComp);
//clear
delete[](char *) nzDiff;
delete[](char *) nzIdx;
// clear
delete[] (char *)nzDiff;
delete[] (char *)nzIdx;
}
return acc;
}
@ -443,6 +443,61 @@ inline Ref<Accessor> ExportData(Asset &a, std::string &meshName, Ref<Buffer> &bu
return acc;
}
inline void ExportNodeExtras(const aiMetadataEntry &metadataEntry, aiString name, CustomExtension &value) {
value.name = name.C_Str();
switch (metadataEntry.mType) {
case AI_BOOL:
value.mBoolValue.value = *static_cast<bool *>(metadataEntry.mData);
value.mBoolValue.isPresent = true;
break;
case AI_INT32:
value.mInt64Value.value = *static_cast<int32_t *>(metadataEntry.mData);
value.mInt64Value.isPresent = true;
break;
case AI_UINT64:
value.mUint64Value.value = *static_cast<uint64_t *>(metadataEntry.mData);
value.mUint64Value.isPresent = true;
break;
case AI_FLOAT:
value.mDoubleValue.value = *static_cast<float *>(metadataEntry.mData);
value.mDoubleValue.isPresent = true;
break;
case AI_DOUBLE:
value.mDoubleValue.value = *static_cast<double *>(metadataEntry.mData);
value.mDoubleValue.isPresent = true;
break;
case AI_AISTRING:
value.mStringValue.value = static_cast<aiString *>(metadataEntry.mData)->C_Str();
value.mStringValue.isPresent = true;
break;
case AI_AIMETADATA: {
const aiMetadata *subMetadata = static_cast<aiMetadata *>(metadataEntry.mData);
value.mValues.value.resize(subMetadata->mNumProperties);
value.mValues.isPresent = true;
for (unsigned i = 0; i < subMetadata->mNumProperties; ++i) {
ExportNodeExtras(subMetadata->mValues[i], subMetadata->mKeys[i], value.mValues.value.at(i));
}
break;
}
default:
// AI_AIVECTOR3D not handled
break;
}
}
inline void ExportNodeExtras(const aiMetadata *metadata, Extras &extras) {
if (metadata == nullptr || metadata->mNumProperties == 0) {
return;
}
extras.mValues.resize(metadata->mNumProperties);
for (unsigned int i = 0; i < metadata->mNumProperties; ++i) {
ExportNodeExtras(metadata->mValues[i], metadata->mKeys[i], extras.mValues.at(i));
}
}
inline void SetSamplerWrap(SamplerWrap &wrap, aiTextureMapMode map) {
switch (map) {
case aiTextureMapMode_Clamp:
@ -544,7 +599,7 @@ void glTF2Exporter::GetMatTex(const aiMaterial &mat, Ref<Texture> &texture, unsi
if (curTex != nullptr) { // embedded
texture->source->name = curTex->mFilename.C_Str();
//basisu: embedded ktx2, bu
// basisu: embedded ktx2, bu
if (curTex->achFormatHint[0]) {
std::string mimeType = "image/";
if (memcmp(curTex->achFormatHint, "jpg", 3) == 0)
@ -564,7 +619,7 @@ void glTF2Exporter::GetMatTex(const aiMaterial &mat, Ref<Texture> &texture, unsi
}
// The asset has its own buffer, see Image::SetData
//basisu: "image/ktx2", "image/basis" as is
// basisu: "image/ktx2", "image/basis" as is
texture->source->SetData(reinterpret_cast<uint8_t *>(curTex->pcData), curTex->mWidth, *mAsset);
} else {
texture->source->uri = path;
@ -574,7 +629,7 @@ void glTF2Exporter::GetMatTex(const aiMaterial &mat, Ref<Texture> &texture, unsi
}
}
//basisu
// basisu
if (useBasisUniversal) {
mAsset->extensionsUsed.KHR_texture_basisu = true;
mAsset->extensionsRequired.KHR_texture_basisu = true;
@ -597,7 +652,7 @@ void glTF2Exporter::GetMatTex(const aiMaterial &mat, NormalTextureInfo &prop, ai
GetMatTex(mat, texture, prop.texCoord, tt, slot);
if (texture) {
//GetMatTexProp(mat, prop.texCoord, "texCoord", tt, slot);
// GetMatTexProp(mat, prop.texCoord, "texCoord", tt, slot);
GetMatTexProp(mat, prop.scale, "scale", tt, slot);
}
}
@ -608,7 +663,7 @@ void glTF2Exporter::GetMatTex(const aiMaterial &mat, OcclusionTextureInfo &prop,
GetMatTex(mat, texture, prop.texCoord, tt, slot);
if (texture) {
//GetMatTexProp(mat, prop.texCoord, "texCoord", tt, slot);
// GetMatTexProp(mat, prop.texCoord, "texCoord", tt, slot);
GetMatTexProp(mat, prop.strength, "strength", tt, slot);
}
}
@ -675,7 +730,7 @@ bool glTF2Exporter::GetMatSpecGloss(const aiMaterial &mat, glTF2::PbrSpecularGlo
bool glTF2Exporter::GetMatSpecular(const aiMaterial &mat, glTF2::MaterialSpecular &specular) {
// Specular requires either/or, default factors of zero disables specular, so do not export
if (GetMatColor(mat, specular.specularColorFactor, AI_MATKEY_COLOR_SPECULAR) != AI_SUCCESS || mat.Get(AI_MATKEY_SPECULAR_FACTOR, specular.specularFactor) != AI_SUCCESS) {
if (GetMatColor(mat, specular.specularColorFactor, AI_MATKEY_COLOR_SPECULAR) != AI_SUCCESS && mat.Get(AI_MATKEY_SPECULAR_FACTOR, specular.specularFactor) != AI_SUCCESS) {
return false;
}
// The spec states that the default is 1.0 and [1.0, 1.0, 1.0]. We if both are 0, which should disable specular. Otherwise, if one is 0, set to 1.0
@ -777,20 +832,30 @@ void glTF2Exporter::ExportMaterials() {
GetMatTex(mat, m->pbrMetallicRoughness.baseColorTexture, aiTextureType_BASE_COLOR);
if (!m->pbrMetallicRoughness.baseColorTexture.texture) {
//if there wasn't a baseColorTexture defined in the source, fallback to any diffuse texture
// if there wasn't a baseColorTexture defined in the source, fallback to any diffuse texture
GetMatTex(mat, m->pbrMetallicRoughness.baseColorTexture, aiTextureType_DIFFUSE);
}
GetMatTex(mat, m->pbrMetallicRoughness.metallicRoughnessTexture, AI_MATKEY_GLTF_PBRMETALLICROUGHNESS_METALLICROUGHNESS_TEXTURE);
GetMatTex(mat, m->pbrMetallicRoughness.metallicRoughnessTexture, aiTextureType_DIFFUSE_ROUGHNESS);
if (!m->pbrMetallicRoughness.metallicRoughnessTexture.texture) {
// if there wasn't a aiTextureType_DIFFUSE_ROUGHNESS defined in the source, fallback to aiTextureType_METALNESS
GetMatTex(mat, m->pbrMetallicRoughness.metallicRoughnessTexture, aiTextureType_METALNESS);
}
if (!m->pbrMetallicRoughness.metallicRoughnessTexture.texture) {
// if there still wasn't a aiTextureType_METALNESS defined in the source, fallback to AI_MATKEY_GLTF_PBRMETALLICROUGHNESS_METALLICROUGHNESS_TEXTURE
GetMatTex(mat, m->pbrMetallicRoughness.metallicRoughnessTexture, AI_MATKEY_GLTF_PBRMETALLICROUGHNESS_METALLICROUGHNESS_TEXTURE);
}
if (GetMatColor(mat, m->pbrMetallicRoughness.baseColorFactor, AI_MATKEY_BASE_COLOR) != AI_SUCCESS) {
// if baseColorFactor wasn't defined, then the source is likely not a metallic roughness material.
//a fallback to any diffuse color should be used instead
// a fallback to any diffuse color should be used instead
GetMatColor(mat, m->pbrMetallicRoughness.baseColorFactor, AI_MATKEY_COLOR_DIFFUSE);
}
if (mat.Get(AI_MATKEY_METALLIC_FACTOR, m->pbrMetallicRoughness.metallicFactor) != AI_SUCCESS) {
//if metallicFactor wasn't defined, then the source is likely not a PBR file, and the metallicFactor should be 0
// if metallicFactor wasn't defined, then the source is likely not a PBR file, and the metallicFactor should be 0
m->pbrMetallicRoughness.metallicFactor = 0;
}
@ -803,10 +868,10 @@ void glTF2Exporter::ExportMaterials() {
if (mat.Get(AI_MATKEY_COLOR_SPECULAR, specularColor) == AI_SUCCESS && mat.Get(AI_MATKEY_SHININESS, shininess) == AI_SUCCESS) {
// convert specular color to luminance
float specularIntensity = specularColor[0] * 0.2125f + specularColor[1] * 0.7154f + specularColor[2] * 0.0721f;
//normalize shininess (assuming max is 1000) with an inverse exponentional curve
// normalize shininess (assuming max is 1000) with an inverse exponentional curve
float normalizedShininess = std::sqrt(shininess / 1000);
//clamp the shininess value between 0 and 1
// clamp the shininess value between 0 and 1
normalizedShininess = std::min(std::max(normalizedShininess, 0.0f), 1.0f);
// low specular intensity values should produce a rough material even if shininess is high.
normalizedShininess = normalizedShininess * specularIntensity;
@ -1004,7 +1069,7 @@ void ExportSkin(Asset &mAsset, const aiMesh *aimesh, Ref<Mesh> &meshRef, Ref<Buf
if (boneIndexFitted != -1) {
vertexJointData[vertexId][boneIndexFitted] = static_cast<float>(jointNamesIndex);
}
}else {
} else {
vertexJointData[vertexId][jointsPerVertex[vertexId]] = static_cast<float>(jointNamesIndex);
vertexWeightData[vertexId][jointsPerVertex[vertexId]] = vertWeight;
@ -1016,7 +1081,7 @@ void ExportSkin(Asset &mAsset, const aiMesh *aimesh, Ref<Mesh> &meshRef, Ref<Buf
Mesh::Primitive &p = meshRef->primitives.back();
Ref<Accessor> vertexJointAccessor = ExportData(mAsset, skinRef->id, bufferRef, aimesh->mNumVertices,
vertexJointData, AttribType::VEC4, AttribType::VEC4, ComponentType_FLOAT);
vertexJointData, AttribType::VEC4, AttribType::VEC4, ComponentType_FLOAT);
if (vertexJointAccessor) {
size_t offset = vertexJointAccessor->bufferView->byteOffset;
size_t bytesLen = vertexJointAccessor->bufferView->byteLength;
@ -1100,7 +1165,7 @@ void glTF2Exporter::ExportMeshes() {
/******************* Vertices ********************/
Ref<Accessor> v = ExportData(*mAsset, meshId, b, aim->mNumVertices, aim->mVertices, AttribType::VEC3,
AttribType::VEC3, ComponentType_FLOAT, BufferViewTarget_ARRAY_BUFFER);
AttribType::VEC3, ComponentType_FLOAT, BufferViewTarget_ARRAY_BUFFER);
if (v) {
p.attributes.position.push_back(v);
}
@ -1114,7 +1179,7 @@ void glTF2Exporter::ExportMeshes() {
}
Ref<Accessor> n = ExportData(*mAsset, meshId, b, aim->mNumVertices, aim->mNormals, AttribType::VEC3,
AttribType::VEC3, ComponentType_FLOAT, BufferViewTarget_ARRAY_BUFFER);
AttribType::VEC3, ComponentType_FLOAT, BufferViewTarget_ARRAY_BUFFER);
if (n) {
p.attributes.normal.push_back(n);
}
@ -1136,7 +1201,7 @@ void glTF2Exporter::ExportMeshes() {
AttribType::Value type = (aim->mNumUVComponents[i] == 2) ? AttribType::VEC2 : AttribType::VEC3;
Ref<Accessor> tc = ExportData(*mAsset, meshId, b, aim->mNumVertices, aim->mTextureCoords[i],
AttribType::VEC3, type, ComponentType_FLOAT, BufferViewTarget_ARRAY_BUFFER);
AttribType::VEC3, type, ComponentType_FLOAT, BufferViewTarget_ARRAY_BUFFER);
if (tc) {
p.attributes.texcoord.push_back(tc);
}
@ -1146,7 +1211,7 @@ void glTF2Exporter::ExportMeshes() {
/*************** Vertex colors ****************/
for (unsigned int indexColorChannel = 0; indexColorChannel < aim->GetNumColorChannels(); ++indexColorChannel) {
Ref<Accessor> c = ExportData(*mAsset, meshId, b, aim->mNumVertices, aim->mColors[indexColorChannel],
AttribType::VEC4, AttribType::VEC4, ComponentType_FLOAT, BufferViewTarget_ARRAY_BUFFER);
AttribType::VEC4, AttribType::VEC4, ComponentType_FLOAT, BufferViewTarget_ARRAY_BUFFER);
if (c) {
p.attributes.color.push_back(c);
}
@ -1164,7 +1229,7 @@ void glTF2Exporter::ExportMeshes() {
}
p.indices = ExportData(*mAsset, meshId, b, indices.size(), &indices[0], AttribType::SCALAR, AttribType::SCALAR,
ComponentType_UNSIGNED_INT, BufferViewTarget_ELEMENT_ARRAY_BUFFER);
ComponentType_UNSIGNED_INT, BufferViewTarget_ELEMENT_ARRAY_BUFFER);
}
switch (aim->mPrimitiveTypes) {
@ -1307,24 +1372,24 @@ void glTF2Exporter::MergeMeshes() {
unsigned int nMeshes = static_cast<unsigned int>(node->meshes.size());
//skip if it's 1 or less meshes per node
// skip if it's 1 or less meshes per node
if (nMeshes > 1) {
Ref<Mesh> firstMesh = node->meshes.at(0);
//loop backwards to allow easy removal of a mesh from a node once it's merged
// loop backwards to allow easy removal of a mesh from a node once it's merged
for (unsigned int m = nMeshes - 1; m >= 1; --m) {
Ref<Mesh> mesh = node->meshes.at(m);
//append this mesh's primitives to the first mesh's primitives
// append this mesh's primitives to the first mesh's primitives
firstMesh->primitives.insert(
firstMesh->primitives.end(),
mesh->primitives.begin(),
mesh->primitives.end());
//remove the mesh from the list of meshes
// remove the mesh from the list of meshes
unsigned int removedIndex = mAsset->meshes.Remove(mesh->id.c_str());
//find the presence of the removed mesh in other nodes
// find the presence of the removed mesh in other nodes
for (unsigned int nn = 0; nn < mAsset->nodes.Size(); ++nn) {
Ref<Node> curNode = mAsset->nodes.Get(nn);
@ -1343,7 +1408,7 @@ void glTF2Exporter::MergeMeshes() {
}
}
//since we were looping backwards, reverse the order of merged primitives to their original order
// since we were looping backwards, reverse the order of merged primitives to their original order
std::reverse(firstMesh->primitives.begin() + 1, firstMesh->primitives.end());
}
}
@ -1386,6 +1451,8 @@ unsigned int glTF2Exporter::ExportNode(const aiNode *n, Ref<Node> &parent) {
node->parent = parent;
node->name = name;
ExportNodeExtras(n->mMetaData, node->extras);
if (!n->mTransformation.IsIdentity()) {
if (mScene->mNumAnimations > 0 || (mProperties && mProperties->HasPropertyBool("GLTF2_NODE_IN_TRS"))) {
aiQuaternion quaternion;
@ -1468,9 +1535,9 @@ inline void ExtractTranslationSampler(Asset &asset, std::string &animId, Ref<Buf
const aiVectorKey &key = nodeChannel->mPositionKeys[i];
// mTime is measured in ticks, but GLTF time is measured in seconds, so convert.
times[i] = static_cast<float>(key.mTime / ticksPerSecond);
values[(i * 3) + 0] = (ai_real) key.mValue.x;
values[(i * 3) + 1] = (ai_real) key.mValue.y;
values[(i * 3) + 2] = (ai_real) key.mValue.z;
values[(i * 3) + 0] = (ai_real)key.mValue.x;
values[(i * 3) + 1] = (ai_real)key.mValue.y;
values[(i * 3) + 2] = (ai_real)key.mValue.z;
}
sampler.input = GetSamplerInputRef(asset, animId, buffer, times);
@ -1487,9 +1554,9 @@ inline void ExtractScaleSampler(Asset &asset, std::string &animId, Ref<Buffer> &
const aiVectorKey &key = nodeChannel->mScalingKeys[i];
// mTime is measured in ticks, but GLTF time is measured in seconds, so convert.
times[i] = static_cast<float>(key.mTime / ticksPerSecond);
values[(i * 3) + 0] = (ai_real) key.mValue.x;
values[(i * 3) + 1] = (ai_real) key.mValue.y;
values[(i * 3) + 2] = (ai_real) key.mValue.z;
values[(i * 3) + 0] = (ai_real)key.mValue.x;
values[(i * 3) + 1] = (ai_real)key.mValue.y;
values[(i * 3) + 2] = (ai_real)key.mValue.z;
}
sampler.input = GetSamplerInputRef(asset, animId, buffer, times);
@ -1506,10 +1573,10 @@ inline void ExtractRotationSampler(Asset &asset, std::string &animId, Ref<Buffer
const aiQuatKey &key = nodeChannel->mRotationKeys[i];
// mTime is measured in ticks, but GLTF time is measured in seconds, so convert.
times[i] = static_cast<float>(key.mTime / ticksPerSecond);
values[(i * 4) + 0] = (ai_real) key.mValue.x;
values[(i * 4) + 1] = (ai_real) key.mValue.y;
values[(i * 4) + 2] = (ai_real) key.mValue.z;
values[(i * 4) + 3] = (ai_real) key.mValue.w;
values[(i * 4) + 0] = (ai_real)key.mValue.x;
values[(i * 4) + 1] = (ai_real)key.mValue.y;
values[(i * 4) + 2] = (ai_real)key.mValue.z;
values[(i * 4) + 3] = (ai_real)key.mValue.w;
}
sampler.input = GetSamplerInputRef(asset, animId, buffer, times);

View File

@ -100,8 +100,6 @@ glTF2Importer::glTF2Importer() :
// empty
}
glTF2Importer::~glTF2Importer() = default;
const aiImporterDesc *glTF2Importer::GetInfo() const {
return &desc;
}
@ -114,7 +112,11 @@ bool glTF2Importer::CanRead(const std::string &filename, IOSystem *pIOHandler, b
if (pIOHandler) {
glTF2::Asset asset(pIOHandler);
return asset.CanRead(filename, extension == "glb");
return asset.CanRead(
filename,
CheckMagicToken(
pIOHandler, filename, AI_GLB_MAGIC_NUMBER, 1, 0,
static_cast<unsigned int>(strlen(AI_GLB_MAGIC_NUMBER))));
}
return false;
@ -232,7 +234,8 @@ inline void SetMaterialTextureProperty(std::vector<int> &embeddedTexIdxs, Asset
SetMaterialTextureProperty(embeddedTexIdxs, r, (glTF2::TextureInfo)prop, mat, texType, texSlot);
if (prop.texture && prop.texture->source) {
mat->AddProperty(&prop.strength, 1, AI_MATKEY_GLTF_TEXTURE_STRENGTH(texType, texSlot));
std::string textureStrengthKey = std::string(_AI_MATKEY_TEXTURE_BASE) + "." + "strength";
mat->AddProperty(&prop.strength, 1, textureStrengthKey.c_str(), texType, texSlot);
}
}
@ -443,10 +446,10 @@ static inline bool CheckValidFacesIndices(aiFace *faces, unsigned nFaces, unsign
#endif // ASSIMP_BUILD_DEBUG
template <typename T>
aiColor4D *GetVertexColorsForType(Ref<Accessor> input) {
aiColor4D *GetVertexColorsForType(Ref<Accessor> input, std::vector<unsigned int> *vertexRemappingTable) {
constexpr float max = std::numeric_limits<T>::max();
aiColor4t<T> *colors;
input->ExtractData(colors);
input->ExtractData(colors, vertexRemappingTable);
auto output = new aiColor4D[input->count];
for (size_t i = 0; i < input->count; i++) {
output[i] = aiColor4D(
@ -461,20 +464,26 @@ void glTF2Importer::ImportMeshes(glTF2::Asset &r) {
ASSIMP_LOG_DEBUG("Importing ", r.meshes.Size(), " meshes");
std::vector<std::unique_ptr<aiMesh>> meshes;
unsigned int k = 0;
meshOffsets.clear();
meshOffsets.reserve(r.meshes.Size() + 1);
mVertexRemappingTables.clear();
// Count the number of aiMeshes
unsigned int num_aiMeshes = 0;
for (unsigned int m = 0; m < r.meshes.Size(); ++m) {
meshOffsets.push_back(num_aiMeshes);
num_aiMeshes += unsigned(r.meshes[m].primitives.size());
}
meshOffsets.push_back(num_aiMeshes); // add a last element so we can always do meshOffsets[n+1] - meshOffsets[n]
std::vector<unsigned int> usedVertexIndices;
std::vector<unsigned int> reverseMappingIndices;
std::vector<unsigned int> indexBuffer;
meshes.reserve(num_aiMeshes);
mVertexRemappingTables.resize(num_aiMeshes);
for (unsigned int m = 0; m < r.meshes.Size(); ++m) {
Mesh &mesh = r.meshes[m];
meshOffsets.push_back(k);
k += unsigned(mesh.primitives.size());
for (unsigned int p = 0; p < mesh.primitives.size(); ++p) {
Mesh::Primitive &prim = mesh.primitives[p];
@ -488,14 +497,14 @@ void glTF2Importer::ImportMeshes(glTF2::Asset &r) {
// Extract used vertices:
bool useIndexBuffer = prim.indices;
std::vector<unsigned int>* vertexRemappingTable = nullptr;
std::vector<unsigned int> *vertexRemappingTable = nullptr;
if (useIndexBuffer) {
size_t count = prim.indices->count;
indexBuffer.resize(count);
usedVertexIndices.clear();
reverseMappingIndices.clear();
usedVertexIndices.reserve(count / 3); // this is a very rough heuristic to reduce re-allocations
vertexRemappingTable = &usedVertexIndices;
vertexRemappingTable = &mVertexRemappingTables[meshes.size()];
vertexRemappingTable->reserve(count / 3); // this is a very rough heuristic to reduce re-allocations
Accessor::Indexer data = prim.indices->GetIndexer();
if (!data.IsValid()) {
throw DeadlyImportError("GLTF: Invalid accessor without data in mesh ", getContextForErrorMessages(mesh.id, mesh.name));
@ -515,8 +524,8 @@ void glTF2Importer::ImportMeshes(glTF2::Asset &r) {
reverseMappingIndices.resize(index + 1, unusedIndex);
}
if (reverseMappingIndices[index] == unusedIndex) {
reverseMappingIndices[index] = static_cast<unsigned int>(usedVertexIndices.size());
usedVertexIndices.push_back(index);
reverseMappingIndices[index] = static_cast<unsigned int>(vertexRemappingTable->size());
vertexRemappingTable->push_back(index);
}
indexBuffer[i] = reverseMappingIndices[index];
}
@ -597,9 +606,9 @@ void glTF2Importer::ImportMeshes(glTF2::Asset &r) {
attr.color[c]->ExtractData(aim->mColors[c], vertexRemappingTable);
} else {
if (componentType == glTF2::ComponentType_UNSIGNED_BYTE) {
aim->mColors[c] = GetVertexColorsForType<unsigned char>(attr.color[c]);
aim->mColors[c] = GetVertexColorsForType<unsigned char>(attr.color[c], vertexRemappingTable);
} else if (componentType == glTF2::ComponentType_UNSIGNED_SHORT) {
aim->mColors[c] = GetVertexColorsForType<unsigned short>(attr.color[c]);
aim->mColors[c] = GetVertexColorsForType<unsigned short>(attr.color[c], vertexRemappingTable);
}
}
}
@ -875,8 +884,6 @@ void glTF2Importer::ImportMeshes(glTF2::Asset &r) {
}
}
meshOffsets.push_back(k);
CopyVector(meshes, mScene->mMeshes, mScene->mNumMeshes);
}
@ -1009,7 +1016,8 @@ static void GetNodeTransform(aiMatrix4x4 &matrix, const glTF2::Node &node) {
}
}
static void BuildVertexWeightMapping(Mesh::Primitive &primitive, std::vector<std::vector<aiVertexWeight>> &map) {
static void BuildVertexWeightMapping(Mesh::Primitive &primitive, std::vector<std::vector<aiVertexWeight>> &map, std::vector<unsigned int>* vertexRemappingTablePtr) {
Mesh::Primitive::Attributes &attr = primitive.attributes;
if (attr.weight.empty() || attr.joint.empty()) {
return;
@ -1018,14 +1026,14 @@ static void BuildVertexWeightMapping(Mesh::Primitive &primitive, std::vector<std
return;
}
size_t num_vertices = attr.weight[0]->count;
size_t num_vertices = 0;
struct Weights {
float values[4];
};
Weights **weights = new Weights*[attr.weight.size()];
for (size_t w = 0; w < attr.weight.size(); ++w) {
attr.weight[w]->ExtractData(weights[w]);
num_vertices = attr.weight[w]->ExtractData(weights[w], vertexRemappingTablePtr);
}
struct Indices8 {
@ -1039,12 +1047,12 @@ static void BuildVertexWeightMapping(Mesh::Primitive &primitive, std::vector<std
if (attr.joint[0]->GetElementSize() == 4) {
indices8 = new Indices8*[attr.joint.size()];
for (size_t j = 0; j < attr.joint.size(); ++j) {
attr.joint[j]->ExtractData(indices8[j]);
attr.joint[j]->ExtractData(indices8[j], vertexRemappingTablePtr);
}
} else {
indices16 = new Indices16 *[attr.joint.size()];
for (size_t j = 0; j < attr.joint.size(); ++j) {
attr.joint[j]->ExtractData(indices16[j]);
attr.joint[j]->ExtractData(indices16[j], vertexRemappingTablePtr);
}
}
//
@ -1103,15 +1111,13 @@ void ParseExtensions(aiMetadata *metadata, const CustomExtension &extension) {
}
}
void ParseExtras(aiMetadata *metadata, const CustomExtension &extension) {
if (extension.mValues.isPresent) {
for (auto const &subExtension : extension.mValues.value) {
ParseExtensions(metadata, subExtension);
}
void ParseExtras(aiMetadata* metadata, const Extras& extras) {
for (auto const &value : extras.mValues) {
ParseExtensions(metadata, value);
}
}
aiNode *ImportNode(aiScene *pScene, glTF2::Asset &r, std::vector<unsigned int> &meshOffsets, glTF2::Ref<glTF2::Node> &ptr) {
aiNode *glTF2Importer::ImportNode(glTF2::Asset &r, glTF2::Ref<glTF2::Node> &ptr) {
Node &node = *ptr;
aiNode *ainode = new aiNode(GetNodeName(node));
@ -1123,18 +1129,18 @@ aiNode *ImportNode(aiScene *pScene, glTF2::Asset &r, std::vector<unsigned int> &
std::fill(ainode->mChildren, ainode->mChildren + ainode->mNumChildren, nullptr);
for (unsigned int i = 0; i < ainode->mNumChildren; ++i) {
aiNode *child = ImportNode(pScene, r, meshOffsets, node.children[i]);
aiNode *child = ImportNode(r, node.children[i]);
child->mParent = ainode;
ainode->mChildren[i] = child;
}
}
if (node.customExtensions || node.extras) {
if (node.customExtensions || node.extras.HasExtras()) {
ainode->mMetaData = new aiMetadata;
if (node.customExtensions) {
ParseExtensions(ainode->mMetaData, node.customExtensions);
}
if (node.extras) {
if (node.extras.HasExtras()) {
ParseExtras(ainode->mMetaData, node.extras);
}
}
@ -1156,11 +1162,13 @@ aiNode *ImportNode(aiScene *pScene, glTF2::Asset &r, std::vector<unsigned int> &
if (node.skin) {
for (int primitiveNo = 0; primitiveNo < count; ++primitiveNo) {
aiMesh *mesh = pScene->mMeshes[meshOffsets[mesh_idx] + primitiveNo];
unsigned int aiMeshIdx = meshOffsets[mesh_idx] + primitiveNo;
aiMesh *mesh = mScene->mMeshes[aiMeshIdx];
unsigned int numBones = static_cast<unsigned int>(node.skin->jointNames.size());
std::vector<unsigned int> *vertexRemappingTablePtr = mVertexRemappingTables[aiMeshIdx].empty() ? nullptr : &mVertexRemappingTables[aiMeshIdx];
std::vector<std::vector<aiVertexWeight>> weighting(numBones);
BuildVertexWeightMapping(node.meshes[0]->primitives[primitiveNo], weighting);
BuildVertexWeightMapping(node.meshes[0]->primitives[primitiveNo], weighting, vertexRemappingTablePtr);
mesh->mNumBones = static_cast<unsigned int>(numBones);
mesh->mBones = new aiBone *[mesh->mNumBones];
@ -1177,7 +1185,7 @@ aiNode *ImportNode(aiScene *pScene, glTF2::Asset &r, std::vector<unsigned int> &
// mapping which makes things doubly-slow.
mat4 *pbindMatrices = nullptr;
node.skin->inverseBindMatrices->ExtractData(pbindMatrices);
node.skin->inverseBindMatrices->ExtractData(pbindMatrices, nullptr);
for (uint32_t i = 0; i < numBones; ++i) {
const std::vector<aiVertexWeight> &weights = weighting[i];
@ -1223,11 +1231,11 @@ aiNode *ImportNode(aiScene *pScene, glTF2::Asset &r, std::vector<unsigned int> &
}
if (node.camera) {
pScene->mCameras[node.camera.GetIndex()]->mName = ainode->mName;
mScene->mCameras[node.camera.GetIndex()]->mName = ainode->mName;
}
if (node.light) {
pScene->mLights[node.light.GetIndex()]->mName = ainode->mName;
mScene->mLights[node.light.GetIndex()]->mName = ainode->mName;
// range is optional - see https://github.com/KhronosGroup/glTF/tree/master/extensions/2.0/Khronos/KHR_lights_punctual
// it is added to meta data of parent node, because there is no other place to put it
@ -1259,7 +1267,7 @@ void glTF2Importer::ImportNodes(glTF2::Asset &r) {
// The root nodes
unsigned int numRootNodes = unsigned(rootNodes.size());
if (numRootNodes == 1) { // a single root node: use it
mScene->mRootNode = ImportNode(mScene, r, meshOffsets, rootNodes[0]);
mScene->mRootNode = ImportNode(r, rootNodes[0]);
} else if (numRootNodes > 1) { // more than one root node: create a fake root
aiNode *root = mScene->mRootNode = new aiNode("ROOT");
@ -1267,7 +1275,7 @@ void glTF2Importer::ImportNodes(glTF2::Asset &r) {
std::fill(root->mChildren, root->mChildren + numRootNodes, nullptr);
for (unsigned int i = 0; i < numRootNodes; ++i) {
aiNode *node = ImportNode(mScene, r, meshOffsets, rootNodes[i]);
aiNode *node = ImportNode(r, rootNodes[i]);
node->mParent = root;
root->mChildren[root->mNumChildren++] = node;
}
@ -1668,13 +1676,17 @@ void glTF2Importer::InternReadFile(const std::string &pFile, aiScene *pScene, IO
// clean all member arrays
meshOffsets.clear();
mVertexRemappingTables.clear();
mEmbeddedTexIdxs.clear();
this->mScene = pScene;
// read the asset file
glTF2::Asset asset(pIOHandler, static_cast<rapidjson::IRemoteSchemaDocumentProvider *>(mSchemaDocumentProvider));
asset.Load(pFile, GetExtension(pFile) == "glb");
asset.Load(pFile,
CheckMagicToken(
pIOHandler, pFile, AI_GLB_MAGIC_NUMBER, 1, 0,
static_cast<unsigned int>(strlen(AI_GLB_MAGIC_NUMBER))));
if (asset.scene) {
pScene->mName = asset.scene->name;
}

View File

@ -43,6 +43,7 @@ OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
#define AI_GLTF2IMPORTER_H_INC
#include <assimp/BaseImporter.h>
#include <AssetLib/glTF2/glTF2Asset.h>
struct aiNode;
@ -59,7 +60,7 @@ namespace Assimp {
class glTF2Importer : public BaseImporter {
public:
glTF2Importer();
~glTF2Importer() override;
~glTF2Importer() override = default;
bool CanRead(const std::string &pFile, IOSystem *pIOHandler, bool checkSig) const override;
protected:
@ -76,10 +77,12 @@ private:
void ImportNodes(glTF2::Asset &a);
void ImportAnimations(glTF2::Asset &a);
void ImportCommonMetadata(glTF2::Asset &a);
aiNode *ImportNode(glTF2::Asset &r, glTF2::Ref<glTF2::Node> &ptr);
private:
std::vector<unsigned int> meshOffsets;
std::vector<int> mEmbeddedTexIdxs;
std::vector<std::vector<unsigned int>> mVertexRemappingTables; // for each converted aiMesh in the scene, it stores a list of vertices that are actually used
aiScene *mScene;
/// An instance of rapidjson::IRemoteSchemaDocumentProvider

View File

@ -965,7 +965,6 @@ IF(ASSIMP_HUNTER_ENABLED)
find_package(minizip CONFIG REQUIRED)
ELSE()
SET( unzip_SRCS
../contrib/unzip/crypt.c
../contrib/unzip/crypt.h
../contrib/unzip/ioapi.c
../contrib/unzip/ioapi.h
@ -1200,7 +1199,6 @@ IF (ASSIMP_WARNINGS_AS_ERRORS)
IF(CMAKE_CXX_COMPILER_ID MATCHES "Clang" ) # clang-cl
TARGET_COMPILE_OPTIONS(assimp PRIVATE -Wall -Werror
-Wno-unused-function
-Wno-microsoft-enum-value
-Wno-switch-enum
-Wno-covered-switch-default
@ -1420,25 +1418,29 @@ if(MSVC AND ASSIMP_INSTALL_PDB)
COMPILE_PDB_NAME assimp${LIBRARY_SUFFIX}
COMPILE_PDB_NAME_DEBUG assimp${LIBRARY_SUFFIX}${CMAKE_DEBUG_POSTFIX}
)
ENDIF()
IF(CMAKE_GENERATOR MATCHES "^Visual Studio")
install(FILES ${Assimp_BINARY_DIR}/code/Debug/assimp${LIBRARY_SUFFIX}${CMAKE_DEBUG_POSTFIX}.pdb
DESTINATION ${ASSIMP_LIB_INSTALL_DIR}
CONFIGURATIONS Debug
)
install(FILES ${Assimp_BINARY_DIR}/code/RelWithDebInfo/assimp${LIBRARY_SUFFIX}.pdb
DESTINATION ${ASSIMP_LIB_INSTALL_DIR}
CONFIGURATIONS RelWithDebInfo
)
IF(GENERATOR_IS_MULTI_CONFIG)
install(FILES ${Assimp_BINARY_DIR}/code/Debug/assimp${LIBRARY_SUFFIX}${CMAKE_DEBUG_POSTFIX}.pdb
DESTINATION ${ASSIMP_LIB_INSTALL_DIR}
CONFIGURATIONS Debug
)
install(FILES ${Assimp_BINARY_DIR}/code/RelWithDebInfo/assimp${LIBRARY_SUFFIX}.pdb
DESTINATION ${ASSIMP_LIB_INSTALL_DIR}
CONFIGURATIONS RelWithDebInfo
)
ELSE()
install(FILES ${Assimp_BINARY_DIR}/code/assimp${LIBRARY_SUFFIX}${CMAKE_DEBUG_POSTFIX}.pdb
DESTINATION ${ASSIMP_LIB_INSTALL_DIR}
CONFIGURATIONS Debug
)
install(FILES ${Assimp_BINARY_DIR}/code/assimp${LIBRARY_SUFFIX}.pdb
DESTINATION ${ASSIMP_LIB_INSTALL_DIR}
CONFIGURATIONS RelWithDebInfo
)
ENDIF()
ELSE()
install(FILES ${Assimp_BINARY_DIR}/code/assimp${LIBRARY_SUFFIX}${CMAKE_DEBUG_POSTFIX}.pdb
install(FILES $<TARGET_PDB_FILE:assimp>
DESTINATION ${ASSIMP_LIB_INSTALL_DIR}
CONFIGURATIONS Debug
)
install(FILES ${Assimp_BINARY_DIR}/code/assimp${LIBRARY_SUFFIX}.pdb
DESTINATION ${ASSIMP_LIB_INSTALL_DIR}
CONFIGURATIONS RelWithDebInfo
)
ENDIF()
ENDIF ()

View File

@ -59,6 +59,31 @@ OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
#include <memory>
#include <sstream>
namespace {
// Checks whether the passed string is a gcs version.
bool IsGcsVersion(const std::string &s) {
if (s.empty()) return false;
return std::all_of(s.cbegin(), s.cend(), [](const char c) {
// gcs only permits numeric characters.
return std::isdigit(static_cast<int>(c));
});
}
// Removes a possible version hash from a filename, as found for example in
// gcs uris (e.g. `gs://bucket/model.glb#1234`), see also
// https://github.com/GoogleCloudPlatform/gsutil/blob/c80f329bc3c4011236c78ce8910988773b2606cb/gslib/storage_url.py#L39.
std::string StripVersionHash(const std::string &filename) {
const std::string::size_type pos = filename.find_last_of('#');
// Only strip if the hash is behind a possible file extension and the part
// behind the hash is a version string.
if (pos != std::string::npos && pos > filename.find_last_of('.') &&
IsGcsVersion(filename.substr(pos + 1))) {
return filename.substr(0, pos);
}
return filename;
}
} // namespace
using namespace Assimp;
// ------------------------------------------------------------------------------------------------
@ -158,7 +183,7 @@ void BaseImporter::GetExtensionList(std::set<std::string> &extensions) {
std::size_t numTokens,
unsigned int searchBytes /* = 200 */,
bool tokensSol /* false */,
bool noAlphaBeforeTokens /* false */) {
bool noGraphBeforeTokens /* false */) {
ai_assert(nullptr != tokens);
ai_assert(0 != numTokens);
ai_assert(0 != searchBytes);
@ -207,8 +232,9 @@ void BaseImporter::GetExtensionList(std::set<std::string> &extensions) {
continue;
}
// We need to make sure that we didn't accidentally identify the end of another token as our token,
// e.g. in a previous version the "gltf " present in some gltf files was detected as "f "
if (noAlphaBeforeTokens && (r != buffer && isalpha(static_cast<unsigned char>(r[-1])))) {
// e.g. in a previous version the "gltf " present in some gltf files was detected as "f ", or a
// Blender-exported glb file containing "Khronos glTF Blender I/O " was detected as "o "
if (noGraphBeforeTokens && (r != buffer && isgraph(static_cast<unsigned char>(r[-1])))) {
continue;
}
// We got a match, either we don't care where it is, or it happens to
@ -229,33 +255,38 @@ void BaseImporter::GetExtensionList(std::set<std::string> &extensions) {
const char *ext0,
const char *ext1,
const char *ext2) {
std::string::size_type pos = pFile.find_last_of('.');
// no file extension - can't read
if (pos == std::string::npos) {
return false;
std::set<std::string> extensions;
for (const char* ext : {ext0, ext1, ext2}) {
if (ext == nullptr) continue;
extensions.emplace(ext);
}
return HasExtension(pFile, extensions);
}
const char *ext_real = &pFile[pos + 1];
if (!ASSIMP_stricmp(ext_real, ext0)) {
return true;
// ------------------------------------------------------------------------------------------------
// Check for file extension
/*static*/ bool BaseImporter::HasExtension(const std::string &pFile, const std::set<std::string> &extensions) {
const std::string file = StripVersionHash(pFile);
// CAUTION: Do not just search for the extension!
// GetExtension() returns the part after the *last* dot, but some extensions
// have dots inside them, e.g. ogre.mesh.xml. Compare the entire end of the
// string.
for (const std::string& ext : extensions) {
// Yay for C++<20 not having std::string::ends_with()
const std::string dotExt = "." + ext;
if (dotExt.length() > file.length()) continue;
// Possible optimization: Fetch the lowercase filename!
if (0 == ASSIMP_stricmp(file.c_str() + file.length() - dotExt.length(), dotExt.c_str())) {
return true;
}
}
// check for other, optional, file extensions
if (ext1 && !ASSIMP_stricmp(ext_real, ext1)) {
return true;
}
if (ext2 && !ASSIMP_stricmp(ext_real, ext2)) {
return true;
}
return false;
}
// ------------------------------------------------------------------------------------------------
// Get file extension from path
std::string BaseImporter::GetExtension(const std::string &file) {
std::string BaseImporter::GetExtension(const std::string &pFile) {
const std::string file = StripVersionHash(pFile);
std::string::size_type pos = file.find_last_of('.');
// no file extension at all
@ -281,12 +312,7 @@ std::string BaseImporter::GetExtension(const std::string &file) {
if (!pIOHandler) {
return false;
}
union {
const char *magic;
const uint16_t *magic_u16;
const uint32_t *magic_u32;
};
magic = reinterpret_cast<const char *>(_magic);
const char *magic = reinterpret_cast<const char *>(_magic);
std::unique_ptr<IOStream> pStream(pIOHandler->Open(pFile));
if (pStream) {
@ -308,15 +334,15 @@ std::string BaseImporter::GetExtension(const std::string &file) {
// that's just for convenience, the chance that we cause conflicts
// is quite low and it can save some lines and prevent nasty bugs
if (2 == size) {
uint16_t rev = *magic_u16;
ByteSwap::Swap(&rev);
if (data_u16[0] == *magic_u16 || data_u16[0] == rev) {
uint16_t magic_u16;
memcpy(&magic_u16, magic, 2);
if (data_u16[0] == magic_u16 || data_u16[0] == ByteSwap::Swapped(magic_u16)) {
return true;
}
} else if (4 == size) {
uint32_t rev = *magic_u32;
ByteSwap::Swap(&rev);
if (data_u32[0] == *magic_u32 || data_u32[0] == rev) {
uint32_t magic_u32;
memcpy(&magic_u32, magic, 4);
if (data_u32[0] == magic_u32 || data_u32[0] == ByteSwap::Swapped(magic_u32)) {
return true;
}
} else {

View File

@ -225,7 +225,7 @@ static void setupExporterArray(std::vector<Exporter::ExportFormatEntry> &exporte
#endif
#ifndef ASSIMP_BUILD_NO_PBRT_EXPORTER
exporters.emplace_back("pbrt", "pbrt-v4 scene description file", "pbrt", &ExportScenePbrt, aiProcess_Triangulate | aiProcess_SortByPType);
exporters.emplace_back("pbrt", "pbrt-v4 scene description file", "pbrt", &ExportScenePbrt, aiProcess_ConvertToLeftHanded | aiProcess_Triangulate | aiProcess_SortByPType);
#endif
#ifndef ASSIMP_BUILD_NO_ASSJSON_EXPORTER

View File

@ -297,7 +297,7 @@ private:
}
const char separator = getOsSeparator();
for (it = in.begin(); it != in.end(); ++it) {
for (it = in.begin(); it < in.end(); ++it) {
const size_t remaining = std::distance(in.end(), it);
// Exclude :// and \\, which remain untouched.
// https://sourceforge.net/tracker/?func=detail&aid=3031725&group_id=226462&atid=1067632

View File

@ -637,24 +637,10 @@ const aiScene* Importer::ReadFile( const char* _pFile, unsigned int pFlags) {
std::set<std::string> extensions;
pimpl->mImporter[a]->GetExtensionList(extensions);
// CAUTION: Do not just search for the extension!
// GetExtension() returns the part after the *last* dot, but some extensions have dots
// inside them, e.g. ogre.mesh.xml. Compare the entire end of the string.
for (std::set<std::string>::const_iterator it = extensions.cbegin(); it != extensions.cend(); ++it) {
// Yay for C++<20 not having std::string::ends_with()
std::string extension = "." + *it;
if (extension.length() <= pFile.length()) {
// Possible optimization: Fetch the lowercase filename!
if (0 == ASSIMP_stricmp(pFile.c_str() + pFile.length() - extension.length(), extension.c_str())) {
ImporterAndIndex candidate = { pimpl->mImporter[a], a };
possibleImporters.push_back(candidate);
break;
}
}
if (BaseImporter::HasExtension(pFile, extensions)) {
ImporterAndIndex candidate = { pimpl->mImporter[a], a };
possibleImporters.push_back(candidate);
}
}
// If just one importer supports this extension, pick it and close the case.

View File

@ -64,8 +64,14 @@ inline double GetArea2D(const T& v1, const T& v2, const T& v3) {
* The function accepts an unconstrained template parameter for use with
* both aiVector3D and aiVector2D, but generally ignores the third coordinate.*/
template <typename T>
inline bool OnLeftSideOfLine2D(const T& p0, const T& p1,const T& p2) {
return GetArea2D(p0,p2,p1) > 0;
inline int OnLeftSideOfLine2D(const T& p0, const T& p1,const T& p2) {
double area = GetArea2D(p0,p2,p1);
if(std::abs(area) < ai_epsilon)
return 0;
else if(area > 0)
return 1;
else
return -1;
}
// -------------------------------------------------------------------------------
@ -75,7 +81,10 @@ inline bool OnLeftSideOfLine2D(const T& p0, const T& p1,const T& p2) {
template <typename T>
inline bool PointInTriangle2D(const T& p0, const T& p1,const T& p2, const T& pp) {
// pp should be left side of the three triangle side, by ccw arrow
return OnLeftSideOfLine2D(p0, p1, pp) && OnLeftSideOfLine2D(p1, p2, pp) && OnLeftSideOfLine2D(p2, p0, pp);
int c1 = OnLeftSideOfLine2D(p0, p1, pp);
int c2 = OnLeftSideOfLine2D(p1, p2, pp);
int c3 = OnLeftSideOfLine2D(p2, p0, pp);
return (c1 >= 0) && (c2 >= 0) && (c3 >= 0);
}
@ -110,7 +119,7 @@ inline bool IsCCW(T* in, size_t npoints) {
c = std::sqrt(cc);
theta = std::acos((bb + cc - aa) / (2 * b * c));
if (OnLeftSideOfLine2D(in[i],in[i+2],in[i+1])) {
if (OnLeftSideOfLine2D(in[i],in[i+2],in[i+1]) == 1) {
// if (convex(in[i].x, in[i].y,
// in[i+1].x, in[i+1].y,
// in[i+2].x, in[i+2].y)) {
@ -140,7 +149,7 @@ inline bool IsCCW(T* in, size_t npoints) {
//if (convex(in[npoints-2].x, in[npoints-2].y,
// in[0].x, in[0].y,
// in[1].x, in[1].y)) {
if (OnLeftSideOfLine2D(in[npoints-2],in[1],in[0])) {
if (OnLeftSideOfLine2D(in[npoints-2],in[1],in[0]) == 1) {
convex_turn = AI_MATH_PI_F - theta;
convex_sum += convex_turn;
} else {

View File

@ -48,6 +48,11 @@ OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
#pragma GCC diagnostic ignored "-Wunused-function"
#endif
#if defined(__clang__)
#pragma clang diagnostic push
#pragma clang diagnostic ignored "-Wunused-function"
#endif
#ifndef STB_USE_HUNTER
/* Use prefixed names for the symbols from stb_image as it is a very commonly embedded library.
Including vanilla stb_image symbols causes duplicate symbol problems if assimp is linked
@ -114,3 +119,6 @@ OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
#pragma GCC diagnostic pop
#endif
#if defined(__clang__)
#pragma clang diagnostic pop
#endif

View File

@ -51,6 +51,7 @@ OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
#include <assimp/material.h>
#include <assimp/types.h>
#include <assimp/DefaultLogger.hpp>
#include <memory>
using namespace Assimp;
@ -473,7 +474,7 @@ aiReturn aiMaterial::AddBinaryProperty(const void *pInput,
}
// Allocate a new material property
aiMaterialProperty *pcNew = new aiMaterialProperty();
std::unique_ptr<aiMaterialProperty> pcNew(new aiMaterialProperty());
// .. and fill it
pcNew->mType = pType;
@ -489,7 +490,7 @@ aiReturn aiMaterial::AddBinaryProperty(const void *pInput,
strcpy(pcNew->mKey.data, pKey);
if (UINT_MAX != iOutIndex) {
mProperties[iOutIndex] = pcNew;
mProperties[iOutIndex] = pcNew.release();
return AI_SUCCESS;
}
@ -502,7 +503,6 @@ aiReturn aiMaterial::AddBinaryProperty(const void *pInput,
try {
ppTemp = new aiMaterialProperty *[mNumAllocated];
} catch (std::bad_alloc &) {
delete pcNew;
return AI_OUTOFMEMORY;
}
@ -513,7 +513,7 @@ aiReturn aiMaterial::AddBinaryProperty(const void *pInput,
mProperties = ppTemp;
}
// push back ...
mProperties[mNumProperties++] = pcNew;
mProperties[mNumProperties++] = pcNew.release();
return AI_SUCCESS;
}

View File

@ -111,7 +111,22 @@ PbrtExporter::PbrtExporter(
mScene(pScene),
mIOSystem(pIOSystem),
mPath(path),
mFile(file) {
mFile(file),
mRootTransform(
// rotates the (already left-handed) CRS -90 degrees around the x axis in order to
// make +Z 'up' and +Y 'towards viewer', as in default in pbrt
1.f, 0.f, 0.f, 0.f, //
0.f, 0.f, -1.f, 0.f, //
0.f, 1.f, 0.f, 0.f, //
0.f, 0.f, 0.f, 1.f //
) {
mRootTransform = aiMatrix4x4(
-1.f, 0, 0.f, 0.f, //
0.0f, -1.f, 0.f, 0.f, //
0.f, 0.f, 1.f, 0.f, //
0.f, 0.f, 0.f, 1.f //
) * mRootTransform;
// Export embedded textures.
if (mScene->mNumTextures > 0)
if (!mIOSystem->CreateDirectory("textures"))
@ -260,7 +275,7 @@ aiMatrix4x4 PbrtExporter::GetNodeTransform(const aiString &name) const {
node = node->mParent;
}
}
return m;
return mRootTransform * m;
}
std::string PbrtExporter::TransformAsString(const aiMatrix4x4 &m) {
@ -309,7 +324,7 @@ void PbrtExporter::WriteCamera(int i) {
// Get camera fov
float hfov = AI_RAD_TO_DEG(camera->mHorizontalFOV);
float fov = (aspect >= 1.0) ? hfov : (hfov * aspect);
float fov = (aspect >= 1.0) ? hfov : (hfov / aspect);
if (fov < 5) {
std::cerr << fov << ": suspiciously low field of view specified by camera. Setting to 45 degrees.\n";
fov = 45;
@ -327,7 +342,7 @@ void PbrtExporter::WriteCamera(int i) {
if (!cameraActive)
mOutput << "# ";
mOutput << "Scale -1 1 1\n"; // right handed -> left handed
mOutput << "Scale 1 1 1\n";
if (!cameraActive)
mOutput << "# ";
mOutput << "LookAt "
@ -383,8 +398,8 @@ void PbrtExporter::WriteWorldDefinition() {
}
mOutput << "# Geometry\n\n";
aiMatrix4x4 worldFromObject;
WriteGeometricObjects(mScene->mRootNode, worldFromObject, meshUses);
WriteGeometricObjects(mScene->mRootNode, mRootTransform, meshUses);
}
void PbrtExporter::WriteTextures() {

View File

@ -100,6 +100,9 @@ private:
// A private set to keep track of which textures have been declared
std::set<std::string> mTextureSet;
// Transform to apply to the root node and all root objects such as cameras, lights, etc.
aiMatrix4x4 mRootTransform;
aiMatrix4x4 GetNodeTransform(const aiString& name) const;
static std::string TransformAsString(const aiMatrix4x4& m);

View File

@ -82,6 +82,9 @@ void UpdateMeshReferences(aiNode *node, const std::vector<unsigned int> &meshMap
for (unsigned int a = 0; a < node->mNumMeshes; ++a) {
unsigned int ref = node->mMeshes[a];
if (ref >= meshMapping.size())
throw DeadlyImportError("Invalid mesh ref");
if (UINT_MAX != (ref = meshMapping[ref])) {
node->mMeshes[out++] = ref;
}
@ -143,7 +146,13 @@ void FindInvalidDataProcess::Execute(aiScene *pScene) {
// we need to remove some meshes.
// therefore we'll also need to remove all references
// to them from the scenegraph
UpdateMeshReferences(pScene->mRootNode, meshMapping);
try {
UpdateMeshReferences(pScene->mRootNode, meshMapping);
} catch (const std::exception&) {
// fix the real number of meshes otherwise we'll get double free in the scene destructor
pScene->mNumMeshes = real;
throw;
}
pScene->mNumMeshes = real;
}

View File

@ -81,6 +81,7 @@ void LimitBoneWeightsProcess::Execute( aiScene* pScene) {
// Executes the post processing step on the given imported data.
void LimitBoneWeightsProcess::SetupProperties(const Importer* pImp) {
this->mMaxWeights = pImp->GetPropertyInteger(AI_CONFIG_PP_LBW_MAX_WEIGHTS,AI_LMW_MAX_WEIGHTS);
this->mRemoveEmptyBones = pImp->GetPropertyInteger(AI_CONFIG_IMPORT_REMOVE_EMPTY_BONES, 1) != 0;
}
// ------------------------------------------------------------------------------------------------
@ -172,9 +173,9 @@ void LimitBoneWeightsProcess::ProcessMesh(aiMesh* pMesh) {
}
// remove empty bones
#ifdef AI_CONFIG_IMPORT_REMOVE_EMPTY_BONES
pMesh->mNumBones = removeEmptyBones(pMesh);
#endif // AI_CONFIG_IMPORT_REMOVE_EMPTY_BONES
if (mRemoveEmptyBones) {
pMesh->mNumBones = removeEmptyBones(pMesh);
}
if (!DefaultLogger::isNullLogger()) {
ASSIMP_LOG_INFO("Removed ", removed, " weights. Input bones: ", old_bones, ". Output bones: ", pMesh->mNumBones);

View File

@ -133,6 +133,7 @@ public:
/** Maximum number of bones influencing any single vertex. */
unsigned int mMaxWeights;
bool mRemoveEmptyBones;
};
} // end of namespace Assimp

View File

@ -451,7 +451,7 @@ bool TriangulateProcess::TriangulateMesh( aiMesh* pMesh) {
*pnt2 = &temp_verts[next];
// Must be a convex point. Assuming ccw winding, it must be on the right of the line between p-1 and p+1.
if (OnLeftSideOfLine2D(*pnt0,*pnt2,*pnt1)) {
if (OnLeftSideOfLine2D(*pnt0,*pnt2,*pnt1) == 1) {
continue;
}

View File

@ -15,9 +15,11 @@ option( DDL_STATIC_LIBRARY "Deprecated, use BUILD_SHARED_LIBS instead."
# for backwards compatibility use DDL_STATIC_LIBRARY as initial value for cmake variable BUILD_SHARED_LIBS
# https://cmake.org/cmake/help/latest/variable/BUILD_SHARED_LIBS.html
if ( DDL_STATIC_LIBRARY )
set ( build_shared_libs_default OFF )
message("Building shared lib.")
set ( build_shared_libs_default OFF )
else()
set ( build_shared_libs_default ON )
message("Building static lib.")
set ( build_shared_libs_default ON )
endif()
option( DDL_BUILD_SHARED_LIBS "Set to ON to build shared libary of OpenDDL Parser." ${build_shared_libs_default} )
option( COVERALLS "Generate coveralls data" OFF )
@ -36,6 +38,7 @@ endif()
add_definitions( -D_VARIADIC_MAX=10 )
add_definitions( -DGTEST_HAS_PTHREAD=0 )
if ( DDL_DEBUG_OUTPUT )
message("Enable debug output.")
add_definitions( -DDDL_DEBUG_HEADER_NAME)
endif()
@ -62,10 +65,12 @@ if (COVERALLS)
include(Coveralls)
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -g -O0 -fprofile-arcs -ftest-coverage")
set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -g -O0 -fprofile-arcs -ftest-coverage")
message("Enable coveralls.")
endif()
# Include the doc component.
if(DDL_DOCUMENTATION)
message("Generate doxygen documentation.")
find_package(Doxygen REQUIRED)
CONFIGURE_FILE( doc/openddlparser_doc.in doc/doxygenfile @ONLY )
add_custom_target(doc ALL

View File

@ -5,13 +5,15 @@ The OpenDDL-Parser is a small and easy to use library for OpenDDL-file-format-pa
Build status
============
Linux build status: [![Build Status](https://travis-ci.org/kimkulling/openddl-parser.png)](https://travis-ci.org/kimkulling/openddl-parser)
Linux build status: [![Build Status](https://travis-ci.com/kimkulling/openddl-parser.svg?branch=master)](https://travis-ci.com/kimkulling/openddl-parser)
Current coverity check status:
<a href="https://scan.coverity.com/projects/5606">
<img alt="Coverity Scan Build Status"
src="https://scan.coverity.com/projects/5606/badge.svg"/>
</a>
Current test coverage:[![Coverage Status](https://coveralls.io/repos/github/kimkulling/openddl-parser/badge.svg?branch=master)](https://coveralls.io/github/kimkulling/openddl-parser?branch=cpp_coveralls)
Get the source code
===================
You can get the code from our git repository, which is located at GitHub. You can clone the repository with the following command:
@ -57,11 +59,11 @@ USE_ODDLPARSER_NS;
int main( int argc, char *argv[] ) {
if( argc < 3 ) {
return 1;
return Error;
}
char *filename( nullptr );
if( 0 == strncmp( FileOption, argv[ 1 ], strlen( FileOption ) ) ) {
if( 0 == strncmp( FileOption, argv[1], strlen( FileOption ) ) ) {
filename = argv[ 2 ];
}
std::cout << "file to import: " << filename << std::endl;
@ -73,24 +75,27 @@ int main( int argc, char *argv[] ) {
FILE *fileStream = fopen( filename, "r+" );
if( NULL == filename ) {
std::cerr << "Cannot open file " << filename << std::endl;
return 1;
return Error;
}
// obtain file size:
fseek( fileStream, 0, SEEK_END );
const size_t size( ftell( fileStream ) );
const size_t size = ftell( fileStream );
rewind( fileStream );
if( size > 0 ) {
char *buffer = new char[ size ];
const size_t readSize( fread( buffer, sizeof( char ), size, fileStream ) );
const size_t readSize = fread( buffer, sizeof( char ), size, fileStream );
assert( readSize == size );
// Set the memory buffer
OpenDDLParser theParser;
theParser.setBuffer( buffer, size );
const bool result( theParser.parse() );
if( !result ) {
if( !theParser.parse() ) {
std::cerr << "Error while parsing file " << filename << "." << std::endl;
return Error;
}
}
return 0;
}
@ -106,9 +111,9 @@ theParser.setBuffer( buffer, size );
const bool result( theParser.parse() );
if ( result ) {
DDLNode *root = theParser.getRoot();
DDLNode::DllNodeList childs = root->getChildNodeList();
for ( size_t i=0; i<childs.size(); i++ ) {
DDLNode *child = childs[ i ];
DDLNode::DllNodeList children = root->getChildNodeList();
for ( size_t i=0; i<children.size(); i++ ) {
DDLNode *child = children[ i ];
Property *prop = child->getProperty(); // to get properties
std::string type = child->getType(); // to get the node type
Value *values = child->getValue(); // to get the data;

View File

@ -134,9 +134,10 @@ bool OpenDDLExport::writeToStream(const std::string &statement) {
}
bool OpenDDLExport::writeNode(DDLNode *node, std::string &statement) {
bool success(true);
writeNodeHeader(node, statement);
if (node->hasProperties()) {
writeProperties(node, statement);
success = writeProperties(node, statement);
}
writeLineEnd(statement);
@ -160,7 +161,7 @@ bool OpenDDLExport::writeNode(DDLNode *node, std::string &statement) {
writeToStream(statement);
return true;
return success;
}
bool OpenDDLExport::writeNodeHeader(DDLNode *node, std::string &statement) {

View File

@ -30,7 +30,10 @@ CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
#include <sstream>
#ifdef _WIN32
#include <windows.h>
# ifndef WIN32_LEAN_AND_MEAN
# define WIN32_LEAN_AND_MEAN
# endif
# include <windows.h>
#endif // _WIN32
BEGIN_ODDLPARSER_NS
@ -71,7 +74,7 @@ const char *getTypeToken(Value::ValueType type) {
return Grammar::PrimitiveTypeToken[(size_t)type];
}
static void logInvalidTokenError(char *in, const std::string &exp, OpenDDLParser::logCallback callback) {
static void logInvalidTokenError(const char *in, const std::string &exp, OpenDDLParser::logCallback callback) {
if (callback) {
std::string full(in);
std::string part(full.substr(0, 50));
@ -338,20 +341,25 @@ char *OpenDDLParser::parseStructure(char *in, char *end) {
bool error(false);
in = lookForNextToken(in, end);
if (*in == *Grammar::OpenBracketToken) {
// loop over all children ( data and nodes )
do {
in = parseStructureBody(in, end, error);
if (in == nullptr) {
return nullptr;
if (in != end) {
if (*in == *Grammar::OpenBracketToken) {
// loop over all children ( data and nodes )
do {
in = parseStructureBody(in, end, error);
if (in == nullptr) {
return nullptr;
}
} while (in != end &&
*in != *Grammar::CloseBracketToken);
if (in != end) {
++in;
}
} while (*in != *Grammar::CloseBracketToken);
++in;
} else {
++in;
logInvalidTokenError(in, std::string(Grammar::OpenBracketToken), m_logCallback);
error = true;
return nullptr;
} else {
++in;
logInvalidTokenError(in, std::string(Grammar::OpenBracketToken), m_logCallback);
error = true;
return nullptr;
}
}
in = lookForNextToken(in, end);
@ -418,8 +426,8 @@ char *OpenDDLParser::parseStructureBody(char *in, char *end, bool &error) {
}
in = lookForNextToken(in, end);
if (*in != '}') {
logInvalidTokenError(in, std::string(Grammar::CloseBracketToken), m_logCallback);
if (in == end || *in != '}') {
logInvalidTokenError(in == end ? "" : in, std::string(Grammar::CloseBracketToken), m_logCallback);
return nullptr;
} else {
//in++;
@ -455,7 +463,7 @@ DDLNode *OpenDDLParser::top() {
return nullptr;
}
DDLNode *top(m_stack.back());
DDLNode *top = m_stack.back();
return top;
}
@ -647,12 +655,15 @@ char *OpenDDLParser::parseBooleanLiteral(char *in, char *end, Value **boolean) {
in = lookForNextToken(in, end);
char *start(in);
size_t len(0);
while (!isSeparator(*in) && in != end) {
++in;
++len;
}
int res = ::strncmp(Grammar::BoolTrue, start, strlen(Grammar::BoolTrue));
int res = ::strncmp(Grammar::BoolTrue, start, len);
if (0 != res) {
res = ::strncmp(Grammar::BoolFalse, start, strlen(Grammar::BoolFalse));
res = ::strncmp(Grammar::BoolFalse, start, len);
if (0 != res) {
*boolean = nullptr;
return in;
@ -733,7 +744,7 @@ char *OpenDDLParser::parseFloatingLiteral(char *in, char *end, Value **floating,
in = lookForNextToken(in, end);
char *start(in);
while (!isSeparator(*in) && in != end) {
while (in != end && !isSeparator(*in)) {
++in;
}
@ -838,6 +849,13 @@ char *OpenDDLParser::parseHexaLiteral(char *in, char *end, Value **data) {
int value(0);
while (pos > 0) {
int v = hex2Decimal(*start);
if (v < 0) {
while (isEndofLine(*in)) {
++in;
}
return in;
}
--pos;
value = (value << 4) | v;
++start;
@ -901,10 +919,10 @@ char *OpenDDLParser::parseDataList(char *in, char *end, Value::ValueType type, V
}
in = lookForNextToken(in, end);
if (*in == '{') {
if (in != end && *in == '{') {
++in;
Value *current(nullptr), *prev(nullptr);
while ('}' != *in) {
while (in != end && '}' != *in) {
current = nullptr;
in = lookForNextToken(in, end);
if (Value::ValueType::ddl_ref == type) {
@ -962,11 +980,12 @@ char *OpenDDLParser::parseDataList(char *in, char *end, Value::ValueType type, V
}
in = getNextSeparator(in, end);
if (',' != *in && Grammar::CloseBracketToken[0] != *in && !isSpace(*in)) {
if (in == end || (',' != *in && Grammar::CloseBracketToken[0] != *in && !isSpace(*in))) {
break;
}
}
++in;
if (in != end)
++in;
}
return in;

View File

@ -26,8 +26,8 @@ CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
#include <string>
#include <vector>
#include <stdio.h>
#include <string.h>
#include <cstdio>
#include <cstring>
#ifndef _WIN32
#include <inttypes.h>
#endif

View File

@ -40,15 +40,6 @@ struct Identifier;
struct Reference;
struct Property;
template <class T>
inline bool isEmbeddedCommentOpenTag(T *in, T *end) {
if (in == '/' && in + 1 == '*') {
return true;
}
return false;
}
/// @brief Utility function to search for the next token or the end of the buffer.
/// @param in [in] The start position in the buffer.
/// @param end [in] The end position in the buffer.

View File

@ -54,7 +54,9 @@ inline bool isSeparator(T in) {
return false;
}
static const unsigned char chartype_table[256] = {
const size_t CharTableSize = 256;
static const unsigned char chartype_table[CharTableSize] = {
0,
0,
0,
@ -318,6 +320,10 @@ static const unsigned char chartype_table[256] = {
template <class T>
inline bool isNumeric(const T in) {
if (static_cast<size_t>(in) >= CharTableSize) {
return '\0';
}
size_t idx = static_cast<size_t>(in);
return idx < sizeof(chartype_table) && (chartype_table[idx] == 1);
}
@ -433,7 +439,7 @@ inline bool isEndofLine(const T in) {
template <class T>
inline static T *getNextSeparator(T *in, T *end) {
while (!isSeparator(*in) || in == end) {
while (in != end && !isSeparator(*in)) {
++in;
}
return in;

View File

@ -1,75 +0,0 @@
diff -r 5de9623d6a50 poly2tri/common/shapes.h
--- a/poly2tri/common/shapes.h Mon Aug 08 22:26:41 2011 -0400
+++ b/poly2tri/common/shapes.h Tue Jan 17 02:36:52 2012 +0100
@@ -35,6 +35,7 @@
#include <vector>
#include <cstddef>
+#include <stdexcept>
#include <assert.h>
#include <cmath>
@@ -136,7 +137,9 @@
p = &p2;
} else if (p1.x == p2.x) {
// Repeat points
- assert(false);
+ // ASSIMP_CHANGE (aramis_acg)
+ throw std::runtime_error("repeat points");
+ //assert(false);
}
}
diff -r 5de9623d6a50 poly2tri/sweep/sweep.cc
--- a/poly2tri/sweep/sweep.cc Mon Aug 08 22:26:41 2011 -0400
+++ b/poly2tri/sweep/sweep.cc Tue Jan 17 02:36:52 2012 +0100
@@ -113,6 +113,8 @@
Point* p1 = triangle->PointCCW(point);
Orientation o1 = Orient2d(eq, *p1, ep);
if (o1 == COLLINEAR) {
+ // ASSIMP_CHANGE (aramis_acg)
+ throw std::runtime_error("EdgeEvent - collinear points not supported");
if( triangle->Contains(&eq, p1)) {
triangle->MarkConstrainedEdge(&eq, p1 );
// We are modifying the constraint maybe it would be better to
@@ -121,8 +123,8 @@
triangle = &triangle->NeighborAcross(point);
EdgeEvent( tcx, ep, *p1, triangle, *p1 );
} else {
+ // ASSIMP_CHANGE (aramis_acg)
std::runtime_error("EdgeEvent - collinear points not supported");
- assert(0);
}
return;
}
@@ -130,6 +132,9 @@
Point* p2 = triangle->PointCW(point);
Orientation o2 = Orient2d(eq, *p2, ep);
if (o2 == COLLINEAR) {
+ // ASSIMP_CHANGE (aramis_acg)
+ throw std::runtime_error("EdgeEvent - collinear points not supported");
+
if( triangle->Contains(&eq, p2)) {
triangle->MarkConstrainedEdge(&eq, p2 );
// We are modifying the constraint maybe it would be better to
@@ -138,8 +143,8 @@
triangle = &triangle->NeighborAcross(point);
EdgeEvent( tcx, ep, *p2, triangle, *p2 );
} else {
- std::runtime_error("EdgeEvent - collinear points not supported");
- assert(0);
+ // ASSIMP_CHANGE (aramis_acg)
+ throw std::runtime_error("EdgeEvent - collinear points not supported");
}
return;
}
@@ -712,7 +717,8 @@
return *ot.PointCW(op);
} else{
//throw new RuntimeException("[Unsupported] Opposing point on constrained edge");
- assert(0);
+ // ASSIMP_CHANGE (aramis_acg)
+ throw std::runtime_error("[Unsupported] Opposing point on constrained edge");
}
}

View File

@ -1,4 +1,4 @@
pugixml 1.12 - an XML processing library
pugixml 1.13 - an XML processing library
Copyright (C) 2006-2022, by Arseny Kapoulkine (arseny.kapoulkine@gmail.com)
Report bugs and download new versions at https://pugixml.org/

View File

@ -1,5 +1,5 @@
/**
* pugixml parser - version 1.12
* pugixml parser - version 1.13
* --------------------------------------------------------
* Copyright (C) 2006-2022, by Arseny Kapoulkine (arseny.kapoulkine@gmail.com)
* Report bugs and download new versions at https://pugixml.org/

View File

@ -1,5 +1,5 @@
/**
* pugixml parser - version 1.12
* pugixml parser - version 1.13
* --------------------------------------------------------
* Copyright (C) 2006-2022, by Arseny Kapoulkine (arseny.kapoulkine@gmail.com)
* Report bugs and download new versions at https://pugixml.org/
@ -1276,12 +1276,14 @@ PUGI__NS_BEGIN
child->parent = parent;
if (node->next_sibling)
node->next_sibling->prev_sibling_c = child;
xml_node_struct* next = node->next_sibling;
if (next)
next->prev_sibling_c = child;
else
parent->first_child->prev_sibling_c = child;
child->next_sibling = node->next_sibling;
child->next_sibling = next;
child->prev_sibling_c = node;
node->next_sibling = child;
@ -1293,12 +1295,14 @@ PUGI__NS_BEGIN
child->parent = parent;
if (node->prev_sibling_c->next_sibling)
node->prev_sibling_c->next_sibling = child;
xml_node_struct* prev = node->prev_sibling_c;
if (prev->next_sibling)
prev->next_sibling = child;
else
parent->first_child = child;
child->prev_sibling_c = node->prev_sibling_c;
child->prev_sibling_c = prev;
child->next_sibling = node;
node->prev_sibling_c = child;
@ -1308,15 +1312,18 @@ PUGI__NS_BEGIN
{
xml_node_struct* parent = node->parent;
if (node->next_sibling)
node->next_sibling->prev_sibling_c = node->prev_sibling_c;
else
parent->first_child->prev_sibling_c = node->prev_sibling_c;
xml_node_struct* next = node->next_sibling;
xml_node_struct* prev = node->prev_sibling_c;
if (node->prev_sibling_c->next_sibling)
node->prev_sibling_c->next_sibling = node->next_sibling;
if (next)
next->prev_sibling_c = prev;
else
parent->first_child = node->next_sibling;
parent->first_child->prev_sibling_c = prev;
if (prev->next_sibling)
prev->next_sibling = next;
else
parent->first_child = next;
node->parent = 0;
node->prev_sibling_c = 0;
@ -1360,39 +1367,46 @@ PUGI__NS_BEGIN
inline void insert_attribute_after(xml_attribute_struct* attr, xml_attribute_struct* place, xml_node_struct* node)
{
if (place->next_attribute)
place->next_attribute->prev_attribute_c = attr;
xml_attribute_struct* next = place->next_attribute;
if (next)
next->prev_attribute_c = attr;
else
node->first_attribute->prev_attribute_c = attr;
attr->next_attribute = place->next_attribute;
attr->next_attribute = next;
attr->prev_attribute_c = place;
place->next_attribute = attr;
}
inline void insert_attribute_before(xml_attribute_struct* attr, xml_attribute_struct* place, xml_node_struct* node)
{
if (place->prev_attribute_c->next_attribute)
place->prev_attribute_c->next_attribute = attr;
xml_attribute_struct* prev = place->prev_attribute_c;
if (prev->next_attribute)
prev->next_attribute = attr;
else
node->first_attribute = attr;
attr->prev_attribute_c = place->prev_attribute_c;
attr->prev_attribute_c = prev;
attr->next_attribute = place;
place->prev_attribute_c = attr;
}
inline void remove_attribute(xml_attribute_struct* attr, xml_node_struct* node)
{
if (attr->next_attribute)
attr->next_attribute->prev_attribute_c = attr->prev_attribute_c;
else
node->first_attribute->prev_attribute_c = attr->prev_attribute_c;
xml_attribute_struct* next = attr->next_attribute;
xml_attribute_struct* prev = attr->prev_attribute_c;
if (attr->prev_attribute_c->next_attribute)
attr->prev_attribute_c->next_attribute = attr->next_attribute;
if (next)
next->prev_attribute_c = prev;
else
node->first_attribute = attr->next_attribute;
node->first_attribute->prev_attribute_c = prev;
if (prev->next_attribute)
prev->next_attribute = next;
else
node->first_attribute = next;
attr->prev_attribute_c = 0;
attr->next_attribute = 0;
@ -4707,6 +4721,9 @@ PUGI__NS_BEGIN
// get actual encoding
xml_encoding buffer_encoding = impl::get_buffer_encoding(encoding, contents, size);
// if convert_buffer below throws bad_alloc, we still need to deallocate contents if we own it
auto_deleter<void> contents_guard(own ? contents : 0, xml_memory::deallocate);
// get private buffer
char_t* buffer = 0;
size_t length = 0;
@ -4714,6 +4731,9 @@ PUGI__NS_BEGIN
// coverity[var_deref_model]
if (!impl::convert_buffer(buffer, length, buffer_encoding, contents, size, is_mutable)) return impl::make_parse_result(status_out_of_memory);
// after this we either deallocate contents (below) or hold on to it via doc->buffer, so we don't need to guard it
contents_guard.release();
// delete original buffer if we performed a conversion
if (own && buffer != contents && contents) impl::xml_memory::deallocate(contents);
@ -5050,7 +5070,7 @@ PUGI__NS_BEGIN
xml_writer_file writer(file);
doc.save(writer, indent, flags, encoding);
return ferror(file) == 0;
return fflush(file) == 0 && ferror(file) == 0;
}
struct name_null_sentry
@ -5185,53 +5205,72 @@ namespace pugi
PUGI__FN xml_attribute xml_attribute::next_attribute() const
{
return _attr ? xml_attribute(_attr->next_attribute) : xml_attribute();
if (!_attr) return xml_attribute();
return xml_attribute(_attr->next_attribute);
}
PUGI__FN xml_attribute xml_attribute::previous_attribute() const
{
return _attr && _attr->prev_attribute_c->next_attribute ? xml_attribute(_attr->prev_attribute_c) : xml_attribute();
if (!_attr) return xml_attribute();
xml_attribute_struct* prev = _attr->prev_attribute_c;
return prev->next_attribute ? xml_attribute(prev) : xml_attribute();
}
PUGI__FN const char_t* xml_attribute::as_string(const char_t* def) const
{
return (_attr && _attr->value) ? _attr->value + 0 : def;
if (!_attr) return def;
const char_t* value = _attr->value;
return value ? value : def;
}
PUGI__FN int xml_attribute::as_int(int def) const
{
return (_attr && _attr->value) ? impl::get_value_int(_attr->value) : def;
if (!_attr) return def;
const char_t* value = _attr->value;
return value ? impl::get_value_int(value) : def;
}
PUGI__FN unsigned int xml_attribute::as_uint(unsigned int def) const
{
return (_attr && _attr->value) ? impl::get_value_uint(_attr->value) : def;
if (!_attr) return def;
const char_t* value = _attr->value;
return value ? impl::get_value_uint(value) : def;
}
PUGI__FN double xml_attribute::as_double(double def) const
{
return (_attr && _attr->value) ? impl::get_value_double(_attr->value) : def;
if (!_attr) return def;
const char_t* value = _attr->value;
return value ? impl::get_value_double(value) : def;
}
PUGI__FN float xml_attribute::as_float(float def) const
{
return (_attr && _attr->value) ? impl::get_value_float(_attr->value) : def;
if (!_attr) return def;
const char_t* value = _attr->value;
return value ? impl::get_value_float(value) : def;
}
PUGI__FN bool xml_attribute::as_bool(bool def) const
{
return (_attr && _attr->value) ? impl::get_value_bool(_attr->value) : def;
if (!_attr) return def;
const char_t* value = _attr->value;
return value ? impl::get_value_bool(value) : def;
}
#ifdef PUGIXML_HAS_LONG_LONG
PUGI__FN long long xml_attribute::as_llong(long long def) const
{
return (_attr && _attr->value) ? impl::get_value_llong(_attr->value) : def;
if (!_attr) return def;
const char_t* value = _attr->value;
return value ? impl::get_value_llong(value) : def;
}
PUGI__FN unsigned long long xml_attribute::as_ullong(unsigned long long def) const
{
return (_attr && _attr->value) ? impl::get_value_ullong(_attr->value) : def;
if (!_attr) return def;
const char_t* value = _attr->value;
return value ? impl::get_value_ullong(value) : def;
}
#endif
@ -5242,12 +5281,16 @@ namespace pugi
PUGI__FN const char_t* xml_attribute::name() const
{
return (_attr && _attr->name) ? _attr->name + 0 : PUGIXML_TEXT("");
if (!_attr) return PUGIXML_TEXT("");
const char_t* name = _attr->name;
return name ? name : PUGIXML_TEXT("");
}
PUGI__FN const char_t* xml_attribute::value() const
{
return (_attr && _attr->value) ? _attr->value + 0 : PUGIXML_TEXT("");
if (!_attr) return PUGIXML_TEXT("");
const char_t* value = _attr->value;
return value ? value : PUGIXML_TEXT("");
}
PUGI__FN size_t xml_attribute::hash_value() const
@ -5329,6 +5372,13 @@ namespace pugi
return impl::strcpy_insitu(_attr->name, _attr->header, impl::xml_memory_page_name_allocated_mask, rhs, impl::strlength(rhs));
}
PUGI__FN bool xml_attribute::set_value(const char_t* rhs, size_t sz)
{
if (!_attr) return false;
return impl::strcpy_insitu(_attr->value, _attr->header, impl::xml_memory_page_value_allocated_mask, rhs, sz);
}
PUGI__FN bool xml_attribute::set_value(const char_t* rhs)
{
if (!_attr) return false;
@ -5521,7 +5571,9 @@ namespace pugi
PUGI__FN const char_t* xml_node::name() const
{
return (_root && _root->name) ? _root->name + 0 : PUGIXML_TEXT("");
if (!_root) return PUGIXML_TEXT("");
const char_t* name = _root->name;
return name ? name : PUGIXML_TEXT("");
}
PUGI__FN xml_node_type xml_node::type() const
@ -5531,7 +5583,9 @@ namespace pugi
PUGI__FN const char_t* xml_node::value() const
{
return (_root && _root->value) ? _root->value + 0 : PUGIXML_TEXT("");
if (!_root) return PUGIXML_TEXT("");
const char_t* value = _root->value;
return value ? value : PUGIXML_TEXT("");
}
PUGI__FN xml_node xml_node::child(const char_t* name_) const
@ -5539,7 +5593,11 @@ namespace pugi
if (!_root) return xml_node();
for (xml_node_struct* i = _root->first_child; i; i = i->next_sibling)
if (i->name && impl::strequal(name_, i->name)) return xml_node(i);
{
const char_t* iname = i->name;
if (iname && impl::strequal(name_, iname))
return xml_node(i);
}
return xml_node();
}
@ -5549,8 +5607,11 @@ namespace pugi
if (!_root) return xml_attribute();
for (xml_attribute_struct* i = _root->first_attribute; i; i = i->next_attribute)
if (i->name && impl::strequal(name_, i->name))
{
const char_t* iname = i->name;
if (iname && impl::strequal(name_, iname))
return xml_attribute(i);
}
return xml_attribute();
}
@ -5560,7 +5621,11 @@ namespace pugi
if (!_root) return xml_node();
for (xml_node_struct* i = _root->next_sibling; i; i = i->next_sibling)
if (i->name && impl::strequal(name_, i->name)) return xml_node(i);
{
const char_t* iname = i->name;
if (iname && impl::strequal(name_, iname))
return xml_node(i);
}
return xml_node();
}
@ -5575,7 +5640,11 @@ namespace pugi
if (!_root) return xml_node();
for (xml_node_struct* i = _root->prev_sibling_c; i->next_sibling; i = i->prev_sibling_c)
if (i->name && impl::strequal(name_, i->name)) return xml_node(i);
{
const char_t* iname = i->name;
if (iname && impl::strequal(name_, iname))
return xml_node(i);
}
return xml_node();
}
@ -5591,24 +5660,30 @@ namespace pugi
// optimistically search from hint up until the end
for (xml_attribute_struct* i = hint; i; i = i->next_attribute)
if (i->name && impl::strequal(name_, i->name))
{
const char_t* iname = i->name;
if (iname && impl::strequal(name_, iname))
{
// update hint to maximize efficiency of searching for consecutive attributes
hint_._attr = i->next_attribute;
return xml_attribute(i);
}
}
// wrap around and search from the first attribute until the hint
// 'j' null pointer check is technically redundant, but it prevents a crash in case the assertion above fails
for (xml_attribute_struct* j = _root->first_attribute; j && j != hint; j = j->next_attribute)
if (j->name && impl::strequal(name_, j->name))
{
const char_t* jname = j->name;
if (jname && impl::strequal(name_, jname))
{
// update hint to maximize efficiency of searching for consecutive attributes
hint_._attr = j->next_attribute;
return xml_attribute(j);
}
}
return xml_attribute();
}
@ -5616,9 +5691,8 @@ namespace pugi
PUGI__FN xml_node xml_node::previous_sibling() const
{
if (!_root) return xml_node();
if (_root->prev_sibling_c->next_sibling) return xml_node(_root->prev_sibling_c);
else return xml_node();
xml_node_struct* prev = _root->prev_sibling_c;
return prev->next_sibling ? xml_node(prev) : xml_node();
}
PUGI__FN xml_node xml_node::parent() const
@ -5645,8 +5719,11 @@ namespace pugi
return _root->value;
for (xml_node_struct* i = _root->first_child; i; i = i->next_sibling)
if (impl::is_text_node(i) && i->value)
return i->value;
{
const char_t* ivalue = i->value;
if (impl::is_text_node(i) && ivalue)
return ivalue;
}
return PUGIXML_TEXT("");
}
@ -5658,22 +5735,28 @@ namespace pugi
PUGI__FN xml_attribute xml_node::first_attribute() const
{
return _root ? xml_attribute(_root->first_attribute) : xml_attribute();
if (!_root) return xml_attribute();
return xml_attribute(_root->first_attribute);
}
PUGI__FN xml_attribute xml_node::last_attribute() const
{
return _root && _root->first_attribute ? xml_attribute(_root->first_attribute->prev_attribute_c) : xml_attribute();
if (!_root) return xml_attribute();
xml_attribute_struct* first = _root->first_attribute;
return first ? xml_attribute(first->prev_attribute_c) : xml_attribute();
}
PUGI__FN xml_node xml_node::first_child() const
{
return _root ? xml_node(_root->first_child) : xml_node();
if (!_root) return xml_node();
return xml_node(_root->first_child);
}
PUGI__FN xml_node xml_node::last_child() const
{
return _root && _root->first_child ? xml_node(_root->first_child->prev_sibling_c) : xml_node();
if (!_root) return xml_node();
xml_node_struct* first = _root->first_child;
return first ? xml_node(first->prev_sibling_c) : xml_node();
}
PUGI__FN bool xml_node::set_name(const char_t* rhs)
@ -5686,6 +5769,16 @@ namespace pugi
return impl::strcpy_insitu(_root->name, _root->header, impl::xml_memory_page_name_allocated_mask, rhs, impl::strlength(rhs));
}
PUGI__FN bool xml_node::set_value(const char_t* rhs, size_t sz)
{
xml_node_type type_ = _root ? PUGI__NODETYPE(_root) : node_null;
if (type_ != node_pcdata && type_ != node_cdata && type_ != node_comment && type_ != node_pi && type_ != node_doctype)
return false;
return impl::strcpy_insitu(_root->value, _root->header, impl::xml_memory_page_value_allocated_mask, rhs, sz);
}
PUGI__FN bool xml_node::set_value(const char_t* rhs)
{
xml_node_type type_ = _root ? PUGI__NODETYPE(_root) : node_null;
@ -6199,12 +6292,22 @@ namespace pugi
if (!_root) return xml_node();
for (xml_node_struct* i = _root->first_child; i; i = i->next_sibling)
if (i->name && impl::strequal(name_, i->name))
{
const char_t* iname = i->name;
if (iname && impl::strequal(name_, iname))
{
for (xml_attribute_struct* a = i->first_attribute; a; a = a->next_attribute)
if (a->name && impl::strequal(attr_name, a->name) && impl::strequal(attr_value, a->value ? a->value + 0 : PUGIXML_TEXT("")))
return xml_node(i);
{
const char_t* aname = a->name;
if (aname && impl::strequal(attr_name, aname))
{
const char_t* avalue = a->value;
if (impl::strequal(attr_value, avalue ? avalue : PUGIXML_TEXT("")))
return xml_node(i);
}
}
}
}
return xml_node();
}
@ -6215,8 +6318,15 @@ namespace pugi
for (xml_node_struct* i = _root->first_child; i; i = i->next_sibling)
for (xml_attribute_struct* a = i->first_attribute; a; a = a->next_attribute)
if (a->name && impl::strequal(attr_name, a->name) && impl::strequal(attr_value, a->value ? a->value + 0 : PUGIXML_TEXT("")))
return xml_node(i);
{
const char_t* aname = a->name;
if (aname && impl::strequal(attr_name, aname))
{
const char_t* avalue = a->value;
if (impl::strequal(attr_value, avalue ? avalue : PUGIXML_TEXT("")))
return xml_node(i);
}
}
return xml_node();
}
@ -6230,8 +6340,9 @@ namespace pugi
for (xml_node_struct* i = _root; i; i = i->parent)
{
const char_t* iname = i->name;
offset += (i != _root);
offset += i->name ? impl::strlength(i->name) : 0;
offset += iname ? impl::strlength(iname) : 0;
}
string_t result;
@ -6242,12 +6353,13 @@ namespace pugi
if (j != _root)
result[--offset] = delimiter;
if (j->name)
const char_t* jname = j->name;
if (jname)
{
size_t length = impl::strlength(j->name);
size_t length = impl::strlength(jname);
offset -= length;
memcpy(&result[offset], j->name, length * sizeof(char_t));
memcpy(&result[offset], jname, length * sizeof(char_t));
}
}
@ -6285,7 +6397,8 @@ namespace pugi
{
for (xml_node_struct* j = context._root->first_child; j; j = j->next_sibling)
{
if (j->name && impl::strequalrange(j->name, path_segment, static_cast<size_t>(path_segment_end - path_segment)))
const char_t* jname = j->name;
if (jname && impl::strequalrange(jname, path_segment, static_cast<size_t>(path_segment_end - path_segment)))
{
xml_node subsearch = xml_node(j).first_element_by_path(next_segment, delimiter);
@ -6477,68 +6590,84 @@ namespace pugi
PUGI__FN const char_t* xml_text::get() const
{
xml_node_struct* d = _data();
return (d && d->value) ? d->value + 0 : PUGIXML_TEXT("");
if (!d) return PUGIXML_TEXT("");
const char_t* value = d->value;
return value ? value : PUGIXML_TEXT("");
}
PUGI__FN const char_t* xml_text::as_string(const char_t* def) const
{
xml_node_struct* d = _data();
return (d && d->value) ? d->value + 0 : def;
if (!d) return def;
const char_t* value = d->value;
return value ? value : def;
}
PUGI__FN int xml_text::as_int(int def) const
{
xml_node_struct* d = _data();
return (d && d->value) ? impl::get_value_int(d->value) : def;
if (!d) return def;
const char_t* value = d->value;
return value ? impl::get_value_int(value) : def;
}
PUGI__FN unsigned int xml_text::as_uint(unsigned int def) const
{
xml_node_struct* d = _data();
return (d && d->value) ? impl::get_value_uint(d->value) : def;
if (!d) return def;
const char_t* value = d->value;
return value ? impl::get_value_uint(value) : def;
}
PUGI__FN double xml_text::as_double(double def) const
{
xml_node_struct* d = _data();
return (d && d->value) ? impl::get_value_double(d->value) : def;
if (!d) return def;
const char_t* value = d->value;
return value ? impl::get_value_double(value) : def;
}
PUGI__FN float xml_text::as_float(float def) const
{
xml_node_struct* d = _data();
return (d && d->value) ? impl::get_value_float(d->value) : def;
if (!d) return def;
const char_t* value = d->value;
return value ? impl::get_value_float(value) : def;
}
PUGI__FN bool xml_text::as_bool(bool def) const
{
xml_node_struct* d = _data();
return (d && d->value) ? impl::get_value_bool(d->value) : def;
if (!d) return def;
const char_t* value = d->value;
return value ? impl::get_value_bool(value) : def;
}
#ifdef PUGIXML_HAS_LONG_LONG
PUGI__FN long long xml_text::as_llong(long long def) const
{
xml_node_struct* d = _data();
return (d && d->value) ? impl::get_value_llong(d->value) : def;
if (!d) return def;
const char_t* value = d->value;
return value ? impl::get_value_llong(value) : def;
}
PUGI__FN unsigned long long xml_text::as_ullong(unsigned long long def) const
{
xml_node_struct* d = _data();
return (d && d->value) ? impl::get_value_ullong(d->value) : def;
if (!d) return def;
const char_t* value = d->value;
return value ? impl::get_value_ullong(value) : def;
}
#endif
PUGI__FN bool xml_text::set(const char_t* rhs, size_t sz)
{
xml_node_struct* dn = _data_new();
return dn ? impl::strcpy_insitu(dn->value, dn->header, impl::xml_memory_page_value_allocated_mask, rhs, sz) : false;
}
PUGI__FN bool xml_text::set(const char_t* rhs)
{
xml_node_struct* dn = _data_new();
@ -7294,7 +7423,7 @@ namespace pugi
using impl::auto_deleter; // MSVC7 workaround
auto_deleter<FILE> file(impl::open_file(path_, (flags & format_save_file_text) ? "w" : "wb"), impl::close_file);
return impl::save_file_impl(*this, file.data, indent, flags, encoding);
return impl::save_file_impl(*this, file.data, indent, flags, encoding) && fclose(file.release()) == 0;
}
PUGI__FN bool xml_document::save_file(const wchar_t* path_, const char_t* indent, unsigned int flags, xml_encoding encoding) const
@ -7302,7 +7431,7 @@ namespace pugi
using impl::auto_deleter; // MSVC7 workaround
auto_deleter<FILE> file(impl::open_file_wide(path_, (flags & format_save_file_text) ? L"w" : L"wb"), impl::close_file);
return impl::save_file_impl(*this, file.data, indent, flags, encoding);
return impl::save_file_impl(*this, file.data, indent, flags, encoding) && fclose(file.release()) == 0;
}
PUGI__FN xml_node xml_document::document_element() const

View File

@ -1,5 +1,5 @@
/**
* pugixml parser - version 1.12
* pugixml parser - version 1.13
* --------------------------------------------------------
* Copyright (C) 2006-2022, by Arseny Kapoulkine (arseny.kapoulkine@gmail.com)
* Report bugs and download new versions at https://pugixml.org/
@ -14,7 +14,7 @@
// Define version macro; evaluates to major * 1000 + minor * 10 + patch so that it's safe to use in less-than comparisons
// Note: pugixml used major * 100 + minor * 10 + patch format up until 1.9 (which had version identifier 190); starting from pugixml 1.10, the minor version number is two digits
#ifndef PUGIXML_VERSION
# define PUGIXML_VERSION 1120 // 1.12
# define PUGIXML_VERSION 1130 // 1.13
#endif
// Include user configuration file (this can define various configuration macros)
@ -115,6 +115,8 @@
#ifndef PUGIXML_NULL
# if __cplusplus >= 201103
# define PUGIXML_NULL nullptr
# elif defined(_MSC_VER) && _MSC_VER >= 1600
# define PUGIXML_NULL nullptr
# else
# define PUGIXML_NULL 0
# endif
@ -416,6 +418,7 @@ namespace pugi
// Set attribute name/value (returns false if attribute is empty or there is not enough memory)
bool set_name(const char_t* rhs);
bool set_value(const char_t* rhs, size_t sz);
bool set_value(const char_t* rhs);
// Set attribute value with type conversion (numbers are converted to strings, boolean is converted to "true"/"false")
@ -550,6 +553,7 @@ namespace pugi
// Set node name/value (returns false if node is empty, there is not enough memory, or node can not have name/value)
bool set_name(const char_t* rhs);
bool set_value(const char_t* rhs, size_t sz);
bool set_value(const char_t* rhs);
// Add attribute with specified name. Returns added attribute, or empty attribute on errors.
@ -775,6 +779,7 @@ namespace pugi
bool as_bool(bool def = false) const;
// Set text (returns false if object is empty or there is not enough memory)
bool set(const char_t* rhs, size_t sz);
bool set(const char_t* rhs);
// Set text with type conversion (numbers are converted to strings, boolean is converted to "true"/"false")

View File

@ -1,172 +0,0 @@
/* crypt.c -- base code for traditional PKWARE encryption
Version 1.01e, February 12th, 2005
Copyright (C) 1998-2005 Gilles Vollant
Modifications for Info-ZIP crypting
Copyright (C) 2003 Terry Thorsen
This code is a modified version of crypting code in Info-ZIP distribution
Copyright (C) 1990-2000 Info-ZIP. All rights reserved.
This program is distributed under the terms of the same license as zlib.
See the accompanying LICENSE file for the full text of the license.
This encryption code is a direct transcription of the algorithm from
Roger Schlafly, described by Phil Katz in the file appnote.txt. This
file (appnote.txt) is distributed with the PKZIP program (even in the
version without encryption capabilities).
If you don't need crypting in your application, just define symbols
NOCRYPT and NOUNCRYPT.
*/
#if defined(WIN32) || defined(_WIN32) || defined(__WIN32) && !defined(__CYGWIN__)
#define MICROSOFT_WINDOWS_WINBASE_H_DEFINE_INTERLOCKED_CPLUSPLUS_OVERLOADS 0
#endif
#include <stdio.h>
#include <stdlib.h>
#include <stdint.h>
#include <time.h>
#ifdef _WIN32
# include <windows.h>
# include <wincrypt.h>
#else
# include <sys/stat.h>
# include <fcntl.h>
# include <unistd.h>
#endif
#include "zlib.h"
#include "crypt.h"
#ifdef _MSC_VER
# pragma warning(push)
# pragma warning(disable : 4244)
#endif // _MSC_VER
/***************************************************************************/
#define CRC32(c, b) ((*(pcrc_32_tab+(((uint32_t)(c) ^ (b)) & 0xff))) ^ ((c) >> 8))
#ifndef ZCR_SEED2
# define ZCR_SEED2 3141592654UL /* use PI as default pattern */
#endif
/***************************************************************************/
uint8_t decrypt_byte(uint32_t *pkeys)
{
unsigned temp; /* POTENTIAL BUG: temp*(temp^1) may overflow in an
* unpredictable manner on 16-bit systems; not a problem
* with any known compiler so far, though */
temp = ((uint32_t)(*(pkeys+2)) & 0xffff) | 2;
return (uint8_t)(((temp * (temp ^ 1)) >> 8) & 0xff);
}
uint8_t update_keys(uint32_t *pkeys, const z_crc_t *pcrc_32_tab, int32_t c)
{
(*(pkeys+0)) = (uint32_t)CRC32((*(pkeys+0)), c);
(*(pkeys+1)) += (*(pkeys+0)) & 0xff;
(*(pkeys+1)) = (*(pkeys+1)) * 134775813L + 1;
{
register int32_t keyshift = (int32_t)((*(pkeys + 1)) >> 24);
(*(pkeys+2)) = (uint32_t)CRC32((*(pkeys+2)), keyshift);
}
return c;
}
void init_keys(const char *passwd, uint32_t *pkeys, const z_crc_t *pcrc_32_tab)
{
*(pkeys+0) = 305419896L;
*(pkeys+1) = 591751049L;
*(pkeys+2) = 878082192L;
while (*passwd != 0)
{
update_keys(pkeys, pcrc_32_tab, *passwd);
passwd += 1;
}
}
/***************************************************************************/
int cryptrand(unsigned char *buf, unsigned int len)
{
static unsigned calls = 0;
int rlen = 0;
#ifdef _WIN32
HCRYPTPROV provider;
unsigned __int64 pentium_tsc[1];
int result = 0;
#if defined(WINAPI_FAMILY) && WINAPI_FAMILY == WINAPI_FAMILY_DESKTOP_APP
if (CryptAcquireContext(&provider, NULL, NULL, PROV_RSA_FULL, CRYPT_VERIFYCONTEXT | CRYPT_SILENT))
{
result = CryptGenRandom(provider, len, buf);
CryptReleaseContext(provider, 0);
if (result)
return len;
}
#endif
for (rlen = 0; rlen < (int)len; ++rlen)
{
if (rlen % 8 == 0)
QueryPerformanceCounter((LARGE_INTEGER *)pentium_tsc);
buf[rlen] = ((unsigned char*)pentium_tsc)[rlen % 8];
}
#else
int frand = open("/dev/urandom", O_RDONLY);
if (frand != -1)
{
rlen = (int)read(frand, buf, len);
close(frand);
}
#endif
if (rlen < (int)len)
{
/* Ensure different random header each time */
if (++calls == 1)
srand((unsigned)(time(NULL) ^ ZCR_SEED2));
while (rlen < (int)len)
buf[rlen++] = (rand() >> 7) & 0xff;
}
return rlen;
}
int crypthead(const char *passwd, uint8_t *buf, int buf_size, uint32_t *pkeys,
const z_crc_t *pcrc_32_tab, uint8_t verify1, uint8_t verify2)
{
uint8_t n = 0; /* index in random header */
uint8_t header[RAND_HEAD_LEN-2]; /* random header */
uint16_t t = 0; /* temporary */
if (buf_size < RAND_HEAD_LEN)
return 0;
init_keys(passwd, pkeys, pcrc_32_tab);
/* First generate RAND_HEAD_LEN-2 random bytes. */
cryptrand(header, RAND_HEAD_LEN-2);
/* Encrypt random header (last two bytes is high word of crc) */
init_keys(passwd, pkeys, pcrc_32_tab);
for (n = 0; n < RAND_HEAD_LEN-2; n++)
buf[n] = (uint8_t)zencode(pkeys, pcrc_32_tab, header[n], t);
buf[n++] = (uint8_t)zencode(pkeys, pcrc_32_tab, verify1, t);
buf[n++] = (uint8_t)zencode(pkeys, pcrc_32_tab, verify2, t);
return n;
}
#ifdef _MSC_VER
# pragma warning(pop)
#endif // _MSC_VER
/***************************************************************************/

View File

@ -1,63 +1,132 @@
/* crypt.h -- base code for traditional PKWARE encryption
/* crypt.h -- base code for crypt/uncrypt ZIPfile
Version 1.01e, February 12th, 2005
Copyright (C) 1998-2005 Gilles Vollant
Modifications for Info-ZIP crypting
Copyright (C) 2003 Terry Thorsen
This code is a modified version of crypting code in Info-ZIP distribution
This code is a modified version of crypting code in Infozip distribution
Copyright (C) 1990-2000 Info-ZIP. All rights reserved.
The encryption/decryption parts of this source code (as opposed to the
non-echoing password parts) were originally written in Europe. The
whole source package can be freely distributed, including from the USA.
(Prior to January 2000, re-export from the US was a violation of US law.)
This program is distributed under the terms of the same license as zlib.
See the accompanying LICENSE file for the full text of the license.
This encryption code is a direct transcription of the algorithm from
Roger Schlafly, described by Phil Katz in the file appnote.txt. This
file (appnote.txt) is distributed with the PKZIP program (even in the
version without encryption capabilities).
If you don't need crypting in your application, just define symbols
NOCRYPT and NOUNCRYPT.
This code support the "Traditional PKWARE Encryption".
The new AES encryption added on Zip format by Winzip (see the page
http://www.winzip.com/aes_info.htm ) and PKWare PKZip 5.x Strong
Encryption is not supported.
*/
#ifndef _MINICRYPT_H
#define _MINICRYPT_H
#define CRC32(c, b) ((*(pcrc_32_tab+(((int)(c) ^ (b)) & 0xff))) ^ ((c) >> 8))
#if ZLIB_VERNUM < 0x1270
#if !defined(Z_U4)
typedef unsigned long z_crc_t;
#endif
#endif
/***********************************************************************
* Return the next byte in the pseudo-random sequence
*/
static int decrypt_byte(unsigned long* pkeys, const z_crc_t* pcrc_32_tab)
{
unsigned temp; /* POTENTIAL BUG: temp*(temp^1) may overflow in an
* unpredictable manner on 16-bit systems; not a problem
* with any known compiler so far, though */
#ifdef __cplusplus
extern "C" {
#endif
(void)pcrc_32_tab;
temp = ((unsigned)(*(pkeys+2)) & 0xffff) | 2;
return (int)(((temp * (temp ^ 1)) >> 8) & 0xff);
}
#define RAND_HEAD_LEN 12
/***********************************************************************
* Update the encryption keys with the next byte of plain text
*/
static int update_keys(unsigned long* pkeys,const z_crc_t* pcrc_32_tab,int c)
{
(*(pkeys+0)) = CRC32((*(pkeys+0)), c);
(*(pkeys+1)) += (*(pkeys+0)) & 0xff;
(*(pkeys+1)) = (*(pkeys+1)) * 134775813L + 1;
{
register int keyshift = (int)((*(pkeys+1)) >> 24);
(*(pkeys+2)) = CRC32((*(pkeys+2)), keyshift);
}
return c;
}
/***************************************************************************/
/***********************************************************************
* Initialize the encryption keys and the random header according to
* the given password.
*/
static void init_keys(const char* passwd,unsigned long* pkeys,const z_crc_t* pcrc_32_tab)
{
*(pkeys+0) = 305419896L;
*(pkeys+1) = 591751049L;
*(pkeys+2) = 878082192L;
while (*passwd != '\0') {
update_keys(pkeys,pcrc_32_tab,(int)*passwd);
passwd++;
}
}
#define zdecode(pkeys,pcrc_32_tab,c) \
(update_keys(pkeys,pcrc_32_tab, c ^= decrypt_byte(pkeys)))
(update_keys(pkeys,pcrc_32_tab,c ^= decrypt_byte(pkeys,pcrc_32_tab)))
#define zencode(pkeys,pcrc_32_tab,c,t) \
(t = decrypt_byte(pkeys), update_keys(pkeys,pcrc_32_tab,c), t^(c))
(t=decrypt_byte(pkeys,pcrc_32_tab), update_keys(pkeys,pcrc_32_tab,c), (Byte)t^(c))
/***************************************************************************/
#ifdef INCLUDECRYPTINGCODE_IFCRYPTALLOWED
/* Return the next byte in the pseudo-random sequence */
uint8_t decrypt_byte(uint32_t *pkeys);
#define RAND_HEAD_LEN 12
/* "last resort" source for second part of crypt seed pattern */
# ifndef ZCR_SEED2
# define ZCR_SEED2 3141592654UL /* use PI as default pattern */
# endif
/* Update the encryption keys with the next byte of plain text */
uint8_t update_keys(uint32_t *pkeys, const z_crc_t *pcrc_32_tab, int32_t c);
static unsigned crypthead(const char* passwd, /* password string */
unsigned char* buf, /* where to write header */
int bufSize,
unsigned long* pkeys,
const z_crc_t* pcrc_32_tab,
unsigned long crcForCrypting)
{
unsigned n; /* index in random header */
int t; /* temporary */
int c; /* random byte */
unsigned char header[RAND_HEAD_LEN-2]; /* random header */
static unsigned calls = 0; /* ensure different random header each time */
/* Initialize the encryption keys and the random header according to the given password. */
void init_keys(const char *passwd, uint32_t *pkeys, const z_crc_t *pcrc_32_tab);
if (bufSize<RAND_HEAD_LEN)
return 0;
/* Generate cryptographically secure random numbers */
int cryptrand(unsigned char *buf, unsigned int len);
/* Create encryption header */
int crypthead(const char *passwd, uint8_t *buf, int buf_size, uint32_t *pkeys,
const z_crc_t *pcrc_32_tab, uint8_t verify1, uint8_t verify2);
/***************************************************************************/
#ifdef __cplusplus
/* First generate RAND_HEAD_LEN-2 random bytes. We encrypt the
* output of rand() to get less predictability, since rand() is
* often poorly implemented.
*/
if (++calls == 1)
{
srand((unsigned)(time(NULL) ^ ZCR_SEED2));
}
init_keys(passwd, pkeys, pcrc_32_tab);
for (n = 0; n < RAND_HEAD_LEN-2; n++)
{
c = (rand() >> 7) & 0xff;
header[n] = (unsigned char)zencode(pkeys, pcrc_32_tab, c, t);
}
/* Encrypt random header (last two bytes is high word of crc) */
init_keys(passwd, pkeys, pcrc_32_tab);
for (n = 0; n < RAND_HEAD_LEN-2; n++)
{
buf[n] = (unsigned char)zencode(pkeys, pcrc_32_tab, header[n], t);
}
buf[n++] = (unsigned char)zencode(pkeys, pcrc_32_tab, (int)(crcForCrypting >> 16) & 0xff, t);
buf[n++] = (unsigned char)zencode(pkeys, pcrc_32_tab, (int)(crcForCrypting >> 24) & 0xff, t);
return n;
}
#endif
#endif

View File

@ -1,81 +1,75 @@
/* ioapi.c -- IO base function header for compress/uncompress .zip
part of the MiniZip project
/* ioapi.h -- IO base function header for compress/uncompress .zip
part of the MiniZip project - ( http://www.winimage.com/zLibDll/minizip.html )
Copyright (C) 1998-2010 Gilles Vollant
http://www.winimage.com/zLibDll/minizip.html
Modifications for Zip64 support
Copyright (C) 2009-2010 Mathias Svensson
http://result42.com
Copyright (C) 1998-2010 Gilles Vollant (minizip) ( http://www.winimage.com/zLibDll/minizip.html )
Modifications for Zip64 support
Copyright (C) 2009-2010 Mathias Svensson ( http://result42.com )
For more info read MiniZip_info.txt
This program is distributed under the terms of the same license as zlib.
See the accompanying LICENSE file for the full text of the license.
*/
#include <stdlib.h>
#include <string.h>
#if defined unix || defined __APPLE__
#include <sys/types.h>
#include <unistd.h>
#if defined(_WIN32) && (!(defined(_CRT_SECURE_NO_WARNINGS)))
#define _CRT_SECURE_NO_WARNINGS
#endif
#if defined(__APPLE__) || defined(IOAPI_NO_64)
// In darwin and perhaps other BSD variants off_t is a 64 bit value, hence no need for specific 64 bit functions
#define FOPEN_FUNC(filename, mode) fopen(filename, mode)
#define FTELLO_FUNC(stream) ftello(stream)
#define FSEEKO_FUNC(stream, offset, origin) fseeko(stream, offset, origin)
#else
#define FOPEN_FUNC(filename, mode) fopen64(filename, mode)
#define FTELLO_FUNC(stream) ftello64(stream)
#define FSEEKO_FUNC(stream, offset, origin) fseeko64(stream, offset, origin)
#endif
#include "ioapi.h"
#ifdef _WIN32
# define snprintf _snprintf
#ifdef _MSC_VER
# pragma warning(push)
# pragma warning(disable : 4131 4100)
#endif
# ifdef __clang__
# pragma clang diagnostic push
# pragma clang diagnostic ignored "-Wunused-parameter"
# endif
#endif // _WIN32
voidpf call_zopen64(const zlib_filefunc64_32_def *pfilefunc, const void *filename, int mode)
voidpf call_zopen64 (const zlib_filefunc64_32_def* pfilefunc,const void*filename,int mode)
{
if (pfilefunc->zfile_func64.zopen64_file != NULL)
return (*(pfilefunc->zfile_func64.zopen64_file)) (pfilefunc->zfile_func64.opaque, filename, mode);
return (*(pfilefunc->zopen32_file))(pfilefunc->zfile_func64.opaque, (const char*)filename, mode);
return (*(pfilefunc->zfile_func64.zopen64_file)) (pfilefunc->zfile_func64.opaque,filename,mode);
else
{
return (*(pfilefunc->zopen32_file))(pfilefunc->zfile_func64.opaque,(const char*)filename,mode);
}
}
voidpf call_zopendisk64(const zlib_filefunc64_32_def *pfilefunc, voidpf filestream, uint32_t number_disk, int mode)
long call_zseek64 (const zlib_filefunc64_32_def* pfilefunc,voidpf filestream, ZPOS64_T offset, int origin)
{
if (pfilefunc->zfile_func64.zopendisk64_file != NULL)
return (*(pfilefunc->zfile_func64.zopendisk64_file)) (pfilefunc->zfile_func64.opaque, filestream, number_disk, mode);
return (*(pfilefunc->zopendisk32_file))(pfilefunc->zfile_func64.opaque, filestream, number_disk, mode);
}
long call_zseek64(const zlib_filefunc64_32_def *pfilefunc, voidpf filestream, uint64_t offset, int origin)
{
uint32_t offset_truncated = 0;
if (pfilefunc->zfile_func64.zseek64_file != NULL)
return (*(pfilefunc->zfile_func64.zseek64_file)) (pfilefunc->zfile_func64.opaque,filestream,offset,origin);
offset_truncated = (uint32_t)offset;
if (offset_truncated != offset)
return -1;
return (*(pfilefunc->zseek32_file))(pfilefunc->zfile_func64.opaque,filestream, offset_truncated, origin);
else
{
uLong offsetTruncated = (uLong)offset;
if (offsetTruncated != offset)
return -1;
else
return (*(pfilefunc->zseek32_file))(pfilefunc->zfile_func64.opaque,filestream,offsetTruncated,origin);
}
}
uint64_t call_ztell64(const zlib_filefunc64_32_def *pfilefunc, voidpf filestream)
ZPOS64_T call_ztell64 (const zlib_filefunc64_32_def* pfilefunc,voidpf filestream)
{
uint64_t position;
if (pfilefunc->zfile_func64.zseek64_file != NULL)
return (*(pfilefunc->zfile_func64.ztell64_file)) (pfilefunc->zfile_func64.opaque, filestream);
position = (*(pfilefunc->ztell32_file))(pfilefunc->zfile_func64.opaque, filestream);
if ((position) == UINT32_MAX)
return (uint64_t)-1;
return position;
return (*(pfilefunc->zfile_func64.ztell64_file)) (pfilefunc->zfile_func64.opaque,filestream);
else
{
uLong tell_uLong = (uLong)(*(pfilefunc->ztell32_file))(pfilefunc->zfile_func64.opaque,filestream);
if ((tell_uLong) == MAXU32)
return (ZPOS64_T)-1;
else
return tell_uLong;
}
}
void fill_zlib_filefunc64_32_def_from_filefunc32(zlib_filefunc64_32_def *p_filefunc64_32, const zlib_filefunc_def *p_filefunc32)
void fill_zlib_filefunc64_32_def_from_filefunc32(zlib_filefunc64_32_def* p_filefunc64_32,const zlib_filefunc_def* p_filefunc32)
{
p_filefunc64_32->zfile_func64.zopen64_file = NULL;
p_filefunc64_32->zfile_func64.zopendisk64_file = NULL;
p_filefunc64_32->zopen32_file = p_filefunc32->zopen_file;
p_filefunc64_32->zopendisk32_file = p_filefunc32->zopendisk_file;
p_filefunc64_32->zfile_func64.zerror_file = p_filefunc32->zerror_file;
p_filefunc64_32->zfile_func64.zread_file = p_filefunc32->zread_file;
p_filefunc64_32->zfile_func64.zwrite_file = p_filefunc32->zwrite_file;
@ -88,255 +82,158 @@ void fill_zlib_filefunc64_32_def_from_filefunc32(zlib_filefunc64_32_def *p_filef
p_filefunc64_32->ztell32_file = p_filefunc32->ztell_file;
}
static voidpf ZCALLBACK fopen_file_func(voidpf opaque, const char *filename, int mode);
static uint32_t ZCALLBACK fread_file_func(voidpf opaque, voidpf stream, void* buf, uint32_t size);
static uint32_t ZCALLBACK fwrite_file_func(voidpf opaque, voidpf stream, const void *buf, uint32_t size);
static uint64_t ZCALLBACK ftell64_file_func(voidpf opaque, voidpf stream);
static long ZCALLBACK fseek64_file_func(voidpf opaque, voidpf stream, uint64_t offset, int origin);
static int ZCALLBACK fclose_file_func(voidpf opaque, voidpf stream);
static int ZCALLBACK ferror_file_func(voidpf opaque, voidpf stream);
typedef struct
{
FILE *file;
int filenameLength;
void *filename;
} FILE_IOPOSIX;
static voidpf file_build_ioposix(FILE *file, const char *filename)
{
FILE_IOPOSIX *ioposix = NULL;
if (file == NULL)
return NULL;
ioposix = (FILE_IOPOSIX*)malloc(sizeof(FILE_IOPOSIX));
ioposix->file = file;
ioposix->filenameLength = (int)strlen(filename) + 1;
ioposix->filename = (char*)malloc(ioposix->filenameLength * sizeof(char));
memcpy((char*)ioposix->filename, filename, ioposix->filenameLength);
return (voidpf)ioposix;
}
static voidpf ZCALLBACK fopen_file_func OF((voidpf opaque, const char* filename, int mode));
static uLong ZCALLBACK fread_file_func OF((voidpf opaque, voidpf stream, void* buf, uLong size));
static uLong ZCALLBACK fwrite_file_func OF((voidpf opaque, voidpf stream, const void* buf,uLong size));
static ZPOS64_T ZCALLBACK ftell64_file_func OF((voidpf opaque, voidpf stream));
static long ZCALLBACK fseek64_file_func OF((voidpf opaque, voidpf stream, ZPOS64_T offset, int origin));
static int ZCALLBACK fclose_file_func OF((voidpf opaque, voidpf stream));
static int ZCALLBACK ferror_file_func OF((voidpf opaque, voidpf stream));
static voidpf ZCALLBACK fopen_file_func(voidpf opaque, const char *filename, int mode)
static voidpf ZCALLBACK fopen_file_func (voidpf opaque, const char* filename, int mode)
{
FILE* file = NULL;
const char *mode_fopen = NULL;
if ((mode & ZLIB_FILEFUNC_MODE_READWRITEFILTER) == ZLIB_FILEFUNC_MODE_READ)
const char* mode_fopen = NULL;
(void)opaque;
if ((mode & ZLIB_FILEFUNC_MODE_READWRITEFILTER)==ZLIB_FILEFUNC_MODE_READ)
mode_fopen = "rb";
else if (mode & ZLIB_FILEFUNC_MODE_EXISTING)
else
if (mode & ZLIB_FILEFUNC_MODE_EXISTING)
mode_fopen = "r+b";
else if (mode & ZLIB_FILEFUNC_MODE_CREATE)
else
if (mode & ZLIB_FILEFUNC_MODE_CREATE)
mode_fopen = "wb";
if ((filename != NULL) && (mode_fopen != NULL))
{
if ((filename!=NULL) && (mode_fopen != NULL))
file = fopen(filename, mode_fopen);
return file_build_ioposix(file, filename);
}
return file;
}
static voidpf ZCALLBACK fopen64_file_func(voidpf opaque, const void *filename, int mode)
static voidpf ZCALLBACK fopen64_file_func (voidpf opaque, const void* filename, int mode)
{
FILE* file = NULL;
const char *mode_fopen = NULL;
if ((mode & ZLIB_FILEFUNC_MODE_READWRITEFILTER) == ZLIB_FILEFUNC_MODE_READ)
const char* mode_fopen = NULL;
(void)opaque;
if ((mode & ZLIB_FILEFUNC_MODE_READWRITEFILTER)==ZLIB_FILEFUNC_MODE_READ)
mode_fopen = "rb";
else if (mode & ZLIB_FILEFUNC_MODE_EXISTING)
else
if (mode & ZLIB_FILEFUNC_MODE_EXISTING)
mode_fopen = "r+b";
else if (mode & ZLIB_FILEFUNC_MODE_CREATE)
else
if (mode & ZLIB_FILEFUNC_MODE_CREATE)
mode_fopen = "wb";
if ((filename != NULL) && (mode_fopen != NULL))
{
file = fopen64((const char*)filename, mode_fopen);
return file_build_ioposix(file, (const char*)filename);
}
if ((filename!=NULL) && (mode_fopen != NULL))
file = FOPEN_FUNC((const char*)filename, mode_fopen);
return file;
}
static voidpf ZCALLBACK fopendisk64_file_func(voidpf opaque, voidpf stream, uint32_t number_disk, int mode)
{
FILE_IOPOSIX *ioposix = NULL;
char *diskFilename = NULL;
voidpf ret = NULL;
int i = 0;
if (stream == NULL)
return NULL;
ioposix = (FILE_IOPOSIX*)stream;
diskFilename = (char*)malloc(ioposix->filenameLength * sizeof(char));
strncpy(diskFilename, (const char*)ioposix->filename, ioposix->filenameLength);
for (i = ioposix->filenameLength - 1; i >= 0; i -= 1)
{
if (diskFilename[i] != '.')
continue;
snprintf(&diskFilename[i], ioposix->filenameLength - i, ".z%02u", number_disk + 1);
break;
}
if (i >= 0)
ret = fopen64_file_func(opaque, diskFilename, mode);
free(diskFilename);
static uLong ZCALLBACK fread_file_func (voidpf opaque, voidpf stream, void* buf, uLong size)
{
uLong ret;
(void)opaque;
ret = (uLong)fread(buf, 1, (size_t)size, (FILE *)stream);
return ret;
}
static voidpf ZCALLBACK fopendisk_file_func(voidpf opaque, voidpf stream, uint32_t number_disk, int mode)
static uLong ZCALLBACK fwrite_file_func (voidpf opaque, voidpf stream, const void* buf, uLong size)
{
FILE_IOPOSIX *ioposix = NULL;
char *diskFilename = NULL;
voidpf ret = NULL;
int i = 0;
if (stream == NULL)
return NULL;
ioposix = (FILE_IOPOSIX*)stream;
diskFilename = (char*)malloc(ioposix->filenameLength * sizeof(char));
strncpy(diskFilename, (const char*)ioposix->filename, ioposix->filenameLength);
for (i = ioposix->filenameLength - 1; i >= 0; i -= 1)
{
if (diskFilename[i] != '.')
continue;
snprintf(&diskFilename[i], ioposix->filenameLength - i, ".z%02u", number_disk + 1);
break;
}
if (i >= 0)
ret = fopen_file_func(opaque, diskFilename, mode);
free(diskFilename);
uLong ret;
(void)opaque;
ret = (uLong)fwrite(buf, 1, (size_t)size, (FILE *)stream);
return ret;
}
static uint32_t ZCALLBACK fread_file_func(voidpf opaque, voidpf stream, void* buf, uint32_t size)
static long ZCALLBACK ftell_file_func (voidpf opaque, voidpf stream)
{
FILE_IOPOSIX *ioposix = NULL;
uint32_t read = (uint32_t)-1;
if (stream == NULL)
return read;
ioposix = (FILE_IOPOSIX*)stream;
read = (uint32_t)fread(buf, 1, (size_t)size, ioposix->file);
return read;
}
static uint32_t ZCALLBACK fwrite_file_func(voidpf opaque, voidpf stream, const void *buf, uint32_t size)
{
FILE_IOPOSIX *ioposix = NULL;
uint32_t written = (uint32_t)-1;
if (stream == NULL)
return written;
ioposix = (FILE_IOPOSIX*)stream;
written = (uint32_t)fwrite(buf, 1, (size_t)size, ioposix->file);
return written;
}
static long ZCALLBACK ftell_file_func(voidpf opaque, voidpf stream)
{
FILE_IOPOSIX *ioposix = NULL;
long ret = -1;
if (stream == NULL)
return ret;
ioposix = (FILE_IOPOSIX*)stream;
ret = ftell(ioposix->file);
long ret;
(void)opaque;
ret = ftell((FILE *)stream);
return ret;
}
static uint64_t ZCALLBACK ftell64_file_func(voidpf opaque, voidpf stream)
static ZPOS64_T ZCALLBACK ftell64_file_func (voidpf opaque, voidpf stream)
{
FILE_IOPOSIX *ioposix = NULL;
uint64_t ret = (uint64_t)-1;
if (stream == NULL)
return ret;
ioposix = (FILE_IOPOSIX*)stream;
ret = ftello64(ioposix->file);
ZPOS64_T ret;
(void)opaque;
ret = (ZPOS64_T)FTELLO_FUNC((FILE *)stream);
return ret;
}
static long ZCALLBACK fseek_file_func(voidpf opaque, voidpf stream, uint32_t offset, int origin)
static long ZCALLBACK fseek_file_func (voidpf opaque, voidpf stream, uLong offset, int origin)
{
FILE_IOPOSIX *ioposix = NULL;
int fseek_origin = 0;
long ret = 0;
if (stream == NULL)
return -1;
ioposix = (FILE_IOPOSIX*)stream;
int fseek_origin=0;
long ret;
(void)opaque;
switch (origin)
{
case ZLIB_FILEFUNC_SEEK_CUR:
fseek_origin = SEEK_CUR;
break;
case ZLIB_FILEFUNC_SEEK_END:
fseek_origin = SEEK_END;
break;
case ZLIB_FILEFUNC_SEEK_SET:
fseek_origin = SEEK_SET;
break;
default:
return -1;
case ZLIB_FILEFUNC_SEEK_CUR :
fseek_origin = SEEK_CUR;
break;
case ZLIB_FILEFUNC_SEEK_END :
fseek_origin = SEEK_END;
break;
case ZLIB_FILEFUNC_SEEK_SET :
fseek_origin = SEEK_SET;
break;
default: return -1;
}
if (fseek(ioposix->file, offset, fseek_origin) != 0)
ret = 0;
if (fseek((FILE *)stream, (long)offset, fseek_origin) != 0)
ret = -1;
return ret;
}
static long ZCALLBACK fseek64_file_func(voidpf opaque, voidpf stream, uint64_t offset, int origin)
static long ZCALLBACK fseek64_file_func (voidpf opaque, voidpf stream, ZPOS64_T offset, int origin)
{
FILE_IOPOSIX *ioposix = NULL;
int fseek_origin = 0;
long ret = 0;
if (stream == NULL)
return -1;
ioposix = (FILE_IOPOSIX*)stream;
int fseek_origin=0;
long ret;
(void)opaque;
switch (origin)
{
case ZLIB_FILEFUNC_SEEK_CUR:
fseek_origin = SEEK_CUR;
break;
case ZLIB_FILEFUNC_SEEK_END:
fseek_origin = SEEK_END;
break;
case ZLIB_FILEFUNC_SEEK_SET:
fseek_origin = SEEK_SET;
break;
default:
return -1;
case ZLIB_FILEFUNC_SEEK_CUR :
fseek_origin = SEEK_CUR;
break;
case ZLIB_FILEFUNC_SEEK_END :
fseek_origin = SEEK_END;
break;
case ZLIB_FILEFUNC_SEEK_SET :
fseek_origin = SEEK_SET;
break;
default: return -1;
}
ret = 0;
if (fseeko64(ioposix->file, offset, fseek_origin) != 0)
ret = -1;
if(FSEEKO_FUNC((FILE *)stream, (z_off_t)offset, fseek_origin) != 0)
ret = -1;
return ret;
}
static int ZCALLBACK fclose_file_func(voidpf opaque, voidpf stream)
static int ZCALLBACK fclose_file_func (voidpf opaque, voidpf stream)
{
FILE_IOPOSIX *ioposix = NULL;
int ret = -1;
if (stream == NULL)
return ret;
ioposix = (FILE_IOPOSIX*)stream;
if (ioposix->filename != NULL)
free(ioposix->filename);
ret = fclose(ioposix->file);
free(ioposix);
int ret;
(void)opaque;
ret = fclose((FILE *)stream);
return ret;
}
static int ZCALLBACK ferror_file_func(voidpf opaque, voidpf stream)
static int ZCALLBACK ferror_file_func (voidpf opaque, voidpf stream)
{
FILE_IOPOSIX *ioposix = NULL;
int ret = -1;
if (stream == NULL)
return ret;
ioposix = (FILE_IOPOSIX*)stream;
ret = ferror(ioposix->file);
int ret;
(void)opaque;
ret = ferror((FILE *)stream);
return ret;
}
void fill_fopen_filefunc(zlib_filefunc_def *pzlib_filefunc_def)
void fill_fopen_filefunc (zlib_filefunc_def* pzlib_filefunc_def)
{
pzlib_filefunc_def->zopen_file = fopen_file_func;
pzlib_filefunc_def->zopendisk_file = fopendisk_file_func;
pzlib_filefunc_def->zread_file = fread_file_func;
pzlib_filefunc_def->zwrite_file = fwrite_file_func;
pzlib_filefunc_def->ztell_file = ftell_file_func;
@ -346,10 +243,9 @@ void fill_fopen_filefunc(zlib_filefunc_def *pzlib_filefunc_def)
pzlib_filefunc_def->opaque = NULL;
}
void fill_fopen64_filefunc(zlib_filefunc64_def *pzlib_filefunc_def)
void fill_fopen64_filefunc (zlib_filefunc64_def* pzlib_filefunc_def)
{
pzlib_filefunc_def->zopen64_file = fopen64_file_func;
pzlib_filefunc_def->zopendisk64_file = fopendisk64_file_func;
pzlib_filefunc_def->zread_file = fread_file_func;
pzlib_filefunc_def->zwrite_file = fwrite_file_func;
pzlib_filefunc_def->ztell64_file = ftell64_file_func;
@ -358,10 +254,3 @@ void fill_fopen64_filefunc(zlib_filefunc64_def *pzlib_filefunc_def)
pzlib_filefunc_def->zerror_file = ferror_file_func;
pzlib_filefunc_def->opaque = NULL;
}
#ifdef _MSC_VER
# pragma warning(pop)
# ifdef __clang__
# pragma clang diagnostic pop
# endif
#endif // _MSC_VER

View File

@ -1,142 +1,207 @@
/* ioapi.h -- IO base function header for compress/uncompress .zip
part of the MiniZip project
part of the MiniZip project - ( http://www.winimage.com/zLibDll/minizip.html )
Copyright (C) 1998-2010 Gilles Vollant
http://www.winimage.com/zLibDll/minizip.html
Modifications for Zip64 support
Copyright (C) 2009-2010 Mathias Svensson
http://result42.com
Copyright (C) 1998-2010 Gilles Vollant (minizip) ( http://www.winimage.com/zLibDll/minizip.html )
Modifications for Zip64 support
Copyright (C) 2009-2010 Mathias Svensson ( http://result42.com )
For more info read MiniZip_info.txt
Changes
Oct-2009 - Defined ZPOS64_T to fpos_t on windows and u_int64_t on linux. (might need to find a better why for this)
Oct-2009 - Change to fseeko64, ftello64 and fopen64 so large files would work on linux.
More if/def section may be needed to support other platforms
Oct-2009 - Defined fxxxx64 calls to normal fopen/ftell/fseek so they would compile on windows.
(but you should use iowin32.c for windows instead)
This program is distributed under the terms of the same license as zlib.
See the accompanying LICENSE file for the full text of the license.
*/
#ifndef _ZLIBIOAPI64_H
#define _ZLIBIOAPI64_H
#if (!defined(_WIN32)) && (!defined(WIN32)) && (!defined(__APPLE__))
// Linux needs this to support file operation on files larger then 4+GB
// But might need better if/def to select just the platforms that needs them.
#ifndef __USE_FILE_OFFSET64
#define __USE_FILE_OFFSET64
#endif
#ifndef __USE_LARGEFILE64
#define __USE_LARGEFILE64
#endif
#ifndef _LARGEFILE64_SOURCE
#define _LARGEFILE64_SOURCE
#endif
#ifndef _FILE_OFFSET_BIT
#define _FILE_OFFSET_BIT 64
#endif
#endif
#include <stdio.h>
#include <stdlib.h>
#include <stdint.h>
#include "zlib.h"
#if defined(USE_FILE32API)
# define fopen64 fopen
# define ftello64 ftell
# define fseeko64 fseek
#define fopen64 fopen
#define ftello64 ftell
#define fseeko64 fseek
#else
#if defined(_MSC_VER)
# define fopen64 fopen
# if (_MSC_VER >= 1400) && (!(defined(NO_MSCVER_FILE64_FUNC)))
# define ftello64 _ftelli64
# define fseeko64 _fseeki64
# else /* old MSC */
# define ftello64 ftell
# define fseeko64 fseek
# endif
#else
# define fopen64 fopen
# define ftello64 ftello
# define fseeko64 fseeko
#if defined(__FreeBSD__) || defined(__OpenBSD__) || defined(__NetBSD__)
#define fopen64 fopen
#define ftello64 ftello
#define fseeko64 fseeko
#endif
#ifdef _MSC_VER
#define fopen64 fopen
#if (_MSC_VER >= 1400) && (!(defined(NO_MSCVER_FILE64_FUNC)))
#define ftello64 _ftelli64
#define fseeko64 _fseeki64
#else // old MSC
#define ftello64 ftell
#define fseeko64 fseek
#endif
#endif
#endif
/*
#ifndef ZPOS64_T
#ifdef _WIN32
#define ZPOS64_T fpos_t
#else
#include <stdint.h>
#define ZPOS64_T uint64_t
#endif
#endif
*/
#ifdef HAVE_MINIZIP64_CONF_H
#include "mz64conf.h"
#endif
/* a type choosen by DEFINE */
#ifdef HAVE_64BIT_INT_CUSTOM
typedef 64BIT_INT_CUSTOM_TYPE ZPOS64_T;
#else
#ifdef HAS_STDINT_H
#include "stdint.h"
typedef uint64_t ZPOS64_T;
#else
#if defined(_MSC_VER) || defined(__BORLANDC__)
typedef unsigned __int64 ZPOS64_T;
#else
typedef unsigned long long int ZPOS64_T;
#endif
#endif
#endif
/* Maximum unsigned 32-bit value used as placeholder for zip64 */
#ifndef MAXU32
#define MAXU32 (0xffffffff)
#endif
#ifdef __cplusplus
extern "C" {
#endif
#define ZLIB_FILEFUNC_SEEK_CUR (1)
#define ZLIB_FILEFUNC_SEEK_END (2)
#define ZLIB_FILEFUNC_SEEK_SET (0)
#define ZLIB_FILEFUNC_MODE_READ (1)
#define ZLIB_FILEFUNC_MODE_WRITE (2)
#define ZLIB_FILEFUNC_MODE_READWRITEFILTER (3)
#define ZLIB_FILEFUNC_MODE_EXISTING (4)
#define ZLIB_FILEFUNC_MODE_CREATE (8)
#define ZLIB_FILEFUNC_MODE_READ (1)
#define ZLIB_FILEFUNC_MODE_WRITE (2)
#define ZLIB_FILEFUNC_MODE_READWRITEFILTER (3)
#define ZLIB_FILEFUNC_MODE_EXISTING (4)
#define ZLIB_FILEFUNC_MODE_CREATE (8)
#ifndef ZCALLBACK
# if (defined(WIN32) || defined(_WIN32) || defined (WINDOWS) || \
defined (_WINDOWS)) && defined(CALLBACK) && defined (USEWINDOWS_CALLBACK)
# define ZCALLBACK CALLBACK
# else
# define ZCALLBACK
# endif
#if (defined(WIN32) || defined(_WIN32) || defined (WINDOWS) || defined (_WINDOWS)) && defined(CALLBACK) && defined (USEWINDOWS_CALLBACK)
#define ZCALLBACK CALLBACK
#else
#define ZCALLBACK
#endif
#endif
typedef voidpf (ZCALLBACK *open_file_func) (voidpf opaque, const char *filename, int mode);
typedef voidpf (ZCALLBACK *opendisk_file_func) (voidpf opaque, voidpf stream, uint32_t number_disk, int mode);
typedef uint32_t (ZCALLBACK *read_file_func) (voidpf opaque, voidpf stream, void* buf, uint32_t size);
typedef uint32_t (ZCALLBACK *write_file_func) (voidpf opaque, voidpf stream, const void *buf, uint32_t size);
typedef int (ZCALLBACK *close_file_func) (voidpf opaque, voidpf stream);
typedef int (ZCALLBACK *error_file_func) (voidpf opaque, voidpf stream);
typedef long (ZCALLBACK *tell_file_func) (voidpf opaque, voidpf stream);
typedef long (ZCALLBACK *seek_file_func) (voidpf opaque, voidpf stream, uint32_t offset, int origin);
typedef voidpf (ZCALLBACK *open_file_func) OF((voidpf opaque, const char* filename, int mode));
typedef uLong (ZCALLBACK *read_file_func) OF((voidpf opaque, voidpf stream, void* buf, uLong size));
typedef uLong (ZCALLBACK *write_file_func) OF((voidpf opaque, voidpf stream, const void* buf, uLong size));
typedef int (ZCALLBACK *close_file_func) OF((voidpf opaque, voidpf stream));
typedef int (ZCALLBACK *testerror_file_func) OF((voidpf opaque, voidpf stream));
typedef long (ZCALLBACK *tell_file_func) OF((voidpf opaque, voidpf stream));
typedef long (ZCALLBACK *seek_file_func) OF((voidpf opaque, voidpf stream, uLong offset, int origin));
/* here is the "old" 32 bits structure structure */
typedef struct zlib_filefunc_def_s
{
open_file_func zopen_file;
opendisk_file_func zopendisk_file;
read_file_func zread_file;
write_file_func zwrite_file;
tell_file_func ztell_file;
seek_file_func zseek_file;
close_file_func zclose_file;
error_file_func zerror_file;
testerror_file_func zerror_file;
voidpf opaque;
} zlib_filefunc_def;
typedef uint64_t (ZCALLBACK *tell64_file_func) (voidpf opaque, voidpf stream);
typedef long (ZCALLBACK *seek64_file_func) (voidpf opaque, voidpf stream, uint64_t offset, int origin);
typedef voidpf (ZCALLBACK *open64_file_func) (voidpf opaque, const void *filename, int mode);
typedef voidpf (ZCALLBACK *opendisk64_file_func)(voidpf opaque, voidpf stream, uint32_t number_disk, int mode);
typedef ZPOS64_T (ZCALLBACK *tell64_file_func) OF((voidpf opaque, voidpf stream));
typedef long (ZCALLBACK *seek64_file_func) OF((voidpf opaque, voidpf stream, ZPOS64_T offset, int origin));
typedef voidpf (ZCALLBACK *open64_file_func) OF((voidpf opaque, const void* filename, int mode));
typedef struct zlib_filefunc64_def_s
{
open64_file_func zopen64_file;
opendisk64_file_func zopendisk64_file;
read_file_func zread_file;
write_file_func zwrite_file;
tell64_file_func ztell64_file;
seek64_file_func zseek64_file;
close_file_func zclose_file;
error_file_func zerror_file;
voidpf opaque;
open64_file_func zopen64_file;
read_file_func zread_file;
write_file_func zwrite_file;
tell64_file_func ztell64_file;
seek64_file_func zseek64_file;
close_file_func zclose_file;
testerror_file_func zerror_file;
voidpf opaque;
} zlib_filefunc64_def;
void fill_fopen_filefunc(zlib_filefunc_def *pzlib_filefunc_def);
void fill_fopen64_filefunc(zlib_filefunc64_def *pzlib_filefunc_def);
void fill_fopen64_filefunc OF((zlib_filefunc64_def* pzlib_filefunc_def));
void fill_fopen_filefunc OF((zlib_filefunc_def* pzlib_filefunc_def));
/* now internal definition, only for zip.c and unzip.h */
typedef struct zlib_filefunc64_32_def_s
{
zlib_filefunc64_def zfile_func64;
open_file_func zopen32_file;
opendisk_file_func zopendisk32_file;
tell_file_func ztell32_file;
seek_file_func zseek32_file;
} zlib_filefunc64_32_def;
#define ZREAD64(filefunc,filestream,buf,size) ((*((filefunc).zfile_func64.zread_file)) ((filefunc).zfile_func64.opaque,filestream,buf,size))
#define ZWRITE64(filefunc,filestream,buf,size) ((*((filefunc).zfile_func64.zwrite_file)) ((filefunc).zfile_func64.opaque,filestream,buf,size))
/*#define ZTELL64(filefunc,filestream) ((*((filefunc).ztell64_file)) ((filefunc).opaque,filestream))*/
/*#define ZSEEK64(filefunc,filestream,pos,mode) ((*((filefunc).zseek64_file)) ((filefunc).opaque,filestream,pos,mode))*/
#define ZCLOSE64(filefunc,filestream) ((*((filefunc).zfile_func64.zclose_file)) ((filefunc).zfile_func64.opaque,filestream))
#define ZERROR64(filefunc,filestream) ((*((filefunc).zfile_func64.zerror_file)) ((filefunc).zfile_func64.opaque,filestream))
voidpf call_zopen64(const zlib_filefunc64_32_def *pfilefunc,const void*filename, int mode);
voidpf call_zopendisk64(const zlib_filefunc64_32_def *pfilefunc, voidpf filestream, uint32_t number_disk, int mode);
long call_zseek64(const zlib_filefunc64_32_def *pfilefunc, voidpf filestream, uint64_t offset, int origin);
uint64_t call_ztell64(const zlib_filefunc64_32_def *pfilefunc, voidpf filestream);
#define ZREAD64(filefunc,filestream,buf,size) ((*((filefunc).zfile_func64.zread_file)) ((filefunc).zfile_func64.opaque,filestream,buf,size))
#define ZWRITE64(filefunc,filestream,buf,size) ((*((filefunc).zfile_func64.zwrite_file)) ((filefunc).zfile_func64.opaque,filestream,buf,size))
//#define ZTELL64(filefunc,filestream) ((*((filefunc).ztell64_file)) ((filefunc).opaque,filestream))
//#define ZSEEK64(filefunc,filestream,pos,mode) ((*((filefunc).zseek64_file)) ((filefunc).opaque,filestream,pos,mode))
#define ZCLOSE64(filefunc,filestream) ((*((filefunc).zfile_func64.zclose_file)) ((filefunc).zfile_func64.opaque,filestream))
#define ZERROR64(filefunc,filestream) ((*((filefunc).zfile_func64.zerror_file)) ((filefunc).zfile_func64.opaque,filestream))
void fill_zlib_filefunc64_32_def_from_filefunc32(zlib_filefunc64_32_def *p_filefunc64_32, const zlib_filefunc_def *p_filefunc32);
voidpf call_zopen64 OF((const zlib_filefunc64_32_def* pfilefunc,const void*filename,int mode));
long call_zseek64 OF((const zlib_filefunc64_32_def* pfilefunc,voidpf filestream, ZPOS64_T offset, int origin));
ZPOS64_T call_ztell64 OF((const zlib_filefunc64_32_def* pfilefunc,voidpf filestream));
#define ZOPEN64(filefunc,filename,mode) (call_zopen64((&(filefunc)),(filename),(mode)))
#define ZOPENDISK64(filefunc,filestream,diskn,mode) (call_zopendisk64((&(filefunc)),(filestream),(diskn),(mode)))
#define ZTELL64(filefunc,filestream) (call_ztell64((&(filefunc)),(filestream)))
#define ZSEEK64(filefunc,filestream,pos,mode) (call_zseek64((&(filefunc)),(filestream),(pos),(mode)))
void fill_zlib_filefunc64_32_def_from_filefunc32(zlib_filefunc64_32_def* p_filefunc64_32,const zlib_filefunc_def* p_filefunc32);
#define ZOPEN64(filefunc,filename,mode) (call_zopen64((&(filefunc)),(filename),(mode)))
#define ZTELL64(filefunc,filestream) (call_ztell64((&(filefunc)),(filestream)))
#define ZSEEK64(filefunc,filestream,pos,mode) (call_zseek64((&(filefunc)),(filestream),(pos),(mode)))
#ifdef __cplusplus
}

File diff suppressed because it is too large Load Diff

View File

@ -1,21 +1,47 @@
/* unzip.h -- IO for uncompress .zip files using zlib
Version 1.1, February 14h, 2010
part of the MiniZip project
part of the MiniZip project - ( http://www.winimage.com/zLibDll/minizip.html )
Copyright (C) 1998-2010 Gilles Vollant
http://www.winimage.com/zLibDll/minizip.html
Modifications of Unzip for Zip64
Copyright (C) 2007-2008 Even Rouault
Modifications for Zip64 support on both zip and unzip
Copyright (C) 2009-2010 Mathias Svensson
http://result42.com
Copyright (C) 1998-2010 Gilles Vollant (minizip) ( http://www.winimage.com/zLibDll/minizip.html )
Modifications of Unzip for Zip64
Copyright (C) 2007-2008 Even Rouault
Modifications for Zip64 support on both zip and unzip
Copyright (C) 2009-2010 Mathias Svensson ( http://result42.com )
For more info read MiniZip_info.txt
---------------------------------------------------------------------------------
Condition of use and distribution are the same than zlib :
This software is provided 'as-is', without any express or implied
warranty. In no event will the authors be held liable for any damages
arising from the use of this software.
Permission is granted to anyone to use this software for any purpose,
including commercial applications, and to alter it and redistribute it
freely, subject to the following restrictions:
1. The origin of this software must not be misrepresented; you must not
claim that you wrote the original software. If you use this software
in a product, an acknowledgment in the product documentation would be
appreciated but is not required.
2. Altered source versions must be plainly marked as such, and must not be
misrepresented as being the original software.
3. This notice may not be removed or altered from any source distribution.
---------------------------------------------------------------------------------
Changes
See header of unzip64.c
This program is distributed under the terms of the same license as zlib.
See the accompanying LICENSE file for the full text of the license.
*/
#ifndef _UNZ_H
#define _UNZ_H
#ifndef _unz64_H
#define _unz64_H
#ifdef __cplusplus
extern "C" {
@ -25,7 +51,7 @@ extern "C" {
#include "zlib.h"
#endif
#ifndef _ZLIBIOAPI_H
#ifndef _ZLIBIOAPI_H
#include "ioapi.h"
#endif
@ -38,12 +64,13 @@ extern "C" {
#if defined(STRICTUNZIP) || defined(STRICTZIPUNZIP)
/* like the STRICT of WIN32, we define a pointer that cannot be converted
from (void*) without cast */
typedef struct TagunzFile__ { int unused; } unz_file__;
typedef unz_file__ *unzFile;
typedef struct TagunzFile__ { int unused; } unzFile__;
typedef unzFile__ *unzFile;
#else
typedef voidp unzFile;
#endif
#define UNZ_OK (0)
#define UNZ_END_OF_LIST_OF_FILE (-100)
#define UNZ_ERRNO (Z_ERRNO)
@ -52,255 +79,359 @@ typedef voidp unzFile;
#define UNZ_BADZIPFILE (-103)
#define UNZ_INTERNALERROR (-104)
#define UNZ_CRCERROR (-105)
#define UNZ_BADPASSWORD (-106)
/* tm_unz contain date/time info */
typedef struct tm_unz_s
{
int tm_sec; /* seconds after the minute - [0,59] */
int tm_min; /* minutes after the hour - [0,59] */
int tm_hour; /* hours since midnight - [0,23] */
int tm_mday; /* day of the month - [1,31] */
int tm_mon; /* months since January - [0,11] */
int tm_year; /* years - [1980..2044] */
} tm_unz;
/* unz_global_info structure contain global data about the ZIPfile
These data comes from the end of central dir */
typedef struct unz_global_info64_s
{
uint64_t number_entry; /* total number of entries in the central dir on this disk */
uint32_t number_disk_with_CD; /* number the the disk with central dir, used for spanning ZIP*/
uint16_t size_comment; /* size of the global comment of the zipfile */
ZPOS64_T number_entry; /* total number of entries in
the central dir on this disk */
uLong size_comment; /* size of the global comment of the zipfile */
} unz_global_info64;
typedef struct unz_global_info_s
{
uint32_t number_entry; /* total number of entries in the central dir on this disk */
uint32_t number_disk_with_CD; /* number the the disk with central dir, used for spanning ZIP*/
uint16_t size_comment; /* size of the global comment of the zipfile */
uLong number_entry; /* total number of entries in
the central dir on this disk */
uLong size_comment; /* size of the global comment of the zipfile */
} unz_global_info;
/* unz_file_info contain information about a file in the zipfile */
typedef struct unz_file_info64_s
{
uint16_t version; /* version made by 2 bytes */
uint16_t version_needed; /* version needed to extract 2 bytes */
uint16_t flag; /* general purpose bit flag 2 bytes */
uint16_t compression_method; /* compression method 2 bytes */
uint32_t dos_date; /* last mod file date in Dos fmt 4 bytes */
uint32_t crc; /* crc-32 4 bytes */
uint64_t compressed_size; /* compressed size 8 bytes */
uint64_t uncompressed_size; /* uncompressed size 8 bytes */
uint16_t size_filename; /* filename length 2 bytes */
uint16_t size_file_extra; /* extra field length 2 bytes */
uint16_t size_file_comment; /* file comment length 2 bytes */
uLong version; /* version made by 2 bytes */
uLong version_needed; /* version needed to extract 2 bytes */
uLong flag; /* general purpose bit flag 2 bytes */
uLong compression_method; /* compression method 2 bytes */
uLong dosDate; /* last mod file date in Dos fmt 4 bytes */
uLong crc; /* crc-32 4 bytes */
ZPOS64_T compressed_size; /* compressed size 8 bytes */
ZPOS64_T uncompressed_size; /* uncompressed size 8 bytes */
uLong size_filename; /* filename length 2 bytes */
uLong size_file_extra; /* extra field length 2 bytes */
uLong size_file_comment; /* file comment length 2 bytes */
uint32_t disk_num_start; /* disk number start 4 bytes */
uint16_t internal_fa; /* internal file attributes 2 bytes */
uint32_t external_fa; /* external file attributes 4 bytes */
uLong disk_num_start; /* disk number start 2 bytes */
uLong internal_fa; /* internal file attributes 2 bytes */
uLong external_fa; /* external file attributes 4 bytes */
uint64_t disk_offset;
uint16_t size_file_extra_internal;
tm_unz tmu_date;
} unz_file_info64;
typedef struct unz_file_info_s
{
uint16_t version; /* version made by 2 bytes */
uint16_t version_needed; /* version needed to extract 2 bytes */
uint16_t flag; /* general purpose bit flag 2 bytes */
uint16_t compression_method; /* compression method 2 bytes */
uint32_t dos_date; /* last mod file date in Dos fmt 4 bytes */
uint32_t crc; /* crc-32 4 bytes */
uint32_t compressed_size; /* compressed size 4 bytes */
uint32_t uncompressed_size; /* uncompressed size 4 bytes */
uint16_t size_filename; /* filename length 2 bytes */
uint16_t size_file_extra; /* extra field length 2 bytes */
uint16_t size_file_comment; /* file comment length 2 bytes */
uLong version; /* version made by 2 bytes */
uLong version_needed; /* version needed to extract 2 bytes */
uLong flag; /* general purpose bit flag 2 bytes */
uLong compression_method; /* compression method 2 bytes */
uLong dosDate; /* last mod file date in Dos fmt 4 bytes */
uLong crc; /* crc-32 4 bytes */
uLong compressed_size; /* compressed size 4 bytes */
uLong uncompressed_size; /* uncompressed size 4 bytes */
uLong size_filename; /* filename length 2 bytes */
uLong size_file_extra; /* extra field length 2 bytes */
uLong size_file_comment; /* file comment length 2 bytes */
uint16_t disk_num_start; /* disk number start 2 bytes */
uint16_t internal_fa; /* internal file attributes 2 bytes */
uint32_t external_fa; /* external file attributes 4 bytes */
uLong disk_num_start; /* disk number start 2 bytes */
uLong internal_fa; /* internal file attributes 2 bytes */
uLong external_fa; /* external file attributes 4 bytes */
uint64_t disk_offset;
tm_unz tmu_date;
} unz_file_info;
/***************************************************************************/
/* Opening and close a zip file */
extern int ZEXPORT unzStringFileNameCompare OF ((const char* fileName1,
const char* fileName2,
int iCaseSensitivity));
/*
Compare two filename (fileName1,fileName2).
If iCaseSenisivity = 1, comparision is case sensitivity (like strcmp)
If iCaseSenisivity = 2, comparision is not case sensitivity (like strcmpi
or strcasecmp)
If iCaseSenisivity = 0, case sensitivity is defaut of your operating system
(like 1 on Unix, 2 on Windows)
*/
extern unzFile ZEXPORT unzOpen(const char *path);
extern unzFile ZEXPORT unzOpen64(const void *path);
/* Open a Zip file.
path should contain the full path (by example, on a Windows XP computer
"c:\\zlib\\zlib113.zip" or on an Unix computer "zlib/zlib113.zip".
return NULL if zipfile cannot be opened or doesn't exist
return unzFile handle if no error
extern unzFile ZEXPORT unzOpen OF((const char *path));
extern unzFile ZEXPORT unzOpen64 OF((const void *path));
/*
Open a Zip file. path contain the full pathname (by example,
on a Windows XP computer "c:\\zlib\\zlib113.zip" or on an Unix computer
"zlib/zlib113.zip".
If the zipfile cannot be opened (file don't exist or in not valid), the
return value is NULL.
Else, the return value is a unzFile Handle, usable with other function
of this unzip package.
the "64" function take a const void* pointer, because the path is just the
value passed to the open64_file_func callback.
Under Windows, if UNICODE is defined, using fill_fopen64_filefunc, the path
is a pointer to a wide unicode string (LPCTSTR is LPCWSTR), so const char*
does not describe the reality
*/
NOTE: The "64" function take a const void *pointer, because the path is just the value passed to the
open64_file_func callback. Under Windows, if UNICODE is defined, using fill_fopen64_filefunc, the path
is a pointer to a wide unicode string (LPCTSTR is LPCWSTR), so const char *does not describe the reality */
extern unzFile ZEXPORT unzOpen2(const char *path, zlib_filefunc_def *pzlib_filefunc_def);
/* Open a Zip file, like unzOpen, but provide a set of file low level API for read/write operations */
extern unzFile ZEXPORT unzOpen2_64(const void *path, zlib_filefunc64_def *pzlib_filefunc_def);
/* Open a Zip file, like unz64Open, but provide a set of file low level API for read/write 64-bit operations */
extern unzFile ZEXPORT unzOpen2 OF((const char *path,
zlib_filefunc_def* pzlib_filefunc_def));
/*
Open a Zip file, like unzOpen, but provide a set of file low level API
for read/write the zip file (see ioapi.h)
*/
extern int ZEXPORT unzClose(unzFile file);
/* Close a ZipFile opened with unzOpen. If there is files inside the .Zip opened with unzOpenCurrentFile,
these files MUST be closed with unzipCloseCurrentFile before call unzipClose.
extern unzFile ZEXPORT unzOpen2_64 OF((const void *path,
zlib_filefunc64_def* pzlib_filefunc_def));
/*
Open a Zip file, like unz64Open, but provide a set of file low level API
for read/write the zip file (see ioapi.h)
*/
return UNZ_OK if there is no error */
extern int ZEXPORT unzClose OF((unzFile file));
/*
Close a ZipFile opened with unzOpen.
If there is files inside the .Zip opened with unzOpenCurrentFile (see later),
these files MUST be closed with unzCloseCurrentFile before call unzClose.
return UNZ_OK if there is no problem. */
extern int ZEXPORT unzGetGlobalInfo(unzFile file, unz_global_info *pglobal_info);
extern int ZEXPORT unzGetGlobalInfo64(unzFile file, unz_global_info64 *pglobal_info);
/* Write info about the ZipFile in the *pglobal_info structure.
extern int ZEXPORT unzGetGlobalInfo OF((unzFile file,
unz_global_info *pglobal_info));
return UNZ_OK if no error */
extern int ZEXPORT unzGetGlobalInfo64 OF((unzFile file,
unz_global_info64 *pglobal_info));
/*
Write info about the ZipFile in the *pglobal_info structure.
No preparation of the structure is needed
return UNZ_OK if there is no problem. */
extern int ZEXPORT unzGetGlobalComment(unzFile file, char *comment, uint16_t comment_size);
/* Get the global comment string of the ZipFile, in the comment buffer.
uSizeBuf is the size of the szComment buffer.
return the number of byte copied or an error code <0 */
extern int ZEXPORT unzGetGlobalComment OF((unzFile file,
char *szComment,
uLong uSizeBuf));
/*
Get the global comment string of the ZipFile, in the szComment buffer.
uSizeBuf is the size of the szComment buffer.
return the number of byte copied or an error code <0
*/
/***************************************************************************/
/* Reading the content of the current zipfile, you can open it, read data from it, and close it
(you can close it before reading all the file) */
/* Unzip package allow you browse the directory of the zipfile */
extern int ZEXPORT unzOpenCurrentFile(unzFile file);
/* Open for reading data the current file in the zipfile.
extern int ZEXPORT unzGoToFirstFile OF((unzFile file));
/*
Set the current file of the zipfile to the first file.
return UNZ_OK if there is no problem
*/
return UNZ_OK if no error */
extern int ZEXPORT unzGoToNextFile OF((unzFile file));
/*
Set the current file of the zipfile to the next file.
return UNZ_OK if there is no problem
return UNZ_END_OF_LIST_OF_FILE if the actual file was the latest.
*/
extern int ZEXPORT unzOpenCurrentFilePassword(unzFile file, const char *password);
/* Open for reading data the current file in the zipfile.
password is a crypting password
extern int ZEXPORT unzLocateFile OF((unzFile file,
const char *szFileName,
int iCaseSensitivity));
/*
Try locate the file szFileName in the zipfile.
For the iCaseSensitivity signification, see unzStringFileNameCompare
return UNZ_OK if no error */
return value :
UNZ_OK if the file is found. It becomes the current file.
UNZ_END_OF_LIST_OF_FILE if the file is not found
*/
extern int ZEXPORT unzOpenCurrentFile2(unzFile file, int *method, int *level, int raw);
/* Same as unzOpenCurrentFile, but open for read raw the file (not uncompress)
if raw==1 *method will receive method of compression, *level will receive level of compression
NOTE: you can set level parameter as NULL (if you did not want known level,
but you CANNOT set method parameter as NULL */
extern int ZEXPORT unzOpenCurrentFile3(unzFile file, int *method, int *level, int raw, const char *password);
/* Same as unzOpenCurrentFile, but takes extra parameter password for encrypted files */
extern int ZEXPORT unzReadCurrentFile(unzFile file, voidp buf, uint32_t len);
/* Read bytes from the current file (opened by unzOpenCurrentFile)
buf contain buffer where data must be copied
len the size of buf.
return the number of byte copied if somes bytes are copied
return 0 if the end of file was reached
return <0 with error code if there is an error (UNZ_ERRNO for IO error, or zLib error for uncompress error) */
extern int ZEXPORT unzGetCurrentFileInfo(unzFile file, unz_file_info *pfile_info, char *filename,
uint16_t filename_size, void *extrafield, uint16_t extrafield_size, char *comment, uint16_t comment_size);
extern int ZEXPORT unzGetCurrentFileInfo64(unzFile file, unz_file_info64 *pfile_info, char *filename,
uint16_t filename_size, void *extrafield, uint16_t extrafield_size, char *comment, uint16_t comment_size);
/* Get Info about the current file
pfile_info if != NULL, the *pfile_info structure will contain somes info about the current file
filename if != NULL, the file name string will be copied in filename
filename_size is the size of the filename buffer
extrafield if != NULL, the extra field information from the central header will be copied in to
extrafield_size is the size of the extraField buffer
comment if != NULL, the comment string of the file will be copied in to
comment_size is the size of the comment buffer */
extern int ZEXPORT unzGetLocalExtrafield(unzFile file, voidp buf, uint32_t len);
/* Read extra field from the current file (opened by unzOpenCurrentFile)
This is the local-header version of the extra field (sometimes, there is
more info in the local-header version than in the central-header)
if buf == NULL, it return the size of the local extra field
if buf != NULL, len is the size of the buffer, the extra header is copied in buf.
return number of bytes copied in buf, or (if <0) the error code */
extern int ZEXPORT unzCloseCurrentFile(unzFile file);
/* Close the file in zip opened with unzOpenCurrentFile
return UNZ_CRCERROR if all the file was read but the CRC is not good */
/***************************************************************************/
/* Browse the directory of the zipfile */
typedef int (*unzFileNameComparer)(unzFile file, const char *filename1, const char *filename2);
typedef int (*unzIteratorFunction)(unzFile file);
typedef int (*unzIteratorFunction2)(unzFile file, unz_file_info64 *pfile_info, char *filename,
uint16_t filename_size, void *extrafield, uint16_t extrafield_size, char *comment, uint16_t comment_size);
extern int ZEXPORT unzGoToFirstFile(unzFile file);
/* Set the current file of the zipfile to the first file.
return UNZ_OK if no error */
extern int ZEXPORT unzGoToFirstFile2(unzFile file, unz_file_info64 *pfile_info, char *filename,
uint16_t filename_size, void *extrafield, uint16_t extrafield_size, char *comment, uint16_t comment_size);
/* Set the current file of the zipfile to the first file and retrieves the current info on success.
Not as seek intensive as unzGoToFirstFile + unzGetCurrentFileInfo.
return UNZ_OK if no error */
extern int ZEXPORT unzGoToNextFile(unzFile file);
/* Set the current file of the zipfile to the next file.
return UNZ_OK if no error
return UNZ_END_OF_LIST_OF_FILE if the actual file was the latest */
extern int ZEXPORT unzGoToNextFile2(unzFile file, unz_file_info64 *pfile_info, char *filename,
uint16_t filename_size, void *extrafield, uint16_t extrafield_size, char *comment, uint16_t comment_size);
/* Set the current file of the zipfile to the next file and retrieves the current
info on success. Does less seeking around than unzGotoNextFile + unzGetCurrentFileInfo.
return UNZ_OK if no error
return UNZ_END_OF_LIST_OF_FILE if the actual file was the latest */
extern int ZEXPORT unzLocateFile(unzFile file, const char *filename, unzFileNameComparer filename_compare_func);
/* Try locate the file szFileName in the zipfile. For custom filename comparison pass in comparison function.
return UNZ_OK if the file is found (it becomes the current file)
return UNZ_END_OF_LIST_OF_FILE if the file is not found */
/***************************************************************************/
/* Raw access to zip file */
/* ****************************************** */
/* Ryan supplied functions */
/* unz_file_info contain information about a file in the zipfile */
typedef struct unz_file_pos_s
{
uint32_t pos_in_zip_directory; /* offset in zip file directory */
uint32_t num_of_file; /* # of file */
uLong pos_in_zip_directory; /* offset in zip file directory */
uLong num_of_file; /* # of file */
} unz_file_pos;
extern int ZEXPORT unzGetFilePos(unzFile file, unz_file_pos *file_pos);
extern int ZEXPORT unzGoToFilePos(unzFile file, unz_file_pos *file_pos);
extern int ZEXPORT unzGetFilePos(
unzFile file,
unz_file_pos* file_pos);
extern int ZEXPORT unzGoToFilePos(
unzFile file,
unz_file_pos* file_pos);
typedef struct unz64_file_pos_s
{
uint64_t pos_in_zip_directory; /* offset in zip file directory */
uint64_t num_of_file; /* # of file */
ZPOS64_T pos_in_zip_directory; /* offset in zip file directory */
ZPOS64_T num_of_file; /* # of file */
} unz64_file_pos;
extern int ZEXPORT unzGetFilePos64(unzFile file, unz64_file_pos *file_pos);
extern int ZEXPORT unzGoToFilePos64(unzFile file, const unz64_file_pos *file_pos);
extern int ZEXPORT unzGetFilePos64(
unzFile file,
unz64_file_pos* file_pos);
extern int32_t ZEXPORT unzGetOffset(unzFile file);
extern int64_t ZEXPORT unzGetOffset64(unzFile file);
/* Get the current file offset */
extern int ZEXPORT unzGoToFilePos64(
unzFile file,
const unz64_file_pos* file_pos);
extern int ZEXPORT unzSetOffset(unzFile file, uint32_t pos);
extern int ZEXPORT unzSetOffset64(unzFile file, uint64_t pos);
/* Set the current file offset */
/* ****************************************** */
extern int32_t ZEXPORT unzTell(unzFile file);
extern int64_t ZEXPORT unzTell64(unzFile file);
/* return current position in uncompressed data */
extern int ZEXPORT unzGetCurrentFileInfo64 OF((unzFile file,
unz_file_info64 *pfile_info,
char *szFileName,
uLong fileNameBufferSize,
void *extraField,
uLong extraFieldBufferSize,
char *szComment,
uLong commentBufferSize));
extern int ZEXPORT unzSeek(unzFile file, uint32_t offset, int origin);
extern int ZEXPORT unzSeek64(unzFile file, uint64_t offset, int origin);
/* Seek within the uncompressed data if compression method is storage */
extern int ZEXPORT unzGetCurrentFileInfo OF((unzFile file,
unz_file_info *pfile_info,
char *szFileName,
uLong fileNameBufferSize,
void *extraField,
uLong extraFieldBufferSize,
char *szComment,
uLong commentBufferSize));
/*
Get Info about the current file
if pfile_info!=NULL, the *pfile_info structure will contain somes info about
the current file
if szFileName!=NULL, the filemane string will be copied in szFileName
(fileNameBufferSize is the size of the buffer)
if extraField!=NULL, the extra field information will be copied in extraField
(extraFieldBufferSize is the size of the buffer).
This is the Central-header version of the extra field
if szComment!=NULL, the comment string of the file will be copied in szComment
(commentBufferSize is the size of the buffer)
*/
/** Addition for GDAL : START */
extern ZPOS64_T ZEXPORT unzGetCurrentFileZStreamPos64 OF((unzFile file));
/** Addition for GDAL : END */
extern int ZEXPORT unzEndOfFile(unzFile file);
/* return 1 if the end of file was reached, 0 elsewhere */
/***************************************************************************/
/* for reading the content of the current zipfile, you can open it, read data
from it, and close it (you can close it before reading all the file)
*/
extern int ZEXPORT unzOpenCurrentFile OF((unzFile file));
/*
Open for reading data the current file in the zipfile.
If there is no error, the return value is UNZ_OK.
*/
extern int ZEXPORT unzOpenCurrentFilePassword OF((unzFile file,
const char* password));
/*
Open for reading data the current file in the zipfile.
password is a crypting password
If there is no error, the return value is UNZ_OK.
*/
extern int ZEXPORT unzOpenCurrentFile2 OF((unzFile file,
int* method,
int* level,
int raw));
/*
Same than unzOpenCurrentFile, but open for read raw the file (not uncompress)
if raw==1
*method will receive method of compression, *level will receive level of
compression
note : you can set level parameter as NULL (if you did not want known level,
but you CANNOT set method parameter as NULL
*/
extern int ZEXPORT unzOpenCurrentFile3 OF((unzFile file,
int* method,
int* level,
int raw,
const char* password));
/*
Same than unzOpenCurrentFile, but open for read raw the file (not uncompress)
if raw==1
*method will receive method of compression, *level will receive level of
compression
note : you can set level parameter as NULL (if you did not want known level,
but you CANNOT set method parameter as NULL
*/
extern int ZEXPORT unzCloseCurrentFile OF((unzFile file));
/*
Close the file in zip opened with unzOpenCurrentFile
Return UNZ_CRCERROR if all the file was read but the CRC is not good
*/
extern int ZEXPORT unzReadCurrentFile OF((unzFile file,
voidp buf,
unsigned len));
/*
Read bytes from the current file (opened by unzOpenCurrentFile)
buf contain buffer where data must be copied
len the size of buf.
return the number of byte copied if somes bytes are copied
return 0 if the end of file was reached
return <0 with error code if there is an error
(UNZ_ERRNO for IO error, or zLib error for uncompress error)
*/
extern z_off_t ZEXPORT unztell OF((unzFile file));
extern ZPOS64_T ZEXPORT unztell64 OF((unzFile file));
/*
Give the current position in uncompressed data
*/
extern int ZEXPORT unzeof OF((unzFile file));
/*
return 1 if the end of file was reached, 0 elsewhere
*/
extern int ZEXPORT unzGetLocalExtrafield OF((unzFile file,
voidp buf,
unsigned len));
/*
Read extra field from the current file (opened by unzOpenCurrentFile)
This is the local-header version of the extra field (sometimes, there is
more info in the local-header version than in the central-header)
if buf==NULL, it return the size of the local extra field
if buf!=NULL, len is the size of the buffer, the extra header is copied in
buf.
the return value is the number of bytes copied in buf, or (if <0)
the error code
*/
/***************************************************************************/
/* Get the current file offset */
extern ZPOS64_T ZEXPORT unzGetOffset64 (unzFile file);
extern uLong ZEXPORT unzGetOffset (unzFile file);
/* Set the current file offset */
extern int ZEXPORT unzSetOffset64 (unzFile file, ZPOS64_T pos);
extern int ZEXPORT unzSetOffset (unzFile file, uLong pos);
#ifdef __cplusplus
}
#endif
#endif /* _UNZ_H */
#endif /* _unz64_H */

View File

@ -0,0 +1,23 @@
Boost Software License - Version 1.0 - August 17th, 2003
Permission is hereby granted, free of charge, to any person or organization
obtaining a copy of the software and accompanying documentation covered by
this license (the "Software") to use, reproduce, display, distribute,
execute, and transmit the Software, and to prepare derivative works of the
Software, and to permit third-parties to whom the Software is furnished to
do so, all subject to the following:
The copyright notices in the Software and this entire statement, including
the above license grant, this restriction and the following disclaimer,
must be included in all copies of the Software, in whole or in part, and
all derivative works of the Software, unless such copies or derivative
works are solely in the form of machine-executable object code generated by
a source language processor.
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, TITLE AND NON-INFRINGEMENT. IN NO EVENT
SHALL THE COPYRIGHT HOLDERS OR ANYONE DISTRIBUTING THE SOFTWARE BE LIABLE
FOR ANY DAMAGES OR OTHER LIABILITY, WHETHER IN CONTRACT, TORT OR OTHERWISE,
ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
DEALINGS IN THE SOFTWARE.

File diff suppressed because it is too large Load Diff

View File

@ -1,12 +0,0 @@
utf8 cpp library
Release 2.3.4
A minor bug fix release. Thanks to all who reported bugs.
Note: Version 2.3.3 contained a regression, and therefore was removed.
Changes from version 2.3.2
- Bug fix [39]: checked.h Line 273 and unchecked.h Line 182 have an extra ';'
- Bug fix [36]: replace_invalid() only works with back_inserter
Files included in the release: utf8.h, core.h, checked.h, unchecked.h, utf8cpp.html, ReleaseNotes

File diff suppressed because it is too large Load Diff

View File

@ -42,7 +42,7 @@ namespace utf8
uint32_t cp;
public:
invalid_code_point(uint32_t codepoint) : cp(codepoint) {}
virtual const char* what() const NOEXCEPT OVERRIDE { return "Invalid code point"; }
virtual const char* what() const UTF_CPP_NOEXCEPT UTF_CPP_OVERRIDE { return "Invalid code point"; }
uint32_t code_point() const {return cp;}
};
@ -50,7 +50,8 @@ namespace utf8
uint8_t u8;
public:
invalid_utf8 (uint8_t u) : u8(u) {}
virtual const char* what() const NOEXCEPT OVERRIDE { return "Invalid UTF-8"; }
invalid_utf8 (char c) : u8(static_cast<uint8_t>(c)) {}
virtual const char* what() const UTF_CPP_NOEXCEPT UTF_CPP_OVERRIDE { return "Invalid UTF-8"; }
uint8_t utf8_octet() const {return u8;}
};
@ -58,13 +59,13 @@ namespace utf8
uint16_t u16;
public:
invalid_utf16 (uint16_t u) : u16(u) {}
virtual const char* what() const NOEXCEPT OVERRIDE { return "Invalid UTF-16"; }
virtual const char* what() const UTF_CPP_NOEXCEPT UTF_CPP_OVERRIDE { return "Invalid UTF-16"; }
uint16_t utf16_word() const {return u16;}
};
class not_enough_room : public exception {
public:
virtual const char* what() const NOEXCEPT OVERRIDE { return "Not enough space"; }
virtual const char* what() const UTF_CPP_NOEXCEPT UTF_CPP_OVERRIDE { return "Not enough space"; }
};
/// The library API - functions intended to be called by the users
@ -75,24 +76,7 @@ namespace utf8
if (!utf8::internal::is_code_point_valid(cp))
throw invalid_code_point(cp);
if (cp < 0x80) // one octet
*(result++) = static_cast<uint8_t>(cp);
else if (cp < 0x800) { // two octets
*(result++) = static_cast<uint8_t>((cp >> 6) | 0xc0);
*(result++) = static_cast<uint8_t>((cp & 0x3f) | 0x80);
}
else if (cp < 0x10000) { // three octets
*(result++) = static_cast<uint8_t>((cp >> 12) | 0xe0);
*(result++) = static_cast<uint8_t>(((cp >> 6) & 0x3f) | 0x80);
*(result++) = static_cast<uint8_t>((cp & 0x3f) | 0x80);
}
else { // four octets
*(result++) = static_cast<uint8_t>((cp >> 18) | 0xf0);
*(result++) = static_cast<uint8_t>(((cp >> 12) & 0x3f) | 0x80);
*(result++) = static_cast<uint8_t>(((cp >> 6) & 0x3f) | 0x80);
*(result++) = static_cast<uint8_t>((cp & 0x3f) | 0x80);
}
return result;
return internal::append(cp, result);
}
template <typename octet_iterator, typename output_iterator>
@ -148,7 +132,7 @@ namespace utf8
case internal::INVALID_LEAD :
case internal::INCOMPLETE_SEQUENCE :
case internal::OVERLONG_SEQUENCE :
throw invalid_utf8(*it);
throw invalid_utf8(static_cast<uint8_t>(*it));
case internal::INVALID_CODE_POINT :
throw invalid_code_point(cp);
}
@ -325,7 +309,9 @@ namespace utf8
} // namespace utf8
#if UTF_CPP_CPLUSPLUS >= 201103L // C++ 11 or later
#if UTF_CPP_CPLUSPLUS >= 201703L // C++ 17 or later
#include "cpp17.h"
#elif UTF_CPP_CPLUSPLUS >= 201103L // C++ 11 or later
#include "cpp11.h"
#endif // C++ 11 or later

View File

@ -39,11 +39,11 @@ DEALINGS IN THE SOFTWARE.
#endif
#if UTF_CPP_CPLUSPLUS >= 201103L // C++ 11 or later
#define OVERRIDE override
#define NOEXCEPT noexcept
#define UTF_CPP_OVERRIDE override
#define UTF_CPP_NOEXCEPT noexcept
#else // C++ 98/03
#define OVERRIDE
#define NOEXCEPT throw()
#define UTF_CPP_OVERRIDE
#define UTF_CPP_NOEXCEPT throw()
#endif // C++ 11 or later
@ -297,6 +297,55 @@ namespace internal
return utf8::internal::validate_next(it, end, ignored);
}
// Internal implementation of both checked and unchecked append() function
// This function will be invoked by the overloads below, as they will know
// the octet_type.
template <typename octet_iterator, typename octet_type>
octet_iterator append(uint32_t cp, octet_iterator result) {
if (cp < 0x80) // one octet
*(result++) = static_cast<octet_type>(cp);
else if (cp < 0x800) { // two octets
*(result++) = static_cast<octet_type>((cp >> 6) | 0xc0);
*(result++) = static_cast<octet_type>((cp & 0x3f) | 0x80);
}
else if (cp < 0x10000) { // three octets
*(result++) = static_cast<octet_type>((cp >> 12) | 0xe0);
*(result++) = static_cast<octet_type>(((cp >> 6) & 0x3f) | 0x80);
*(result++) = static_cast<octet_type>((cp & 0x3f) | 0x80);
}
else { // four octets
*(result++) = static_cast<octet_type>((cp >> 18) | 0xf0);
*(result++) = static_cast<octet_type>(((cp >> 12) & 0x3f)| 0x80);
*(result++) = static_cast<octet_type>(((cp >> 6) & 0x3f) | 0x80);
*(result++) = static_cast<octet_type>((cp & 0x3f) | 0x80);
}
return result;
}
// One of the following overloads will be invoked from the API calls
// A simple (but dangerous) case: the caller appends byte(s) to a char array
inline char* append(uint32_t cp, char* result) {
return append<char*, char>(cp, result);
}
// Hopefully, most common case: the caller uses back_inserter
// i.e. append(cp, std::back_inserter(str));
template<typename container_type>
std::back_insert_iterator<container_type> append
(uint32_t cp, std::back_insert_iterator<container_type> result) {
return append<std::back_insert_iterator<container_type>,
typename container_type::value_type>(cp, result);
}
// The caller uses some other kind of output operator - not covered above
// Note that in this case we are not able to determine octet_type
// so we assume it's uint_8; that can cause a conversion warning if we are wrong.
template <typename octet_iterator>
octet_iterator append(uint32_t cp, octet_iterator result) {
return append<octet_iterator, uint8_t>(cp, result);
}
} // namespace internal
/// The library API - functions intended to be called by the users

View File

@ -70,7 +70,7 @@ namespace utf8
inline std::size_t find_invalid(const std::string& s)
{
std::string::const_iterator invalid = find_invalid(s.begin(), s.end());
return (invalid == s.end()) ? std::string::npos : (invalid - s.begin());
return (invalid == s.end()) ? std::string::npos : static_cast<std::size_t>(invalid - s.begin());
}
inline bool is_valid(const std::string& s)

View File

@ -0,0 +1,103 @@
// Copyright 2018 Nemanja Trifunovic
/*
Permission is hereby granted, free of charge, to any person or organization
obtaining a copy of the software and accompanying documentation covered by
this license (the "Software") to use, reproduce, display, distribute,
execute, and transmit the Software, and to prepare derivative works of the
Software, and to permit third-parties to whom the Software is furnished to
do so, all subject to the following:
The copyright notices in the Software and this entire statement, including
the above license grant, this restriction and the following disclaimer,
must be included in all copies of the Software, in whole or in part, and
all derivative works of the Software, unless such copies or derivative
works are solely in the form of machine-executable object code generated by
a source language processor.
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, TITLE AND NON-INFRINGEMENT. IN NO EVENT
SHALL THE COPYRIGHT HOLDERS OR ANYONE DISTRIBUTING THE SOFTWARE BE LIABLE
FOR ANY DAMAGES OR OTHER LIABILITY, WHETHER IN CONTRACT, TORT OR OTHERWISE,
ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
DEALINGS IN THE SOFTWARE.
*/
#ifndef UTF8_FOR_CPP_7e906c01_03a3_4daf_b420_ea7ea952b3c9
#define UTF8_FOR_CPP_7e906c01_03a3_4daf_b420_ea7ea952b3c9
#include "checked.h"
#include <string>
namespace utf8
{
inline void append(char32_t cp, std::string& s)
{
append(uint32_t(cp), std::back_inserter(s));
}
inline std::string utf16to8(std::u16string_view s)
{
std::string result;
utf16to8(s.begin(), s.end(), std::back_inserter(result));
return result;
}
inline std::u16string utf8to16(std::string_view s)
{
std::u16string result;
utf8to16(s.begin(), s.end(), std::back_inserter(result));
return result;
}
inline std::string utf32to8(std::u32string_view s)
{
std::string result;
utf32to8(s.begin(), s.end(), std::back_inserter(result));
return result;
}
inline std::u32string utf8to32(std::string_view s)
{
std::u32string result;
utf8to32(s.begin(), s.end(), std::back_inserter(result));
return result;
}
inline std::size_t find_invalid(std::string_view s)
{
std::string_view::const_iterator invalid = find_invalid(s.begin(), s.end());
return (invalid == s.end()) ? std::string_view::npos : static_cast<std::size_t>(invalid - s.begin());
}
inline bool is_valid(std::string_view s)
{
return is_valid(s.begin(), s.end());
}
inline std::string replace_invalid(std::string_view s, char32_t replacement)
{
std::string result;
replace_invalid(s.begin(), s.end(), std::back_inserter(result), replacement);
return result;
}
inline std::string replace_invalid(std::string_view s)
{
std::string result;
replace_invalid(s.begin(), s.end(), std::back_inserter(result));
return result;
}
inline bool starts_with_bom(std::string_view s)
{
return starts_with_bom(s.begin(), s.end());
}
} // namespace utf8
#endif // header guard

View File

@ -37,24 +37,7 @@ namespace utf8
template <typename octet_iterator>
octet_iterator append(uint32_t cp, octet_iterator result)
{
if (cp < 0x80) // one octet
*(result++) = static_cast<uint8_t>(cp);
else if (cp < 0x800) { // two octets
*(result++) = static_cast<uint8_t>((cp >> 6) | 0xc0);
*(result++) = static_cast<uint8_t>((cp & 0x3f) | 0x80);
}
else if (cp < 0x10000) { // three octets
*(result++) = static_cast<uint8_t>((cp >> 12) | 0xe0);
*(result++) = static_cast<uint8_t>(((cp >> 6) & 0x3f) | 0x80);
*(result++) = static_cast<uint8_t>((cp & 0x3f) | 0x80);
}
else { // four octets
*(result++) = static_cast<uint8_t>((cp >> 18) | 0xf0);
*(result++) = static_cast<uint8_t>(((cp >> 12) & 0x3f)| 0x80);
*(result++) = static_cast<uint8_t>(((cp >> 6) & 0x3f) | 0x80);
*(result++) = static_cast<uint8_t>((cp & 0x3f) | 0x80);
}
return result;
return internal::append(cp, result);
}
template <typename octet_iterator, typename output_iterator>

View File

@ -10,7 +10,7 @@ endif()
project(zlib C)
SET (ZLIB_VERSION_MAJOR 1)
SET (ZLIB_VERSION_MINOR 2)
SET (ZLIB_VERSION_PATCH 11)
SET (ZLIB_VERSION_PATCH 13)
SET (ZLIB_VERSION ${ZLIB_VERSION_MAJOR}.${ZLIB_VERSION_MINOR}.${ZLIB_VERSION_PATCH})
SET (ZLIB_SOVERSION 1)
SET (PROJECT_VERSION "${ZLIB_VERSION}")
@ -76,15 +76,7 @@ if(MSVC)
set(CMAKE_DEBUG_POSTFIX "d")
add_definitions(-D_CRT_SECURE_NO_DEPRECATE)
add_definitions(-D_CRT_NONSTDC_NO_DEPRECATE)
if(CMAKE_CXX_COMPILER_ID MATCHES "Clang" ) # clang-cl
SET(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -Wno-deprecated-non-prototype")
endif()
include_directories(${CMAKE_CURRENT_SOURCE_DIR})
else()
if(CMAKE_CXX_COMPILER_ID MATCHES "Clang" ) # clang-cl
SET(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -Wno-deprecated-non-prototype")
endif()
endif()
if(NOT CMAKE_CURRENT_SOURCE_DIR STREQUAL CMAKE_CURRENT_BINARY_DIR)

File diff suppressed because it is too large Load Diff

View File

@ -0,0 +1,22 @@
Copyright notice:
(C) 1995-2022 Jean-loup Gailly and Mark Adler
This software is provided 'as-is', without any express or implied
warranty. In no event will the authors be held liable for any damages
arising from the use of this software.
Permission is granted to anyone to use this software for any purpose,
including commercial applications, and to alter it and redistribute it
freely, subject to the following restrictions:
1. The origin of this software must not be misrepresented; you must not
claim that you wrote the original software. If you use this software
in a product, an acknowledgment in the product documentation would be
appreciated but is not required.
2. Altered source versions must be plainly marked as such, and must not be
misrepresented as being the original software.
3. This notice may not be removed or altered from any source distribution.
Jean-loup Gailly Mark Adler
jloup@gzip.org madler@alumni.caltech.edu

View File

@ -19,7 +19,7 @@
memory, Z_BUF_ERROR if there was not enough room in the output buffer,
Z_STREAM_ERROR if the level parameter is invalid.
*/
int ZEXPORT compress2 (dest, destLen, source, sourceLen, level)
int ZEXPORT compress2(dest, destLen, source, sourceLen, level)
Bytef *dest;
uLongf *destLen;
const Bytef *source;
@ -65,7 +65,7 @@ int ZEXPORT compress2 (dest, destLen, source, sourceLen, level)
/* ===========================================================================
*/
int ZEXPORT compress (dest, destLen, source, sourceLen)
int ZEXPORT compress(dest, destLen, source, sourceLen)
Bytef *dest;
uLongf *destLen;
const Bytef *source;
@ -78,7 +78,7 @@ int ZEXPORT compress (dest, destLen, source, sourceLen)
If the default memLevel or windowBits for deflateInit() is changed, then
this function needs to be updated.
*/
uLong ZEXPORT compressBound (sourceLen)
uLong ZEXPORT compressBound(sourceLen)
uLong sourceLen;
{
return sourceLen + (sourceLen >> 12) + (sourceLen >> 14) +

View File

@ -1,4 +1,4 @@
All files under this contrib directory are UNSUPPORTED. There were
All files under this contrib directory are UNSUPPORTED. They were
provided by users of zlib and were not tested by the authors of zlib.
Use at your own risk. Please contact the authors of the contributions
for help about these, not the zlib authors. Thanks.
@ -8,14 +8,6 @@ ada/ by Dmitriy Anisimkov <anisimkov@yahoo.com>
Support for Ada
See http://zlib-ada.sourceforge.net/
amd64/ by Mikhail Teterin <mi@ALDAN.algebra.com>
asm code for AMD64
See patch at http://www.freebsd.org/cgi/query-pr.cgi?pr=bin/96393
asm686/ by Brian Raiter <breadbox@muppetlabs.com>
asm code for Pentium and PPro/PII, using the AT&T (GNU as) syntax
See http://www.muppetlabs.com/~breadbox/software/assembly.html
blast/ by Mark Adler <madler@alumni.caltech.edu>
Decompressor for output of PKWare Data Compression Library (DCL)
@ -32,9 +24,6 @@ gcc_gvmat64/by Gilles Vollant <info@winimage.com>
infback9/ by Mark Adler <madler@alumni.caltech.edu>
Unsupported diffs to infback to decode the deflate64 format
inflate86/ by Chris Anderson <christop@charm.net>
Tuned x86 gcc asm code to replace inflate_fast()
iostream/ by Kevin Ruland <kevin@rodin.wustl.edu>
A C++ I/O streams interface to the zlib gz* functions
@ -45,16 +34,6 @@ iostream3/ by Ludwig Schwardt <schwardt@sun.ac.za>
and Kevin Ruland <kevin@rodin.wustl.edu>
Yet another C++ I/O streams interface
masmx64/ by Gilles Vollant <info@winimage.com>
x86 64-bit (AMD64 and Intel EM64t) code for x64 assembler to
replace longest_match() and inflate_fast(), also masm x86
64-bits translation of Chris Anderson inflate_fast()
masmx86/ by Gilles Vollant <info@winimage.com>
x86 asm code to replace longest_match() and inflate_fast(),
for Visual C++ and MASM (32 bits).
Based on Brian Raiter (asm686) and Chris Anderson (inflate86)
minizip/ by Gilles Vollant <info@winimage.com>
Mini zip and unzip based on zlib
Includes Zip64 support by Mathias Svensson <mathias@result42.com>

View File

@ -57,7 +57,7 @@ int blast(blast_in infun, void *inhow, blast_out outfun, void *outhow,
* use by the application to pass an input descriptor to infun(), if desired.
*
* If left and in are not NULL and *left is not zero when blast() is called,
* then the *left bytes are *in are consumed for input before infun() is used.
* then the *left bytes at *in are consumed for input before infun() is used.
*
* The output function is invoked: err = outfun(how, buf, len), where the bytes
* to be written are buf[0..len-1]. If err is not zero, then blast() returns

View File

@ -1 +1 @@
AIAIAIAIAIAIA
AIAIAIAIAIAIA

View File

@ -152,7 +152,7 @@ procedure DecompressToUserBuf(const InBuf: Pointer; InBytes: Integer;
const OutBuf: Pointer; BufSize: Integer);
const
zlib_version = '1.2.11';
zlib_version = '1.2.13';
type
EZlibError = class(Exception);

View File

@ -1,33 +1,33 @@
<?xml version="1.0" encoding="utf-8" ?>
<project name="DotZLib" default="build" basedir="./DotZLib">
<description>A .Net wrapper library around ZLib1.dll</description>
<property name="nunit.location" value="c:/program files/NUnit V2.1/bin" />
<property name="build.root" value="bin" />
<property name="debug" value="true" />
<property name="nunit" value="true" />
<property name="build.folder" value="${build.root}/debug/" if="${debug}" />
<property name="build.folder" value="${build.root}/release/" unless="${debug}" />
<target name="clean" description="Remove all generated files">
<delete dir="${build.root}" failonerror="false" />
</target>
<target name="build" description="compiles the source code">
<mkdir dir="${build.folder}" />
<csc target="library" output="${build.folder}DotZLib.dll" debug="${debug}">
<references basedir="${nunit.location}">
<includes if="${nunit}" name="nunit.framework.dll" />
</references>
<sources>
<includes name="*.cs" />
<excludes name="UnitTests.cs" unless="${nunit}" />
</sources>
<arg value="/d:nunit" if="${nunit}" />
</csc>
</target>
<?xml version="1.0" encoding="utf-8" ?>
<project name="DotZLib" default="build" basedir="./DotZLib">
<description>A .Net wrapper library around ZLib1.dll</description>
<property name="nunit.location" value="c:/program files/NUnit V2.1/bin" />
<property name="build.root" value="bin" />
<property name="debug" value="true" />
<property name="nunit" value="true" />
<property name="build.folder" value="${build.root}/debug/" if="${debug}" />
<property name="build.folder" value="${build.root}/release/" unless="${debug}" />
<target name="clean" description="Remove all generated files">
<delete dir="${build.root}" failonerror="false" />
</target>
<target name="build" description="compiles the source code">
<mkdir dir="${build.folder}" />
<csc target="library" output="${build.folder}DotZLib.dll" debug="${debug}">
<references basedir="${nunit.location}">
<includes if="${nunit}" name="nunit.framework.dll" />
</references>
<sources>
<includes name="*.cs" />
<excludes name="UnitTests.cs" unless="${nunit}" />
</sources>
<arg value="/d:nunit" if="${nunit}" />
</csc>
</target>
</project>

View File

@ -1,58 +1,58 @@
using System.Reflection;
using System.Runtime.CompilerServices;
//
// General Information about an assembly is controlled through the following
// set of attributes. Change these attribute values to modify the information
// associated with an assembly.
//
[assembly: AssemblyTitle("DotZLib")]
[assembly: AssemblyDescription(".Net bindings for ZLib compression dll 1.2.x")]
[assembly: AssemblyConfiguration("")]
[assembly: AssemblyCompany("Henrik Ravn")]
[assembly: AssemblyProduct("")]
[assembly: AssemblyCopyright("(c) 2004 by Henrik Ravn")]
[assembly: AssemblyTrademark("")]
[assembly: AssemblyCulture("")]
//
// Version information for an assembly consists of the following four values:
//
// Major Version
// Minor Version
// Build Number
// Revision
//
// You can specify all the values or you can default the Revision and Build Numbers
// by using the '*' as shown below:
[assembly: AssemblyVersion("1.0.*")]
//
// In order to sign your assembly you must specify a key to use. Refer to the
// Microsoft .NET Framework documentation for more information on assembly signing.
//
// Use the attributes below to control which key is used for signing.
//
// Notes:
// (*) If no key is specified, the assembly is not signed.
// (*) KeyName refers to a key that has been installed in the Crypto Service
// Provider (CSP) on your machine. KeyFile refers to a file which contains
// a key.
// (*) If the KeyFile and the KeyName values are both specified, the
// following processing occurs:
// (1) If the KeyName can be found in the CSP, that key is used.
// (2) If the KeyName does not exist and the KeyFile does exist, the key
// in the KeyFile is installed into the CSP and used.
// (*) In order to create a KeyFile, you can use the sn.exe (Strong Name) utility.
// When specifying the KeyFile, the location of the KeyFile should be
// relative to the project output directory which is
// %Project Directory%\obj\<configuration>. For example, if your KeyFile is
// located in the project directory, you would specify the AssemblyKeyFile
// attribute as [assembly: AssemblyKeyFile("..\\..\\mykey.snk")]
// (*) Delay Signing is an advanced option - see the Microsoft .NET Framework
// documentation for more information on this.
//
[assembly: AssemblyDelaySign(false)]
[assembly: AssemblyKeyFile("")]
[assembly: AssemblyKeyName("")]
using System.Reflection;
using System.Runtime.CompilerServices;
//
// General Information about an assembly is controlled through the following
// set of attributes. Change these attribute values to modify the information
// associated with an assembly.
//
[assembly: AssemblyTitle("DotZLib")]
[assembly: AssemblyDescription(".Net bindings for ZLib compression dll 1.2.x")]
[assembly: AssemblyConfiguration("")]
[assembly: AssemblyCompany("Henrik Ravn")]
[assembly: AssemblyProduct("")]
[assembly: AssemblyCopyright("(c) 2004 by Henrik Ravn")]
[assembly: AssemblyTrademark("")]
[assembly: AssemblyCulture("")]
//
// Version information for an assembly consists of the following four values:
//
// Major Version
// Minor Version
// Build Number
// Revision
//
// You can specify all the values or you can default the Revision and Build Numbers
// by using the '*' as shown below:
[assembly: AssemblyVersion("1.0.*")]
//
// In order to sign your assembly you must specify a key to use. Refer to the
// Microsoft .NET Framework documentation for more information on assembly signing.
//
// Use the attributes below to control which key is used for signing.
//
// Notes:
// (*) If no key is specified, the assembly is not signed.
// (*) KeyName refers to a key that has been installed in the Crypto Service
// Provider (CSP) on your machine. KeyFile refers to a file which contains
// a key.
// (*) If the KeyFile and the KeyName values are both specified, the
// following processing occurs:
// (1) If the KeyName can be found in the CSP, that key is used.
// (2) If the KeyName does not exist and the KeyFile does exist, the key
// in the KeyFile is installed into the CSP and used.
// (*) In order to create a KeyFile, you can use the sn.exe (Strong Name) utility.
// When specifying the KeyFile, the location of the KeyFile should be
// relative to the project output directory which is
// %Project Directory%\obj\<configuration>. For example, if your KeyFile is
// located in the project directory, you would specify the AssemblyKeyFile
// attribute as [assembly: AssemblyKeyFile("..\\..\\mykey.snk")]
// (*) Delay Signing is an advanced option - see the Microsoft .NET Framework
// documentation for more information on this.
//
[assembly: AssemblyDelaySign(false)]
[assembly: AssemblyKeyFile("")]
[assembly: AssemblyKeyName("")]

View File

@ -1,202 +1,202 @@
//
// © Copyright Henrik Ravn 2004
//
// Use, modification and distribution are subject to the Boost Software License, Version 1.0.
// (See accompanying file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
//
using System;
using System.Runtime.InteropServices;
using System.Text;
namespace DotZLib
{
#region ChecksumGeneratorBase
/// <summary>
/// Implements the common functionality needed for all <see cref="ChecksumGenerator"/>s
/// </summary>
/// <example></example>
public abstract class ChecksumGeneratorBase : ChecksumGenerator
{
/// <summary>
/// The value of the current checksum
/// </summary>
protected uint _current;
/// <summary>
/// Initializes a new instance of the checksum generator base - the current checksum is
/// set to zero
/// </summary>
public ChecksumGeneratorBase()
{
_current = 0;
}
/// <summary>
/// Initializes a new instance of the checksum generator basewith a specified value
/// </summary>
/// <param name="initialValue">The value to set the current checksum to</param>
public ChecksumGeneratorBase(uint initialValue)
{
_current = initialValue;
}
/// <summary>
/// Resets the current checksum to zero
/// </summary>
public void Reset() { _current = 0; }
/// <summary>
/// Gets the current checksum value
/// </summary>
public uint Value { get { return _current; } }
/// <summary>
/// Updates the current checksum with part of an array of bytes
/// </summary>
/// <param name="data">The data to update the checksum with</param>
/// <param name="offset">Where in <c>data</c> to start updating</param>
/// <param name="count">The number of bytes from <c>data</c> to use</param>
/// <exception cref="ArgumentException">The sum of offset and count is larger than the length of <c>data</c></exception>
/// <exception cref="NullReferenceException"><c>data</c> is a null reference</exception>
/// <exception cref="ArgumentOutOfRangeException">Offset or count is negative.</exception>
/// <remarks>All the other <c>Update</c> methods are implmeneted in terms of this one.
/// This is therefore the only method a derived class has to implement</remarks>
public abstract void Update(byte[] data, int offset, int count);
/// <summary>
/// Updates the current checksum with an array of bytes.
/// </summary>
/// <param name="data">The data to update the checksum with</param>
public void Update(byte[] data)
{
Update(data, 0, data.Length);
}
/// <summary>
/// Updates the current checksum with the data from a string
/// </summary>
/// <param name="data">The string to update the checksum with</param>
/// <remarks>The characters in the string are converted by the UTF-8 encoding</remarks>
public void Update(string data)
{
Update(Encoding.UTF8.GetBytes(data));
}
/// <summary>
/// Updates the current checksum with the data from a string, using a specific encoding
/// </summary>
/// <param name="data">The string to update the checksum with</param>
/// <param name="encoding">The encoding to use</param>
public void Update(string data, Encoding encoding)
{
Update(encoding.GetBytes(data));
}
}
#endregion
#region CRC32
/// <summary>
/// Implements a CRC32 checksum generator
/// </summary>
public sealed class CRC32Checksum : ChecksumGeneratorBase
{
#region DLL imports
[DllImport("ZLIB1.dll", CallingConvention=CallingConvention.Cdecl)]
private static extern uint crc32(uint crc, int data, uint length);
#endregion
/// <summary>
/// Initializes a new instance of the CRC32 checksum generator
/// </summary>
public CRC32Checksum() : base() {}
/// <summary>
/// Initializes a new instance of the CRC32 checksum generator with a specified value
/// </summary>
/// <param name="initialValue">The value to set the current checksum to</param>
public CRC32Checksum(uint initialValue) : base(initialValue) {}
/// <summary>
/// Updates the current checksum with part of an array of bytes
/// </summary>
/// <param name="data">The data to update the checksum with</param>
/// <param name="offset">Where in <c>data</c> to start updating</param>
/// <param name="count">The number of bytes from <c>data</c> to use</param>
/// <exception cref="ArgumentException">The sum of offset and count is larger than the length of <c>data</c></exception>
/// <exception cref="NullReferenceException"><c>data</c> is a null reference</exception>
/// <exception cref="ArgumentOutOfRangeException">Offset or count is negative.</exception>
public override void Update(byte[] data, int offset, int count)
{
if (offset < 0 || count < 0) throw new ArgumentOutOfRangeException();
if ((offset+count) > data.Length) throw new ArgumentException();
GCHandle hData = GCHandle.Alloc(data, GCHandleType.Pinned);
try
{
_current = crc32(_current, hData.AddrOfPinnedObject().ToInt32()+offset, (uint)count);
}
finally
{
hData.Free();
}
}
}
#endregion
#region Adler
/// <summary>
/// Implements a checksum generator that computes the Adler checksum on data
/// </summary>
public sealed class AdlerChecksum : ChecksumGeneratorBase
{
#region DLL imports
[DllImport("ZLIB1.dll", CallingConvention=CallingConvention.Cdecl)]
private static extern uint adler32(uint adler, int data, uint length);
#endregion
/// <summary>
/// Initializes a new instance of the Adler checksum generator
/// </summary>
public AdlerChecksum() : base() {}
/// <summary>
/// Initializes a new instance of the Adler checksum generator with a specified value
/// </summary>
/// <param name="initialValue">The value to set the current checksum to</param>
public AdlerChecksum(uint initialValue) : base(initialValue) {}
/// <summary>
/// Updates the current checksum with part of an array of bytes
/// </summary>
/// <param name="data">The data to update the checksum with</param>
/// <param name="offset">Where in <c>data</c> to start updating</param>
/// <param name="count">The number of bytes from <c>data</c> to use</param>
/// <exception cref="ArgumentException">The sum of offset and count is larger than the length of <c>data</c></exception>
/// <exception cref="NullReferenceException"><c>data</c> is a null reference</exception>
/// <exception cref="ArgumentOutOfRangeException">Offset or count is negative.</exception>
public override void Update(byte[] data, int offset, int count)
{
if (offset < 0 || count < 0) throw new ArgumentOutOfRangeException();
if ((offset+count) > data.Length) throw new ArgumentException();
GCHandle hData = GCHandle.Alloc(data, GCHandleType.Pinned);
try
{
_current = adler32(_current, hData.AddrOfPinnedObject().ToInt32()+offset, (uint)count);
}
finally
{
hData.Free();
}
}
}
#endregion
}
//
// © Copyright Henrik Ravn 2004
//
// Use, modification and distribution are subject to the Boost Software License, Version 1.0.
// (See accompanying file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
//
using System;
using System.Runtime.InteropServices;
using System.Text;
namespace DotZLib
{
#region ChecksumGeneratorBase
/// <summary>
/// Implements the common functionality needed for all <see cref="ChecksumGenerator"/>s
/// </summary>
/// <example></example>
public abstract class ChecksumGeneratorBase : ChecksumGenerator
{
/// <summary>
/// The value of the current checksum
/// </summary>
protected uint _current;
/// <summary>
/// Initializes a new instance of the checksum generator base - the current checksum is
/// set to zero
/// </summary>
public ChecksumGeneratorBase()
{
_current = 0;
}
/// <summary>
/// Initializes a new instance of the checksum generator basewith a specified value
/// </summary>
/// <param name="initialValue">The value to set the current checksum to</param>
public ChecksumGeneratorBase(uint initialValue)
{
_current = initialValue;
}
/// <summary>
/// Resets the current checksum to zero
/// </summary>
public void Reset() { _current = 0; }
/// <summary>
/// Gets the current checksum value
/// </summary>
public uint Value { get { return _current; } }
/// <summary>
/// Updates the current checksum with part of an array of bytes
/// </summary>
/// <param name="data">The data to update the checksum with</param>
/// <param name="offset">Where in <c>data</c> to start updating</param>
/// <param name="count">The number of bytes from <c>data</c> to use</param>
/// <exception cref="ArgumentException">The sum of offset and count is larger than the length of <c>data</c></exception>
/// <exception cref="NullReferenceException"><c>data</c> is a null reference</exception>
/// <exception cref="ArgumentOutOfRangeException">Offset or count is negative.</exception>
/// <remarks>All the other <c>Update</c> methods are implmeneted in terms of this one.
/// This is therefore the only method a derived class has to implement</remarks>
public abstract void Update(byte[] data, int offset, int count);
/// <summary>
/// Updates the current checksum with an array of bytes.
/// </summary>
/// <param name="data">The data to update the checksum with</param>
public void Update(byte[] data)
{
Update(data, 0, data.Length);
}
/// <summary>
/// Updates the current checksum with the data from a string
/// </summary>
/// <param name="data">The string to update the checksum with</param>
/// <remarks>The characters in the string are converted by the UTF-8 encoding</remarks>
public void Update(string data)
{
Update(Encoding.UTF8.GetBytes(data));
}
/// <summary>
/// Updates the current checksum with the data from a string, using a specific encoding
/// </summary>
/// <param name="data">The string to update the checksum with</param>
/// <param name="encoding">The encoding to use</param>
public void Update(string data, Encoding encoding)
{
Update(encoding.GetBytes(data));
}
}
#endregion
#region CRC32
/// <summary>
/// Implements a CRC32 checksum generator
/// </summary>
public sealed class CRC32Checksum : ChecksumGeneratorBase
{
#region DLL imports
[DllImport("ZLIB1.dll", CallingConvention=CallingConvention.Cdecl)]
private static extern uint crc32(uint crc, int data, uint length);
#endregion
/// <summary>
/// Initializes a new instance of the CRC32 checksum generator
/// </summary>
public CRC32Checksum() : base() {}
/// <summary>
/// Initializes a new instance of the CRC32 checksum generator with a specified value
/// </summary>
/// <param name="initialValue">The value to set the current checksum to</param>
public CRC32Checksum(uint initialValue) : base(initialValue) {}
/// <summary>
/// Updates the current checksum with part of an array of bytes
/// </summary>
/// <param name="data">The data to update the checksum with</param>
/// <param name="offset">Where in <c>data</c> to start updating</param>
/// <param name="count">The number of bytes from <c>data</c> to use</param>
/// <exception cref="ArgumentException">The sum of offset and count is larger than the length of <c>data</c></exception>
/// <exception cref="NullReferenceException"><c>data</c> is a null reference</exception>
/// <exception cref="ArgumentOutOfRangeException">Offset or count is negative.</exception>
public override void Update(byte[] data, int offset, int count)
{
if (offset < 0 || count < 0) throw new ArgumentOutOfRangeException();
if ((offset+count) > data.Length) throw new ArgumentException();
GCHandle hData = GCHandle.Alloc(data, GCHandleType.Pinned);
try
{
_current = crc32(_current, hData.AddrOfPinnedObject().ToInt32()+offset, (uint)count);
}
finally
{
hData.Free();
}
}
}
#endregion
#region Adler
/// <summary>
/// Implements a checksum generator that computes the Adler checksum on data
/// </summary>
public sealed class AdlerChecksum : ChecksumGeneratorBase
{
#region DLL imports
[DllImport("ZLIB1.dll", CallingConvention=CallingConvention.Cdecl)]
private static extern uint adler32(uint adler, int data, uint length);
#endregion
/// <summary>
/// Initializes a new instance of the Adler checksum generator
/// </summary>
public AdlerChecksum() : base() {}
/// <summary>
/// Initializes a new instance of the Adler checksum generator with a specified value
/// </summary>
/// <param name="initialValue">The value to set the current checksum to</param>
public AdlerChecksum(uint initialValue) : base(initialValue) {}
/// <summary>
/// Updates the current checksum with part of an array of bytes
/// </summary>
/// <param name="data">The data to update the checksum with</param>
/// <param name="offset">Where in <c>data</c> to start updating</param>
/// <param name="count">The number of bytes from <c>data</c> to use</param>
/// <exception cref="ArgumentException">The sum of offset and count is larger than the length of <c>data</c></exception>
/// <exception cref="NullReferenceException"><c>data</c> is a null reference</exception>
/// <exception cref="ArgumentOutOfRangeException">Offset or count is negative.</exception>
public override void Update(byte[] data, int offset, int count)
{
if (offset < 0 || count < 0) throw new ArgumentOutOfRangeException();
if ((offset+count) > data.Length) throw new ArgumentException();
GCHandle hData = GCHandle.Alloc(data, GCHandleType.Pinned);
try
{
_current = adler32(_current, hData.AddrOfPinnedObject().ToInt32()+offset, (uint)count);
}
finally
{
hData.Free();
}
}
}
#endregion
}

View File

@ -1,83 +1,83 @@
//
// © Copyright Henrik Ravn 2004
//
// Use, modification and distribution are subject to the Boost Software License, Version 1.0.
// (See accompanying file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
//
using System;
using System.Diagnostics;
namespace DotZLib
{
/// <summary>
/// This class implements a circular buffer
/// </summary>
internal class CircularBuffer
{
#region Private data
private int _capacity;
private int _head;
private int _tail;
private int _size;
private byte[] _buffer;
#endregion
public CircularBuffer(int capacity)
{
Debug.Assert( capacity > 0 );
_buffer = new byte[capacity];
_capacity = capacity;
_head = 0;
_tail = 0;
_size = 0;
}
public int Size { get { return _size; } }
public int Put(byte[] source, int offset, int count)
{
Debug.Assert( count > 0 );
int trueCount = Math.Min(count, _capacity - Size);
for (int i = 0; i < trueCount; ++i)
_buffer[(_tail+i) % _capacity] = source[offset+i];
_tail += trueCount;
_tail %= _capacity;
_size += trueCount;
return trueCount;
}
public bool Put(byte b)
{
if (Size == _capacity) // no room
return false;
_buffer[_tail++] = b;
_tail %= _capacity;
++_size;
return true;
}
public int Get(byte[] destination, int offset, int count)
{
int trueCount = Math.Min(count,Size);
for (int i = 0; i < trueCount; ++i)
destination[offset + i] = _buffer[(_head+i) % _capacity];
_head += trueCount;
_head %= _capacity;
_size -= trueCount;
return trueCount;
}
public int Get()
{
if (Size == 0)
return -1;
int result = (int)_buffer[_head++ % _capacity];
--_size;
return result;
}
}
}
//
// © Copyright Henrik Ravn 2004
//
// Use, modification and distribution are subject to the Boost Software License, Version 1.0.
// (See accompanying file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
//
using System;
using System.Diagnostics;
namespace DotZLib
{
/// <summary>
/// This class implements a circular buffer
/// </summary>
internal class CircularBuffer
{
#region Private data
private int _capacity;
private int _head;
private int _tail;
private int _size;
private byte[] _buffer;
#endregion
public CircularBuffer(int capacity)
{
Debug.Assert( capacity > 0 );
_buffer = new byte[capacity];
_capacity = capacity;
_head = 0;
_tail = 0;
_size = 0;
}
public int Size { get { return _size; } }
public int Put(byte[] source, int offset, int count)
{
Debug.Assert( count > 0 );
int trueCount = Math.Min(count, _capacity - Size);
for (int i = 0; i < trueCount; ++i)
_buffer[(_tail+i) % _capacity] = source[offset+i];
_tail += trueCount;
_tail %= _capacity;
_size += trueCount;
return trueCount;
}
public bool Put(byte b)
{
if (Size == _capacity) // no room
return false;
_buffer[_tail++] = b;
_tail %= _capacity;
++_size;
return true;
}
public int Get(byte[] destination, int offset, int count)
{
int trueCount = Math.Min(count,Size);
for (int i = 0; i < trueCount; ++i)
destination[offset + i] = _buffer[(_head+i) % _capacity];
_head += trueCount;
_head %= _capacity;
_size -= trueCount;
return trueCount;
}
public int Get()
{
if (Size == 0)
return -1;
int result = (int)_buffer[_head++ % _capacity];
--_size;
return result;
}
}
}

View File

@ -1,198 +1,198 @@
//
// © Copyright Henrik Ravn 2004
//
// Use, modification and distribution are subject to the Boost Software License, Version 1.0.
// (See accompanying file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
//
using System;
using System.Runtime.InteropServices;
namespace DotZLib
{
/// <summary>
/// Implements the common functionality needed for all <see cref="Codec"/>s
/// </summary>
public abstract class CodecBase : Codec, IDisposable
{
#region Data members
/// <summary>
/// Instance of the internal zlib buffer structure that is
/// passed to all functions in the zlib dll
/// </summary>
internal ZStream _ztream = new ZStream();
/// <summary>
/// True if the object instance has been disposed, false otherwise
/// </summary>
protected bool _isDisposed = false;
/// <summary>
/// The size of the internal buffers
/// </summary>
protected const int kBufferSize = 16384;
private byte[] _outBuffer = new byte[kBufferSize];
private byte[] _inBuffer = new byte[kBufferSize];
private GCHandle _hInput;
private GCHandle _hOutput;
private uint _checksum = 0;
#endregion
/// <summary>
/// Initializes a new instance of the <c>CodeBase</c> class.
/// </summary>
public CodecBase()
{
try
{
_hInput = GCHandle.Alloc(_inBuffer, GCHandleType.Pinned);
_hOutput = GCHandle.Alloc(_outBuffer, GCHandleType.Pinned);
}
catch (Exception)
{
CleanUp(false);
throw;
}
}
#region Codec Members
/// <summary>
/// Occurs when more processed data are available.
/// </summary>
public event DataAvailableHandler DataAvailable;
/// <summary>
/// Fires the <see cref="DataAvailable"/> event
/// </summary>
protected void OnDataAvailable()
{
if (_ztream.total_out > 0)
{
if (DataAvailable != null)
DataAvailable( _outBuffer, 0, (int)_ztream.total_out);
resetOutput();
}
}
/// <summary>
/// Adds more data to the codec to be processed.
/// </summary>
/// <param name="data">Byte array containing the data to be added to the codec</param>
/// <remarks>Adding data may, or may not, raise the <c>DataAvailable</c> event</remarks>
public void Add(byte[] data)
{
Add(data,0,data.Length);
}
/// <summary>
/// Adds more data to the codec to be processed.
/// </summary>
/// <param name="data">Byte array containing the data to be added to the codec</param>
/// <param name="offset">The index of the first byte to add from <c>data</c></param>
/// <param name="count">The number of bytes to add</param>
/// <remarks>Adding data may, or may not, raise the <c>DataAvailable</c> event</remarks>
/// <remarks>This must be implemented by a derived class</remarks>
public abstract void Add(byte[] data, int offset, int count);
/// <summary>
/// Finishes up any pending data that needs to be processed and handled.
/// </summary>
/// <remarks>This must be implemented by a derived class</remarks>
public abstract void Finish();
/// <summary>
/// Gets the checksum of the data that has been added so far
/// </summary>
public uint Checksum { get { return _checksum; } }
#endregion
#region Destructor & IDisposable stuff
/// <summary>
/// Destroys this instance
/// </summary>
~CodecBase()
{
CleanUp(false);
}
/// <summary>
/// Releases any unmanaged resources and calls the <see cref="CleanUp()"/> method of the derived class
/// </summary>
public void Dispose()
{
CleanUp(true);
}
/// <summary>
/// Performs any codec specific cleanup
/// </summary>
/// <remarks>This must be implemented by a derived class</remarks>
protected abstract void CleanUp();
// performs the release of the handles and calls the dereived CleanUp()
private void CleanUp(bool isDisposing)
{
if (!_isDisposed)
{
CleanUp();
if (_hInput.IsAllocated)
_hInput.Free();
if (_hOutput.IsAllocated)
_hOutput.Free();
_isDisposed = true;
}
}
#endregion
#region Helper methods
/// <summary>
/// Copies a number of bytes to the internal codec buffer - ready for proccesing
/// </summary>
/// <param name="data">The byte array that contains the data to copy</param>
/// <param name="startIndex">The index of the first byte to copy</param>
/// <param name="count">The number of bytes to copy from <c>data</c></param>
protected void copyInput(byte[] data, int startIndex, int count)
{
Array.Copy(data, startIndex, _inBuffer,0, count);
_ztream.next_in = _hInput.AddrOfPinnedObject();
_ztream.total_in = 0;
_ztream.avail_in = (uint)count;
}
/// <summary>
/// Resets the internal output buffers to a known state - ready for processing
/// </summary>
protected void resetOutput()
{
_ztream.total_out = 0;
_ztream.avail_out = kBufferSize;
_ztream.next_out = _hOutput.AddrOfPinnedObject();
}
/// <summary>
/// Updates the running checksum property
/// </summary>
/// <param name="newSum">The new checksum value</param>
protected void setChecksum(uint newSum)
{
_checksum = newSum;
}
#endregion
}
}
//
// © Copyright Henrik Ravn 2004
//
// Use, modification and distribution are subject to the Boost Software License, Version 1.0.
// (See accompanying file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
//
using System;
using System.Runtime.InteropServices;
namespace DotZLib
{
/// <summary>
/// Implements the common functionality needed for all <see cref="Codec"/>s
/// </summary>
public abstract class CodecBase : Codec, IDisposable
{
#region Data members
/// <summary>
/// Instance of the internal zlib buffer structure that is
/// passed to all functions in the zlib dll
/// </summary>
internal ZStream _ztream = new ZStream();
/// <summary>
/// True if the object instance has been disposed, false otherwise
/// </summary>
protected bool _isDisposed = false;
/// <summary>
/// The size of the internal buffers
/// </summary>
protected const int kBufferSize = 16384;
private byte[] _outBuffer = new byte[kBufferSize];
private byte[] _inBuffer = new byte[kBufferSize];
private GCHandle _hInput;
private GCHandle _hOutput;
private uint _checksum = 0;
#endregion
/// <summary>
/// Initializes a new instance of the <c>CodeBase</c> class.
/// </summary>
public CodecBase()
{
try
{
_hInput = GCHandle.Alloc(_inBuffer, GCHandleType.Pinned);
_hOutput = GCHandle.Alloc(_outBuffer, GCHandleType.Pinned);
}
catch (Exception)
{
CleanUp(false);
throw;
}
}
#region Codec Members
/// <summary>
/// Occurs when more processed data are available.
/// </summary>
public event DataAvailableHandler DataAvailable;
/// <summary>
/// Fires the <see cref="DataAvailable"/> event
/// </summary>
protected void OnDataAvailable()
{
if (_ztream.total_out > 0)
{
if (DataAvailable != null)
DataAvailable( _outBuffer, 0, (int)_ztream.total_out);
resetOutput();
}
}
/// <summary>
/// Adds more data to the codec to be processed.
/// </summary>
/// <param name="data">Byte array containing the data to be added to the codec</param>
/// <remarks>Adding data may, or may not, raise the <c>DataAvailable</c> event</remarks>
public void Add(byte[] data)
{
Add(data,0,data.Length);
}
/// <summary>
/// Adds more data to the codec to be processed.
/// </summary>
/// <param name="data">Byte array containing the data to be added to the codec</param>
/// <param name="offset">The index of the first byte to add from <c>data</c></param>
/// <param name="count">The number of bytes to add</param>
/// <remarks>Adding data may, or may not, raise the <c>DataAvailable</c> event</remarks>
/// <remarks>This must be implemented by a derived class</remarks>
public abstract void Add(byte[] data, int offset, int count);
/// <summary>
/// Finishes up any pending data that needs to be processed and handled.
/// </summary>
/// <remarks>This must be implemented by a derived class</remarks>
public abstract void Finish();
/// <summary>
/// Gets the checksum of the data that has been added so far
/// </summary>
public uint Checksum { get { return _checksum; } }
#endregion
#region Destructor & IDisposable stuff
/// <summary>
/// Destroys this instance
/// </summary>
~CodecBase()
{
CleanUp(false);
}
/// <summary>
/// Releases any unmanaged resources and calls the <see cref="CleanUp()"/> method of the derived class
/// </summary>
public void Dispose()
{
CleanUp(true);
}
/// <summary>
/// Performs any codec specific cleanup
/// </summary>
/// <remarks>This must be implemented by a derived class</remarks>
protected abstract void CleanUp();
// performs the release of the handles and calls the dereived CleanUp()
private void CleanUp(bool isDisposing)
{
if (!_isDisposed)
{
CleanUp();
if (_hInput.IsAllocated)
_hInput.Free();
if (_hOutput.IsAllocated)
_hOutput.Free();
_isDisposed = true;
}
}
#endregion
#region Helper methods
/// <summary>
/// Copies a number of bytes to the internal codec buffer - ready for proccesing
/// </summary>
/// <param name="data">The byte array that contains the data to copy</param>
/// <param name="startIndex">The index of the first byte to copy</param>
/// <param name="count">The number of bytes to copy from <c>data</c></param>
protected void copyInput(byte[] data, int startIndex, int count)
{
Array.Copy(data, startIndex, _inBuffer,0, count);
_ztream.next_in = _hInput.AddrOfPinnedObject();
_ztream.total_in = 0;
_ztream.avail_in = (uint)count;
}
/// <summary>
/// Resets the internal output buffers to a known state - ready for processing
/// </summary>
protected void resetOutput()
{
_ztream.total_out = 0;
_ztream.avail_out = kBufferSize;
_ztream.next_out = _hOutput.AddrOfPinnedObject();
}
/// <summary>
/// Updates the running checksum property
/// </summary>
/// <param name="newSum">The new checksum value</param>
protected void setChecksum(uint newSum)
{
_checksum = newSum;
}
#endregion
}
}

View File

@ -1,106 +1,106 @@
//
// © Copyright Henrik Ravn 2004
//
// Use, modification and distribution are subject to the Boost Software License, Version 1.0.
// (See accompanying file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
//
using System;
using System.Diagnostics;
using System.Runtime.InteropServices;
namespace DotZLib
{
/// <summary>
/// Implements a data compressor, using the deflate algorithm in the ZLib dll
/// </summary>
public sealed class Deflater : CodecBase
{
#region Dll imports
[DllImport("ZLIB1.dll", CallingConvention=CallingConvention.Cdecl, CharSet=CharSet.Ansi)]
private static extern int deflateInit_(ref ZStream sz, int level, string vs, int size);
[DllImport("ZLIB1.dll", CallingConvention=CallingConvention.Cdecl)]
private static extern int deflate(ref ZStream sz, int flush);
[DllImport("ZLIB1.dll", CallingConvention=CallingConvention.Cdecl)]
private static extern int deflateReset(ref ZStream sz);
[DllImport("ZLIB1.dll", CallingConvention=CallingConvention.Cdecl)]
private static extern int deflateEnd(ref ZStream sz);
#endregion
/// <summary>
/// Constructs an new instance of the <c>Deflater</c>
/// </summary>
/// <param name="level">The compression level to use for this <c>Deflater</c></param>
public Deflater(CompressLevel level) : base()
{
int retval = deflateInit_(ref _ztream, (int)level, Info.Version, Marshal.SizeOf(_ztream));
if (retval != 0)
throw new ZLibException(retval, "Could not initialize deflater");
resetOutput();
}
/// <summary>
/// Adds more data to the codec to be processed.
/// </summary>
/// <param name="data">Byte array containing the data to be added to the codec</param>
/// <param name="offset">The index of the first byte to add from <c>data</c></param>
/// <param name="count">The number of bytes to add</param>
/// <remarks>Adding data may, or may not, raise the <c>DataAvailable</c> event</remarks>
public override void Add(byte[] data, int offset, int count)
{
if (data == null) throw new ArgumentNullException();
if (offset < 0 || count < 0) throw new ArgumentOutOfRangeException();
if ((offset+count) > data.Length) throw new ArgumentException();
int total = count;
int inputIndex = offset;
int err = 0;
while (err >= 0 && inputIndex < total)
{
copyInput(data, inputIndex, Math.Min(total - inputIndex, kBufferSize));
while (err >= 0 && _ztream.avail_in > 0)
{
err = deflate(ref _ztream, (int)FlushTypes.None);
if (err == 0)
while (_ztream.avail_out == 0)
{
OnDataAvailable();
err = deflate(ref _ztream, (int)FlushTypes.None);
}
inputIndex += (int)_ztream.total_in;
}
}
setChecksum( _ztream.adler );
}
/// <summary>
/// Finishes up any pending data that needs to be processed and handled.
/// </summary>
public override void Finish()
{
int err;
do
{
err = deflate(ref _ztream, (int)FlushTypes.Finish);
OnDataAvailable();
}
while (err == 0);
setChecksum( _ztream.adler );
deflateReset(ref _ztream);
resetOutput();
}
/// <summary>
/// Closes the internal zlib deflate stream
/// </summary>
protected override void CleanUp() { deflateEnd(ref _ztream); }
}
}
//
// © Copyright Henrik Ravn 2004
//
// Use, modification and distribution are subject to the Boost Software License, Version 1.0.
// (See accompanying file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
//
using System;
using System.Diagnostics;
using System.Runtime.InteropServices;
namespace DotZLib
{
/// <summary>
/// Implements a data compressor, using the deflate algorithm in the ZLib dll
/// </summary>
public sealed class Deflater : CodecBase
{
#region Dll imports
[DllImport("ZLIB1.dll", CallingConvention=CallingConvention.Cdecl, CharSet=CharSet.Ansi)]
private static extern int deflateInit_(ref ZStream sz, int level, string vs, int size);
[DllImport("ZLIB1.dll", CallingConvention=CallingConvention.Cdecl)]
private static extern int deflate(ref ZStream sz, int flush);
[DllImport("ZLIB1.dll", CallingConvention=CallingConvention.Cdecl)]
private static extern int deflateReset(ref ZStream sz);
[DllImport("ZLIB1.dll", CallingConvention=CallingConvention.Cdecl)]
private static extern int deflateEnd(ref ZStream sz);
#endregion
/// <summary>
/// Constructs an new instance of the <c>Deflater</c>
/// </summary>
/// <param name="level">The compression level to use for this <c>Deflater</c></param>
public Deflater(CompressLevel level) : base()
{
int retval = deflateInit_(ref _ztream, (int)level, Info.Version, Marshal.SizeOf(_ztream));
if (retval != 0)
throw new ZLibException(retval, "Could not initialize deflater");
resetOutput();
}
/// <summary>
/// Adds more data to the codec to be processed.
/// </summary>
/// <param name="data">Byte array containing the data to be added to the codec</param>
/// <param name="offset">The index of the first byte to add from <c>data</c></param>
/// <param name="count">The number of bytes to add</param>
/// <remarks>Adding data may, or may not, raise the <c>DataAvailable</c> event</remarks>
public override void Add(byte[] data, int offset, int count)
{
if (data == null) throw new ArgumentNullException();
if (offset < 0 || count < 0) throw new ArgumentOutOfRangeException();
if ((offset+count) > data.Length) throw new ArgumentException();
int total = count;
int inputIndex = offset;
int err = 0;
while (err >= 0 && inputIndex < total)
{
copyInput(data, inputIndex, Math.Min(total - inputIndex, kBufferSize));
while (err >= 0 && _ztream.avail_in > 0)
{
err = deflate(ref _ztream, (int)FlushTypes.None);
if (err == 0)
while (_ztream.avail_out == 0)
{
OnDataAvailable();
err = deflate(ref _ztream, (int)FlushTypes.None);
}
inputIndex += (int)_ztream.total_in;
}
}
setChecksum( _ztream.adler );
}
/// <summary>
/// Finishes up any pending data that needs to be processed and handled.
/// </summary>
public override void Finish()
{
int err;
do
{
err = deflate(ref _ztream, (int)FlushTypes.Finish);
OnDataAvailable();
}
while (err == 0);
setChecksum( _ztream.adler );
deflateReset(ref _ztream);
resetOutput();
}
/// <summary>
/// Closes the internal zlib deflate stream
/// </summary>
protected override void CleanUp() { deflateEnd(ref _ztream); }
}
}

View File

@ -1,288 +1,288 @@
//
// © Copyright Henrik Ravn 2004
//
// Use, modification and distribution are subject to the Boost Software License, Version 1.0.
// (See accompanying file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
//
using System;
using System.IO;
using System.Runtime.InteropServices;
using System.Text;
namespace DotZLib
{
#region Internal types
/// <summary>
/// Defines constants for the various flush types used with zlib
/// </summary>
internal enum FlushTypes
{
None, Partial, Sync, Full, Finish, Block
}
#region ZStream structure
// internal mapping of the zlib zstream structure for marshalling
[StructLayoutAttribute(LayoutKind.Sequential, Pack=4, Size=0, CharSet=CharSet.Ansi)]
internal struct ZStream
{
public IntPtr next_in;
public uint avail_in;
public uint total_in;
public IntPtr next_out;
public uint avail_out;
public uint total_out;
[MarshalAs(UnmanagedType.LPStr)]
string msg;
uint state;
uint zalloc;
uint zfree;
uint opaque;
int data_type;
public uint adler;
uint reserved;
}
#endregion
#endregion
#region Public enums
/// <summary>
/// Defines constants for the available compression levels in zlib
/// </summary>
public enum CompressLevel : int
{
/// <summary>
/// The default compression level with a reasonable compromise between compression and speed
/// </summary>
Default = -1,
/// <summary>
/// No compression at all. The data are passed straight through.
/// </summary>
None = 0,
/// <summary>
/// The maximum compression rate available.
/// </summary>
Best = 9,
/// <summary>
/// The fastest available compression level.
/// </summary>
Fastest = 1
}
#endregion
#region Exception classes
/// <summary>
/// The exception that is thrown when an error occurs on the zlib dll
/// </summary>
public class ZLibException : ApplicationException
{
/// <summary>
/// Initializes a new instance of the <see cref="ZLibException"/> class with a specified
/// error message and error code
/// </summary>
/// <param name="errorCode">The zlib error code that caused the exception</param>
/// <param name="msg">A message that (hopefully) describes the error</param>
public ZLibException(int errorCode, string msg) : base(String.Format("ZLib error {0} {1}", errorCode, msg))
{
}
/// <summary>
/// Initializes a new instance of the <see cref="ZLibException"/> class with a specified
/// error code
/// </summary>
/// <param name="errorCode">The zlib error code that caused the exception</param>
public ZLibException(int errorCode) : base(String.Format("ZLib error {0}", errorCode))
{
}
}
#endregion
#region Interfaces
/// <summary>
/// Declares methods and properties that enables a running checksum to be calculated
/// </summary>
public interface ChecksumGenerator
{
/// <summary>
/// Gets the current value of the checksum
/// </summary>
uint Value { get; }
/// <summary>
/// Clears the current checksum to 0
/// </summary>
void Reset();
/// <summary>
/// Updates the current checksum with an array of bytes
/// </summary>
/// <param name="data">The data to update the checksum with</param>
void Update(byte[] data);
/// <summary>
/// Updates the current checksum with part of an array of bytes
/// </summary>
/// <param name="data">The data to update the checksum with</param>
/// <param name="offset">Where in <c>data</c> to start updating</param>
/// <param name="count">The number of bytes from <c>data</c> to use</param>
/// <exception cref="ArgumentException">The sum of offset and count is larger than the length of <c>data</c></exception>
/// <exception cref="ArgumentNullException"><c>data</c> is a null reference</exception>
/// <exception cref="ArgumentOutOfRangeException">Offset or count is negative.</exception>
void Update(byte[] data, int offset, int count);
/// <summary>
/// Updates the current checksum with the data from a string
/// </summary>
/// <param name="data">The string to update the checksum with</param>
/// <remarks>The characters in the string are converted by the UTF-8 encoding</remarks>
void Update(string data);
/// <summary>
/// Updates the current checksum with the data from a string, using a specific encoding
/// </summary>
/// <param name="data">The string to update the checksum with</param>
/// <param name="encoding">The encoding to use</param>
void Update(string data, Encoding encoding);
}
/// <summary>
/// Represents the method that will be called from a codec when new data
/// are available.
/// </summary>
/// <paramref name="data">The byte array containing the processed data</paramref>
/// <paramref name="startIndex">The index of the first processed byte in <c>data</c></paramref>
/// <paramref name="count">The number of processed bytes available</paramref>
/// <remarks>On return from this method, the data may be overwritten, so grab it while you can.
/// You cannot assume that startIndex will be zero.
/// </remarks>
public delegate void DataAvailableHandler(byte[] data, int startIndex, int count);
/// <summary>
/// Declares methods and events for implementing compressors/decompressors
/// </summary>
public interface Codec
{
/// <summary>
/// Occurs when more processed data are available.
/// </summary>
event DataAvailableHandler DataAvailable;
/// <summary>
/// Adds more data to the codec to be processed.
/// </summary>
/// <param name="data">Byte array containing the data to be added to the codec</param>
/// <remarks>Adding data may, or may not, raise the <c>DataAvailable</c> event</remarks>
void Add(byte[] data);
/// <summary>
/// Adds more data to the codec to be processed.
/// </summary>
/// <param name="data">Byte array containing the data to be added to the codec</param>
/// <param name="offset">The index of the first byte to add from <c>data</c></param>
/// <param name="count">The number of bytes to add</param>
/// <remarks>Adding data may, or may not, raise the <c>DataAvailable</c> event</remarks>
void Add(byte[] data, int offset, int count);
/// <summary>
/// Finishes up any pending data that needs to be processed and handled.
/// </summary>
void Finish();
/// <summary>
/// Gets the checksum of the data that has been added so far
/// </summary>
uint Checksum { get; }
}
#endregion
#region Classes
/// <summary>
/// Encapsulates general information about the ZLib library
/// </summary>
public class Info
{
#region DLL imports
[DllImport("ZLIB1.dll", CallingConvention=CallingConvention.Cdecl)]
private static extern uint zlibCompileFlags();
[DllImport("ZLIB1.dll", CallingConvention=CallingConvention.Cdecl)]
private static extern string zlibVersion();
#endregion
#region Private stuff
private uint _flags;
// helper function that unpacks a bitsize mask
private static int bitSize(uint bits)
{
switch (bits)
{
case 0: return 16;
case 1: return 32;
case 2: return 64;
}
return -1;
}
#endregion
/// <summary>
/// Constructs an instance of the <c>Info</c> class.
/// </summary>
public Info()
{
_flags = zlibCompileFlags();
}
/// <summary>
/// True if the library is compiled with debug info
/// </summary>
public bool HasDebugInfo { get { return 0 != (_flags & 0x100); } }
/// <summary>
/// True if the library is compiled with assembly optimizations
/// </summary>
public bool UsesAssemblyCode { get { return 0 != (_flags & 0x200); } }
/// <summary>
/// Gets the size of the unsigned int that was compiled into Zlib
/// </summary>
public int SizeOfUInt { get { return bitSize(_flags & 3); } }
/// <summary>
/// Gets the size of the unsigned long that was compiled into Zlib
/// </summary>
public int SizeOfULong { get { return bitSize((_flags >> 2) & 3); } }
/// <summary>
/// Gets the size of the pointers that were compiled into Zlib
/// </summary>
public int SizeOfPointer { get { return bitSize((_flags >> 4) & 3); } }
/// <summary>
/// Gets the size of the z_off_t type that was compiled into Zlib
/// </summary>
public int SizeOfOffset { get { return bitSize((_flags >> 6) & 3); } }
/// <summary>
/// Gets the version of ZLib as a string, e.g. "1.2.1"
/// </summary>
public static string Version { get { return zlibVersion(); } }
}
#endregion
}
//
// © Copyright Henrik Ravn 2004
//
// Use, modification and distribution are subject to the Boost Software License, Version 1.0.
// (See accompanying file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
//
using System;
using System.IO;
using System.Runtime.InteropServices;
using System.Text;
namespace DotZLib
{
#region Internal types
/// <summary>
/// Defines constants for the various flush types used with zlib
/// </summary>
internal enum FlushTypes
{
None, Partial, Sync, Full, Finish, Block
}
#region ZStream structure
// internal mapping of the zlib zstream structure for marshalling
[StructLayoutAttribute(LayoutKind.Sequential, Pack=4, Size=0, CharSet=CharSet.Ansi)]
internal struct ZStream
{
public IntPtr next_in;
public uint avail_in;
public uint total_in;
public IntPtr next_out;
public uint avail_out;
public uint total_out;
[MarshalAs(UnmanagedType.LPStr)]
string msg;
uint state;
uint zalloc;
uint zfree;
uint opaque;
int data_type;
public uint adler;
uint reserved;
}
#endregion
#endregion
#region Public enums
/// <summary>
/// Defines constants for the available compression levels in zlib
/// </summary>
public enum CompressLevel : int
{
/// <summary>
/// The default compression level with a reasonable compromise between compression and speed
/// </summary>
Default = -1,
/// <summary>
/// No compression at all. The data are passed straight through.
/// </summary>
None = 0,
/// <summary>
/// The maximum compression rate available.
/// </summary>
Best = 9,
/// <summary>
/// The fastest available compression level.
/// </summary>
Fastest = 1
}
#endregion
#region Exception classes
/// <summary>
/// The exception that is thrown when an error occurs on the zlib dll
/// </summary>
public class ZLibException : ApplicationException
{
/// <summary>
/// Initializes a new instance of the <see cref="ZLibException"/> class with a specified
/// error message and error code
/// </summary>
/// <param name="errorCode">The zlib error code that caused the exception</param>
/// <param name="msg">A message that (hopefully) describes the error</param>
public ZLibException(int errorCode, string msg) : base(String.Format("ZLib error {0} {1}", errorCode, msg))
{
}
/// <summary>
/// Initializes a new instance of the <see cref="ZLibException"/> class with a specified
/// error code
/// </summary>
/// <param name="errorCode">The zlib error code that caused the exception</param>
public ZLibException(int errorCode) : base(String.Format("ZLib error {0}", errorCode))
{
}
}
#endregion
#region Interfaces
/// <summary>
/// Declares methods and properties that enables a running checksum to be calculated
/// </summary>
public interface ChecksumGenerator
{
/// <summary>
/// Gets the current value of the checksum
/// </summary>
uint Value { get; }
/// <summary>
/// Clears the current checksum to 0
/// </summary>
void Reset();
/// <summary>
/// Updates the current checksum with an array of bytes
/// </summary>
/// <param name="data">The data to update the checksum with</param>
void Update(byte[] data);
/// <summary>
/// Updates the current checksum with part of an array of bytes
/// </summary>
/// <param name="data">The data to update the checksum with</param>
/// <param name="offset">Where in <c>data</c> to start updating</param>
/// <param name="count">The number of bytes from <c>data</c> to use</param>
/// <exception cref="ArgumentException">The sum of offset and count is larger than the length of <c>data</c></exception>
/// <exception cref="ArgumentNullException"><c>data</c> is a null reference</exception>
/// <exception cref="ArgumentOutOfRangeException">Offset or count is negative.</exception>
void Update(byte[] data, int offset, int count);
/// <summary>
/// Updates the current checksum with the data from a string
/// </summary>
/// <param name="data">The string to update the checksum with</param>
/// <remarks>The characters in the string are converted by the UTF-8 encoding</remarks>
void Update(string data);
/// <summary>
/// Updates the current checksum with the data from a string, using a specific encoding
/// </summary>
/// <param name="data">The string to update the checksum with</param>
/// <param name="encoding">The encoding to use</param>
void Update(string data, Encoding encoding);
}
/// <summary>
/// Represents the method that will be called from a codec when new data
/// are available.
/// </summary>
/// <paramref name="data">The byte array containing the processed data</paramref>
/// <paramref name="startIndex">The index of the first processed byte in <c>data</c></paramref>
/// <paramref name="count">The number of processed bytes available</paramref>
/// <remarks>On return from this method, the data may be overwritten, so grab it while you can.
/// You cannot assume that startIndex will be zero.
/// </remarks>
public delegate void DataAvailableHandler(byte[] data, int startIndex, int count);
/// <summary>
/// Declares methods and events for implementing compressors/decompressors
/// </summary>
public interface Codec
{
/// <summary>
/// Occurs when more processed data are available.
/// </summary>
event DataAvailableHandler DataAvailable;
/// <summary>
/// Adds more data to the codec to be processed.
/// </summary>
/// <param name="data">Byte array containing the data to be added to the codec</param>
/// <remarks>Adding data may, or may not, raise the <c>DataAvailable</c> event</remarks>
void Add(byte[] data);
/// <summary>
/// Adds more data to the codec to be processed.
/// </summary>
/// <param name="data">Byte array containing the data to be added to the codec</param>
/// <param name="offset">The index of the first byte to add from <c>data</c></param>
/// <param name="count">The number of bytes to add</param>
/// <remarks>Adding data may, or may not, raise the <c>DataAvailable</c> event</remarks>
void Add(byte[] data, int offset, int count);
/// <summary>
/// Finishes up any pending data that needs to be processed and handled.
/// </summary>
void Finish();
/// <summary>
/// Gets the checksum of the data that has been added so far
/// </summary>
uint Checksum { get; }
}
#endregion
#region Classes
/// <summary>
/// Encapsulates general information about the ZLib library
/// </summary>
public class Info
{
#region DLL imports
[DllImport("ZLIB1.dll", CallingConvention=CallingConvention.Cdecl)]
private static extern uint zlibCompileFlags();
[DllImport("ZLIB1.dll", CallingConvention=CallingConvention.Cdecl)]
private static extern string zlibVersion();
#endregion
#region Private stuff
private uint _flags;
// helper function that unpacks a bitsize mask
private static int bitSize(uint bits)
{
switch (bits)
{
case 0: return 16;
case 1: return 32;
case 2: return 64;
}
return -1;
}
#endregion
/// <summary>
/// Constructs an instance of the <c>Info</c> class.
/// </summary>
public Info()
{
_flags = zlibCompileFlags();
}
/// <summary>
/// True if the library is compiled with debug info
/// </summary>
public bool HasDebugInfo { get { return 0 != (_flags & 0x100); } }
/// <summary>
/// True if the library is compiled with assembly optimizations
/// </summary>
public bool UsesAssemblyCode { get { return 0 != (_flags & 0x200); } }
/// <summary>
/// Gets the size of the unsigned int that was compiled into Zlib
/// </summary>
public int SizeOfUInt { get { return bitSize(_flags & 3); } }
/// <summary>
/// Gets the size of the unsigned long that was compiled into Zlib
/// </summary>
public int SizeOfULong { get { return bitSize((_flags >> 2) & 3); } }
/// <summary>
/// Gets the size of the pointers that were compiled into Zlib
/// </summary>
public int SizeOfPointer { get { return bitSize((_flags >> 4) & 3); } }
/// <summary>
/// Gets the size of the z_off_t type that was compiled into Zlib
/// </summary>
public int SizeOfOffset { get { return bitSize((_flags >> 6) & 3); } }
/// <summary>
/// Gets the version of ZLib as a string, e.g. "1.2.1"
/// </summary>
public static string Version { get { return zlibVersion(); } }
}
#endregion
}

View File

@ -1,141 +1,141 @@
<VisualStudioProject>
<CSHARP
ProjectType = "Local"
ProductVersion = "7.10.3077"
SchemaVersion = "2.0"
ProjectGuid = "{BB1EE0B1-1808-46CB-B786-949D91117FC5}"
>
<Build>
<Settings
ApplicationIcon = ""
AssemblyKeyContainerName = ""
AssemblyName = "DotZLib"
AssemblyOriginatorKeyFile = ""
DefaultClientScript = "JScript"
DefaultHTMLPageLayout = "Grid"
DefaultTargetSchema = "IE50"
DelaySign = "false"
OutputType = "Library"
PreBuildEvent = ""
PostBuildEvent = ""
RootNamespace = "DotZLib"
RunPostBuildEvent = "OnBuildSuccess"
StartupObject = ""
>
<Config
Name = "Debug"
AllowUnsafeBlocks = "false"
BaseAddress = "285212672"
CheckForOverflowUnderflow = "false"
ConfigurationOverrideFile = ""
DefineConstants = "DEBUG;TRACE"
DocumentationFile = "docs\DotZLib.xml"
DebugSymbols = "true"
FileAlignment = "4096"
IncrementalBuild = "false"
NoStdLib = "false"
NoWarn = "1591"
Optimize = "false"
OutputPath = "bin\Debug\"
RegisterForComInterop = "false"
RemoveIntegerChecks = "false"
TreatWarningsAsErrors = "false"
WarningLevel = "4"
/>
<Config
Name = "Release"
AllowUnsafeBlocks = "false"
BaseAddress = "285212672"
CheckForOverflowUnderflow = "false"
ConfigurationOverrideFile = ""
DefineConstants = "TRACE"
DocumentationFile = "docs\DotZLib.xml"
DebugSymbols = "false"
FileAlignment = "4096"
IncrementalBuild = "false"
NoStdLib = "false"
NoWarn = ""
Optimize = "true"
OutputPath = "bin\Release\"
RegisterForComInterop = "false"
RemoveIntegerChecks = "false"
TreatWarningsAsErrors = "false"
WarningLevel = "4"
/>
</Settings>
<References>
<Reference
Name = "System"
AssemblyName = "System"
HintPath = "C:\WINNT\Microsoft.NET\Framework\v1.1.4322\System.dll"
/>
<Reference
Name = "System.Data"
AssemblyName = "System.Data"
HintPath = "C:\WINNT\Microsoft.NET\Framework\v1.1.4322\System.Data.dll"
/>
<Reference
Name = "System.XML"
AssemblyName = "System.Xml"
HintPath = "C:\WINNT\Microsoft.NET\Framework\v1.1.4322\System.XML.dll"
/>
<Reference
Name = "nunit.framework"
AssemblyName = "nunit.framework"
HintPath = "E:\apps\NUnit V2.1\\bin\nunit.framework.dll"
AssemblyFolderKey = "hklm\dn\nunit.framework"
/>
</References>
</Build>
<Files>
<Include>
<File
RelPath = "AssemblyInfo.cs"
SubType = "Code"
BuildAction = "Compile"
/>
<File
RelPath = "ChecksumImpl.cs"
SubType = "Code"
BuildAction = "Compile"
/>
<File
RelPath = "CircularBuffer.cs"
SubType = "Code"
BuildAction = "Compile"
/>
<File
RelPath = "CodecBase.cs"
SubType = "Code"
BuildAction = "Compile"
/>
<File
RelPath = "Deflater.cs"
SubType = "Code"
BuildAction = "Compile"
/>
<File
RelPath = "DotZLib.cs"
SubType = "Code"
BuildAction = "Compile"
/>
<File
RelPath = "GZipStream.cs"
SubType = "Code"
BuildAction = "Compile"
/>
<File
RelPath = "Inflater.cs"
SubType = "Code"
BuildAction = "Compile"
/>
<File
RelPath = "UnitTests.cs"
SubType = "Code"
BuildAction = "Compile"
/>
</Include>
</Files>
</CSHARP>
</VisualStudioProject>
<VisualStudioProject>
<CSHARP
ProjectType = "Local"
ProductVersion = "7.10.3077"
SchemaVersion = "2.0"
ProjectGuid = "{BB1EE0B1-1808-46CB-B786-949D91117FC5}"
>
<Build>
<Settings
ApplicationIcon = ""
AssemblyKeyContainerName = ""
AssemblyName = "DotZLib"
AssemblyOriginatorKeyFile = ""
DefaultClientScript = "JScript"
DefaultHTMLPageLayout = "Grid"
DefaultTargetSchema = "IE50"
DelaySign = "false"
OutputType = "Library"
PreBuildEvent = ""
PostBuildEvent = ""
RootNamespace = "DotZLib"
RunPostBuildEvent = "OnBuildSuccess"
StartupObject = ""
>
<Config
Name = "Debug"
AllowUnsafeBlocks = "false"
BaseAddress = "285212672"
CheckForOverflowUnderflow = "false"
ConfigurationOverrideFile = ""
DefineConstants = "DEBUG;TRACE"
DocumentationFile = "docs\DotZLib.xml"
DebugSymbols = "true"
FileAlignment = "4096"
IncrementalBuild = "false"
NoStdLib = "false"
NoWarn = "1591"
Optimize = "false"
OutputPath = "bin\Debug\"
RegisterForComInterop = "false"
RemoveIntegerChecks = "false"
TreatWarningsAsErrors = "false"
WarningLevel = "4"
/>
<Config
Name = "Release"
AllowUnsafeBlocks = "false"
BaseAddress = "285212672"
CheckForOverflowUnderflow = "false"
ConfigurationOverrideFile = ""
DefineConstants = "TRACE"
DocumentationFile = "docs\DotZLib.xml"
DebugSymbols = "false"
FileAlignment = "4096"
IncrementalBuild = "false"
NoStdLib = "false"
NoWarn = ""
Optimize = "true"
OutputPath = "bin\Release\"
RegisterForComInterop = "false"
RemoveIntegerChecks = "false"
TreatWarningsAsErrors = "false"
WarningLevel = "4"
/>
</Settings>
<References>
<Reference
Name = "System"
AssemblyName = "System"
HintPath = "C:\WINNT\Microsoft.NET\Framework\v1.1.4322\System.dll"
/>
<Reference
Name = "System.Data"
AssemblyName = "System.Data"
HintPath = "C:\WINNT\Microsoft.NET\Framework\v1.1.4322\System.Data.dll"
/>
<Reference
Name = "System.XML"
AssemblyName = "System.Xml"
HintPath = "C:\WINNT\Microsoft.NET\Framework\v1.1.4322\System.XML.dll"
/>
<Reference
Name = "nunit.framework"
AssemblyName = "nunit.framework"
HintPath = "E:\apps\NUnit V2.1\\bin\nunit.framework.dll"
AssemblyFolderKey = "hklm\dn\nunit.framework"
/>
</References>
</Build>
<Files>
<Include>
<File
RelPath = "AssemblyInfo.cs"
SubType = "Code"
BuildAction = "Compile"
/>
<File
RelPath = "ChecksumImpl.cs"
SubType = "Code"
BuildAction = "Compile"
/>
<File
RelPath = "CircularBuffer.cs"
SubType = "Code"
BuildAction = "Compile"
/>
<File
RelPath = "CodecBase.cs"
SubType = "Code"
BuildAction = "Compile"
/>
<File
RelPath = "Deflater.cs"
SubType = "Code"
BuildAction = "Compile"
/>
<File
RelPath = "DotZLib.cs"
SubType = "Code"
BuildAction = "Compile"
/>
<File
RelPath = "GZipStream.cs"
SubType = "Code"
BuildAction = "Compile"
/>
<File
RelPath = "Inflater.cs"
SubType = "Code"
BuildAction = "Compile"
/>
<File
RelPath = "UnitTests.cs"
SubType = "Code"
BuildAction = "Compile"
/>
</Include>
</Files>
</CSHARP>
</VisualStudioProject>

View File

@ -1,301 +1,301 @@
//
// © Copyright Henrik Ravn 2004
//
// Use, modification and distribution are subject to the Boost Software License, Version 1.0.
// (See accompanying file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
//
using System;
using System.IO;
using System.Runtime.InteropServices;
namespace DotZLib
{
/// <summary>
/// Implements a compressed <see cref="Stream"/>, in GZip (.gz) format.
/// </summary>
public class GZipStream : Stream, IDisposable
{
#region Dll Imports
[DllImport("ZLIB1.dll", CallingConvention=CallingConvention.Cdecl, CharSet=CharSet.Ansi)]
private static extern IntPtr gzopen(string name, string mode);
[DllImport("ZLIB1.dll", CallingConvention=CallingConvention.Cdecl)]
private static extern int gzclose(IntPtr gzFile);
[DllImport("ZLIB1.dll", CallingConvention=CallingConvention.Cdecl)]
private static extern int gzwrite(IntPtr gzFile, int data, int length);
[DllImport("ZLIB1.dll", CallingConvention=CallingConvention.Cdecl)]
private static extern int gzread(IntPtr gzFile, int data, int length);
[DllImport("ZLIB1.dll", CallingConvention=CallingConvention.Cdecl)]
private static extern int gzgetc(IntPtr gzFile);
[DllImport("ZLIB1.dll", CallingConvention=CallingConvention.Cdecl)]
private static extern int gzputc(IntPtr gzFile, int c);
#endregion
#region Private data
private IntPtr _gzFile;
private bool _isDisposed = false;
private bool _isWriting;
#endregion
#region Constructors
/// <summary>
/// Creates a new file as a writeable GZipStream
/// </summary>
/// <param name="fileName">The name of the compressed file to create</param>
/// <param name="level">The compression level to use when adding data</param>
/// <exception cref="ZLibException">If an error occurred in the internal zlib function</exception>
public GZipStream(string fileName, CompressLevel level)
{
_isWriting = true;
_gzFile = gzopen(fileName, String.Format("wb{0}", (int)level));
if (_gzFile == IntPtr.Zero)
throw new ZLibException(-1, "Could not open " + fileName);
}
/// <summary>
/// Opens an existing file as a readable GZipStream
/// </summary>
/// <param name="fileName">The name of the file to open</param>
/// <exception cref="ZLibException">If an error occurred in the internal zlib function</exception>
public GZipStream(string fileName)
{
_isWriting = false;
_gzFile = gzopen(fileName, "rb");
if (_gzFile == IntPtr.Zero)
throw new ZLibException(-1, "Could not open " + fileName);
}
#endregion
#region Access properties
/// <summary>
/// Returns true of this stream can be read from, false otherwise
/// </summary>
public override bool CanRead
{
get
{
return !_isWriting;
}
}
/// <summary>
/// Returns false.
/// </summary>
public override bool CanSeek
{
get
{
return false;
}
}
/// <summary>
/// Returns true if this tsream is writeable, false otherwise
/// </summary>
public override bool CanWrite
{
get
{
return _isWriting;
}
}
#endregion
#region Destructor & IDispose stuff
/// <summary>
/// Destroys this instance
/// </summary>
~GZipStream()
{
cleanUp(false);
}
/// <summary>
/// Closes the external file handle
/// </summary>
public void Dispose()
{
cleanUp(true);
}
// Does the actual closing of the file handle.
private void cleanUp(bool isDisposing)
{
if (!_isDisposed)
{
gzclose(_gzFile);
_isDisposed = true;
}
}
#endregion
#region Basic reading and writing
/// <summary>
/// Attempts to read a number of bytes from the stream.
/// </summary>
/// <param name="buffer">The destination data buffer</param>
/// <param name="offset">The index of the first destination byte in <c>buffer</c></param>
/// <param name="count">The number of bytes requested</param>
/// <returns>The number of bytes read</returns>
/// <exception cref="ArgumentNullException">If <c>buffer</c> is null</exception>
/// <exception cref="ArgumentOutOfRangeException">If <c>count</c> or <c>offset</c> are negative</exception>
/// <exception cref="ArgumentException">If <c>offset</c> + <c>count</c> is &gt; buffer.Length</exception>
/// <exception cref="NotSupportedException">If this stream is not readable.</exception>
/// <exception cref="ObjectDisposedException">If this stream has been disposed.</exception>
public override int Read(byte[] buffer, int offset, int count)
{
if (!CanRead) throw new NotSupportedException();
if (buffer == null) throw new ArgumentNullException();
if (offset < 0 || count < 0) throw new ArgumentOutOfRangeException();
if ((offset+count) > buffer.Length) throw new ArgumentException();
if (_isDisposed) throw new ObjectDisposedException("GZipStream");
GCHandle h = GCHandle.Alloc(buffer, GCHandleType.Pinned);
int result;
try
{
result = gzread(_gzFile, h.AddrOfPinnedObject().ToInt32() + offset, count);
if (result < 0)
throw new IOException();
}
finally
{
h.Free();
}
return result;
}
/// <summary>
/// Attempts to read a single byte from the stream.
/// </summary>
/// <returns>The byte that was read, or -1 in case of error or End-Of-File</returns>
public override int ReadByte()
{
if (!CanRead) throw new NotSupportedException();
if (_isDisposed) throw new ObjectDisposedException("GZipStream");
return gzgetc(_gzFile);
}
/// <summary>
/// Writes a number of bytes to the stream
/// </summary>
/// <param name="buffer"></param>
/// <param name="offset"></param>
/// <param name="count"></param>
/// <exception cref="ArgumentNullException">If <c>buffer</c> is null</exception>
/// <exception cref="ArgumentOutOfRangeException">If <c>count</c> or <c>offset</c> are negative</exception>
/// <exception cref="ArgumentException">If <c>offset</c> + <c>count</c> is &gt; buffer.Length</exception>
/// <exception cref="NotSupportedException">If this stream is not writeable.</exception>
/// <exception cref="ObjectDisposedException">If this stream has been disposed.</exception>
public override void Write(byte[] buffer, int offset, int count)
{
if (!CanWrite) throw new NotSupportedException();
if (buffer == null) throw new ArgumentNullException();
if (offset < 0 || count < 0) throw new ArgumentOutOfRangeException();
if ((offset+count) > buffer.Length) throw new ArgumentException();
if (_isDisposed) throw new ObjectDisposedException("GZipStream");
GCHandle h = GCHandle.Alloc(buffer, GCHandleType.Pinned);
try
{
int result = gzwrite(_gzFile, h.AddrOfPinnedObject().ToInt32() + offset, count);
if (result < 0)
throw new IOException();
}
finally
{
h.Free();
}
}
/// <summary>
/// Writes a single byte to the stream
/// </summary>
/// <param name="value">The byte to add to the stream.</param>
/// <exception cref="NotSupportedException">If this stream is not writeable.</exception>
/// <exception cref="ObjectDisposedException">If this stream has been disposed.</exception>
public override void WriteByte(byte value)
{
if (!CanWrite) throw new NotSupportedException();
if (_isDisposed) throw new ObjectDisposedException("GZipStream");
int result = gzputc(_gzFile, (int)value);
if (result < 0)
throw new IOException();
}
#endregion
#region Position & length stuff
/// <summary>
/// Not supported.
/// </summary>
/// <param name="value"></param>
/// <exception cref="NotSupportedException">Always thrown</exception>
public override void SetLength(long value)
{
throw new NotSupportedException();
}
/// <summary>
/// Not suppported.
/// </summary>
/// <param name="offset"></param>
/// <param name="origin"></param>
/// <returns></returns>
/// <exception cref="NotSupportedException">Always thrown</exception>
public override long Seek(long offset, SeekOrigin origin)
{
throw new NotSupportedException();
}
/// <summary>
/// Flushes the <c>GZipStream</c>.
/// </summary>
/// <remarks>In this implementation, this method does nothing. This is because excessive
/// flushing may degrade the achievable compression rates.</remarks>
public override void Flush()
{
// left empty on purpose
}
/// <summary>
/// Gets/sets the current position in the <c>GZipStream</c>. Not suppported.
/// </summary>
/// <remarks>In this implementation this property is not supported</remarks>
/// <exception cref="NotSupportedException">Always thrown</exception>
public override long Position
{
get
{
throw new NotSupportedException();
}
set
{
throw new NotSupportedException();
}
}
/// <summary>
/// Gets the size of the stream. Not suppported.
/// </summary>
/// <remarks>In this implementation this property is not supported</remarks>
/// <exception cref="NotSupportedException">Always thrown</exception>
public override long Length
{
get
{
throw new NotSupportedException();
}
}
#endregion
}
}
//
// © Copyright Henrik Ravn 2004
//
// Use, modification and distribution are subject to the Boost Software License, Version 1.0.
// (See accompanying file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
//
using System;
using System.IO;
using System.Runtime.InteropServices;
namespace DotZLib
{
/// <summary>
/// Implements a compressed <see cref="Stream"/>, in GZip (.gz) format.
/// </summary>
public class GZipStream : Stream, IDisposable
{
#region Dll Imports
[DllImport("ZLIB1.dll", CallingConvention=CallingConvention.Cdecl, CharSet=CharSet.Ansi)]
private static extern IntPtr gzopen(string name, string mode);
[DllImport("ZLIB1.dll", CallingConvention=CallingConvention.Cdecl)]
private static extern int gzclose(IntPtr gzFile);
[DllImport("ZLIB1.dll", CallingConvention=CallingConvention.Cdecl)]
private static extern int gzwrite(IntPtr gzFile, int data, int length);
[DllImport("ZLIB1.dll", CallingConvention=CallingConvention.Cdecl)]
private static extern int gzread(IntPtr gzFile, int data, int length);
[DllImport("ZLIB1.dll", CallingConvention=CallingConvention.Cdecl)]
private static extern int gzgetc(IntPtr gzFile);
[DllImport("ZLIB1.dll", CallingConvention=CallingConvention.Cdecl)]
private static extern int gzputc(IntPtr gzFile, int c);
#endregion
#region Private data
private IntPtr _gzFile;
private bool _isDisposed = false;
private bool _isWriting;
#endregion
#region Constructors
/// <summary>
/// Creates a new file as a writeable GZipStream
/// </summary>
/// <param name="fileName">The name of the compressed file to create</param>
/// <param name="level">The compression level to use when adding data</param>
/// <exception cref="ZLibException">If an error occurred in the internal zlib function</exception>
public GZipStream(string fileName, CompressLevel level)
{
_isWriting = true;
_gzFile = gzopen(fileName, String.Format("wb{0}", (int)level));
if (_gzFile == IntPtr.Zero)
throw new ZLibException(-1, "Could not open " + fileName);
}
/// <summary>
/// Opens an existing file as a readable GZipStream
/// </summary>
/// <param name="fileName">The name of the file to open</param>
/// <exception cref="ZLibException">If an error occurred in the internal zlib function</exception>
public GZipStream(string fileName)
{
_isWriting = false;
_gzFile = gzopen(fileName, "rb");
if (_gzFile == IntPtr.Zero)
throw new ZLibException(-1, "Could not open " + fileName);
}
#endregion
#region Access properties
/// <summary>
/// Returns true of this stream can be read from, false otherwise
/// </summary>
public override bool CanRead
{
get
{
return !_isWriting;
}
}
/// <summary>
/// Returns false.
/// </summary>
public override bool CanSeek
{
get
{
return false;
}
}
/// <summary>
/// Returns true if this tsream is writeable, false otherwise
/// </summary>
public override bool CanWrite
{
get
{
return _isWriting;
}
}
#endregion
#region Destructor & IDispose stuff
/// <summary>
/// Destroys this instance
/// </summary>
~GZipStream()
{
cleanUp(false);
}
/// <summary>
/// Closes the external file handle
/// </summary>
public void Dispose()
{
cleanUp(true);
}
// Does the actual closing of the file handle.
private void cleanUp(bool isDisposing)
{
if (!_isDisposed)
{
gzclose(_gzFile);
_isDisposed = true;
}
}
#endregion
#region Basic reading and writing
/// <summary>
/// Attempts to read a number of bytes from the stream.
/// </summary>
/// <param name="buffer">The destination data buffer</param>
/// <param name="offset">The index of the first destination byte in <c>buffer</c></param>
/// <param name="count">The number of bytes requested</param>
/// <returns>The number of bytes read</returns>
/// <exception cref="ArgumentNullException">If <c>buffer</c> is null</exception>
/// <exception cref="ArgumentOutOfRangeException">If <c>count</c> or <c>offset</c> are negative</exception>
/// <exception cref="ArgumentException">If <c>offset</c> + <c>count</c> is &gt; buffer.Length</exception>
/// <exception cref="NotSupportedException">If this stream is not readable.</exception>
/// <exception cref="ObjectDisposedException">If this stream has been disposed.</exception>
public override int Read(byte[] buffer, int offset, int count)
{
if (!CanRead) throw new NotSupportedException();
if (buffer == null) throw new ArgumentNullException();
if (offset < 0 || count < 0) throw new ArgumentOutOfRangeException();
if ((offset+count) > buffer.Length) throw new ArgumentException();
if (_isDisposed) throw new ObjectDisposedException("GZipStream");
GCHandle h = GCHandle.Alloc(buffer, GCHandleType.Pinned);
int result;
try
{
result = gzread(_gzFile, h.AddrOfPinnedObject().ToInt32() + offset, count);
if (result < 0)
throw new IOException();
}
finally
{
h.Free();
}
return result;
}
/// <summary>
/// Attempts to read a single byte from the stream.
/// </summary>
/// <returns>The byte that was read, or -1 in case of error or End-Of-File</returns>
public override int ReadByte()
{
if (!CanRead) throw new NotSupportedException();
if (_isDisposed) throw new ObjectDisposedException("GZipStream");
return gzgetc(_gzFile);
}
/// <summary>
/// Writes a number of bytes to the stream
/// </summary>
/// <param name="buffer"></param>
/// <param name="offset"></param>
/// <param name="count"></param>
/// <exception cref="ArgumentNullException">If <c>buffer</c> is null</exception>
/// <exception cref="ArgumentOutOfRangeException">If <c>count</c> or <c>offset</c> are negative</exception>
/// <exception cref="ArgumentException">If <c>offset</c> + <c>count</c> is &gt; buffer.Length</exception>
/// <exception cref="NotSupportedException">If this stream is not writeable.</exception>
/// <exception cref="ObjectDisposedException">If this stream has been disposed.</exception>
public override void Write(byte[] buffer, int offset, int count)
{
if (!CanWrite) throw new NotSupportedException();
if (buffer == null) throw new ArgumentNullException();
if (offset < 0 || count < 0) throw new ArgumentOutOfRangeException();
if ((offset+count) > buffer.Length) throw new ArgumentException();
if (_isDisposed) throw new ObjectDisposedException("GZipStream");
GCHandle h = GCHandle.Alloc(buffer, GCHandleType.Pinned);
try
{
int result = gzwrite(_gzFile, h.AddrOfPinnedObject().ToInt32() + offset, count);
if (result < 0)
throw new IOException();
}
finally
{
h.Free();
}
}
/// <summary>
/// Writes a single byte to the stream
/// </summary>
/// <param name="value">The byte to add to the stream.</param>
/// <exception cref="NotSupportedException">If this stream is not writeable.</exception>
/// <exception cref="ObjectDisposedException">If this stream has been disposed.</exception>
public override void WriteByte(byte value)
{
if (!CanWrite) throw new NotSupportedException();
if (_isDisposed) throw new ObjectDisposedException("GZipStream");
int result = gzputc(_gzFile, (int)value);
if (result < 0)
throw new IOException();
}
#endregion
#region Position & length stuff
/// <summary>
/// Not supported.
/// </summary>
/// <param name="value"></param>
/// <exception cref="NotSupportedException">Always thrown</exception>
public override void SetLength(long value)
{
throw new NotSupportedException();
}
/// <summary>
/// Not suppported.
/// </summary>
/// <param name="offset"></param>
/// <param name="origin"></param>
/// <returns></returns>
/// <exception cref="NotSupportedException">Always thrown</exception>
public override long Seek(long offset, SeekOrigin origin)
{
throw new NotSupportedException();
}
/// <summary>
/// Flushes the <c>GZipStream</c>.
/// </summary>
/// <remarks>In this implementation, this method does nothing. This is because excessive
/// flushing may degrade the achievable compression rates.</remarks>
public override void Flush()
{
// left empty on purpose
}
/// <summary>
/// Gets/sets the current position in the <c>GZipStream</c>. Not suppported.
/// </summary>
/// <remarks>In this implementation this property is not supported</remarks>
/// <exception cref="NotSupportedException">Always thrown</exception>
public override long Position
{
get
{
throw new NotSupportedException();
}
set
{
throw new NotSupportedException();
}
}
/// <summary>
/// Gets the size of the stream. Not suppported.
/// </summary>
/// <remarks>In this implementation this property is not supported</remarks>
/// <exception cref="NotSupportedException">Always thrown</exception>
public override long Length
{
get
{
throw new NotSupportedException();
}
}
#endregion
}
}

View File

@ -1,105 +1,105 @@
//
// © Copyright Henrik Ravn 2004
//
// Use, modification and distribution are subject to the Boost Software License, Version 1.0.
// (See accompanying file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
//
using System;
using System.Diagnostics;
using System.Runtime.InteropServices;
namespace DotZLib
{
/// <summary>
/// Implements a data decompressor, using the inflate algorithm in the ZLib dll
/// </summary>
public class Inflater : CodecBase
{
#region Dll imports
[DllImport("ZLIB1.dll", CallingConvention=CallingConvention.Cdecl, CharSet=CharSet.Ansi)]
private static extern int inflateInit_(ref ZStream sz, string vs, int size);
[DllImport("ZLIB1.dll", CallingConvention=CallingConvention.Cdecl)]
private static extern int inflate(ref ZStream sz, int flush);
[DllImport("ZLIB1.dll", CallingConvention=CallingConvention.Cdecl)]
private static extern int inflateReset(ref ZStream sz);
[DllImport("ZLIB1.dll", CallingConvention=CallingConvention.Cdecl)]
private static extern int inflateEnd(ref ZStream sz);
#endregion
/// <summary>
/// Constructs an new instance of the <c>Inflater</c>
/// </summary>
public Inflater() : base()
{
int retval = inflateInit_(ref _ztream, Info.Version, Marshal.SizeOf(_ztream));
if (retval != 0)
throw new ZLibException(retval, "Could not initialize inflater");
resetOutput();
}
/// <summary>
/// Adds more data to the codec to be processed.
/// </summary>
/// <param name="data">Byte array containing the data to be added to the codec</param>
/// <param name="offset">The index of the first byte to add from <c>data</c></param>
/// <param name="count">The number of bytes to add</param>
/// <remarks>Adding data may, or may not, raise the <c>DataAvailable</c> event</remarks>
public override void Add(byte[] data, int offset, int count)
{
if (data == null) throw new ArgumentNullException();
if (offset < 0 || count < 0) throw new ArgumentOutOfRangeException();
if ((offset+count) > data.Length) throw new ArgumentException();
int total = count;
int inputIndex = offset;
int err = 0;
while (err >= 0 && inputIndex < total)
{
copyInput(data, inputIndex, Math.Min(total - inputIndex, kBufferSize));
err = inflate(ref _ztream, (int)FlushTypes.None);
if (err == 0)
while (_ztream.avail_out == 0)
{
OnDataAvailable();
err = inflate(ref _ztream, (int)FlushTypes.None);
}
inputIndex += (int)_ztream.total_in;
}
setChecksum( _ztream.adler );
}
/// <summary>
/// Finishes up any pending data that needs to be processed and handled.
/// </summary>
public override void Finish()
{
int err;
do
{
err = inflate(ref _ztream, (int)FlushTypes.Finish);
OnDataAvailable();
}
while (err == 0);
setChecksum( _ztream.adler );
inflateReset(ref _ztream);
resetOutput();
}
/// <summary>
/// Closes the internal zlib inflate stream
/// </summary>
protected override void CleanUp() { inflateEnd(ref _ztream); }
}
}
//
// © Copyright Henrik Ravn 2004
//
// Use, modification and distribution are subject to the Boost Software License, Version 1.0.
// (See accompanying file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
//
using System;
using System.Diagnostics;
using System.Runtime.InteropServices;
namespace DotZLib
{
/// <summary>
/// Implements a data decompressor, using the inflate algorithm in the ZLib dll
/// </summary>
public class Inflater : CodecBase
{
#region Dll imports
[DllImport("ZLIB1.dll", CallingConvention=CallingConvention.Cdecl, CharSet=CharSet.Ansi)]
private static extern int inflateInit_(ref ZStream sz, string vs, int size);
[DllImport("ZLIB1.dll", CallingConvention=CallingConvention.Cdecl)]
private static extern int inflate(ref ZStream sz, int flush);
[DllImport("ZLIB1.dll", CallingConvention=CallingConvention.Cdecl)]
private static extern int inflateReset(ref ZStream sz);
[DllImport("ZLIB1.dll", CallingConvention=CallingConvention.Cdecl)]
private static extern int inflateEnd(ref ZStream sz);
#endregion
/// <summary>
/// Constructs an new instance of the <c>Inflater</c>
/// </summary>
public Inflater() : base()
{
int retval = inflateInit_(ref _ztream, Info.Version, Marshal.SizeOf(_ztream));
if (retval != 0)
throw new ZLibException(retval, "Could not initialize inflater");
resetOutput();
}
/// <summary>
/// Adds more data to the codec to be processed.
/// </summary>
/// <param name="data">Byte array containing the data to be added to the codec</param>
/// <param name="offset">The index of the first byte to add from <c>data</c></param>
/// <param name="count">The number of bytes to add</param>
/// <remarks>Adding data may, or may not, raise the <c>DataAvailable</c> event</remarks>
public override void Add(byte[] data, int offset, int count)
{
if (data == null) throw new ArgumentNullException();
if (offset < 0 || count < 0) throw new ArgumentOutOfRangeException();
if ((offset+count) > data.Length) throw new ArgumentException();
int total = count;
int inputIndex = offset;
int err = 0;
while (err >= 0 && inputIndex < total)
{
copyInput(data, inputIndex, Math.Min(total - inputIndex, kBufferSize));
err = inflate(ref _ztream, (int)FlushTypes.None);
if (err == 0)
while (_ztream.avail_out == 0)
{
OnDataAvailable();
err = inflate(ref _ztream, (int)FlushTypes.None);
}
inputIndex += (int)_ztream.total_in;
}
setChecksum( _ztream.adler );
}
/// <summary>
/// Finishes up any pending data that needs to be processed and handled.
/// </summary>
public override void Finish()
{
int err;
do
{
err = inflate(ref _ztream, (int)FlushTypes.Finish);
OnDataAvailable();
}
while (err == 0);
setChecksum( _ztream.adler );
inflateReset(ref _ztream);
resetOutput();
}
/// <summary>
/// Closes the internal zlib inflate stream
/// </summary>
protected override void CleanUp() { inflateEnd(ref _ztream); }
}
}

View File

@ -1,274 +1,274 @@
//
// © Copyright Henrik Ravn 2004
//
// Use, modification and distribution are subject to the Boost Software License, Version 1.0.
// (See accompanying file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
//
using System;
using System.Collections;
using System.IO;
// uncomment the define below to include unit tests
//#define nunit
#if nunit
using NUnit.Framework;
// Unit tests for the DotZLib class library
// ----------------------------------------
//
// Use this with NUnit 2 from http://www.nunit.org
//
namespace DotZLibTests
{
using DotZLib;
// helper methods
internal class Utils
{
public static bool byteArrEqual( byte[] lhs, byte[] rhs )
{
if (lhs.Length != rhs.Length)
return false;
for (int i = lhs.Length-1; i >= 0; --i)
if (lhs[i] != rhs[i])
return false;
return true;
}
}
[TestFixture]
public class CircBufferTests
{
#region Circular buffer tests
[Test]
public void SinglePutGet()
{
CircularBuffer buf = new CircularBuffer(10);
Assert.AreEqual( 0, buf.Size );
Assert.AreEqual( -1, buf.Get() );
Assert.IsTrue(buf.Put( 1 ));
Assert.AreEqual( 1, buf.Size );
Assert.AreEqual( 1, buf.Get() );
Assert.AreEqual( 0, buf.Size );
Assert.AreEqual( -1, buf.Get() );
}
[Test]
public void BlockPutGet()
{
CircularBuffer buf = new CircularBuffer(10);
byte[] arr = {1,2,3,4,5,6,7,8,9,10};
Assert.AreEqual( 10, buf.Put(arr,0,10) );
Assert.AreEqual( 10, buf.Size );
Assert.IsFalse( buf.Put(11) );
Assert.AreEqual( 1, buf.Get() );
Assert.IsTrue( buf.Put(11) );
byte[] arr2 = (byte[])arr.Clone();
Assert.AreEqual( 9, buf.Get(arr2,1,9) );
Assert.IsTrue( Utils.byteArrEqual(arr,arr2) );
}
#endregion
}
[TestFixture]
public class ChecksumTests
{
#region CRC32 Tests
[Test]
public void CRC32_Null()
{
CRC32Checksum crc32 = new CRC32Checksum();
Assert.AreEqual( 0, crc32.Value );
crc32 = new CRC32Checksum(1);
Assert.AreEqual( 1, crc32.Value );
crc32 = new CRC32Checksum(556);
Assert.AreEqual( 556, crc32.Value );
}
[Test]
public void CRC32_Data()
{
CRC32Checksum crc32 = new CRC32Checksum();
byte[] data = { 1,2,3,4,5,6,7 };
crc32.Update(data);
Assert.AreEqual( 0x70e46888, crc32.Value );
crc32 = new CRC32Checksum();
crc32.Update("penguin");
Assert.AreEqual( 0x0e5c1a120, crc32.Value );
crc32 = new CRC32Checksum(1);
crc32.Update("penguin");
Assert.AreEqual(0x43b6aa94, crc32.Value);
}
#endregion
#region Adler tests
[Test]
public void Adler_Null()
{
AdlerChecksum adler = new AdlerChecksum();
Assert.AreEqual(0, adler.Value);
adler = new AdlerChecksum(1);
Assert.AreEqual( 1, adler.Value );
adler = new AdlerChecksum(556);
Assert.AreEqual( 556, adler.Value );
}
[Test]
public void Adler_Data()
{
AdlerChecksum adler = new AdlerChecksum(1);
byte[] data = { 1,2,3,4,5,6,7 };
adler.Update(data);
Assert.AreEqual( 0x5b001d, adler.Value );
adler = new AdlerChecksum();
adler.Update("penguin");
Assert.AreEqual(0x0bcf02f6, adler.Value );
adler = new AdlerChecksum(1);
adler.Update("penguin");
Assert.AreEqual(0x0bd602f7, adler.Value);
}
#endregion
}
[TestFixture]
public class InfoTests
{
#region Info tests
[Test]
public void Info_Version()
{
Info info = new Info();
Assert.AreEqual("1.2.11", Info.Version);
Assert.AreEqual(32, info.SizeOfUInt);
Assert.AreEqual(32, info.SizeOfULong);
Assert.AreEqual(32, info.SizeOfPointer);
Assert.AreEqual(32, info.SizeOfOffset);
}
#endregion
}
[TestFixture]
public class DeflateInflateTests
{
#region Deflate tests
[Test]
public void Deflate_Init()
{
using (Deflater def = new Deflater(CompressLevel.Default))
{
}
}
private ArrayList compressedData = new ArrayList();
private uint adler1;
private ArrayList uncompressedData = new ArrayList();
private uint adler2;
public void CDataAvail(byte[] data, int startIndex, int count)
{
for (int i = 0; i < count; ++i)
compressedData.Add(data[i+startIndex]);
}
[Test]
public void Deflate_Compress()
{
compressedData.Clear();
byte[] testData = new byte[35000];
for (int i = 0; i < testData.Length; ++i)
testData[i] = 5;
using (Deflater def = new Deflater((CompressLevel)5))
{
def.DataAvailable += new DataAvailableHandler(CDataAvail);
def.Add(testData);
def.Finish();
adler1 = def.Checksum;
}
}
#endregion
#region Inflate tests
[Test]
public void Inflate_Init()
{
using (Inflater inf = new Inflater())
{
}
}
private void DDataAvail(byte[] data, int startIndex, int count)
{
for (int i = 0; i < count; ++i)
uncompressedData.Add(data[i+startIndex]);
}
[Test]
public void Inflate_Expand()
{
uncompressedData.Clear();
using (Inflater inf = new Inflater())
{
inf.DataAvailable += new DataAvailableHandler(DDataAvail);
inf.Add((byte[])compressedData.ToArray(typeof(byte)));
inf.Finish();
adler2 = inf.Checksum;
}
Assert.AreEqual( adler1, adler2 );
}
#endregion
}
[TestFixture]
public class GZipStreamTests
{
#region GZipStream test
[Test]
public void GZipStream_WriteRead()
{
using (GZipStream gzOut = new GZipStream("gzstream.gz", CompressLevel.Best))
{
BinaryWriter writer = new BinaryWriter(gzOut);
writer.Write("hi there");
writer.Write(Math.PI);
writer.Write(42);
}
using (GZipStream gzIn = new GZipStream("gzstream.gz"))
{
BinaryReader reader = new BinaryReader(gzIn);
string s = reader.ReadString();
Assert.AreEqual("hi there",s);
double d = reader.ReadDouble();
Assert.AreEqual(Math.PI, d);
int i = reader.ReadInt32();
Assert.AreEqual(42,i);
}
}
#endregion
}
}
#endif
//
// © Copyright Henrik Ravn 2004
//
// Use, modification and distribution are subject to the Boost Software License, Version 1.0.
// (See accompanying file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
//
using System;
using System.Collections;
using System.IO;
// uncomment the define below to include unit tests
//#define nunit
#if nunit
using NUnit.Framework;
// Unit tests for the DotZLib class library
// ----------------------------------------
//
// Use this with NUnit 2 from http://www.nunit.org
//
namespace DotZLibTests
{
using DotZLib;
// helper methods
internal class Utils
{
public static bool byteArrEqual( byte[] lhs, byte[] rhs )
{
if (lhs.Length != rhs.Length)
return false;
for (int i = lhs.Length-1; i >= 0; --i)
if (lhs[i] != rhs[i])
return false;
return true;
}
}
[TestFixture]
public class CircBufferTests
{
#region Circular buffer tests
[Test]
public void SinglePutGet()
{
CircularBuffer buf = new CircularBuffer(10);
Assert.AreEqual( 0, buf.Size );
Assert.AreEqual( -1, buf.Get() );
Assert.IsTrue(buf.Put( 1 ));
Assert.AreEqual( 1, buf.Size );
Assert.AreEqual( 1, buf.Get() );
Assert.AreEqual( 0, buf.Size );
Assert.AreEqual( -1, buf.Get() );
}
[Test]
public void BlockPutGet()
{
CircularBuffer buf = new CircularBuffer(10);
byte[] arr = {1,2,3,4,5,6,7,8,9,10};
Assert.AreEqual( 10, buf.Put(arr,0,10) );
Assert.AreEqual( 10, buf.Size );
Assert.IsFalse( buf.Put(11) );
Assert.AreEqual( 1, buf.Get() );
Assert.IsTrue( buf.Put(11) );
byte[] arr2 = (byte[])arr.Clone();
Assert.AreEqual( 9, buf.Get(arr2,1,9) );
Assert.IsTrue( Utils.byteArrEqual(arr,arr2) );
}
#endregion
}
[TestFixture]
public class ChecksumTests
{
#region CRC32 Tests
[Test]
public void CRC32_Null()
{
CRC32Checksum crc32 = new CRC32Checksum();
Assert.AreEqual( 0, crc32.Value );
crc32 = new CRC32Checksum(1);
Assert.AreEqual( 1, crc32.Value );
crc32 = new CRC32Checksum(556);
Assert.AreEqual( 556, crc32.Value );
}
[Test]
public void CRC32_Data()
{
CRC32Checksum crc32 = new CRC32Checksum();
byte[] data = { 1,2,3,4,5,6,7 };
crc32.Update(data);
Assert.AreEqual( 0x70e46888, crc32.Value );
crc32 = new CRC32Checksum();
crc32.Update("penguin");
Assert.AreEqual( 0x0e5c1a120, crc32.Value );
crc32 = new CRC32Checksum(1);
crc32.Update("penguin");
Assert.AreEqual(0x43b6aa94, crc32.Value);
}
#endregion
#region Adler tests
[Test]
public void Adler_Null()
{
AdlerChecksum adler = new AdlerChecksum();
Assert.AreEqual(0, adler.Value);
adler = new AdlerChecksum(1);
Assert.AreEqual( 1, adler.Value );
adler = new AdlerChecksum(556);
Assert.AreEqual( 556, adler.Value );
}
[Test]
public void Adler_Data()
{
AdlerChecksum adler = new AdlerChecksum(1);
byte[] data = { 1,2,3,4,5,6,7 };
adler.Update(data);
Assert.AreEqual( 0x5b001d, adler.Value );
adler = new AdlerChecksum();
adler.Update("penguin");
Assert.AreEqual(0x0bcf02f6, adler.Value );
adler = new AdlerChecksum(1);
adler.Update("penguin");
Assert.AreEqual(0x0bd602f7, adler.Value);
}
#endregion
}
[TestFixture]
public class InfoTests
{
#region Info tests
[Test]
public void Info_Version()
{
Info info = new Info();
Assert.AreEqual("1.2.13", Info.Version);
Assert.AreEqual(32, info.SizeOfUInt);
Assert.AreEqual(32, info.SizeOfULong);
Assert.AreEqual(32, info.SizeOfPointer);
Assert.AreEqual(32, info.SizeOfOffset);
}
#endregion
}
[TestFixture]
public class DeflateInflateTests
{
#region Deflate tests
[Test]
public void Deflate_Init()
{
using (Deflater def = new Deflater(CompressLevel.Default))
{
}
}
private ArrayList compressedData = new ArrayList();
private uint adler1;
private ArrayList uncompressedData = new ArrayList();
private uint adler2;
public void CDataAvail(byte[] data, int startIndex, int count)
{
for (int i = 0; i < count; ++i)
compressedData.Add(data[i+startIndex]);
}
[Test]
public void Deflate_Compress()
{
compressedData.Clear();
byte[] testData = new byte[35000];
for (int i = 0; i < testData.Length; ++i)
testData[i] = 5;
using (Deflater def = new Deflater((CompressLevel)5))
{
def.DataAvailable += new DataAvailableHandler(CDataAvail);
def.Add(testData);
def.Finish();
adler1 = def.Checksum;
}
}
#endregion
#region Inflate tests
[Test]
public void Inflate_Init()
{
using (Inflater inf = new Inflater())
{
}
}
private void DDataAvail(byte[] data, int startIndex, int count)
{
for (int i = 0; i < count; ++i)
uncompressedData.Add(data[i+startIndex]);
}
[Test]
public void Inflate_Expand()
{
uncompressedData.Clear();
using (Inflater inf = new Inflater())
{
inf.DataAvailable += new DataAvailableHandler(DDataAvail);
inf.Add((byte[])compressedData.ToArray(typeof(byte)));
inf.Finish();
adler2 = inf.Checksum;
}
Assert.AreEqual( adler1, adler2 );
}
#endregion
}
[TestFixture]
public class GZipStreamTests
{
#region GZipStream test
[Test]
public void GZipStream_WriteRead()
{
using (GZipStream gzOut = new GZipStream("gzstream.gz", CompressLevel.Best))
{
BinaryWriter writer = new BinaryWriter(gzOut);
writer.Write("hi there");
writer.Write(Math.PI);
writer.Write(42);
}
using (GZipStream gzIn = new GZipStream("gzstream.gz"))
{
BinaryReader reader = new BinaryReader(gzIn);
string s = reader.ReadString();
Assert.AreEqual("hi there",s);
double d = reader.ReadDouble();
Assert.AreEqual(Math.PI, d);
int i = reader.ReadInt32();
Assert.AreEqual(42,i);
}
}
#endregion
}
}
#endif

View File

@ -20,4 +20,4 @@ FITNESS FOR A PARTICULAR PURPOSE, TITLE AND NON-INFRINGEMENT. IN NO EVENT
SHALL THE COPYRIGHT HOLDERS OR ANYONE DISTRIBUTING THE SOFTWARE BE LIABLE
FOR ANY DAMAGES OR OTHER LIABILITY, WHETHER IN CONTRACT, TORT OR OTHERWISE,
ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
DEALINGS IN THE SOFTWARE.
DEALINGS IN THE SOFTWARE.

Some files were not shown because too many files have changed in this diff Show More