Imported Upstream version 9.20
[platform/upstream/7zip.git] / CPP / 7zip / Common / CreateCoder.cpp
1 // CreateCoder.cpp\r
2 \r
3 #include "StdAfx.h"\r
4 \r
5 #include "../../Windows/Defs.h"\r
6 #include "../../Windows/PropVariant.h"\r
7 \r
8 #include "CreateCoder.h"\r
9 \r
10 #include "FilterCoder.h"\r
11 #include "RegisterCodec.h"\r
12 \r
13 static const unsigned int kNumCodecsMax = 64;\r
14 unsigned int g_NumCodecs = 0;\r
15 const CCodecInfo *g_Codecs[kNumCodecsMax];\r
16 void RegisterCodec(const CCodecInfo *codecInfo)\r
17 {\r
18   if (g_NumCodecs < kNumCodecsMax)\r
19     g_Codecs[g_NumCodecs++] = codecInfo;\r
20 }\r
21 \r
22 #ifdef EXTERNAL_CODECS\r
23 static HRESULT ReadNumberOfStreams(ICompressCodecsInfo *codecsInfo, UInt32 index, PROPID propID, UInt32 &res)\r
24 {\r
25   NWindows::NCOM::CPropVariant prop;\r
26   RINOK(codecsInfo->GetProperty(index, propID, &prop));\r
27   if (prop.vt == VT_EMPTY)\r
28     res = 1;\r
29   else if (prop.vt == VT_UI4)\r
30     res = prop.ulVal;\r
31   else\r
32     return E_INVALIDARG;\r
33   return S_OK;\r
34 }\r
35 \r
36 static HRESULT ReadIsAssignedProp(ICompressCodecsInfo *codecsInfo, UInt32 index, PROPID propID, bool &res)\r
37 {\r
38   NWindows::NCOM::CPropVariant prop;\r
39   RINOK(codecsInfo->GetProperty(index, propID, &prop));\r
40   if (prop.vt == VT_EMPTY)\r
41     res = true;\r
42   else if (prop.vt == VT_BOOL)\r
43     res = VARIANT_BOOLToBool(prop.boolVal);\r
44   else\r
45     return E_INVALIDARG;\r
46   return S_OK;\r
47 }\r
48 \r
49 HRESULT LoadExternalCodecs(ICompressCodecsInfo *codecsInfo, CObjectVector<CCodecInfoEx> &externalCodecs)\r
50 {\r
51   UInt32 num;\r
52   RINOK(codecsInfo->GetNumberOfMethods(&num));\r
53   for (UInt32 i = 0; i < num; i++)\r
54   {\r
55     CCodecInfoEx info;\r
56     NWindows::NCOM::CPropVariant prop;\r
57     RINOK(codecsInfo->GetProperty(i, NMethodPropID::kID, &prop));\r
58     // if (prop.vt != VT_BSTR)\r
59     // info.Id.IDSize = (Byte)SysStringByteLen(prop.bstrVal);\r
60     // memmove(info.Id.ID, prop.bstrVal, info.Id.IDSize);\r
61     if (prop.vt != VT_UI8)\r
62     {\r
63       continue; // old Interface\r
64       // return E_INVALIDARG;\r
65     }\r
66     info.Id = prop.uhVal.QuadPart;\r
67     prop.Clear();\r
68     \r
69     RINOK(codecsInfo->GetProperty(i, NMethodPropID::kName, &prop));\r
70     if (prop.vt == VT_BSTR)\r
71       info.Name = prop.bstrVal;\r
72     else if (prop.vt != VT_EMPTY)\r
73       return E_INVALIDARG;;\r
74     \r
75     RINOK(ReadNumberOfStreams(codecsInfo, i, NMethodPropID::kInStreams, info.NumInStreams));\r
76     RINOK(ReadNumberOfStreams(codecsInfo, i, NMethodPropID::kOutStreams, info.NumOutStreams));\r
77     RINOK(ReadIsAssignedProp(codecsInfo, i, NMethodPropID::kEncoderIsAssigned, info.EncoderIsAssigned));\r
78     RINOK(ReadIsAssignedProp(codecsInfo, i, NMethodPropID::kDecoderIsAssigned, info.DecoderIsAssigned));\r
79     \r
80     externalCodecs.Add(info);\r
81   }\r
82   return S_OK;\r
83 }\r
84 \r
85 #endif\r
86 \r
87 bool FindMethod(\r
88   #ifdef EXTERNAL_CODECS\r
89   ICompressCodecsInfo * /* codecsInfo */, const CObjectVector<CCodecInfoEx> *externalCodecs,\r
90   #endif\r
91   const UString &name,\r
92   CMethodId &methodId, UInt32 &numInStreams, UInt32 &numOutStreams)\r
93 {\r
94   UInt32 i;\r
95   for (i = 0; i < g_NumCodecs; i++)\r
96   {\r
97     const CCodecInfo &codec = *g_Codecs[i];\r
98     if (name.CompareNoCase(codec.Name) == 0)\r
99     {\r
100       methodId = codec.Id;\r
101       numInStreams = codec.NumInStreams;\r
102       numOutStreams = 1;\r
103       return true;\r
104     }\r
105   }\r
106   #ifdef EXTERNAL_CODECS\r
107   if (externalCodecs)\r
108     for (i = 0; i < (UInt32)externalCodecs->Size(); i++)\r
109     {\r
110       const CCodecInfoEx &codec = (*externalCodecs)[i];\r
111       if (codec.Name.CompareNoCase(name) == 0)\r
112       {\r
113         methodId = codec.Id;\r
114         numInStreams = codec.NumInStreams;\r
115         numOutStreams = codec.NumOutStreams;\r
116         return true;\r
117       }\r
118     }\r
119   #endif\r
120   return false;\r
121 }\r
122 \r
123 bool FindMethod(\r
124   #ifdef EXTERNAL_CODECS\r
125   ICompressCodecsInfo * /* codecsInfo */, const CObjectVector<CCodecInfoEx> *externalCodecs,\r
126   #endif\r
127   CMethodId methodId, UString &name)\r
128 {\r
129   UInt32 i;\r
130   for (i = 0; i < g_NumCodecs; i++)\r
131   {\r
132     const CCodecInfo &codec = *g_Codecs[i];\r
133     if (methodId == codec.Id)\r
134     {\r
135       name = codec.Name;\r
136       return true;\r
137     }\r
138   }\r
139   #ifdef EXTERNAL_CODECS\r
140   if (externalCodecs)\r
141     for (i = 0; i < (UInt32)externalCodecs->Size(); i++)\r
142     {\r
143       const CCodecInfoEx &codec = (*externalCodecs)[i];\r
144       if (methodId == codec.Id)\r
145       {\r
146         name = codec.Name;\r
147         return true;\r
148       }\r
149     }\r
150   #endif\r
151   return false;\r
152 }\r
153 \r
154 HRESULT CreateCoder(\r
155   DECL_EXTERNAL_CODECS_LOC_VARS\r
156   CMethodId methodId,\r
157   CMyComPtr<ICompressFilter> &filter,\r
158   CMyComPtr<ICompressCoder> &coder,\r
159   CMyComPtr<ICompressCoder2> &coder2,\r
160   bool encode, bool onlyCoder)\r
161 {\r
162   bool created = false;\r
163   UInt32 i;\r
164   for (i = 0; i < g_NumCodecs; i++)\r
165   {\r
166     const CCodecInfo &codec = *g_Codecs[i];\r
167     if (codec.Id == methodId)\r
168     {\r
169       if (encode)\r
170       {\r
171         if (codec.CreateEncoder)\r
172         {\r
173           void *p = codec.CreateEncoder();\r
174           if (codec.IsFilter) filter = (ICompressFilter *)p;\r
175           else if (codec.NumInStreams == 1) coder = (ICompressCoder *)p;\r
176           else coder2 = (ICompressCoder2 *)p;\r
177           created = (p != 0);\r
178           break;\r
179         }\r
180       }\r
181       else\r
182         if (codec.CreateDecoder)\r
183         {\r
184           void *p = codec.CreateDecoder();\r
185           if (codec.IsFilter) filter = (ICompressFilter *)p;\r
186           else if (codec.NumInStreams == 1) coder = (ICompressCoder *)p;\r
187           else coder2 = (ICompressCoder2 *)p;\r
188           created = (p != 0);\r
189           break;\r
190         }\r
191     }\r
192   }\r
193 \r
194   #ifdef EXTERNAL_CODECS\r
195   if (!created && externalCodecs)\r
196     for (i = 0; i < (UInt32)externalCodecs->Size(); i++)\r
197     {\r
198       const CCodecInfoEx &codec = (*externalCodecs)[i];\r
199       if (codec.Id == methodId)\r
200       {\r
201         if (encode)\r
202         {\r
203           if (codec.EncoderIsAssigned)\r
204           {\r
205             if (codec.IsSimpleCodec())\r
206             {\r
207               HRESULT result = codecsInfo->CreateEncoder(i, &IID_ICompressCoder, (void **)&coder);\r
208               if (result != S_OK && result != E_NOINTERFACE && result != CLASS_E_CLASSNOTAVAILABLE)\r
209                 return result;\r
210               if (!coder)\r
211               {\r
212                 RINOK(codecsInfo->CreateEncoder(i, &IID_ICompressFilter, (void **)&filter));\r
213               }\r
214             }\r
215             else\r
216             {\r
217               RINOK(codecsInfo->CreateEncoder(i, &IID_ICompressCoder2, (void **)&coder2));\r
218             }\r
219             break;\r
220           }\r
221         }\r
222         else\r
223           if (codec.DecoderIsAssigned)\r
224           {\r
225             if (codec.IsSimpleCodec())\r
226             {\r
227               HRESULT result = codecsInfo->CreateDecoder(i, &IID_ICompressCoder, (void **)&coder);\r
228               if (result != S_OK && result != E_NOINTERFACE && result != CLASS_E_CLASSNOTAVAILABLE)\r
229                 return result;\r
230               if (!coder)\r
231               {\r
232                 RINOK(codecsInfo->CreateDecoder(i, &IID_ICompressFilter, (void **)&filter));\r
233               }\r
234             }\r
235             else\r
236             {\r
237               RINOK(codecsInfo->CreateDecoder(i, &IID_ICompressCoder2, (void **)&coder2));\r
238             }\r
239             break;\r
240           }\r
241       }\r
242     }\r
243   #endif\r
244 \r
245   if (onlyCoder && filter)\r
246   {\r
247     CFilterCoder *coderSpec = new CFilterCoder;\r
248     coder = coderSpec;\r
249     coderSpec->Filter = filter;\r
250   }\r
251   return S_OK;\r
252 }\r
253 \r
254 HRESULT CreateCoder(\r
255   DECL_EXTERNAL_CODECS_LOC_VARS\r
256   CMethodId methodId,\r
257   CMyComPtr<ICompressCoder> &coder,\r
258   CMyComPtr<ICompressCoder2> &coder2,\r
259   bool encode)\r
260 {\r
261   CMyComPtr<ICompressFilter> filter;\r
262   return CreateCoder(\r
263     EXTERNAL_CODECS_LOC_VARS\r
264     methodId,\r
265     filter, coder, coder2, encode, true);\r
266 }\r
267 \r
268 HRESULT CreateCoder(\r
269   DECL_EXTERNAL_CODECS_LOC_VARS\r
270   CMethodId methodId,\r
271   CMyComPtr<ICompressCoder> &coder, bool encode)\r
272 {\r
273   CMyComPtr<ICompressFilter> filter;\r
274   CMyComPtr<ICompressCoder2> coder2;\r
275   return CreateCoder(\r
276     EXTERNAL_CODECS_LOC_VARS\r
277     methodId,\r
278     coder, coder2, encode);\r
279 }\r
280 \r
281 HRESULT CreateFilter(\r
282   DECL_EXTERNAL_CODECS_LOC_VARS\r
283   CMethodId methodId,\r
284   CMyComPtr<ICompressFilter> &filter,\r
285   bool encode)\r
286 {\r
287   CMyComPtr<ICompressCoder> coder;\r
288   CMyComPtr<ICompressCoder2> coder2;\r
289   return CreateCoder(\r
290     EXTERNAL_CODECS_LOC_VARS\r
291     methodId,\r
292     filter, coder, coder2, encode, false);\r
293 }\r