diff --git a/CMakeLists.txt b/CMakeLists.txt index cc81a96e0..26f27f275 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -57,6 +57,7 @@ option (AUTOMATED_BUILD_SYSTEM "TRUE if built by an automate" OFF) option (BUILD_SHARED "Build rawtherapee with shared libraries" OFF) option (WITH_RAWZOR "Build with Rawzor support" OFF) +option (WITH_BZIP "Build with Bzip2 support" ON) option (WITH_MYFILE_MMAP "Build using memory mapped file" ON) option (OPTION_OMP "Build with OpenMP support" ON) @@ -287,6 +288,16 @@ if (WITH_RAWZOR) endif (WIN32) endif (WITH_RAWZOR) +# link witz bzip +if (WITH_BZIP) + find_package(BZip2) + if (BZIP2_FOUND) + add_definitions (-DBZIP_SUPPORT) + set (EXTRA_INCDIR ${EXTRA_LIB} ${BZIP2_INCLUDE_DIR}) + set (EXTRA_LIB ${EXTRA_LIB} ${BZIP2_LIBRARIES}) + endif (BZIP2_FOUND) +endif (WITH_BZIP) + if (WITH_MYFILE_MMAP) add_definitions (-DMYFILE_MMAP) endif (WITH_MYFILE_MMAP) diff --git a/COMPILE.txt b/COMPILE.txt index 431761388..0167d6736 100644 --- a/COMPILE.txt +++ b/COMPILE.txt @@ -231,6 +231,12 @@ Linux On Ubuntu/Debian the requirements can be installed by running: sudo apt-get install build-essential cmake libgtk2.0-dev libgtkmm-2.4-dev libtiff-dev libpng-dev libjpeg-dev liblcms-dev libiptcdata-dev mercurial + Optional: + - libbz2 available from http://www.bzip.org + + On Ubuntu/Debian the optional libraries can be installed by running: + sudo apt-get install libbz2-dev + Compile: - Enter the root directory of the RawTherapee source tree - Type: cmake -DCMAKE_BUILD_TYPE=Release -DCMAKE_INSTALL_PREFIX=./release -DBINDIR=. -DDATADIR=. -DLIBDIR=. diff --git a/rtengine/myfile.cc b/rtengine/myfile.cc index 0cfef0b88..56fed38f8 100644 --- a/rtengine/myfile.cc +++ b/rtengine/myfile.cc @@ -23,6 +23,9 @@ #ifdef RAWZOR_SUPPORT #include #endif +#ifdef BZIP_SUPPORT +#include +#endif // get mmap() sorted out #ifdef MYFILE_MMAP @@ -94,6 +97,76 @@ IMFILE* fopen (const char* fname) mf->data = (char*)data; mf->eof = false; +#ifdef BZIP_SUPPORT + { + bool bzip = false; + Glib::ustring bname = Glib::path_get_basename(fname); + int lastdot = bname.find_last_of ('.'); + if (lastdot!=bname.npos) + bzip = bname.substr (lastdot).casefold() == Glib::ustring(".bz2").casefold(); + + if (bzip) { + int ret; + + // initialize bzip stream structure + bz_stream stream; + stream.bzalloc = 0; + stream.bzfree = 0; + stream.opaque = 0; + ret = BZ2_bzDecompressInit(&stream, 0, 0); + + if (ret != BZ_OK) { + printf("bzip initialization failed with error %d\n", ret); + } + else { + // allocate initial buffer for decompressed data + unsigned int buffer_out_count = 0; // bytes of decompressed data + unsigned int buffer_size = 10*1024*1024; // 10 MB, extended dynamically if needed + char* buffer = 0; + + stream.next_in = mf->data; // input data address + stream.avail_in = mf->size; + + while (ret == BZ_OK) { + buffer = static_cast( realloc(buffer, buffer_size)); // allocate/resize buffer + + stream.next_out = buffer + buffer_out_count; // output data adress + stream.avail_out = buffer_size - buffer_out_count; + + ret = BZ2_bzDecompress(&stream); + + buffer_size *= 2; // increase buffer size for next iteration + buffer_out_count = stream.total_out_lo32; + if (stream.total_out_hi32 > 0) + printf("bzip decompressed data byte count high byte is nonzero: %d\n", stream.total_out_hi32); + } + + if (ret == BZ_STREAM_END) { + //delete [] mf->data; + // close memory mapping, setting fd -1 will ensure deletion of mf->data upon fclose() + mf->fd = -1; + munmap((void*)mf->data,mf->size); + close(mf->fd); + + char* realData = new char [buffer_out_count]; + memcpy(realData, buffer, buffer_out_count); + + mf->data = realData; + mf->size = buffer_out_count; + } + else + printf("bzip decompression failed with error %d\n", ret); + + // cleanup + free(buffer); + ret = BZ2_bzDecompressEnd(&stream); + if (ret != BZ_OK) + printf("bzip cleanup failed with error %d\n", ret); + } + } + } +#endif // BZIP_SUPPORT + return mf; } @@ -137,8 +210,7 @@ IMFILE* fopen (const char* fname) { } // RAWZOR support end #endif - - return mf; + return mf; } IMFILE* gfopen (const char* fname) { @@ -176,7 +248,71 @@ IMFILE* gfopen (const char* fname) { } // RAWZOR support end #endif - return mf; +#ifdef BZIP_SUPPORT + { + bool bzip = false; + Glib::ustring bname = Glib::path_get_basename(fname); + int lastdot = bname.find_last_of ('.'); + if (lastdot!=bname.npos) + bzip = bname.substr (lastdot).casefold() == Glib::ustring(".bz2").casefold(); + + if (bzip) { + int ret; + + // initialize bzip stream structure + bz_stream stream; + stream.bzalloc = 0; + stream.bzfree = 0; + stream.opaque = 0; + ret = BZ2_bzDecompressInit(&stream, 0, 0); + + if (ret != BZ_OK) { + printf("bzip initialization failed with error %d\n", ret); + } + else { + // allocate initial buffer for decompressed data + unsigned int buffer_out_count = 0; // bytes of decompressed data + unsigned int buffer_size = 10*1024*1024; // 10 MB, extended dynamically if needed + char* buffer = 0; + + stream.next_in = mf->data; // input data address + stream.avail_in = mf->size; + + while (ret == BZ_OK) { + buffer = static_cast( realloc(buffer, buffer_size)); // allocate/resize buffer + + stream.next_out = buffer + buffer_out_count; // output data adress + stream.avail_out = buffer_size - buffer_out_count; + + ret = BZ2_bzDecompress(&stream); + + buffer_size *= 2; // increase buffer size for next iteration + buffer_out_count = stream.total_out_lo32; + if (stream.total_out_hi32 > 0) + printf("bzip decompressed data byte count high byte is nonzero: %d\n", stream.total_out_hi32); + } + + if (ret == BZ_STREAM_END) { + delete [] mf->data; + char* realData = new char [buffer_out_count]; + memcpy(realData, buffer, buffer_out_count); + + mf->data = realData; + mf->size = buffer_out_count; + } + else + printf("bzip decompression failed with error %d\n", ret); + + // cleanup + free(buffer); + ret = BZ2_bzDecompressEnd(&stream); + if (ret != BZ_OK) + printf("bzip cleanup failed with error %d\n", ret); + } + } + } +#endif // BZIP_SUPPORT + return mf; } #endif //MYFILE_MMAP