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 76HRESULT SetLzmaProp(PROPID propID, const PROPVARIANT &prop, CLzmaEncProps &ep) 77{ 78 if (propID == NCoderPropID::kMatchFinder) 79 { 80 if (prop.vt != VT_BSTR) 81 return E_INVALIDARG; 82 return ParseMatchFinder(prop.bstrVal, &ep.btMode, &ep.numHashBytes) ? S_OK : E_INVALIDARG; 83 } 84 if (prop.vt != VT_UI4) 85 return E_INVALIDARG; 86 UInt32 v = prop.ulVal; 87 switch (propID) 88 { 89 case NCoderPropID::kNumFastBytes: ep.fb = v; break; 90 case NCoderPropID::kMatchFinderCycles: ep.mc = v; break; 91 case NCoderPropID::kAlgorithm: ep.algo = v; break; 92 case NCoderPropID::kDictionarySize: ep.dictSize = v; break; 93 case NCoderPropID::kPosStateBits: ep.pb = v; break; 94 case NCoderPropID::kLitPosBits: ep.lp = v; break; 95 case NCoderPropID::kLitContextBits: ep.lc = v; break; 96 default: return E_INVALIDARG; 97 } 98 return S_OK; 99} 100 101STDMETHODIMP CEncoder::SetCoderProperties(const PROPID *propIDs, 102 const PROPVARIANT *coderProps, UInt32 numProps) 103{ 104 CLzmaEncProps props; 105 LzmaEncProps_Init(&props); 106 107 for (UInt32 i = 0; i < numProps; i++) 108 { 109 const PROPVARIANT &prop = coderProps[i]; 110 PROPID propID = propIDs[i]; 111 switch (propID) 112 { 113 case NCoderPropID::kEndMarker: 114 if (prop.vt != VT_BOOL) return E_INVALIDARG; props.writeEndMark = (prop.boolVal == VARIANT_TRUE); break; 115 case NCoderPropID::kNumThreads: 116 if (prop.vt != VT_UI4) return E_INVALIDARG; props.numThreads = prop.ulVal; break; 117 default: 118 RINOK(SetLzmaProp(propID, prop, props)); 119 } 120 } 121 return SResToHRESULT(LzmaEnc_SetProps(_encoder, &props)); 122} 123 124STDMETHODIMP CEncoder::WriteCoderProperties(ISequentialOutStream *outStream) 125{ 126 Byte props[LZMA_PROPS_SIZE]; 127 size_t size = LZMA_PROPS_SIZE; 128 RINOK(LzmaEnc_WriteProperties(_encoder, props, &size)); 129 return WriteStream(outStream, props, size); 130} 131 132STDMETHODIMP CEncoder::Code(ISequentialInStream *inStream, ISequentialOutStream *outStream, 133 const UInt64 * /* inSize */, const UInt64 * /* outSize */, ICompressProgressInfo *progress) 134{ 135 CSeqInStreamWrap inWrap(inStream); 136 CSeqOutStreamWrap outWrap(outStream); 137 CCompressProgressWrap progressWrap(progress); 138 139 SRes res = LzmaEnc_Encode(_encoder, &outWrap.p, &inWrap.p, progress ? &progressWrap.p : NULL, &g_Alloc, &g_BigAlloc); 140 if (res == SZ_ERROR_READ && inWrap.Res != S_OK) 141 return inWrap.Res; 142 if (res == SZ_ERROR_WRITE && outWrap.Res != S_OK) 143 return outWrap.Res; 144 if (res == SZ_ERROR_PROGRESS && progressWrap.Res != S_OK) 145 return progressWrap.Res; 146 return SResToHRESULT(res); 147} 148 149}} 150