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