/* * bit7z - A C++ static library to interface with the 7-zip shared libraries. * Copyright (c) 2014-2023 Riccardo Ostani - All Rights Reserved. * * This Source Code Form is subject to the terms of the Mozilla Public * License, v. 2.0. If a copy of the MPL was not distributed with this * file, You can obtain one at https://mozilla.org/MPL/2.0/. */ #ifndef BITINPUTARCHIVE_HPP #define BITINPUTARCHIVE_HPP #include #include #include "bitabstractarchivehandler.hpp" #include "bitarchiveitemoffset.hpp" #include "bitformat.hpp" #include "bitfs.hpp" struct IInStream; struct IInArchive; struct IOutArchive; namespace bit7z { using std::vector; /** * @brief Offset from where the archive starts within the input file. */ enum struct ArchiveStartOffset : std::uint8_t { None, ///< Don't specify an archive start offset. For some formats, like Zip archives, ///< this means that the whole input file will be searched for the archive's start. FileStart ///< Check only the file start for the archive's start. }; /** * @brief The BitInputArchive class, given a handler object, allows reading/extracting the content of archives. */ class BitInputArchive { public: /** * @brief Constructs a BitInputArchive object, opening the input file archive. * * @param handler the reference to the BitAbstractArchiveHandler object containing all the settings to * be used for reading the input archive * @param inFile the path to the input archive file * @param startOffset (optional) specifies whether to search for the archive's start throughout the * entire file or only at the beginning. The default behavior is to search at the beginning. */ BitInputArchive( const BitAbstractArchiveHandler& handler, const tstring& inFile, ArchiveStartOffset startOffset = ArchiveStartOffset::None ); /** * @brief Constructs a BitInputArchive object, opening the input file archive. * * @param handler the reference to the BitAbstractArchiveHandler object containing all the settings to * be used for reading the input archive * @param arcPath the path to the input archive file * @param startOffset (optional) whether to search for the archive's start throughout the entire file * or only at the beginning. The default behavior is to search at the beginning. */ BitInputArchive( const BitAbstractArchiveHandler& handler, const fs::path& arcPath, ArchiveStartOffset startOffset = ArchiveStartOffset::None ); /** * @brief Constructs a BitInputArchive object, opening the archive given in the input buffer. * * @param handler the reference to the BitAbstractArchiveHandler object containing all the settings to * be used for reading the input archive * @param inBuffer the buffer containing the input archive * @param startOffset (optional) whether to search for the archive's start throughout the entire file * or only at the beginning. The default behavior is to search at the beginning. */ BitInputArchive( const BitAbstractArchiveHandler& handler, const buffer_t& inBuffer, ArchiveStartOffset startOffset = ArchiveStartOffset::None ); /** * @brief Constructs a BitInputArchive object, opening the archive by reading the given input stream. * * @param handler the reference to the BitAbstractArchiveHandler object containing all the settings to * be used for reading the input archive * @param inStream the standard input stream of the input archive * @param startOffset (optional) whether to search for the archive's start throughout the entire file * or only at the beginning. The default behavior is to search at the beginning. */ BitInputArchive( const BitAbstractArchiveHandler& handler, std::istream& inStream, ArchiveStartOffset startOffset = ArchiveStartOffset::None ); BitInputArchive( const BitInputArchive& ) = delete; BitInputArchive( BitInputArchive&& ) = delete; auto operator=( const BitInputArchive& ) -> BitInputArchive& = delete; auto operator=( BitInputArchive&& ) -> BitInputArchive& = delete; virtual ~BitInputArchive(); /** * @return the detected format of the file. */ BIT7Z_NODISCARD auto detectedFormat() const noexcept -> const BitInFormat&; /** * @brief Gets the specified archive property. * * @param property the property to be retrieved. * * @return the current value of the archive property or an empty BitPropVariant if no value is specified. */ BIT7Z_NODISCARD auto archiveProperty( BitProperty property ) const -> BitPropVariant; /** * @brief Gets the specified property of an item in the archive. * * @param index the index (in the archive) of the item. * @param property the property to be retrieved. * * @return the current value of the item property or an empty BitPropVariant if the item has no value for * the property. */ BIT7Z_NODISCARD auto itemProperty( uint32_t index, BitProperty property ) const -> BitPropVariant; /** * @return the number of items contained in the archive. */ BIT7Z_NODISCARD auto itemsCount() const -> uint32_t; /** * @param index the index of an item in the archive. * * @return true if and only if the item at the given index is a folder. */ BIT7Z_NODISCARD auto isItemFolder( uint32_t index ) const -> bool; /** * @param index the index of an item in the archive. * * @return true if and only if the item at the given index is encrypted. */ BIT7Z_NODISCARD auto isItemEncrypted( uint32_t index ) const -> bool; /** * @return the path to the archive (the empty string for buffer/stream archives). */ BIT7Z_NODISCARD auto archivePath() const noexcept -> const tstring&; /** * @return the BitAbstractArchiveHandler object containing the settings for reading the archive. */ BIT7Z_NODISCARD auto handler() const noexcept -> const BitAbstractArchiveHandler&; /** * @brief Use the given format property to read the archive. * * @param name the name of the property. * @param property the property value. */ void useFormatProperty( const wchar_t* name, const BitPropVariant& property ) const; /** * @brief Use the given format property to read the archive. * * @tparam T the type of the property. * @param name the name of the property. * @param value the property value. */ template< typename T, typename = typename std::enable_if< is_explicitly_convertible< T, BitPropVariant >::value >::type > void useFormatProperty( const wchar_t* name, T&& value ) const { // NOLINT(*-avoid-c-arrays) useFormatProperty( name, BitPropVariant{ std::forward< T >( value ) } ); } BIT7Z_DEPRECATED_MSG("Since v4.0; please, use the extractTo method.") inline void extract( const tstring& outDir, const std::vector< uint32_t >& indices = {} ) const { extractTo( outDir, indices ); } /** * @brief Extracts the archive to the chosen directory. * * @param outDir the output directory where the extracted files will be put. */ void extractTo( const tstring& outDir ) const; /** * @brief Extracts the specified items to the chosen directory. * * @param outDir the output directory where the extracted files will be put. * @param indices the array of indices of the files in the archive that must be extracted. */ void extractTo( const tstring& outDir, const std::vector< uint32_t >& indices ) const; BIT7Z_DEPRECATED_MSG("Since v4.0; please, use the extractTo method.") inline void extract( std::vector< byte_t >& outBuffer, uint32_t index = 0 ) const { extractTo( outBuffer, index ); } /** * @brief Extracts a file to the output buffer. * * @param outBuffer the output buffer where the content of the archive will be put. * @param index the index of the file to be extracted. */ void extractTo( std::vector< byte_t >& outBuffer, uint32_t index = 0 ) const; template< std::size_t N > BIT7Z_DEPRECATED_MSG("Since v4.0; please, use the extractTo method.") void extract( std::array< byte_t, N >& buffer, uint32_t index = 0 ) const { extractTo( buffer.data(), buffer.size(), index ); } /** * @brief Extracts a file to the pre-allocated output buffer. * * @tparam N the size of the output buffer (it must be equal to the unpacked size * of the item to be extracted). * @param buffer the pre-allocated output buffer. * @param index the index of the file to be extracted. */ template< std::size_t N > void extractTo( std::array< byte_t, N >& buffer, uint32_t index = 0 ) const { extractTo( buffer.data(), buffer.size(), index ); } template< std::size_t N > BIT7Z_DEPRECATED_MSG("Since v4.0; please, use the extractTo method.") void extract( byte_t (& buffer)[N], uint32_t index = 0 ) const { // NOLINT(*-avoid-c-arrays) extractTo( buffer, N, index ); } /** * @brief Extracts a file to the pre-allocated output buffer. * * @tparam N the size of the output buffer (it must be equal to the unpacked size * of the item to be extracted). * @param buffer the pre-allocated output buffer. * @param index the index of the file to be extracted. */ template< std::size_t N > void extractTo( byte_t (& buffer)[N], uint32_t index = 0 ) const { // NOLINT(*-avoid-c-arrays) extractTo( buffer, N, index ); } BIT7Z_DEPRECATED_MSG("Since v4.0; please, use the extractTo method.") inline void extract( byte_t* buffer, std::size_t size, uint32_t index = 0 ) const { extractTo( buffer, size, index ); } /** * @brief Extracts a file to the pre-allocated output buffer. * * @param buffer the pre-allocated output buffer. * @param size the size of the output buffer (it must be equal to the unpacked size * of the item to be extracted). * @param index the index of the file to be extracted. */ void extractTo( byte_t* buffer, std::size_t size, uint32_t index = 0 ) const; BIT7Z_DEPRECATED_MSG("Since v4.0; please, use the extractTo method.") inline void extract( std::ostream& outStream, uint32_t index = 0 ) const { extractTo( outStream, index ); } /** * @brief Extracts a file to the output stream. * * @param outStream the (binary) stream where the content of the archive will be put. * @param index the index of the file to be extracted. */ void extractTo( std::ostream& outStream, uint32_t index = 0 ) const; BIT7Z_DEPRECATED_MSG("Since v4.0; please, use the extractTo method.") inline void extract( std::map< tstring, std::vector< byte_t > >& outMap ) const { extractTo( outMap ); } /** * @brief Extracts the content of the archive to a map of memory buffers, where the keys are the paths * of the files (inside the archive), and the values are their decompressed contents. * * @param outMap the output map. */ void extractTo( std::map< tstring, std::vector< byte_t > >& outMap ) const; /** * @brief Tests the archive without extracting its content. * * If the archive is not valid, a BitException is thrown! */ void test() const; /** * @brief Tests the item at the given index inside the archive without extracting it. * * If the archive is not valid, or there's no item at the given index, a BitException is thrown! * * @param index the index of the file to be tested. */ void testItem( uint32_t index ) const; protected: auto initUpdatableArchive( IOutArchive** newArc ) const -> HRESULT; BIT7Z_NODISCARD auto close() const noexcept -> HRESULT; friend class BitAbstractArchiveOpener; friend class BitAbstractArchiveCreator; friend class BitOutputArchive; private: IInArchive* mInArchive; const BitInFormat* mDetectedFormat; const BitAbstractArchiveHandler& mArchiveHandler; tstring mArchivePath; BIT7Z_NODISCARD auto openArchiveStream( const fs::path& name, IInStream* inStream, ArchiveStartOffset startOffset ) -> IInArchive*; public: /** * @brief An iterator for the elements contained in an archive. */ class ConstIterator { public: // iterator traits using iterator_category BIT7Z_MAYBE_UNUSED = std::input_iterator_tag; using value_type BIT7Z_MAYBE_UNUSED = BitArchiveItemOffset; using reference = const BitArchiveItemOffset&; using pointer = const BitArchiveItemOffset*; using difference_type BIT7Z_MAYBE_UNUSED = uint32_t; //so that count_if returns an uint32_t /** * @brief Advances the iterator to the next element in the archive. * * @return the iterator pointing to the next element in the archive. */ auto operator++() noexcept -> ConstIterator&; /** * @brief Advances the iterator to the next element in the archive. * * @return the iterator before the advancement. */ auto operator++( int ) noexcept -> ConstIterator; // NOLINT(cert-dcl21-cpp) /** * @brief Compares the iterator with another iterator. * * @param other Another iterator. * * @return whether the two iterators point to the same element in the archive or not. */ auto operator==( const ConstIterator& other ) const noexcept -> bool; /** * @brief Compares the iterator with another iterator. * * @param other Another iterator. * * @return whether the two iterators point to the different elements in the archive or not. */ auto operator!=( const ConstIterator& other ) const noexcept -> bool; /** * @brief Accesses the pointed-to element in the archive. * * @return a reference to the pointed-to element in the archive. */ auto operator*() const noexcept -> reference; /** * @brief Accesses the pointed-to element in the archive. * * @return a pointer to the pointed-to element in the archive. */ auto operator->() const noexcept -> pointer; private: BitArchiveItemOffset mItemOffset; ConstIterator( uint32_t itemIndex, const BitInputArchive& itemArchive ) noexcept; friend class BitInputArchive; }; BIT7Z_DEPRECATED_TYPEDEF( const_iterator, ConstIterator, "Use ConstIterator" ); /** * @return an iterator to the first element of the archive; if the archive is empty, * the returned iterator will be equal to the end() iterator. */ BIT7Z_NODISCARD auto begin() const noexcept -> BitInputArchive::ConstIterator; /** * @return an iterator to the element following the last element of the archive; * this element acts as a placeholder: attempting to access it results in undefined behavior. */ BIT7Z_NODISCARD auto end() const noexcept -> BitInputArchive::ConstIterator; /** * @return an iterator to the first element of the archive; if the archive is empty, * the returned iterator will be equal to the end() iterator. */ BIT7Z_NODISCARD auto cbegin() const noexcept -> BitInputArchive::ConstIterator; /** * @return an iterator to the element following the last element of the archive; * this element acts as a placeholder: attempting to access it results in undefined behavior. */ BIT7Z_NODISCARD auto cend() const noexcept -> BitInputArchive::ConstIterator; /** * @brief Find an item in the archive that has the given path. * * @param path the path to be searched in the archive. * * @return an iterator to the item with the given path, or an iterator equal to the end() iterator * if no item is found. */ BIT7Z_NODISCARD auto find( const tstring& path ) const noexcept -> BitInputArchive::ConstIterator; /** * @brief Find if there is an item in the archive that has the given path. * * @param path the path to be searched in the archive. * * @return true if and only if an item with the given path exists in the archive. */ BIT7Z_NODISCARD auto contains( const tstring& path ) const noexcept -> bool; /** * @brief Retrieve the item at the given index. * * @param index the index of the item to be retrieved. * * @return the item at the given index within the archive. */ BIT7Z_NODISCARD auto itemAt( uint32_t index ) const -> BitArchiveItemOffset; }; } // namespace bit7z #endif //BITINPUTARCHIVE_HPP