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 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 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 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 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 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 439 CEncoder::~CEncoder() 440 { 441 delete _bindReverseConverter; 442 } 443 444 }} 445