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
SzBigAlloc(void *,size_t size)15 static void *SzBigAlloc(void *, size_t size) { return BigAlloc(size); }
SzBigFree(void *,void * address)16 static void SzBigFree(void *, void *address) { BigFree(address); }
17 static ISzAlloc g_BigAlloc = { SzBigAlloc, SzBigFree };
18
SzAlloc(void *,size_t size)19 static void *SzAlloc(void *, size_t size) { return MyAlloc(size); }
SzFree(void *,void * address)20 static void SzFree(void *, void *address) { MyFree(address); }
21 static ISzAlloc g_Alloc = { SzAlloc, SzFree };
22
CEncoder()23 CEncoder::CEncoder()
24 {
25 _encoder = 0;
26 _encoder = LzmaEnc_Create(&g_Alloc);
27 if (_encoder == 0)
28 throw 1;
29 }
30
~CEncoder()31 CEncoder::~CEncoder()
32 {
33 if (_encoder != 0)
34 LzmaEnc_Destroy(_encoder, &g_Alloc, &g_BigAlloc);
35 }
36
GetUpperChar(wchar_t c)37 inline wchar_t GetUpperChar(wchar_t c)
38 {
39 if (c >= 'a' && c <= 'z')
40 c -= 0x20;
41 return c;
42 }
43
ParseMatchFinder(const wchar_t * s,int * btMode,int * numHashBytes)44 static 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
SetLzmaProp(PROPID propID,const PROPVARIANT & prop,CLzmaEncProps & ep)76 HRESULT 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
SetCoderProperties(const PROPID * propIDs,const PROPVARIANT * coderProps,UInt32 numProps)101 STDMETHODIMP 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
WriteCoderProperties(ISequentialOutStream * outStream)124 STDMETHODIMP 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
Code(ISequentialInStream * inStream,ISequentialOutStream * outStream,const UInt64 *,const UInt64 *,ICompressProgressInfo * progress)132 STDMETHODIMP 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