diff --git a/debian/changelog b/debian/changelog index a65f217..01f13e0 100644 --- a/debian/changelog +++ b/debian/changelog @@ -9,6 +9,7 @@ rpi-imager (1.7.6) unstable; urgency=medium * Workaround for ArchLinux's lsblk labeling internal SD card readers (mmcblk0) as non-removable storage. * Allow drag-dropping image files to Imager. + * Local .xz files: parse uncompressed size for better progress reports. -- Floris Bos Sat, 23 Sep 2023 19:47:40 +0200 diff --git a/src/CMakeLists.txt b/src/CMakeLists.txt index 38017ab..d338580 100644 --- a/src/CMakeLists.txt +++ b/src/CMakeLists.txt @@ -352,5 +352,5 @@ else() install(FILES "${CMAKE_CURRENT_BINARY_DIR}/rpi-imager.metainfo.xml" DESTINATION share/metainfo) endif() -include_directories(${CURL_INCLUDE_DIR} ${LibArchive_INCLUDE_DIR} ${OPENSSL_INCLUDE_DIR}) +include_directories(${CURL_INCLUDE_DIR} ${LibArchive_INCLUDE_DIR} ${OPENSSL_INCLUDE_DIR} ${LIBLZMA_INCLUDE_DIR}) target_link_libraries(${PROJECT_NAME} PRIVATE ${QT}::Core ${QT}::Quick ${QT}::Svg ${CURL_LIBRARIES} ${LibArchive_LIBRARIES} ${OPENSSL_LIBRARIES} ${ATOMIC_LIBRARY} ${EXTRALIBS}) diff --git a/src/imagewriter.cpp b/src/imagewriter.cpp index 9253642..5d5b397 100644 --- a/src/imagewriter.cpp +++ b/src/imagewriter.cpp @@ -14,6 +14,7 @@ #include "wlancredentials.h" #include #include +#include #include #include #include @@ -242,6 +243,8 @@ void ImageWriter::startWrite() _extrLen = _downloadLen; else if (lowercaseurl.endsWith(".zip")) _parseCompressedFile(); + else if (lowercaseurl.endsWith(".xz")) + _parseXZFile(); } if (_devLen && _extrLen > _devLen) @@ -648,6 +651,47 @@ void ImageWriter::_parseCompressedFile() qDebug() << "Parsed .zip file containing" << numFiles << "files, uncompressed size:" << _extrLen; } +void ImageWriter::_parseXZFile() +{ + QFile f(_src.toLocalFile()); + lzma_stream_flags opts = { 0 }; + _extrLen = 0; + + if (f.size() > LZMA_STREAM_HEADER_SIZE && f.open(f.ReadOnly)) + { + f.seek(f.size()-LZMA_STREAM_HEADER_SIZE); + QByteArray footer = f.read(LZMA_STREAM_HEADER_SIZE); + lzma_ret ret = lzma_stream_footer_decode(&opts, (const uint8_t *) footer.constData()); + + if (ret == LZMA_OK && opts.backward_size < 1000000 && opts.backward_size < f.size()-LZMA_STREAM_HEADER_SIZE) + { + f.seek(f.size()-LZMA_STREAM_HEADER_SIZE-opts.backward_size); + QByteArray buf = f.read(opts.backward_size+LZMA_STREAM_HEADER_SIZE); + lzma_index *idx; + uint64_t memlimit = UINT64_MAX; + size_t pos = 0; + + ret = lzma_index_buffer_decode(&idx, &memlimit, NULL, (const uint8_t *) buf.constData(), &pos, buf.size()); + if (ret == LZMA_OK) + { + _extrLen = lzma_index_uncompressed_size(idx); + qDebug() << "Parsed .xz file. Uncompressed size:" << _extrLen; + } + else + { + qDebug() << "Unable to parse index of .xz file"; + } + lzma_index_end(idx, NULL); + } + else + { + qDebug() << "Unable to parse footer of .xz file"; + } + + f.close(); + } +} + bool ImageWriter::isOnline() { return _online || !_embeddedMode; diff --git a/src/imagewriter.h b/src/imagewriter.h index 4328815..2fd63da 100644 --- a/src/imagewriter.h +++ b/src/imagewriter.h @@ -181,6 +181,7 @@ protected: #endif void _parseCompressedFile(); + void _parseXZFile(); QString _pubKeyFileName(); QString _privKeyFileName(); QString _sshKeyDir();