Core: Zlib gzip support

git-svn-id: svn://ultimatepp.org/upp/trunk@4733 f0d560ea-af0d-0410-9eb7-867de7ffcac7
This commit is contained in:
cxl 2012-03-31 22:23:13 +00:00
parent e333617ab1
commit a89c7d9cd6
7 changed files with 304 additions and 27 deletions

View file

@ -196,6 +196,22 @@ enum
typedef int SOCKET;
#endif
#ifdef PLATFORM_WIN32
#include <plugin/z/lib/zlib.h>
#include <plugin/z/lib/zutil.h>
#else
#include <zlib.h>
#ifndef DEF_MEM_LEVEL
#define DEF_MEM_LEVEL 8
#endif
#ifndef OS_CODE
#define OS_CODE 0x03
#endif
#endif
#include <algorithm>
#include <string>
#include <complex>

View file

@ -54,16 +54,11 @@ class TcpSocket {
public:
Callback WhenWait;
TcpSocket& Timeout(int ms) { timeout = ms; global = false; return *this; }
TcpSocket& GlobalTimeout(int ms);
TcpSocket& Blocking() { return Timeout(Null); }
static String GetHostName();
int GetDone() const { return done; }
TcpSocket();
~TcpSocket() { Close(); }
static void Init();
bool IsOpen() const { return socket != INVALID_SOCKET; }
@ -114,7 +109,12 @@ public:
bool PutAll(const char *s, int len) { return Put(s, len) == len; }
bool PutAll(const String& s) { return Put(s) == s.GetCount(); }
static String GetHostName();
TcpSocket& Timeout(int ms) { timeout = ms; global = false; return *this; }
TcpSocket& GlobalTimeout(int ms);
TcpSocket& Blocking() { return Timeout(Null); }
TcpSocket();
~TcpSocket() { Close(); }
};
struct HttpHeader {

View file

@ -1,20 +1,7 @@
#include "Core.h"
#ifdef PLATFORM_WIN32
#include <plugin/z/lib/zlib.h>
#include <plugin/z/lib/zutil.h>
#else
#include <zlib.h>
#ifndef DEF_MEM_LEVEL
#define DEF_MEM_LEVEL 8
#endif
#ifndef OS_CODE
#define OS_CODE 0x03
#endif
#endif
#define LDUMP(x) // DDUMP(x)
#define LLOG(x) // DLOG(x)
NAMESPACE_UPP
@ -43,6 +30,8 @@ enum
RESERVED = 0xE0, /* bits 5..7: reserved */
};
static byte sGZip_header[10] = { GZ_MAGIC1, GZ_MAGIC2, Z_DEFLATED, 0, 0, 0, 0, 0, 0, OS_CODE };
void Crc32Stream::Out(const void *ptr, dword count)
{
crc = crc32(crc, (byte *)ptr, count);
@ -65,6 +54,227 @@ dword CRC32(const String& s)
return CRC32(~s, s.GetLength());
}
void Zlib::Begin()
{
Free();
error = false;
if(docrc || gzip)
crc = crc32(0, NULL, 0);
out.Clear();
}
void Zlib::Compress()
{
Begin();
if(deflateInit2(&z, Z_DEFAULT_COMPRESSION, Z_DEFLATED,
hdr && !gzip ? MAX_WBITS : -MAX_WBITS, DEF_MEM_LEVEL,
Z_DEFAULT_STRATEGY) != Z_OK)
Panic("deflateInit2 failed");
mode = DEFLATE;
if(gzip)
WhenOut(sGZip_header, 10);
}
void Zlib::Decompress()
{
Begin();
if(inflateInit2(&z, hdr && !gzip ? +MAX_WBITS : -MAX_WBITS) != Z_OK)
Panic("inflateInit2 failed");
mode = INFLATE;
}
void Zlib::Pump(bool finish)
{
if(error)
return;
if(gzip_footer)
return;
ASSERT(mode);
LDUMP(mode);
if(!output)
output.Alloc(chunk);
for(;;) {
LLOG("---");
LDUMP(z.avail_in);
int code;
z.avail_out = chunk;
z.next_out = output;
code = (mode == DEFLATE ? deflate : inflate)(&z, finish ? Z_FINISH : Z_NO_FLUSH);
LDUMP(code);
LDUMP(z.avail_in);
LDUMP(z.avail_out);
int count = chunk - z.avail_out;
LDUMP(count);
LDUMP(count);
if(count) {
if((docrc || gzip) && mode == INFLATE)
crc = crc32(crc, output, count);
WhenOut((const char *)~output, count);
if(mode == INFLATE)
total += count;
}
if(mode == INFLATE && code == Z_STREAM_END) {
gzip_footer = true;
break;
}
if(mode == INFLATE ? code == Z_BUF_ERROR : count == 0)
break;
if(code != Z_OK && code != Z_STREAM_END) {
LLOG("ERROR " << code);
Free();
error = true;
break;
}
}
}
int Zlib::GzipHeader(const char *ptr, int size)
{
int pos = 10;
if(pos > size)
return 0;
int flags = ptr[3];
if(ptr[2] != Z_DEFLATED || (flags & RESERVED) != 0) {
error = true;
return 0;
}
if(flags & EXTRA_FIELD) {
if(pos + 2 > size)
return 0;
int len = MAKEWORD(ptr[pos], ptr[pos + 1]);
if(len < 0) {
error = true;
return 0;
}
if((pos += len + 2) > size)
return 0;
}
for(int i = !!(flags & ORIG_NAME) + !!(flags & COMMENT); i > 0; i--) {
while(ptr[pos])
if(++pos > size)
return 0;
if(++pos > size)
return 0;
}
if(flags & HEAD_CRC)
if((pos += 2) > size)
return 0;
return pos;
}
void Zlib::Put0(const char *ptr, int size)
{
if(error)
return;
ASSERT(mode);
if(size <= 0)
return;
if(gzip && !gzip_done && mode == INFLATE) {
if(gzip_hs.GetCount()) {
gzip_hs.Cat(ptr, size);
ptr = ~gzip_hs;
size = gzip_hs.GetCount();
}
int pos = GzipHeader(ptr, size);
if(!pos) {
if(gzip_hs.GetCount() == 0)
gzip_hs.Cat(ptr, size);
return;
}
gzip_done = true;
size -= pos;
ptr += pos;
}
if(size <= 0)
return;
if(mode == DEFLATE) {
total += size;
if(docrc || gzip)
crc = crc32(crc, (const Bytef *)ptr, size);
}
z.next_in = (Bytef *)ptr;
z.avail_in = size;
Pump(Z_NO_FLUSH);
}
void Zlib::Put(const void *ptr, dword size)
{
if(error)
return;
const char *p = reinterpret_cast<const char *>(ptr);
while(size) {
LLOG("Put " << size);
int psz = (int) min(size, dword(INT_MAX / 4));
Put0(p, size);
size -= psz;
p += psz;
}
}
void Zlib::PutOut(const void *ptr, dword size)
{
out.Cat((const char *)ptr, (int)size);
LDUMP(out.GetCount());
}
void Zlib::End()
{
LLOG("End");
if(mode != INFLATE || !gzip || gzip_done)
Pump(Z_FINISH);
if(gzip && mode == DEFLATE) {
char h[8];
Poke32le(h, crc);
Poke32le(h + 4, total);
WhenOut(h, 8);
}
Free();
}
void Zlib::Free()
{
if(mode == INFLATE)
inflateEnd(&z);
if(mode == DEFLATE)
deflateEnd(&z);
mode = NONE;
gzip_hs.Clear();
gzip_done = false;
gzip_footer = false;
total = 0;
}
Zlib& Zlib::ChunkSize(int n)
{
ASSERT(n < INT_MAX / 4);
output.Clear();
chunk = n;
return *this;
}
Zlib::Zlib()
{
z.zalloc = zalloc_new;
z.zfree = zfree_new;
z.opaque = 0;
docrc = false;
crc = 0;
hdr = true;
WhenOut = callback(this, &Zlib::PutOut);
mode = NONE;
gzip = false;
}
Zlib::~Zlib()
{
if(mode)
End();
}
static int sZpress(Stream& out, Stream& in, int size, Gate2<int, int> progress, bool nohdr, dword *crc,
bool compress)
{
@ -169,8 +379,7 @@ String ZDecompress(const String& s, Gate2<int, int> progress)
int GZCompress(Stream& out, Stream& in, int size, Gate2<int, int> progress)
{
static byte gzip_header[10] = { GZ_MAGIC1, GZ_MAGIC2, Z_DEFLATED, 0, 0, 0, 0, 0, 0, OS_CODE };
out.Put(gzip_header, 10);
out.Put(sGZip_header, 10);
dword crc;
int sz = ZCompress(out, in, size, progress, true, &crc);
out.Put32le(crc);

View file

@ -13,6 +13,55 @@ public:
dword CRC32(const void *ptr, dword count);
dword CRC32(const String& s);
class Zlib {
enum { NONE, DEFLATE, INFLATE };
z_stream z;
Buffer<Bytef> output;
int chunk;
int mode;
dword crc;
int total;
bool docrc;
bool hdr;
bool error;
bool gzip;
bool gzip_done;
bool gzip_footer;
String gzip_hs;
void PutOut(const void *ptr, dword size);
void Pump(bool finish);
void Begin();
void Free();
void Put0(const char *ptr, int size);
int GzipHeader(const char *ptr, int size);
public:
Callback2<const void *, dword> WhenOut;
String out;
dword GetCrc() const { return crc; }
bool IsError() const { return error; }
void Compress();
void Decompress();
void Put(const void *ptr, dword size);
void Put(const String& s) { Put(~s, s.GetCount()); }
void End();
Zlib& GZip(bool gzip_ = true) { gzip = gzip_; return *this; }
Zlib& Header(bool hdr_ = true) { hdr = hdr_; return *this; }
Zlib& NoHeader() { return Header(false); }
Zlib& Crc(bool b = true) { docrc = b; return *this; }
Zlib& NoCrc() { return Crc(false); }
Zlib& ChunkSize(int n);
Zlib();
~Zlib();
};
int ZCompress(Stream& out, Stream& in, int size, Gate2<int, int> progress = false, bool nohdr = false, dword *crc = NULL);
int ZDecompress(Stream& out, Stream& in, int size, Gate2<int, int> progress = false, bool nohdr = false, dword *crc = NULL);

View file

@ -1,7 +1,8 @@
#ifndef _Web_icpp_init_stub
#define _Web_icpp_init_stub
#include "Core/init"
#define BLITZ_INDEX__ F812213f29e8b190fead32d3e1aa22ad7
#include "Web/SSL/init"
#define BLITZ_INDEX__ F173e4988d70c85ab4a78f4702f196919
#include "Web_init.icpp"
#undef BLITZ_INDEX__
#endif

View file

@ -17,7 +17,8 @@ uses
plugin/astyle,
usvn,
TextDiffCtrl,
TabBar;
TabBar,
Web/SSL;
uses(POSIX) ide\SrcUpdater;

View file

@ -17,5 +17,6 @@
#include "usvn/init"
#include "TextDiffCtrl/init"
#include "TabBar/init"
#include "Web/SSL/init"
#include "ide\SrcUpdater/init"
#endif