Uncompress Deflate - c++

I'm working on a function that can uncompress the deflate compression, so i can read/draw png files in my c++ program. However, the deflate specification isn't very clear on some things.
So my main question is:
Paragraph 3.2.7. Compression with dynamic Huffman codes (BTYPE=10) of the specification state that
the distance code follows the literal/length
But it does not state how many bits the distance code occupy, is it an entire byte?
And how does the distance code relate?.. whats its use, really?
Any one have a general explanation? since the specification is kinda lacking in clarity.
The specification i found here:
http://www.ietf.org/rfc/rfc1951.txt
Edit (Here is my following code to use with puff inflate code.)
First the header (ConceptApp.h)
#include "resource.h"
#ifdef _WIN64
typedef unsigned long long SIZE_PTR;
#else
typedef unsigned long SIZE_PTR;
#endif
typedef struct _IMAGE {
DWORD Width; //Width in pixels.
DWORD Height; //Height in pixels.
DWORD BitsPerPixel; //24 (RGB), 32 (RGBA).
DWORD Planes; //Count of color planes
PBYTE Pixels; //Pointer to the first pixel of the image.
} IMAGE, *PIMAGE;
typedef DWORD LodePNGColorType;
typedef struct _LodePNGColorMode {
DWORD colortype;
DWORD bitdepth;
} LodePNGColorMode;
typedef struct LodePNGInfo
{
/*header (IHDR), palette (PLTE) and transparency (tRNS) chunks*/
unsigned compression_method;/*compression method of the original file. Always 0.*/
unsigned filter_method; /*filter method of the original file*/
unsigned interlace_method; /*interlace method of the original file*/
LodePNGColorMode color; /*color type and bits, palette and transparency of the PNG file*/
} LodePNGInfo;
typedef struct _ZLIB {
BYTE CMF;
BYTE FLG;
//DWORD DICTID; //if FLG.FDICT (Bit 5) is set, this variable follows.
//Compressed data here...
} ZLIB, *PZLIB;
typedef struct _PNG_IHDR {
DWORD Width;
DWORD Height;
BYTE BitDepth;
BYTE ColourType;
BYTE CompressionMethod;
BYTE FilterMethod;
BYTE InterlaceMethod;
} PNG_IHDR, *PPNG_IHDR;
typedef struct _PNG_CHUNK {
DWORD Length;
CHAR ChuckType[4];
} PNG_CHUNK, *PPNG_CHUNK;
typedef struct _PNG {
BYTE Signature[8];
PNG_CHUNK FirstChunk;
} PNG, *PPNG;
And the code .cpp file:
The main function can be found at the bottom of the file (LoadPng)
BYTE LoadPng(PPNG PngFile, PIMAGE ImageData)
{
PDWORD Pixel = 0;
DWORD ChunkSize = 0;
PPNG_IHDR PngIhdr = (PPNG_IHDR) ((SIZE_PTR) &PngFile->FirstChunk + sizeof(PNG_CHUNK));
DWORD Png_Width = Png_ReadDword((PBYTE)&PngIhdr->Width);
DWORD Png_Height = Png_ReadDword((PBYTE)&PngIhdr->Height);
DWORD BufferSize = (Png_Width*Png_Height) * 8; //This just a guess right now, havent done the math yet. !!!
ChunkSize = Png_ReadDword((PBYTE)&PngFile->FirstChunk.Length);
PPNG_CHUNK ThisChunk = (PPNG_CHUNK) ((SIZE_PTR)&PngFile->FirstChunk + ChunkSize + 12); //12 is the length var itself, Chunktype and CRC.
PPNG_CHUNK NextChunk;
PBYTE UncompressedData = (PBYTE) malloc(BufferSize);
INT RetValue = 0;
do
{
ChunkSize = Png_ReadDword((PBYTE)&ThisChunk->Length);
NextChunk = (PPNG_CHUNK) ((SIZE_PTR)ThisChunk + ChunkSize + 12); //12 is the length var itself, Chunktype and CRC.
if (Png_IsChunk(ThisChunk->ChuckType, "IDAT")) //Is IDAT ?
{
PZLIB iData = (PZLIB) ((SIZE_PTR)ThisChunk + 8); //8 is the length and chunkType.
PBYTE FirstBlock; //ponter to the first 3 bits of the deflate stuff.
if ((iData->CMF & 8) == 8) //deflate compression method.
{
if ((iData->FLG & 0x20) == 0x20)
{
FirstBlock = (PBYTE) ((SIZE_PTR)iData + 6); //DICTID Present.
}
else FirstBlock = (PBYTE) ((SIZE_PTR)iData + 2); //DICTID Not present.
RetValue = puff(UncompressedData, &BufferSize, FirstBlock, &ChunkSize); //I belive chunksize should be fine.
if (RetValue != 0)
{
WCHAR ErrorText[100];
swprintf_s(ErrorText, 100, L"%u", RetValue); //Convert data into string.
MessageBox(NULL, ErrorText, NULL, MB_OK);
}
}
}
ThisChunk = NextChunk;
} while (!Png_IsChunk(ThisChunk->ChuckType, "IEND"));
//LodePNGInfo ImageInfo;
//PBYTE Png_Real_Image = (PBYTE) malloc(BufferSize);
//ImageInfo.compression_method = PngIhdr->CompressionMethod;
//ImageInfo.filter_method = PngIhdr->FilterMethod;
//ImageInfo.interlace_method = PngIhdr->InterlaceMethod;
//ImageInfo.color.bitdepth = PngIhdr->BitDepth;
//ImageInfo.color.colortype = PngIhdr->ColourType;
//Remove Filter/crap blah blah.
//postProcessScanlines(Png_Real_Image, UncompressedData, Png_Width, Png_Height, &ImageInfo);
ImageData->Width = Png_Width;
ImageData->Height = Png_Height;
ImageData->Planes = 0; //Will need changed later.
ImageData->BitsPerPixel = 32; //Will need changed later.
ImageData->Pixels = 0;
//ImageData->Pixels = Png_Real_Image; //image not uncompressed yet.
return TRUE; //ret true for now. fix later.
}

I just hope to make clearer what is stated before--Huffman coding is a method for encoding values using a variable number of bits. In, say, ASCII coding, every letter gets the same number of bits no matter how frequently it is used. In Huffman coding, you could make "e" have fewer bits than an "X".
The trick in huffman coding is how the codes are prefixed. After reading each bit, the decoder knows, unambiguously, whether it has a value or needs to read another bit.
To comprehend the deflate process you need to understand LZ algorithm and Huffman coding.
On their own, both techniques are simple. The complexity comes from how they are put together.
LZ compresses by finding previous occurrences of a string. When a string has occurred previously, it is compressed by referencing the previous occurrence. The Distance is the offset to the previous occurrence. Distance and length specify that occurrence.

The problem is not with puff.
All the IDAT chunks in the png file need to be put together before calling puff.
It should look something like this:
BYTE LoadPng(PPNG PngFile, PIMAGE ImageData)
{
PDWORD Pixel = 0;
DWORD ChunkSize = 0;
PPNG_IHDR PngIhdr = (PPNG_IHDR) ((SIZE_PTR) &PngFile->FirstChunk + sizeof(PNG_CHUNK));
DWORD Png_Width = Png_ReadDword((PBYTE)&PngIhdr->Width);
DWORD Png_Height = Png_ReadDword((PBYTE)&PngIhdr->Height);
DWORD BufferSize = (Png_Width*Png_Height) * 8; //This just a guess right now, havent done the math yet. !!!
ChunkSize = Png_ReadDword((PBYTE)&PngFile->FirstChunk.Length);
PPNG_CHUNK ThisChunk = (PPNG_CHUNK) ((SIZE_PTR)&PngFile->FirstChunk + ChunkSize + 12); //12 is the length var itself, Chunktype and CRC.
PPNG_CHUNK NextChunk;
PBYTE UncompressedData = (PBYTE) malloc(BufferSize);
PBYTE TempBuffer = (PBYTE) malloc(BufferSize); //Put all idat chunks together befor uncompressing.
DWORD DeflateSize = 0; //All IDAT Chunks Added.
PZLIB iData = NULL;
PBYTE FirstBlock = NULL; //ponter to the first 3 bits of the deflate stuff.
INT RetValue = 0;
do
{
ChunkSize = Png_ReadDword((PBYTE)&ThisChunk->Length);
NextChunk = (PPNG_CHUNK) ((SIZE_PTR)ThisChunk + ChunkSize + 12); //12 is the length var itself, Chunktype and CRC.
if (Png_IsChunk(ThisChunk->ChuckType, "IDAT")) //Is IDAT ?
{
CopyMemory(&TempBuffer[DeflateSize], (PBYTE) ((SIZE_PTR)ThisChunk + 8), ChunkSize); //8 is the length and chunkType.
DeflateSize += ChunkSize;
}
ThisChunk = NextChunk;
} while (!Png_IsChunk(ThisChunk->ChuckType, "IEND"));
iData = (PZLIB) TempBuffer;
if ((iData->CMF & 8) == 8) //deflate compression method.
{
if ((iData->FLG & 0x20) == 0x20)
{
FirstBlock = (PBYTE) ((SIZE_PTR)iData + 6); //DICTID Present.
}
else FirstBlock = (PBYTE) ((SIZE_PTR)iData + 2); //DICTID Not present.
}
RetValue = puff(UncompressedData, &BufferSize, FirstBlock, &DeflateSize); //I belive chunksize should be fine.
if (RetValue != 0)
{
WCHAR ErrorText[100];
swprintf_s(ErrorText, 100, L"%u", RetValue);
MessageBox(NULL, ErrorText, NULL, MB_OK);
}
//LodePNGInfo ImageInfo;
//PBYTE Png_Real_Image = (PBYTE) malloc(BufferSize);
//ImageInfo.compression_method = PngIhdr->CompressionMethod;
//ImageInfo.filter_method = PngIhdr->FilterMethod;
//ImageInfo.interlace_method = PngIhdr->InterlaceMethod;
//ImageInfo.color.bitdepth = PngIhdr->BitDepth;
//ImageInfo.color.colortype = PngIhdr->ColourType;
//Remove Filter/crap blah blah.
//postProcessScanlines(Png_Real_Image, UncompressedData, Png_Width, Png_Height, &ImageInfo);
ImageData->Width = Png_Width;
ImageData->Height = Png_Height;
ImageData->Planes = 0; //Will need changed later.
ImageData->BitsPerPixel = 32; //Will need changed later.
ImageData->Pixels = 0;
//ImageData->Pixels = Png_Real_Image; //image not uncompressed yet.
return TRUE; //ret true for now. fix later.
}

You need to first read up on compression, since there is a lot of basic stuff that you're not getting. E.g. The Data Compression Book, by Nelson and Gailly.
Since it's a code, specifically a Huffman code, by definition the number of bits are variable.
If you don't know what the distance is for, then you need to first understand the LZ77 compression approach.
Lastly, aside from curiosity and self-education, there is no need for you to understand the deflate specification or to write your own inflate code. That's what zlib is for.

Related

How to get all tags from a tiff file with libtiff?

I have a tiff file and would like to get a list of all tags used in that file. If I understand the TiffGetField() function correctly, it only gets the values of tags specified. But how do I know what tags the file uses? I would like to get all used tags in the file. Is there an easy way to get them with libtiff?
It seems to be a very manual process from my experience. I used the TIFF tag reference here https://www.awaresystems.be/imaging/tiff/tifftags.html to create a custom structure
typedef struct
{
TIFF_TAGS_BASELINE Baseline;
TIFF_TAGS_EXTENSION Extension;
TIFF_TAGS_PRIVATE Private;
} TIFF_TAGS;
With each substructure custom defined. For example,
typedef struct
{
TIFF_UINT32_T NewSubfileType; // TIFFTAG_SUBFILETYPE
TIFF_UINT16_T SubfileType; // TIFFTAG_OSUBFILETYPE
TIFF_UINT32_T ImageWidth; // TIFFTAG_IMAGEWIDTH
TIFF_UINT32_T ImageLength; // TIFFTAG_IMAGELENGTH
TIFF_UINT16_T BitsPerSample; // TIFFTAG_BITSPERSAMPLE
...
char *Copyright; // TIFFTAG_COPYRIGHT
} TIFF_TAGS_BASELINE;
Then I have custom readers:
TIFF_TAGS *read_tiff_tags(char *filename)
{
TIFF_TAGS *tags = NULL;
TIFF *tif = TIFFOpen(filename, "r");
if (tif)
{
tags = calloc(1, sizeof(TIFF_TAGS));
read_tiff_tags_baseline(tif, tags);
read_tiff_tags_extension(tif, tags);
read_tiff_tags_private(tif, tags);
TIFFClose(tif);
}
return tags;
}
Where you have to manually read each field. Depending on if it's an array, you'll have to check the return status. For simple fields, it's something like
// The number of columns in the image, i.e., the number of pixels per row.
TIFFGetField(tif, TIFFTAG_IMAGEWIDTH, &tags->Baseline.ImageWidth);
but for array fields you'll need something like this
// The scanner model name or number.
status = TIFFGetField(tif, TIFFTAG_MODEL, &infobuf);
if (status)
{
len = strlen(infobuf);
tags->Baseline.Model = malloc(sizeof(char) * (len + 1));
_mysprintf(tags->Baseline.Model, (int)(len + 1), "%s", infobuf);
tags->Baseline.Model[len] = 0;
}
else
{
tags->Baseline.Model = NULL;
}
// For each strip, the byte offset of that strip.
status = TIFFGetField(tif, TIFFTAG_STRIPOFFSETS, &arraybuf);
if (status)
{
tags->Baseline.NumberOfStrips = TIFFNumberOfStrips(tif);
tags->Baseline.StripOffsets = calloc(tags->Baseline.NumberOfStrips, sizeof(TIFF_UINT32_T));
for (strip = 0; strip < tags->Baseline.NumberOfStrips; strip++)
{
tags->Baseline.StripOffsets[strip] = arraybuf[strip];
}
}
else
{
tags->Baseline.StripOffsets = NULL;
}
My suggestion is to only read the fields you want/need and ignore everything else. Hope that helps.

Can zlib remove padding without compressing the rest of the file?

I'm looking for a way to apply a specific compression strategy using zlib-1.2.5.
I need to force zlib to pack a file without actually compressing it. The only part I want to compress is 0 padding at the end of the file, so that the output file does not have it. The size of input files ranges from 1MB to 1GB, padding is 512B.
Is this achievable with zlib?
Edit:
The code I'm working on is based on Unreal Engine 4:
https://github.com/EpicGames/UnrealEngine/blob/release/Engine/Source/Runtime/Core/Private/Misc/Compression.cpp
static bool appCompressMemoryZLIB(void* CompressedBuffer, int32& CompressedSize, const void* UncompressedBuffer, int32 UncompressedSize, int32 BitWindow, int32 CompLevel)
{
DECLARE_SCOPE_CYCLE_COUNTER(TEXT("Compress Memory ZLIB"), STAT_appCompressMemoryZLIB, STATGROUP_Compression);
ensureMsgf(CompLevel >= Z_DEFAULT_COMPRESSION, TEXT("CompLevel must be >= Z_DEFAULT_COMPRESSION"));
ensureMsgf(CompLevel <= Z_BEST_COMPRESSION, TEXT("CompLevel must be <= Z_BEST_COMPRESSION"));
CompLevel = FMath::Clamp(CompLevel, Z_DEFAULT_COMPRESSION, Z_BEST_COMPRESSION);
// Zlib wants to use unsigned long.
unsigned long ZCompressedSize = CompressedSize;
unsigned long ZUncompressedSize = UncompressedSize;
bool bOperationSucceeded = false;
// Compress data
// If using the default Zlib bit window, use the zlib routines, otherwise go manual with deflate2
if (BitWindow == 0 || BitWindow == DEFAULT_ZLIB_BIT_WINDOW)
{
bOperationSucceeded = compress2((uint8*)CompressedBuffer, &ZCompressedSize, (const uint8*)UncompressedBuffer, ZUncompressedSize, CompLevel) == Z_OK ? true : false;
}
else
{
z_stream stream;
stream.next_in = (Bytef*)UncompressedBuffer;
stream.avail_in = (uInt)ZUncompressedSize;
stream.next_out = (Bytef*)CompressedBuffer;
stream.avail_out = (uInt)ZCompressedSize;
stream.zalloc = &zalloc;
stream.zfree = &zfree;
stream.opaque = Z_NULL;
if (ensure(Z_OK == deflateInit2(&stream, CompLevel, Z_DEFLATED, BitWindow, MAX_MEM_LEVEL, Z_DEFAULT_STRATEGY)))
{
if (ensure(Z_STREAM_END == deflate(&stream, Z_FINISH)))
{
ZCompressedSize = stream.total_out;
if (ensure(Z_OK == deflateEnd(&stream)))
{
bOperationSucceeded = true;
}
}
else
{
deflateEnd(&stream);
}
}
}
// Propagate compressed size from intermediate variable back into out variable.
CompressedSize = ZCompressedSize;
return bOperationSucceeded;
}
With params: input buffer size = 65kB, CompLevel=Z_DEFAULT_COMPRESSION, MAX_MEM_LEVEL=9, BitWindow=15
No, there is not.
If all you want to do is strip the zeros at the end, then that is trivial. It's a few lines of code. You don't need zlib's 18,000 lines of code to do that.
If you also want to restore those zeros to the file at the other end ("decompressing it"), that is trivial as well. Just send a count of the zeros that were removed, with that count in a few bytes appended to the end. On the other end, replace that count with that many zero bytes. Also a few lines of code.

How to compress/decompress buffer using Fast-LZMA2

I want to compress/decompress a unsigned char buffer using fast-LZMA2 by 7Zip : https://github.com/conor42/fast-lzma2
In the sample there's two function :
static int compress_file(FL2_CStream *fcs)
{
unsigned char in_buffer[8 * 1024];
unsigned char out_buffer[4 * 1024];
FL2_inBuffer in_buf = { in_buffer, sizeof(in_buffer), sizeof(in_buffer) };
FL2_outBuffer out_buf = { out_buffer, sizeof(out_buffer), 0 };
size_t res = 0;
size_t in_size = 0;
size_t out_size = 0;
do {
if (in_buf.pos == in_buf.size) {
in_buf.size = fread(in_buffer, 1, sizeof(in_buffer), fin);
in_size += in_buf.size;
in_buf.pos = 0;
}
res = FL2_compressStream(fcs, &out_buf, &in_buf);
if (FL2_isError(res))
goto error_out;
fwrite(out_buf.dst, 1, out_buf.pos, fout);
out_size += out_buf.pos;
out_buf.pos = 0;
} while (in_buf.size == sizeof(in_buffer));
do {
res = FL2_endStream(fcs, &out_buf);
if (FL2_isError(res))
goto error_out;
fwrite(out_buf.dst, 1, out_buf.pos, fout);
out_size += out_buf.pos;
out_buf.pos = 0;
} while (res);
fprintf(stdout, "\t%ld -> %ld\n", in_size, out_size);
return 0;
error_out:
fprintf(stderr, "Error: %s\n", FL2_getErrorName(res));
return 1;
}
static int decompress_file(FL2_DStream *fds)
{
unsigned char in_buffer[4 * 1024];
unsigned char out_buffer[8 * 1024];
FL2_inBuffer in_buf = { in_buffer, sizeof(in_buffer), sizeof(in_buffer) };
FL2_outBuffer out_buf = { out_buffer, sizeof(out_buffer), 0 };
size_t res;
size_t in_size = 0;
size_t out_size = 0;
do {
if (in_buf.pos == in_buf.size) {
in_buf.size = fread(in_buffer, 1, sizeof(in_buffer), fout);
in_size += in_buf.size;
in_buf.pos = 0;
}
res = FL2_decompressStream(fds, &out_buf, &in_buf);
if (FL2_isError(res))
goto error_out;
/* Discard the output. XXhash will verify the integrity. */
out_size += out_buf.pos;
out_buf.pos = 0;
} while (res && in_buf.size);
fprintf(stdout, "\t%ld -> %ld\n", in_size, out_size);
return 0;
error_out:
fprintf(stderr, "Error: %s\n", FL2_getErrorName(res));
return 1;
}
But I have no idea how to make it work with a buffer and also without size limit like 8*1024
like zlib deflate compression.
I want something like
LZMA2_Compress(void* buffer,size_t bufferSize);
and LZMA2_Decompress(void* buffer,size_t bufferSize);
I want to use this algorithm on some heavy files and Fast LZMA2 is the fastest high ratio compression I found, Please don't suggest me using other methods.
Here's my test code, It's working but just need to correct information:
https://gist.github.com/Bit00009/3241bb66301f8aaba16074537d094e61
Check the header file for all of the functions available. This one looks like the one you need. You will need to cast your buffers as (void *).
High level functions
fast-lzma2.h
...
/*! FL2_compress() :
* Compresses `src` content as a single LZMA2 compressed stream into already allocated `dst`.
* Call FL2_compressMt() to use > 1 thread. Specify nbThreads = 0 to use all cores.
* #return : compressed size written into `dst` (<= `dstCapacity),
* or an error code if it fails (which can be tested using FL2_isError()). */
FL2LIB_API size_t FL2LIB_CALL FL2_compress(void* dst, size_t dstCapacity,
const void* src, size_t srcSize,
int compressionLevel);
...
Management of memory and options
To do explicit memory management (set dictionary size, buffer size, etc.) you need to create a context:
fast-lzma2.h
/*= Compression context
* When compressing many times, it is recommended to allocate a context just once,
* and re-use it for each successive compression operation. This will make workload
* friendlier for system's memory. The context may not use the number of threads requested
* if the library is compiled for single-threaded compression or nbThreads > FL2_MAXTHREADS.
* Call FL2_getCCtxThreadCount to obtain the actual number allocated. */
typedef struct FL2_CCtx_s FL2_CCtx;
FL2LIB_API FL2_CCtx* FL2LIB_CALL FL2_createCCtx(void);
than you can use FL2_CCtx_setParameter() to set the parameters in the context. The possible values for the paramters are listed in FL2_cParameter , and the value FL2_p_dictionarySize will allow you to set the dictionary size.
/*! FL2_CCtx_setParameter() :
* Set one compression parameter, selected by enum FL2_cParameter.
* #result : informational value (typically, the one being set, possibly corrected),
* or an error code (which can be tested with FL2_isError()). */
FL2LIB_API size_t FL2LIB_CALL FL2_CCtx_setParameter(FL2_CCtx* cctx, FL2_cParameter param, size_t value);
Finally you can compress the buffer by calling FL2_compressCCtx()
/*! FL2_compressCCtx() :
* Same as FL2_compress(), but requires an allocated FL2_CCtx (see FL2_createCCtx()). */
FL2LIB_API size_t FL2LIB_CALL FL2_compressCCtx(FL2_CCtx* cctx,
void* dst, size_t dstCapacity,
const void* src, size_t srcSize,
int compressionLevel);

C++ zilib deflate/inflate and ztream parameters

After understood (with some help...) how work the compress and uncompress functions of zlib library, I'm now trying to understand how deflate and inflate work. As far as i understand, compress is used in a single call, whereas deflate can be called several time.
Having a simple program with a Particle struct (coordinate x, y, z), I can deflate my datas without errors (getting a Z_STREAM_END response) and then inflate them with another z_stream object (Z_STREAM_END response too). But when I tried to display back my datas from the inflate response, I can get the x and y coordinate of my struct by not the third one (z).
I think it's due to a wrong parameters i gave to my z_stream object for inflate, but I can't find which one. As far as i understand reading docs and example, that's how I think z_stream works (this is just an example) :
// Here i give a total memory size for the output buffer used by deflate func
#define CHUNK 16384
struct Particle
{
float x;
float y;
float z;
};
...
// An element to get a single particule and give it to deflate func
Bytef *dataOriginal = (Bytef*)malloc( sizeof(Particle) );
// This var will be used to pass compressed data
Bytef *dataCompressed = (Bytef*)malloc( CHUNK );
z_stream strm;
strm.zalloc = Z_NULL;
strm.zfree = Z_NULL;
strm.opaque = Z_NULL;
deflateInit(&strm, Z_DEFAULT_COMPRESSION);
strm.avail_out = CHUNK;
strm.next_out = dataCompressed;
int nbrLoop = 2;
int spaceUsed = 0;
int flush;
Particle p;
for (var i = 0; i<nbrLoop; i++){
// set all values equals to 0
memset( &p, 0, sizeof(Particle) );
// insert some random values
p.x = (i+1) * 1;
p.y = (i+1) * 3;
p.z = (i+1) * 7;
//copy this values in a Bytef* elements
memcpy( dataOriginal, &p, sizeof(Particle) );
strm.avail_in = sizeof(dataOriginal);
strm.next_in = dataOriginal;
// If it's the last particle :
if(i == nbrLoop - 1){
flush = Z_FINISH;
}
else{
flush = Z_NO_FLUSH;
}
int response = deflate(&strm, flush);
// I don't get any errors here
// EDIT : Get Z_OK at first loop, the Z_STREAM_END at second (last)
if( res == Z_STREAM_END ){
spaceUsed = CHUNK - strm.avail_out;
}
}
deflateEnd(&strm);
// Trying to get back my datas
Bytef *decomp = (Bytef*)malloc( sizeof(Particle) );
z_stream strmInflate;
strmInflate.zalloc = Z_NULL;
strmInflate.zfree = Z_NULL;
strmInflate.opaque = Z_NULL;
inflateInit(&strmInflate);
// datas i want to get at the next inflate
strmInflate.avail_in = sizeof(Particle);
strmInflate.next_in = dataCompressed;
// Two particles were compressed, so i need to get back two
strmInflate.avail_out = sizeof(Particle) * 2;
strmInflate.next_out = decomp;
int response = inflate( &strmInflate, Z_NO_FLUSH );
// No error here,
// EDIT : Get Z_OK
inflateEnd( &strmInflate );
Particle testP;
memset( &testP, 0, sizeof(Particle) );
memcpy( &testP, decomp, sizeof(Particle) );
std::cout << testP.x << std::endl; // display 1 OK
std::cout << testP.y << std::endl; // display 3 OK
std::cout << testP.z << std::endl; // display 0 NOT OK
Moreover, i thought that calling inflate a second time will allow me to recover datas of my second particle that was created in my for loop but i can't retrieve it.
Thanks in advance for any help !
strmInflate.avail_in = sizeof(Particle); needs to be strmInflate.avail_in = spaceUsed; You have to provide inflate all of the data produced by deflate.
At the end you want to get Z_STREAM_END from inflate(), not Z_OK. Otherwise you have not decompressed the entire generated stream.
Note that per the documentation in zlib.h, you need to also set next_in and avail_in (to Z_NULL and 0 if you like) before calling inflateInit()
Depending on the size of the input and output buffers you will be using in the final application, you may need more loops to assure that deflate() and inflate() can finish their jobs. Please see the example of how to use zlib.

Resource instead of external file C++

I am reusing some old code(originally developed on c, not c++) with some functions to open/read/manipulate text-files. The path to the text-files is passed to the functions as a string (char*) then opened using: FileToUse = fopen(filename, "rb"); then multiple calls to fread() and fseek() are used. This code is known to work for external text-files, but now I would like to include the textfiles as resources in my project (MFC C++ in visual studio).
I found some examples on the web on how to use resources rusulting in this code:
HINSTANCE hInst = AfxGetResourceHandle();
HRSRC hResource = FindResource(hInst, MAKEINTRESOURCE(IDR_TEXTFILE1), "TEXTFILE");
if (hResource){
HGLOBAL hLoadedResource = LoadResource(hInst, hResource);
if (hLoadedResource){
const char* pResource = LockResource(hLoadedResource);
if (pResource){
DWORD dwResourceSize = SizeofResource(hInst, hResource);
if (0 != dwResourceSize){ // if(FileToUse){
memcpy(&Buffer, pResource, (15 * 2)); // fread($Buffer, 15, 2, FileToUse);
pTemp = pResource + 200; // fseek(FileToUse, 200, SEEK_SET);
pTemp = pTemp + 100; // fseek(FileToUse, 100, SEEK_CUR);
pTemp = pResource + (dwResourceSize - 1) - 40; // fseek(FileToUse, -40, SEEK_END);
}
}
}
}
I replaced the fread call by memcpy() as shown, but I'm missing the return value of fread (actual read items) and in the original code the filepointer was moved by fseek, I wonder whether my approach using a temporary pointer is correct.
My ultimate goal is to simulate the fread and fseek calls for resources with similar function prototypes:
size_t resread( void* buffer, size_t size, size_t count, char* resource );
int resseek( char* resource, long offset, int origin );
Any suggestions are much appreciated.
Thanks for your help, based on the Agent_L's suggestion this is what I came up with:
Text-resource type:
struct _resource {
const char * content; // File content
size_t size; // File size
size_t ptrloc; // 'Pointer' location
};
typedef struct _resource RES_TXT;
resread based on fread:
size_t resread( void* buffer, size_t size, size_t count, RES_TXT * resource)
{
size_t actualCount = ( resource->size - resource->ptrloc ) / size;
actualCount = min( count, actualCount );
if ( actualCount <= 0 ) return 0;
memcpy(buffer, (resource->_ptr + resource->ptrloc), (actualCount * size) );
resource->ptrloc += (actualCount * size);
return actualCount;
}
and to complete resseek based on fseek:
int resseek( RES_TXT * resource, long offset, int origin ) {
size_t nextloc;
switch ( origin ) {
case SEEK_SET: nextloc = 0;
break;
case SEEK_CUR: nextloc = resource->ptrloc;
break;
case SEEK_END: nextloc = resource->size;
break;
default: return -1;
}
nextloc += offset;
if ( nextloc >= 0 && nextloc < resource->size )
resource->ptrloc = nextloc;
else
return -1;
return 0;
}
Any call to fseek and fread can now be replaced to use a resource instead of an external file.
The file handle contains not only the data but also it's length and current position. You have to duplicate that.
(handwirtten code, unproven):
struct resFile
{
char* pData;
int iLenght;
int iCurrPosition;
};
size_t resread( void* buffer, size_t size, size_t count, resFile* resource)
{
int ActualRead = min(size*count, resource->iLenght - resource->iCurrPosition);
memcpy(buffer, resource->pData + resource->iCurrPosition, ActualRead);
resource->iCurrPostion += ActualRead;
return ActualRead;
}
Let me notify you that fread shifts current file position. This means that you don't need invoke fseek each time. From this perspective may be you code can avoid implementation of resseek by simple increasing Buffer pointer