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