2003-11-24 00:08:58 +00:00
|
|
|
#ifndef __CLZMA_H__
|
|
|
|
#define __CLZMA_H__
|
|
|
|
|
|
|
|
#include "compressor.h"
|
|
|
|
#include "7zip/7zip/IStream.h"
|
|
|
|
#include "7zip/7zip/Compress/LZMA/LZMAEncoder.h"
|
|
|
|
#include "7zip/Common/MyCom.h"
|
|
|
|
|
2003-11-26 20:27:36 +00:00
|
|
|
// implemented in build.cpp - simply calls CompressReal
|
|
|
|
DWORD WINAPI lzmaCompressThread(LPVOID lpParameter);
|
2003-11-24 00:08:58 +00:00
|
|
|
|
2003-11-26 20:27:36 +00:00
|
|
|
class CLZMA:
|
|
|
|
public ICompressor,
|
2003-11-24 00:08:58 +00:00
|
|
|
public ISequentialInStream,
|
|
|
|
public ISequentialOutStream,
|
2003-11-26 20:27:36 +00:00
|
|
|
public CMyUnknownImp
|
2003-11-24 00:08:58 +00:00
|
|
|
{
|
2003-11-26 20:27:36 +00:00
|
|
|
private:
|
|
|
|
NCompress::NLZMA::CEncoder *_encoder;
|
2003-11-24 00:08:58 +00:00
|
|
|
|
2003-11-26 20:27:36 +00:00
|
|
|
HANDLE hCompressionThread;
|
|
|
|
|
|
|
|
BYTE *next_in; /* next input byte */
|
|
|
|
UINT avail_in; /* number of bytes available at next_in */
|
|
|
|
|
|
|
|
BYTE *next_out; /* next output byte should be put there */
|
|
|
|
UINT avail_out; /* remaining free space at next_out */
|
|
|
|
|
|
|
|
int res;
|
|
|
|
|
|
|
|
BOOL finish;
|
|
|
|
|
|
|
|
CRITICAL_SECTION cs;
|
|
|
|
BOOL nt_locked; /* nsis thread locked */
|
|
|
|
BOOL ct_locked; /* compression thread locked */
|
|
|
|
BOOL compressor_finished;
|
2003-11-24 00:08:58 +00:00
|
|
|
|
|
|
|
public:
|
2003-11-26 20:27:36 +00:00
|
|
|
MY_UNKNOWN_IMP
|
|
|
|
|
|
|
|
CLZMA(): _encoder(NULL)
|
2003-11-24 00:08:58 +00:00
|
|
|
{
|
|
|
|
_encoder = new NCompress::NLZMA::CEncoder();
|
|
|
|
_encoder->SetWriteEndMarkerMode(true);
|
2003-11-26 20:27:36 +00:00
|
|
|
hCompressionThread = NULL;
|
|
|
|
compressor_finished = FALSE;
|
|
|
|
finish = FALSE;
|
2004-01-06 00:53:12 +00:00
|
|
|
ct_locked = TRUE;
|
2003-11-26 20:27:36 +00:00
|
|
|
End();
|
2003-11-30 16:02:48 +00:00
|
|
|
InitializeCriticalSection(&cs);
|
2003-11-24 00:08:58 +00:00
|
|
|
}
|
2003-11-26 20:27:36 +00:00
|
|
|
|
2004-03-12 20:43:54 +00:00
|
|
|
virtual ~CLZMA()
|
2003-11-24 00:08:58 +00:00
|
|
|
{
|
2003-11-26 20:27:36 +00:00
|
|
|
End();
|
2003-11-30 16:02:48 +00:00
|
|
|
DeleteCriticalSection(&cs);
|
2003-11-26 20:27:36 +00:00
|
|
|
if (_encoder)
|
2003-11-24 00:08:58 +00:00
|
|
|
{
|
|
|
|
delete _encoder;
|
2003-11-26 20:27:36 +00:00
|
|
|
_encoder = NULL;
|
2003-11-24 00:08:58 +00:00
|
|
|
}
|
|
|
|
}
|
2003-11-26 20:27:36 +00:00
|
|
|
|
|
|
|
int Init(int level, UINT32 dicSize)
|
2003-11-24 00:08:58 +00:00
|
|
|
{
|
2003-11-26 20:27:36 +00:00
|
|
|
End();
|
|
|
|
|
|
|
|
nt_locked = TRUE;
|
|
|
|
ct_locked = FALSE;
|
2003-11-24 00:08:58 +00:00
|
|
|
|
2003-11-26 20:27:36 +00:00
|
|
|
compressor_finished = FALSE;
|
|
|
|
finish = FALSE;
|
|
|
|
|
|
|
|
res = C_OK;
|
|
|
|
|
|
|
|
PROPID propdIDs [] =
|
2003-11-24 00:08:58 +00:00
|
|
|
{
|
|
|
|
NCoderPropID::kAlgorithm,
|
|
|
|
NCoderPropID::kDictionarySize,
|
|
|
|
NCoderPropID::kNumFastBytes
|
|
|
|
};
|
2004-03-12 20:43:54 +00:00
|
|
|
const int kNumProps = sizeof(propdIDs) / sizeof(propdIDs[0]);
|
2003-11-24 00:08:58 +00:00
|
|
|
PROPVARIANT props[kNumProps];
|
|
|
|
// NCoderPropID::kAlgorithm
|
|
|
|
props[0].vt = VT_UI4;
|
|
|
|
props[0].ulVal = 2;
|
|
|
|
// NCoderPropID::kDictionarySize
|
|
|
|
props[1].vt = VT_UI4;
|
|
|
|
props[1].ulVal = dicSize;
|
|
|
|
// NCoderPropID::kNumFastBytes
|
|
|
|
props[2].vt = VT_UI4;
|
|
|
|
props[2].ulVal = 64;
|
|
|
|
if (_encoder->SetCoderProperties(propdIDs, props, kNumProps) != 0)
|
|
|
|
return -1;
|
2003-11-26 20:27:36 +00:00
|
|
|
return _encoder->SetStreams(this, this, 0, 0);
|
2003-11-24 00:08:58 +00:00
|
|
|
}
|
|
|
|
|
2003-11-26 20:27:36 +00:00
|
|
|
int Init(int level)
|
2003-11-24 00:08:58 +00:00
|
|
|
{
|
|
|
|
// default dictionary size is 8MB
|
2003-11-26 20:27:36 +00:00
|
|
|
return Init(level, 8 << 20);
|
2003-11-24 00:08:58 +00:00
|
|
|
}
|
2003-11-26 20:27:36 +00:00
|
|
|
|
2003-11-24 00:08:58 +00:00
|
|
|
int End()
|
|
|
|
{
|
2004-01-06 00:53:12 +00:00
|
|
|
if (!compressor_finished && !ct_locked)
|
|
|
|
{
|
|
|
|
// kill compression thread
|
|
|
|
avail_in = 0;
|
|
|
|
avail_out = 0;
|
|
|
|
finish = TRUE;
|
|
|
|
LeaveCriticalSection(&cs);
|
|
|
|
while (!ct_locked)
|
|
|
|
Sleep(0);
|
|
|
|
nt_locked = FALSE;
|
|
|
|
EnterCriticalSection(&cs);
|
|
|
|
while (ct_locked)
|
|
|
|
Sleep(0);
|
|
|
|
nt_locked = TRUE;
|
|
|
|
LeaveCriticalSection(&cs);
|
|
|
|
}
|
2003-11-26 20:27:36 +00:00
|
|
|
if (hCompressionThread)
|
|
|
|
{
|
|
|
|
CloseHandle(hCompressionThread);
|
|
|
|
hCompressionThread = NULL;
|
|
|
|
}
|
|
|
|
SetNextOut(NULL, 0);
|
|
|
|
SetNextIn(NULL, 0);
|
2003-11-24 00:08:58 +00:00
|
|
|
return C_OK;
|
|
|
|
}
|
2003-11-26 20:27:36 +00:00
|
|
|
|
|
|
|
int CompressReal()
|
2003-11-24 00:08:58 +00:00
|
|
|
{
|
2003-11-26 20:27:36 +00:00
|
|
|
EnterCriticalSection(&cs);
|
|
|
|
ct_locked = TRUE;
|
|
|
|
|
|
|
|
while (nt_locked)
|
|
|
|
Sleep(0);
|
|
|
|
|
2003-11-30 16:02:48 +00:00
|
|
|
try
|
2003-11-26 20:27:36 +00:00
|
|
|
{
|
2003-11-30 16:02:48 +00:00
|
|
|
if (_encoder->WriteCoderProperties(this) == S_OK)
|
2003-11-26 20:27:36 +00:00
|
|
|
{
|
2003-11-30 16:02:48 +00:00
|
|
|
while (true)
|
2003-11-26 20:27:36 +00:00
|
|
|
{
|
2003-11-30 16:02:48 +00:00
|
|
|
UINT64 inSize, outSize;
|
|
|
|
INT32 finished;
|
|
|
|
if (_encoder->CodeOneBlock(&inSize, &outSize, &finished))
|
|
|
|
{
|
|
|
|
res = -2;
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
if (finished)
|
|
|
|
{
|
|
|
|
res = C_OK;
|
|
|
|
break;
|
|
|
|
}
|
2003-11-26 20:27:36 +00:00
|
|
|
}
|
|
|
|
}
|
2003-11-30 16:02:48 +00:00
|
|
|
else
|
|
|
|
{
|
|
|
|
res = -2;
|
|
|
|
}
|
2003-11-26 20:27:36 +00:00
|
|
|
}
|
2003-11-30 16:02:48 +00:00
|
|
|
catch (...)
|
2003-11-24 00:08:58 +00:00
|
|
|
{
|
2003-11-30 16:02:48 +00:00
|
|
|
res = -3;
|
2003-11-24 00:08:58 +00:00
|
|
|
}
|
2003-11-26 20:27:36 +00:00
|
|
|
|
|
|
|
compressor_finished = TRUE;
|
|
|
|
LeaveCriticalSection(&cs);
|
|
|
|
ct_locked = FALSE;
|
|
|
|
return C_OK;
|
|
|
|
}
|
|
|
|
|
|
|
|
int Compress(BOOL flush)
|
|
|
|
{
|
|
|
|
if (compressor_finished)
|
2004-01-05 14:22:14 +00:00
|
|
|
{
|
|
|
|
// act like zlib when it comes to stream ending
|
|
|
|
if (flush)
|
|
|
|
return C_OK;
|
|
|
|
else
|
|
|
|
return -1;
|
|
|
|
}
|
2003-11-26 20:27:36 +00:00
|
|
|
|
2004-01-06 00:53:12 +00:00
|
|
|
finish = flush;
|
|
|
|
|
2003-11-26 20:27:36 +00:00
|
|
|
if (!hCompressionThread)
|
2003-11-24 00:08:58 +00:00
|
|
|
{
|
2003-11-26 20:27:36 +00:00
|
|
|
DWORD dwThreadId;
|
2004-01-06 00:53:12 +00:00
|
|
|
|
2003-11-26 20:27:36 +00:00
|
|
|
hCompressionThread = CreateThread(0, 0, lzmaCompressThread, (LPVOID) this, 0, &dwThreadId);
|
|
|
|
if (!hCompressionThread)
|
|
|
|
return -2;
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
LeaveCriticalSection(&cs);
|
|
|
|
}
|
|
|
|
|
|
|
|
while (!ct_locked)
|
|
|
|
Sleep(0);
|
|
|
|
|
|
|
|
nt_locked = FALSE;
|
|
|
|
|
|
|
|
EnterCriticalSection(&cs);
|
|
|
|
nt_locked = TRUE;
|
|
|
|
|
2004-01-06 00:53:12 +00:00
|
|
|
while (ct_locked)
|
|
|
|
Sleep(0);
|
|
|
|
|
2003-11-30 16:02:48 +00:00
|
|
|
if (compressor_finished)
|
2003-11-26 20:27:36 +00:00
|
|
|
{
|
2003-11-30 16:02:48 +00:00
|
|
|
LeaveCriticalSection(&cs);
|
|
|
|
return res;
|
2003-11-24 00:08:58 +00:00
|
|
|
}
|
2003-11-26 20:27:36 +00:00
|
|
|
|
2003-11-24 00:08:58 +00:00
|
|
|
return C_OK;
|
|
|
|
}
|
2003-11-26 20:27:36 +00:00
|
|
|
|
|
|
|
void GetMoreIO()
|
|
|
|
{
|
|
|
|
LeaveCriticalSection(&cs);
|
|
|
|
while (!nt_locked)
|
|
|
|
Sleep(0);
|
|
|
|
|
|
|
|
ct_locked = FALSE;
|
|
|
|
|
|
|
|
EnterCriticalSection(&cs);
|
|
|
|
ct_locked = TRUE;
|
|
|
|
|
|
|
|
while (nt_locked)
|
|
|
|
Sleep(0);
|
|
|
|
}
|
|
|
|
|
|
|
|
STDMETHOD(Read)(void *data, UINT32 size, UINT32 *processedSize)
|
2003-11-24 00:08:58 +00:00
|
|
|
{
|
2003-11-26 20:27:36 +00:00
|
|
|
return ReadPart(data, size, processedSize);
|
2003-11-24 00:08:58 +00:00
|
|
|
}
|
2003-11-26 20:27:36 +00:00
|
|
|
|
|
|
|
STDMETHOD(ReadPart)(void *data, UINT32 size, UINT32 *processedSize)
|
2003-11-24 00:08:58 +00:00
|
|
|
{
|
2003-11-26 20:27:36 +00:00
|
|
|
if (processedSize)
|
|
|
|
*processedSize = 0;
|
|
|
|
while (size)
|
|
|
|
{
|
|
|
|
if (!avail_in)
|
|
|
|
{
|
|
|
|
if (finish)
|
|
|
|
{
|
|
|
|
return S_OK;
|
|
|
|
}
|
|
|
|
GetMoreIO();
|
|
|
|
if (!avail_in && finish)
|
|
|
|
{
|
|
|
|
return S_OK;
|
|
|
|
}
|
|
|
|
if (!avail_in)
|
|
|
|
return E_ABORT;
|
|
|
|
}
|
|
|
|
UINT32 l = min(size, avail_in);
|
|
|
|
memcpy(data, next_in, l);
|
|
|
|
avail_in -= l;
|
|
|
|
size -= l;
|
|
|
|
next_in += l;
|
|
|
|
data = LPBYTE(data) + l;
|
|
|
|
if (processedSize)
|
|
|
|
*processedSize += l;
|
|
|
|
}
|
|
|
|
return S_OK;
|
2003-11-24 00:08:58 +00:00
|
|
|
}
|
2003-11-26 20:27:36 +00:00
|
|
|
|
|
|
|
STDMETHOD(Write)(const void *data, UINT32 size, UINT32 *processedSize)
|
2003-11-24 00:08:58 +00:00
|
|
|
{
|
2003-11-26 20:27:36 +00:00
|
|
|
return WritePart(data, size, processedSize);
|
2003-11-24 00:08:58 +00:00
|
|
|
}
|
2003-11-26 20:27:36 +00:00
|
|
|
|
|
|
|
STDMETHOD(WritePart)(const void *data, UINT32 size, UINT32 *processedSize)
|
|
|
|
{
|
|
|
|
if (processedSize)
|
|
|
|
*processedSize = 0;
|
|
|
|
while (size)
|
|
|
|
{
|
|
|
|
if (!avail_out)
|
|
|
|
{
|
|
|
|
GetMoreIO();
|
|
|
|
if (!avail_out)
|
|
|
|
return E_ABORT;
|
|
|
|
}
|
|
|
|
UINT32 l = min(size, avail_out);
|
|
|
|
memcpy(next_out, data, l);
|
|
|
|
avail_out -= l;
|
|
|
|
size -= l;
|
|
|
|
next_out += l;
|
|
|
|
data = LPBYTE(data) + l;
|
|
|
|
if (processedSize)
|
|
|
|
*processedSize += l;
|
|
|
|
}
|
|
|
|
return S_OK;
|
|
|
|
}
|
|
|
|
|
|
|
|
void SetNextIn(char *in, unsigned int size)
|
|
|
|
{
|
|
|
|
next_in = (LPBYTE) in;
|
|
|
|
avail_in = size;
|
|
|
|
}
|
|
|
|
|
|
|
|
void SetNextOut(char *out, unsigned int size)
|
|
|
|
{
|
|
|
|
next_out = (LPBYTE) out;
|
|
|
|
avail_out = size;
|
|
|
|
}
|
|
|
|
|
|
|
|
virtual char *GetNextOut() { return (char *) next_out; }
|
|
|
|
virtual unsigned int GetAvailIn() { return avail_in; }
|
|
|
|
virtual unsigned int GetAvailOut() { return avail_out; }
|
|
|
|
const char *GetName() { return "lzma"; }
|
2003-11-24 00:08:58 +00:00
|
|
|
};
|
|
|
|
|
2004-03-12 20:43:54 +00:00
|
|
|
#endif
|