5

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

  • boost library 1.67.0 on a Linux platform

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

Some programmer dude
  • 400,186
  • 35
  • 402
  • 621

2 Answers2

5

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).

iericzhou
  • 620
  • 8
  • 11
  • Thanks a LOT - this is not just a problem with the extension, but `xz` and `lzma` are different compressed formats. – TCSGrad Oct 06 '20 at 04:14
3

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)

sehe
  • 374,641
  • 47
  • 450
  • 633