forked from p7zip-project/p7zip
-
Notifications
You must be signed in to change notification settings - Fork 2
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
- Loading branch information
1 parent
081bc28
commit ca81051
Showing
7 changed files
with
437 additions
and
3 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,294 @@ | ||
// Lzma2Encoder.cpp | ||
|
||
#include "StdAfx.h" | ||
|
||
#include "../../../C/Alloc.h" | ||
|
||
#include "../Common/CWrappers.h" | ||
#include "../Common/StreamUtils.h" | ||
|
||
#include "Lzma2Encoder.h" | ||
#include "FastLzma2Encoder.h" | ||
#include "../../../Codecs/fast-lzma2/fl2_errors.h" | ||
|
||
#ifndef max | ||
#define max(a, b) (((a) > (b)) ? (a) : (b)) | ||
#endif | ||
|
||
#ifndef min | ||
#define min(a, b) (((a) < (b)) ? (a) : (b)) | ||
#endif | ||
|
||
namespace NCompress { | ||
|
||
namespace NLzma { | ||
|
||
HRESULT SetLzmaProp(PROPID propID, const PROPVARIANT &prop, CLzmaEncProps &ep); | ||
|
||
} | ||
|
||
namespace NLzma2 { | ||
|
||
HRESULT SetLzma2Prop(PROPID propID, const PROPVARIANT &prop, CLzma2EncProps &lzma2Props); | ||
|
||
static HRESULT TranslateError(size_t res) | ||
{ | ||
if (FL2_getErrorCode(res) == FL2_error_memory_allocation) | ||
return E_OUTOFMEMORY; | ||
return S_FALSE; | ||
} | ||
|
||
#define CHECK_S(f_) do { \ | ||
size_t r_ = f_; \ | ||
if (FL2_isError(r_)) \ | ||
return TranslateError(r_); \ | ||
} while (false) | ||
|
||
#define CHECK_H(f_) do { \ | ||
HRESULT r_ = f_; \ | ||
if (r_ != S_OK) \ | ||
return r_; \ | ||
} while (false) | ||
|
||
#define CHECK_P(f) if (FL2_isError(f)) return E_INVALIDARG; /* check and convert error code */ | ||
|
||
#define MIN_BLOCK_SIZE (1U << 20) | ||
#define MAX_BLOCK_SIZE (1U << 28) | ||
|
||
CFastEncoder::FastLzma2::FastLzma2() | ||
: fcs(NULL), | ||
dict_pos(0) | ||
{ | ||
} | ||
|
||
CFastEncoder::FastLzma2::~FastLzma2() | ||
{ | ||
FL2_freeCCtx(fcs); | ||
} | ||
|
||
HRESULT CFastEncoder::FastLzma2::SetCoderProperties(const PROPID *propIDs, const PROPVARIANT *coderProps, UInt32 numProps) | ||
{ | ||
CLzma2EncProps lzma2Props; | ||
Lzma2EncProps_Init(&lzma2Props); | ||
|
||
for (UInt32 i = 0; i < numProps; i++) | ||
{ | ||
RINOK(SetLzma2Prop(propIDs[i], coderProps[i], lzma2Props)); | ||
} | ||
if (fcs == NULL) { | ||
fcs = FL2_createCStreamMt(lzma2Props.numTotalThreads, 1); | ||
if (fcs == NULL) | ||
return E_OUTOFMEMORY; | ||
} | ||
if (lzma2Props.lzmaProps.algo > 2) { | ||
if (lzma2Props.lzmaProps.algo > 3) | ||
return E_INVALIDARG; | ||
lzma2Props.lzmaProps.algo = 2; | ||
FL2_CCtx_setParameter(fcs, FL2_p_highCompression, 1); | ||
FL2_CCtx_setParameter(fcs, FL2_p_compressionLevel, lzma2Props.lzmaProps.level); | ||
} | ||
else { | ||
FL2_CCtx_setParameter(fcs, FL2_p_compressionLevel, lzma2Props.lzmaProps.level); | ||
} | ||
size_t dictSize = lzma2Props.lzmaProps.dictSize; | ||
if (!dictSize) { | ||
dictSize = (UInt32)FL2_CCtx_getParameter(fcs, FL2_p_dictionarySize); | ||
} | ||
UInt64 reduceSize = lzma2Props.lzmaProps.reduceSize; | ||
reduceSize += (reduceSize < (UInt64)-1); /* prevent extra buffer shift after read */ | ||
dictSize = (UInt32)min(dictSize, reduceSize); | ||
dictSize = max(dictSize, FL2_DICTSIZE_MIN); | ||
CHECK_P(FL2_CCtx_setParameter(fcs, FL2_p_dictionarySize, dictSize)); | ||
if (lzma2Props.lzmaProps.algo >= 0) { | ||
CHECK_P(FL2_CCtx_setParameter(fcs, FL2_p_strategy, (unsigned)lzma2Props.lzmaProps.algo)); | ||
} | ||
if (lzma2Props.lzmaProps.fb > 0) | ||
CHECK_P(FL2_CCtx_setParameter(fcs, FL2_p_fastLength, lzma2Props.lzmaProps.fb)); | ||
if (lzma2Props.lzmaProps.mc > 0) | ||
CHECK_P(FL2_CCtx_setParameter(fcs, FL2_p_hybridCycles, lzma2Props.lzmaProps.mc)); | ||
if (lzma2Props.lzmaProps.lc >= 0) | ||
CHECK_P(FL2_CCtx_setParameter(fcs, FL2_p_literalCtxBits, lzma2Props.lzmaProps.lc)); | ||
if (lzma2Props.lzmaProps.lp >= 0) | ||
CHECK_P(FL2_CCtx_setParameter(fcs, FL2_p_literalPosBits, lzma2Props.lzmaProps.lp)); | ||
if (lzma2Props.lzmaProps.pb >= 0) | ||
CHECK_P(FL2_CCtx_setParameter(fcs, FL2_p_posBits, lzma2Props.lzmaProps.pb)); | ||
if (lzma2Props.blockSize == 0) | ||
lzma2Props.blockSize = min(max(MIN_BLOCK_SIZE, dictSize * 4U), MAX_BLOCK_SIZE); | ||
else if (lzma2Props.blockSize == LZMA2_ENC_PROPS__BLOCK_SIZE__SOLID) | ||
lzma2Props.blockSize = 0; | ||
unsigned r = 0; | ||
if (lzma2Props.blockSize != 0) { | ||
r = 1; | ||
// Do not exceed the block size. TODO: the lib should support setting a value instead of a multiplier. | ||
while (r < FL2_RESET_INTERVAL_MAX && (r + 1) * (UInt64)dictSize <= lzma2Props.blockSize) | ||
++r; | ||
} | ||
CHECK_P(FL2_CCtx_setParameter(fcs, FL2_p_resetInterval, r)); | ||
FL2_CCtx_setParameter(fcs, FL2_p_omitProperties, 1); | ||
FL2_setCStreamTimeout(fcs, 500); | ||
return S_OK; | ||
} | ||
|
||
size_t CFastEncoder::FastLzma2::GetDictSize() const | ||
{ | ||
return FL2_CCtx_getParameter(fcs, FL2_p_dictionarySize); | ||
} | ||
|
||
HRESULT CFastEncoder::FastLzma2::Begin() | ||
{ | ||
CHECK_S(FL2_initCStream(fcs, 0)); | ||
CHECK_S(FL2_getDictionaryBuffer(fcs, &dict)); | ||
dict_pos = 0; | ||
return S_OK; | ||
} | ||
|
||
BYTE* CFastEncoder::FastLzma2::GetAvailableBuffer(unsigned long& size) | ||
{ | ||
size = static_cast<unsigned long>(dict.size - dict_pos); | ||
return reinterpret_cast<BYTE*>(dict.dst) + dict_pos; | ||
} | ||
|
||
HRESULT CFastEncoder::FastLzma2::WaitAndReport(size_t& res, ICompressProgressInfo *progress) | ||
{ | ||
while (FL2_isTimedOut(res)) { | ||
if (!UpdateProgress(progress)) | ||
return S_FALSE; | ||
res = FL2_waitCStream(fcs); | ||
} | ||
CHECK_S(res); | ||
return S_OK; | ||
} | ||
|
||
HRESULT CFastEncoder::FastLzma2::AddByteCount(size_t count, ISequentialOutStream *outStream, ICompressProgressInfo *progress) | ||
{ | ||
dict_pos += count; | ||
if (dict_pos == dict.size) { | ||
size_t res = FL2_updateDictionary(fcs, dict_pos); | ||
CHECK_H(WaitAndReport(res, progress)); | ||
if (res != 0) | ||
CHECK_H(WriteBuffers(outStream)); | ||
res = FL2_getDictionaryBuffer(fcs, &dict); | ||
while (FL2_isTimedOut(res)) { | ||
if (!UpdateProgress(progress)) | ||
return S_FALSE; | ||
res = FL2_getDictionaryBuffer(fcs, &dict); | ||
} | ||
CHECK_S(res); | ||
dict_pos = 0; | ||
} | ||
if (!UpdateProgress(progress)) | ||
return S_FALSE; | ||
return S_OK; | ||
} | ||
|
||
bool CFastEncoder::FastLzma2::UpdateProgress(ICompressProgressInfo *progress) | ||
{ | ||
if (progress) { | ||
UInt64 outProcessed; | ||
UInt64 inProcessed = FL2_getCStreamProgress(fcs, &outProcessed); | ||
HRESULT err = progress->SetRatioInfo(&inProcessed, &outProcessed); | ||
if (err != S_OK) { | ||
FL2_cancelCStream(fcs); | ||
return false; | ||
} | ||
} | ||
return true; | ||
} | ||
|
||
HRESULT CFastEncoder::FastLzma2::WriteBuffers(ISequentialOutStream *outStream) | ||
{ | ||
size_t csize; | ||
for (;;) { | ||
FL2_cBuffer cbuf; | ||
do { | ||
csize = FL2_getNextCompressedBuffer(fcs, &cbuf); | ||
} while (FL2_isTimedOut(csize)); | ||
CHECK_S(csize); | ||
if (csize == 0) | ||
break; | ||
HRESULT err = WriteStream(outStream, cbuf.src, cbuf.size); | ||
if (err != S_OK) | ||
return err; | ||
} | ||
return S_OK; | ||
} | ||
|
||
HRESULT CFastEncoder::FastLzma2::End(ISequentialOutStream *outStream, ICompressProgressInfo *progress) | ||
{ | ||
if (dict_pos) { | ||
size_t res = FL2_updateDictionary(fcs, dict_pos); | ||
CHECK_H(WaitAndReport(res, progress)); | ||
} | ||
|
||
size_t res = FL2_endStream(fcs, nullptr); | ||
CHECK_H(WaitAndReport(res, progress)); | ||
while (res) { | ||
CHECK_H(WriteBuffers(outStream)); | ||
res = FL2_endStream(fcs, nullptr); | ||
CHECK_H(WaitAndReport(res, progress)); | ||
} | ||
return S_OK; | ||
} | ||
|
||
void CFastEncoder::FastLzma2::Cancel() | ||
{ | ||
FL2_cancelCStream(fcs); | ||
} | ||
|
||
CFastEncoder::CFastEncoder() | ||
{ | ||
} | ||
|
||
CFastEncoder::~CFastEncoder() | ||
{ | ||
} | ||
|
||
|
||
STDMETHODIMP CFastEncoder::SetCoderProperties(const PROPID *propIDs, | ||
const PROPVARIANT *coderProps, UInt32 numProps) | ||
{ | ||
return _encoder.SetCoderProperties(propIDs, coderProps, numProps); | ||
} | ||
|
||
|
||
#define LZMA2_DIC_SIZE_FROM_PROP(p) (((UInt32)2 | ((p) & 1)) << ((p) / 2 + 11)) | ||
|
||
STDMETHODIMP CFastEncoder::WriteCoderProperties(ISequentialOutStream *outStream) | ||
{ | ||
Byte prop; | ||
unsigned i; | ||
size_t dictSize = _encoder.GetDictSize(); | ||
for (i = 0; i < 40; i++) | ||
if (dictSize <= LZMA2_DIC_SIZE_FROM_PROP(i)) | ||
break; | ||
prop = (Byte)i; | ||
return WriteStream(outStream, &prop, 1); | ||
} | ||
|
||
|
||
STDMETHODIMP CFastEncoder::Code(ISequentialInStream *inStream, ISequentialOutStream *outStream, | ||
const UInt64 * /* inSize */, const UInt64 * /* outSize */, ICompressProgressInfo *progress) | ||
{ | ||
CHECK_H(_encoder.Begin()); | ||
size_t inSize; | ||
unsigned long dSize; | ||
do | ||
{ | ||
BYTE* dict = _encoder.GetAvailableBuffer(dSize); | ||
|
||
inSize = dSize; | ||
HRESULT err = ReadStream(inStream, dict, &inSize); | ||
if (err != S_OK) { | ||
_encoder.Cancel(); | ||
return err; | ||
} | ||
CHECK_H(_encoder.AddByteCount(inSize, outStream, progress)); | ||
|
||
} while (inSize == dSize); | ||
|
||
CHECK_H(_encoder.End(outStream, progress)); | ||
|
||
return S_OK; | ||
} | ||
|
||
}} |
Oops, something went wrong.