1 // 7zEncode.cpp
2
3 #include "StdAfx.h"
4
5 #include "../../Common/CreateCoder.h"
6 #include "../../Common/FilterCoder.h"
7 #include "../../Common/LimitedStreams.h"
8 #include "../../Common/InOutTempBuffer.h"
9 #include "../../Common/ProgressUtils.h"
10 #include "../../Common/StreamObjects.h"
11
12 #include "7zEncode.h"
13 #include "7zSpecStream.h"
14
15 static const UInt64 k_Delta = 0x03;
16 static const UInt64 k_BCJ = 0x03030103;
17 static const UInt64 k_BCJ2 = 0x0303011B;
18 static const UInt64 k_AES = 0x06F10701;
19
20 namespace NArchive {
21 namespace N7z {
22
ConvertBindInfoToFolderItemInfo(const NCoderMixer::CBindInfo & bindInfo,const CRecordVector<CMethodId> decompressionMethods,CFolder & folder)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
CreateMixerCoder(DECL_EXTERNAL_CODECS_LOC_VARS const UInt64 * inSizeForReduce)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
Encode(DECL_EXTERNAL_CODECS_LOC_VARS ISequentialInStream * inStream,const UInt64 * inStreamSize,const UInt64 * inSizeForReduce,CFolder & folderItem,ISequentialOutStream * outStream,CRecordVector<UInt64> & packSizes,ICompressProgressInfo * compressProgress)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 + 1 < _codersInfo.Size(); i++)
244 {
245 UInt64 m = _codersInfo[i].MethodID;
246 if (m == k_Delta || m == k_BCJ || m == k_BCJ2)
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
CEncoder(const CCompressionMethodMode & options)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
EncoderConstr()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
~CEncoder()448 CEncoder::~CEncoder()
449 {
450 delete _bindReverseConverter;
451 }
452
453 }}
454