1// 7zDecode.cpp 2 3#include "StdAfx.h" 4 5#include "../../Common/LimitedStreams.h" 6#include "../../Common/LockedStream.h" 7#include "../../Common/ProgressUtils.h" 8#include "../../Common/StreamObjects.h" 9 10#include "7zDecode.h" 11 12namespace NArchive { 13namespace N7z { 14 15static void ConvertFolderItemInfoToBindInfo(const CFolder &folder, 16 CBindInfoEx &bindInfo) 17{ 18 bindInfo.Clear(); 19 bindInfo.BindPairs.ClearAndSetSize(folder.BindPairs.Size()); 20 unsigned i; 21 for (i = 0; i < folder.BindPairs.Size(); i++) 22 { 23 NCoderMixer::CBindPair &bindPair = bindInfo.BindPairs[i]; 24 bindPair.InIndex = (UInt32)folder.BindPairs[i].InIndex; 25 bindPair.OutIndex = (UInt32)folder.BindPairs[i].OutIndex; 26 } 27 28 bindInfo.Coders.ClearAndSetSize(folder.Coders.Size()); 29 bindInfo.CoderMethodIDs.ClearAndSetSize(folder.Coders.Size()); 30 31 UInt32 outStreamIndex = 0; 32 for (i = 0; i < folder.Coders.Size(); i++) 33 { 34 NCoderMixer::CCoderStreamsInfo &coderStreamsInfo = bindInfo.Coders[i]; 35 const CCoderInfo &coderInfo = folder.Coders[i]; 36 coderStreamsInfo.NumInStreams = (UInt32)coderInfo.NumInStreams; 37 coderStreamsInfo.NumOutStreams = (UInt32)coderInfo.NumOutStreams; 38 bindInfo.CoderMethodIDs[i] = coderInfo.MethodID; 39 for (UInt32 j = 0; j < coderStreamsInfo.NumOutStreams; j++, outStreamIndex++) 40 if (folder.FindBindPairForOutStream(outStreamIndex) < 0) 41 bindInfo.OutStreams.Add(outStreamIndex); 42 } 43 bindInfo.InStreams.ClearAndSetSize(folder.PackStreams.Size()); 44 for (i = 0; i < folder.PackStreams.Size(); i++) 45 bindInfo.InStreams[i] = (UInt32)folder.PackStreams[i]; 46} 47 48static bool AreCodersEqual(const NCoderMixer::CCoderStreamsInfo &a1, 49 const NCoderMixer::CCoderStreamsInfo &a2) 50{ 51 return (a1.NumInStreams == a2.NumInStreams) && 52 (a1.NumOutStreams == a2.NumOutStreams); 53} 54 55static bool AreBindPairsEqual(const NCoderMixer::CBindPair &a1, const NCoderMixer::CBindPair &a2) 56{ 57 return (a1.InIndex == a2.InIndex) && 58 (a1.OutIndex == a2.OutIndex); 59} 60 61static bool AreBindInfoExEqual(const CBindInfoEx &a1, const CBindInfoEx &a2) 62{ 63 if (a1.Coders.Size() != a2.Coders.Size()) 64 return false; 65 unsigned i; 66 for (i = 0; i < a1.Coders.Size(); i++) 67 if (!AreCodersEqual(a1.Coders[i], a2.Coders[i])) 68 return false; 69 if (a1.BindPairs.Size() != a2.BindPairs.Size()) 70 return false; 71 for (i = 0; i < a1.BindPairs.Size(); i++) 72 if (!AreBindPairsEqual(a1.BindPairs[i], a2.BindPairs[i])) 73 return false; 74 for (i = 0; i < a1.CoderMethodIDs.Size(); i++) 75 if (a1.CoderMethodIDs[i] != a2.CoderMethodIDs[i]) 76 return false; 77 if (a1.InStreams.Size() != a2.InStreams.Size()) 78 return false; 79 if (a1.OutStreams.Size() != a2.OutStreams.Size()) 80 return false; 81 return true; 82} 83 84CDecoder::CDecoder(bool multiThread) 85{ 86 #ifndef _ST_MODE 87 multiThread = true; 88 #endif 89 _multiThread = multiThread; 90 _bindInfoExPrevIsDefined = false; 91} 92 93HRESULT CDecoder::Decode( 94 DECL_EXTERNAL_CODECS_LOC_VARS 95 IInStream *inStream, 96 UInt64 startPos, 97 const CFolders &folders, int folderIndex, 98 ISequentialOutStream *outStream, 99 ICompressProgressInfo *compressProgress 100 _7Z_DECODER_CRYPRO_VARS_DECL 101 #if !defined(_7ZIP_ST) && !defined(_SFX) 102 , bool mtMode, UInt32 numThreads 103 #endif 104 ) 105{ 106 const UInt64 *packPositions = &folders.PackPositions[folders.FoStartPackStreamIndex[folderIndex]]; 107 CFolder folderInfo; 108 folders.ParseFolderInfo(folderIndex, folderInfo); 109 110 if (!folderInfo.CheckStructure(folders.GetNumFolderUnpackSizes(folderIndex))) 111 return E_NOTIMPL; 112 113 /* 114 We don't need to init isEncrypted and passwordIsDefined 115 We must upgrade them only 116 #ifndef _NO_CRYPTO 117 isEncrypted = false; 118 passwordIsDefined = false; 119 #endif 120 */ 121 122 CObjectVector< CMyComPtr<ISequentialInStream> > inStreams; 123 124 CLockedInStream lockedInStream; 125 lockedInStream.Init(inStream); 126 127 for (unsigned j = 0; j < folderInfo.PackStreams.Size(); j++) 128 { 129 CLockedSequentialInStreamImp *lockedStreamImpSpec = new CLockedSequentialInStreamImp; 130 CMyComPtr<ISequentialInStream> lockedStreamImp = lockedStreamImpSpec; 131 lockedStreamImpSpec->Init(&lockedInStream, startPos + packPositions[j]); 132 CLimitedSequentialInStream *streamSpec = new CLimitedSequentialInStream; 133 CMyComPtr<ISequentialInStream> inStream = streamSpec; 134 streamSpec->SetStream(lockedStreamImp); 135 streamSpec->Init(packPositions[j + 1] - packPositions[j]); 136 inStreams.Add(inStream); 137 } 138 139 unsigned numCoders = folderInfo.Coders.Size(); 140 141 CBindInfoEx bindInfo; 142 ConvertFolderItemInfoToBindInfo(folderInfo, bindInfo); 143 bool createNewCoders; 144 if (!_bindInfoExPrevIsDefined) 145 createNewCoders = true; 146 else 147 createNewCoders = !AreBindInfoExEqual(bindInfo, _bindInfoExPrev); 148 if (createNewCoders) 149 { 150 unsigned i; 151 _decoders.Clear(); 152 // _decoders2.Clear(); 153 154 _mixerCoder.Release(); 155 156 if (_multiThread) 157 { 158 _mixerCoderMTSpec = new NCoderMixer::CCoderMixer2MT; 159 _mixerCoder = _mixerCoderMTSpec; 160 _mixerCoderCommon = _mixerCoderMTSpec; 161 } 162 else 163 { 164 #ifdef _ST_MODE 165 _mixerCoderSTSpec = new NCoderMixer::CCoderMixer2ST; 166 _mixerCoder = _mixerCoderSTSpec; 167 _mixerCoderCommon = _mixerCoderSTSpec; 168 #endif 169 } 170 RINOK(_mixerCoderCommon->SetBindInfo(bindInfo)); 171 172 for (i = 0; i < numCoders; i++) 173 { 174 const CCoderInfo &coderInfo = folderInfo.Coders[i]; 175 176 177 CMyComPtr<ICompressCoder> decoder; 178 CMyComPtr<ICompressCoder2> decoder2; 179 RINOK(CreateCoder( 180 EXTERNAL_CODECS_LOC_VARS 181 coderInfo.MethodID, decoder, decoder2, false)); 182 CMyComPtr<IUnknown> decoderUnknown; 183 if (coderInfo.IsSimpleCoder()) 184 { 185 if (decoder == 0) 186 return E_NOTIMPL; 187 188 decoderUnknown = (IUnknown *)decoder; 189 190 if (_multiThread) 191 _mixerCoderMTSpec->AddCoder(decoder); 192 #ifdef _ST_MODE 193 else 194 _mixerCoderSTSpec->AddCoder(decoder, false); 195 #endif 196 } 197 else 198 { 199 if (decoder2 == 0) 200 return E_NOTIMPL; 201 decoderUnknown = (IUnknown *)decoder2; 202 if (_multiThread) 203 _mixerCoderMTSpec->AddCoder2(decoder2); 204 #ifdef _ST_MODE 205 else 206 _mixerCoderSTSpec->AddCoder2(decoder2, false); 207 #endif 208 } 209 _decoders.Add(decoderUnknown); 210 #ifdef EXTERNAL_CODECS 211 CMyComPtr<ISetCompressCodecsInfo> setCompressCodecsInfo; 212 decoderUnknown.QueryInterface(IID_ISetCompressCodecsInfo, (void **)&setCompressCodecsInfo); 213 if (setCompressCodecsInfo) 214 { 215 RINOK(setCompressCodecsInfo->SetCompressCodecsInfo(__externalCodecs->GetCodecs)); 216 } 217 #endif 218 } 219 _bindInfoExPrev = bindInfo; 220 _bindInfoExPrevIsDefined = true; 221 } 222 unsigned i; 223 _mixerCoderCommon->ReInit(); 224 225 UInt32 packStreamIndex = 0; 226 UInt32 unpackStreamIndexStart = folders.FoToCoderUnpackSizes[folderIndex]; 227 UInt32 unpackStreamIndex = unpackStreamIndexStart; 228 UInt32 coderIndex = 0; 229 // UInt32 coder2Index = 0; 230 231 for (i = 0; i < numCoders; i++) 232 { 233 const CCoderInfo &coderInfo = folderInfo.Coders[i]; 234 CMyComPtr<IUnknown> &decoder = _decoders[coderIndex]; 235 236 { 237 CMyComPtr<ICompressSetDecoderProperties2> setDecoderProperties; 238 decoder.QueryInterface(IID_ICompressSetDecoderProperties2, &setDecoderProperties); 239 if (setDecoderProperties) 240 { 241 const CByteBuffer &props = coderInfo.Props; 242 size_t size = props.Size(); 243 if (size > 0xFFFFFFFF) 244 return E_NOTIMPL; 245 // if (size > 0) 246 { 247 RINOK(setDecoderProperties->SetDecoderProperties2((const Byte *)props, (UInt32)size)); 248 } 249 } 250 } 251 252 #if !defined(_7ZIP_ST) && !defined(_SFX) 253 if (mtMode) 254 { 255 CMyComPtr<ICompressSetCoderMt> setCoderMt; 256 decoder.QueryInterface(IID_ICompressSetCoderMt, &setCoderMt); 257 if (setCoderMt) 258 { 259 RINOK(setCoderMt->SetNumberOfThreads(numThreads)); 260 } 261 } 262 #endif 263 264 #ifndef _NO_CRYPTO 265 { 266 CMyComPtr<ICryptoSetPassword> cryptoSetPassword; 267 decoder.QueryInterface(IID_ICryptoSetPassword, &cryptoSetPassword); 268 if (cryptoSetPassword) 269 { 270 isEncrypted = true; 271 if (!getTextPassword) 272 return E_NOTIMPL; 273 CMyComBSTR passwordBSTR; 274 RINOK(getTextPassword->CryptoGetTextPassword(&passwordBSTR)); 275 passwordIsDefined = true; 276 size_t len = 0; 277 if (passwordBSTR) 278 len = MyStringLen((BSTR)passwordBSTR); 279 CByteBuffer buffer(len * 2); 280 for (size_t i = 0; i < len; i++) 281 { 282 wchar_t c = passwordBSTR[i]; 283 ((Byte *)buffer)[i * 2] = (Byte)c; 284 ((Byte *)buffer)[i * 2 + 1] = (Byte)(c >> 8); 285 } 286 RINOK(cryptoSetPassword->CryptoSetPassword((const Byte *)buffer, (UInt32)buffer.Size())); 287 } 288 } 289 #endif 290 291 coderIndex++; 292 293 UInt32 numInStreams = (UInt32)coderInfo.NumInStreams; 294 UInt32 numOutStreams = (UInt32)coderInfo.NumOutStreams; 295 CObjArray<UInt64> packSizes(numInStreams); 296 CObjArray<const UInt64 *> packSizesPointers(numInStreams); 297 CObjArray<const UInt64 *> unpackSizesPointers(numOutStreams); 298 UInt32 j; 299 300 for (j = 0; j < numOutStreams; j++, unpackStreamIndex++) 301 unpackSizesPointers[j] = &folders.CoderUnpackSizes[unpackStreamIndex]; 302 303 for (j = 0; j < numInStreams; j++, packStreamIndex++) 304 { 305 int bindPairIndex = folderInfo.FindBindPairForInStream(packStreamIndex); 306 if (bindPairIndex >= 0) 307 packSizesPointers[j] = &folders.CoderUnpackSizes[unpackStreamIndexStart + (UInt32)folderInfo.BindPairs[bindPairIndex].OutIndex]; 308 else 309 { 310 int index = folderInfo.FindPackStreamArrayIndex(packStreamIndex); 311 if (index < 0) 312 return S_FALSE; // check it 313 packSizes[j] = packPositions[index + 1] - packPositions[index]; 314 packSizesPointers[j] = &packSizes[j]; 315 } 316 } 317 318 _mixerCoderCommon->SetCoderInfo(i, packSizesPointers, unpackSizesPointers); 319 } 320 UInt32 mainCoder, temp; 321 bindInfo.FindOutStream(bindInfo.OutStreams[0], mainCoder, temp); 322 323 if (_multiThread) 324 _mixerCoderMTSpec->SetProgressCoderIndex(mainCoder); 325 /* 326 else 327 _mixerCoderSTSpec->SetProgressCoderIndex(mainCoder);; 328 */ 329 330 if (numCoders == 0) 331 return 0; 332 unsigned num = inStreams.Size(); 333 CObjArray<ISequentialInStream *> inStreamPointers(num); 334 for (i = 0; i < num; i++) 335 inStreamPointers[i] = inStreams[i]; 336 ISequentialOutStream *outStreamPointer = outStream; 337 return _mixerCoder->Code( 338 inStreamPointers, NULL, num, 339 &outStreamPointer, NULL, 1, 340 compressProgress); 341} 342 343}} 344