Skip to content

Commit

Permalink
Add basic OverwriteMode enum
Browse files Browse the repository at this point in the history
Issue #116
  • Loading branch information
rikyoz committed Dec 20, 2022
1 parent d09f946 commit cee0457
Show file tree
Hide file tree
Showing 6 changed files with 101 additions and 30 deletions.
7 changes: 3 additions & 4 deletions include/bitabstractarchivecreator.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -33,10 +33,9 @@ struct ArchiveProperties {
* @brief Enumeration representing how an archive creator should deal when the output archive already exists.
*/
enum struct UpdateMode {
None, ///< The creator will throw an exception.
Append, ///< New items will be appended to the archive.
Overwrite, ///< New items whose path already exists in the archive will be overwritten, other will be appended.
OverwriteArchive ///< The output archive will be deleted and recreated (unless it is a multi-volume archive, in which case an exception is thrown).
None, ///< The creator will throw an exception (unless the OverwriteMode is not None).
Append, ///< The creator will append the new items to the existing archive.
Overwrite ///< New items whose path already exists in the archive will overwrite the old ones, other will be appended.
};

/**
Expand Down
28 changes: 27 additions & 1 deletion include/bitabstractarchivehandler.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -49,6 +49,17 @@ using FileCallback = function< void( tstring ) >;
*/
using PasswordCallback = function< tstring() >;

/**
* @brief Enumeration representing how a handler should deal when an output file already exists.
*/
enum struct OverwriteMode {
None = 0, ///< The handler will throw an exception if the output file or buffer already exists.
Overwrite, ///< The handler will overwrite the old file or buffer with the new one.
Skip, ///< The handler will skip writing to the output file or buffer.
//TODO: RenameOutput,
//TODO: RenameExisting
};

/**
* @brief Abstract class representing a generic archive handler.
*/
Expand Down Expand Up @@ -115,6 +126,11 @@ class BitAbstractArchiveHandler {
*/
BIT7Z_NODISCARD PasswordCallback passwordCallback() const;

/**
* @return the current overwrite mode.
*/
BIT7Z_NODISCARD OverwriteMode overwriteMode() const;

/**
* @brief Sets up a password to be used by the archive handler.
*
Expand Down Expand Up @@ -194,12 +210,22 @@ class BitAbstractArchiveHandler {
*/
void setPasswordCallback( const PasswordCallback& callback );

/**
* @brief Sets how the handler should behave when it tries to output to an existing file or buffer.
*
* @param mode the overwrite modem to be used by the handler.
*/
void setOverwriteMode( OverwriteMode mode );

protected:
const Bit7zLibrary& mLibrary;
tstring mPassword;
bool mRetainDirectories;
OverwriteMode mOverwriteMode;

explicit BitAbstractArchiveHandler( const Bit7zLibrary& lib, tstring password = {} );
explicit BitAbstractArchiveHandler( const Bit7zLibrary& lib,
tstring password = {},
OverwriteMode overwrite_mode = OverwriteMode::None );

private:
//CALLBACKS
Expand Down
17 changes: 15 additions & 2 deletions src/bitabstractarchivehandler.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -14,8 +14,13 @@

using namespace bit7z;

BitAbstractArchiveHandler::BitAbstractArchiveHandler( const Bit7zLibrary& lib, tstring password )
: mLibrary( lib ), mPassword( std::move( password ) ), mRetainDirectories( true ) {}
BitAbstractArchiveHandler::BitAbstractArchiveHandler( const Bit7zLibrary& lib,
tstring password,
OverwriteMode overwrite_mode )
: mLibrary{ lib },
mPassword{ std::move( password ) },
mRetainDirectories{ true },
mOverwriteMode{ overwrite_mode } {}

const Bit7zLibrary& BitAbstractArchiveHandler::library() const noexcept {
return mLibrary;
Expand Down Expand Up @@ -53,6 +58,10 @@ PasswordCallback BitAbstractArchiveHandler::passwordCallback() const {
return mPasswordCallback;
}

OverwriteMode BitAbstractArchiveHandler::overwriteMode() const {
return mOverwriteMode;
}

void BitAbstractArchiveHandler::setPassword( const tstring& password ) {
mPassword = password;
}
Expand Down Expand Up @@ -84,3 +93,7 @@ void BitAbstractArchiveHandler::setFileCallback( const FileCallback& callback )
void BitAbstractArchiveHandler::setPasswordCallback( const PasswordCallback& callback ) {
mPasswordCallback = callback;
}

void BitAbstractArchiveHandler::setOverwriteMode( OverwriteMode mode ) {
mOverwriteMode = mode;
}
2 changes: 1 addition & 1 deletion src/bitabstractarchiveopener.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,7 @@ using namespace bit7z;
BitAbstractArchiveOpener::BitAbstractArchiveOpener( const Bit7zLibrary& lib,
const BitInFormat& format,
const tstring& password )
: BitAbstractArchiveHandler( lib, password ), mFormat( format ) {}
: BitAbstractArchiveHandler{ lib, password, OverwriteMode::Overwrite }, mFormat{ format } {}

const BitInFormat& BitAbstractArchiveOpener::format() const noexcept {
return mFormat;
Expand Down
54 changes: 35 additions & 19 deletions src/bitoutputarchive.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -23,22 +23,32 @@
namespace bit7z {
BitOutputArchive::BitOutputArchive( const BitAbstractArchiveCreator& creator, tstring in_file )
: mInputArchiveItemsCount{ 0 }, mArchiveCreator{ creator } {
if ( mArchiveCreator.overwriteMode() != OverwriteMode::None ) {
return;
}

if ( in_file.empty() ) { // No input file specified, so we are creating a totally new archive!
return;
}

std::error_code ec;
if ( !in_file.empty() && fs::exists( in_file, ec ) ) {
if ( mArchiveCreator.updateMode() == UpdateMode::None ) {
throw BitException( "Cannot update existing archive",
make_error_code( BitError::WrongUpdateMode ) );
}
if ( !mArchiveCreator.compressionFormat().hasFeature( FormatFeatures::MultipleFiles ) ) {
//Update mode is set but format does not support adding more files.
throw BitException( "Cannot update existing archive",
make_error_code( BitError::FormatFeatureNotSupported ) );
}
if ( mArchiveCreator.updateMode() != UpdateMode::OverwriteArchive ) {
mInputArchive = std::make_unique< BitInputArchive >( creator, std::move( in_file ) );
mInputArchiveItemsCount = mInputArchive->itemsCount();
}
if ( !fs::exists( in_file, ec ) ) { // An input file was specified, but it doesn't exist, so we ignore it.
return;
}

if ( mArchiveCreator.updateMode() == UpdateMode::None ) {
throw BitException( "Cannot update existing archive",
make_error_code( BitError::WrongUpdateMode ) );
}

if ( !mArchiveCreator.compressionFormat().hasFeature( FormatFeatures::MultipleFiles ) ) {
//Update mode is set but format does not support adding more files.
throw BitException( "Cannot update existing archive",
make_error_code( BitError::FormatFeatureNotSupported ) );
}

mInputArchive = std::make_unique< BitInputArchive >( creator, std::move( in_file ) );
mInputArchiveItemsCount = mInputArchive->itemsCount();
}

BitOutputArchive::BitOutputArchive( const BitAbstractArchiveCreator& creator,
Expand Down Expand Up @@ -101,12 +111,18 @@ void BitOutputArchive::addDirectory( const tstring& in_dir ) {
}

void BitOutputArchive::compressTo( const tstring& out_file ) {
if ( mArchiveCreator.updateMode() == UpdateMode::OverwriteArchive ) {
OverwriteMode overwrite_mode = mArchiveCreator.overwriteMode();
if ( overwrite_mode == OverwriteMode::Overwrite ) {
std::error_code error;
fs::remove( out_file, error );
if ( error ) {
throw BitException( "Failed to delete the old archive file", error, out_file );
}
} else if ( overwrite_mode == OverwriteMode::Skip ) {
std::error_code error;
if ( fs::exists( out_file, error ) ) {
return;
}
}

auto update_callback = bit7z::make_com< UpdateCallback >( *this );
Expand Down Expand Up @@ -145,9 +161,9 @@ void BitOutputArchive::compressOut( IOutArchive* out_arc,
UpdateCallback* update_callback ) {
if ( mInputArchive != nullptr && mArchiveCreator.updateMode() == UpdateMode::Overwrite ) {
for ( const auto& new_item : mNewItemsVector ) {
auto overwritten_item = mInputArchive->find( new_item->inArchivePath().string< tchar >() );
if ( overwritten_item != mInputArchive->cend() ) {
mDeletedItems.insert( overwritten_item->index() );
auto updated_item = mInputArchive->find( new_item->inArchivePath().string< tchar >() );
if ( updated_item != mInputArchive->cend() ) {
mDeletedItems.insert( updated_item->index() );
}
}
}
Expand Down Expand Up @@ -204,7 +220,7 @@ void BitOutputArchive::compressToFile( const tstring& out_file, UpdateCallback*

void BitOutputArchive::compressTo( std::vector< byte_t >& out_buffer ) {
if ( !out_buffer.empty() ) {
if ( mArchiveCreator.updateMode() == UpdateMode::OverwriteArchive ) {
if ( mArchiveCreator.overwriteMode() == OverwriteMode::Overwrite ) {
out_buffer.clear();
} else {
throw BitException( "Cannot compress to buffer", make_error_code( BitError::NonEmptyOutputBuffer ) );
Expand Down
23 changes: 20 additions & 3 deletions src/internal/fileextractcallback.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -85,9 +85,26 @@ HRESULT FileExtractCallback::getOutStream( uint32_t index, ISequentialOutStream*
std::error_code ec;
fs::create_directories( mFilePathOnDisk.parent_path(), ec );

if ( fs::exists( mFilePathOnDisk, ec ) && !fs::remove( mFilePathOnDisk, ec ) ) {
mErrorMessage = kCannotDeleteOutput;
return E_ABORT;
if ( fs::exists( mFilePathOnDisk, ec ) ) {
OverwriteMode overwrite_mode = mHandler.overwriteMode();

switch ( overwrite_mode ) {
case OverwriteMode::None: {
mErrorMessage = kCannotDeleteOutput;
return E_ABORT;
}
case OverwriteMode::Skip: {
return S_OK;
}
case OverwriteMode::Overwrite:
default: {
if ( !fs::remove( mFilePathOnDisk, ec ) ) {
mErrorMessage = kCannotDeleteOutput;
return E_ABORT;
}
break;
}
}
}

try {
Expand Down

0 comments on commit cee0457

Please sign in to comment.