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