1// LzmaEncoder.cpp 2 3#include "StdAfx.h" 4 5#include "../../../C/Alloc.h" 6 7#include "../Common/CWrappers.h" 8#include "../Common/StreamUtils.h" 9 10#include "LzmaEncoder.h" 11 12namespace NCompress { 13namespace NLzma { 14 15static void *SzBigAlloc(void *, size_t size) { return BigAlloc(size); } 16static void SzBigFree(void *, void *address) { BigFree(address); } 17static ISzAlloc g_BigAlloc = { SzBigAlloc, SzBigFree }; 18 19static void *SzAlloc(void *, size_t size) { return MyAlloc(size); } 20static void SzFree(void *, void *address) { MyFree(address); } 21static ISzAlloc g_Alloc = { SzAlloc, SzFree }; 22 23CEncoder::CEncoder() 24{ 25 _encoder = 0; 26 _encoder = LzmaEnc_Create(&g_Alloc); 27 if (_encoder == 0) 28 throw 1; 29} 30 31CEncoder::~CEncoder() 32{ 33 if (_encoder != 0) 34 LzmaEnc_Destroy(_encoder, &g_Alloc, &g_BigAlloc); 35} 36 37inline wchar_t GetUpperChar(wchar_t c) 38{ 39 if (c >= 'a' && c <= 'z') 40 c -= 0x20; 41 return c; 42} 43 44static int ParseMatchFinder(const wchar_t *s, int *btMode, int *numHashBytes) 45{ 46 wchar_t c = GetUpperChar(*s++); 47 if (c == L'H') 48 { 49 if (GetUpperChar(*s++) != L'C') 50 return 0; 51 int numHashBytesLoc = (int)(*s++ - L'0'); 52 if (numHashBytesLoc < 4 || numHashBytesLoc > 4) 53 return 0; 54 if (*s++ != 0) 55 return 0; 56 *btMode = 0; 57 *numHashBytes = numHashBytesLoc; 58 return 1; 59 } 60 if (c != L'B') 61 return 0; 62 63 if (GetUpperChar(*s++) != L'T') 64 return 0; 65 int numHashBytesLoc = (int)(*s++ - L'0'); 66 if (numHashBytesLoc < 2 || numHashBytesLoc > 4) 67 return 0; 68 c = GetUpperChar(*s++); 69 if (c != L'\0') 70 return 0; 71 *btMode = 1; 72 *numHashBytes = numHashBytesLoc; 73 return 1; 74} 75 76#define SET_PROP_32(_id_, _dest_) case NCoderPropID::_id_: ep._dest_ = v; break; 77 78HRESULT SetLzmaProp(PROPID propID, const PROPVARIANT &prop, CLzmaEncProps &ep) 79{ 80 if (propID == NCoderPropID::kMatchFinder) 81 { 82 if (prop.vt != VT_BSTR) 83 return E_INVALIDARG; 84 return ParseMatchFinder(prop.bstrVal, &ep.btMode, &ep.numHashBytes) ? S_OK : E_INVALIDARG; 85 } 86 if (propID > NCoderPropID::kReduceSize) 87 return S_OK; 88 if (propID == NCoderPropID::kReduceSize) 89 { 90 if (prop.vt == VT_UI8) 91 ep.reduceSize = prop.uhVal.QuadPart; 92 return S_OK; 93 } 94 if (prop.vt != VT_UI4) 95 return E_INVALIDARG; 96 UInt32 v = prop.ulVal; 97 switch (propID) 98 { 99 case NCoderPropID::kDefaultProp: if (v > 31) return E_INVALIDARG; ep.dictSize = (UInt32)1 << (unsigned)v; break; 100 SET_PROP_32(kLevel, level) 101 SET_PROP_32(kNumFastBytes, fb) 102 SET_PROP_32(kMatchFinderCycles, mc) 103 SET_PROP_32(kAlgorithm, algo) 104 SET_PROP_32(kDictionarySize, dictSize) 105 SET_PROP_32(kPosStateBits, pb) 106 SET_PROP_32(kLitPosBits, lp) 107 SET_PROP_32(kLitContextBits, lc) 108 SET_PROP_32(kNumThreads, numThreads) 109 default: return E_INVALIDARG; 110 } 111 return S_OK; 112} 113 114STDMETHODIMP CEncoder::SetCoderProperties(const PROPID *propIDs, 115 const PROPVARIANT *coderProps, UInt32 numProps) 116{ 117 CLzmaEncProps props; 118 LzmaEncProps_Init(&props); 119 120 for (UInt32 i = 0; i < numProps; i++) 121 { 122 const PROPVARIANT &prop = coderProps[i]; 123 PROPID propID = propIDs[i]; 124 switch (propID) 125 { 126 case NCoderPropID::kEndMarker: 127 if (prop.vt != VT_BOOL) return E_INVALIDARG; props.writeEndMark = (prop.boolVal != VARIANT_FALSE); break; 128 default: 129 RINOK(SetLzmaProp(propID, prop, props)); 130 } 131 } 132 return SResToHRESULT(LzmaEnc_SetProps(_encoder, &props)); 133} 134 135STDMETHODIMP CEncoder::WriteCoderProperties(ISequentialOutStream *outStream) 136{ 137 Byte props[LZMA_PROPS_SIZE]; 138 size_t size = LZMA_PROPS_SIZE; 139 RINOK(LzmaEnc_WriteProperties(_encoder, props, &size)); 140 return WriteStream(outStream, props, size); 141} 142 143STDMETHODIMP CEncoder::Code(ISequentialInStream *inStream, ISequentialOutStream *outStream, 144 const UInt64 * /* inSize */, const UInt64 * /* outSize */, ICompressProgressInfo *progress) 145{ 146 CSeqInStreamWrap inWrap(inStream); 147 CSeqOutStreamWrap outWrap(outStream); 148 CCompressProgressWrap progressWrap(progress); 149 150 SRes res = LzmaEnc_Encode(_encoder, &outWrap.p, &inWrap.p, progress ? &progressWrap.p : NULL, &g_Alloc, &g_BigAlloc); 151 _inputProcessed = inWrap.Processed; 152 if (res == SZ_ERROR_READ && inWrap.Res != S_OK) 153 return inWrap.Res; 154 if (res == SZ_ERROR_WRITE && outWrap.Res != S_OK) 155 return outWrap.Res; 156 if (res == SZ_ERROR_PROGRESS && progressWrap.Res != S_OK) 157 return progressWrap.Res; 158 return SResToHRESULT(res); 159} 160 161}} 162