OLD | NEW |
| (Empty) |
1 // Encode.cpp | |
2 | |
3 #include "StdAfx.h" | |
4 | |
5 #include "7zEncode.h" | |
6 #include "7zSpecStream.h" | |
7 | |
8 #include "../../IPassword.h" | |
9 #include "../../Common/ProgressUtils.h" | |
10 #include "../../Common/LimitedStreams.h" | |
11 #include "../../Common/InOutTempBuffer.h" | |
12 #include "../../Common/StreamObjects.h" | |
13 #include "../../Common/CreateCoder.h" | |
14 #include "../../Common/FilterCoder.h" | |
15 | |
16 static const UInt64 k_AES = 0x06F10701; | |
17 static const UInt64 k_BCJ = 0x03030103; | |
18 static const UInt64 k_BCJ2 = 0x0303011B; | |
19 | |
20 namespace NArchive { | |
21 namespace N7z { | |
22 | |
23 static void ConvertBindInfoToFolderItemInfo(const NCoderMixer::CBindInfo &bindIn
fo, | |
24 const CRecordVector<CMethodId> decompressionMethods, | |
25 CFolder &folder) | |
26 { | |
27 folder.Coders.Clear(); | |
28 // bindInfo.CoderMethodIDs.Clear(); | |
29 // folder.OutStreams.Clear(); | |
30 folder.PackStreams.Clear(); | |
31 folder.BindPairs.Clear(); | |
32 int i; | |
33 for (i = 0; i < bindInfo.BindPairs.Size(); i++) | |
34 { | |
35 CBindPair bindPair; | |
36 bindPair.InIndex = bindInfo.BindPairs[i].InIndex; | |
37 bindPair.OutIndex = bindInfo.BindPairs[i].OutIndex; | |
38 folder.BindPairs.Add(bindPair); | |
39 } | |
40 for (i = 0; i < bindInfo.Coders.Size(); i++) | |
41 { | |
42 CCoderInfo coderInfo; | |
43 const NCoderMixer::CCoderStreamsInfo &coderStreamsInfo = bindInfo.Coders[i]; | |
44 coderInfo.NumInStreams = coderStreamsInfo.NumInStreams; | |
45 coderInfo.NumOutStreams = coderStreamsInfo.NumOutStreams; | |
46 coderInfo.MethodID = decompressionMethods[i]; | |
47 folder.Coders.Add(coderInfo); | |
48 } | |
49 for (i = 0; i < bindInfo.InStreams.Size(); i++) | |
50 folder.PackStreams.Add(bindInfo.InStreams[i]); | |
51 } | |
52 | |
53 HRESULT CEncoder::CreateMixerCoder( | |
54 DECL_EXTERNAL_CODECS_LOC_VARS | |
55 const UInt64 *inSizeForReduce) | |
56 { | |
57 _mixerCoderSpec = new NCoderMixer::CCoderMixer2MT; | |
58 _mixerCoder = _mixerCoderSpec; | |
59 RINOK(_mixerCoderSpec->SetBindInfo(_bindInfo)); | |
60 for (int i = 0; i < _options.Methods.Size(); i++) | |
61 { | |
62 const CMethodFull &methodFull = _options.Methods[i]; | |
63 _codersInfo.Add(CCoderInfo()); | |
64 CCoderInfo &encodingInfo = _codersInfo.Back(); | |
65 encodingInfo.MethodID = methodFull.Id; | |
66 CMyComPtr<ICompressCoder> encoder; | |
67 CMyComPtr<ICompressCoder2> encoder2; | |
68 | |
69 | |
70 RINOK(CreateCoder( | |
71 EXTERNAL_CODECS_LOC_VARS | |
72 methodFull.Id, encoder, encoder2, true)); | |
73 | |
74 if (!encoder && !encoder2) | |
75 return E_FAIL; | |
76 | |
77 CMyComPtr<IUnknown> encoderCommon = encoder ? (IUnknown *)encoder : (IUnknow
n *)encoder2; | |
78 | |
79 #ifdef COMPRESS_MT | |
80 { | |
81 CMyComPtr<ICompressSetCoderMt> setCoderMt; | |
82 encoderCommon.QueryInterface(IID_ICompressSetCoderMt, &setCoderMt); | |
83 if (setCoderMt) | |
84 { | |
85 RINOK(setCoderMt->SetNumberOfThreads(_options.NumThreads)); | |
86 } | |
87 } | |
88 #endif | |
89 | |
90 | |
91 RINOK(SetMethodProperties(methodFull, inSizeForReduce, encoderCommon)); | |
92 | |
93 /* | |
94 CMyComPtr<ICryptoResetSalt> resetSalt; | |
95 encoderCommon.QueryInterface(IID_ICryptoResetSalt, (void **)&resetSalt); | |
96 if (resetSalt != NULL) | |
97 { | |
98 resetSalt->ResetSalt(); | |
99 } | |
100 */ | |
101 | |
102 #ifdef EXTERNAL_CODECS | |
103 CMyComPtr<ISetCompressCodecsInfo> setCompressCodecsInfo; | |
104 encoderCommon.QueryInterface(IID_ISetCompressCodecsInfo, (void **)&setCompre
ssCodecsInfo); | |
105 if (setCompressCodecsInfo) | |
106 { | |
107 RINOK(setCompressCodecsInfo->SetCompressCodecsInfo(codecsInfo)); | |
108 } | |
109 #endif | |
110 | |
111 CMyComPtr<ICryptoSetPassword> cryptoSetPassword; | |
112 encoderCommon.QueryInterface(IID_ICryptoSetPassword, &cryptoSetPassword); | |
113 | |
114 if (cryptoSetPassword) | |
115 { | |
116 CByteBuffer buffer; | |
117 const UInt32 sizeInBytes = _options.Password.Length() * 2; | |
118 buffer.SetCapacity(sizeInBytes); | |
119 for (int i = 0; i < _options.Password.Length(); i++) | |
120 { | |
121 wchar_t c = _options.Password[i]; | |
122 ((Byte *)buffer)[i * 2] = (Byte)c; | |
123 ((Byte *)buffer)[i * 2 + 1] = (Byte)(c >> 8); | |
124 } | |
125 RINOK(cryptoSetPassword->CryptoSetPassword((const Byte *)buffer, sizeInByt
es)); | |
126 } | |
127 | |
128 if (encoder) | |
129 _mixerCoderSpec->AddCoder(encoder); | |
130 else | |
131 _mixerCoderSpec->AddCoder2(encoder2); | |
132 } | |
133 return S_OK; | |
134 } | |
135 | |
136 HRESULT CEncoder::Encode( | |
137 DECL_EXTERNAL_CODECS_LOC_VARS | |
138 ISequentialInStream *inStream, | |
139 const UInt64 *inStreamSize, const UInt64 *inSizeForReduce, | |
140 CFolder &folderItem, | |
141 ISequentialOutStream *outStream, | |
142 CRecordVector<UInt64> &packSizes, | |
143 ICompressProgressInfo *compressProgress) | |
144 { | |
145 RINOK(EncoderConstr()); | |
146 | |
147 if (_mixerCoderSpec == NULL) | |
148 { | |
149 RINOK(CreateMixerCoder(EXTERNAL_CODECS_LOC_VARS inSizeForReduce)); | |
150 } | |
151 _mixerCoderSpec->ReInit(); | |
152 // _mixerCoderSpec->SetCoderInfo(0, NULL, NULL, progress); | |
153 | |
154 CObjectVector<CInOutTempBuffer> inOutTempBuffers; | |
155 CObjectVector<CSequentialOutTempBufferImp *> tempBufferSpecs; | |
156 CObjectVector<CMyComPtr<ISequentialOutStream> > tempBuffers; | |
157 int numMethods = _bindInfo.Coders.Size(); | |
158 int i; | |
159 for (i = 1; i < _bindInfo.OutStreams.Size(); i++) | |
160 { | |
161 inOutTempBuffers.Add(CInOutTempBuffer()); | |
162 inOutTempBuffers.Back().Create(); | |
163 inOutTempBuffers.Back().InitWriting(); | |
164 } | |
165 for (i = 1; i < _bindInfo.OutStreams.Size(); i++) | |
166 { | |
167 CSequentialOutTempBufferImp *tempBufferSpec = | |
168 new CSequentialOutTempBufferImp; | |
169 CMyComPtr<ISequentialOutStream> tempBuffer = tempBufferSpec; | |
170 tempBufferSpec->Init(&inOutTempBuffers[i - 1]); | |
171 tempBuffers.Add(tempBuffer); | |
172 tempBufferSpecs.Add(tempBufferSpec); | |
173 } | |
174 | |
175 for (i = 0; i < numMethods; i++) | |
176 _mixerCoderSpec->SetCoderInfo(i, NULL, NULL); | |
177 | |
178 if (_bindInfo.InStreams.IsEmpty()) | |
179 return E_FAIL; | |
180 UInt32 mainCoderIndex, mainStreamIndex; | |
181 _bindInfo.FindInStream(_bindInfo.InStreams[0], mainCoderIndex, mainStreamIndex
); | |
182 | |
183 if (inStreamSize != NULL) | |
184 { | |
185 CRecordVector<const UInt64 *> sizePointers; | |
186 for (UInt32 i = 0; i < _bindInfo.Coders[mainCoderIndex].NumInStreams; i++) | |
187 if (i == mainStreamIndex) | |
188 sizePointers.Add(inStreamSize); | |
189 else | |
190 sizePointers.Add(NULL); | |
191 _mixerCoderSpec->SetCoderInfo(mainCoderIndex, &sizePointers.Front(), NULL); | |
192 } | |
193 | |
194 | |
195 // UInt64 outStreamStartPos; | |
196 // RINOK(stream->Seek(0, STREAM_SEEK_CUR, &outStreamStartPos)); | |
197 | |
198 CSequentialInStreamSizeCount2 *inStreamSizeCountSpec = | |
199 new CSequentialInStreamSizeCount2; | |
200 CMyComPtr<ISequentialInStream> inStreamSizeCount = inStreamSizeCountSpec; | |
201 CSequentialOutStreamSizeCount *outStreamSizeCountSpec = | |
202 new CSequentialOutStreamSizeCount; | |
203 CMyComPtr<ISequentialOutStream> outStreamSizeCount = outStreamSizeCountSpec; | |
204 | |
205 inStreamSizeCountSpec->Init(inStream); | |
206 outStreamSizeCountSpec->SetStream(outStream); | |
207 outStreamSizeCountSpec->Init(); | |
208 | |
209 CRecordVector<ISequentialInStream *> inStreamPointers; | |
210 CRecordVector<ISequentialOutStream *> outStreamPointers; | |
211 inStreamPointers.Add(inStreamSizeCount); | |
212 outStreamPointers.Add(outStreamSizeCount); | |
213 for (i = 1; i < _bindInfo.OutStreams.Size(); i++) | |
214 outStreamPointers.Add(tempBuffers[i - 1]); | |
215 | |
216 for (i = 0; i < _codersInfo.Size(); i++) | |
217 { | |
218 CCoderInfo &encodingInfo = _codersInfo[i]; | |
219 | |
220 CMyComPtr<ICryptoResetInitVector> resetInitVector; | |
221 _mixerCoderSpec->_coders[i].QueryInterface(IID_ICryptoResetInitVector, (void
**)&resetInitVector); | |
222 if (resetInitVector != NULL) | |
223 { | |
224 resetInitVector->ResetInitVector(); | |
225 } | |
226 | |
227 CMyComPtr<ICompressWriteCoderProperties> writeCoderProperties; | |
228 _mixerCoderSpec->_coders[i].QueryInterface(IID_ICompressWriteCoderProperties
, (void **)&writeCoderProperties); | |
229 if (writeCoderProperties != NULL) | |
230 { | |
231 CSequentialOutStreamImp *outStreamSpec = new CSequentialOutStreamImp; | |
232 CMyComPtr<ISequentialOutStream> outStream(outStreamSpec); | |
233 outStreamSpec->Init(); | |
234 writeCoderProperties->WriteCoderProperties(outStream); | |
235 size_t size = outStreamSpec->GetSize(); | |
236 encodingInfo.Props.SetCapacity(size); | |
237 memmove(encodingInfo.Props, outStreamSpec->GetBuffer(), size); | |
238 } | |
239 } | |
240 | |
241 UInt32 progressIndex = mainCoderIndex; | |
242 | |
243 for (i = 0; i < _codersInfo.Size(); i++) | |
244 { | |
245 const CCoderInfo &e = _codersInfo[i]; | |
246 if ((e.MethodID == k_BCJ || e.MethodID == k_BCJ2) && i + 1 < _codersInfo.Siz
e()) | |
247 progressIndex = i + 1; | |
248 } | |
249 | |
250 _mixerCoderSpec->SetProgressCoderIndex(progressIndex); | |
251 | |
252 RINOK(_mixerCoder->Code(&inStreamPointers.Front(), NULL, 1, | |
253 &outStreamPointers.Front(), NULL, outStreamPointers.Size(), compressProgress
)); | |
254 | |
255 ConvertBindInfoToFolderItemInfo(_decompressBindInfo, _decompressionMethods, | |
256 folderItem); | |
257 | |
258 packSizes.Add(outStreamSizeCountSpec->GetSize()); | |
259 | |
260 for (i = 1; i < _bindInfo.OutStreams.Size(); i++) | |
261 { | |
262 CInOutTempBuffer &inOutTempBuffer = inOutTempBuffers[i - 1]; | |
263 inOutTempBuffer.FlushWrite(); | |
264 inOutTempBuffer.InitReading(); | |
265 inOutTempBuffer.WriteToStream(outStream); | |
266 packSizes.Add(inOutTempBuffer.GetDataSize()); | |
267 } | |
268 | |
269 for (i = 0; i < (int)_bindReverseConverter->NumSrcInStreams; i++) | |
270 { | |
271 int binder = _bindInfo.FindBinderForInStream( | |
272 _bindReverseConverter->DestOutToSrcInMap[i]); | |
273 UInt64 streamSize; | |
274 if (binder < 0) | |
275 streamSize = inStreamSizeCountSpec->GetSize(); | |
276 else | |
277 streamSize = _mixerCoderSpec->GetWriteProcessedSize(binder); | |
278 folderItem.UnpackSizes.Add(streamSize); | |
279 } | |
280 for (i = numMethods - 1; i >= 0; i--) | |
281 folderItem.Coders[numMethods - 1 - i].Props = _codersInfo[i].Props; | |
282 return S_OK; | |
283 } | |
284 | |
285 | |
286 CEncoder::CEncoder(const CCompressionMethodMode &options): | |
287 _bindReverseConverter(0), | |
288 _constructed(false) | |
289 { | |
290 if (options.IsEmpty()) | |
291 throw 1; | |
292 | |
293 _options = options; | |
294 _mixerCoderSpec = NULL; | |
295 } | |
296 | |
297 HRESULT CEncoder::EncoderConstr() | |
298 { | |
299 if (_constructed) | |
300 return S_OK; | |
301 if (_options.Methods.IsEmpty()) | |
302 { | |
303 // it has only password method; | |
304 if (!_options.PasswordIsDefined) | |
305 throw 1; | |
306 if (!_options.Binds.IsEmpty()) | |
307 throw 1; | |
308 NCoderMixer::CCoderStreamsInfo coderStreamsInfo; | |
309 CMethodFull method; | |
310 | |
311 method.NumInStreams = 1; | |
312 method.NumOutStreams = 1; | |
313 coderStreamsInfo.NumInStreams = 1; | |
314 coderStreamsInfo.NumOutStreams = 1; | |
315 method.Id = k_AES; | |
316 | |
317 _options.Methods.Add(method); | |
318 _bindInfo.Coders.Add(coderStreamsInfo); | |
319 | |
320 _bindInfo.InStreams.Add(0); | |
321 _bindInfo.OutStreams.Add(0); | |
322 } | |
323 else | |
324 { | |
325 | |
326 UInt32 numInStreams = 0, numOutStreams = 0; | |
327 int i; | |
328 for (i = 0; i < _options.Methods.Size(); i++) | |
329 { | |
330 const CMethodFull &methodFull = _options.Methods[i]; | |
331 NCoderMixer::CCoderStreamsInfo coderStreamsInfo; | |
332 coderStreamsInfo.NumInStreams = methodFull.NumOutStreams; | |
333 coderStreamsInfo.NumOutStreams = methodFull.NumInStreams; | |
334 if (_options.Binds.IsEmpty()) | |
335 { | |
336 if (i < _options.Methods.Size() - 1) | |
337 { | |
338 NCoderMixer::CBindPair bindPair; | |
339 bindPair.InIndex = numInStreams + coderStreamsInfo.NumInStreams; | |
340 bindPair.OutIndex = numOutStreams; | |
341 _bindInfo.BindPairs.Add(bindPair); | |
342 } | |
343 else | |
344 _bindInfo.OutStreams.Insert(0, numOutStreams); | |
345 for (UInt32 j = 1; j < coderStreamsInfo.NumOutStreams; j++) | |
346 _bindInfo.OutStreams.Add(numOutStreams + j); | |
347 } | |
348 | |
349 numInStreams += coderStreamsInfo.NumInStreams; | |
350 numOutStreams += coderStreamsInfo.NumOutStreams; | |
351 | |
352 _bindInfo.Coders.Add(coderStreamsInfo); | |
353 } | |
354 | |
355 if (!_options.Binds.IsEmpty()) | |
356 { | |
357 for (i = 0; i < _options.Binds.Size(); i++) | |
358 { | |
359 NCoderMixer::CBindPair bindPair; | |
360 const CBind &bind = _options.Binds[i]; | |
361 bindPair.InIndex = _bindInfo.GetCoderInStreamIndex(bind.InCoder) + bind.In
Stream; | |
362 bindPair.OutIndex = _bindInfo.GetCoderOutStreamIndex(bind.OutCoder) + bind
.OutStream; | |
363 _bindInfo.BindPairs.Add(bindPair); | |
364 } | |
365 for (i = 0; i < (int)numOutStreams; i++) | |
366 if (_bindInfo.FindBinderForOutStream(i) == -1) | |
367 _bindInfo.OutStreams.Add(i); | |
368 } | |
369 | |
370 for (i = 0; i < (int)numInStreams; i++) | |
371 if (_bindInfo.FindBinderForInStream(i) == -1) | |
372 _bindInfo.InStreams.Add(i); | |
373 | |
374 if (_bindInfo.InStreams.IsEmpty()) | |
375 throw 1; // this is error | |
376 | |
377 // Make main stream first in list | |
378 int inIndex = _bindInfo.InStreams[0]; | |
379 for (;;) | |
380 { | |
381 UInt32 coderIndex, coderStreamIndex; | |
382 _bindInfo.FindInStream(inIndex, coderIndex, coderStreamIndex); | |
383 UInt32 outIndex = _bindInfo.GetCoderOutStreamIndex(coderIndex); | |
384 int binder = _bindInfo.FindBinderForOutStream(outIndex); | |
385 if (binder >= 0) | |
386 { | |
387 inIndex = _bindInfo.BindPairs[binder].InIndex; | |
388 continue; | |
389 } | |
390 for (i = 0; i < _bindInfo.OutStreams.Size(); i++) | |
391 if (_bindInfo.OutStreams[i] == outIndex) | |
392 { | |
393 _bindInfo.OutStreams.Delete(i); | |
394 _bindInfo.OutStreams.Insert(0, outIndex); | |
395 break; | |
396 } | |
397 break; | |
398 } | |
399 | |
400 if (_options.PasswordIsDefined) | |
401 { | |
402 int numCryptoStreams = _bindInfo.OutStreams.Size(); | |
403 | |
404 for (i = 0; i < numCryptoStreams; i++) | |
405 { | |
406 NCoderMixer::CBindPair bindPair; | |
407 bindPair.InIndex = numInStreams + i; | |
408 bindPair.OutIndex = _bindInfo.OutStreams[i]; | |
409 _bindInfo.BindPairs.Add(bindPair); | |
410 } | |
411 _bindInfo.OutStreams.Clear(); | |
412 | |
413 /* | |
414 if (numCryptoStreams == 0) | |
415 numCryptoStreams = 1; | |
416 */ | |
417 | |
418 for (i = 0; i < numCryptoStreams; i++) | |
419 { | |
420 NCoderMixer::CCoderStreamsInfo coderStreamsInfo; | |
421 CMethodFull method; | |
422 method.NumInStreams = 1; | |
423 method.NumOutStreams = 1; | |
424 coderStreamsInfo.NumInStreams = method.NumOutStreams; | |
425 coderStreamsInfo.NumOutStreams = method.NumInStreams; | |
426 method.Id = k_AES; | |
427 | |
428 _options.Methods.Add(method); | |
429 _bindInfo.Coders.Add(coderStreamsInfo); | |
430 _bindInfo.OutStreams.Add(numOutStreams + i); | |
431 } | |
432 } | |
433 | |
434 } | |
435 | |
436 for (int i = _options.Methods.Size() - 1; i >= 0; i--) | |
437 { | |
438 const CMethodFull &methodFull = _options.Methods[i]; | |
439 _decompressionMethods.Add(methodFull.Id); | |
440 } | |
441 | |
442 _bindReverseConverter = new NCoderMixer::CBindReverseConverter(_bindInfo); | |
443 _bindReverseConverter->CreateReverseBindInfo(_decompressBindInfo); | |
444 _constructed = true; | |
445 return S_OK; | |
446 } | |
447 | |
448 CEncoder::~CEncoder() | |
449 { | |
450 delete _bindReverseConverter; | |
451 } | |
452 | |
453 }} | |
OLD | NEW |