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 // 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 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 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 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 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 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 459 CEncoder::~CEncoder() 460 { 461 delete _bindReverseConverter; 462 } 463 464 }} 465