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