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
15CEncoder::CEncoder()
16{
17  _encoder = NULL;
18  _encoder = LzmaEnc_Create(&g_Alloc);
19  if (!_encoder)
20    throw 1;
21}
22
23CEncoder::~CEncoder()
24{
25  if (_encoder)
26    LzmaEnc_Destroy(_encoder, &g_Alloc, &g_BigAlloc);
27}
28
29static inline wchar_t GetUpperChar(wchar_t c)
30{
31  if (c >= 'a' && c <= 'z')
32    c -= 0x20;
33  return c;
34}
35
36static 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
69HRESULT 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
105STDMETHODIMP 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
126STDMETHODIMP 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
134STDMETHODIMP 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