1370b324cSopenharmony_ci// LzmaEncoder.cpp
2370b324cSopenharmony_ci
3370b324cSopenharmony_ci#include "StdAfx.h"
4370b324cSopenharmony_ci
5370b324cSopenharmony_ci#include "../../../C/Alloc.h"
6370b324cSopenharmony_ci
7370b324cSopenharmony_ci#include "../Common/CWrappers.h"
8370b324cSopenharmony_ci#include "../Common/StreamUtils.h"
9370b324cSopenharmony_ci
10370b324cSopenharmony_ci#include "LzmaEncoder.h"
11370b324cSopenharmony_ci
12370b324cSopenharmony_ci// #define LOG_LZMA_THREADS
13370b324cSopenharmony_ci
14370b324cSopenharmony_ci#ifdef LOG_LZMA_THREADS
15370b324cSopenharmony_ci
16370b324cSopenharmony_ci#include <stdio.h>
17370b324cSopenharmony_ci
18370b324cSopenharmony_ci#include "../../Common/IntToString.h"
19370b324cSopenharmony_ci#include "../../Windows/TimeUtils.h"
20370b324cSopenharmony_ci
21370b324cSopenharmony_ciEXTERN_C_BEGIN
22370b324cSopenharmony_civoid LzmaEnc_GetLzThreads(CLzmaEncHandle pp, HANDLE lz_threads[2]);
23370b324cSopenharmony_ciEXTERN_C_END
24370b324cSopenharmony_ci
25370b324cSopenharmony_ci#endif
26370b324cSopenharmony_ci
27370b324cSopenharmony_cinamespace NCompress {
28370b324cSopenharmony_cinamespace NLzma {
29370b324cSopenharmony_ci
30370b324cSopenharmony_ciCEncoder::CEncoder()
31370b324cSopenharmony_ci{
32370b324cSopenharmony_ci  _encoder = NULL;
33370b324cSopenharmony_ci  _encoder = LzmaEnc_Create(&g_AlignedAlloc);
34370b324cSopenharmony_ci  if (!_encoder)
35370b324cSopenharmony_ci    throw 1;
36370b324cSopenharmony_ci}
37370b324cSopenharmony_ci
38370b324cSopenharmony_ciCEncoder::~CEncoder()
39370b324cSopenharmony_ci{
40370b324cSopenharmony_ci  if (_encoder)
41370b324cSopenharmony_ci    LzmaEnc_Destroy(_encoder, &g_AlignedAlloc, &g_BigAlloc);
42370b324cSopenharmony_ci}
43370b324cSopenharmony_ci
44370b324cSopenharmony_cistatic inline wchar_t GetLowCharFast(wchar_t c)
45370b324cSopenharmony_ci{
46370b324cSopenharmony_ci  return c |= 0x20;
47370b324cSopenharmony_ci}
48370b324cSopenharmony_ci
49370b324cSopenharmony_cistatic int ParseMatchFinder(const wchar_t *s, int *btMode, int *numHashBytes)
50370b324cSopenharmony_ci{
51370b324cSopenharmony_ci  const wchar_t c = GetLowCharFast(*s++);
52370b324cSopenharmony_ci  if (c == 'h')
53370b324cSopenharmony_ci  {
54370b324cSopenharmony_ci    if (GetLowCharFast(*s++) != 'c')
55370b324cSopenharmony_ci      return 0;
56370b324cSopenharmony_ci    const int num = (int)(*s++ - L'0');
57370b324cSopenharmony_ci    if (num < 4 || num > 5)
58370b324cSopenharmony_ci      return 0;
59370b324cSopenharmony_ci    if (*s != 0)
60370b324cSopenharmony_ci      return 0;
61370b324cSopenharmony_ci    *btMode = 0;
62370b324cSopenharmony_ci    *numHashBytes = num;
63370b324cSopenharmony_ci    return 1;
64370b324cSopenharmony_ci  }
65370b324cSopenharmony_ci
66370b324cSopenharmony_ci  if (c != 'b')
67370b324cSopenharmony_ci    return 0;
68370b324cSopenharmony_ci  {
69370b324cSopenharmony_ci    if (GetLowCharFast(*s++) != 't')
70370b324cSopenharmony_ci      return 0;
71370b324cSopenharmony_ci    const int num = (int)(*s++ - L'0');
72370b324cSopenharmony_ci    if (num < 2 || num > 5)
73370b324cSopenharmony_ci      return 0;
74370b324cSopenharmony_ci    if (*s != 0)
75370b324cSopenharmony_ci      return 0;
76370b324cSopenharmony_ci    *btMode = 1;
77370b324cSopenharmony_ci    *numHashBytes = num;
78370b324cSopenharmony_ci    return 1;
79370b324cSopenharmony_ci  }
80370b324cSopenharmony_ci}
81370b324cSopenharmony_ci
82370b324cSopenharmony_ci#define SET_PROP_32(_id_, _dest_) case NCoderPropID::_id_: ep._dest_ = (int)v; break;
83370b324cSopenharmony_ci#define SET_PROP_32U(_id_, _dest_) case NCoderPropID::_id_: ep._dest_ = v; break;
84370b324cSopenharmony_ci
85370b324cSopenharmony_ciHRESULT SetLzmaProp(PROPID propID, const PROPVARIANT &prop, CLzmaEncProps &ep);
86370b324cSopenharmony_ciHRESULT SetLzmaProp(PROPID propID, const PROPVARIANT &prop, CLzmaEncProps &ep)
87370b324cSopenharmony_ci{
88370b324cSopenharmony_ci  if (propID == NCoderPropID::kMatchFinder)
89370b324cSopenharmony_ci  {
90370b324cSopenharmony_ci    if (prop.vt != VT_BSTR)
91370b324cSopenharmony_ci      return E_INVALIDARG;
92370b324cSopenharmony_ci    return ParseMatchFinder(prop.bstrVal, &ep.btMode, &ep.numHashBytes) ? S_OK : E_INVALIDARG;
93370b324cSopenharmony_ci  }
94370b324cSopenharmony_ci
95370b324cSopenharmony_ci  if (propID == NCoderPropID::kAffinity)
96370b324cSopenharmony_ci  {
97370b324cSopenharmony_ci    if (prop.vt == VT_UI8)
98370b324cSopenharmony_ci      ep.affinity = prop.uhVal.QuadPart;
99370b324cSopenharmony_ci    else
100370b324cSopenharmony_ci      return E_INVALIDARG;
101370b324cSopenharmony_ci    return S_OK;
102370b324cSopenharmony_ci  }
103370b324cSopenharmony_ci
104370b324cSopenharmony_ci  if (propID == NCoderPropID::kHashBits)
105370b324cSopenharmony_ci  {
106370b324cSopenharmony_ci    if (prop.vt == VT_UI4)
107370b324cSopenharmony_ci      ep.numHashOutBits = prop.ulVal;
108370b324cSopenharmony_ci    else
109370b324cSopenharmony_ci      return E_INVALIDARG;
110370b324cSopenharmony_ci    return S_OK;
111370b324cSopenharmony_ci  }
112370b324cSopenharmony_ci
113370b324cSopenharmony_ci  if (propID > NCoderPropID::kReduceSize)
114370b324cSopenharmony_ci    return S_OK;
115370b324cSopenharmony_ci
116370b324cSopenharmony_ci  if (propID == NCoderPropID::kReduceSize)
117370b324cSopenharmony_ci  {
118370b324cSopenharmony_ci    if (prop.vt == VT_UI8)
119370b324cSopenharmony_ci      ep.reduceSize = prop.uhVal.QuadPart;
120370b324cSopenharmony_ci    else
121370b324cSopenharmony_ci      return E_INVALIDARG;
122370b324cSopenharmony_ci    return S_OK;
123370b324cSopenharmony_ci  }
124370b324cSopenharmony_ci
125370b324cSopenharmony_ci  if (propID == NCoderPropID::kDictionarySize)
126370b324cSopenharmony_ci  {
127370b324cSopenharmony_ci    if (prop.vt == VT_UI8)
128370b324cSopenharmony_ci    {
129370b324cSopenharmony_ci      // 21.03 : we support 64-bit VT_UI8 for dictionary and (dict == 4 GiB)
130370b324cSopenharmony_ci      const UInt64 v = prop.uhVal.QuadPart;
131370b324cSopenharmony_ci      if (v > ((UInt64)1 << 32))
132370b324cSopenharmony_ci        return E_INVALIDARG;
133370b324cSopenharmony_ci      UInt32 dict;
134370b324cSopenharmony_ci      if (v == ((UInt64)1 << 32))
135370b324cSopenharmony_ci        dict = (UInt32)(Int32)-1;
136370b324cSopenharmony_ci      else
137370b324cSopenharmony_ci        dict = (UInt32)v;
138370b324cSopenharmony_ci      ep.dictSize = dict;
139370b324cSopenharmony_ci      return S_OK;
140370b324cSopenharmony_ci    }
141370b324cSopenharmony_ci  }
142370b324cSopenharmony_ci
143370b324cSopenharmony_ci  if (prop.vt != VT_UI4)
144370b324cSopenharmony_ci    return E_INVALIDARG;
145370b324cSopenharmony_ci  const UInt32 v = prop.ulVal;
146370b324cSopenharmony_ci  switch (propID)
147370b324cSopenharmony_ci  {
148370b324cSopenharmony_ci    case NCoderPropID::kDefaultProp:
149370b324cSopenharmony_ci      if (v > 32)
150370b324cSopenharmony_ci        return E_INVALIDARG;
151370b324cSopenharmony_ci      ep.dictSize = (v == 32) ? (UInt32)(Int32)-1 : (UInt32)1 << (unsigned)v;
152370b324cSopenharmony_ci      break;
153370b324cSopenharmony_ci    SET_PROP_32(kLevel, level)
154370b324cSopenharmony_ci    SET_PROP_32(kNumFastBytes, fb)
155370b324cSopenharmony_ci    SET_PROP_32U(kMatchFinderCycles, mc)
156370b324cSopenharmony_ci    SET_PROP_32(kAlgorithm, algo)
157370b324cSopenharmony_ci    SET_PROP_32U(kDictionarySize, dictSize)
158370b324cSopenharmony_ci    SET_PROP_32(kPosStateBits, pb)
159370b324cSopenharmony_ci    SET_PROP_32(kLitPosBits, lp)
160370b324cSopenharmony_ci    SET_PROP_32(kLitContextBits, lc)
161370b324cSopenharmony_ci    SET_PROP_32(kNumThreads, numThreads)
162370b324cSopenharmony_ci    default: return E_INVALIDARG;
163370b324cSopenharmony_ci  }
164370b324cSopenharmony_ci  return S_OK;
165370b324cSopenharmony_ci}
166370b324cSopenharmony_ci
167370b324cSopenharmony_ciZ7_COM7F_IMF(CEncoder::SetCoderProperties(const PROPID *propIDs,
168370b324cSopenharmony_ci    const PROPVARIANT *coderProps, UInt32 numProps))
169370b324cSopenharmony_ci{
170370b324cSopenharmony_ci  CLzmaEncProps props;
171370b324cSopenharmony_ci  LzmaEncProps_Init(&props);
172370b324cSopenharmony_ci
173370b324cSopenharmony_ci  for (UInt32 i = 0; i < numProps; i++)
174370b324cSopenharmony_ci  {
175370b324cSopenharmony_ci    const PROPVARIANT &prop = coderProps[i];
176370b324cSopenharmony_ci    const PROPID propID = propIDs[i];
177370b324cSopenharmony_ci    switch (propID)
178370b324cSopenharmony_ci    {
179370b324cSopenharmony_ci      case NCoderPropID::kEndMarker:
180370b324cSopenharmony_ci        if (prop.vt != VT_BOOL)
181370b324cSopenharmony_ci          return E_INVALIDARG;
182370b324cSopenharmony_ci        props.writeEndMark = (prop.boolVal != VARIANT_FALSE);
183370b324cSopenharmony_ci        break;
184370b324cSopenharmony_ci      default:
185370b324cSopenharmony_ci        RINOK(SetLzmaProp(propID, prop, props))
186370b324cSopenharmony_ci    }
187370b324cSopenharmony_ci  }
188370b324cSopenharmony_ci  return SResToHRESULT(LzmaEnc_SetProps(_encoder, &props));
189370b324cSopenharmony_ci}
190370b324cSopenharmony_ci
191370b324cSopenharmony_ci
192370b324cSopenharmony_ciZ7_COM7F_IMF(CEncoder::SetCoderPropertiesOpt(const PROPID *propIDs,
193370b324cSopenharmony_ci    const PROPVARIANT *coderProps, UInt32 numProps))
194370b324cSopenharmony_ci{
195370b324cSopenharmony_ci  for (UInt32 i = 0; i < numProps; i++)
196370b324cSopenharmony_ci  {
197370b324cSopenharmony_ci    const PROPVARIANT &prop = coderProps[i];
198370b324cSopenharmony_ci    const PROPID propID = propIDs[i];
199370b324cSopenharmony_ci    if (propID == NCoderPropID::kExpectedDataSize)
200370b324cSopenharmony_ci      if (prop.vt == VT_UI8)
201370b324cSopenharmony_ci        LzmaEnc_SetDataSize(_encoder, prop.uhVal.QuadPart);
202370b324cSopenharmony_ci  }
203370b324cSopenharmony_ci  return S_OK;
204370b324cSopenharmony_ci}
205370b324cSopenharmony_ci
206370b324cSopenharmony_ci
207370b324cSopenharmony_ciZ7_COM7F_IMF(CEncoder::WriteCoderProperties(ISequentialOutStream *outStream))
208370b324cSopenharmony_ci{
209370b324cSopenharmony_ci  Byte props[LZMA_PROPS_SIZE];
210370b324cSopenharmony_ci  SizeT size = LZMA_PROPS_SIZE;
211370b324cSopenharmony_ci  RINOK(LzmaEnc_WriteProperties(_encoder, props, &size))
212370b324cSopenharmony_ci  return WriteStream(outStream, props, size);
213370b324cSopenharmony_ci}
214370b324cSopenharmony_ci
215370b324cSopenharmony_ci
216370b324cSopenharmony_ci#define RET_IF_WRAP_ERROR(wrapRes, sRes, sResErrorCode) \
217370b324cSopenharmony_ci  if (wrapRes != S_OK /* && (sRes == SZ_OK || sRes == sResErrorCode) */) return wrapRes;
218370b324cSopenharmony_ci
219370b324cSopenharmony_ci
220370b324cSopenharmony_ci
221370b324cSopenharmony_ci#ifdef LOG_LZMA_THREADS
222370b324cSopenharmony_ci
223370b324cSopenharmony_cistatic inline UInt64 GetTime64(const FILETIME &t) { return ((UInt64)t.dwHighDateTime << 32) | t.dwLowDateTime; }
224370b324cSopenharmony_ci
225370b324cSopenharmony_cistatic void PrintNum(UInt64 val, unsigned numDigits, char c = ' ')
226370b324cSopenharmony_ci{
227370b324cSopenharmony_ci  char temp[64];
228370b324cSopenharmony_ci  char *p = temp + 32;
229370b324cSopenharmony_ci  ConvertUInt64ToString(val, p);
230370b324cSopenharmony_ci  unsigned len = (unsigned)strlen(p);
231370b324cSopenharmony_ci  for (; len < numDigits; len++)
232370b324cSopenharmony_ci    *--p = c;
233370b324cSopenharmony_ci  printf("%s", p);
234370b324cSopenharmony_ci}
235370b324cSopenharmony_ci
236370b324cSopenharmony_cistatic void PrintTime(const char *s, UInt64 val, UInt64 total)
237370b324cSopenharmony_ci{
238370b324cSopenharmony_ci  printf("  %s :", s);
239370b324cSopenharmony_ci  const UInt32 kFreq = 10000000;
240370b324cSopenharmony_ci  UInt64 sec = val / kFreq;
241370b324cSopenharmony_ci  PrintNum(sec, 6);
242370b324cSopenharmony_ci  printf(" .");
243370b324cSopenharmony_ci  UInt32 ms = (UInt32)(val - (sec * kFreq)) / (kFreq / 1000);
244370b324cSopenharmony_ci  PrintNum(ms, 3, '0');
245370b324cSopenharmony_ci
246370b324cSopenharmony_ci  while (val > ((UInt64)1 << 56))
247370b324cSopenharmony_ci  {
248370b324cSopenharmony_ci    val >>= 1;
249370b324cSopenharmony_ci    total >>= 1;
250370b324cSopenharmony_ci  }
251370b324cSopenharmony_ci
252370b324cSopenharmony_ci  UInt64 percent = 0;
253370b324cSopenharmony_ci  if (total != 0)
254370b324cSopenharmony_ci    percent = val * 100 / total;
255370b324cSopenharmony_ci  printf("  =");
256370b324cSopenharmony_ci  PrintNum(percent, 4);
257370b324cSopenharmony_ci  printf("%%");
258370b324cSopenharmony_ci}
259370b324cSopenharmony_ci
260370b324cSopenharmony_ci
261370b324cSopenharmony_cistruct CBaseStat
262370b324cSopenharmony_ci{
263370b324cSopenharmony_ci  UInt64 kernelTime, userTime;
264370b324cSopenharmony_ci
265370b324cSopenharmony_ci  BOOL Get(HANDLE thread, const CBaseStat *prevStat)
266370b324cSopenharmony_ci  {
267370b324cSopenharmony_ci    FILETIME creationTimeFT, exitTimeFT, kernelTimeFT, userTimeFT;
268370b324cSopenharmony_ci    BOOL res = GetThreadTimes(thread
269370b324cSopenharmony_ci      , &creationTimeFT, &exitTimeFT, &kernelTimeFT, &userTimeFT);
270370b324cSopenharmony_ci    if (res)
271370b324cSopenharmony_ci    {
272370b324cSopenharmony_ci      kernelTime = GetTime64(kernelTimeFT);
273370b324cSopenharmony_ci      userTime = GetTime64(userTimeFT);
274370b324cSopenharmony_ci      if (prevStat)
275370b324cSopenharmony_ci      {
276370b324cSopenharmony_ci        kernelTime -= prevStat->kernelTime;
277370b324cSopenharmony_ci        userTime -= prevStat->userTime;
278370b324cSopenharmony_ci      }
279370b324cSopenharmony_ci    }
280370b324cSopenharmony_ci    return res;
281370b324cSopenharmony_ci  }
282370b324cSopenharmony_ci};
283370b324cSopenharmony_ci
284370b324cSopenharmony_ci
285370b324cSopenharmony_cistatic void PrintStat(HANDLE thread, UInt64 totalTime, const CBaseStat *prevStat)
286370b324cSopenharmony_ci{
287370b324cSopenharmony_ci  CBaseStat newStat;
288370b324cSopenharmony_ci  if (!newStat.Get(thread, prevStat))
289370b324cSopenharmony_ci    return;
290370b324cSopenharmony_ci
291370b324cSopenharmony_ci  PrintTime("K", newStat.kernelTime, totalTime);
292370b324cSopenharmony_ci
293370b324cSopenharmony_ci  const UInt64 processTime = newStat.kernelTime + newStat.userTime;
294370b324cSopenharmony_ci
295370b324cSopenharmony_ci  PrintTime("U", newStat.userTime, totalTime);
296370b324cSopenharmony_ci  PrintTime("S", processTime, totalTime);
297370b324cSopenharmony_ci  printf("\n");
298370b324cSopenharmony_ci  // PrintTime("G ", totalTime, totalTime);
299370b324cSopenharmony_ci}
300370b324cSopenharmony_ci
301370b324cSopenharmony_ci#endif
302370b324cSopenharmony_ci
303370b324cSopenharmony_ci
304370b324cSopenharmony_ci
305370b324cSopenharmony_ciZ7_COM7F_IMF(CEncoder::Code(ISequentialInStream *inStream, ISequentialOutStream *outStream,
306370b324cSopenharmony_ci    const UInt64 * /* inSize */, const UInt64 * /* outSize */, ICompressProgressInfo *progress))
307370b324cSopenharmony_ci{
308370b324cSopenharmony_ci  CSeqInStreamWrap inWrap;
309370b324cSopenharmony_ci  CSeqOutStreamWrap outWrap;
310370b324cSopenharmony_ci  CCompressProgressWrap progressWrap;
311370b324cSopenharmony_ci
312370b324cSopenharmony_ci  inWrap.Init(inStream);
313370b324cSopenharmony_ci  outWrap.Init(outStream);
314370b324cSopenharmony_ci  progressWrap.Init(progress);
315370b324cSopenharmony_ci
316370b324cSopenharmony_ci  #ifdef LOG_LZMA_THREADS
317370b324cSopenharmony_ci
318370b324cSopenharmony_ci  FILETIME startTimeFT;
319370b324cSopenharmony_ci  NWindows::NTime::GetCurUtcFileTime(startTimeFT);
320370b324cSopenharmony_ci  UInt64 totalTime = GetTime64(startTimeFT);
321370b324cSopenharmony_ci  CBaseStat oldStat;
322370b324cSopenharmony_ci  if (!oldStat.Get(GetCurrentThread(), NULL))
323370b324cSopenharmony_ci    return E_FAIL;
324370b324cSopenharmony_ci
325370b324cSopenharmony_ci  #endif
326370b324cSopenharmony_ci
327370b324cSopenharmony_ci
328370b324cSopenharmony_ci  SRes res = LzmaEnc_Encode(_encoder, &outWrap.vt, &inWrap.vt,
329370b324cSopenharmony_ci      progress ? &progressWrap.vt : NULL, &g_AlignedAlloc, &g_BigAlloc);
330370b324cSopenharmony_ci
331370b324cSopenharmony_ci  _inputProcessed = inWrap.Processed;
332370b324cSopenharmony_ci
333370b324cSopenharmony_ci  RET_IF_WRAP_ERROR(inWrap.Res, res, SZ_ERROR_READ)
334370b324cSopenharmony_ci  RET_IF_WRAP_ERROR(outWrap.Res, res, SZ_ERROR_WRITE)
335370b324cSopenharmony_ci  RET_IF_WRAP_ERROR(progressWrap.Res, res, SZ_ERROR_PROGRESS)
336370b324cSopenharmony_ci
337370b324cSopenharmony_ci
338370b324cSopenharmony_ci  #ifdef LOG_LZMA_THREADS
339370b324cSopenharmony_ci
340370b324cSopenharmony_ci  NWindows::NTime::GetCurUtcFileTime(startTimeFT);
341370b324cSopenharmony_ci  totalTime = GetTime64(startTimeFT) - totalTime;
342370b324cSopenharmony_ci  HANDLE lz_threads[2];
343370b324cSopenharmony_ci  LzmaEnc_GetLzThreads(_encoder, lz_threads);
344370b324cSopenharmony_ci  printf("\n");
345370b324cSopenharmony_ci  printf("Main: ");  PrintStat(GetCurrentThread(), totalTime, &oldStat);
346370b324cSopenharmony_ci  printf("Hash: ");  PrintStat(lz_threads[0], totalTime, NULL);
347370b324cSopenharmony_ci  printf("BinT: ");  PrintStat(lz_threads[1], totalTime, NULL);
348370b324cSopenharmony_ci  // PrintTime("Total: ", totalTime, totalTime);
349370b324cSopenharmony_ci  printf("\n");
350370b324cSopenharmony_ci
351370b324cSopenharmony_ci  #endif
352370b324cSopenharmony_ci
353370b324cSopenharmony_ci  return SResToHRESULT(res);
354370b324cSopenharmony_ci}
355370b324cSopenharmony_ci
356370b324cSopenharmony_ci}}
357