1353952Sdim//===-- LZMA.cpp ------------------------------------------------*- C++ -*-===// 2353952Sdim// 3353952Sdim// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. 4353952Sdim// See https://llvm.org/LICENSE.txt for license information. 5353952Sdim// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception 6353952Sdim// 7353952Sdim//===----------------------------------------------------------------------===// 8353952Sdim 9353952Sdim#include "lldb/Host/Config.h" 10353952Sdim#include "llvm/ADT/StringRef.h" 11353952Sdim#include "llvm/Support/Error.h" 12353952Sdim 13353952Sdim#if LLDB_ENABLE_LZMA 14353952Sdim#include <lzma.h> 15353952Sdim#endif // LLDB_ENABLE_LZMA 16353952Sdim 17353952Sdimnamespace lldb_private { 18353952Sdim 19353952Sdimnamespace lzma { 20353952Sdim 21353952Sdim#if !LLDB_ENABLE_LZMA 22353952Sdimbool isAvailable() { return false; } 23353952Sdimllvm::Expected<uint64_t> 24353952SdimgetUncompressedSize(llvm::ArrayRef<uint8_t> InputBuffer) { 25353952Sdim llvm_unreachable("lzma::getUncompressedSize is unavailable"); 26353952Sdim} 27353952Sdim 28353952Sdimllvm::Error uncompress(llvm::ArrayRef<uint8_t> InputBuffer, 29353952Sdim llvm::SmallVectorImpl<uint8_t> &Uncompressed) { 30353952Sdim llvm_unreachable("lzma::uncompress is unavailable"); 31353952Sdim} 32353952Sdim 33353952Sdim#else // LLDB_ENABLE_LZMA 34353952Sdim 35353952Sdimbool isAvailable() { return true; } 36353952Sdim 37353952Sdimstatic const char *convertLZMACodeToString(lzma_ret Code) { 38353952Sdim switch (Code) { 39353952Sdim case LZMA_STREAM_END: 40353952Sdim return "lzma error: LZMA_STREAM_END"; 41353952Sdim case LZMA_NO_CHECK: 42353952Sdim return "lzma error: LZMA_NO_CHECK"; 43353952Sdim case LZMA_UNSUPPORTED_CHECK: 44353952Sdim return "lzma error: LZMA_UNSUPPORTED_CHECK"; 45353952Sdim case LZMA_GET_CHECK: 46353952Sdim return "lzma error: LZMA_GET_CHECK"; 47353952Sdim case LZMA_MEM_ERROR: 48353952Sdim return "lzma error: LZMA_MEM_ERROR"; 49353952Sdim case LZMA_MEMLIMIT_ERROR: 50353952Sdim return "lzma error: LZMA_MEMLIMIT_ERROR"; 51353952Sdim case LZMA_FORMAT_ERROR: 52353952Sdim return "lzma error: LZMA_FORMAT_ERROR"; 53353952Sdim case LZMA_OPTIONS_ERROR: 54353952Sdim return "lzma error: LZMA_OPTIONS_ERROR"; 55353952Sdim case LZMA_DATA_ERROR: 56353952Sdim return "lzma error: LZMA_DATA_ERROR"; 57353952Sdim case LZMA_BUF_ERROR: 58353952Sdim return "lzma error: LZMA_BUF_ERROR"; 59353952Sdim case LZMA_PROG_ERROR: 60353952Sdim return "lzma error: LZMA_PROG_ERROR"; 61353952Sdim default: 62353952Sdim llvm_unreachable("unknown or unexpected lzma status code"); 63353952Sdim } 64353952Sdim} 65353952Sdim 66353952Sdimllvm::Expected<uint64_t> 67353952SdimgetUncompressedSize(llvm::ArrayRef<uint8_t> InputBuffer) { 68353952Sdim lzma_stream_flags opts{}; 69353952Sdim if (InputBuffer.size() < LZMA_STREAM_HEADER_SIZE) { 70353952Sdim return llvm::createStringError( 71353952Sdim llvm::inconvertibleErrorCode(), 72353952Sdim "size of xz-compressed blob (%lu bytes) is smaller than the " 73353952Sdim "LZMA_STREAM_HEADER_SIZE (%lu bytes)", 74353952Sdim InputBuffer.size(), LZMA_STREAM_HEADER_SIZE); 75353952Sdim } 76353952Sdim 77353952Sdim // Decode xz footer. 78353952Sdim lzma_ret xzerr = lzma_stream_footer_decode( 79353952Sdim &opts, InputBuffer.take_back(LZMA_STREAM_HEADER_SIZE).data()); 80353952Sdim if (xzerr != LZMA_OK) { 81353952Sdim return llvm::createStringError(llvm::inconvertibleErrorCode(), 82353952Sdim "lzma_stream_footer_decode()=%s", 83353952Sdim convertLZMACodeToString(xzerr)); 84353952Sdim } 85353952Sdim if (InputBuffer.size() < (opts.backward_size + LZMA_STREAM_HEADER_SIZE)) { 86353952Sdim return llvm::createStringError( 87353952Sdim llvm::inconvertibleErrorCode(), 88353952Sdim "xz-compressed buffer size (%lu bytes) too small (required at " 89353952Sdim "least %lu bytes) ", 90353952Sdim InputBuffer.size(), (opts.backward_size + LZMA_STREAM_HEADER_SIZE)); 91353952Sdim } 92353952Sdim 93353952Sdim // Decode xz index. 94353952Sdim lzma_index *xzindex; 95353952Sdim uint64_t memlimit(UINT64_MAX); 96353952Sdim size_t inpos = 0; 97353952Sdim xzerr = lzma_index_buffer_decode( 98353952Sdim &xzindex, &memlimit, nullptr, 99353952Sdim InputBuffer.take_back(LZMA_STREAM_HEADER_SIZE + opts.backward_size) 100353952Sdim .data(), 101353952Sdim &inpos, InputBuffer.size()); 102353952Sdim if (xzerr != LZMA_OK) { 103353952Sdim return llvm::createStringError(llvm::inconvertibleErrorCode(), 104353952Sdim "lzma_index_buffer_decode()=%s", 105353952Sdim convertLZMACodeToString(xzerr)); 106353952Sdim } 107353952Sdim 108353952Sdim // Get size of uncompressed file to construct an in-memory buffer of the 109353952Sdim // same size on the calling end (if needed). 110353952Sdim uint64_t uncompressedSize = lzma_index_uncompressed_size(xzindex); 111353952Sdim 112353952Sdim // Deallocate xz index as it is no longer needed. 113353952Sdim lzma_index_end(xzindex, nullptr); 114353952Sdim 115353952Sdim return uncompressedSize; 116353952Sdim} 117353952Sdim 118353952Sdimllvm::Error uncompress(llvm::ArrayRef<uint8_t> InputBuffer, 119353952Sdim llvm::SmallVectorImpl<uint8_t> &Uncompressed) { 120353952Sdim llvm::Expected<uint64_t> uncompressedSize = getUncompressedSize(InputBuffer); 121353952Sdim 122353952Sdim if (auto err = uncompressedSize.takeError()) 123353952Sdim return err; 124353952Sdim 125353952Sdim Uncompressed.resize(*uncompressedSize); 126353952Sdim 127353952Sdim // Decompress xz buffer to buffer. 128353952Sdim uint64_t memlimit = UINT64_MAX; 129353952Sdim size_t inpos = 0; 130353952Sdim size_t outpos = 0; 131353952Sdim lzma_ret ret = lzma_stream_buffer_decode( 132353952Sdim &memlimit, 0, nullptr, InputBuffer.data(), &inpos, InputBuffer.size(), 133353952Sdim Uncompressed.data(), &outpos, Uncompressed.size()); 134353952Sdim if (ret != LZMA_OK) { 135353952Sdim return llvm::createStringError(llvm::inconvertibleErrorCode(), 136353952Sdim "lzma_stream_buffer_decode()=%s", 137353952Sdim convertLZMACodeToString(ret)); 138353952Sdim } 139353952Sdim 140353952Sdim return llvm::Error::success(); 141353952Sdim} 142353952Sdim 143353952Sdim#endif // LLDB_ENABLE_LZMA 144353952Sdim 145353952Sdim} // end of namespace lzma 146353952Sdim} // namespace lldb_private 147