Implement LZMA file compression
This commit is contained in:
parent
6dbcba505b
commit
f56dd6d208
4 changed files with 181 additions and 3 deletions
|
|
@ -33,7 +33,7 @@ endif()
|
||||||
SET (ORIGINAL_LIB_SUFFIXES ${CMAKE_FIND_LIBRARY_SUFFIXES})
|
SET (ORIGINAL_LIB_SUFFIXES ${CMAKE_FIND_LIBRARY_SUFFIXES})
|
||||||
|
|
||||||
SET(BOOST_COMPONENTS)
|
SET(BOOST_COMPONENTS)
|
||||||
LIST(APPEND BOOST_COMPONENTS thread date_time system filesystem program_options signals serialization chrono unit_test_framework context locale)
|
LIST(APPEND BOOST_COMPONENTS thread date_time system filesystem program_options signals serialization chrono unit_test_framework context locale iostreams)
|
||||||
|
|
||||||
IF( WIN32 )
|
IF( WIN32 )
|
||||||
MESSAGE(STATUS "Configuring fc to build on Win32")
|
MESSAGE(STATUS "Configuring fc to build on Win32")
|
||||||
|
|
@ -237,6 +237,9 @@ target_link_libraries( udt_server fc udt )
|
||||||
add_executable( udt_client tests/udtc.cpp )
|
add_executable( udt_client tests/udtc.cpp )
|
||||||
target_link_libraries( udt_client fc udt )
|
target_link_libraries( udt_client fc udt )
|
||||||
|
|
||||||
|
add_executable( lzma_compress_file tests/lzma_compress_file.cpp )
|
||||||
|
target_link_libraries( lzma_compress_file fc )
|
||||||
|
|
||||||
#add_executable( test_compress tests/compress.cpp )
|
#add_executable( test_compress tests/compress.cpp )
|
||||||
#target_link_libraries( test_compress fc )
|
#target_link_libraries( test_compress fc )
|
||||||
#add_executable( test_aes tests/aes_test.cpp )
|
#add_executable( test_aes tests/aes_test.cpp )
|
||||||
|
|
|
||||||
|
|
@ -1,9 +1,16 @@
|
||||||
#pragma once
|
#pragma once
|
||||||
|
|
||||||
|
#include <fc/filesystem.hpp>
|
||||||
#include <vector>
|
#include <vector>
|
||||||
|
|
||||||
namespace fc {
|
namespace fc {
|
||||||
|
|
||||||
std::vector<char> lzma_compress( const std::vector<char>& in );
|
std::vector<char> lzma_compress( const std::vector<char>& in );
|
||||||
std::vector<char> lzma_decompress( const std::vector<char>& compressed );
|
std::vector<char> lzma_decompress( const std::vector<char>& compressed );
|
||||||
|
|
||||||
|
void lzma_compress_file( path src_path,
|
||||||
|
path dst_path,
|
||||||
|
unsigned char level = 5,
|
||||||
|
unsigned int dict_size = (1 << 20) );
|
||||||
|
|
||||||
} // namespace fc
|
} // namespace fc
|
||||||
|
|
|
||||||
|
|
@ -3,6 +3,14 @@
|
||||||
|
|
||||||
#include <lzma_c.h>
|
#include <lzma_c.h>
|
||||||
|
|
||||||
|
#include <boost/iostreams/device/mapped_file.hpp>
|
||||||
|
|
||||||
|
#include <fstream>
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
#include <iostream>
|
||||||
|
|
||||||
namespace fc {
|
namespace fc {
|
||||||
|
|
||||||
std::vector<char> lzma_compress(const std::vector<char>& in)
|
std::vector<char> lzma_compress(const std::vector<char>& in)
|
||||||
|
|
@ -50,4 +58,141 @@ std::vector<char> lzma_decompress( const std::vector<char>& compressed )
|
||||||
return out;
|
return out;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
struct lzma_file_ctx
|
||||||
|
{
|
||||||
|
const unsigned char* src_buf;
|
||||||
|
size_t src_len;
|
||||||
|
|
||||||
|
path dst_path;
|
||||||
|
};
|
||||||
|
|
||||||
|
static int input_callback( void* input_ctx, void* input_buf, size_t* input_len )
|
||||||
|
{
|
||||||
|
FC_ASSERT( input_ctx != NULL );
|
||||||
|
FC_ASSERT( input_buf != NULL );
|
||||||
|
|
||||||
|
const auto ctx = ( struct lzma_file_ctx* )input_ctx;
|
||||||
|
const auto size = ( ctx->src_len < *input_len ) ? ctx->src_len : *input_len;
|
||||||
|
|
||||||
|
if( size > 0 )
|
||||||
|
{
|
||||||
|
memcpy( input_buf, ( void * )ctx->src_buf, size );
|
||||||
|
ctx->src_buf += size;
|
||||||
|
ctx->src_len -= size;
|
||||||
|
}
|
||||||
|
|
||||||
|
*input_len = size;
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
static size_t output_callback( void* output_ctx, const void* output_buf, size_t output_len )
|
||||||
|
{
|
||||||
|
FC_ASSERT( output_ctx != NULL );
|
||||||
|
FC_ASSERT( output_buf != NULL );
|
||||||
|
|
||||||
|
const auto ctx = ( struct lzma_file_ctx* )output_ctx;
|
||||||
|
|
||||||
|
if( output_len > 0 )
|
||||||
|
{
|
||||||
|
size_t dst_len = 0;
|
||||||
|
if( !exists( ctx->dst_path ) )
|
||||||
|
{
|
||||||
|
auto fs = std::ofstream( ctx->dst_path.string() );
|
||||||
|
fs.close();
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
dst_len = file_size( ctx->dst_path );
|
||||||
|
}
|
||||||
|
|
||||||
|
resize_file( ctx->dst_path, dst_len + output_len );
|
||||||
|
|
||||||
|
boost::iostreams::mapped_file_sink dst_file;
|
||||||
|
dst_file.open( ctx->dst_path.string() );
|
||||||
|
FC_ASSERT( dst_file.is_open() );
|
||||||
|
|
||||||
|
memcpy( ( void* )(dst_file.data() + dst_len), output_buf, output_len);
|
||||||
|
|
||||||
|
dst_file.close();
|
||||||
|
}
|
||||||
|
|
||||||
|
return output_len;
|
||||||
|
}
|
||||||
|
|
||||||
|
void lzma_compress_file( path src_path,
|
||||||
|
path dst_path,
|
||||||
|
unsigned char level,
|
||||||
|
unsigned int dict_size )
|
||||||
|
{
|
||||||
|
FC_ASSERT( exists( src_path ) );
|
||||||
|
FC_ASSERT( !exists( dst_path ) );
|
||||||
|
|
||||||
|
boost::iostreams::mapped_file_source src_file;
|
||||||
|
src_file.open( src_path.string() );
|
||||||
|
FC_ASSERT( src_file.is_open() );
|
||||||
|
|
||||||
|
elzma_compress_handle handle = NULL;
|
||||||
|
handle = elzma_compress_alloc();
|
||||||
|
FC_ASSERT( handle != NULL );
|
||||||
|
|
||||||
|
struct lzma_file_ctx ctx;
|
||||||
|
ctx.src_buf = ( const unsigned char* )src_file.data();
|
||||||
|
ctx.src_len = src_file.size();
|
||||||
|
ctx.dst_path = dst_path;
|
||||||
|
|
||||||
|
auto rc = elzma_compress_config( handle,
|
||||||
|
ELZMA_LC_DEFAULT,
|
||||||
|
ELZMA_LP_DEFAULT,
|
||||||
|
ELZMA_PB_DEFAULT,
|
||||||
|
level,
|
||||||
|
dict_size,
|
||||||
|
elzma_file_format::ELZMA_lzma,
|
||||||
|
ctx.src_len );
|
||||||
|
|
||||||
|
try
|
||||||
|
{
|
||||||
|
FC_ASSERT( rc == ELZMA_E_OK );
|
||||||
|
}
|
||||||
|
catch( ... )
|
||||||
|
{
|
||||||
|
elzma_compress_free( &handle );
|
||||||
|
throw;
|
||||||
|
}
|
||||||
|
|
||||||
|
rc = elzma_compress_run( handle,
|
||||||
|
input_callback,
|
||||||
|
( void * )&ctx,
|
||||||
|
output_callback,
|
||||||
|
( void * )&ctx,
|
||||||
|
NULL,
|
||||||
|
NULL );
|
||||||
|
|
||||||
|
elzma_compress_free( &handle );
|
||||||
|
FC_ASSERT( rc == ELZMA_E_OK );
|
||||||
|
|
||||||
|
|
||||||
|
/* TEST */
|
||||||
|
FC_ASSERT( exists( dst_path ) );
|
||||||
|
|
||||||
|
boost::iostreams::mapped_file_source dst_file;
|
||||||
|
dst_file.open( dst_path.string() );
|
||||||
|
FC_ASSERT( dst_file.is_open() );
|
||||||
|
|
||||||
|
std::vector<char> result( dst_file.data(), dst_file.data() + dst_file.size() );
|
||||||
|
dst_file.close();
|
||||||
|
|
||||||
|
for( const auto& c : result )
|
||||||
|
{
|
||||||
|
std::cout << c;
|
||||||
|
}
|
||||||
|
std::cout << "\n";
|
||||||
|
|
||||||
|
result = lzma_decompress( result );
|
||||||
|
for( const auto& c : result )
|
||||||
|
{
|
||||||
|
std::cout << c;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
} // namespace fc
|
} // namespace fc
|
||||||
|
|
|
||||||
23
tests/lzma_compress_file.cpp
Normal file
23
tests/lzma_compress_file.cpp
Normal file
|
|
@ -0,0 +1,23 @@
|
||||||
|
#include <fc/compress/lzma.hpp>
|
||||||
|
#include <fc/filesystem.hpp>
|
||||||
|
|
||||||
|
#include <iostream>
|
||||||
|
#include <string>
|
||||||
|
|
||||||
|
using namespace fc;
|
||||||
|
|
||||||
|
int main( int argc, char** argv )
|
||||||
|
{
|
||||||
|
if( argc != 2 && argc != 3 )
|
||||||
|
{
|
||||||
|
std::cout << "usage: " << argv[0] << " <src_path> [dst_path = src_path.lzma]\n";
|
||||||
|
exit( -1 );
|
||||||
|
}
|
||||||
|
|
||||||
|
auto src = std::string( argv[1] );
|
||||||
|
auto dst = (argc == 3) ? std::string( argv[2] ) : src + ".lzma";
|
||||||
|
|
||||||
|
lzma_compress_file( src, dst );
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
Loading…
Reference in a new issue