Browse Source

QGCCLZMA: use xz-embedded lib

QGC4.4
Beat Küng 4 years ago committed by Lorenz Meier
parent
commit
1a3e01bb3f
  1. 138
      src/Compression/QGCLZMA.cc
  2. 2
      src/Vehicle/ComponentInformationManager.cc

138
src/Compression/QGCLZMA.cc

@ -13,16 +13,10 @@
#include <QDir> #include <QDir>
#include <QtDebug> #include <QtDebug>
#include "lzma.h" #include "xz.h"
bool QGCLZMA::inflateLZMAFile(const QString& lzmaFilename, const QString& decompressedFilename) bool QGCLZMA::inflateLZMAFile(const QString& lzmaFilename, const QString& decompressedFilename)
{ {
bool success = true;
const int cBuffer = 1024 * 5;
unsigned char inputBuffer[cBuffer];
unsigned char outputBuffer[cBuffer];
lzma_stream lzmaStrm = LZMA_STREAM_INIT;
QFile inputFile(lzmaFilename); QFile inputFile(lzmaFilename);
if (!inputFile.open(QIODevice::ReadOnly)) { if (!inputFile.open(QIODevice::ReadOnly)) {
qWarning() << "QGCLZMA::inflateLZMAFile: open input file failed" << lzmaFilename << inputFile.errorString(); qWarning() << "QGCLZMA::inflateLZMAFile: open input file failed" << lzmaFilename << inputFile.errorString();
@ -35,63 +29,99 @@ bool QGCLZMA::inflateLZMAFile(const QString& lzmaFilename, const QString& decomp
return false; return false;
} }
// UINT64_MAX - used as much memory as needed to decode
int lzmaRetCode = lzma_alone_decoder(&lzmaStrm, UINT64_MAX); // TODO: call once during startup
if (lzmaRetCode != LZMA_OK) { xz_crc32_init();
qWarning() << "QGCLZMA::inflateLZMAFile: lzma_alone_decoder failed:" << lzmaRetCode; xz_crc64_init();
xz_dec *s = xz_dec_init(XZ_DYNALLOC, (uint32_t)-1);
if (s == nullptr) {
qWarning() << "QGCLZMA::inflateLZMAFile: Memory allocation failed";
return false; return false;
} }
// When LZMA_CONCATENATED flag was used when initializing the decoder, const int buf_size = 4 * 1024;
// we need to tell lzma_code() when there will be no more input. uint8_t in[buf_size];
// This is done by setting action to LZMA_FINISH instead of LZMA_RUN uint8_t out[buf_size];
// in the same way as it is done when encoding.
// xz_buf b;
// When LZMA_CONCATENATED isn't used, there is no need to use b.in = in;
// LZMA_FINISH to tell when all the input has been read, but it b.in_pos = 0;
// is still OK to use it if you want. When LZMA_CONCATENATED isn't b.in_size = 0;
// used, the decoder will stop after the first .xz stream. In that b.out = out;
// case some unused data may be left in lzmaStrm.next_in. b.out_pos = 0;
lzma_action action = LZMA_RUN; b.out_size = buf_size;
lzmaStrm.next_in = nullptr; while (true) {
lzmaStrm.avail_in = 0; if (b.in_pos == b.in_size) {
lzmaStrm.next_out = nullptr; b.in_size = static_cast<size_t>(inputFile.read((char*)in, sizeof(in)));
lzmaStrm.avail_out = cBuffer; b.in_pos = 0;
do {
lzmaStrm.avail_in = static_cast<unsigned>(inputFile.read((char*)inputBuffer, cBuffer));
if (lzmaStrm.avail_in == 0) {
break;
} }
lzmaStrm.next_in = inputBuffer;
do { xz_ret ret = xz_dec_run(s, &b);
lzmaStrm.avail_out = cBuffer;
lzmaStrm.next_out = outputBuffer;
lzmaRetCode = lzma_code(&lzmaStrm, action); if (b.out_pos == sizeof(out)) {
if (lzmaRetCode != LZMA_OK && lzmaRetCode != LZMA_STREAM_END) { size_t cBytesWritten = (size_t)outputFile.write((char*)out, static_cast<int>(b.out_pos));
qWarning() << "QGCLZMA::inflateLZMAFile: inflate failed:" << lzmaRetCode; if (cBytesWritten != b.out_pos) {
goto Error; qWarning() << "QGCLZMA::inflateLZMAFile: output file write failed:" << outputFile.fileName() << outputFile.errorString();
goto error;
} }
unsigned cBytesInflated = cBuffer - lzmaStrm.avail_out; b.out_pos = 0;
qint64 cBytesWritten = outputFile.write((char*)outputBuffer, static_cast<int>(cBytesInflated)); }
if (cBytesWritten != cBytesInflated) {
qWarning() << "QGCLZMA::inflateLZMAFile: output file write failed:" << outputFile.fileName() << outputFile.errorString();
goto Error;
} if (ret == XZ_OK)
} while (lzmaStrm.avail_out == 0); continue;
} while (lzmaRetCode != LZMA_STREAM_END);
if (ret == XZ_UNSUPPORTED_CHECK) {
qWarning() << "QGCLZMA::inflateLZMAFile: Unsupported check; not verifying file integrity";
continue;
}
size_t cBytesWritten = (size_t)outputFile.write((char*)out, static_cast<int>(b.out_pos));
if (cBytesWritten != b.out_pos) {
qWarning() << "QGCLZMA::inflateLZMAFile: output file write failed:" << outputFile.fileName() << outputFile.errorString();
goto error;
}
switch (ret) {
case XZ_STREAM_END:
xz_dec_end(s);
return true;
case XZ_MEM_ERROR:
qWarning() << "QGCLZMA::inflateLZMAFile: Memory allocation failed";
goto error;
case XZ_MEMLIMIT_ERROR:
qWarning() << "QGCLZMA::inflateLZMAFile: Memory usage limit reached";
goto error;
case XZ_FORMAT_ERROR:
qWarning() << "QGCLZMA::inflateLZMAFile: Not a .xz file";
goto error;
case XZ_OPTIONS_ERROR:
qWarning() << "QGCLZMA::inflateLZMAFile: Unsupported options in the .xz headers";
goto error;
case XZ_DATA_ERROR:
case XZ_BUF_ERROR:
qWarning() << "QGCLZMA::inflateLZMAFile: File is corrupt";
goto error;
default:
qWarning() << "QGCLZMA::inflateLZMAFile: Bug!";
goto error;
}
}
Out: xz_dec_end(s);
lzma_end(&lzmaStrm); return true;
return success; error:
xz_dec_end(s);
return false;
Error:
success = false;
goto Out;
} }

2
src/Vehicle/ComponentInformationManager.cc

@ -210,7 +210,7 @@ QString RequestMetaDataTypeStateMachine::_downloadCompleteJsonWorker(const QStri
{ {
QString outputFileName = fileName; QString outputFileName = fileName;
if (fileName.endsWith(".lzma", Qt::CaseInsensitive)) { if (fileName.endsWith(".lzma", Qt::CaseInsensitive) || fileName.endsWith(".xz", Qt::CaseInsensitive)) {
outputFileName = (QDir(QStandardPaths::writableLocation(QStandardPaths::TempLocation)).absoluteFilePath(inflatedFileName)); outputFileName = (QDir(QStandardPaths::writableLocation(QStandardPaths::TempLocation)).absoluteFilePath(inflatedFileName));
if (QGCLZMA::inflateLZMAFile(fileName, outputFileName)) { if (QGCLZMA::inflateLZMAFile(fileName, outputFileName)) {
QFile(fileName).remove(); QFile(fileName).remove();

Loading…
Cancel
Save