flatten 20260225
This commit is contained in:
425
tjp/core/zip/Compress+zlib.cpp
Executable file
425
tjp/core/zip/Compress+zlib.cpp
Executable file
@@ -0,0 +1,425 @@
|
||||
// TJP COPYRIGHT HEADER
|
||||
|
||||
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
#include <time.h>
|
||||
#include <errno.h>
|
||||
#include <fcntl.h>
|
||||
#include <assert.h>
|
||||
|
||||
#ifndef WIN32
|
||||
# include <unistd.h>
|
||||
# include <utime.h>
|
||||
# include <sys/types.h>
|
||||
# include <sys/stat.h>
|
||||
#else
|
||||
# include <direct.h>
|
||||
# include <io.h>
|
||||
#endif
|
||||
|
||||
#include <zlib/zlib.h>
|
||||
#include "minizip/zip.h"
|
||||
|
||||
#ifdef WIN32
|
||||
#include "minizip/iowin32.h"
|
||||
#endif
|
||||
|
||||
#include <fstream>
|
||||
#include <list>
|
||||
#include <string>
|
||||
#include "Compress.h"
|
||||
#include "../file/File.h"
|
||||
#include "../file/Path.h"
|
||||
|
||||
#include "../endian/Endian.h"
|
||||
#include "MemoryBuffer.hpp"
|
||||
|
||||
#include <tjp/core/log/Log.h>
|
||||
#include <tjp/core/log/LogOf.h>
|
||||
|
||||
#define WRITEBUFFERSIZE (16384)
|
||||
#define MAXFILENAME (256)
|
||||
|
||||
using namespace tjp;
|
||||
using namespace core::zip;
|
||||
using namespace core;
|
||||
|
||||
|
||||
#ifdef WIN32
|
||||
uLong filetime(const std::string &f, tm_zip *tmzip, uLong *dt)
|
||||
{
|
||||
int ret = -1;
|
||||
{
|
||||
FILETIME ftLocal;
|
||||
HANDLE hFind;
|
||||
WIN32_FIND_DATA ff32;
|
||||
|
||||
hFind = FindFirstFile(f.c_str(),&ff32);
|
||||
if (hFind != INVALID_HANDLE_VALUE)
|
||||
{
|
||||
FileTimeToLocalFileTime(&(ff32.ftLastWriteTime),&ftLocal);
|
||||
FileTimeToDosDateTime(&ftLocal,((LPWORD)dt)+1,((LPWORD)dt)+0);
|
||||
FindClose(hFind);
|
||||
ret = 0;
|
||||
}
|
||||
}
|
||||
return ret;
|
||||
}
|
||||
#else
|
||||
uLong filetime(const char *f, tm_zip *tmzip, uLong *dt)
|
||||
{
|
||||
struct stat s; /* results of stat() */
|
||||
struct tm* filedate;
|
||||
time_t tm_t=0;
|
||||
|
||||
if (strcmp(f,"-")!=0)
|
||||
{
|
||||
char name[MAXFILENAME+1];
|
||||
auto len = strlen(f);
|
||||
if (len > MAXFILENAME)
|
||||
len = MAXFILENAME;
|
||||
|
||||
strncpy(name, f,MAXFILENAME-1);
|
||||
/* strncpy doesnt append the trailing NULL, of the string is too long. */
|
||||
name[ MAXFILENAME ] = '\0';
|
||||
|
||||
if (name[len - 1] == '/')
|
||||
name[len - 1] = '\0';
|
||||
/* not all systems allow stat'ing a file with / appended */
|
||||
if (stat(name,&s)==0)
|
||||
{
|
||||
tm_t = s.st_mtime;
|
||||
}
|
||||
else
|
||||
return 1;
|
||||
}
|
||||
filedate = localtime(&tm_t);
|
||||
|
||||
tmzip->tm_sec = filedate->tm_sec;
|
||||
tmzip->tm_min = filedate->tm_min;
|
||||
tmzip->tm_hour = filedate->tm_hour;
|
||||
tmzip->tm_mday = filedate->tm_mday;
|
||||
tmzip->tm_mon = filedate->tm_mon ;
|
||||
tmzip->tm_year = filedate->tm_year;
|
||||
|
||||
return 0;
|
||||
}
|
||||
#endif
|
||||
|
||||
|
||||
/* calculate the CRC32 of a file,
|
||||
because to encrypt a file, we need known the CRC32 of the file before */
|
||||
int getFileCrc(const std::string &filenameinzip,unsigned long &result_crc)
|
||||
{
|
||||
const int size_buf = 16384;
|
||||
char *buf = new char[size_buf];
|
||||
|
||||
uLong calculate_crc=0;
|
||||
int err=ZIP_OK;
|
||||
FILE * fin = fopen(filenameinzip.c_str(),"rb");
|
||||
uInt size_read = 0;
|
||||
unsigned long total_read = 0;
|
||||
if (fin==NULL)
|
||||
{
|
||||
err = ZIP_ERRNO;
|
||||
}
|
||||
|
||||
if (err == ZIP_OK)
|
||||
do
|
||||
{
|
||||
err = ZIP_OK;
|
||||
size_read = (int)fread(buf,1,size_buf,fin);
|
||||
if (size_read < size_buf)
|
||||
if (feof(fin)==0)
|
||||
{
|
||||
err = ZIP_ERRNO;
|
||||
}
|
||||
|
||||
if (size_read>0)
|
||||
calculate_crc = crc32(calculate_crc,(const Bytef *)buf,size_read);
|
||||
total_read += size_read;
|
||||
|
||||
} while ((err == ZIP_OK) && (size_read>0));
|
||||
|
||||
if (fin)
|
||||
fclose(fin);
|
||||
|
||||
result_crc=calculate_crc;
|
||||
return err;
|
||||
}
|
||||
|
||||
void compressFile(
|
||||
zipFile zf,
|
||||
const std::string &path,
|
||||
const std::string &filename,
|
||||
const char *password,
|
||||
int opt_compress_level=Z_DEFAULT_COMPRESSION
|
||||
)
|
||||
{
|
||||
std::string filenameinzip = path;
|
||||
zip_fileinfo zi;
|
||||
unsigned long crcFile=0;
|
||||
|
||||
zi.tmz_date.tm_sec = zi.tmz_date.tm_min = zi.tmz_date.tm_hour =
|
||||
zi.tmz_date.tm_mday = zi.tmz_date.tm_mon = zi.tmz_date.tm_year = 0;
|
||||
zi.dosDate = 0;
|
||||
zi.internal_fa = 0;
|
||||
zi.external_fa = 0;
|
||||
if (filetime(filenameinzip.c_str(),&zi.tmz_date,&zi.dosDate) != ZIP_OK)
|
||||
throw zip::Exception ("filetime failed " + filenameinzip);
|
||||
|
||||
if (password != NULL)
|
||||
{
|
||||
if (getFileCrc(filenameinzip,crcFile) != ZIP_OK)
|
||||
throw zip::Exception ("getFileCrc");
|
||||
}
|
||||
|
||||
std::string unixFileName = file::convertDelimiter(filename, file::LocalDirectoryDelimiter, file::ServerDirectoryDelimiter);
|
||||
|
||||
if (zipOpenNewFileInZip3(zf,unixFileName.c_str(),&zi,
|
||||
NULL,0,NULL,0,NULL /* comment*/,
|
||||
(opt_compress_level != 0) ? Z_DEFLATED : 0,
|
||||
opt_compress_level,0,
|
||||
/* -MAX_WBITS, DEF_MEM_LEVEL, Z_DEFAULT_STRATEGY, */
|
||||
-MAX_WBITS, DEF_MEM_LEVEL, Z_DEFAULT_STRATEGY,
|
||||
password,crcFile)
|
||||
!= ZIP_OK)
|
||||
throw zip::Exception ("zipOpenNewFileInZip");
|
||||
|
||||
const int buffer_size = 16384;
|
||||
char *buffer = new char[buffer_size];
|
||||
|
||||
try
|
||||
{
|
||||
std::ifstream fin (filenameinzip.c_str(), std::ios::binary);
|
||||
|
||||
if (!fin)
|
||||
throw zip::Exception ("error opening file to compress");
|
||||
|
||||
int size_read;
|
||||
|
||||
do
|
||||
{
|
||||
fin.read (buffer, buffer_size);
|
||||
size_read = (int)fin.gcount();
|
||||
|
||||
if (size_read>0)
|
||||
{
|
||||
if (zipWriteInFileInZip (zf,buffer,size_read) < 0)
|
||||
throw zip::Exception ("zipWriteInFileInZip");
|
||||
|
||||
}
|
||||
|
||||
} while (fin);
|
||||
|
||||
}
|
||||
catch (zip::Exception &e)
|
||||
{
|
||||
delete[] buffer;
|
||||
|
||||
zipCloseFileInZip(zf);
|
||||
throw e;
|
||||
}
|
||||
|
||||
if (zipCloseFileInZip(zf) != ZIP_OK)
|
||||
throw zip::Exception ("zipCloseFileInZip");
|
||||
}
|
||||
|
||||
void zip::compress (const std::string &file, const std::string &path, const std::list<std::string> &files)
|
||||
{
|
||||
zipFile zf;
|
||||
|
||||
#ifdef WIN32
|
||||
zlib_filefunc_def ffunc;
|
||||
fill_win32_filefunc(&ffunc);
|
||||
zf = zipOpen2(file.c_str(),0,NULL,&ffunc);
|
||||
#else
|
||||
zf = zipOpen(file.c_str(),0);
|
||||
#endif
|
||||
|
||||
if (!zf)
|
||||
throw zip::Exception ("zipOpen");
|
||||
|
||||
std::list<std::string>::const_iterator i;
|
||||
for (i=files.begin(); i!=files.end(); ++i)
|
||||
{
|
||||
compressFile (zf, path + *i, *i, NULL);
|
||||
}
|
||||
|
||||
if (zipClose(zf,NULL) != ZIP_OK)
|
||||
throw zip::Exception ("zipClose");
|
||||
}
|
||||
|
||||
void zip::compress (const std::string &file, const std::map<std::string, std::string> &zipFileNameToDiskFileName)
|
||||
{
|
||||
zipFile zf;
|
||||
|
||||
#ifdef WIN32
|
||||
zlib_filefunc_def ffunc;
|
||||
fill_win32_filefunc(&ffunc);
|
||||
zf = zipOpen2(file.c_str(),0,NULL,&ffunc);
|
||||
#else
|
||||
zf = zipOpen(file.c_str(),0);
|
||||
#endif
|
||||
|
||||
if (!zf)
|
||||
throw zip::Exception ("zipOpen");
|
||||
|
||||
std::map<std::string, std::string>::const_iterator i;
|
||||
for (i=zipFileNameToDiskFileName.begin(); i!=zipFileNameToDiskFileName.end(); ++i)
|
||||
{
|
||||
compressFile (zf, i->second, i->first, NULL);
|
||||
}
|
||||
|
||||
if (zipClose(zf,NULL) != ZIP_OK)
|
||||
throw zip::Exception ("zipClose");
|
||||
}
|
||||
|
||||
void zip::compress (const std::string &from, const std::string &to)
|
||||
{
|
||||
std::ifstream infile (from.c_str(), std::ios::binary);
|
||||
|
||||
int size_buf = 16384;
|
||||
char *buf = new char[16384];
|
||||
|
||||
try
|
||||
{
|
||||
file::ensurePath (to);
|
||||
gzFile gz = gzopen (to.c_str(), "wb");
|
||||
|
||||
if (gz == NULL)
|
||||
throw zip::Exception ("gzopen");
|
||||
|
||||
int read = 0;
|
||||
while (infile)
|
||||
{
|
||||
infile.read (buf, size_buf);
|
||||
read = (int)infile.gcount();
|
||||
|
||||
if (gzwrite (gz, buf, read))
|
||||
throw zip::Exception ("gzwrite");
|
||||
}
|
||||
}
|
||||
catch (zip::Exception &e)
|
||||
{
|
||||
delete[] buf;
|
||||
file::deleteFile (to);
|
||||
throw e;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
typedef unsigned int Header;
|
||||
|
||||
bool zip::compress (const char *in, int insize, char *&out, int &outsize, int level)
|
||||
{
|
||||
uLongf ulInSize = insize;
|
||||
uLongf ulOutSize = insize - sizeof(Header);
|
||||
|
||||
char *block = new char[insize];
|
||||
Header *header = (Header *)block;
|
||||
char *data = block + sizeof (Header);
|
||||
|
||||
int error = ::compress2((Bytef*)data, &ulOutSize, (const Bytef*)in, ulInSize, level);
|
||||
|
||||
if ((error!=Z_OK))
|
||||
{
|
||||
delete[] block;
|
||||
return false;
|
||||
}
|
||||
|
||||
*header = (Header)ulInSize;
|
||||
endian::swap (*header);
|
||||
|
||||
out = block;
|
||||
outsize = int(ulOutSize + sizeof(Header));
|
||||
|
||||
//-----------------------------------------------------
|
||||
/*
|
||||
char *temp;
|
||||
int tempsize;
|
||||
decompress (out, outsize, temp, tempsize);
|
||||
|
||||
assert (tempsize == insize);
|
||||
assert (memcmp (in, temp, tempsize)==0);
|
||||
|
||||
delete[] temp;
|
||||
*/
|
||||
//-----------------------------------------------------
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
bool zip::compress (const char *in, int insize, std::vector<char> &out, int level)
|
||||
{
|
||||
uLongf ulInSize = insize;
|
||||
uLongf ulOutSize = insize - sizeof(Header);
|
||||
|
||||
out.resize(insize);
|
||||
char *block = out.data();
|
||||
Header *header = (Header *)block;
|
||||
char *data = block + sizeof (Header);
|
||||
|
||||
int error = ::compress2((Bytef*)data, &ulOutSize, (const Bytef*)in, ulInSize, level);
|
||||
|
||||
if ((error!=Z_OK))
|
||||
{
|
||||
delete[] block;
|
||||
return false;
|
||||
}
|
||||
|
||||
*header = (Header)ulInSize;
|
||||
endian::swap (*header);
|
||||
|
||||
out.resize(int(ulOutSize + sizeof(Header)));
|
||||
|
||||
//-----------------------------------------------------
|
||||
/*
|
||||
char *temp;
|
||||
int tempsize;
|
||||
decompress (out, outsize, temp, tempsize);
|
||||
|
||||
assert (tempsize == insize);
|
||||
assert (memcmp (in, temp, tempsize)==0);
|
||||
|
||||
delete[] temp;
|
||||
*/
|
||||
//-----------------------------------------------------
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
std::vector<char> zip::compress(const char *in, int insize, int level)
|
||||
{
|
||||
std::vector<char> result;
|
||||
zip::compress(in, insize, result, level);
|
||||
return result;
|
||||
}
|
||||
|
||||
Vector<char> zip::compress (const std::string &path, const std::list<std::string> &files)
|
||||
{
|
||||
MemoryBuffer buffer({});
|
||||
|
||||
zipFile zf = zipOpen2("dummy.zip", APPEND_STATUS_CREATE, nullptr, &buffer.funcs);
|
||||
if (!zf)
|
||||
throw zip::Exception ("zipOpen");
|
||||
|
||||
std::list<std::string>::const_iterator i;
|
||||
for (i=files.begin(); i!=files.end(); ++i)
|
||||
{
|
||||
auto file = path + *i;
|
||||
sLogDebug("debug", logVar(file));
|
||||
compressFile (zf, file, *i, NULL);
|
||||
}
|
||||
|
||||
if (zipClose(zf,NULL) != ZIP_OK)
|
||||
throw zip::Exception ("zipClose");
|
||||
|
||||
return buffer.buffer;
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
56
tjp/core/zip/Compress+zstd.cpp
Executable file
56
tjp/core/zip/Compress+zstd.cpp
Executable file
@@ -0,0 +1,56 @@
|
||||
// TJP COPYRIGHT HEADER
|
||||
|
||||
|
||||
#include "Compress.h"
|
||||
#include "Decompress.h"
|
||||
|
||||
#include <zstd/zstd.h>
|
||||
|
||||
using namespace tjp;
|
||||
using namespace core::zstd;
|
||||
using namespace core;
|
||||
|
||||
std::vector<char> zstd::compress(const char *in, int insize, int level)
|
||||
{
|
||||
// Get maximum compressed size
|
||||
size_t maxCompressedSize = ZSTD_compressBound(insize);
|
||||
|
||||
// Allocate output buffer
|
||||
std::vector<char> result(maxCompressedSize);
|
||||
|
||||
// Compress the input
|
||||
size_t compressedSize = ZSTD_compress(result.data(), maxCompressedSize, in, insize, level);
|
||||
|
||||
// Check for compression error
|
||||
if (ZSTD_isError(compressedSize)) {
|
||||
result.clear();
|
||||
return result;
|
||||
}
|
||||
|
||||
// Resize result to actual compressed size
|
||||
result.resize(compressedSize);
|
||||
return result;
|
||||
}
|
||||
|
||||
std::vector<char> zstd::decompress(const char *in, int insize)
|
||||
{
|
||||
// Get decompressed size from the frame header
|
||||
unsigned long long decompressedSize = ZSTD_getFrameContentSize(in, insize);
|
||||
|
||||
if (decompressedSize == ZSTD_CONTENTSIZE_ERROR || decompressedSize == ZSTD_CONTENTSIZE_UNKNOWN) {
|
||||
return {};
|
||||
}
|
||||
|
||||
// Allocate output buffer
|
||||
std::vector<char> result(decompressedSize);
|
||||
|
||||
// Decompress
|
||||
size_t actualSize = ZSTD_decompress(result.data(), decompressedSize, in, insize);
|
||||
|
||||
// Check for decompression error
|
||||
if (ZSTD_isError(actualSize)) {
|
||||
return {};
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
40
tjp/core/zip/Compress.h
Executable file
40
tjp/core/zip/Compress.h
Executable file
@@ -0,0 +1,40 @@
|
||||
// TJP COPYRIGHT HEADER
|
||||
|
||||
#pragma once
|
||||
|
||||
#include "Exception.h"
|
||||
#include <tjp/core/containers/Vector.h>
|
||||
#include <list>
|
||||
#include <vector>
|
||||
#include <map>
|
||||
|
||||
namespace tjp {
|
||||
namespace core {
|
||||
namespace zip {
|
||||
|
||||
/**
|
||||
* decompresses the given file to the given path, sets the files to the set of files
|
||||
* found
|
||||
*/
|
||||
void compress (const std::string &file, const std::string &path, const std::list<std::string> &files);
|
||||
void compress (const std::string &file, const std::map<std::string, std::string> &zipFileNameToDiskFileName);
|
||||
void compress (const std::string &from, const std::string &to);
|
||||
|
||||
Vector<char> compress (const std::string &path, const std::list<std::string> &files);
|
||||
|
||||
bool compress (const char *from, int fromSize, char *&to, int &toSize, int level=9);
|
||||
|
||||
bool compress (const char *from, int fromSize, std::vector<char> &to, int level=9);
|
||||
|
||||
std::vector<char> compress (const char *from, int fromSize, int level=9);
|
||||
|
||||
} // namespace
|
||||
|
||||
namespace zstd {
|
||||
|
||||
std::vector<char> compress (const char *from, int fromSize, int level=9);
|
||||
|
||||
}
|
||||
|
||||
} //
|
||||
} //
|
||||
276
tjp/core/zip/Decompress.cpp
Executable file
276
tjp/core/zip/Decompress.cpp
Executable file
@@ -0,0 +1,276 @@
|
||||
// TJP COPYRIGHT HEADER
|
||||
|
||||
|
||||
#include "Decompress.h"
|
||||
#include <assert.h>
|
||||
#include <list>
|
||||
#include "../endian/Endian.h"
|
||||
#include "../file/File.h"
|
||||
#include <fstream>
|
||||
|
||||
#include <tjp/core/log/Log.h>
|
||||
#include "../file/Path.h"
|
||||
|
||||
#include <cstring>
|
||||
#include <zlib/zlib.h>
|
||||
|
||||
#include "minizip/ioapi.h"
|
||||
#ifdef WIN32
|
||||
#include "minizip/iowin32.h"
|
||||
#endif
|
||||
|
||||
using namespace tjp;
|
||||
using namespace core;
|
||||
using namespace core::zip;
|
||||
|
||||
|
||||
#include "minizip/unzip.h"
|
||||
|
||||
void extractFile(
|
||||
unzFile uf,
|
||||
const char *password,
|
||||
const std::string &basedirectory,
|
||||
std::string &relativefilename
|
||||
)
|
||||
{
|
||||
unz_file_info file_info;
|
||||
char filename_inzip[256];
|
||||
|
||||
int err;
|
||||
|
||||
err = unzGetCurrentFileInfo(uf,&file_info,filename_inzip,sizeof(filename_inzip),NULL,0,NULL,0);
|
||||
if (err!=UNZ_OK)
|
||||
{
|
||||
throw zip::Exception ("unzGetCurrentFileInfo");
|
||||
}
|
||||
|
||||
relativefilename = filename_inzip;
|
||||
|
||||
std::string filename = basedirectory + file::convertDelimiter (relativefilename);
|
||||
file::ensurePath (filename);
|
||||
|
||||
const int size_buf = 16384;
|
||||
char *buf = new char [size_buf];
|
||||
|
||||
try
|
||||
{
|
||||
std::ofstream outfile (filename.c_str(), std::ios::binary);
|
||||
|
||||
if (unzOpenCurrentFilePassword(uf,password)!=UNZ_OK)
|
||||
{
|
||||
throw zip::Exception ("unzOpenCurrentFilePassword");
|
||||
}
|
||||
|
||||
int len;
|
||||
do
|
||||
{
|
||||
len = unzReadCurrentFile(uf,buf,size_buf);
|
||||
if (len<0)
|
||||
{
|
||||
throw zip::Exception("unzReadCurrentFile");
|
||||
}
|
||||
else
|
||||
if (len>0)
|
||||
{
|
||||
if (!outfile.write (buf, len))
|
||||
{
|
||||
throw zip::Exception("error in writing extracted file\n");
|
||||
}
|
||||
}
|
||||
}
|
||||
while (len>0);
|
||||
|
||||
}
|
||||
catch (zip::Exception &e)
|
||||
{
|
||||
file::deleteFile(filename);
|
||||
unzCloseCurrentFile (uf);
|
||||
delete[] buf;
|
||||
throw e;
|
||||
}
|
||||
|
||||
delete[] buf;
|
||||
|
||||
// change_file_date(filename,file_info.dosDate,
|
||||
// file_info.tmu_date);
|
||||
|
||||
err = unzCloseCurrentFile (uf);
|
||||
if (err!=UNZ_OK)
|
||||
{
|
||||
throw zip::Exception("error %d with zipfile in unzCloseCurrentFile");
|
||||
}
|
||||
}
|
||||
|
||||
void extractZip(
|
||||
unzFile uf,
|
||||
const char* password,
|
||||
const std::string &basedirectory,
|
||||
std::list<std::string> &list
|
||||
)
|
||||
{
|
||||
uLong i;
|
||||
unz_global_info gi;
|
||||
int err;
|
||||
|
||||
err = unzGetGlobalInfo (uf,&gi);
|
||||
if (err!=UNZ_OK)
|
||||
throw zip::Exception("unzGetGlobalInfo");
|
||||
|
||||
for (i=0;i<gi.number_entry;i++)
|
||||
{
|
||||
std::string filename;
|
||||
extractFile(uf, password, basedirectory, filename);
|
||||
list.push_back(filename);
|
||||
|
||||
if ((i+1)<gi.number_entry)
|
||||
{
|
||||
err = unzGoToNextFile(uf);
|
||||
|
||||
if (err!=UNZ_OK)
|
||||
throw zip::Exception ("unzGoToNextFile");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void extractOneFile(
|
||||
unzFile uf,
|
||||
const std::string &filename,
|
||||
const char* password,
|
||||
const std::string &basedirectory
|
||||
)
|
||||
{
|
||||
if (unzLocateFile(uf,filename.c_str(),false)!=UNZ_OK)
|
||||
throw zip::Exception ("unzLocateFile");
|
||||
|
||||
std::string dummyfilename;
|
||||
extractFile(uf,password,basedirectory,dummyfilename);
|
||||
}
|
||||
|
||||
void zip::decompress (const std::string &file, const std::string &path, std::list<std::string> &files)
|
||||
{
|
||||
#ifdef WIN32
|
||||
zlib_filefunc_def ffunc;
|
||||
#endif
|
||||
|
||||
char filename_try[256+1];
|
||||
strncpy(filename_try, file.c_str(),256-1);
|
||||
/* strncpy doesnt append the trailing NULL, if the string is too long. */
|
||||
filename_try[256] = '\0';
|
||||
|
||||
#ifdef WIN32
|
||||
fill_win32_filefunc(&ffunc);
|
||||
unzFile uf = unzOpen2(filename_try,&ffunc);
|
||||
#else
|
||||
unzFile uf = unzOpen(filename_try);
|
||||
#endif
|
||||
|
||||
if (uf==NULL)
|
||||
{
|
||||
throw zip::Exception ("unzOpen");
|
||||
}
|
||||
|
||||
try
|
||||
{
|
||||
extractZip (uf,NULL, path, files);
|
||||
}
|
||||
catch (zip::Exception &)
|
||||
{
|
||||
unzCloseCurrentFile(uf);
|
||||
throw;
|
||||
}
|
||||
unzCloseCurrentFile(uf);
|
||||
}
|
||||
|
||||
void zip::decompress (const std::string &from, const std::string &to)
|
||||
{
|
||||
gzFile gz = gzopen (from.c_str(), "rb");
|
||||
|
||||
if (gz == NULL)
|
||||
throw zip::Exception ("gzopen");
|
||||
|
||||
int size_buf = 16384;
|
||||
char *buf = new char[16384];
|
||||
|
||||
try
|
||||
{
|
||||
file::ensurePath (to);
|
||||
std::ofstream outfile (to.c_str(), std::ios::binary);
|
||||
|
||||
int read = 0;
|
||||
while ( (read = gzread (gz, buf, size_buf) > 0) && outfile)
|
||||
{
|
||||
outfile.write (buf, read);
|
||||
}
|
||||
|
||||
if (read < 0 && !outfile)
|
||||
{
|
||||
throw zip::Exception ("gzread");
|
||||
}
|
||||
}
|
||||
catch (zip::Exception &e)
|
||||
{
|
||||
delete[] buf;
|
||||
file::deleteFile (to);
|
||||
throw e;
|
||||
}
|
||||
}
|
||||
|
||||
typedef unsigned int Header;
|
||||
|
||||
bool zip::decompress (const char *in, int insize, char *&out, int &outsize)
|
||||
{
|
||||
const char *block = in;
|
||||
const Header *header = (const Header *)block;
|
||||
const char *data = block + sizeof (Header);
|
||||
|
||||
endian::swap (*header);
|
||||
|
||||
uLongf ulInSize = insize - sizeof (Header);
|
||||
uLongf ulOutSize = *header;
|
||||
|
||||
char *uncompressed = new char[ulOutSize];
|
||||
int error = ::uncompress((Bytef *)uncompressed, &ulOutSize, (const Bytef*)data, ulInSize);
|
||||
|
||||
if (error!=Z_OK)
|
||||
{
|
||||
delete[] uncompressed;
|
||||
return false;
|
||||
}
|
||||
|
||||
out = uncompressed;
|
||||
outsize = (int)ulOutSize;
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
bool zip::decompress (const char *in, int insize, std::vector<char> &out)
|
||||
{
|
||||
const char *block = in;
|
||||
const Header *header = (const Header *)block;
|
||||
const char *data = block + sizeof (Header);
|
||||
|
||||
endian::swap (*header);
|
||||
|
||||
uLongf ulInSize = insize - sizeof (Header);
|
||||
uLongf ulOutSize = *header;
|
||||
|
||||
out.resize(ulOutSize);
|
||||
char *uncompressed = out.data();
|
||||
int error = ::uncompress((Bytef *)uncompressed, &ulOutSize, (const Bytef*)data, ulInSize);
|
||||
|
||||
if (error!=Z_OK)
|
||||
{
|
||||
delete[] uncompressed;
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
std::vector<char> zip::decompress (const char *in, int insize)
|
||||
{
|
||||
std::vector<char> out;
|
||||
zip::decompress(in, insize, out);
|
||||
|
||||
return out;
|
||||
}
|
||||
38
tjp/core/zip/Decompress.h
Executable file
38
tjp/core/zip/Decompress.h
Executable file
@@ -0,0 +1,38 @@
|
||||
// TJP COPYRIGHT HEADER
|
||||
|
||||
|
||||
#pragma once
|
||||
|
||||
#include "Exception.h"
|
||||
#include <list>
|
||||
#include <vector>
|
||||
|
||||
namespace tjp {
|
||||
namespace core {
|
||||
namespace zip {
|
||||
|
||||
/**
|
||||
* decompresses the given file to the given path, sets the files to the set of files
|
||||
* found
|
||||
*/
|
||||
void decompress (const std::string &file, const std::string &path, std::list<std::string> &files);
|
||||
|
||||
void decompress (const std::string &from, const std::string &to);
|
||||
|
||||
bool decompress (const char *from, int fromSize, char *&to, int &toSize);
|
||||
|
||||
bool decompress (const char *from, int fromSize, std::vector<char> &to);
|
||||
|
||||
std::vector<char> decompress (const char *from, int fromSize);
|
||||
|
||||
} // namespace
|
||||
|
||||
namespace zstd {
|
||||
|
||||
std::vector<char> decompress (const char *from, int fromSize);
|
||||
|
||||
}
|
||||
|
||||
} // namespace
|
||||
} // namespace
|
||||
|
||||
13
tjp/core/zip/Exception.h
Executable file
13
tjp/core/zip/Exception.h
Executable file
@@ -0,0 +1,13 @@
|
||||
// TJP COPYRIGHT HEADER
|
||||
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <tjp/core/exception/Exception.hpp>
|
||||
|
||||
namespace tjp::core::zip {
|
||||
|
||||
DECLARE_EXCEPTION (Exception);
|
||||
|
||||
} // namespace Zip
|
||||
|
||||
101
tjp/core/zip/MemoryBuffer.cpp
Executable file
101
tjp/core/zip/MemoryBuffer.cpp
Executable file
@@ -0,0 +1,101 @@
|
||||
// TJP COPYRIGHT HEADER
|
||||
|
||||
#include "MemoryBuffer.hpp"
|
||||
|
||||
#include <cstring>
|
||||
|
||||
namespace tjp::core::zip {
|
||||
|
||||
// Custom read function for zlib
|
||||
static voidpf ZCALLBACK mem_open(voidpf opaque, const char* filename, int mode) {
|
||||
|
||||
return opaque; // Opaque is our MemoryBuffer
|
||||
}
|
||||
|
||||
int ZCALLBACK mem_close(voidpf opaque, voidpf stream) {
|
||||
// Nothing to do here since std::vector manages memory automatically
|
||||
return ZIP_OK;
|
||||
}
|
||||
|
||||
static uLong ZCALLBACK mem_read(voidpf opaque, voidpf stream, void* buf, uLong size) {
|
||||
MemoryBuffer* mem = static_cast<MemoryBuffer*>(opaque);
|
||||
size_t remaining = mem->buffer.size() - mem->position;
|
||||
|
||||
size_t toRead = (remaining < size) ? remaining : size;
|
||||
if (toRead > 0) {
|
||||
std::memcpy(buf, mem->buffer.data() + mem->position, toRead);
|
||||
mem->position += toRead;
|
||||
}
|
||||
return static_cast<uLong>(toRead);
|
||||
}
|
||||
|
||||
static long ZCALLBACK mem_tell(voidpf opaque, voidpf stream) {
|
||||
MemoryBuffer* mem = static_cast<MemoryBuffer*>(opaque);
|
||||
return static_cast<long>(mem->position);
|
||||
}
|
||||
|
||||
static long ZCALLBACK mem_seek(voidpf opaque, voidpf stream, uLong offset, int origin) {
|
||||
MemoryBuffer* mem = static_cast<MemoryBuffer*>(opaque);
|
||||
size_t new_pos = mem->position;
|
||||
|
||||
if (origin == ZLIB_FILEFUNC_SEEK_CUR) {
|
||||
new_pos += offset;
|
||||
} else if (origin == ZLIB_FILEFUNC_SEEK_END) {
|
||||
new_pos = mem->buffer.size() + offset;
|
||||
} else if (origin == ZLIB_FILEFUNC_SEEK_SET) {
|
||||
new_pos = offset;
|
||||
}
|
||||
|
||||
if (new_pos > mem->buffer.size()) {
|
||||
return -1; // Seeking beyond the buffer
|
||||
}
|
||||
|
||||
mem->position = new_pos;
|
||||
return 0; // Success
|
||||
}
|
||||
|
||||
uLong ZCALLBACK mem_write(voidpf opaque, voidpf stream, const void* buf, uLong size)
|
||||
{
|
||||
MemoryBuffer* mem = static_cast<MemoryBuffer*>(opaque);
|
||||
const char *data = (const char *)buf;
|
||||
|
||||
if (mem->buffer.size() < mem->position)
|
||||
return -1;
|
||||
|
||||
auto remaining = mem->buffer.size() - mem->position;
|
||||
auto wm = std::min(remaining, size);
|
||||
|
||||
if (wm > 0)
|
||||
std::memcpy(
|
||||
mem->buffer.data() + mem->position,
|
||||
data,
|
||||
wm
|
||||
);
|
||||
|
||||
if (size > wm)
|
||||
mem->buffer.insert(
|
||||
mem->buffer.end(),
|
||||
data + wm,
|
||||
data + (size - wm)
|
||||
);
|
||||
|
||||
mem->position += size;
|
||||
|
||||
return size;
|
||||
}
|
||||
|
||||
MemoryBuffer::MemoryBuffer(Vector<char> &&contents) :
|
||||
buffer(std::move(contents)),
|
||||
funcs{0}
|
||||
{
|
||||
funcs.zopen_file = mem_open;
|
||||
funcs.zwrite_file = mem_write;
|
||||
funcs.ztell_file = mem_tell;
|
||||
funcs.zclose_file = mem_close;
|
||||
funcs.zread_file = mem_read;
|
||||
// funcs.zerror_file = mem_error;
|
||||
funcs.zseek_file = mem_seek;
|
||||
funcs.opaque = this;
|
||||
} //
|
||||
|
||||
} // namespace
|
||||
11
tjp/core/zip/MemoryBuffer.h
Executable file
11
tjp/core/zip/MemoryBuffer.h
Executable file
@@ -0,0 +1,11 @@
|
||||
// TJP COPYRIGHT HEADER
|
||||
|
||||
|
||||
#pragma once
|
||||
|
||||
namespace tjp::core::zip {
|
||||
|
||||
// Custom memory structure
|
||||
struct MemoryBuffer;
|
||||
|
||||
} //
|
||||
25
tjp/core/zip/MemoryBuffer.hpp
Executable file
25
tjp/core/zip/MemoryBuffer.hpp
Executable file
@@ -0,0 +1,25 @@
|
||||
// TJP COPYRIGHT HEADER
|
||||
|
||||
|
||||
#pragma once
|
||||
|
||||
#include "Exception.h"
|
||||
#include <tjp/core/containers/Vector.h>
|
||||
|
||||
#include <zlib/zlib.h>
|
||||
#include "minizip/zip.h"
|
||||
|
||||
namespace tjp::core::zip {
|
||||
|
||||
// Custom memory structure
|
||||
struct MemoryBuffer
|
||||
{
|
||||
Vector<char> buffer;
|
||||
size_t position = 0;
|
||||
|
||||
zlib_filefunc_def funcs;
|
||||
|
||||
MemoryBuffer(Vector<char> &&);
|
||||
};
|
||||
|
||||
} //
|
||||
138
tjp/core/zip/VirtualFileSystem.cpp
Normal file
138
tjp/core/zip/VirtualFileSystem.cpp
Normal file
@@ -0,0 +1,138 @@
|
||||
// TJP COPYRIGHT HEADER
|
||||
|
||||
#include "VirtualFileSystem.hpp"
|
||||
|
||||
#include <zlib/zlib.h>
|
||||
|
||||
#include "minizip/ioapi.h"
|
||||
#ifdef WIN32
|
||||
#include "minizip/iowin32.h"
|
||||
#endif
|
||||
|
||||
#include "minizip/unzip.h"
|
||||
|
||||
#include "../zip/MemoryBuffer.hpp"
|
||||
|
||||
#include <tjp/core/exception/Exception.hpp>
|
||||
|
||||
#include <tjp/core/debug/debug_break.h>
|
||||
|
||||
namespace tjp::core::zip {
|
||||
|
||||
using Contents = file::Contents;
|
||||
using ContentsView = file::ContentsView;
|
||||
|
||||
struct VirtualFileSystem::I
|
||||
{
|
||||
zip::MemoryBuffer memoryBuffer;
|
||||
unzFile uf = nullptr;
|
||||
|
||||
I(Contents &&contents);
|
||||
~I();
|
||||
|
||||
Contents get(const StringView &fileName);
|
||||
void put(const StringView &fileName, ContentsView);
|
||||
bool has(const StringView &fileName);
|
||||
} ;
|
||||
|
||||
VirtualFileSystem::I::I(Contents &&contents) :
|
||||
memoryBuffer(std::move(contents))
|
||||
{
|
||||
uf = unzOpen2("dummy.zip", &memoryBuffer.funcs);
|
||||
}
|
||||
|
||||
VirtualFileSystem::I::~I()
|
||||
{
|
||||
if (uf)
|
||||
unzClose(uf);
|
||||
|
||||
uf = nullptr;
|
||||
}
|
||||
|
||||
Contents VirtualFileSystem::I::get(const StringView &fileName)
|
||||
{
|
||||
// debug_break();
|
||||
|
||||
if (unzLocateFile(uf,fileName.data(),false)!=UNZ_OK)
|
||||
throw Exception { "File does not exist" };
|
||||
|
||||
unz_file_info file_info;
|
||||
char filename_inzip[256];
|
||||
|
||||
int err;
|
||||
|
||||
err = unzGetCurrentFileInfo(uf,&file_info,filename_inzip,sizeof(filename_inzip),NULL,0,NULL,0);
|
||||
if (err!=UNZ_OK)
|
||||
{
|
||||
throw Exception ("unzGetCurrentFileInfo");
|
||||
}
|
||||
|
||||
Contents contents;
|
||||
contents.resize(file_info.uncompressed_size);
|
||||
|
||||
try
|
||||
{
|
||||
if (unzOpenCurrentFile(uf) != UNZ_OK)
|
||||
throw Exception { "Open failure" };
|
||||
|
||||
auto len = unzReadCurrentFile(uf, contents.data(), contents.size());
|
||||
if (len != contents.size())
|
||||
throw Exception { "Read error" };
|
||||
|
||||
unzCloseCurrentFile (uf);
|
||||
|
||||
return contents;
|
||||
}
|
||||
catch (Exception &e)
|
||||
{
|
||||
unzCloseCurrentFile (uf);
|
||||
throw e;
|
||||
}
|
||||
}
|
||||
|
||||
bool VirtualFileSystem::I::has(const StringView &fileName)
|
||||
{
|
||||
return unzLocateFile(uf,fileName.data(),false) == UNZ_OK;
|
||||
}
|
||||
|
||||
void VirtualFileSystem::I::put(const StringView &fileName, ContentsView)
|
||||
{
|
||||
throw Exception { "Not implemented" };
|
||||
}
|
||||
|
||||
VirtualFileSystem::VirtualFileSystem(Contents &&contents) :
|
||||
i(new I(std::move(contents)))
|
||||
{
|
||||
}
|
||||
|
||||
Contents VirtualFileSystem::get(const StringView &path) const
|
||||
{
|
||||
return i->get(path);
|
||||
}
|
||||
|
||||
Optional<Contents> VirtualFileSystem::get_if(const StringView &path) const
|
||||
{
|
||||
try
|
||||
{
|
||||
return i->get(path);
|
||||
}
|
||||
catch(...)
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
return {};
|
||||
}
|
||||
|
||||
void VirtualFileSystem::put(const StringView &path, ContentsView contents)
|
||||
{
|
||||
return i->put(path, contents);
|
||||
}
|
||||
|
||||
bool VirtualFileSystem::has(const StringView &path) const
|
||||
{
|
||||
return i->has(path);
|
||||
}
|
||||
|
||||
|
||||
} // namespace
|
||||
9
tjp/core/zip/VirtualFileSystem.h
Normal file
9
tjp/core/zip/VirtualFileSystem.h
Normal file
@@ -0,0 +1,9 @@
|
||||
// TJP COPYRIGHT HEADER
|
||||
|
||||
#pragma once
|
||||
|
||||
namespace tjp::core::zip {
|
||||
|
||||
struct VirtualFileSystem;
|
||||
|
||||
} // namespace
|
||||
32
tjp/core/zip/VirtualFileSystem.hpp
Normal file
32
tjp/core/zip/VirtualFileSystem.hpp
Normal file
@@ -0,0 +1,32 @@
|
||||
// TJP COPYRIGHT HEADER
|
||||
|
||||
#pragma once
|
||||
|
||||
#include "../file/VirtualFileSystem.hpp"
|
||||
#include <tjp/core/exception/Exception.hpp>
|
||||
|
||||
namespace tjp::core::zip {
|
||||
|
||||
struct VirtualFileSystem : file::VirtualFileSystem
|
||||
{
|
||||
using Super = file::VirtualFileSystem;
|
||||
|
||||
struct I;
|
||||
mutable I *i;
|
||||
|
||||
VirtualFileSystem(file::Contents &&contents);
|
||||
|
||||
inline
|
||||
String pathFor(const StringView &path) const override
|
||||
{
|
||||
throw Exception { "No Implemented" };
|
||||
}
|
||||
|
||||
file::Contents get(const StringView &path) const override;
|
||||
Optional<file::Contents> get_if(const StringView &path) const override;
|
||||
void put(const StringView &path, file::ContentsView contents) override;
|
||||
bool has(const StringView &fileName) const override;
|
||||
} ;
|
||||
|
||||
|
||||
} // namespace
|
||||
232
tjp/core/zip/_delete/Compression.cpp
Executable file
232
tjp/core/zip/_delete/Compression.cpp
Executable file
@@ -0,0 +1,232 @@
|
||||
// TJP COPYRIGHT HEADER
|
||||
|
||||
|
||||
#include "Compression.hpp"
|
||||
#include <zlib/zlib.h>
|
||||
|
||||
#include <tjp/core/threads/Lock.hpp>
|
||||
#include <tjp/core/containers/Vector.hpp>
|
||||
#include <tjp/core/algorithm/mem_copy.hpp>
|
||||
|
||||
namespace tjp::core::zip {
|
||||
|
||||
// ----------------------
|
||||
|
||||
CompressorOneShot::CompressorOneShot(int level_) :
|
||||
level(level_)
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
bool CompressorOneShot::operate(const Data *from, Size fromSize, Data *&to, Size &toSize)
|
||||
{
|
||||
const Bytef *source = (const Bytef *)from;
|
||||
uLongf sourceLen = (uLongf)fromSize;
|
||||
Bytef *dest = (Bytef *)to;
|
||||
uLongf destLen = (uLongf)toSize;
|
||||
|
||||
auto result = compress2(dest, &destLen, source, sourceLen, level) == Z_OK;
|
||||
|
||||
toSize = destLen;
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
bool DecompressorOneShot::operate(const Data *from, Size fromSize, Data *&to, Size &toSize)
|
||||
{
|
||||
const Bytef *source = (const Bytef *)from;
|
||||
uLongf sourceLen = fromSize;
|
||||
Bytef *dest = (Bytef *)to;
|
||||
uLongf destLen = toSize;
|
||||
|
||||
auto result = ::uncompress(dest, &destLen, source, sourceLen) == Z_OK;
|
||||
|
||||
toSize = destLen;
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
// ---------------------
|
||||
|
||||
Compressor::Compressor(int level_) :
|
||||
level(level_),
|
||||
i(nullptr)
|
||||
{
|
||||
}
|
||||
|
||||
void *Compressor::allocateStream()
|
||||
{
|
||||
auto z = (z_streamp)calloc(1, sizeof(z_stream));
|
||||
deflateInit(z, level);
|
||||
return z;
|
||||
}
|
||||
|
||||
void Compressor::deallocateStream(void *z)
|
||||
{
|
||||
free(z);
|
||||
}
|
||||
|
||||
bool Compressor::operate(const Data *from, Size fromSize, Data *&to, Size &toSize)
|
||||
{
|
||||
auto strm = (z_streamp)i;
|
||||
|
||||
strm->next_in = (Bytef*)from;
|
||||
strm->avail_in = (uInt)fromSize;
|
||||
|
||||
strm->next_out = (Bytef*)to;
|
||||
strm->avail_out = (uInt)toSize;
|
||||
|
||||
auto result = deflate(strm, Z_FINISH);
|
||||
toSize = strm->total_out;
|
||||
|
||||
return result == Z_STREAM_END;
|
||||
}
|
||||
|
||||
// ------------
|
||||
|
||||
Decompressor::Decompressor() :
|
||||
i(nullptr)
|
||||
{
|
||||
}
|
||||
|
||||
|
||||
void *Decompressor::allocateStream()
|
||||
{
|
||||
auto z = (z_streamp)calloc(1, sizeof(z_stream));
|
||||
inflateInit(z);
|
||||
return z;
|
||||
}
|
||||
|
||||
|
||||
void Decompressor::deallocateStream(void *z)
|
||||
{
|
||||
free(z);
|
||||
}
|
||||
|
||||
bool Decompressor::operate(const Data *from, Size fromSize, Data *&to, Size &toSize)
|
||||
{
|
||||
auto strm = (z_streamp)i;
|
||||
|
||||
strm->next_in = (Bytef*)from;
|
||||
strm->avail_in = (uInt)fromSize;
|
||||
|
||||
strm->next_out = (Bytef*)to;
|
||||
strm->avail_out = (uInt)toSize;
|
||||
|
||||
auto result = inflate(strm, Z_FINISH);
|
||||
toSize = strm->total_out;
|
||||
|
||||
return result == Z_STREAM_END;
|
||||
}
|
||||
|
||||
// ------------
|
||||
|
||||
struct Pool
|
||||
{
|
||||
Mutex mutex;
|
||||
Vector<z_stream *> pooled;
|
||||
|
||||
z_stream *allocate();
|
||||
void release(z_stream *);
|
||||
} ;
|
||||
|
||||
z_stream * Pool::allocate()
|
||||
{
|
||||
auto lock = lock_of(mutex);
|
||||
|
||||
if (pooled.empty())
|
||||
return nullptr;
|
||||
|
||||
auto result = pooled.back();
|
||||
pooled.pop_back();
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
void Pool::release(z_stream *z)
|
||||
{
|
||||
auto lock = lock_of(mutex);
|
||||
|
||||
pooled.push_back(z);
|
||||
}
|
||||
|
||||
static Pool deflators[10];
|
||||
static Pool inflators;
|
||||
|
||||
void *getPoolStream(int level)
|
||||
{
|
||||
if (level == -1)
|
||||
return (void *)inflators.allocate();
|
||||
|
||||
if (level > 9)
|
||||
level = 9;
|
||||
|
||||
return (void *)deflators[level].allocate();
|
||||
}
|
||||
|
||||
void putPoolStream(int level, void *s)
|
||||
{
|
||||
if (level == -1)
|
||||
return inflators.release((z_streamp)s);
|
||||
|
||||
if (level > 9)
|
||||
level = 9;
|
||||
|
||||
return deflators[level].release((z_streamp)s);
|
||||
|
||||
}
|
||||
|
||||
// --------------
|
||||
|
||||
bool setDict(void *p, int level, char *dict, size_t size)
|
||||
{
|
||||
auto z = (z_streamp)p;
|
||||
|
||||
int error = 0;
|
||||
if (level < 0)
|
||||
error = inflateSetDictionary(z, (const Bytef *)dict, (uInt)size);
|
||||
else
|
||||
error = deflateSetDictionary(z, (const Bytef *)dict, (uInt)size);
|
||||
|
||||
return error == Z_OK;
|
||||
}
|
||||
|
||||
bool getDict(void *p, int level, char *dict, size_t size)
|
||||
{
|
||||
auto z = (z_streamp)p;
|
||||
|
||||
auto size_ = (uInt)size;
|
||||
|
||||
char store[32768];
|
||||
|
||||
int error = 0;
|
||||
if (level < 0)
|
||||
error = inflateGetDictionary(z, (Bytef *)&store[0], &size_);
|
||||
else
|
||||
error = deflateGetDictionary(z, (Bytef *)&store[0], &size_);
|
||||
|
||||
// zlib seems to store from end to front
|
||||
auto offset =
|
||||
size_ > size ?
|
||||
size_ - size :
|
||||
0;
|
||||
|
||||
mem_copy(dict, &store[offset], size);
|
||||
|
||||
return error == Z_OK;
|
||||
}
|
||||
|
||||
// ----------------
|
||||
|
||||
bool clearStream(void *p, int level)
|
||||
{
|
||||
auto z = (z_streamp)p;
|
||||
|
||||
if (level < 0)
|
||||
return (inflateReset(z) == Z_OK);
|
||||
else
|
||||
return (deflateReset(z) == Z_OK);
|
||||
}
|
||||
|
||||
|
||||
} // namespace
|
||||
18
tjp/core/zip/_delete/Compression.h
Executable file
18
tjp/core/zip/_delete/Compression.h
Executable file
@@ -0,0 +1,18 @@
|
||||
// TJP COPYRIGHT HEADER
|
||||
|
||||
|
||||
#pragma once
|
||||
|
||||
namespace tjp {
|
||||
namespace core {
|
||||
namespace zip {
|
||||
|
||||
/**
|
||||
* decompresses the given file to the given path, sets the files to the set of files
|
||||
* found
|
||||
*/
|
||||
struct Compressor;
|
||||
|
||||
} // namespace
|
||||
} //
|
||||
} //
|
||||
267
tjp/core/zip/_delete/Compression.hpp
Executable file
267
tjp/core/zip/_delete/Compression.hpp
Executable file
@@ -0,0 +1,267 @@
|
||||
// TJP COPYRIGHT HEADER
|
||||
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <stddef.h>
|
||||
#include <utility>
|
||||
#include <string.h>
|
||||
|
||||
namespace tjp::core::zip {
|
||||
|
||||
using Data = char;
|
||||
using Size = size_t;
|
||||
|
||||
/**
|
||||
* decompresses the given file to the given path, sets the files to the set of files
|
||||
* found
|
||||
*/
|
||||
struct Operator
|
||||
{
|
||||
virtual ~Operator() {}
|
||||
|
||||
virtual char getID() = 0;
|
||||
virtual bool operate(const Data *from, Size fromSize, Data *&to, Size &toSize) = 0;
|
||||
} ;
|
||||
|
||||
|
||||
template<typename T>
|
||||
struct VirtualOperator : Operator
|
||||
{
|
||||
using Operator = T;
|
||||
Operator op;
|
||||
|
||||
template<typename ... Args>
|
||||
VirtualOperator(Args&& ... args) :
|
||||
op(std::forward<Args>(args)...)
|
||||
{}
|
||||
|
||||
char getID() override
|
||||
{
|
||||
return op.getID();
|
||||
}
|
||||
|
||||
bool operate(const Data *from, Size fromSize, Data *&to, Size &toSize) override
|
||||
{
|
||||
return op.operate(from, fromSize, to, toSize);
|
||||
}
|
||||
} ;
|
||||
|
||||
struct CompressorOneShot
|
||||
{
|
||||
CompressorOneShot(int level_);
|
||||
|
||||
int level;
|
||||
bool enabled();
|
||||
char getID();
|
||||
|
||||
bool operate(const Data *from, Size fromSize, Data *&to, Size &toSize);
|
||||
} ;
|
||||
|
||||
struct DecompressorOneShot
|
||||
{
|
||||
char getID();
|
||||
bool operate(const Data *from, Size fromSize, Data *&to, Size &toSize);
|
||||
} ;
|
||||
|
||||
struct Compressor
|
||||
{
|
||||
Compressor(int level_);
|
||||
|
||||
void setExecutor(void *);
|
||||
void *getExecutor();
|
||||
|
||||
void *i;
|
||||
int level;
|
||||
|
||||
int getLevel();
|
||||
bool enabled();
|
||||
char getID();
|
||||
|
||||
bool operate(const Data *from, Size fromSize, Data *&to, Size &toSize);
|
||||
|
||||
void *allocateStream();
|
||||
void deallocateStream(void *);
|
||||
} ;
|
||||
|
||||
struct Decompressor
|
||||
{
|
||||
Decompressor();
|
||||
|
||||
void *i;
|
||||
|
||||
void setExecutor(void *);
|
||||
void *getExecutor();
|
||||
|
||||
char getID();
|
||||
int getLevel();
|
||||
|
||||
bool operate(const Data *from, Size fromSize, Data *&to, Size &toSize);
|
||||
|
||||
void *allocateStream();
|
||||
void deallocateStream(void *);
|
||||
} ;
|
||||
|
||||
template<typename T>
|
||||
struct Chain
|
||||
{
|
||||
using Next = T;
|
||||
Next next;
|
||||
|
||||
template<typename ... Args>
|
||||
Chain(Args&& ... args) :
|
||||
next(std::forward<Args>(args)...)
|
||||
{}
|
||||
|
||||
auto setExecutor(void *i)
|
||||
{
|
||||
next.setExecutor(i);
|
||||
}
|
||||
|
||||
auto getExecutor()
|
||||
{
|
||||
return next.getExecutor();
|
||||
}
|
||||
|
||||
auto enabled()
|
||||
{
|
||||
return next.enabled();
|
||||
}
|
||||
|
||||
auto getLevel()
|
||||
{
|
||||
return next.getLevel();
|
||||
}
|
||||
|
||||
auto getID()
|
||||
{
|
||||
return next.getID();
|
||||
}
|
||||
|
||||
auto operate(const Data *from, Size fromSize, Data *&to, Size &toSize)
|
||||
{
|
||||
return next.operate(from, fromSize, to, toSize);
|
||||
}
|
||||
|
||||
void *allocateStream()
|
||||
{
|
||||
return next.allocateStream();
|
||||
}
|
||||
|
||||
void deallocateStream(void *s)
|
||||
{
|
||||
next.deallocateStream(s);
|
||||
}
|
||||
|
||||
} ;
|
||||
|
||||
template<typename T>
|
||||
struct RetainMemory : Chain<T>
|
||||
{
|
||||
using Super = Chain<T>;
|
||||
|
||||
template<typename ... Args>
|
||||
RetainMemory(Args&& ... args) :
|
||||
Super(std::forward<Args>(args)...)
|
||||
{
|
||||
Super::setExecutor(Super::allocateStream());
|
||||
}
|
||||
|
||||
~RetainMemory()
|
||||
{
|
||||
Super::deallocateStream(Super::getExecutor());
|
||||
}
|
||||
} ;
|
||||
|
||||
bool clearStream(void *p, int level);
|
||||
|
||||
template<typename T>
|
||||
struct Clear : Chain<T>
|
||||
{
|
||||
using Super = Chain<T>;
|
||||
|
||||
template<typename ... Args>
|
||||
Clear(Args&& ... args) :
|
||||
Super(std::forward<Args>(args)...)
|
||||
{
|
||||
}
|
||||
|
||||
bool operate(const Data *from, Size fromSize, Data *&to, Size &toSize)
|
||||
{
|
||||
if (!clearStream(Super::getExecutor(), Super::getLevel()))
|
||||
return false;
|
||||
|
||||
return Super::operate(from, fromSize, to, toSize);
|
||||
}
|
||||
} ;
|
||||
|
||||
void *getPoolStream(int level);
|
||||
void putPoolStream(int level, void *);
|
||||
|
||||
template<typename T>
|
||||
struct MemoryPool : Chain<T>
|
||||
{
|
||||
using Super = Chain<T>;
|
||||
|
||||
template<typename ... Args>
|
||||
MemoryPool(Args&& ... args) :
|
||||
Super(std::forward<Args>(args)...)
|
||||
{
|
||||
}
|
||||
|
||||
bool operate(const Data *from, Size fromSize, Data *&to, Size &toSize)
|
||||
{
|
||||
auto l = Super::getLevel();
|
||||
auto s = getPoolStream(l);
|
||||
if (!s)
|
||||
s = Super::allocateStream();
|
||||
|
||||
Super::setExecutor(s);
|
||||
auto result = Super::operate(from, fromSize, to, toSize);
|
||||
|
||||
Super::setExecutor(nullptr);
|
||||
|
||||
putPoolStream(l, s);
|
||||
return result;
|
||||
}
|
||||
} ;
|
||||
|
||||
bool setDict(void *p, int level, char *dict, size_t size);
|
||||
bool getDict(void *p, int level, char *dict, size_t size);
|
||||
|
||||
template<typename T>
|
||||
struct MiniDict : Chain<T>
|
||||
{
|
||||
using Super = Chain<T>;
|
||||
|
||||
static constexpr size_t DictSize = 256;
|
||||
using Dict = char[DictSize];
|
||||
Dict dict;
|
||||
|
||||
template<typename ... Args>
|
||||
MiniDict(Args&& ... args) :
|
||||
Super(std::forward<Args>(args)...)
|
||||
{
|
||||
memset(dict, 0, sizeof(dict));
|
||||
}
|
||||
|
||||
bool operate(const Data *from, Size fromSize, Data *&to, Size &toSize)
|
||||
{
|
||||
if (!setDict(Super::getExecutor(), Super::getLevel(), dict, DictSize))
|
||||
return false;
|
||||
|
||||
auto result = Super::operate(from, fromSize, to, toSize);
|
||||
|
||||
if (!getDict(Super::getExecutor(), Super::getLevel(), dict, DictSize))
|
||||
return false;
|
||||
|
||||
return result;
|
||||
}
|
||||
} ;
|
||||
|
||||
using StandardCompressor = MemoryPool<Clear<Compressor>>;
|
||||
using StandardDecompressor = MemoryPool<Clear<Decompressor>>;
|
||||
|
||||
} // namespace
|
||||
|
||||
#include "Compression.inl"
|
||||
82
tjp/core/zip/_delete/Compression.inl
Executable file
82
tjp/core/zip/_delete/Compression.inl
Executable file
@@ -0,0 +1,82 @@
|
||||
// TJP COPYRIGHT HEADER
|
||||
|
||||
|
||||
#pragma once
|
||||
|
||||
namespace tjp::core::zip {
|
||||
|
||||
inline
|
||||
bool CompressorOneShot::enabled()
|
||||
{
|
||||
return level > 0;
|
||||
}
|
||||
|
||||
inline
|
||||
bool Compressor::enabled()
|
||||
{
|
||||
return level > 0;
|
||||
}
|
||||
|
||||
inline
|
||||
char CompressorOneShot::getID()
|
||||
{
|
||||
return 1;
|
||||
}
|
||||
|
||||
inline
|
||||
char DecompressorOneShot::getID()
|
||||
{
|
||||
return 1;
|
||||
}
|
||||
|
||||
inline
|
||||
char Compressor::getID()
|
||||
{
|
||||
return 2;
|
||||
}
|
||||
|
||||
inline
|
||||
int Compressor::getLevel()
|
||||
{
|
||||
return level;
|
||||
}
|
||||
|
||||
inline
|
||||
void Compressor::setExecutor(void *i_)
|
||||
{
|
||||
i = i_;
|
||||
}
|
||||
|
||||
inline
|
||||
void *Compressor::getExecutor()
|
||||
{
|
||||
return i;
|
||||
}
|
||||
|
||||
|
||||
inline
|
||||
char Decompressor::getID()
|
||||
{
|
||||
return 2;
|
||||
}
|
||||
|
||||
inline
|
||||
void Decompressor::setExecutor(void *i_)
|
||||
{
|
||||
i = i_;
|
||||
}
|
||||
|
||||
inline
|
||||
void *Decompressor::getExecutor()
|
||||
{
|
||||
return i;
|
||||
}
|
||||
|
||||
inline
|
||||
int Decompressor::getLevel()
|
||||
{
|
||||
return -1;
|
||||
}
|
||||
|
||||
|
||||
} // namespace
|
||||
165
tjp/core/zip/_delete/_tests/Compression.cpp
Normal file
165
tjp/core/zip/_delete/_tests/Compression.cpp
Normal file
@@ -0,0 +1,165 @@
|
||||
// TJP COPYRIGHT HEADER
|
||||
|
||||
#include <tjp/core/zip/_delete/Compression.hpp>
|
||||
|
||||
#include <tjp/core/testing/catch.hpp>
|
||||
#include <tjp/core/containers/Vector.hpp>
|
||||
|
||||
#include <tjp/core/random/Random.h>
|
||||
#include <tjp/core/testing/NO_WHEN.h>
|
||||
|
||||
#include <tjp/core/log/Log.h>
|
||||
#include <tjp/core/log/LogOf.h>
|
||||
|
||||
namespace tjp::core::zip {
|
||||
|
||||
SCENARIO("zip::compression")
|
||||
{
|
||||
GIVEN("CompressorOneShot")
|
||||
{
|
||||
Vector<char> source, compressed, uncompressed;
|
||||
source.resize(90);
|
||||
compressed.resize(100);
|
||||
uncompressed.resize(100,1);
|
||||
|
||||
CompressorOneShot compressor(5);
|
||||
DecompressorOneShot decompressor;
|
||||
|
||||
auto compressedSize = compressed.size();
|
||||
auto compressedData = compressed.data();
|
||||
auto didCompress = compressor.operate(
|
||||
source.data(), source.size(),
|
||||
compressedData, compressedSize
|
||||
);
|
||||
REQUIRE(didCompress);
|
||||
|
||||
auto uncompressedSize = uncompressed.size();
|
||||
auto uncompressedData = uncompressed.data();
|
||||
auto didDecompress = decompressor.operate(
|
||||
compressed.data(), compressedSize,
|
||||
uncompressedData, uncompressedSize
|
||||
);
|
||||
REQUIRE(didDecompress);
|
||||
uncompressed.resize(uncompressedSize);
|
||||
|
||||
auto same = source == uncompressed;
|
||||
REQUIRE(uncompressedSize == source.size());
|
||||
REQUIRE(same);
|
||||
}
|
||||
|
||||
GIVEN("RetainMemory")
|
||||
{
|
||||
Vector<char> source, compressed, uncompressed;
|
||||
source.resize(90);
|
||||
compressed.resize(100);
|
||||
uncompressed.resize(100,1);
|
||||
|
||||
RetainMemory<Compressor> compressor(5);
|
||||
RetainMemory<Decompressor> decompressor;
|
||||
|
||||
auto compressedSize = compressed.size();
|
||||
auto compressedData = compressed.data();
|
||||
auto didCompress = compressor.operate(
|
||||
source.data(), source.size(),
|
||||
compressedData, compressedSize
|
||||
);
|
||||
REQUIRE(didCompress);
|
||||
|
||||
auto uncompressedSize = uncompressed.size();
|
||||
auto uncompressedData = uncompressed.data();
|
||||
auto didDecompress = decompressor.operate(
|
||||
compressed.data(), compressedSize,
|
||||
uncompressedData, uncompressedSize
|
||||
);
|
||||
REQUIRE(didDecompress);
|
||||
uncompressed.resize(uncompressedSize);
|
||||
|
||||
auto same = source == uncompressed;
|
||||
REQUIRE(uncompressedSize == source.size());
|
||||
REQUIRE(same);
|
||||
}
|
||||
|
||||
GIVEN("MemoryPool")
|
||||
{
|
||||
Vector<char> source, compressed, uncompressed;
|
||||
source.resize(90);
|
||||
compressed.resize(100);
|
||||
|
||||
for (auto i=0; i<16; ++i)
|
||||
{
|
||||
uncompressed.clear();
|
||||
uncompressed.resize(100,1);
|
||||
|
||||
MemoryPool<Clear<Compressor>> compressor((i % 4) + 1);
|
||||
MemoryPool<Clear<Decompressor>> decompressor;
|
||||
|
||||
auto compressedSize = compressed.size();
|
||||
auto compressedData = compressed.data();
|
||||
auto didCompress = compressor.operate(
|
||||
source.data(), source.size(),
|
||||
compressedData, compressedSize
|
||||
);
|
||||
REQUIRE(didCompress);
|
||||
|
||||
auto uncompressedSize = uncompressed.size();
|
||||
auto uncompressedData = uncompressed.data();
|
||||
auto didDecompress = decompressor.operate(
|
||||
compressed.data(), compressedSize,
|
||||
uncompressedData, uncompressedSize
|
||||
);
|
||||
REQUIRE(didDecompress);
|
||||
uncompressed.resize(uncompressedSize);
|
||||
|
||||
auto same = source == uncompressed;
|
||||
REQUIRE(uncompressedSize == source.size());
|
||||
REQUIRE(same);
|
||||
}
|
||||
}
|
||||
|
||||
NO_GIVEN("MiniDict")
|
||||
{
|
||||
Vector<char> source, compressed, uncompressed;
|
||||
source.resize(90);
|
||||
compressed.resize(100);
|
||||
|
||||
for (auto i=0; i<90; ++i)
|
||||
source[i] = i%13;
|
||||
|
||||
MemoryPool<Clear<MiniDict<Compressor>>> compressor(5);
|
||||
MemoryPool<Clear<MiniDict<Decompressor>>> decompressor;
|
||||
int lastCompression = 1000000;
|
||||
|
||||
for (auto i=0; i<16; ++i)
|
||||
{
|
||||
uncompressed.clear();
|
||||
uncompressed.resize(100,1);
|
||||
|
||||
auto compressedSize = compressed.size();
|
||||
auto compressedData = compressed.data();
|
||||
auto didCompress = compressor.operate(
|
||||
source.data(), source.size(),
|
||||
compressedData, compressedSize
|
||||
);
|
||||
REQUIRE(didCompress);
|
||||
sLogTest("testing", logVar(compressedSize) << logVar(lastCompression));
|
||||
|
||||
REQUIRE(compressedSize < lastCompression);
|
||||
lastCompression = compressedSize;
|
||||
|
||||
auto uncompressedSize = uncompressed.size();
|
||||
auto uncompressedData = uncompressed.data();
|
||||
auto didDecompress = decompressor.operate(
|
||||
compressed.data(), compressedSize,
|
||||
uncompressedData, uncompressedSize
|
||||
);
|
||||
REQUIRE(didDecompress);
|
||||
uncompressed.resize(uncompressedSize);
|
||||
|
||||
auto same = source == uncompressed;
|
||||
REQUIRE(uncompressedSize == source.size());
|
||||
REQUIRE(same);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
} // namespace
|
||||
Reference in New Issue
Block a user