1*9dba64beSDimitry Andric //===-- LZMA.cpp ------------------------------------------------*- C++ -*-===// 2*9dba64beSDimitry Andric // 3*9dba64beSDimitry Andric // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. 4*9dba64beSDimitry Andric // See https://llvm.org/LICENSE.txt for license information. 5*9dba64beSDimitry Andric // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception 6*9dba64beSDimitry Andric // 7*9dba64beSDimitry Andric //===----------------------------------------------------------------------===// 8*9dba64beSDimitry Andric 9*9dba64beSDimitry Andric #include "lldb/Host/Config.h" 10*9dba64beSDimitry Andric #include "llvm/ADT/StringRef.h" 11*9dba64beSDimitry Andric #include "llvm/Support/Error.h" 12*9dba64beSDimitry Andric 13*9dba64beSDimitry Andric #if LLDB_ENABLE_LZMA 14*9dba64beSDimitry Andric #include <lzma.h> 15*9dba64beSDimitry Andric #endif // LLDB_ENABLE_LZMA 16*9dba64beSDimitry Andric 17*9dba64beSDimitry Andric namespace lldb_private { 18*9dba64beSDimitry Andric 19*9dba64beSDimitry Andric namespace lzma { 20*9dba64beSDimitry Andric 21*9dba64beSDimitry Andric #if !LLDB_ENABLE_LZMA 22*9dba64beSDimitry Andric bool isAvailable() { return false; } 23*9dba64beSDimitry Andric llvm::Expected<uint64_t> 24*9dba64beSDimitry Andric getUncompressedSize(llvm::ArrayRef<uint8_t> InputBuffer) { 25*9dba64beSDimitry Andric llvm_unreachable("lzma::getUncompressedSize is unavailable"); 26*9dba64beSDimitry Andric } 27*9dba64beSDimitry Andric 28*9dba64beSDimitry Andric llvm::Error uncompress(llvm::ArrayRef<uint8_t> InputBuffer, 29*9dba64beSDimitry Andric llvm::SmallVectorImpl<uint8_t> &Uncompressed) { 30*9dba64beSDimitry Andric llvm_unreachable("lzma::uncompress is unavailable"); 31*9dba64beSDimitry Andric } 32*9dba64beSDimitry Andric 33*9dba64beSDimitry Andric #else // LLDB_ENABLE_LZMA 34*9dba64beSDimitry Andric 35*9dba64beSDimitry Andric bool isAvailable() { return true; } 36*9dba64beSDimitry Andric 37*9dba64beSDimitry Andric static const char *convertLZMACodeToString(lzma_ret Code) { 38*9dba64beSDimitry Andric switch (Code) { 39*9dba64beSDimitry Andric case LZMA_STREAM_END: 40*9dba64beSDimitry Andric return "lzma error: LZMA_STREAM_END"; 41*9dba64beSDimitry Andric case LZMA_NO_CHECK: 42*9dba64beSDimitry Andric return "lzma error: LZMA_NO_CHECK"; 43*9dba64beSDimitry Andric case LZMA_UNSUPPORTED_CHECK: 44*9dba64beSDimitry Andric return "lzma error: LZMA_UNSUPPORTED_CHECK"; 45*9dba64beSDimitry Andric case LZMA_GET_CHECK: 46*9dba64beSDimitry Andric return "lzma error: LZMA_GET_CHECK"; 47*9dba64beSDimitry Andric case LZMA_MEM_ERROR: 48*9dba64beSDimitry Andric return "lzma error: LZMA_MEM_ERROR"; 49*9dba64beSDimitry Andric case LZMA_MEMLIMIT_ERROR: 50*9dba64beSDimitry Andric return "lzma error: LZMA_MEMLIMIT_ERROR"; 51*9dba64beSDimitry Andric case LZMA_FORMAT_ERROR: 52*9dba64beSDimitry Andric return "lzma error: LZMA_FORMAT_ERROR"; 53*9dba64beSDimitry Andric case LZMA_OPTIONS_ERROR: 54*9dba64beSDimitry Andric return "lzma error: LZMA_OPTIONS_ERROR"; 55*9dba64beSDimitry Andric case LZMA_DATA_ERROR: 56*9dba64beSDimitry Andric return "lzma error: LZMA_DATA_ERROR"; 57*9dba64beSDimitry Andric case LZMA_BUF_ERROR: 58*9dba64beSDimitry Andric return "lzma error: LZMA_BUF_ERROR"; 59*9dba64beSDimitry Andric case LZMA_PROG_ERROR: 60*9dba64beSDimitry Andric return "lzma error: LZMA_PROG_ERROR"; 61*9dba64beSDimitry Andric default: 62*9dba64beSDimitry Andric llvm_unreachable("unknown or unexpected lzma status code"); 63*9dba64beSDimitry Andric } 64*9dba64beSDimitry Andric } 65*9dba64beSDimitry Andric 66*9dba64beSDimitry Andric llvm::Expected<uint64_t> 67*9dba64beSDimitry Andric getUncompressedSize(llvm::ArrayRef<uint8_t> InputBuffer) { 68*9dba64beSDimitry Andric lzma_stream_flags opts{}; 69*9dba64beSDimitry Andric if (InputBuffer.size() < LZMA_STREAM_HEADER_SIZE) { 70*9dba64beSDimitry Andric return llvm::createStringError( 71*9dba64beSDimitry Andric llvm::inconvertibleErrorCode(), 72*9dba64beSDimitry Andric "size of xz-compressed blob (%lu bytes) is smaller than the " 73*9dba64beSDimitry Andric "LZMA_STREAM_HEADER_SIZE (%lu bytes)", 74*9dba64beSDimitry Andric InputBuffer.size(), LZMA_STREAM_HEADER_SIZE); 75*9dba64beSDimitry Andric } 76*9dba64beSDimitry Andric 77*9dba64beSDimitry Andric // Decode xz footer. 78*9dba64beSDimitry Andric lzma_ret xzerr = lzma_stream_footer_decode( 79*9dba64beSDimitry Andric &opts, InputBuffer.take_back(LZMA_STREAM_HEADER_SIZE).data()); 80*9dba64beSDimitry Andric if (xzerr != LZMA_OK) { 81*9dba64beSDimitry Andric return llvm::createStringError(llvm::inconvertibleErrorCode(), 82*9dba64beSDimitry Andric "lzma_stream_footer_decode()=%s", 83*9dba64beSDimitry Andric convertLZMACodeToString(xzerr)); 84*9dba64beSDimitry Andric } 85*9dba64beSDimitry Andric if (InputBuffer.size() < (opts.backward_size + LZMA_STREAM_HEADER_SIZE)) { 86*9dba64beSDimitry Andric return llvm::createStringError( 87*9dba64beSDimitry Andric llvm::inconvertibleErrorCode(), 88*9dba64beSDimitry Andric "xz-compressed buffer size (%lu bytes) too small (required at " 89*9dba64beSDimitry Andric "least %lu bytes) ", 90*9dba64beSDimitry Andric InputBuffer.size(), (opts.backward_size + LZMA_STREAM_HEADER_SIZE)); 91*9dba64beSDimitry Andric } 92*9dba64beSDimitry Andric 93*9dba64beSDimitry Andric // Decode xz index. 94*9dba64beSDimitry Andric lzma_index *xzindex; 95*9dba64beSDimitry Andric uint64_t memlimit(UINT64_MAX); 96*9dba64beSDimitry Andric size_t inpos = 0; 97*9dba64beSDimitry Andric xzerr = lzma_index_buffer_decode( 98*9dba64beSDimitry Andric &xzindex, &memlimit, nullptr, 99*9dba64beSDimitry Andric InputBuffer.take_back(LZMA_STREAM_HEADER_SIZE + opts.backward_size) 100*9dba64beSDimitry Andric .data(), 101*9dba64beSDimitry Andric &inpos, InputBuffer.size()); 102*9dba64beSDimitry Andric if (xzerr != LZMA_OK) { 103*9dba64beSDimitry Andric return llvm::createStringError(llvm::inconvertibleErrorCode(), 104*9dba64beSDimitry Andric "lzma_index_buffer_decode()=%s", 105*9dba64beSDimitry Andric convertLZMACodeToString(xzerr)); 106*9dba64beSDimitry Andric } 107*9dba64beSDimitry Andric 108*9dba64beSDimitry Andric // Get size of uncompressed file to construct an in-memory buffer of the 109*9dba64beSDimitry Andric // same size on the calling end (if needed). 110*9dba64beSDimitry Andric uint64_t uncompressedSize = lzma_index_uncompressed_size(xzindex); 111*9dba64beSDimitry Andric 112*9dba64beSDimitry Andric // Deallocate xz index as it is no longer needed. 113*9dba64beSDimitry Andric lzma_index_end(xzindex, nullptr); 114*9dba64beSDimitry Andric 115*9dba64beSDimitry Andric return uncompressedSize; 116*9dba64beSDimitry Andric } 117*9dba64beSDimitry Andric 118*9dba64beSDimitry Andric llvm::Error uncompress(llvm::ArrayRef<uint8_t> InputBuffer, 119*9dba64beSDimitry Andric llvm::SmallVectorImpl<uint8_t> &Uncompressed) { 120*9dba64beSDimitry Andric llvm::Expected<uint64_t> uncompressedSize = getUncompressedSize(InputBuffer); 121*9dba64beSDimitry Andric 122*9dba64beSDimitry Andric if (auto err = uncompressedSize.takeError()) 123*9dba64beSDimitry Andric return err; 124*9dba64beSDimitry Andric 125*9dba64beSDimitry Andric Uncompressed.resize(*uncompressedSize); 126*9dba64beSDimitry Andric 127*9dba64beSDimitry Andric // Decompress xz buffer to buffer. 128*9dba64beSDimitry Andric uint64_t memlimit = UINT64_MAX; 129*9dba64beSDimitry Andric size_t inpos = 0; 130*9dba64beSDimitry Andric size_t outpos = 0; 131*9dba64beSDimitry Andric lzma_ret ret = lzma_stream_buffer_decode( 132*9dba64beSDimitry Andric &memlimit, 0, nullptr, InputBuffer.data(), &inpos, InputBuffer.size(), 133*9dba64beSDimitry Andric Uncompressed.data(), &outpos, Uncompressed.size()); 134*9dba64beSDimitry Andric if (ret != LZMA_OK) { 135*9dba64beSDimitry Andric return llvm::createStringError(llvm::inconvertibleErrorCode(), 136*9dba64beSDimitry Andric "lzma_stream_buffer_decode()=%s", 137*9dba64beSDimitry Andric convertLZMACodeToString(ret)); 138*9dba64beSDimitry Andric } 139*9dba64beSDimitry Andric 140*9dba64beSDimitry Andric return llvm::Error::success(); 141*9dba64beSDimitry Andric } 142*9dba64beSDimitry Andric 143*9dba64beSDimitry Andric #endif // LLDB_ENABLE_LZMA 144*9dba64beSDimitry Andric 145*9dba64beSDimitry Andric } // end of namespace lzma 146*9dba64beSDimitry Andric } // namespace lldb_private 147