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
CEncoder()15 CEncoder::CEncoder()
16 {
17 _encoder = NULL;
18 _encoder = LzmaEnc_Create(&g_Alloc);
19 if (!_encoder)
20 throw 1;
21 }
22
~CEncoder()23 CEncoder::~CEncoder()
24 {
25 if (_encoder)
26 LzmaEnc_Destroy(_encoder, &g_Alloc, &g_BigAlloc);
27 }
28
GetUpperChar(wchar_t c)29 static inline wchar_t GetUpperChar(wchar_t c)
30 {
31 if (c >= 'a' && c <= 'z')
32 c -= 0x20;
33 return c;
34 }
35
ParseMatchFinder(const wchar_t * s,int * btMode,int * numHashBytes)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
SetLzmaProp(PROPID propID,const PROPVARIANT & prop,CLzmaEncProps & ep)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 if (propID > NCoderPropID::kReduceSize)
78 return S_OK;
79 if (propID == NCoderPropID::kReduceSize)
80 {
81 if (prop.vt == VT_UI8)
82 ep.reduceSize = prop.uhVal.QuadPart;
83 return S_OK;
84 }
85 if (prop.vt != VT_UI4)
86 return E_INVALIDARG;
87 UInt32 v = prop.ulVal;
88 switch (propID)
89 {
90 case NCoderPropID::kDefaultProp: if (v > 31) return E_INVALIDARG; ep.dictSize = (UInt32)1 << (unsigned)v; break;
91 SET_PROP_32(kLevel, level)
92 SET_PROP_32(kNumFastBytes, fb)
93 SET_PROP_32(kMatchFinderCycles, mc)
94 SET_PROP_32(kAlgorithm, algo)
95 SET_PROP_32(kDictionarySize, dictSize)
96 SET_PROP_32(kPosStateBits, pb)
97 SET_PROP_32(kLitPosBits, lp)
98 SET_PROP_32(kLitContextBits, lc)
99 SET_PROP_32(kNumThreads, numThreads)
100 default: return E_INVALIDARG;
101 }
102 return S_OK;
103 }
104
SetCoderProperties(const PROPID * propIDs,const PROPVARIANT * coderProps,UInt32 numProps)105 STDMETHODIMP CEncoder::SetCoderProperties(const PROPID *propIDs,
106 const PROPVARIANT *coderProps, UInt32 numProps)
107 {
108 CLzmaEncProps props;
109 LzmaEncProps_Init(&props);
110
111 for (UInt32 i = 0; i < numProps; i++)
112 {
113 const PROPVARIANT &prop = coderProps[i];
114 PROPID propID = propIDs[i];
115 switch (propID)
116 {
117 case NCoderPropID::kEndMarker:
118 if (prop.vt != VT_BOOL) return E_INVALIDARG; props.writeEndMark = (prop.boolVal != VARIANT_FALSE); break;
119 default:
120 RINOK(SetLzmaProp(propID, prop, props));
121 }
122 }
123 return SResToHRESULT(LzmaEnc_SetProps(_encoder, &props));
124 }
125
WriteCoderProperties(ISequentialOutStream * outStream)126 STDMETHODIMP CEncoder::WriteCoderProperties(ISequentialOutStream *outStream)
127 {
128 Byte props[LZMA_PROPS_SIZE];
129 size_t size = LZMA_PROPS_SIZE;
130 RINOK(LzmaEnc_WriteProperties(_encoder, props, &size));
131 return WriteStream(outStream, props, size);
132 }
133
Code(ISequentialInStream * inStream,ISequentialOutStream * outStream,const UInt64 *,const UInt64 *,ICompressProgressInfo * progress)134 STDMETHODIMP CEncoder::Code(ISequentialInStream *inStream, ISequentialOutStream *outStream,
135 const UInt64 * /* inSize */, const UInt64 * /* outSize */, ICompressProgressInfo *progress)
136 {
137 CSeqInStreamWrap inWrap(inStream);
138 CSeqOutStreamWrap outWrap(outStream);
139 CCompressProgressWrap progressWrap(progress);
140
141 SRes res = LzmaEnc_Encode(_encoder, &outWrap.p, &inWrap.p, progress ? &progressWrap.p : NULL, &g_Alloc, &g_BigAlloc);
142 _inputProcessed = inWrap.Processed;
143 if (res == SZ_ERROR_READ && inWrap.Res != S_OK)
144 return inWrap.Res;
145 if (res == SZ_ERROR_WRITE && outWrap.Res != S_OK)
146 return outWrap.Res;
147 if (res == SZ_ERROR_PROGRESS && progressWrap.Res != S_OK)
148 return progressWrap.Res;
149 return SResToHRESULT(res);
150 }
151
152 }}
153