Merge from m-c to fix last bustage.
[mozilla-central.git] / modules / lib7z / 7zLib.cpp
bloba32b2d90f2d59213ea4ff5bd3bb8c439a377536c
1 /* -*- Mode: C++; c-basic-offset: 2; tab-width: 8; indent-tabs-mode: nil; -*- */
2 /*****************************************************************************
4 * This 7z Library is based the 7z Client and 7z Standalone Extracting Plugin
5 * code from the LZMA SDK.
6 * It is in the public domain (see http://www.7-zip.org/sdk.html).
8 * Any copyright in these files held by contributors to the Mozilla Project is
9 * also dedicated to the Public Domain.
10 * http://creativecommons.org/licenses/publicdomain/
12 * Contributor(s):
13 * Alex Pakhotin <alexp@mozilla.com>
15 *****************************************************************************/
17 #include "Common/MyWindows.h"
18 #include "Common/NewHandler.h"
20 #include "Common/IntToString.h"
21 #include "Common/MyInitGuid.h"
22 #include "Common/StringConvert.h"
24 #include "Windows/DLL.h"
25 #include "Windows/FileDir.h"
26 #include "Windows/FileFind.h"
27 #include "Windows/FileName.h"
28 #include "Windows/NtCheck.h"
29 #include "Windows/PropVariant.h"
30 #include "Windows/PropVariantConversions.h"
32 #include "7zip/Common/FileStreams.h"
34 #include "7zip/ICoder.h"
35 #include "7zip/Archive/IArchive.h"
37 #include "7zip/IPassword.h"
38 #include "7zip/MyVersion.h"
40 // Used for global structures initialization
41 #include "../C/7zCrc.h"
42 #include "7zip/Common/RegisterArc.h"
43 #include "7zip/Common/RegisterCodec.h"
44 #include "7zip/Archive/7z/7zHandler.h"
45 #include "7zip/Compress/Bcj2Coder.h"
46 #include "7zip/Compress/BcjCoder.h"
47 #include "7zip/Compress/CopyCoder.h"
48 #include "7zip/Compress/Lzma2Decoder.h"
49 #include "7zip/Compress/LzmaDecoder.h"
51 #include "7zLib.h"
53 using namespace NWindows;
55 STDAPI CreateArchiver(const GUID *classID, const GUID *iid, void **outObject);
57 DEFINE_GUID(CLSID_CArchiveHandler,
58 0x23170F69, 0x40C1, 0x278A, 0x10, 0x00, 0x00, 0x01, 0x10, 0x00, 0x00, 0x00);
60 DEFINE_GUID(CLSID_CFormat7z,
61 0x23170F69, 0x40C1, 0x278A, 0x10, 0x00, 0x00, 0x01, 0x10, 0x07, 0x00, 0x00);
63 // Global static structures copied here from *Register.cpp files
64 // Static global variable defined in a module didn't work when used in a library
66 // 7z
67 static IInArchive *CreateArc() { return new NArchive::N7z::CHandler; }
68 static CArcInfo g_ArcInfo =
69 { L"7z", L"7z", 0, 7, {'7', 'z', 0xBC, 0xAF, 0x27, 0x1C}, 6, false, CreateArc, NULL };
71 // BCJ2
72 static void *CreateCodecBCJ2() { return (void *)(ICompressCoder2 *)(new NCompress::NBcj2::CDecoder()); }
74 static CCodecInfo g_CodecInfoBCJ2 =
75 { CreateCodecBCJ2, NULL, 0x0303011B, L"BCJ2", 4, false };
77 // BCJ
78 static void *CreateCodecBCJ() { return (void *)(ICompressFilter *)(new CBCJ_x86_Decoder()); }
80 static CCodecInfo g_CodecInfoBCJ =
81 { CreateCodecBCJ, NULL, 0x03030103, L"BCJ", 1, true };
83 // Copy
84 static void *CreateCodecCopy() { return (void *)(ICompressCoder *)(new NCompress::CCopyCoder); }
86 static CCodecInfo g_CodecInfoCopy =
87 { CreateCodecCopy, CreateCodecCopy, 0x00, L"Copy", 1, false };
89 // LZMA2
90 static void *CreateCodecLZMA2() { return (void *)(ICompressCoder *)(new NCompress::NLzma2::CDecoder); }
92 static CCodecInfo g_CodecInfoLZMA2 =
93 { CreateCodecLZMA2, NULL, 0x21, L"LZMA2", 1, false };
95 // LZMA
96 static void *CreateCodecLZMA() { return (void *)(ICompressCoder *)(new NCompress::NLzma::CDecoder); }
98 static CCodecInfo g_CodecInfoLZMA =
99 { CreateCodecLZMA, NULL, 0x030101, L"LZMA", 1, false };
101 // Initialize all global structures
102 static void Initialize7z()
104 static bool bInitialized = false;
106 if (bInitialized)
107 return;
109 CrcGenerateTable();
111 RegisterArc(&g_ArcInfo);
113 RegisterCodec(&g_CodecInfoBCJ2);
114 RegisterCodec(&g_CodecInfoBCJ);
115 RegisterCodec(&g_CodecInfoCopy);
116 RegisterCodec(&g_CodecInfoLZMA2);
117 RegisterCodec(&g_CodecInfoLZMA);
119 bInitialized = true;
122 #ifdef _CONSOLE
123 #include "stdio.h"
125 void PrintString(const UString &s)
127 printf("%s", (LPCSTR)GetOemString(s));
130 void PrintString(const AString &s)
132 printf("%s", (LPCSTR)s);
135 void PrintNewLine()
137 PrintString("\n");
140 void PrintStringLn(const AString &s)
142 PrintString(s);
143 PrintNewLine();
146 void PrintError(const AString &s)
148 PrintNewLine();
149 PrintString(s);
150 PrintNewLine();
152 #else
154 #define PrintString(s)
155 #define PrintString(s)
156 #define PrintNewLine()
157 #define PrintStringLn(s)
159 static UString g_sError;
161 void PrintError(const AString &s)
163 g_sError += GetUnicodeString(s) + L"\n";
166 const wchar_t* GetExtractorError()
168 return (const wchar_t*)g_sError;
171 #endif
173 static HRESULT IsArchiveItemProp(IInArchive *archive, UInt32 index, PROPID propID, bool &result)
175 NCOM::CPropVariant prop;
176 RINOK(archive->GetProperty(index, propID, &prop));
177 if (prop.vt == VT_BOOL)
178 result = VARIANT_BOOLToBool(prop.boolVal);
179 else if (prop.vt == VT_EMPTY)
180 result = false;
181 else
182 return E_FAIL;
183 return S_OK;
186 static HRESULT IsArchiveItemFolder(IInArchive *archive, UInt32 index, bool &result)
188 return IsArchiveItemProp(archive, index, kpidIsDir, result);
192 static const wchar_t *kEmptyFileAlias = L"[Content]";
195 //////////////////////////////////////////////////////////////
196 // Archive Open callback class
198 class CArchiveOpenCallback:
199 public IArchiveOpenCallback,
200 public ICryptoGetTextPassword,
201 public CMyUnknownImp
203 public:
204 MY_UNKNOWN_IMP1(ICryptoGetTextPassword)
206 STDMETHOD(SetTotal)(const UInt64 *files, const UInt64 *bytes);
207 STDMETHOD(SetCompleted)(const UInt64 *files, const UInt64 *bytes);
209 STDMETHOD(CryptoGetTextPassword)(BSTR *password);
211 bool PasswordIsDefined;
212 UString Password;
214 CArchiveOpenCallback() : PasswordIsDefined(false) {}
217 STDMETHODIMP CArchiveOpenCallback::SetTotal(const UInt64 * /* files */, const UInt64 * /* bytes */)
219 return S_OK;
222 STDMETHODIMP CArchiveOpenCallback::SetCompleted(const UInt64 * /* files */, const UInt64 * /* bytes */)
224 return S_OK;
227 STDMETHODIMP CArchiveOpenCallback::CryptoGetTextPassword(BSTR *password)
229 if (!PasswordIsDefined)
231 // You can ask real password here from user
232 // Password = GetPassword(OutStream);
233 // PasswordIsDefined = true;
234 PrintError("Password is not defined");
235 return E_ABORT;
237 return StringToBstr(Password, password);
241 //////////////////////////////////////////////////////////////
242 // Archive Extracting callback class
244 static const wchar_t *kCantDeleteOutputFile = L"ERROR: Can not delete output file ";
246 static const char *kTestingString = "Testing ";
247 static const char *kExtractingString = "Extracting ";
248 static const char *kSkippingString = "Skipping ";
250 static const char *kUnsupportedMethod = "Unsupported Method";
251 static const char *kCRCFailed = "CRC Failed";
252 static const char *kDataError = "Data Error";
253 static const char *kUnknownError = "Unknown Error";
255 class CArchiveExtractCallback:
256 public IArchiveExtractCallback,
257 public ICryptoGetTextPassword,
258 public CMyUnknownImp
260 public:
261 MY_UNKNOWN_IMP1(ICryptoGetTextPassword)
263 // IProgress
264 STDMETHOD(SetTotal)(UInt64 size);
265 STDMETHOD(SetCompleted)(const UInt64 *completeValue);
267 // IArchiveExtractCallback
268 STDMETHOD(GetStream)(UInt32 index, ISequentialOutStream **outStream, Int32 askExtractMode);
269 STDMETHOD(PrepareOperation)(Int32 askExtractMode);
270 STDMETHOD(SetOperationResult)(Int32 resultEOperationResult);
272 // ICryptoGetTextPassword
273 STDMETHOD(CryptoGetTextPassword)(BSTR *aPassword);
275 private:
276 CMyComPtr<IInArchive> _archiveHandler;
277 UString _directoryPath; // Output directory
278 UString _filePath; // name inside archive
279 UString _diskFilePath; // full path to file on disk
280 bool _extractMode;
281 struct CProcessedFileInfo
283 FILETIME MTime;
284 UInt32 Attrib;
285 bool isDir;
286 bool AttribDefined;
287 bool MTimeDefined;
288 } _processedFileInfo;
290 COutFileStream *_outFileStreamSpec;
291 CMyComPtr<ISequentialOutStream> _outFileStream;
293 SzExtractProgressCallback *_progressCallback;
294 UInt32 _numItemsTotal;
295 UInt32 _numItemsExtracted;
297 public:
298 void Init(IInArchive *archiveHandler, const UString &directoryPath, SzExtractProgressCallback *progressCallback);
300 UInt64 NumErrors;
301 bool PasswordIsDefined;
302 UString Password;
304 CArchiveExtractCallback() : PasswordIsDefined(false) {}
307 void CArchiveExtractCallback::Init(IInArchive *archiveHandler, const UString &directoryPath, SzExtractProgressCallback *progressCallback)
309 NumErrors = 0;
310 _archiveHandler = archiveHandler;
311 _directoryPath = directoryPath;
312 NFile::NName::NormalizeDirPathPrefix(_directoryPath);
313 _progressCallback = progressCallback;
314 _numItemsTotal = 0;
315 _numItemsExtracted = 0;
316 archiveHandler->GetNumberOfItems(&_numItemsTotal);
319 // SetTotal and SetCompleted callback methods show progress
320 // based on the input buffer, which does not really correspond
321 // to the actual extraction progress.
322 // Current implementation uses number of files as the progress indicator,
323 // which gives better result with an archive containing a lot of files.
324 STDMETHODIMP CArchiveExtractCallback::SetTotal(UInt64 /* size */)
327 char s[30];
328 ConvertUInt64ToString(size, s);
329 PrintString(AString("\n--- Total: "));
330 PrintStringLn(s);
332 return S_OK;
335 STDMETHODIMP CArchiveExtractCallback::SetCompleted(const UInt64 * /* completeValue */)
338 char s[30];
339 ConvertUInt64ToString(*completeValue, s);
340 PrintString(AString("\n--- Completed: "));
341 PrintStringLn(s);
343 return S_OK;
346 STDMETHODIMP CArchiveExtractCallback::GetStream(UInt32 index,
347 ISequentialOutStream **outStream, Int32 askExtractMode)
349 *outStream = 0;
350 _outFileStream.Release();
353 // Get Name
354 NCOM::CPropVariant prop;
355 RINOK(_archiveHandler->GetProperty(index, kpidPath, &prop));
357 UString fullPath;
358 if (prop.vt == VT_EMPTY)
359 fullPath = kEmptyFileAlias;
360 else
362 if (prop.vt != VT_BSTR)
363 return E_FAIL;
364 fullPath = prop.bstrVal;
366 _filePath = fullPath;
369 if (askExtractMode != NArchive::NExtract::NAskMode::kExtract)
370 return S_OK;
373 // Get Attrib
374 NCOM::CPropVariant prop;
375 RINOK(_archiveHandler->GetProperty(index, kpidAttrib, &prop));
376 if (prop.vt == VT_EMPTY)
378 _processedFileInfo.Attrib = 0;
379 _processedFileInfo.AttribDefined = false;
381 else
383 if (prop.vt != VT_UI4)
384 return E_FAIL;
385 _processedFileInfo.Attrib = prop.ulVal;
386 _processedFileInfo.AttribDefined = true;
390 RINOK(IsArchiveItemFolder(_archiveHandler, index, _processedFileInfo.isDir));
393 // Get Modified Time
394 NCOM::CPropVariant prop;
395 RINOK(_archiveHandler->GetProperty(index, kpidMTime, &prop));
396 _processedFileInfo.MTimeDefined = false;
397 switch(prop.vt)
399 case VT_EMPTY:
400 // _processedFileInfo.MTime = _utcMTimeDefault;
401 break;
402 case VT_FILETIME:
403 _processedFileInfo.MTime = prop.filetime;
404 _processedFileInfo.MTimeDefined = true;
405 break;
406 default:
407 return E_FAIL;
413 // Get Size
414 NCOM::CPropVariant prop;
415 RINOK(_archiveHandler->GetProperty(index, kpidSize, &prop));
416 bool newFileSizeDefined = (prop.vt != VT_EMPTY);
417 UInt64 newFileSize;
418 if (newFileSizeDefined)
419 newFileSize = ConvertPropVariantToUInt64(prop);
424 // Create folders for file
425 int slashPos = _filePath.ReverseFind(WCHAR_PATH_SEPARATOR);
426 if (slashPos >= 0)
427 NFile::NDirectory::CreateComplexDirectory(_directoryPath + _filePath.Left(slashPos));
430 UString fullProcessedPath = _directoryPath + _filePath;
431 _diskFilePath = fullProcessedPath;
433 if (_processedFileInfo.isDir)
435 NFile::NDirectory::CreateComplexDirectory(fullProcessedPath);
437 else
439 NFile::NFind::CFileInfoW fi;
440 if (fi.Find(fullProcessedPath))
442 if (!NFile::NDirectory::DeleteFileAlways(fullProcessedPath))
444 PrintString(UString(kCantDeleteOutputFile) + fullProcessedPath);
445 return E_ABORT;
449 _outFileStreamSpec = new COutFileStream;
450 CMyComPtr<ISequentialOutStream> outStreamLoc(_outFileStreamSpec);
451 if (!_outFileStreamSpec->Open(fullProcessedPath, CREATE_ALWAYS))
453 PrintString((UString)L"can not open output file " + fullProcessedPath);
454 return E_ABORT;
456 _outFileStream = outStreamLoc;
457 *outStream = outStreamLoc.Detach();
459 return S_OK;
462 STDMETHODIMP CArchiveExtractCallback::PrepareOperation(Int32 askExtractMode)
464 _extractMode = false;
465 switch (askExtractMode)
467 case NArchive::NExtract::NAskMode::kExtract: _extractMode = true; break;
469 switch (askExtractMode)
471 case NArchive::NExtract::NAskMode::kExtract: PrintString(kExtractingString); break;
472 case NArchive::NExtract::NAskMode::kTest: PrintString(kTestingString); break;
473 case NArchive::NExtract::NAskMode::kSkip: PrintString(kSkippingString); break;
475 PrintString(_filePath);
476 _numItemsExtracted++;
477 if (_progressCallback)
479 _progressCallback(_numItemsExtracted * 100 / _numItemsTotal);
481 return S_OK;
484 STDMETHODIMP CArchiveExtractCallback::SetOperationResult(Int32 operationResult)
486 switch(operationResult)
488 case NArchive::NExtract::NOperationResult::kOK:
489 break;
490 default:
492 NumErrors++;
493 PrintString(" ");
494 switch(operationResult)
496 case NArchive::NExtract::NOperationResult::kUnSupportedMethod:
497 PrintString(kUnsupportedMethod);
498 break;
499 case NArchive::NExtract::NOperationResult::kCRCError:
500 PrintString(kCRCFailed);
501 break;
502 case NArchive::NExtract::NOperationResult::kDataError:
503 PrintString(kDataError);
504 break;
505 default:
506 PrintString(kUnknownError);
511 if (_outFileStream != NULL)
513 if (_processedFileInfo.MTimeDefined)
514 _outFileStreamSpec->SetMTime(&_processedFileInfo.MTime);
515 RINOK(_outFileStreamSpec->Close());
517 _outFileStream.Release();
518 if (_extractMode && _processedFileInfo.AttribDefined)
519 NFile::NDirectory::MySetFileAttributes(_diskFilePath, _processedFileInfo.Attrib);
520 PrintNewLine();
521 return S_OK;
525 STDMETHODIMP CArchiveExtractCallback::CryptoGetTextPassword(BSTR *password)
527 if (!PasswordIsDefined)
529 // You can ask real password here from user
530 // Password = GetPassword(OutStream);
531 // PasswordIsDefined = true;
532 PrintError("Password is not defined");
533 return E_ABORT;
535 return StringToBstr(Password, password);
538 static WRes MyCreateDir(const WCHAR *name)
540 return CreateDirectoryW(name, NULL) ? 0 : GetLastError();
543 static WRes CreateOutputDir(const WCHAR *outputDir)
545 WRes res = SZ_OK;
546 WCHAR name[MAX_PATH];
547 size_t j;
548 if (outputDir == NULL || outputDir[0] == 0)
549 return SZ_ERROR_PARAM;
550 wcsncpy(name, outputDir, MAX_PATH-1);
551 name[MAX_PATH-1] = 0;
553 for (j = 1; name[j] != 0 && res == 0; j++)
555 if (name[j] == CHAR_PATH_SEPARATOR)
557 name[j] = 0;
558 res = MyCreateDir(name);
559 name[j] = CHAR_PATH_SEPARATOR;
562 if (res == 0 && name[wcslen(name) - 1] != CHAR_PATH_SEPARATOR)
564 res = MyCreateDir(name);
566 return res;
569 //////////////////////////////////////////////////////////////////////////
570 // Main extract functions
573 * Extract 7z-archive
575 * @param archiveFileName Name of the archive
576 * @param fileToExtract Name of the file to extract (if NULL - extract all files)
577 * @param outputDir Output directory for extracted files
578 * @param progressCallback Function to be called on each file - can show the progress
580 int SzExtract(const WCHAR *archiveName,
581 const WCHAR *fileToExtract, const WCHAR *outputDir,
582 SzExtractProgressCallback *progressCallback)
584 return SzExtractSfx(archiveName, 0, fileToExtract, outputDir, progressCallback);
588 * Extract 7z-SFX-archive
590 * @param archiveFileName Name of the archive
591 * @param sfxStubSize Size of the stub at the beginning of the file before the actual archive data (could be 0)
592 * @param fileToExtract Name of the file to extract (if NULL - extract all files)
593 * @param outputDir Output directory for extracted files
594 * @param progressCallback Function to be called on each file to show the progress
596 int SzExtractSfx(const WCHAR *archiveName, DWORD sfxStubSize,
597 const WCHAR *fileToExtract, const WCHAR *outputDir,
598 SzExtractProgressCallback *progressCallback)
600 Initialize7z();
602 CreateOutputDir(outputDir);
604 #ifdef _DEBUG_OUTPUT
605 PrintString("Loading archive ");
606 PrintString(archiveName);
607 PrintNewLine();
608 #endif
610 // Extracting
612 CMyComPtr<IInArchive> archive;
613 if (CreateArchiver(&CLSID_CFormat7z, &IID_IInArchive, (void **)&archive) != S_OK)
615 PrintError("Can not get class object");
616 return SZ_ERROR_FAIL;
619 #ifdef _DEBUG_OUTPUT
620 PrintStringLn("Created archiver");
621 #endif
623 CInFileStream *fileSpec = new CInFileStream;
624 CMyComPtr<IInStream> file = fileSpec;
626 if (!fileSpec->Open(archiveName))
628 PrintError("Can not open archive file");
629 return SZ_ERROR_NO_ARCHIVE;
631 if (sfxStubSize > 0)
632 file->Seek(sfxStubSize, STREAM_SEEK_SET, NULL);
634 #ifdef _DEBUG_OUTPUT
635 PrintStringLn("Opened file");
636 #endif
639 CArchiveOpenCallback *openCallbackSpec = new CArchiveOpenCallback;
640 CMyComPtr<IArchiveOpenCallback> openCallback(openCallbackSpec);
641 openCallbackSpec->PasswordIsDefined = false;
642 // openCallbackSpec->PasswordIsDefined = true;
643 // openCallbackSpec->Password = L"1";
645 if (archive->Open(file, 0, openCallback) != S_OK)
647 PrintError("Can not open archive");
648 return SZ_ERROR_NO_ARCHIVE;
652 #ifdef _DEBUG_OUTPUT
653 PrintStringLn("Extracting...");
654 #endif
656 CArchiveExtractCallback *extractCallbackSpec = new CArchiveExtractCallback;
657 CMyComPtr<IArchiveExtractCallback> extractCallback(extractCallbackSpec);
658 extractCallbackSpec->Init(archive, outputDir, progressCallback);
659 extractCallbackSpec->PasswordIsDefined = false;
660 // extractCallbackSpec->PasswordIsDefined = true;
661 // extractCallbackSpec->Password = L"1";
663 HRESULT result = S_OK;
664 UInt32 numItems = 0;
665 archive->GetNumberOfItems(&numItems);
666 if (numItems == 0)
668 PrintError("No files found in the archive");
669 return SZ_ERROR_DATA;
671 if (fileToExtract)
673 // Extract one file
674 for (UInt32 i = 0; i < numItems; i++)
676 // Get name of file
677 NWindows::NCOM::CPropVariant prop;
678 archive->GetProperty(i, kpidPath, &prop);
679 UString s = ConvertPropVariantToString(prop);
680 if (wcscmp(fileToExtract, s) == 0)
682 PrintString(s);
683 PrintString("\n");
684 // Extract the current file
685 result = archive->Extract(&i, 1, false, extractCallback);
686 break;
690 else
692 // Extract all
693 result = archive->Extract(NULL, (UInt32)(Int32)(-1), false, extractCallback);
695 if (result != S_OK)
697 PrintError("Extract Error");
698 return SZ_ERROR_DATA;
701 return SZ_OK;
705 * Get information about 7z-SFX-archive
707 * @param archiveFileName Name of the archive
708 * @param sfxStubSize Size of the stub at the beginning of the file before the actual archive data (could be 0)
710 * Output parameters:
711 * @param pUncompressedSize Pointer to 64 bit integer for the total uncompressed size
712 * @param pNumberOfFiles (optional) Pointer to a number of files in the archive
713 * @param pNumberOfDirs (optional) Pointer to a number of directories in the archive
715 int SzGetSfxArchiveInfo(const WCHAR *archiveName, const DWORD sfxStubSize,
716 ULONGLONG *pUncompressedSize, DWORD *pNumberOfFiles, DWORD *pNumberOfDirs)
718 if (!archiveName || !pUncompressedSize)
719 return SZ_ERROR_PARAM;
721 *pUncompressedSize = 0;
723 Initialize7z();
725 CMyComPtr<IInArchive> archive;
726 if (CreateArchiver(&CLSID_CFormat7z, &IID_IInArchive, (void **)&archive) != S_OK)
728 PrintError("Can not get class object");
729 return SZ_ERROR_FAIL;
732 CInFileStream *fileSpec = new CInFileStream;
733 CMyComPtr<IInStream> file = fileSpec;
735 if (!fileSpec->Open(archiveName))
737 PrintError("Can not open archive file");
738 return SZ_ERROR_NO_ARCHIVE;
740 if (sfxStubSize > 0)
741 file->Seek(sfxStubSize, STREAM_SEEK_SET, NULL);
743 CArchiveOpenCallback *openCallbackSpec = new CArchiveOpenCallback;
744 CMyComPtr<IArchiveOpenCallback> openCallback(openCallbackSpec);
745 openCallbackSpec->PasswordIsDefined = false;
747 if (archive->Open(file, 0, openCallback) != S_OK)
749 PrintError("Can not open archive");
750 return SZ_ERROR_NO_ARCHIVE;
753 UInt32 numItems = 0;
754 archive->GetNumberOfItems(&numItems);
755 if (numItems == 0)
757 PrintError("No files found in the archive");
758 return SZ_ERROR_DATA;
761 if (pNumberOfFiles)
762 *pNumberOfFiles = 0;
764 if (pNumberOfDirs)
765 *pNumberOfDirs = 0;
767 // Iterate through all items
768 for (UInt32 i = 0; i < numItems; i++)
770 bool isDir = false;
771 RINOK(IsArchiveItemFolder(archive, i, isDir));
772 if (isDir)
774 if (pNumberOfDirs)
775 (*pNumberOfDirs)++;
776 continue;
779 UInt64 unpackSize = 0;
781 NWindows::NCOM::CPropVariant prop;
782 if (archive->GetProperty(i, kpidSize, &prop) != S_OK)
784 PrintError("Cannot get size property value");
785 return SZ_ERROR_DATA;
787 if (prop.vt != VT_EMPTY)
788 unpackSize = ConvertPropVariantToUInt64(prop);
790 (*pUncompressedSize) += unpackSize;
792 if (pNumberOfFiles)
793 (*pNumberOfFiles)++;
796 return SZ_OK;