1 // Extract.cpp 2 3 #include "StdAfx.h" 4 5 #include <stdio.h> 6 7 #include "Windows/FileDir.h" 8 #include "Windows/PropVariant.h" 9 #include "Windows/PropVariantConversions.h" 10 11 #include "../Common/ExtractingFilePath.h" 12 13 #include "Extract.h" 14 #include "SetProperties.h" 15 16 using namespace NWindows; 17 18 static HRESULT DecompressArchive( 19 const CArc &arc, 20 UInt64 packSize, 21 const NWildcard::CCensorNode &wildcardCensor, 22 const CExtractOptions &options, 23 IExtractCallbackUI *callback, 24 CArchiveExtractCallback *extractCallbackSpec, 25 UString &errorMessage, 26 UInt64 &stdInProcessed) 27 { 28 stdInProcessed = 0; 29 IInArchive *archive = arc.Archive; 30 CRecordVector<UInt32> realIndices; 31 if (!options.StdInMode) 32 { 33 UInt32 numItems; 34 RINOK(archive->GetNumberOfItems(&numItems)); 35 36 for (UInt32 i = 0; i < numItems; i++) 37 { 38 UString filePath; 39 RINOK(arc.GetItemPath(i, filePath)); 40 bool isFolder; 41 RINOK(IsArchiveItemFolder(archive, i, isFolder)); 42 if (!wildcardCensor.CheckPath(filePath, !isFolder)) 43 continue; 44 realIndices.Add(i); 45 } 46 if (realIndices.Size() == 0) 47 { 48 callback->ThereAreNoFiles(); 49 return S_OK; 50 } 51 } 52 53 UStringVector removePathParts; 54 55 UString outDir = options.OutputDir; 56 outDir.Replace(L"*", GetCorrectFsPath(arc.DefaultName)); 57 #ifdef _WIN32 58 // GetCorrectFullFsPath doesn't like "..". 59 // outDir.TrimRight(); 60 // outDir = GetCorrectFullFsPath(outDir); 61 #endif 62 63 if (!outDir.IsEmpty()) 64 if (!NFile::NDirectory::CreateComplexDirectory(outDir)) 65 { 66 HRESULT res = ::GetLastError(); 67 if (res == S_OK) 68 res = E_FAIL; 69 errorMessage = ((UString)L"Can not create output directory ") + outDir; 70 return res; 71 } 72 73 extractCallbackSpec->Init( 74 options.StdInMode ? &wildcardCensor : NULL, 75 &arc, 76 callback, 77 options.StdOutMode, options.TestMode, options.CalcCrc, 78 outDir, 79 removePathParts, 80 packSize); 81 82 #if !defined(_7ZIP_ST) && !defined(_SFX) 83 RINOK(SetProperties(archive, options.Properties)); 84 #endif 85 86 HRESULT result; 87 Int32 testMode = (options.TestMode && !options.CalcCrc) ? 1: 0; 88 if (options.StdInMode) 89 { 90 result = archive->Extract(NULL, (UInt32)(Int32)-1, testMode, extractCallbackSpec); 91 NCOM::CPropVariant prop; 92 if (archive->GetArchiveProperty(kpidPhySize, &prop) == S_OK) 93 if (prop.vt == VT_UI8 || prop.vt == VT_UI4) 94 stdInProcessed = ConvertPropVariantToUInt64(prop); 95 } 96 else 97 result = archive->Extract(&realIndices.Front(), realIndices.Size(), testMode, extractCallbackSpec); 98 99 return callback->ExtractResult(result); 100 } 101 102 HRESULT DecompressArchives( 103 CCodecs *codecs, const CIntVector &formatIndices, 104 UStringVector &arcPaths, UStringVector &arcPathsFull, 105 const NWildcard::CCensorNode &wildcardCensor, 106 const CExtractOptions &options, 107 IOpenCallbackUI *openCallback, 108 IExtractCallbackUI *extractCallback, 109 UString &errorMessage, 110 CDecompressStat &stat) 111 { 112 stat.Clear(); 113 int i; 114 UInt64 totalPackSize = 0; 115 CRecordVector<UInt64> archiveSizes; 116 117 int numArcs = options.StdInMode ? 1 : arcPaths.Size(); 118 119 for (i = 0; i < numArcs; i++) 120 { 121 NFile::NFind::CFileInfoW fi; 122 fi.Size = 0; 123 if (!options.StdInMode) 124 { 125 const UString &arcPath = arcPaths[i]; 126 if (!fi.Find(arcPath)) 127 throw "there is no such archive"; 128 if (fi.IsDir()) 129 throw "can't decompress folder"; 130 } 131 archiveSizes.Add(fi.Size); 132 totalPackSize += fi.Size; 133 } 134 CArchiveExtractCallback *extractCallbackSpec = new CArchiveExtractCallback; 135 CMyComPtr<IArchiveExtractCallback> ec(extractCallbackSpec); 136 bool multi = (numArcs > 1); 137 extractCallbackSpec->InitForMulti(multi, options.PathMode, options.OverwriteMode); 138 if (multi) 139 { 140 RINOK(extractCallback->SetTotal(totalPackSize)); 141 } 142 for (i = 0; i < numArcs; i++) 143 { 144 const UString &arcPath = arcPaths[i]; 145 NFile::NFind::CFileInfoW fi; 146 if (options.StdInMode) 147 { 148 fi.Size = 0; 149 fi.Attrib = 0; 150 } 151 else 152 { 153 if (!fi.Find(arcPath) || fi.IsDir()) 154 throw "there is no such archive"; 155 } 156 157 #ifndef _NO_CRYPTO 158 openCallback->Open_ClearPasswordWasAskedFlag(); 159 #endif 160 161 RINOK(extractCallback->BeforeOpen(arcPath)); 162 CArchiveLink archiveLink; 163 164 CIntVector formatIndices2 = formatIndices; 165 #ifndef _SFX 166 if (formatIndices.IsEmpty()) 167 { 168 int pos = arcPath.ReverseFind(L'.'); 169 if (pos >= 0) 170 { 171 UString s = arcPath.Mid(pos + 1); 172 int index = codecs->FindFormatForExtension(s); 173 if (index >= 0 && s == L"001") 174 { 175 s = arcPath.Left(pos); 176 pos = s.ReverseFind(L'.'); 177 if (pos >= 0) 178 { 179 int index2 = codecs->FindFormatForExtension(s.Mid(pos + 1)); 180 if (index2 >= 0 && s.CompareNoCase(L"rar") != 0) 181 { 182 formatIndices2.Add(index2); 183 formatIndices2.Add(index); 184 } 185 } 186 } 187 } 188 } 189 #endif 190 HRESULT result = archiveLink.Open2(codecs, formatIndices2, options.StdInMode, NULL, arcPath, openCallback); 191 if (result == E_ABORT) 192 return result; 193 194 bool crypted = false; 195 #ifndef _NO_CRYPTO 196 crypted = openCallback->Open_WasPasswordAsked(); 197 #endif 198 199 RINOK(extractCallback->OpenResult(arcPath, result, crypted)); 200 if (result != S_OK) 201 continue; 202 203 if (!options.StdInMode) 204 for (int v = 0; v < archiveLink.VolumePaths.Size(); v++) 205 { 206 int index = arcPathsFull.FindInSorted(archiveLink.VolumePaths[v]); 207 if (index >= 0 && index > i) 208 { 209 arcPaths.Delete(index); 210 arcPathsFull.Delete(index); 211 totalPackSize -= archiveSizes[index]; 212 archiveSizes.Delete(index); 213 numArcs = arcPaths.Size(); 214 } 215 } 216 if (archiveLink.VolumePaths.Size() != 0) 217 { 218 totalPackSize += archiveLink.VolumesSize; 219 RINOK(extractCallback->SetTotal(totalPackSize)); 220 } 221 222 #ifndef _NO_CRYPTO 223 UString password; 224 RINOK(openCallback->Open_GetPasswordIfAny(password)); 225 if (!password.IsEmpty()) 226 { 227 RINOK(extractCallback->SetPassword(password)); 228 } 229 #endif 230 231 for (int v = 0; v < archiveLink.Arcs.Size(); v++) 232 { 233 const UString &s = archiveLink.Arcs[v].ErrorMessage; 234 if (!s.IsEmpty()) 235 { 236 RINOK(extractCallback->MessageError(s)); 237 } 238 } 239 240 CArc &arc = archiveLink.Arcs.Back(); 241 arc.MTimeDefined = (!options.StdInMode && !fi.IsDevice); 242 arc.MTime = fi.MTime; 243 244 UInt64 packProcessed; 245 RINOK(DecompressArchive(arc, 246 fi.Size + archiveLink.VolumesSize, 247 wildcardCensor, options, extractCallback, extractCallbackSpec, errorMessage, packProcessed)); 248 if (!options.StdInMode) 249 packProcessed = fi.Size + archiveLink.VolumesSize; 250 extractCallbackSpec->LocalProgressSpec->InSize += packProcessed; 251 extractCallbackSpec->LocalProgressSpec->OutSize = extractCallbackSpec->UnpackSize; 252 if (!errorMessage.IsEmpty()) 253 return E_FAIL; 254 } 255 stat.NumFolders = extractCallbackSpec->NumFolders; 256 stat.NumFiles = extractCallbackSpec->NumFiles; 257 stat.UnpackSize = extractCallbackSpec->UnpackSize; 258 stat.CrcSum = extractCallbackSpec->CrcSum; 259 260 stat.NumArchives = arcPaths.Size(); 261 stat.PackSize = extractCallbackSpec->LocalProgressSpec->InSize; 262 return S_OK; 263 } 264