|
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 &bindInfo, |
|
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 : (IUnknown *)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 **)&setCompressCodecsInfo); |
|
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, sizeInBytes)); |
|
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.Properties.SetCapacity(size); |
|
237 memmove(encodingInfo.Properties, 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.Size()) |
|
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].Properties = _codersInfo[i].Properties; |
|
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.InStream; |
|
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 }} |