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 
16 extern unsigned g_NumCodecs;
17 extern const CCodecInfo *g_Codecs[];
18 
19 extern unsigned g_NumHashers;
20 extern const CHasherInfo *g_Hashers[];
21 
SetPropFromAscii(const char * s,PROPVARIANT * prop)22 static 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 
SetPropGUID(const GUID & guid,PROPVARIANT * value)35 static 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 
MethodToClassID(UInt16 typeId,CMethodId id,PROPVARIANT * value)42 static 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 
FindCodecClassId(const GUID * clsid,bool isCoder2,bool isFilter,bool & encode,int & index)52 static 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 
85 /*
86 #ifdef __GNUC__
87 #ifndef __clang__
88 #pragma GCC diagnostic ignored "-Wduplicated-branches"
89 #endif
90 #endif
91 */
92 
CreateCoderMain(unsigned index,bool encode,void ** coder)93 static HRESULT CreateCoderMain(unsigned index, bool encode, void **coder)
94 {
95   COM_TRY_BEGIN
96 
97   const CCodecInfo &codec = *g_Codecs[index];
98 
99   void *c;
100   if (encode)
101     c = codec.CreateEncoder();
102   else
103     c = codec.CreateDecoder();
104 
105   if (c)
106   {
107     IUnknown *unk;
108     unk = (IUnknown *)c;
109     /*
110     if (codec.IsFilter)
111       unk = (IUnknown *)(ICompressFilter *)c;
112     else if (codec.NumStreams != 1)
113       unk = (IUnknown *)(ICompressCoder2 *)c;
114     else
115       unk = (IUnknown *)(ICompressCoder *)c;
116     */
117     unk->AddRef();
118     *coder = c;
119   }
120   return S_OK;
121 
122   COM_TRY_END
123 }
124 
CreateCoder2(bool encode,UInt32 index,const GUID * iid,void ** outObject)125 static HRESULT CreateCoder2(bool encode, UInt32 index, const GUID *iid, void **outObject)
126 {
127   *outObject = NULL;
128 
129   const CCodecInfo &codec = *g_Codecs[index];
130 
131   if (encode ? !codec.CreateEncoder : !codec.CreateDecoder)
132     return CLASS_E_CLASSNOTAVAILABLE;
133 
134   if (codec.IsFilter)
135   {
136     if (*iid != IID_ICompressFilter) return E_NOINTERFACE;
137   }
138   else if (codec.NumStreams != 1)
139   {
140     if (*iid != IID_ICompressCoder2) return E_NOINTERFACE;
141   }
142   else
143   {
144     if (*iid != IID_ICompressCoder) return E_NOINTERFACE;
145   }
146 
147   return CreateCoderMain(index, encode, outObject);
148 }
149 
150 
151 STDAPI CreateDecoder(UInt32 index, const GUID *iid, void **outObject);
CreateDecoder(UInt32 index,const GUID * iid,void ** outObject)152 STDAPI CreateDecoder(UInt32 index, const GUID *iid, void **outObject)
153 {
154   return CreateCoder2(false, index, iid, outObject);
155 }
156 
157 
158 STDAPI CreateEncoder(UInt32 index, const GUID *iid, void **outObject);
CreateEncoder(UInt32 index,const GUID * iid,void ** outObject)159 STDAPI CreateEncoder(UInt32 index, const GUID *iid, void **outObject)
160 {
161   return CreateCoder2(true, index, iid, outObject);
162 }
163 
164 
165 STDAPI CreateCoder(const GUID *clsid, const GUID *iid, void **outObject);
CreateCoder(const GUID * clsid,const GUID * iid,void ** outObject)166 STDAPI CreateCoder(const GUID *clsid, const GUID *iid, void **outObject)
167 {
168   *outObject = NULL;
169 
170   bool isFilter = false;
171   bool isCoder2 = false;
172   bool isCoder = (*iid == IID_ICompressCoder) != 0;
173   if (!isCoder)
174   {
175     isFilter = (*iid == IID_ICompressFilter) != 0;
176     if (!isFilter)
177     {
178       isCoder2 = (*iid == IID_ICompressCoder2) != 0;
179       if (!isCoder2)
180         return E_NOINTERFACE;
181     }
182   }
183 
184   bool encode;
185   int codecIndex;
186   HRESULT res = FindCodecClassId(clsid, isCoder2, isFilter, encode, codecIndex);
187   if (res != S_OK)
188     return res;
189   if (codecIndex < 0)
190     return CLASS_E_CLASSNOTAVAILABLE;
191 
192   return CreateCoderMain(codecIndex, encode, outObject);
193 }
194 
195 
196 STDAPI GetMethodProperty(UInt32 codecIndex, PROPID propID, PROPVARIANT *value);
GetMethodProperty(UInt32 codecIndex,PROPID propID,PROPVARIANT * value)197 STDAPI GetMethodProperty(UInt32 codecIndex, PROPID propID, PROPVARIANT *value)
198 {
199   ::VariantClear((VARIANTARG *)value);
200   const CCodecInfo &codec = *g_Codecs[codecIndex];
201   switch (propID)
202   {
203     case NMethodPropID::kID:
204       value->uhVal.QuadPart = (UInt64)codec.Id;
205       value->vt = VT_UI8;
206       break;
207     case NMethodPropID::kName:
208       SetPropFromAscii(codec.Name, value);
209       break;
210     case NMethodPropID::kDecoder:
211       if (codec.CreateDecoder)
212         return MethodToClassID(k_7zip_GUID_Data3_Decoder, codec.Id, value);
213       break;
214     case NMethodPropID::kEncoder:
215       if (codec.CreateEncoder)
216         return MethodToClassID(k_7zip_GUID_Data3_Encoder, codec.Id, value);
217       break;
218     case NMethodPropID::kDecoderIsAssigned:
219         value->vt = VT_BOOL;
220         value->boolVal = BoolToVARIANT_BOOL(codec.CreateDecoder != NULL);
221       break;
222     case NMethodPropID::kEncoderIsAssigned:
223         value->vt = VT_BOOL;
224         value->boolVal = BoolToVARIANT_BOOL(codec.CreateEncoder != NULL);
225       break;
226     case NMethodPropID::kPackStreams:
227       if (codec.NumStreams != 1)
228       {
229         value->vt = VT_UI4;
230         value->ulVal = (ULONG)codec.NumStreams;
231       }
232       break;
233     case NMethodPropID::kIsFilter:
234       {
235         value->vt = VT_BOOL;
236         value->boolVal = BoolToVARIANT_BOOL(codec.IsFilter);
237       }
238       break;
239     /*
240     case NMethodPropID::kDecoderFlags:
241       {
242         value->vt = VT_UI4;
243         value->ulVal = (ULONG)codec.DecoderFlags;
244       }
245       break;
246     case NMethodPropID::kEncoderFlags:
247       {
248         value->vt = VT_UI4;
249         value->ulVal = (ULONG)codec.EncoderFlags;
250       }
251       break;
252     */
253   }
254   return S_OK;
255 }
256 
257 
258 STDAPI GetNumberOfMethods(UINT32 *numCodecs);
GetNumberOfMethods(UINT32 * numCodecs)259 STDAPI GetNumberOfMethods(UINT32 *numCodecs)
260 {
261   *numCodecs = g_NumCodecs;
262   return S_OK;
263 }
264 
265 
266 // ---------- Hashers ----------
267 
FindHasherClassId(const GUID * clsid)268 static int FindHasherClassId(const GUID *clsid) throw()
269 {
270   if (clsid->Data1 != k_7zip_GUID_Data1 ||
271       clsid->Data2 != k_7zip_GUID_Data2 ||
272       clsid->Data3 != k_7zip_GUID_Data3_Hasher)
273     return -1;
274   UInt64 id = GetUi64(clsid->Data4);
275   for (unsigned i = 0; i < g_NumCodecs; i++)
276     if (id == g_Hashers[i]->Id)
277       return i;
278   return -1;
279 }
280 
CreateHasher2(UInt32 index,IHasher ** hasher)281 static HRESULT CreateHasher2(UInt32 index, IHasher **hasher)
282 {
283   COM_TRY_BEGIN
284   *hasher = g_Hashers[index]->CreateHasher();
285   if (*hasher)
286     (*hasher)->AddRef();
287   return S_OK;
288   COM_TRY_END
289 }
290 
291 STDAPI CreateHasher(const GUID *clsid, IHasher **outObject);
CreateHasher(const GUID * clsid,IHasher ** outObject)292 STDAPI CreateHasher(const GUID *clsid, IHasher **outObject)
293 {
294   COM_TRY_BEGIN
295   *outObject = 0;
296   int index = FindHasherClassId(clsid);
297   if (index < 0)
298     return CLASS_E_CLASSNOTAVAILABLE;
299   return CreateHasher2(index, outObject);
300   COM_TRY_END
301 }
302 
303 STDAPI GetHasherProp(UInt32 codecIndex, PROPID propID, PROPVARIANT *value);
GetHasherProp(UInt32 codecIndex,PROPID propID,PROPVARIANT * value)304 STDAPI GetHasherProp(UInt32 codecIndex, PROPID propID, PROPVARIANT *value)
305 {
306   ::VariantClear((VARIANTARG *)value);
307   const CHasherInfo &codec = *g_Hashers[codecIndex];
308   switch (propID)
309   {
310     case NMethodPropID::kID:
311       value->uhVal.QuadPart = (UInt64)codec.Id;
312       value->vt = VT_UI8;
313       break;
314     case NMethodPropID::kName:
315       SetPropFromAscii(codec.Name, value);
316       break;
317     case NMethodPropID::kEncoder:
318       if (codec.CreateHasher)
319         return MethodToClassID(k_7zip_GUID_Data3_Hasher, codec.Id, value);
320       break;
321     case NMethodPropID::kDigestSize:
322       value->ulVal = (ULONG)codec.DigestSize;
323       value->vt = VT_UI4;
324       break;
325   }
326   return S_OK;
327 }
328 
329 class CHashers:
330   public IHashers,
331   public CMyUnknownImp
332 {
333 public:
334   MY_UNKNOWN_IMP1(IHashers)
335 
336   STDMETHOD_(UInt32, GetNumHashers)();
337   STDMETHOD(GetHasherProp)(UInt32 index, PROPID propID, PROPVARIANT *value);
338   STDMETHOD(CreateHasher)(UInt32 index, IHasher **hasher);
339 };
340 
341 STDAPI GetHashers(IHashers **hashers);
GetHashers(IHashers ** hashers)342 STDAPI GetHashers(IHashers **hashers)
343 {
344   COM_TRY_BEGIN
345   *hashers = new CHashers;
346   if (*hashers)
347     (*hashers)->AddRef();
348   return S_OK;
349   COM_TRY_END
350 }
351 
STDMETHODIMP_(UInt32)352 STDMETHODIMP_(UInt32) CHashers::GetNumHashers()
353 {
354   return g_NumHashers;
355 }
356 
GetHasherProp(UInt32 index,PROPID propID,PROPVARIANT * value)357 STDMETHODIMP CHashers::GetHasherProp(UInt32 index, PROPID propID, PROPVARIANT *value)
358 {
359   return ::GetHasherProp(index, propID, value);
360 }
361 
CreateHasher(UInt32 index,IHasher ** hasher)362 STDMETHODIMP CHashers::CreateHasher(UInt32 index, IHasher **hasher)
363 {
364   return ::CreateHasher2(index, hasher);
365 }
366