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 
CreateCoderMain(unsigned index,bool encode,void ** coder)85 static 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 
CreateCoder2(bool encode,UInt32 index,const GUID * iid,void ** outObject)114 static 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 
CreateDecoder(UInt32 index,const GUID * iid,void ** outObject)139 STDAPI CreateDecoder(UInt32 index, const GUID *iid, void **outObject)
140 {
141   return CreateCoder2(false, index, iid, outObject);
142 }
143 
CreateEncoder(UInt32 index,const GUID * iid,void ** outObject)144 STDAPI CreateEncoder(UInt32 index, const GUID *iid, void **outObject)
145 {
146   return CreateCoder2(true, index, iid, outObject);
147 }
148 
CreateCoder(const GUID * clsid,const GUID * iid,void ** outObject)149 STDAPI 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 
GetMethodProperty(UInt32 codecIndex,PROPID propID,PROPVARIANT * value)178 STDAPI 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 
GetNumberOfMethods(UINT32 * numCodecs)241 STDAPI GetNumberOfMethods(UINT32 *numCodecs)
242 {
243   *numCodecs = g_NumCodecs;
244   return S_OK;
245 }
246 
247 
248 // ---------- Hashers ----------
249 
FindHasherClassId(const GUID * clsid)250 static 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 
CreateHasher2(UInt32 index,IHasher ** hasher)263 static 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 
CreateHasher(const GUID * clsid,IHasher ** outObject)273 STDAPI 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 
GetHasherProp(UInt32 codecIndex,PROPID propID,PROPVARIANT * value)284 STDAPI 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 
309 class CHashers:
310   public IHashers,
311   public CMyUnknownImp
312 {
313 public:
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 
GetHashers(IHashers ** hashers)321 STDAPI 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 
STDMETHODIMP_(UInt32)331 STDMETHODIMP_(UInt32) CHashers::GetNumHashers()
332 {
333   return g_NumHashers;
334 }
335 
GetHasherProp(UInt32 index,PROPID propID,PROPVARIANT * value)336 STDMETHODIMP CHashers::GetHasherProp(UInt32 index, PROPID propID, PROPVARIANT *value)
337 {
338   return ::GetHasherProp(index, propID, value);
339 }
340 
CreateHasher(UInt32 index,IHasher ** hasher)341 STDMETHODIMP CHashers::CreateHasher(UInt32 index, IHasher **hasher)
342 {
343   return ::CreateHasher2(index, hasher);
344 }
345