user5911118
user5911118

Reputation:

C++ Boost and Lzma decompression

I am trying to decompress a .7z (or .xz or .lzma) file using

with the following code:

    vector<T> readFromCompressedFile(string input_file_path, string output_file_path)
    {
    namespace io = boost::iostreams;

    stringstream strstream;

    ifstream file(input_file_path.c_str(), ios_base::in | ios_base::binary);
    ofstream out(output_file_path, ios_base::out | ios_base::binary);

    boost::iostreams::filtering_istream in;
    in.push(io::lzma_decompressor());
    in.push(file);

    io::copy(in, out);

    cout<<strstream.str()<<endl;

The code compiles, but I get a runtime exception (lzma_error) raised by the copy method

warning: GDB: Failed to set controlling terminal: Operation not permitted
terminate called after throwing an instance of 'boost::exception_detail::clone_impl<boost::exception_detail::error_info_injector<boost::iostreams::lzma_error> >'
  what():  lzma error: iostream error

I tried with no luck to use a filtering_streambuf filter with a chunk of code very similar to the one for the gzip example

https://www.boost.org/doc/libs/1_67_0/libs/iostreams/doc/classes/gzip.html#examples

However I am able to decompress a file compressed with gzip and with the above code. It seems that the issue is limited to LZMA algorithm.

Anyone with the same issue? Any ideas?

Thank you

Upvotes: 5

Views: 3292

Answers (2)

iericzhou
iericzhou

Reputation: 645

Your code is fine and this is not a bug.

At first, I encountered the same problem as described above, but after some study I found that it is because boost iostreams library calls lzma_stream_decoder provided by the XZ library to do the decoding job, and .lzma or .7z format file is not supported by the lzma_stream_decoder. If you try to decode .lzma or .7z format file with boost iostreams library, an exception with error code: LZMA_FORMAT_ERROR will be thrown. Please refer to the error code definition in the XZ source code xz-5.2.4.tar.gz

\src\liblzma\api\lzma\base.h

LZMA_FORMAT_ERROR       = 7,
    /**<
     * \brief       File format not recognized
     *
     * The decoder did not recognize the input as supported file
     * format. This error can occur, for example, when trying to
     * decode .lzma format file with lzma_stream_decoder,
     * because lzma_stream_decoder accepts only the .xz format.
     */

And please refer to the source code of boost iostreams library: lzma.cpp

You may try to decode a .xz file and there will be no problem. I have alredy tested this with the same code you provided on Windows X64 & boost library 1.66.0.

By the way, the code provided by @sehe for error detecting is misleading:

 try {
    io::copy(in, out);
} catch(io::lzma_error const& e) {
    std::cout << boost::diagnostic_information(e, true);
    std::cout << e.code() << ": " << e.code().message() << "\n";
}

should be:

 try {
    io::copy(in, out);
} catch(io::lzma_error const& e) {
    std::cout << boost::diagnostic_information(e, true);
    std::cout << e.error() << ": " << e.code().message() << "\n";
}

Then you will find the error code thrown with the exception is: 7 (LZMA_FORMAT_ERROR).

Upvotes: 5

sehe
sehe

Reputation: 392833

I can confirm the same issue.

No problem decompressing the lzma file using other tools. There might be a versioning thing at play, or maybe there's a bug. Here's a cleaned up version of the code that doesn't have as much noise, irons out some dubious style (using namespace std) and tries to get more error information:

#include <boost/iostreams/copy.hpp>
#include <boost/iostreams/filter/lzma.hpp>
#include <boost/iostreams/filtering_stream.hpp>
#include <boost/exception/diagnostic_information.hpp>
#include <fstream>
#include <iostream>

namespace io = boost::iostreams;

void foo(std::string input_file_path, std::string output_file_path) {
    namespace io = boost::iostreams;

    std::ifstream file(input_file_path, std::ios::binary);
    std::ofstream out(output_file_path, std::ios::binary);

    boost::iostreams::filtering_istreambuf in;
    in.push(io::lzma_decompressor());
    in.push(file);

    try {
        io::copy(in, out);
    } catch(io::lzma_error const& e) {
        std::cout << boost::diagnostic_information(e, true);
        std::cout << e.code() << ": " << e.code().message() << "\n";
    } catch(boost::exception const& e) {
        std::cout << boost::diagnostic_information(e, true);
    }
}

int main() {
    foo("test.cpp.lzma", "output.txt");
}

On my system I have verified that that both the test program and /usr/bin/lzma link to the exact same version of the library, so versioning problems seem pretty unlikely at this point:

enter image description here

I think the problem should be reported upstream (at the boost Trac, mailing list or github issue)

Upvotes: 3

Related Questions