//===-- LZMA.cpp ----------------------------------------------------------===// // // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. // See https://llvm.org/LICENSE.txt for license information. // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception // //===----------------------------------------------------------------------===// #include "lldb/Host/Config.h" #include "llvm/ADT/StringRef.h" #include "llvm/Support/Error.h" #if LLDB_ENABLE_LZMA #include #endif // LLDB_ENABLE_LZMA namespace lldb_private { namespace lzma { #if !LLDB_ENABLE_LZMA bool isAvailable() { return false; } llvm::Expected getUncompressedSize(llvm::ArrayRef InputBuffer) { llvm_unreachable("lzma::getUncompressedSize is unavailable"); } llvm::Error uncompress(llvm::ArrayRef InputBuffer, llvm::SmallVectorImpl &Uncompressed) { llvm_unreachable("lzma::uncompress is unavailable"); } #else // LLDB_ENABLE_LZMA bool isAvailable() { return true; } static const char *convertLZMACodeToString(lzma_ret Code) { switch (Code) { case LZMA_STREAM_END: return "lzma error: LZMA_STREAM_END"; case LZMA_NO_CHECK: return "lzma error: LZMA_NO_CHECK"; case LZMA_UNSUPPORTED_CHECK: return "lzma error: LZMA_UNSUPPORTED_CHECK"; case LZMA_GET_CHECK: return "lzma error: LZMA_GET_CHECK"; case LZMA_MEM_ERROR: return "lzma error: LZMA_MEM_ERROR"; case LZMA_MEMLIMIT_ERROR: return "lzma error: LZMA_MEMLIMIT_ERROR"; case LZMA_FORMAT_ERROR: return "lzma error: LZMA_FORMAT_ERROR"; case LZMA_OPTIONS_ERROR: return "lzma error: LZMA_OPTIONS_ERROR"; case LZMA_DATA_ERROR: return "lzma error: LZMA_DATA_ERROR"; case LZMA_BUF_ERROR: return "lzma error: LZMA_BUF_ERROR"; case LZMA_PROG_ERROR: return "lzma error: LZMA_PROG_ERROR"; default: llvm_unreachable("unknown or unexpected lzma status code"); } } llvm::Expected getUncompressedSize(llvm::ArrayRef InputBuffer) { lzma_stream_flags opts{}; if (InputBuffer.size() < LZMA_STREAM_HEADER_SIZE) { return llvm::createStringError( llvm::inconvertibleErrorCode(), "size of xz-compressed blob (%lu bytes) is smaller than the " "LZMA_STREAM_HEADER_SIZE (%lu bytes)", InputBuffer.size(), LZMA_STREAM_HEADER_SIZE); } // Decode xz footer. lzma_ret xzerr = lzma_stream_footer_decode( &opts, InputBuffer.take_back(LZMA_STREAM_HEADER_SIZE).data()); if (xzerr != LZMA_OK) { return llvm::createStringError(llvm::inconvertibleErrorCode(), "lzma_stream_footer_decode()=%s", convertLZMACodeToString(xzerr)); } if (InputBuffer.size() < (opts.backward_size + LZMA_STREAM_HEADER_SIZE)) { return llvm::createStringError( llvm::inconvertibleErrorCode(), "xz-compressed buffer size (%lu bytes) too small (required at " "least %lu bytes) ", InputBuffer.size(), (opts.backward_size + LZMA_STREAM_HEADER_SIZE)); } // Decode xz index. lzma_index *xzindex; uint64_t memlimit(UINT64_MAX); size_t inpos = 0; xzerr = lzma_index_buffer_decode( &xzindex, &memlimit, nullptr, InputBuffer.take_back(LZMA_STREAM_HEADER_SIZE + opts.backward_size) .data(), &inpos, InputBuffer.size()); if (xzerr != LZMA_OK) { return llvm::createStringError(llvm::inconvertibleErrorCode(), "lzma_index_buffer_decode()=%s", convertLZMACodeToString(xzerr)); } // Get size of uncompressed file to construct an in-memory buffer of the // same size on the calling end (if needed). uint64_t uncompressedSize = lzma_index_uncompressed_size(xzindex); // Deallocate xz index as it is no longer needed. lzma_index_end(xzindex, nullptr); return uncompressedSize; } llvm::Error uncompress(llvm::ArrayRef InputBuffer, llvm::SmallVectorImpl &Uncompressed) { llvm::Expected uncompressedSize = getUncompressedSize(InputBuffer); if (auto err = uncompressedSize.takeError()) return err; Uncompressed.resize(*uncompressedSize); // Decompress xz buffer to buffer. uint64_t memlimit = UINT64_MAX; size_t inpos = 0; size_t outpos = 0; lzma_ret ret = lzma_stream_buffer_decode( &memlimit, 0, nullptr, InputBuffer.data(), &inpos, InputBuffer.size(), Uncompressed.data(), &outpos, Uncompressed.size()); if (ret != LZMA_OK) { return llvm::createStringError(llvm::inconvertibleErrorCode(), "lzma_stream_buffer_decode()=%s", convertLZMACodeToString(ret)); } return llvm::Error::success(); } #endif // LLDB_ENABLE_LZMA } // end of namespace lzma } // namespace lldb_private