1// CodecExports.cpp
2
3#include "StdAfx.h"
4
5#include "../../../C/CpuArch.h"
6
7#include "../../Common/ComTry.h"
8#include "../../Common/MyCom.h"
9
10#include "../../Windows/Defs.h"
11
12#include "../ICoder.h"
13
14#include "../Common/RegisterCodec.h"
15
16extern unsigned g_NumCodecs;
17extern const CCodecInfo *g_Codecs[];
18
19extern unsigned g_NumHashers;
20extern const CHasherInfo *g_Hashers[];
21
22static void SetPropFromAscii(const char *s, PROPVARIANT *prop) throw()
23{
24  UINT len = (UINT)strlen(s);
25  BSTR dest = ::SysAllocStringLen(NULL, len);
26  if (dest)
27  {
28    for (UINT i = 0; i <= len; i++)
29      dest[i] = (Byte)s[i];
30    prop->bstrVal = dest;
31    prop->vt = VT_BSTR;
32  }
33}
34
35static inline HRESULT SetPropGUID(const GUID &guid, PROPVARIANT *value) throw()
36{
37  if ((value->bstrVal = ::SysAllocStringByteLen((const char *)&guid, sizeof(guid))) != NULL)
38    value->vt = VT_BSTR;
39  return S_OK;
40}
41
42static HRESULT MethodToClassID(UInt16 typeId, CMethodId id, PROPVARIANT *value) throw()
43{
44  GUID clsId;
45  clsId.Data1 = k_7zip_GUID_Data1;
46  clsId.Data2 = k_7zip_GUID_Data2;
47  clsId.Data3 = typeId;
48  SetUi64(clsId.Data4, id);
49  return SetPropGUID(clsId, value);
50}
51
52static HRESULT FindCodecClassId(const GUID *clsid, bool isCoder2, bool isFilter, bool &encode, int &index) throw()
53{
54  index = -1;
55  if (clsid->Data1 != k_7zip_GUID_Data1 ||
56      clsid->Data2 != k_7zip_GUID_Data2)
57    return S_OK;
58
59  encode = true;
60
61       if (clsid->Data3 == k_7zip_GUID_Data3_Decoder) encode = false;
62  else if (clsid->Data3 != k_7zip_GUID_Data3_Encoder) return S_OK;
63
64  UInt64 id = GetUi64(clsid->Data4);
65
66  for (unsigned i = 0; i < g_NumCodecs; i++)
67  {
68    const CCodecInfo &codec = *g_Codecs[i];
69
70    if (id != codec.Id
71        || (encode ? !codec.CreateEncoder : !codec.CreateDecoder)
72        || (isFilter ? !codec.IsFilter : codec.IsFilter))
73      continue;
74
75    if (codec.NumStreams == 1 ? isCoder2 : !isCoder2)
76      return E_NOINTERFACE;
77
78    index = i;
79    return S_OK;
80  }
81
82  return S_OK;
83}
84
85static HRESULT CreateCoderMain(unsigned index, bool encode, void **coder)
86{
87  COM_TRY_BEGIN
88
89  const CCodecInfo &codec = *g_Codecs[index];
90
91  void *c;
92  if (encode)
93    c = codec.CreateEncoder();
94  else
95    c = codec.CreateDecoder();
96
97  if (c)
98  {
99    IUnknown *unk;
100    if (codec.IsFilter)
101      unk = (IUnknown *)(ICompressFilter *)c;
102    else if (codec.NumStreams != 1)
103      unk = (IUnknown *)(ICompressCoder2 *)c;
104    else
105      unk = (IUnknown *)(ICompressCoder *)c;
106    unk->AddRef();
107    *coder = c;
108  }
109  return S_OK;
110
111  COM_TRY_END
112}
113
114static HRESULT CreateCoder2(bool encode, UInt32 index, const GUID *iid, void **outObject)
115{
116  *outObject = NULL;
117
118  const CCodecInfo &codec = *g_Codecs[index];
119
120  if (encode ? !codec.CreateEncoder : !codec.CreateDecoder)
121    return CLASS_E_CLASSNOTAVAILABLE;
122
123  if (codec.IsFilter)
124  {
125    if (*iid != IID_ICompressFilter) return E_NOINTERFACE;
126  }
127  else if (codec.NumStreams != 1)
128  {
129    if (*iid != IID_ICompressCoder2) return E_NOINTERFACE;
130  }
131  else
132  {
133    if (*iid != IID_ICompressCoder) return E_NOINTERFACE;
134  }
135
136  return CreateCoderMain(index, encode, outObject);
137}
138
139STDAPI CreateDecoder(UInt32 index, const GUID *iid, void **outObject)
140{
141  return CreateCoder2(false, index, iid, outObject);
142}
143
144STDAPI CreateEncoder(UInt32 index, const GUID *iid, void **outObject)
145{
146  return CreateCoder2(true, index, iid, outObject);
147}
148
149STDAPI CreateCoder(const GUID *clsid, const GUID *iid, void **outObject)
150{
151  *outObject = NULL;
152
153  bool isFilter = false;
154  bool isCoder2 = false;
155  bool isCoder = (*iid == IID_ICompressCoder) != 0;
156  if (!isCoder)
157  {
158    isFilter = (*iid == IID_ICompressFilter) != 0;
159    if (!isFilter)
160    {
161      isCoder2 = (*iid == IID_ICompressCoder2) != 0;
162      if (!isCoder2)
163        return E_NOINTERFACE;
164    }
165  }
166
167  bool encode;
168  int codecIndex;
169  HRESULT res = FindCodecClassId(clsid, isCoder2, isFilter, encode, codecIndex);
170  if (res != S_OK)
171    return res;
172  if (codecIndex < 0)
173    return CLASS_E_CLASSNOTAVAILABLE;
174
175  return CreateCoderMain(codecIndex, encode, outObject);
176}
177
178STDAPI GetMethodProperty(UInt32 codecIndex, PROPID propID, PROPVARIANT *value)
179{
180  ::VariantClear((VARIANTARG *)value);
181  const CCodecInfo &codec = *g_Codecs[codecIndex];
182  switch (propID)
183  {
184    case NMethodPropID::kID:
185      value->uhVal.QuadPart = (UInt64)codec.Id;
186      value->vt = VT_UI8;
187      break;
188    case NMethodPropID::kName:
189      SetPropFromAscii(codec.Name, value);
190      break;
191    case NMethodPropID::kDecoder:
192      if (codec.CreateDecoder)
193        return MethodToClassID(k_7zip_GUID_Data3_Decoder, codec.Id, value);
194      break;
195    case NMethodPropID::kEncoder:
196      if (codec.CreateEncoder)
197        return MethodToClassID(k_7zip_GUID_Data3_Encoder, codec.Id, value);
198      break;
199    case NMethodPropID::kDecoderIsAssigned:
200        value->vt = VT_BOOL;
201        value->boolVal = BoolToVARIANT_BOOL(codec.CreateDecoder != NULL);
202      break;
203    case NMethodPropID::kEncoderIsAssigned:
204        value->vt = VT_BOOL;
205        value->boolVal = BoolToVARIANT_BOOL(codec.CreateEncoder != NULL);
206      break;
207    case NMethodPropID::kPackStreams:
208      if (codec.NumStreams != 1)
209      {
210        value->vt = VT_UI4;
211        value->ulVal = (ULONG)codec.NumStreams;
212      }
213      break;
214    /*
215    case NMethodPropID::kIsFilter:
216      // if (codec.IsFilter)
217      {
218        value->vt = VT_BOOL;
219        value->boolVal = BoolToVARIANT_BOOL(codec.IsFilter);
220      }
221      break;
222    */
223    /*
224    case NMethodPropID::kDecoderFlags:
225      {
226        value->vt = VT_UI4;
227        value->ulVal = (ULONG)codec.DecoderFlags;
228      }
229      break;
230    case NMethodPropID::kEncoderFlags:
231      {
232        value->vt = VT_UI4;
233        value->ulVal = (ULONG)codec.EncoderFlags;
234      }
235      break;
236    */
237  }
238  return S_OK;
239}
240
241STDAPI GetNumberOfMethods(UINT32 *numCodecs)
242{
243  *numCodecs = g_NumCodecs;
244  return S_OK;
245}
246
247
248// ---------- Hashers ----------
249
250static int FindHasherClassId(const GUID *clsid) throw()
251{
252  if (clsid->Data1 != k_7zip_GUID_Data1 ||
253      clsid->Data2 != k_7zip_GUID_Data2 ||
254      clsid->Data3 != k_7zip_GUID_Data3_Hasher)
255    return -1;
256  UInt64 id = GetUi64(clsid->Data4);
257  for (unsigned i = 0; i < g_NumCodecs; i++)
258    if (id == g_Hashers[i]->Id)
259      return i;
260  return -1;
261}
262
263static HRESULT CreateHasher2(UInt32 index, IHasher **hasher)
264{
265  COM_TRY_BEGIN
266  *hasher = g_Hashers[index]->CreateHasher();
267  if (*hasher)
268    (*hasher)->AddRef();
269  return S_OK;
270  COM_TRY_END
271}
272
273STDAPI CreateHasher(const GUID *clsid, IHasher **outObject)
274{
275  COM_TRY_BEGIN
276  *outObject = 0;
277  int index = FindHasherClassId(clsid);
278  if (index < 0)
279    return CLASS_E_CLASSNOTAVAILABLE;
280  return CreateHasher2(index, outObject);
281  COM_TRY_END
282}
283
284STDAPI GetHasherProp(UInt32 codecIndex, PROPID propID, PROPVARIANT *value)
285{
286  ::VariantClear((VARIANTARG *)value);
287  const CHasherInfo &codec = *g_Hashers[codecIndex];
288  switch (propID)
289  {
290    case NMethodPropID::kID:
291      value->uhVal.QuadPart = (UInt64)codec.Id;
292      value->vt = VT_UI8;
293      break;
294    case NMethodPropID::kName:
295      SetPropFromAscii(codec.Name, value);
296      break;
297    case NMethodPropID::kEncoder:
298      if (codec.CreateHasher)
299        return MethodToClassID(k_7zip_GUID_Data3_Hasher, codec.Id, value);
300      break;
301    case NMethodPropID::kDigestSize:
302      value->ulVal = (ULONG)codec.DigestSize;
303      value->vt = VT_UI4;
304      break;
305  }
306  return S_OK;
307}
308
309class CHashers:
310  public IHashers,
311  public CMyUnknownImp
312{
313public:
314  MY_UNKNOWN_IMP1(IHashers)
315
316  STDMETHOD_(UInt32, GetNumHashers)();
317  STDMETHOD(GetHasherProp)(UInt32 index, PROPID propID, PROPVARIANT *value);
318  STDMETHOD(CreateHasher)(UInt32 index, IHasher **hasher);
319};
320
321STDAPI GetHashers(IHashers **hashers)
322{
323  COM_TRY_BEGIN
324  *hashers = new CHashers;
325  if (*hashers)
326    (*hashers)->AddRef();
327  return S_OK;
328  COM_TRY_END
329}
330
331STDMETHODIMP_(UInt32) CHashers::GetNumHashers()
332{
333  return g_NumHashers;
334}
335
336STDMETHODIMP CHashers::GetHasherProp(UInt32 index, PROPID propID, PROPVARIANT *value)
337{
338  return ::GetHasherProp(index, propID, value);
339}
340
341STDMETHODIMP CHashers::CreateHasher(UInt32 index, IHasher **hasher)
342{
343  return ::CreateHasher2(index, hasher);
344}
345