1// CodecExports.cpp 2 3#include "StdAfx.h" 4 5#include "../../../C/CpuArch.h" 6#include "../../../C/7zVersion.h" 7 8#include "../../Common/ComTry.h" 9#include "../../Common/MyCom.h" 10 11#include "../../Windows/Defs.h" 12#include "../../Windows/PropVariant.h" 13 14#include "../ICoder.h" 15 16#include "../Common/RegisterCodec.h" 17 18extern unsigned g_NumCodecs; 19extern const CCodecInfo *g_Codecs[]; 20 21extern unsigned g_NumHashers; 22extern const CHasherInfo *g_Hashers[]; 23 24static void SetPropFromAscii(const char *s, PROPVARIANT *prop) throw() 25{ 26 const UINT len = (UINT)strlen(s); 27 BSTR dest = ::SysAllocStringLen(NULL, len); 28 if (dest) 29 { 30 for (UINT i = 0; i <= len; i++) 31 dest[i] = (Byte)s[i]; 32 prop->bstrVal = dest; 33 prop->vt = VT_BSTR; 34 } 35} 36 37static inline HRESULT SetPropGUID(const GUID &guid, PROPVARIANT *value) throw() 38{ 39 if ((value->bstrVal = ::SysAllocStringByteLen((const char *)&guid, sizeof(guid))) != NULL) 40 value->vt = VT_BSTR; 41 return S_OK; 42} 43 44static HRESULT MethodToClassID(UInt16 typeId, CMethodId id, PROPVARIANT *value) throw() 45{ 46 GUID clsId; 47 clsId.Data1 = k_7zip_GUID_Data1; 48 clsId.Data2 = k_7zip_GUID_Data2; 49 clsId.Data3 = typeId; 50 SetUi64(clsId.Data4, id) 51 return SetPropGUID(clsId, value); 52} 53 54static HRESULT FindCodecClassId(const GUID *clsid, bool isCoder2, bool isFilter, bool &encode, int &index) throw() 55{ 56 index = -1; 57 if (clsid->Data1 != k_7zip_GUID_Data1 || 58 clsid->Data2 != k_7zip_GUID_Data2) 59 return S_OK; 60 61 encode = true; 62 63 if (clsid->Data3 == k_7zip_GUID_Data3_Decoder) encode = false; 64 else if (clsid->Data3 != k_7zip_GUID_Data3_Encoder) return S_OK; 65 66 const UInt64 id = GetUi64(clsid->Data4); 67 68 for (unsigned i = 0; i < g_NumCodecs; i++) 69 { 70 const CCodecInfo &codec = *g_Codecs[i]; 71 72 if (id != codec.Id 73 || (encode ? !codec.CreateEncoder : !codec.CreateDecoder) 74 || (isFilter ? !codec.IsFilter : codec.IsFilter)) 75 continue; 76 77 if (codec.NumStreams == 1 ? isCoder2 : !isCoder2) 78 return E_NOINTERFACE; 79 80 index = (int)i; 81 return S_OK; 82 } 83 84 return S_OK; 85} 86 87/* 88#ifdef __GNUC__ 89#ifndef __clang__ 90#pragma GCC diagnostic ignored "-Wduplicated-branches" 91#endif 92#endif 93*/ 94 95static HRESULT CreateCoderMain(unsigned index, bool encode, void **coder) 96{ 97 COM_TRY_BEGIN 98 99 const CCodecInfo &codec = *g_Codecs[index]; 100 101 void *c; 102 if (encode) 103 c = codec.CreateEncoder(); 104 else 105 c = codec.CreateDecoder(); 106 107 if (c) 108 { 109 IUnknown *unk; 110 unk = (IUnknown *)c; 111 /* 112 if (codec.IsFilter) 113 unk = (IUnknown *)(ICompressFilter *)c; 114 else if (codec.NumStreams != 1) 115 unk = (IUnknown *)(ICompressCoder2 *)c; 116 else 117 unk = (IUnknown *)(ICompressCoder *)c; 118 */ 119 unk->AddRef(); 120 *coder = c; 121 } 122 return S_OK; 123 124 COM_TRY_END 125} 126 127static HRESULT CreateCoder2(bool encode, UInt32 index, const GUID *iid, void **outObject) 128{ 129 *outObject = NULL; 130 131 const CCodecInfo &codec = *g_Codecs[index]; 132 133 if (encode ? !codec.CreateEncoder : !codec.CreateDecoder) 134 return CLASS_E_CLASSNOTAVAILABLE; 135 136 if (codec.IsFilter) 137 { 138 if (*iid != IID_ICompressFilter) return E_NOINTERFACE; 139 } 140 else if (codec.NumStreams != 1) 141 { 142 if (*iid != IID_ICompressCoder2) return E_NOINTERFACE; 143 } 144 else 145 { 146 if (*iid != IID_ICompressCoder) return E_NOINTERFACE; 147 } 148 149 return CreateCoderMain(index, encode, outObject); 150} 151 152 153STDAPI CreateDecoder(UInt32 index, const GUID *iid, void **outObject); 154STDAPI CreateDecoder(UInt32 index, const GUID *iid, void **outObject) 155{ 156 return CreateCoder2(false, index, iid, outObject); 157} 158 159 160STDAPI CreateEncoder(UInt32 index, const GUID *iid, void **outObject); 161STDAPI CreateEncoder(UInt32 index, const GUID *iid, void **outObject) 162{ 163 return CreateCoder2(true, index, iid, outObject); 164} 165 166 167STDAPI CreateCoder(const GUID *clsid, const GUID *iid, void **outObject); 168STDAPI CreateCoder(const GUID *clsid, const GUID *iid, void **outObject) 169{ 170 *outObject = NULL; 171 172 bool isFilter = false; 173 bool isCoder2 = false; 174 const bool isCoder = (*iid == IID_ICompressCoder) != 0; 175 if (!isCoder) 176 { 177 isFilter = (*iid == IID_ICompressFilter) != 0; 178 if (!isFilter) 179 { 180 isCoder2 = (*iid == IID_ICompressCoder2) != 0; 181 if (!isCoder2) 182 return E_NOINTERFACE; 183 } 184 } 185 186 bool encode; 187 int codecIndex; 188 const HRESULT res = FindCodecClassId(clsid, isCoder2, isFilter, encode, codecIndex); 189 if (res != S_OK) 190 return res; 191 if (codecIndex < 0) 192 return CLASS_E_CLASSNOTAVAILABLE; 193 194 return CreateCoderMain((unsigned)codecIndex, encode, outObject); 195} 196 197 198STDAPI GetMethodProperty(UInt32 codecIndex, PROPID propID, PROPVARIANT *value); 199STDAPI GetMethodProperty(UInt32 codecIndex, PROPID propID, PROPVARIANT *value) 200{ 201 ::VariantClear((VARIANTARG *)value); 202 const CCodecInfo &codec = *g_Codecs[codecIndex]; 203 switch (propID) 204 { 205 case NMethodPropID::kID: 206 value->uhVal.QuadPart = (UInt64)codec.Id; 207 value->vt = VT_UI8; 208 break; 209 case NMethodPropID::kName: 210 SetPropFromAscii(codec.Name, value); 211 break; 212 case NMethodPropID::kDecoder: 213 if (codec.CreateDecoder) 214 return MethodToClassID(k_7zip_GUID_Data3_Decoder, codec.Id, value); 215 break; 216 case NMethodPropID::kEncoder: 217 if (codec.CreateEncoder) 218 return MethodToClassID(k_7zip_GUID_Data3_Encoder, codec.Id, value); 219 break; 220 case NMethodPropID::kDecoderIsAssigned: 221 value->vt = VT_BOOL; 222 value->boolVal = BoolToVARIANT_BOOL(codec.CreateDecoder != NULL); 223 break; 224 case NMethodPropID::kEncoderIsAssigned: 225 value->vt = VT_BOOL; 226 value->boolVal = BoolToVARIANT_BOOL(codec.CreateEncoder != NULL); 227 break; 228 case NMethodPropID::kPackStreams: 229 if (codec.NumStreams != 1) 230 { 231 value->vt = VT_UI4; 232 value->ulVal = (ULONG)codec.NumStreams; 233 } 234 break; 235 case NMethodPropID::kIsFilter: 236 { 237 value->vt = VT_BOOL; 238 value->boolVal = BoolToVARIANT_BOOL(codec.IsFilter); 239 } 240 break; 241 /* 242 case NMethodPropID::kDecoderFlags: 243 { 244 value->vt = VT_UI4; 245 value->ulVal = (ULONG)codec.DecoderFlags; 246 } 247 break; 248 case NMethodPropID::kEncoderFlags: 249 { 250 value->vt = VT_UI4; 251 value->ulVal = (ULONG)codec.EncoderFlags; 252 } 253 break; 254 */ 255 } 256 return S_OK; 257} 258 259 260STDAPI GetNumberOfMethods(UInt32 *numCodecs); 261STDAPI GetNumberOfMethods(UInt32 *numCodecs) 262{ 263 *numCodecs = g_NumCodecs; 264 return S_OK; 265} 266 267 268// ---------- Hashers ---------- 269 270static int FindHasherClassId(const GUID *clsid) throw() 271{ 272 if (clsid->Data1 != k_7zip_GUID_Data1 || 273 clsid->Data2 != k_7zip_GUID_Data2 || 274 clsid->Data3 != k_7zip_GUID_Data3_Hasher) 275 return -1; 276 const UInt64 id = GetUi64(clsid->Data4); 277 for (unsigned i = 0; i < g_NumCodecs; i++) 278 if (id == g_Hashers[i]->Id) 279 return (int)i; 280 return -1; 281} 282 283static HRESULT CreateHasher2(UInt32 index, IHasher **hasher) 284{ 285 COM_TRY_BEGIN 286 *hasher = g_Hashers[index]->CreateHasher(); 287 if (*hasher) 288 (*hasher)->AddRef(); 289 return S_OK; 290 COM_TRY_END 291} 292 293STDAPI CreateHasher(const GUID *clsid, IHasher **outObject); 294STDAPI CreateHasher(const GUID *clsid, IHasher **outObject) 295{ 296 COM_TRY_BEGIN 297 *outObject = NULL; 298 const int index = FindHasherClassId(clsid); 299 if (index < 0) 300 return CLASS_E_CLASSNOTAVAILABLE; 301 return CreateHasher2((UInt32)(unsigned)index, outObject); 302 COM_TRY_END 303} 304 305STDAPI GetHasherProp(UInt32 codecIndex, PROPID propID, PROPVARIANT *value); 306STDAPI GetHasherProp(UInt32 codecIndex, PROPID propID, PROPVARIANT *value) 307{ 308 ::VariantClear((VARIANTARG *)value); 309 const CHasherInfo &codec = *g_Hashers[codecIndex]; 310 switch (propID) 311 { 312 case NMethodPropID::kID: 313 value->uhVal.QuadPart = (UInt64)codec.Id; 314 value->vt = VT_UI8; 315 break; 316 case NMethodPropID::kName: 317 SetPropFromAscii(codec.Name, value); 318 break; 319 case NMethodPropID::kEncoder: 320 if (codec.CreateHasher) 321 return MethodToClassID(k_7zip_GUID_Data3_Hasher, codec.Id, value); 322 break; 323 case NMethodPropID::kDigestSize: 324 value->ulVal = (ULONG)codec.DigestSize; 325 value->vt = VT_UI4; 326 break; 327 } 328 return S_OK; 329} 330 331Z7_CLASS_IMP_COM_1(CHashers, IHashers) }; 332 333STDAPI GetHashers(IHashers **hashers); 334STDAPI GetHashers(IHashers **hashers) 335{ 336 COM_TRY_BEGIN 337 *hashers = new CHashers; 338 if (*hashers) 339 (*hashers)->AddRef(); 340 return S_OK; 341 COM_TRY_END 342} 343 344Z7_COM7F_IMF2(UInt32, CHashers::GetNumHashers()) 345{ 346 return g_NumHashers; 347} 348 349Z7_COM7F_IMF(CHashers::GetHasherProp(UInt32 index, PROPID propID, PROPVARIANT *value)) 350{ 351 return ::GetHasherProp(index, propID, value); 352} 353 354Z7_COM7F_IMF(CHashers::CreateHasher(UInt32 index, IHasher **hasher)) 355{ 356 return ::CreateHasher2(index, hasher); 357} 358 359 360STDAPI GetModuleProp(PROPID propID, PROPVARIANT *value); 361STDAPI GetModuleProp(PROPID propID, PROPVARIANT *value) 362{ 363 ::VariantClear((VARIANTARG *)value); 364 switch (propID) 365 { 366 case NModulePropID::kInterfaceType: 367 { 368 NWindows::NCOM::PropVarEm_Set_UInt32(value, NModuleInterfaceType::k_IUnknown_VirtDestructor_ThisModule); 369 break; 370 } 371 case NModulePropID::kVersion: 372 { 373 NWindows::NCOM::PropVarEm_Set_UInt32(value, (MY_VER_MAJOR << 16) | MY_VER_MINOR); 374 break; 375 } 376 } 377 return S_OK; 378} 379