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