Home | History | Annotate | Download | only in Compress
      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