diff options
Diffstat (limited to 'CPP/7zip/Common/CreateCoder.cpp')
-rw-r--r-- | CPP/7zip/Common/CreateCoder.cpp | 545 |
1 files changed, 545 insertions, 0 deletions
diff --git a/CPP/7zip/Common/CreateCoder.cpp b/CPP/7zip/Common/CreateCoder.cpp new file mode 100644 index 0000000..872f17f --- /dev/null +++ b/CPP/7zip/Common/CreateCoder.cpp | |||
@@ -0,0 +1,545 @@ | |||
1 | // CreateCoder.cpp | ||
2 | |||
3 | #include "StdAfx.h" | ||
4 | |||
5 | #include "../../Windows/Defs.h" | ||
6 | #include "../../Windows/PropVariant.h" | ||
7 | |||
8 | #include "CreateCoder.h" | ||
9 | |||
10 | #include "FilterCoder.h" | ||
11 | #include "RegisterCodec.h" | ||
12 | |||
13 | static const unsigned kNumCodecsMax = 64; | ||
14 | extern | ||
15 | unsigned g_NumCodecs; | ||
16 | unsigned g_NumCodecs = 0; | ||
17 | extern | ||
18 | const CCodecInfo *g_Codecs[]; | ||
19 | const CCodecInfo *g_Codecs[kNumCodecsMax]; | ||
20 | |||
21 | // We use g_ExternalCodecs in other stages. | ||
22 | #ifdef EXTERNAL_CODECS | ||
23 | /* | ||
24 | extern CExternalCodecs g_ExternalCodecs; | ||
25 | #define CHECK_GLOBAL_CODECS \ | ||
26 | if (!__externalCodecs || !__externalCodecs->IsSet()) __externalCodecs = &g_ExternalCodecs; | ||
27 | */ | ||
28 | #define CHECK_GLOBAL_CODECS | ||
29 | #endif | ||
30 | |||
31 | |||
32 | void RegisterCodec(const CCodecInfo *codecInfo) throw() | ||
33 | { | ||
34 | if (g_NumCodecs < kNumCodecsMax) | ||
35 | g_Codecs[g_NumCodecs++] = codecInfo; | ||
36 | } | ||
37 | |||
38 | static const unsigned kNumHashersMax = 16; | ||
39 | extern | ||
40 | unsigned g_NumHashers; | ||
41 | unsigned g_NumHashers = 0; | ||
42 | extern | ||
43 | const CHasherInfo *g_Hashers[]; | ||
44 | const CHasherInfo *g_Hashers[kNumHashersMax]; | ||
45 | |||
46 | void RegisterHasher(const CHasherInfo *hashInfo) throw() | ||
47 | { | ||
48 | if (g_NumHashers < kNumHashersMax) | ||
49 | g_Hashers[g_NumHashers++] = hashInfo; | ||
50 | } | ||
51 | |||
52 | |||
53 | #ifdef EXTERNAL_CODECS | ||
54 | |||
55 | static HRESULT ReadNumberOfStreams(ICompressCodecsInfo *codecsInfo, UInt32 index, PROPID propID, UInt32 &res) | ||
56 | { | ||
57 | NWindows::NCOM::CPropVariant prop; | ||
58 | RINOK(codecsInfo->GetProperty(index, propID, &prop)); | ||
59 | if (prop.vt == VT_EMPTY) | ||
60 | res = 1; | ||
61 | else if (prop.vt == VT_UI4) | ||
62 | res = prop.ulVal; | ||
63 | else | ||
64 | return E_INVALIDARG; | ||
65 | return S_OK; | ||
66 | } | ||
67 | |||
68 | static HRESULT ReadIsAssignedProp(ICompressCodecsInfo *codecsInfo, UInt32 index, PROPID propID, bool &res) | ||
69 | { | ||
70 | NWindows::NCOM::CPropVariant prop; | ||
71 | RINOK(codecsInfo->GetProperty(index, propID, &prop)); | ||
72 | if (prop.vt == VT_EMPTY) | ||
73 | res = true; | ||
74 | else if (prop.vt == VT_BOOL) | ||
75 | res = VARIANT_BOOLToBool(prop.boolVal); | ||
76 | else | ||
77 | return E_INVALIDARG; | ||
78 | return S_OK; | ||
79 | } | ||
80 | |||
81 | HRESULT CExternalCodecs::Load() | ||
82 | { | ||
83 | Codecs.Clear(); | ||
84 | Hashers.Clear(); | ||
85 | |||
86 | if (GetCodecs) | ||
87 | { | ||
88 | CCodecInfoEx info; | ||
89 | |||
90 | UString s; | ||
91 | UInt32 num; | ||
92 | RINOK(GetCodecs->GetNumMethods(&num)); | ||
93 | |||
94 | for (UInt32 i = 0; i < num; i++) | ||
95 | { | ||
96 | NWindows::NCOM::CPropVariant prop; | ||
97 | |||
98 | RINOK(GetCodecs->GetProperty(i, NMethodPropID::kID, &prop)); | ||
99 | if (prop.vt != VT_UI8) | ||
100 | continue; // old Interface | ||
101 | info.Id = prop.uhVal.QuadPart; | ||
102 | |||
103 | prop.Clear(); | ||
104 | |||
105 | info.Name.Empty(); | ||
106 | RINOK(GetCodecs->GetProperty(i, NMethodPropID::kName, &prop)); | ||
107 | if (prop.vt == VT_BSTR) | ||
108 | info.Name.SetFromWStr_if_Ascii(prop.bstrVal); | ||
109 | else if (prop.vt != VT_EMPTY) | ||
110 | continue; | ||
111 | |||
112 | RINOK(ReadNumberOfStreams(GetCodecs, i, NMethodPropID::kPackStreams, info.NumStreams)); | ||
113 | { | ||
114 | UInt32 numUnpackStreams = 1; | ||
115 | RINOK(ReadNumberOfStreams(GetCodecs, i, NMethodPropID::kUnpackStreams, numUnpackStreams)); | ||
116 | if (numUnpackStreams != 1) | ||
117 | continue; | ||
118 | } | ||
119 | RINOK(ReadIsAssignedProp(GetCodecs, i, NMethodPropID::kEncoderIsAssigned, info.EncoderIsAssigned)); | ||
120 | RINOK(ReadIsAssignedProp(GetCodecs, i, NMethodPropID::kDecoderIsAssigned, info.DecoderIsAssigned)); | ||
121 | RINOK(ReadIsAssignedProp(GetCodecs, i, NMethodPropID::kIsFilter, info.IsFilter)); | ||
122 | |||
123 | Codecs.Add(info); | ||
124 | } | ||
125 | } | ||
126 | |||
127 | if (GetHashers) | ||
128 | { | ||
129 | UInt32 num = GetHashers->GetNumHashers(); | ||
130 | CHasherInfoEx info; | ||
131 | |||
132 | for (UInt32 i = 0; i < num; i++) | ||
133 | { | ||
134 | NWindows::NCOM::CPropVariant prop; | ||
135 | |||
136 | RINOK(GetHashers->GetHasherProp(i, NMethodPropID::kID, &prop)); | ||
137 | if (prop.vt != VT_UI8) | ||
138 | continue; | ||
139 | info.Id = prop.uhVal.QuadPart; | ||
140 | |||
141 | prop.Clear(); | ||
142 | |||
143 | info.Name.Empty(); | ||
144 | RINOK(GetHashers->GetHasherProp(i, NMethodPropID::kName, &prop)); | ||
145 | if (prop.vt == VT_BSTR) | ||
146 | info.Name.SetFromWStr_if_Ascii(prop.bstrVal); | ||
147 | else if (prop.vt != VT_EMPTY) | ||
148 | continue; | ||
149 | |||
150 | Hashers.Add(info); | ||
151 | } | ||
152 | } | ||
153 | |||
154 | return S_OK; | ||
155 | } | ||
156 | |||
157 | #endif | ||
158 | |||
159 | |||
160 | int FindMethod_Index( | ||
161 | DECL_EXTERNAL_CODECS_LOC_VARS | ||
162 | const AString &name, | ||
163 | bool encode, | ||
164 | CMethodId &methodId, | ||
165 | UInt32 &numStreams) | ||
166 | { | ||
167 | unsigned i; | ||
168 | for (i = 0; i < g_NumCodecs; i++) | ||
169 | { | ||
170 | const CCodecInfo &codec = *g_Codecs[i]; | ||
171 | if ((encode ? codec.CreateEncoder : codec.CreateDecoder) | ||
172 | && StringsAreEqualNoCase_Ascii(name, codec.Name)) | ||
173 | { | ||
174 | methodId = codec.Id; | ||
175 | numStreams = codec.NumStreams; | ||
176 | return (int)i; | ||
177 | } | ||
178 | } | ||
179 | |||
180 | #ifdef EXTERNAL_CODECS | ||
181 | |||
182 | CHECK_GLOBAL_CODECS | ||
183 | |||
184 | if (__externalCodecs) | ||
185 | for (i = 0; i < __externalCodecs->Codecs.Size(); i++) | ||
186 | { | ||
187 | const CCodecInfoEx &codec = __externalCodecs->Codecs[i]; | ||
188 | if ((encode ? codec.EncoderIsAssigned : codec.DecoderIsAssigned) | ||
189 | && StringsAreEqualNoCase_Ascii(name, codec.Name)) | ||
190 | { | ||
191 | methodId = codec.Id; | ||
192 | numStreams = codec.NumStreams; | ||
193 | return (int)(g_NumCodecs + i); | ||
194 | } | ||
195 | } | ||
196 | |||
197 | #endif | ||
198 | |||
199 | return -1; | ||
200 | } | ||
201 | |||
202 | |||
203 | static int FindMethod_Index( | ||
204 | DECL_EXTERNAL_CODECS_LOC_VARS | ||
205 | CMethodId methodId, bool encode) | ||
206 | { | ||
207 | unsigned i; | ||
208 | for (i = 0; i < g_NumCodecs; i++) | ||
209 | { | ||
210 | const CCodecInfo &codec = *g_Codecs[i]; | ||
211 | if (codec.Id == methodId && (encode ? codec.CreateEncoder : codec.CreateDecoder)) | ||
212 | return (int)i; | ||
213 | } | ||
214 | |||
215 | #ifdef EXTERNAL_CODECS | ||
216 | |||
217 | CHECK_GLOBAL_CODECS | ||
218 | |||
219 | if (__externalCodecs) | ||
220 | for (i = 0; i < __externalCodecs->Codecs.Size(); i++) | ||
221 | { | ||
222 | const CCodecInfoEx &codec = __externalCodecs->Codecs[i]; | ||
223 | if (codec.Id == methodId && (encode ? codec.EncoderIsAssigned : codec.DecoderIsAssigned)) | ||
224 | return (int)(g_NumCodecs + i); | ||
225 | } | ||
226 | |||
227 | #endif | ||
228 | |||
229 | return -1; | ||
230 | } | ||
231 | |||
232 | |||
233 | bool FindMethod( | ||
234 | DECL_EXTERNAL_CODECS_LOC_VARS | ||
235 | CMethodId methodId, | ||
236 | AString &name) | ||
237 | { | ||
238 | name.Empty(); | ||
239 | |||
240 | unsigned i; | ||
241 | for (i = 0; i < g_NumCodecs; i++) | ||
242 | { | ||
243 | const CCodecInfo &codec = *g_Codecs[i]; | ||
244 | if (methodId == codec.Id) | ||
245 | { | ||
246 | name = codec.Name; | ||
247 | return true; | ||
248 | } | ||
249 | } | ||
250 | |||
251 | #ifdef EXTERNAL_CODECS | ||
252 | |||
253 | CHECK_GLOBAL_CODECS | ||
254 | |||
255 | if (__externalCodecs) | ||
256 | for (i = 0; i < __externalCodecs->Codecs.Size(); i++) | ||
257 | { | ||
258 | const CCodecInfoEx &codec = __externalCodecs->Codecs[i]; | ||
259 | if (methodId == codec.Id) | ||
260 | { | ||
261 | name = codec.Name; | ||
262 | return true; | ||
263 | } | ||
264 | } | ||
265 | |||
266 | #endif | ||
267 | |||
268 | return false; | ||
269 | } | ||
270 | |||
271 | bool FindHashMethod( | ||
272 | DECL_EXTERNAL_CODECS_LOC_VARS | ||
273 | const AString &name, | ||
274 | CMethodId &methodId) | ||
275 | { | ||
276 | unsigned i; | ||
277 | for (i = 0; i < g_NumHashers; i++) | ||
278 | { | ||
279 | const CHasherInfo &codec = *g_Hashers[i]; | ||
280 | if (StringsAreEqualNoCase_Ascii(name, codec.Name)) | ||
281 | { | ||
282 | methodId = codec.Id; | ||
283 | return true; | ||
284 | } | ||
285 | } | ||
286 | |||
287 | #ifdef EXTERNAL_CODECS | ||
288 | |||
289 | CHECK_GLOBAL_CODECS | ||
290 | |||
291 | if (__externalCodecs) | ||
292 | for (i = 0; i < __externalCodecs->Hashers.Size(); i++) | ||
293 | { | ||
294 | const CHasherInfoEx &codec = __externalCodecs->Hashers[i]; | ||
295 | if (StringsAreEqualNoCase_Ascii(name, codec.Name)) | ||
296 | { | ||
297 | methodId = codec.Id; | ||
298 | return true; | ||
299 | } | ||
300 | } | ||
301 | |||
302 | #endif | ||
303 | |||
304 | return false; | ||
305 | } | ||
306 | |||
307 | void GetHashMethods( | ||
308 | DECL_EXTERNAL_CODECS_LOC_VARS | ||
309 | CRecordVector<CMethodId> &methods) | ||
310 | { | ||
311 | methods.ClearAndSetSize(g_NumHashers); | ||
312 | unsigned i; | ||
313 | for (i = 0; i < g_NumHashers; i++) | ||
314 | methods[i] = (*g_Hashers[i]).Id; | ||
315 | |||
316 | #ifdef EXTERNAL_CODECS | ||
317 | |||
318 | CHECK_GLOBAL_CODECS | ||
319 | |||
320 | if (__externalCodecs) | ||
321 | for (i = 0; i < __externalCodecs->Hashers.Size(); i++) | ||
322 | methods.Add(__externalCodecs->Hashers[i].Id); | ||
323 | |||
324 | #endif | ||
325 | } | ||
326 | |||
327 | |||
328 | |||
329 | HRESULT CreateCoder_Index( | ||
330 | DECL_EXTERNAL_CODECS_LOC_VARS | ||
331 | unsigned i, bool encode, | ||
332 | CMyComPtr<ICompressFilter> &filter, | ||
333 | CCreatedCoder &cod) | ||
334 | { | ||
335 | cod.IsExternal = false; | ||
336 | cod.IsFilter = false; | ||
337 | cod.NumStreams = 1; | ||
338 | |||
339 | if (i < g_NumCodecs) | ||
340 | { | ||
341 | const CCodecInfo &codec = *g_Codecs[i]; | ||
342 | // if (codec.Id == methodId) | ||
343 | { | ||
344 | if (encode) | ||
345 | { | ||
346 | if (codec.CreateEncoder) | ||
347 | { | ||
348 | void *p = codec.CreateEncoder(); | ||
349 | if (codec.IsFilter) filter = (ICompressFilter *)p; | ||
350 | else if (codec.NumStreams == 1) cod.Coder = (ICompressCoder *)p; | ||
351 | else { cod.Coder2 = (ICompressCoder2 *)p; cod.NumStreams = codec.NumStreams; } | ||
352 | return S_OK; | ||
353 | } | ||
354 | } | ||
355 | else | ||
356 | if (codec.CreateDecoder) | ||
357 | { | ||
358 | void *p = codec.CreateDecoder(); | ||
359 | if (codec.IsFilter) filter = (ICompressFilter *)p; | ||
360 | else if (codec.NumStreams == 1) cod.Coder = (ICompressCoder *)p; | ||
361 | else { cod.Coder2 = (ICompressCoder2 *)p; cod.NumStreams = codec.NumStreams; } | ||
362 | return S_OK; | ||
363 | } | ||
364 | } | ||
365 | } | ||
366 | |||
367 | #ifdef EXTERNAL_CODECS | ||
368 | |||
369 | CHECK_GLOBAL_CODECS | ||
370 | |||
371 | if (__externalCodecs) | ||
372 | { | ||
373 | i -= g_NumCodecs; | ||
374 | cod.IsExternal = true; | ||
375 | if (i < __externalCodecs->Codecs.Size()) | ||
376 | { | ||
377 | const CCodecInfoEx &codec = __externalCodecs->Codecs[i]; | ||
378 | // if (codec.Id == methodId) | ||
379 | { | ||
380 | if (encode) | ||
381 | { | ||
382 | if (codec.EncoderIsAssigned) | ||
383 | { | ||
384 | if (codec.NumStreams == 1) | ||
385 | { | ||
386 | HRESULT res = __externalCodecs->GetCodecs->CreateEncoder(i, &IID_ICompressCoder, (void **)&cod.Coder); | ||
387 | if (res != S_OK && res != E_NOINTERFACE && res != CLASS_E_CLASSNOTAVAILABLE) | ||
388 | return res; | ||
389 | if (cod.Coder) | ||
390 | return res; | ||
391 | return __externalCodecs->GetCodecs->CreateEncoder(i, &IID_ICompressFilter, (void **)&filter); | ||
392 | } | ||
393 | cod.NumStreams = codec.NumStreams; | ||
394 | return __externalCodecs->GetCodecs->CreateEncoder(i, &IID_ICompressCoder2, (void **)&cod.Coder2); | ||
395 | } | ||
396 | } | ||
397 | else | ||
398 | if (codec.DecoderIsAssigned) | ||
399 | { | ||
400 | if (codec.NumStreams == 1) | ||
401 | { | ||
402 | HRESULT res = __externalCodecs->GetCodecs->CreateDecoder(i, &IID_ICompressCoder, (void **)&cod.Coder); | ||
403 | if (res != S_OK && res != E_NOINTERFACE && res != CLASS_E_CLASSNOTAVAILABLE) | ||
404 | return res; | ||
405 | if (cod.Coder) | ||
406 | return res; | ||
407 | return __externalCodecs->GetCodecs->CreateDecoder(i, &IID_ICompressFilter, (void **)&filter); | ||
408 | } | ||
409 | cod.NumStreams = codec.NumStreams; | ||
410 | return __externalCodecs->GetCodecs->CreateDecoder(i, &IID_ICompressCoder2, (void **)&cod.Coder2); | ||
411 | } | ||
412 | } | ||
413 | } | ||
414 | } | ||
415 | #endif | ||
416 | |||
417 | return S_OK; | ||
418 | } | ||
419 | |||
420 | |||
421 | HRESULT CreateCoder_Index( | ||
422 | DECL_EXTERNAL_CODECS_LOC_VARS | ||
423 | unsigned index, bool encode, | ||
424 | CCreatedCoder &cod) | ||
425 | { | ||
426 | CMyComPtr<ICompressFilter> filter; | ||
427 | HRESULT res = CreateCoder_Index( | ||
428 | EXTERNAL_CODECS_LOC_VARS | ||
429 | index, encode, | ||
430 | filter, cod); | ||
431 | |||
432 | if (filter) | ||
433 | { | ||
434 | cod.IsFilter = true; | ||
435 | CFilterCoder *coderSpec = new CFilterCoder(encode); | ||
436 | cod.Coder = coderSpec; | ||
437 | coderSpec->Filter = filter; | ||
438 | } | ||
439 | |||
440 | return res; | ||
441 | } | ||
442 | |||
443 | |||
444 | HRESULT CreateCoder_Id( | ||
445 | DECL_EXTERNAL_CODECS_LOC_VARS | ||
446 | CMethodId methodId, bool encode, | ||
447 | CMyComPtr<ICompressFilter> &filter, | ||
448 | CCreatedCoder &cod) | ||
449 | { | ||
450 | int index = FindMethod_Index(EXTERNAL_CODECS_LOC_VARS methodId, encode); | ||
451 | if (index < 0) | ||
452 | return S_OK; | ||
453 | return CreateCoder_Index(EXTERNAL_CODECS_LOC_VARS (unsigned)index, encode, filter, cod); | ||
454 | } | ||
455 | |||
456 | |||
457 | HRESULT CreateCoder_Id( | ||
458 | DECL_EXTERNAL_CODECS_LOC_VARS | ||
459 | CMethodId methodId, bool encode, | ||
460 | CCreatedCoder &cod) | ||
461 | { | ||
462 | CMyComPtr<ICompressFilter> filter; | ||
463 | HRESULT res = CreateCoder_Id( | ||
464 | EXTERNAL_CODECS_LOC_VARS | ||
465 | methodId, encode, | ||
466 | filter, cod); | ||
467 | |||
468 | if (filter) | ||
469 | { | ||
470 | cod.IsFilter = true; | ||
471 | CFilterCoder *coderSpec = new CFilterCoder(encode); | ||
472 | cod.Coder = coderSpec; | ||
473 | coderSpec->Filter = filter; | ||
474 | } | ||
475 | |||
476 | return res; | ||
477 | } | ||
478 | |||
479 | |||
480 | HRESULT CreateCoder_Id( | ||
481 | DECL_EXTERNAL_CODECS_LOC_VARS | ||
482 | CMethodId methodId, bool encode, | ||
483 | CMyComPtr<ICompressCoder> &coder) | ||
484 | { | ||
485 | CCreatedCoder cod; | ||
486 | HRESULT res = CreateCoder_Id( | ||
487 | EXTERNAL_CODECS_LOC_VARS | ||
488 | methodId, encode, | ||
489 | cod); | ||
490 | coder = cod.Coder; | ||
491 | return res; | ||
492 | } | ||
493 | |||
494 | HRESULT CreateFilter( | ||
495 | DECL_EXTERNAL_CODECS_LOC_VARS | ||
496 | CMethodId methodId, bool encode, | ||
497 | CMyComPtr<ICompressFilter> &filter) | ||
498 | { | ||
499 | CCreatedCoder cod; | ||
500 | return CreateCoder_Id( | ||
501 | EXTERNAL_CODECS_LOC_VARS | ||
502 | methodId, encode, | ||
503 | filter, cod); | ||
504 | } | ||
505 | |||
506 | |||
507 | HRESULT CreateHasher( | ||
508 | DECL_EXTERNAL_CODECS_LOC_VARS | ||
509 | CMethodId methodId, | ||
510 | AString &name, | ||
511 | CMyComPtr<IHasher> &hasher) | ||
512 | { | ||
513 | name.Empty(); | ||
514 | |||
515 | unsigned i; | ||
516 | for (i = 0; i < g_NumHashers; i++) | ||
517 | { | ||
518 | const CHasherInfo &codec = *g_Hashers[i]; | ||
519 | if (codec.Id == methodId) | ||
520 | { | ||
521 | hasher = codec.CreateHasher(); | ||
522 | name = codec.Name; | ||
523 | break; | ||
524 | } | ||
525 | } | ||
526 | |||
527 | #ifdef EXTERNAL_CODECS | ||
528 | |||
529 | CHECK_GLOBAL_CODECS | ||
530 | |||
531 | if (!hasher && __externalCodecs) | ||
532 | for (i = 0; i < __externalCodecs->Hashers.Size(); i++) | ||
533 | { | ||
534 | const CHasherInfoEx &codec = __externalCodecs->Hashers[i]; | ||
535 | if (codec.Id == methodId) | ||
536 | { | ||
537 | name = codec.Name; | ||
538 | return __externalCodecs->GetHashers->CreateHasher((UInt32)i, &hasher); | ||
539 | } | ||
540 | } | ||
541 | |||
542 | #endif | ||
543 | |||
544 | return S_OK; | ||
545 | } | ||