Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

G++ deflate #364

Open
wants to merge 3 commits into
base: master
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
206 changes: 206 additions & 0 deletions contrib/g++_deflate/Deflate.cpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,206 @@
/*
* Copyright (C) 2018 Pierre G. Richard.
* Written: 06/22/2018
* This code is licensed under the terms of the MIT license.
*
* C++ implementation of the DEFLATE compression algorithm over the zlib
* compression library written by Jean-Loup Gailly and Mark Adler.
*/
#include "zlib.h"
#include "Deflate.h"

/*----------------------------------------------Deflate::StreamBuf::StreamBuf-+
| Constructor |
+----------------------------------------------------------------------------*/
Deflate::StreamBuf::StreamBuf(int windowBits, int chunkSize) :
m_buffer(0), m_rc(Z_OK),
m_windowBits(windowBits), m_chunkSize(chunkSize), m_isInited(false)
{
m_stream.zalloc = 0;
m_stream.zfree = 0;
m_stream.opaque = 0;
}

/*---------------------------------------------Deflate::StreamBuf::~StreamBuf-+
| Destructor |
+----------------------------------------------------------------------------*/
Deflate::StreamBuf::~StreamBuf() {}


/*-----------------------------------------------------Deflate::StreamBuf::rc-+
| Get the actual return code |
+----------------------------------------------------------------------------*/
int Deflate::StreamBuf::rc() const { return m_rc; }

/*------------------------------------------------Deflate::StreamBuf::cleanUp-+
| Cleanup (when the derived StreamBuf's are destroyed) |
+----------------------------------------------------------------------------*/
void Deflate::StreamBuf::cleanUp() {
if (m_buffer) delete[] m_buffer, m_buffer = 0;
if (m_isInited) xxflateEnd(&m_stream), m_isInited = false;
}

/*-----------------------------------------------Deflate::StreamBuf::overflow-+
| The underlying ostream is full |
+----------------------------------------------------------------------------*/
int Deflate::StreamBuf::overflow(int c) {
if (pcount() < m_chunkSize) { // then, extend the buffer
return MemStreamBuf::overflow(c);
}else { // then, empty the buffer
breathe(Z_NO_FLUSH); // compress, or decompress its contents
if (m_rc == Z_OK) {
return sputc(c); // shouldn't trigger an overflow
}else {
return -1;
}
}
}

/*------------------------------------------------Deflate::StreamBuf::breathe-+
| This is where most processing is done: breathe (deflate or inflate) |
+----------------------------------------------------------------------------*/
void Deflate::StreamBuf::breathe(int flush) {
m_stream.next_in = (unsigned char *)str();
m_stream.avail_in = pcount();
if (!m_isInited) { // lazy initialization at first breath
m_buffer = new unsigned char[m_chunkSize];
m_rc = init(
&m_stream,
Z_DEFAULT_COMPRESSION, // 0..9 Default to 6
Z_DEFLATED, // must be Z_DEFLATED
-m_windowBits, //<-minus! // raw window size -15..-8 Default to -15
8, // memory level 1..9 Default to 8
Z_DEFAULT_STRATEGY
);
m_isInited = (m_rc == Z_OK);
}
if (m_buffer && (m_rc == Z_OK)) do {
m_stream.next_out = m_buffer;
m_stream.avail_out = m_chunkSize;
}while (
(
m_rc = xxflate(&m_stream, flush),
m_rc == Z_OK
) && (
m_rc = (
m_out.write((char const *)m_buffer, m_chunkSize-m_stream.avail_out)?
Z_OK : Z_ERRNO
),
m_rc == Z_OK
) && (
m_stream.avail_out == 0
)
);
freeze(0); // thaw our str'ed buffer
pubseekpos(0); // Reset the stream pointers
}

/*---------------------------------------------------Deflate::StreamBuf::sync-+
| Take the ownership of the compress buffer: |
| - m_out.str freezes the buffer so that the m_out destructor does nada |
| - init with `Given' let "this" destructor destroy the buffer |
| Why shrinkBy? Despite what Mark says, deflate produces the trailer. |
+----------------------------------------------------------------------------*/
int Deflate::StreamBuf::sync() { // no more data (flush)
if (breathe(Z_SYNC_FLUSH), m_rc == Z_OK) { // Z_FINISH is unfit for Deflate
reset(); // free the decompress buffer
MemStreamBuf::init(
m_out.str(), m_out.pcount()-shrinkBy(), MemStreamBuf::Given
);
xxflateEnd(&m_stream);
delete[] m_buffer;
m_buffer = 0;
return 0;
}else {
return -1;
}
}

/*------------------------------Deflate::CompressStreamBuf::CompressStreamBuf-+
| |
+----------------------------------------------------------------------------*/
Deflate::CompressStreamBuf::CompressStreamBuf(int windowBits, int chunkSize)
: StreamBuf(windowBits, chunkSize) {}

/*-----------------------------Deflate::CompressStreamBuf::~CompressStreamBuf-+
| |
+----------------------------------------------------------------------------*/
Deflate::CompressStreamBuf::~CompressStreamBuf() {
cleanUp();
}

/*-------------------------------------------Deflate::CompressStreamBuf::init-+
| |
+----------------------------------------------------------------------------*/
int Deflate::CompressStreamBuf::init(
z_stream * stream, int level, int method,
int windowBits, int memLevel, int strategy
) {
return ::deflateInit2(stream, level, method, windowBits, memLevel, strategy);
}

/*----------------------------------------Deflate::CompressStreamBuf::xxflate-+
| |
+----------------------------------------------------------------------------*/
int Deflate::CompressStreamBuf::xxflate(z_stream * stream, int flush) {
return ::deflate(stream, flush);
}

/*---------------------------------------Deflate::CompressStreamBuf::shrinkBy-+
| |
+----------------------------------------------------------------------------*/
int Deflate::CompressStreamBuf::shrinkBy() {
return 4; // trailer size (0x0000FFFF)
}

/*-------------------------------------Deflate::CompressStreamBuf::xxflateEnd-+
| |
+----------------------------------------------------------------------------*/
int Deflate::CompressStreamBuf::xxflateEnd(z_stream * stream) {
return ::deflateEnd(stream);
}

/*--------------------------Deflate::DecompressStreamBuf::DecompressStreamBuf-+
| |
+----------------------------------------------------------------------------*/
Deflate::DecompressStreamBuf::DecompressStreamBuf(int windowBits, int chunkSize)
: StreamBuf(windowBits, chunkSize) {}

/*-------------------------Deflate::DecompressStreamBuf::~DecompressStreamBuf-+
| |
+----------------------------------------------------------------------------*/
Deflate::DecompressStreamBuf::~DecompressStreamBuf() {
cleanUp();
}

/*-----------------------------------------Deflate::DecompressStreamBuf::init-+
| |
+----------------------------------------------------------------------------*/
int Deflate::DecompressStreamBuf::init(
z_stream * stream, int, int, int windowBits, int, int
) {
return ::inflateInit2(stream, windowBits);
}

/*--------------------------------------Deflate::DecompressStreamBuf::xxflate-+
| |
+----------------------------------------------------------------------------*/
int Deflate::DecompressStreamBuf::xxflate(z_stream * stream, int flush) {
return ::inflate(stream, flush);
}

/*-------------------------------------Deflate::DecompressStreamBuf::shrinkBy-+
| |
+----------------------------------------------------------------------------*/
int Deflate::DecompressStreamBuf::shrinkBy() {
return 0;
}

/*-----------------------------------Deflate::DecompressStreamBuf::xxflateEnd-+
| |
+----------------------------------------------------------------------------*/
int Deflate::DecompressStreamBuf::xxflateEnd(z_stream * stream) {
return ::inflateEnd(stream);
}

/*===========================================================================*/
119 changes: 119 additions & 0 deletions contrib/g++_deflate/Deflate.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,119 @@
/*
* Copyright (C) 2018 Pierre G. Richard.
* Written: 06/22/2018
* This code is licensed under the terms of the MIT license.
*
* Deflate is a C++ implementation of the DEFLATE compression algorithm
* as specified in RFC 1951. It has both a Compressor and a Decompressor,
* which are standard iostream's.
*
* Deflate is simply a wrapper over the zlib interface compression library
* written by Jean-Loup Gailly and Mark Adler.
*
* Primarily intended for compressing or decompressing HTML5 websockets data,
* as described in RFC 7692, "Deflate" does "raw" deflate.
*
* Deflate depends on "MemStream", an early implementation of what is today
* known as "std::strstream" or "std::stringstream". The MemStream source
* is part of this distribution.
*
* This C++ code has been tested on Linux and g++. It should be easy to port it
* to other environments.
*
* Here is simple example of use:
*
* #include "Deflate.h"
*
* int main() {
* Deflate::Compressor compressor;
* Deflate::Decompressor decompressor;
*
* compressor << "Hello, Hello?" << std::flush;
* decompressor << compressor.rdbuf() << std::flush;
*
* std::cout << '|' << decompressor.rdbuf() << '|' << std::endl;
* return 0;
* }
*
* To compile and run:
* g++ -Wno-write-strings -Wall -std=c++0x -O0 -g -D _DEBUG \
* ZTest.cpp Deflate.cpp MemStream.cpp -o ZTest -lz && ZTest
*/

#ifndef _DEFLATE_H_INCLUDED
#define _DEFLATE_H_INCLUDED
#include <iostream>
#include "zlib.h" // for z_stream
#include "MemStream.h"

class Deflate {
public:
class StreamBuf : public MemStreamBuf {
public:
StreamBuf(int windowBits, int chunkSize);
virtual ~StreamBuf();
int rc() const;
protected:
void cleanUp();
private:
unsigned char * m_buffer;
z_stream m_stream;
MemStream m_out;
int m_rc;
int const m_windowBits;
int const m_chunkSize;
bool m_isInited;

void breathe(int);
virtual int overflow(int c);
virtual int sync();
virtual int init(z_stream *, int, int, int, int, int) = 0;
virtual int xxflate(z_stream *, int) = 0;
virtual int xxflateEnd(z_stream *) = 0;
virtual int shrinkBy() = 0;
};

class CompressStreamBuf : public StreamBuf {
public:
CompressStreamBuf(int, int);
virtual ~CompressStreamBuf();
private:
virtual int init(z_stream *, int, int, int, int, int);
virtual int xxflate(z_stream *, int);
virtual int shrinkBy();
virtual int xxflateEnd(z_stream *);
};

class DecompressStreamBuf : public StreamBuf {
public:
DecompressStreamBuf(int, int);
virtual ~DecompressStreamBuf();
private:
virtual int init(z_stream *, int, int, int, int, int);
virtual int xxflate(z_stream *, int);
virtual int shrinkBy();
virtual int xxflateEnd(z_stream *);
};

class Compressor : public std::iostream {
public:
Compressor(int windowBits = 15, int chunkSize = 0x4000)
: iostream(&m_buf), m_buf(windowBits, chunkSize) {}
int pcount() { return m_buf.pcount(); }
int rc() const { return m_buf.rc(); }
private:
CompressStreamBuf m_buf;
};

class Decompressor : public std::iostream {
public:
Decompressor(int windowBits = 15, int chunkSize = 0x4000)
: iostream(&m_buf), m_buf(windowBits, chunkSize) {}
int pcount() { return m_buf.pcount(); }
int rc() const { return m_buf.rc(); }
private:
DecompressStreamBuf m_buf;
};
};
#endif
/*===========================================================================*/
21 changes: 21 additions & 0 deletions contrib/g++_deflate/LICENSE
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
MIT License

Copyright (c) 2018 Jaxo, Inc.

Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:

The above copyright notice and this permission notice shall be included in all
copies or substantial portions of the Software.

THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
SOFTWARE.
Loading