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 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 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 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 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 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 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 139 STDAPI CreateDecoder(UInt32 index, const GUID *iid, void **outObject) 140 { 141 return CreateCoder2(false, index, iid, outObject); 142 } 143 144 STDAPI CreateEncoder(UInt32 index, const GUID *iid, void **outObject) 145 { 146 return CreateCoder2(true, index, iid, outObject); 147 } 148 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 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 241 STDAPI GetNumberOfMethods(UINT32 *numCodecs) 242 { 243 *numCodecs = g_NumCodecs; 244 return S_OK; 245 } 246 247 248 // ---------- Hashers ---------- 249 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 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 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 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 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 331 STDMETHODIMP_(UInt32) CHashers::GetNumHashers() 332 { 333 return g_NumHashers; 334 } 335 336 STDMETHODIMP CHashers::GetHasherProp(UInt32 index, PROPID propID, PROPVARIANT *value) 337 { 338 return ::GetHasherProp(index, propID, value); 339 } 340 341 STDMETHODIMP CHashers::CreateHasher(UInt32 index, IHasher **hasher) 342 { 343 return ::CreateHasher2(index, hasher); 344 } 345