Skip to content

Commit

Permalink
Add an option to automatically prepend paths with the long path prefix
Browse files Browse the repository at this point in the history
Closes issue #45
  • Loading branch information
rikyoz committed Jan 10, 2023
1 parent 13fb363 commit 3d3cec7
Show file tree
Hide file tree
Showing 21 changed files with 186 additions and 56 deletions.
8 changes: 8 additions & 0 deletions cmake/BuildOptions.cmake
Original file line number Diff line number Diff line change
Expand Up @@ -45,4 +45,12 @@ if( CMAKE_CXX_COMPILER_ID MATCHES "Clang" )
set( CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -stdlib=libc++" )
set( CMAKE_EXE_LINKER_FLAGS "${CMAKE_EXE_LINKER_FLAGS} -stdlib=libc++ -lc++abi" )
endif()
endif()

if( WIN32 )
option( BIT7Z_AUTO_PREFIX_LONG_PATHS "Enable or disable automatically prepend paths with Windows long path prefix" )
message( STATUS "Auto prefix long paths: ${BIT7Z_AUTO_PREFIX_LONG_PATHS}" )
if( BIT7Z_AUTO_PREFIX_LONG_PATHS )
target_compile_definitions( ${LIB_TARGET} PUBLIC BIT7Z_AUTO_PREFIX_LONG_PATHS )
endif()
endif()
24 changes: 19 additions & 5 deletions include/bit7z/bitinputarchive.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,7 @@
#include "bitabstractarchivehandler.hpp"
#include "bitarchiveitemoffset.hpp"
#include "bitformat.hpp"
#include "bitfs.hpp"

struct IInStream;
struct IInArchive;
Expand All @@ -32,11 +33,24 @@ class BitInputArchive {
/**
* @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 in_file the path to the input archive file
* @param handler the reference to the BitAbstractArchiveHandler object containing all the settings to
* be used for reading the input archive
* @param in_file the path to the input archive file
*/
BitInputArchive( const BitAbstractArchiveHandler& handler, const tstring& in_file );

/**
* @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 arc_path the path to the input archive file
*/
BitInputArchive( const BitAbstractArchiveHandler& handler, tstring in_file );
#if defined( _WIN32 ) && defined( BIT7Z_AUTO_PREFIX_LONG_PATHS )
BitInputArchive( const BitAbstractArchiveHandler& handler, fs::path arc_path );
#else
BitInputArchive( const BitAbstractArchiveHandler& handler, const fs::path& arc_path );
#endif

/**
* @brief Constructs a BitInputArchive object, opening the archive given in the input buffer.
Expand Down Expand Up @@ -196,7 +210,7 @@ class BitInputArchive {
void test() const;

protected:
IInArchive* openArchiveStream( const tstring& name, IInStream* in_stream );
IInArchive* openArchiveStream( const fs::path& name, IInStream* in_stream );

HRESULT initUpdatableArchive( IOutArchive** newArc ) const;

Expand Down
16 changes: 15 additions & 1 deletion include/bit7z/bitoutputarchive.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -54,6 +54,14 @@ class UpdateCallback;
*/
class BitOutputArchive {
public:
/**
* @brief Constructs a BitOutputArchive object for a completely new archive.
*
* @param creator the reference to the BitAbstractArchiveCreator object containing all the settings to
* be used for creating the new archive.
*/
explicit BitOutputArchive( const BitAbstractArchiveCreator& creator );

/**
* @brief Constructs a BitOutputArchive object, opening an (optional) input file archive.
*
Expand All @@ -65,7 +73,7 @@ class BitOutputArchive {
* be used for creating the new archive and reading the (optional) input archive.
* @param in_file (optional) the path to an input archive file.
*/
explicit BitOutputArchive( const BitAbstractArchiveCreator& creator, tstring in_file = {} );
explicit BitOutputArchive( const BitAbstractArchiveCreator& creator, const tstring& in_file );

/**
* @brief Constructs a BitOutputArchive object, opening an input file archive from the given buffer.
Expand Down Expand Up @@ -283,6 +291,12 @@ class BitOutputArchive {

CMyComPtr< IOutStream > initOutFileStream( const fs::path& out_archive, bool updating_archive ) const;

#if defined( _WIN32 ) && defined( BIT7Z_AUTO_PREFIX_LONG_PATHS )
BitOutputArchive( const BitAbstractArchiveCreator& creator, fs::path in_arc );
#else
BitOutputArchive( const BitAbstractArchiveCreator& creator, const fs::path& in_arc );
#endif

void compressToFile( const fs::path& out_file, UpdateCallback* update_callback );

void compressOut( IOutArchive* out_arc,
Expand Down
1 change: 1 addition & 0 deletions src/bitarchivewriter.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,7 @@
*/

#include "bitarchivewriter.hpp"
#include "internal/fs.hpp"

namespace bit7z {

Expand Down
1 change: 1 addition & 0 deletions src/bitfilecompressor.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,7 @@
#include "biterror.hpp"
#include "bitexception.hpp"
#include "bitoutputarchive.hpp"
#include "internal/fs.hpp"

using namespace std;
using namespace bit7z;
Expand Down
46 changes: 29 additions & 17 deletions src/bitinputarchive.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,7 @@
#include "internal/cfileinstream.hpp"
#include "internal/fileextractcallback.hpp"
#include "internal/fixedbufferextractcallback.hpp"
#include "internal/fsutil.hpp"
#include "internal/streamextractcallback.hpp"
#include "internal/opencallback.hpp"
#include "internal/util.hpp"
Expand Down Expand Up @@ -74,11 +75,7 @@ void testArc( IInArchive* in_archive, ExtractCallback* extract_callback ) {
}
}

bool ends_with( const tstring& str, const tstring& suffix ) {
return str.size() >= suffix.size() && str.compare( str.size() - suffix.size(), suffix.size(), suffix ) == 0;
}

IInArchive* BitInputArchive::openArchiveStream( const tstring& name, IInStream* in_stream ) {
IInArchive* BitInputArchive::openArchiveStream( const fs::path& name, IInStream* in_stream ) {
#ifdef BIT7Z_AUTO_FORMAT
bool detected_by_signature = false;
if ( *mDetectedFormat == BitFormat::Auto ) {
Expand Down Expand Up @@ -116,30 +113,45 @@ IInArchive* BitInputArchive::openArchiveStream( const tstring& name, IInStream*
#endif

if ( res != S_OK ) {
throw BitException( "Failed to open the archive", make_hresult_code( res ), name );
throw BitException( "Failed to open the archive", make_hresult_code( res ), name.string< tchar >() );
}

return in_archive.Detach();
}

BitInputArchive::BitInputArchive( const BitAbstractArchiveHandler& handler, tstring in_file )
: mArchiveHandler{ handler }, mArchivePath{ std::move( in_file ) } {

#ifdef BIT7Z_AUTO_FORMAT
//if auto, detect the format from extension (and try later from signature if it fails), otherwise try passed format.
mDetectedFormat = ( handler.format() == BitFormat::Auto ? &detectFormatFromExt( mArchivePath )
: &handler.format() );
# define DETECT_FORMAT( format, arc_path ) ( format == BitFormat::Auto ? &detectFormatFromExt( arc_path ) : &format )
#else
# define DETECT_FORMAT( format, arc_path ) &format
#endif

BitInputArchive::BitInputArchive( const BitAbstractArchiveHandler& handler, const tstring& in_file )
: BitInputArchive( handler, fs::path{ in_file } ) {}

#if defined( _WIN32 ) && defined( BIT7Z_AUTO_PREFIX_LONG_PATHS )
BitInputArchive::BitInputArchive( const BitAbstractArchiveHandler& handler, fs::path arc_path )
: mDetectedFormat{ nullptr },
#else
mDetectedFormat = &handler.format();
BitInputArchive::BitInputArchive( const BitAbstractArchiveHandler& handler, const fs::path& arc_path )
: mDetectedFormat{ DETECT_FORMAT( handler.format(), arc_path ) },
#endif
mArchiveHandler{ handler },
mArchivePath{ arc_path.string< tchar >() } {

#if defined( _WIN32 ) && defined( BIT7Z_AUTO_PREFIX_LONG_PATHS )
if ( filesystem::fsutil::should_format_long_path( arc_path ) ) {
arc_path = filesystem::fsutil::format_long_path( arc_path );
}
mDetectedFormat = DETECT_FORMAT( handler.format(), arc_path );
#endif

CMyComPtr< IInStream > file_stream;
if ( *mDetectedFormat != BitFormat::Split && ends_with( mArchivePath, BIT7Z_STRING( ".001" ) ) ) {
file_stream = bit7z::make_com< CMultiVolumeInStream, IInStream >( mArchivePath );
if ( *mDetectedFormat != BitFormat::Split && arc_path.extension() == ".001" ) {
file_stream = bit7z::make_com< CMultiVolumeInStream, IInStream >( arc_path );
} else {
file_stream = bit7z::make_com< CFileInStream, IInStream >( mArchivePath );
file_stream = bit7z::make_com< CFileInStream, IInStream >( arc_path );
}
mInArchive = openArchiveStream( mArchivePath, file_stream );
mInArchive = openArchiveStream( arc_path, file_stream );
}

BitInputArchive::BitInputArchive( const BitAbstractArchiveHandler& handler, const vector< byte_t >& in_buffer )
Expand Down
41 changes: 29 additions & 12 deletions src/bitoutputarchive.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -16,24 +16,41 @@
#include "bitexception.hpp"
#include "internal/cbufferoutstream.hpp"
#include "internal/cmultivolumeoutstream.hpp"
#include "internal/fsutil.hpp"
#include "internal/genericinputitem.hpp"
#include "internal/updatecallback.hpp"
#include "internal/util.hpp"

namespace bit7z {

BitOutputArchive::BitOutputArchive( const BitAbstractArchiveCreator& creator, tstring in_file )
BitOutputArchive::BitOutputArchive( const BitAbstractArchiveCreator& creator )
: mArchiveCreator{ creator }, mInputArchiveItemsCount{ 0 } {}

BitOutputArchive::BitOutputArchive( const BitAbstractArchiveCreator& creator, const tstring& in_file )
: BitOutputArchive( creator, fs::path{ in_file } ) {}

#if defined( _WIN32 ) && defined( BIT7Z_AUTO_PREFIX_LONG_PATHS )
BitOutputArchive::BitOutputArchive( const BitAbstractArchiveCreator& creator, fs::path in_arc )
#else
BitOutputArchive::BitOutputArchive( const BitAbstractArchiveCreator& creator, const fs::path& in_arc )
#endif
: mArchiveCreator{ creator }, mInputArchiveItemsCount{ 0 } {
if ( mArchiveCreator.overwriteMode() != OverwriteMode::None ) {
return;
}

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

#if defined( _WIN32 ) && defined( BIT7Z_AUTO_PREFIX_LONG_PATHS )
if ( filesystem::fsutil::should_format_long_path( in_arc ) ) {
in_arc = filesystem::fsutil::format_long_path( in_arc );
}
#endif

std::error_code error;
if ( !fs::exists( in_file, error ) ) { // An input file was specified, but it doesn't exist, so we ignore it.
if ( !fs::exists( in_arc, error ) ) { // An input file was specified, but it doesn't exist, so we ignore it.
return;
}

Expand All @@ -48,7 +65,7 @@ BitOutputArchive::BitOutputArchive( const BitAbstractArchiveCreator& creator, ts
make_error_code( BitError::FormatFeatureNotSupported ) );
}

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

Expand Down Expand Up @@ -183,18 +200,16 @@ void BitOutputArchive::compressToFile( const fs::path& out_file, UpdateCallback*
* the one of CMyComPtr (which in turns calls the one of IOutStream)! */
out_stream.Release(); //Releasing the output stream so that we can rename it as the original file.

std::error_code error;
#if defined( __MINGW32__ ) && defined( BIT7Z_USE_STANDARD_FILESYSTEM )
/* MinGW seems to not follow the standard since filesystem::rename does not overwrite an already
* existing destination file (as it should). So we explicitly remove it before! */
std::error_code ec;
fs::remove( out_file, ec );
if ( ec ) {
throw BitException( "Failed to delete the old archive file", ec, out_file );
if ( !fs::remove( out_file, error ) ) {
throw BitException( "Failed to delete the old archive file", error, out_file.string< tchar >() );
}
#endif

//remove the old file and rename the temporary file (move file with overwriting)
std::error_code error;
fs::path tmp_file = out_file;
tmp_file += ".tmp";
fs::rename( tmp_file, out_file, error );
Expand All @@ -205,21 +220,23 @@ void BitOutputArchive::compressToFile( const fs::path& out_file, UpdateCallback*
}

void BitOutputArchive::compressTo( const tstring& out_file ) {
using namespace bit7z::filesystem;
const fs::path out_path = FORMAT_LONG_PATH( out_file );
std::error_code error;
if ( fs::exists( out_file, error ) ) {
if ( fs::exists( out_path, error ) ) {
const OverwriteMode overwrite_mode = mArchiveCreator.overwriteMode();
if ( overwrite_mode == OverwriteMode::Skip ) { // Skipping if the output file already exists
return;
}
if ( overwrite_mode == OverwriteMode::Overwrite && !fs::remove( out_file, error ) ) {
if ( overwrite_mode == OverwriteMode::Overwrite && !fs::remove( out_path, error ) ) {
throw BitException( "Failed to delete the old archive file", error, out_file );
}
// Note: if overwrite_mode is OverwriteMode::None, an exception will be thrown by the CFileOutStream constructor
// called by the initOutFileStream function.
}

auto update_callback = bit7z::make_com< UpdateCallback >( *this );
compressToFile( out_file, update_callback );
compressToFile( out_path, update_callback );
}

void BitOutputArchive::compressTo( std::vector< byte_t >& out_buffer ) {
Expand Down
12 changes: 12 additions & 0 deletions src/internal/archiveproperties.hpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
#ifndef ARCHIVEPROPERTIES_HPP
#define ARCHIVEPROPERTIES_HPP

namespace bit7z {

class ArchiveProperties {

};

} // bit7z

#endif //ARCHIVEPROPERTIES_HPP
8 changes: 4 additions & 4 deletions src/internal/cmultivolumeinstream.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -20,10 +20,10 @@
using bit7z::CMultiVolumeInStream;
using bit7z::CVolumeInStream;

CMultiVolumeInStream::CMultiVolumeInStream( const tstring& first_volume ) : mCurrentPosition{ 0 }, mTotalSize{ 0 } {
CMultiVolumeInStream::CMultiVolumeInStream( const fs::path& first_volume ) : mCurrentPosition{ 0 }, mTotalSize{ 0 } {
constexpr size_t volume_digits = 3u;
size_t volume_index = 1u;
tstring volume_path = first_volume;
fs::path volume_path = first_volume;
while ( fs::exists( volume_path ) ) {
addVolume( volume_path );

Expand All @@ -34,7 +34,7 @@ CMultiVolumeInStream::CMultiVolumeInStream( const tstring& first_volume ) : mCur
volume_digits - volume_ext.length(),
BIT7Z_STRING( '0' ) );
}
volume_path.replace( volume_path.size() - volume_digits, volume_digits, volume_ext );
volume_path.replace_extension( volume_ext );
}
}

Expand Down Expand Up @@ -123,7 +123,7 @@ STDMETHODIMP CMultiVolumeInStream::Seek( Int64 offset, UInt32 seekOrigin, UInt64
return S_OK;
}

void CMultiVolumeInStream::addVolume( const bit7z::tstring& volume_path ) {
void CMultiVolumeInStream::addVolume( const fs::path& volume_path ) {
uint64_t global_offset = 0;
if ( !mVolumes.empty() ) {
const auto& last_stream = mVolumes.back();
Expand Down
4 changes: 2 additions & 2 deletions src/internal/cmultivolumeinstream.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -27,10 +27,10 @@ class CMultiVolumeInStream : public IInStream, public CMyUnknownImp {

const CMyComPtr< CVolumeInStream >& currentVolume();

void addVolume( const bit7z::tstring& volume_path );
void addVolume( const fs::path& volume_path );

public:
explicit CMultiVolumeInStream( const tstring& first_volume );
explicit CMultiVolumeInStream( const fs::path& first_volume );

CMultiVolumeInStream( const CMultiVolumeInStream& ) = delete;

Expand Down
2 changes: 1 addition & 1 deletion src/internal/cvolumeinstream.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,7 @@

using bit7z::CVolumeInStream;

CVolumeInStream::CVolumeInStream( const bit7z::tstring& volume_path, uint64_t global_offset )
CVolumeInStream::CVolumeInStream( const fs::path& volume_path, uint64_t global_offset )
: CFileInStream{ volume_path }, mSize{ fs::file_size( volume_path ) }, mGlobalOffset{ global_offset } {}

BIT7Z_NODISCARD
Expand Down
2 changes: 1 addition & 1 deletion src/internal/cvolumeinstream.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,7 @@ namespace bit7z {

class CVolumeInStream final : public CFileInStream {
public:
explicit CVolumeInStream( const tstring& volume_path, uint64_t global_offset );
explicit CVolumeInStream( const fs::path& volume_path, uint64_t global_offset );

BIT7Z_NODISCARD uint64_t globalOffset() const;

Expand Down
7 changes: 7 additions & 0 deletions src/internal/fileextractcallback.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,7 @@
using namespace std;
using namespace NWindows;
using namespace bit7z;
using namespace bit7z::filesystem;

constexpr auto kCannotDeleteOutput = "Cannot delete output file";

Expand Down Expand Up @@ -71,6 +72,12 @@ HRESULT FileExtractCallback::getOutStream( uint32_t index, ISequentialOutStream*
}
mFilePathOnDisk = mDirectoryPath / filePath;

#if defined( _WIN32 ) && defined( BIT7Z_AUTO_PREFIX_LONG_PATHS )
if ( fsutil::should_format_long_path( mFilePathOnDisk ) ) {
mFilePathOnDisk = fsutil::format_long_path( mFilePathOnDisk );
}
#endif

if ( !isItemFolder( index ) ) { // File
if ( mHandler.fileCallback() ) {
mHandler.fileCallback()( filePath.string< tchar >() );
Expand Down
Loading

0 comments on commit 3d3cec7

Please sign in to comment.