blob: d94b4eb2ce1f827675808193ea8639af395161bf [file] [log] [blame]
// Copyright 2018 The Chromium OS Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
#include "modemfwd/file_decompressor.h"
#include <lzma.h>
#include <stdint.h>
#include <stdio.h>
#include <memory>
#include <base/files/file.h>
namespace modemfwd {
bool DecompressXzFile(const base::FilePath& in_file_path,
const base::FilePath& out_file_path) {
base::File in_file(in_file_path,
base::File::FLAG_OPEN | base::File::FLAG_READ);
if (!in_file.IsValid()) {
LOG(ERROR) << "Failed to open '" << in_file_path.value() << "' for read";
return false;
}
base::File out_file(out_file_path,
base::File::FLAG_CREATE_ALWAYS | base::File::FLAG_WRITE);
if (!out_file.IsValid()) {
LOG(ERROR) << "Failed to open '" << out_file_path.value() << "' for write";
return false;
}
lzma_stream stream = LZMA_STREAM_INIT;
lzma_ret ret = lzma_stream_decoder(&stream, UINT64_MAX, 0);
if (ret != LZMA_OK) {
LOG(ERROR) << "Failed initialize LZMA decoder, error=" << ret;
return false;
}
std::unique_ptr<lzma_stream, decltype(&lzma_end)> auto_stream_deleter(
&stream, &lzma_end);
lzma_action action = LZMA_RUN;
const size_t in_buffer_size = BUFSIZ;
const size_t out_buffer_size = BUFSIZ;
auto in_buffer = std::make_unique<uint8_t[]>(in_buffer_size);
auto out_buffer = std::make_unique<uint8_t[]>(out_buffer_size);
stream.next_in = nullptr;
stream.avail_in = 0;
stream.next_out = out_buffer.get();
stream.avail_out = out_buffer_size;
for (;;) {
if (stream.avail_in == 0) {
int read_ret = in_file.ReadAtCurrentPos(
reinterpret_cast<char*>(in_buffer.get()), in_buffer_size);
if (read_ret < 0) {
PLOG(ERROR) << "Failed to read from '" << out_file_path.value() << "'";
return false;
}
if (read_ret == 0)
action = LZMA_FINISH;
stream.next_in = in_buffer.get();
stream.avail_in = read_ret;
}
ret = lzma_code(&stream, action);
// Flushes the decoded data from the output buffer to the output file.
if (stream.avail_out == 0 || ret == LZMA_STREAM_END) {
size_t write_size = out_buffer_size - stream.avail_out;
if (out_file.WriteAtCurrentPos(reinterpret_cast<char*>(out_buffer.get()),
write_size) !=
static_cast<int>(write_size)) {
PLOG(ERROR) << "Failed to write to '" << out_file_path.value() << "'";
return false;
}
stream.next_out = out_buffer.get();
stream.avail_out = out_buffer_size;
}
// A LZMA_STREAM_END return value indicates that the stream has been
// decoded successfully.
if (ret == LZMA_STREAM_END)
break;
// Otherwise, a return value other than LZMA_OK indicates an error.
if (ret != LZMA_OK) {
LOG(ERROR) << "Failed to decompress '" << in_file_path.value()
<< "', error=" << ret;
return false;
}
}
return true;
}
} // namespace modemfwd