plugin/zip: Zip: Streaming mode for individual files

git-svn-id: svn://ultimatepp.org/upp/trunk@7421 f0d560ea-af0d-0410-9eb7-867de7ffcac7
This commit is contained in:
cxl 2014-06-06 08:01:22 +00:00
parent 5c9e92b773
commit ef2bd2b6e4
6 changed files with 135 additions and 214 deletions

View file

@ -15,7 +15,9 @@ topic "OutFilterStream";
[s1;:OutFilterStream`:`:class: [@(0.0.255)3 class][3 _][*3 OutFilterStream][3 _:_][@(0.0.255)3 p
ublic][3 _][*@3;3 Stream]&]
[s2;%% Adapter Stream that glues an output stream with some filtering
object, typically of compression/decompression class.&]
object, typically of compression/decompression class. Output
stream can also be omitted, in that case OutFilterStream is useful
to convert anything capable of consuming data into Stream.&]
[s3; &]
[ {{10000F(128)G(128)@1 [s0;%% [* Public Member List]]}}&]
[s3; &]
@ -26,21 +28,23 @@ call does nothing.&]
[s3; &]
[s4; &]
[s5;:OutFilterStream`:`:out: [_^Stream^ Stream]_`*[* out]&]
[s2;%% Pointer to the output stream.&]
[s2;%% Pointer to the output stream. Can be NULL.&]
[s3; &]
[s4; &]
[s5;:OutFilterStream`:`:Filter: [_^Callback2^ Callback2]<[@(0.0.255) const]_[@(0.0.255) voi
d]_`*, [@(0.0.255) int]>_[* Filter]&]
[s2;%% Callback to filter input function.&]
[s2;%% Callback to filter input function. This is called when OutFilterStream
needs to output a chunk of buffered data.&]
[s3; &]
[s4; &]
[s5;:OutFilterStream`:`:End: [_^Callback^ Callback]_[* End]&]
[s2;%% Callback to filter finalization.&]
[s2;%% Callback to filter finalization. Called on closing the stream.&]
[s3; &]
[s4; &]
[s5;:OutFilterStream`:`:Out`(const void`*`,int`): [@(0.0.255) void]_[* Out]([@(0.0.255) con
st]_[@(0.0.255) void]_`*[*@3 ptr], [@(0.0.255) int]_[*@3 size])&]
[s2;%% Method serving as filter output.&]
[s2;%% Method serving as filter output. Basically performs out`->Put(ptr,
size), also keeps track of output bytes written (see GetCount).&]
[s3;%% &]
[s4; &]
[s5;:OutFilterStream`:`:GetCount`(`)const: [@(0.0.255) int64]_[* GetCount]()_[@(0.0.255) co

View file

@ -1,7 +1,5 @@
#include "zip.h"
#ifndef OLD_UNZIP
NAMESPACE_UPP
void UnZip::ReadDir()
@ -68,7 +66,7 @@ void UnZip::ReadDir()
error = false;
}
Time UnZip::GetTime(dword dt)
Time UnZip::GetZipTime(dword dt)
{
Time time;
time.year = int16(((dt >> 25) & 0x7f) + 1980);
@ -163,5 +161,3 @@ UnZip::UnZip()
UnZip::~UnZip() {}
END_UPP_NAMESPACE
#endif

View file

@ -1,127 +0,0 @@
#include "zip.h"
#ifdef OLD_UNZIP
NAMESPACE_UPP
void UnZip::ReadHeader()
{
if(zip->Get32le() != 0x04034b50) {
eof = true;
return;
}
if(zip->Get16le() > 20) {
SetError();
return;
}
bit = zip->Get16le();
method = zip->Get16le();
dword dt = zip->Get32le();
time.year = int16(((dt >> 25) & 0x7f) + 1980);
time.month = byte((dt >> 21) & 0x0f);
time.day = byte((dt >> 16) & 0x1f);
time.hour = byte((dt >> 11) & 0x1f);
time.minute = byte((dt >> 5) & 0x3f);
time.second = byte((dt << 1) & 0x3e);
crc32 = zip->Get32le();
csize = zip->Get32le();
usize = zip->Get32le();
dword filelen = zip->Get16le();
dword extralen = zip->Get16le();
path = zip->Get(filelen);
zip->SeekCur(extralen);
done += 5 * 2 + 5 * 4;
}
void UnZip::SkipFile()
{
zip->SeekCur(csize);
done += csize;
ReadHeader();
}
int64 zPress(Stream& out, Stream& in, int64 size, Gate2<int64, int64> progress, bool gzip,
bool compress, dword *crc, bool hdr);
bool UnZip::ReadFile(Stream& out, Gate2<int, int> progress)
{
dword crc;
int l;
if(method == 0) {
Buffer<byte> temp(65536);
int loaded;
int count = csize;
Crc32Stream crc32;
while(count > 0 && (loaded = zip->Get(temp, (int)min<int64>(count, 65536))) > 0) {
out.Put(temp, loaded);
crc32.Put(temp, loaded);
count -= loaded;
}
if(count > 0) {
SetError();
return false;
}
l = csize;
crc = crc32;
}
else
if(method == 8)
l = (int)zPress(out, *zip, csize, AsGate64(progress), false, false, &crc, false);
else {
SetError();
return false;
}
if(crc != crc32 || l != usize) {
SetError();
return false;
}
done += csize;
ReadHeader();
return true;
}
String UnZip::ReadFile(Gate2<int, int> progress)
{
StringStream ss;
return ReadFile(ss, progress) ? ss.GetResult() : String::GetVoid();
}
void UnZip::Create(Stream& _zip)
{
eof = error = false;
zip = &_zip;
done = 0;
ReadHeader();
}
bool UnZip::IsEof() const
{
return eof || !zip || error || zip->IsEof();
}
bool UnZip::IsFolder() const
{
return *path.Last() == '/';
}
UnZip::UnZip(Stream& in)
{
Create(in);
}
UnZip::UnZip()
{
error = true;
zip = NULL;
}
UnZip::~UnZip() {}
END_UPP_NAMESPACE
#endif

View file

@ -13,37 +13,112 @@ void Zip::WriteFolder(const char *path, Time tm)
int64 zPress(Stream& out, Stream& in, int64 size, Gate2<int64, int64> progress, bool gzip,
bool compress, dword *crc, bool hdr);
void Zip::WriteFile(const void *ptr, int size, const char *path, Gate2<int, int> progress, Time tm)
void Zip::FileHeader(const char *path, Time tm)
{
File& f = file.Add();
File& f = file.Top();
f.path = UnixPath(path);
StringStream ss;
MemReadStream ms(ptr, size);
dword crc;
zPress(ss, ms, size, AsGate64(progress), false, true, &crc, false);
String data = ss.GetResult();
const void *r = ~data;
int csize = data.GetLength();
zip->Put32le(0x04034b50);
zip->Put16le(20);
zip->Put16le(0);
if(data.GetLength() >= size) {
r = ptr;
csize = size;
zip->Put16le(f.method = 0);
}
else
zip->Put16le(f.method = 8);
zip->Put16le(f.version);
zip->Put16le(f.gpflag);
zip->Put16le(f.method);
zip->Put32le(f.time = (tm.day << 16) | (tm.month << 21) | ((tm.year - 1980) << 25) |
(tm.hour << 11) | (tm.minute << 5) | (tm.second >> 1));
zip->Put32le(f.crc = crc);
zip->Put32le(f.csize = csize);
zip->Put32le(f.usize = size);
ASSERT((f.gpflag & 0x8) == 0 || f.crc == 0);
zip->Put32le(f.crc);
ASSERT((f.gpflag & 0x8) == 0 || f.csize == 0);
zip->Put32le(f.csize);
ASSERT((f.gpflag & 0x8) == 0 || f.usize == 0);
zip->Put32le(f.usize);
zip->Put16le(strlen(f.path));
zip->Put16le(0);
zip->Put(f.path);
zip->Put(r, csize);
done += 5 * 2 + 5 * 4 + csize + f.path.GetCount();
done += 5*2 + 5*4 + f.path.GetCount();
}
void Zip::BeginFile(const char *path, Time tm)
{
ASSERT(!IsFileOpened());
pipeZLib.Create();
pipeZLib->WhenOut = THISBACK(PutCompressed);
pipeZLib->GZip(false).CRC().NoHeader().Compress();
File& f = file.Add();
f.version = 21;
f.gpflag = 0x8;
f.method = 8;
f.crc = 0;
f.csize = 0;
f.usize = 0;
FileHeader(path, tm);
if (zip->IsError()) WhenError();
}
void Zip::BeginFile(OutFilterStream& oz, const char *path, Time tm)
{
BeginFile(path, tm);
oz.Filter = THISBACK(Put);
oz.End = THISBACK(EndFile);
}
void Zip::Put(const void *ptr, int size)
{
ASSERT(IsFileOpened());
File& f = file.Top();
pipeZLib->Put(ptr, size);
f.usize += size;
}
void Zip::EndFile()
{
if(!IsFileOpened())
return;
File& f = file.Top();
ASSERT(f.gpflag & 0x8);
pipeZLib->End();
zip->Put32le(f.crc = pipeZLib->GetCRC());
zip->Put32le(f.csize);
zip->Put32le(f.usize);
done += 3*4;
pipeZLib.Clear();
if (zip->IsError()) WhenError();
}
void Zip::PutCompressed(const void *ptr, int size)
{
ASSERT(IsFileOpened());
zip->Put(ptr, size);
if (zip->IsError()) WhenError();
done += size;
file.Top().csize += size;
}
void Zip::WriteFile(const void *ptr, int size, const char *path, Gate2<int, int> progress, Time tm)
{
ASSERT(!IsFileOpened());
File& f = file.Add();
StringStream ss;
MemReadStream ms(ptr, size);
f.usize = size;
zPress(ss, ms, size, AsGate64(progress), false, true, &f.crc, false);
String data = ss.GetResult();
const void *r = ~data;
f.csize = data.GetLength();
f.version = 20;
f.gpflag = 0;
if(data.GetLength() >= size) {
r = ptr;
f.csize = size;
f.method = 0;
}
else
f.method = 8;
FileHeader(path, tm);
zip->Put(r, f.csize);
done += f.csize;
if (zip->IsError()) WhenError();
}
void Zip::WriteFile(const String& s, const char *path, Gate2<int, int> progress, Time tm)
@ -68,8 +143,8 @@ void Zip::Finish()
File& f = file[i];
zip->Put32le(0x02014b50);
zip->Put16le(20);
zip->Put16le(20);
zip->Put16le(0); // general purpose bit flag
zip->Put16le(f.version);
zip->Put16le(f.gpflag); // general purpose bit flag
zip->Put16le(f.method);
zip->Put32le(f.time);
zip->Put32le(f.crc);
@ -82,7 +157,7 @@ void Zip::Finish()
zip->Put16le(0); // internal file attributes 2 bytes
zip->Put32le(0); // external file attributes 4 bytes
zip->Put32le(rof); // relative offset of local header 4 bytes
rof+=5 * 2 + 5 * 4 + f.csize + f.path.GetCount();
rof+=5 * 2 + 5 * 4 + f.csize + f.path.GetCount() + (f.gpflag & 0x8 ? 3*4 : 0);
zip->Put(f.path);
done += 7 * 4 + 9 * 2 + f.path.GetCount();
}
@ -94,6 +169,7 @@ void Zip::Finish()
zip->Put32le(done - off); // size of the central directory
zip->Put32le(off); //offset of start of central directory with respect to the starting disk number
zip->Put16le(0);
if (zip->IsError()) WhenError();
zip = NULL;
}

View file

@ -5,8 +5,6 @@
NAMESPACE_UPP
#ifndef OLD_UNZIP
class UnZip {
struct File : Moveable<File> {
word bit;
@ -26,7 +24,7 @@ class UnZip {
void ReadDir();
static Time GetTime(dword time);
static Time GetZipTime(dword time);
public:
bool IsEof() const { return current >= file.GetCount(); }
@ -39,6 +37,7 @@ public:
String GetPath(int i) const { return file[i].path; }
bool IsFolder(int i) const { return *file[i].path.Last() == '/'; }
int GetLength(int i) const { return file[i].usize; }
Time GetTime(int i) const { return GetZipTime(file[i].time); }
void Seek(int i) { ASSERT(i >= 0 && i < file.GetCount()); current = i; }
@ -61,52 +60,6 @@ public:
virtual ~UnZip();
};
#else
class UnZip {
Stream *zip;
bool error;
bool eof;
String path;
word bit;
word method;
Time time;
dword crc32;
dword csize;
dword usize;
dword done;
void Init();
void ReadHeader();
void SetError() { error = true; }
public:
bool IsEof() const;
operator bool() const { return !IsEof(); }
bool IsError() const { return error; }
bool IsFolder() const;
String GetPath() const { return path; }
int GetLength() const { return usize; }
Time GetTime() const { return time; }
void SkipFile();
bool ReadFile(Stream& out, Gate2<int, int> progress = false);
String ReadFile(Gate2<int, int> progress = false);
dword GetPos() { return done; }
void Create(Stream& in);
UnZip(Stream& in);
UnZip();
virtual ~UnZip();
};
#endif
class FileUnZip : public UnZip {
FileIn zip;
@ -135,11 +88,15 @@ public:
};
class Zip {
typedef Zip CLASSNAME;
Stream *zip;
struct File {
String path;
dword time;
int version;
int gpflag;
int method;
dword crc;
dword csize;
@ -149,9 +106,25 @@ class Zip {
dword done;
One<Zlib> pipeZLib;
void WriteFile0(const void *ptr, int size, const char *path, Gate2<int, int> progress, Time tm, int method);
void FileHeader(const char *path, Time tm);
void PutCompressed(const void *data, int size);
typedef Zip CLASSNAME;
public:
Callback WhenError;
void BeginFile(const char *path, Time tm = GetSysTime());
void BeginFile(OutFilterStream& oz, const char *path, Time tm = GetSysTime());
void Put(const void *data, int size);
void EndFile();
bool IsFileOpened() const { return pipeZLib; }
void WriteFolder(const char *path, Time tm);
void WriteFile(const void *ptr, int size, const char *path, Gate2<int, int> progress = false, Time tm = GetSysTime());
void WriteFile(const String& s, const char *path, Gate2<int, int> progress = false, Time tm = GetSysTime());

View file

@ -4,6 +4,5 @@ file
zip.h,
Zip.cpp,
UnZip.cpp,
UnZipUtil.cpp,
UnZipOld.cpp;
UnZipUtil.cpp;