#pragma region CPL License /* Nuclex Native Framework Copyright (C) 2002-2013 Nuclex Development Labs This library is free software; you can redistribute it and/or modify it under the terms of the IBM Common Public License as published by the IBM Corporation; either version 1.0 of the License, or (at your option) any later version. This library is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the IBM Common Public License for more details. You should have received a copy of the IBM Common Public License along with this library */ #pragma endregion // CPL License // If the library is compiled as a DLL, this ensures symbols are exported #define NUCLEX_STORAGE_SOURCE 1 #include "SevenZipArchive.h" #include "../../Helpers/StringHelper.h" #include "../../Helpers/DateHelper.h" #include "lzma/7zCrc.h" #include #include namespace Nuclex { namespace Storage { namespace FileSystem { namespace SevenZip { // ------------------------------------------------------------------------------------------- // std::once_flag SevenZipArchive::sevenZipCrcTableInitialized; // ------------------------------------------------------------------------------------------- // SevenZipArchive::SevenZipArchive(const std::shared_ptr &archiveBlob) : archiveBlob(archiveBlob), archiveBlobStream(archiveBlob) { std::call_once(sevenZipCrcTableInitialized, &SevenZipArchive::initializeCrcTable); ::SzArEx_Init(&this->archiveInterface); SRes result = ::SzArEx_Open( &this->archiveInterface, &this->archiveBlobStream, &this->allocator, &this->allocator ); if(result != SZ_OK) { throw std::runtime_error("Could not open 7-Zip archive"); } } // ------------------------------------------------------------------------------------------- // SevenZipArchive::~SevenZipArchive() { ::SzArEx_Free(&this->archiveInterface, &this->allocator); } // ------------------------------------------------------------------------------------------- // std::size_t SevenZipArchive::CountFiles() const { // Assumption: std::size_t is >= 7-Zip's UInt32 on all supported platforms return static_cast(this->archiveInterface.db.NumFiles); } // ------------------------------------------------------------------------------------------- // std::string SevenZipArchive::GetFilePath(std::size_t index) const { using Nuclex::Storage::Helpers::StringHelper; { using namespace std; assert( (index < this->archiveInterface.db.NumFiles) && "Index must be within the number of files contained in the archive" ); } std::size_t beginOffset = this->archiveInterface.FileNameOffsets[index]; std::size_t endOffset = this->archiveInterface.FileNameOffsets[index + 1]; const std::uint16_t *pathsArray = reinterpret_cast( this->archiveInterface.FileNames.data ); return StringHelper::Utf8FromWideChar( pathsArray + beginOffset, pathsArray + endOffset - 1 ); } // ------------------------------------------------------------------------------------------- // bool SevenZipArchive::IsDirectory(std::size_t index) const { { using namespace std; assert( (index < this->archiveInterface.db.NumFiles) && "Index must be within the number of files contained in the archive" ); } return (this->archiveInterface.db.Files[index].IsDir != 0); } // ------------------------------------------------------------------------------------------- // std::uint64_t SevenZipArchive::GetUncompressedSize(std::size_t index) const { { using namespace std; assert( (index < this->archiveInterface.db.NumFiles) && "Index must be within the number of files contained in the archive" ); } return this->archiveInterface.db.Files[index].Size; } // ------------------------------------------------------------------------------------------- // std::time_t SevenZipArchive::GetLastModificationTime(std::size_t index) const { using Nuclex::Storage::Helpers::DateHelper; { using namespace std; assert( (index < this->archiveInterface.db.NumFiles) && "Index must be within the number of files contained in the archive" ); } bool timeProvided = (this->archiveInterface.db.Files[index].MTimeDefined != 0); if(timeProvided) { const CNtfsFileTime &ntfsTime = this->archiveInterface.db.Files[index].MTime; return DateHelper::PosixTimeFromFileTime(ntfsTime.High, ntfsTime.Low); } else { return 0; // 1970-01-01 } } // ------------------------------------------------------------------------------------------- // std::size_t SevenZipArchive::GetSolidBlockIndex(std::size_t index) const { { using namespace std; assert( (index < this->archiveInterface.db.NumFiles) && "Index must be within the number of files contained in the archive" ); } return this->archiveInterface.FileIndexToFolderIndexMap[index]; } // ------------------------------------------------------------------------------------------- // std::uint64_t SevenZipArchive::GetFileOffsetInSolidBlock(std::size_t index) const { { using namespace std; assert( (index < this->archiveInterface.db.NumFiles) && "Index must be within the number of files contained in the archive" ); } std::uint64_t offset = 0; { std::size_t solidBlockIndex = GetSolidBlockIndex(index); std::size_t firstFileInSolidBlockIndex = GetFirstFileIndexInSolidBlock(solidBlockIndex); for(std::size_t sumIndex = firstFileInSolidBlockIndex; sumIndex < index; ++sumIndex) { offset += this->archiveInterface.db.Files[sumIndex].Size; } } return offset; } // ------------------------------------------------------------------------------------------- // std::size_t SevenZipArchive::GetFirstFileIndexInSolidBlock(std::size_t solidBlockIndex) const { { using namespace std; assert( (solidBlockIndex < this->archiveInterface.db.NumFolders) && "Index must be within the number of solid blocks contained in the archive" ); } return this->archiveInterface.FolderStartFileIndex[solidBlockIndex]; } // ------------------------------------------------------------------------------------------- // std::uint64_t SevenZipArchive::GetStreamSize( std::size_t solidBlockIndex, std::size_t streamIndex /* = 0 */ ) const { { using namespace std; assert( (solidBlockIndex < this->archiveInterface.db.NumFolders) && "Index must be within the number of solid blocks contained in the archive" ); } std::size_t firstPackStreamIndex = this->archiveInterface.FolderStartPackStreamIndex[ solidBlockIndex ]; return this->archiveInterface.db.PackSizes[firstPackStreamIndex + streamIndex]; } // ------------------------------------------------------------------------------------------- // std::uint64_t SevenZipArchive::GetStreamStartPosition( std::size_t solidBlockIndex, std::size_t streamIndex /* = 0 */ ) const { { using namespace std; assert( (solidBlockIndex < this->archiveInterface.db.NumFolders) && "Index must be within the number of solid blocks contained in the archive" ); } std::uint64_t position = this->archiveInterface.dataPos; { std::size_t firstPackStreamIndex = this->archiveInterface.FolderStartPackStreamIndex[ solidBlockIndex ]; position += this->archiveInterface.PackStreamStartPositions[ firstPackStreamIndex + streamIndex ]; } return position; } // ------------------------------------------------------------------------------------------- // const CSzFolder &SevenZipArchive::GetSolidBlock(std::size_t solidBlockIndex) { { using namespace std; assert( (solidBlockIndex < this->archiveInterface.db.NumFolders) && "Index must be within the number of solid blocks contained in the archive" ); } return this->archiveInterface.db.Folders[solidBlockIndex]; } // ------------------------------------------------------------------------------------------- // void SevenZipArchive::initializeCrcTable() { ::CrcGenerateTable(); } // ------------------------------------------------------------------------------------------- // }}}} // namespace Nuclex::Storage::FileSystem::SevenZip