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