1*5ffd83dbSDimitry Andric //===-- LZMA.cpp ----------------------------------------------------------===// 29dba64beSDimitry Andric // 39dba64beSDimitry Andric // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. 49dba64beSDimitry Andric // See https://llvm.org/LICENSE.txt for license information. 59dba64beSDimitry Andric // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception 69dba64beSDimitry Andric // 79dba64beSDimitry Andric //===----------------------------------------------------------------------===// 89dba64beSDimitry Andric 99dba64beSDimitry Andric #include "lldb/Host/Config.h" 109dba64beSDimitry Andric #include "llvm/ADT/StringRef.h" 119dba64beSDimitry Andric #include "llvm/Support/Error.h" 129dba64beSDimitry Andric 139dba64beSDimitry Andric #if LLDB_ENABLE_LZMA 149dba64beSDimitry Andric #include <lzma.h> 159dba64beSDimitry Andric #endif // LLDB_ENABLE_LZMA 169dba64beSDimitry Andric 179dba64beSDimitry Andric namespace lldb_private { 189dba64beSDimitry Andric 199dba64beSDimitry Andric namespace lzma { 209dba64beSDimitry Andric 219dba64beSDimitry Andric #if !LLDB_ENABLE_LZMA 229dba64beSDimitry Andric bool isAvailable() { return false; } 239dba64beSDimitry Andric llvm::Expected<uint64_t> 249dba64beSDimitry Andric getUncompressedSize(llvm::ArrayRef<uint8_t> InputBuffer) { 259dba64beSDimitry Andric llvm_unreachable("lzma::getUncompressedSize is unavailable"); 269dba64beSDimitry Andric } 279dba64beSDimitry Andric 289dba64beSDimitry Andric llvm::Error uncompress(llvm::ArrayRef<uint8_t> InputBuffer, 299dba64beSDimitry Andric llvm::SmallVectorImpl<uint8_t> &Uncompressed) { 309dba64beSDimitry Andric llvm_unreachable("lzma::uncompress is unavailable"); 319dba64beSDimitry Andric } 329dba64beSDimitry Andric 339dba64beSDimitry Andric #else // LLDB_ENABLE_LZMA 349dba64beSDimitry Andric 359dba64beSDimitry Andric bool isAvailable() { return true; } 369dba64beSDimitry Andric 379dba64beSDimitry Andric static const char *convertLZMACodeToString(lzma_ret Code) { 389dba64beSDimitry Andric switch (Code) { 399dba64beSDimitry Andric case LZMA_STREAM_END: 409dba64beSDimitry Andric return "lzma error: LZMA_STREAM_END"; 419dba64beSDimitry Andric case LZMA_NO_CHECK: 429dba64beSDimitry Andric return "lzma error: LZMA_NO_CHECK"; 439dba64beSDimitry Andric case LZMA_UNSUPPORTED_CHECK: 449dba64beSDimitry Andric return "lzma error: LZMA_UNSUPPORTED_CHECK"; 459dba64beSDimitry Andric case LZMA_GET_CHECK: 469dba64beSDimitry Andric return "lzma error: LZMA_GET_CHECK"; 479dba64beSDimitry Andric case LZMA_MEM_ERROR: 489dba64beSDimitry Andric return "lzma error: LZMA_MEM_ERROR"; 499dba64beSDimitry Andric case LZMA_MEMLIMIT_ERROR: 509dba64beSDimitry Andric return "lzma error: LZMA_MEMLIMIT_ERROR"; 519dba64beSDimitry Andric case LZMA_FORMAT_ERROR: 529dba64beSDimitry Andric return "lzma error: LZMA_FORMAT_ERROR"; 539dba64beSDimitry Andric case LZMA_OPTIONS_ERROR: 549dba64beSDimitry Andric return "lzma error: LZMA_OPTIONS_ERROR"; 559dba64beSDimitry Andric case LZMA_DATA_ERROR: 569dba64beSDimitry Andric return "lzma error: LZMA_DATA_ERROR"; 579dba64beSDimitry Andric case LZMA_BUF_ERROR: 589dba64beSDimitry Andric return "lzma error: LZMA_BUF_ERROR"; 599dba64beSDimitry Andric case LZMA_PROG_ERROR: 609dba64beSDimitry Andric return "lzma error: LZMA_PROG_ERROR"; 619dba64beSDimitry Andric default: 629dba64beSDimitry Andric llvm_unreachable("unknown or unexpected lzma status code"); 639dba64beSDimitry Andric } 649dba64beSDimitry Andric } 659dba64beSDimitry Andric 669dba64beSDimitry Andric llvm::Expected<uint64_t> 679dba64beSDimitry Andric getUncompressedSize(llvm::ArrayRef<uint8_t> InputBuffer) { 689dba64beSDimitry Andric lzma_stream_flags opts{}; 699dba64beSDimitry Andric if (InputBuffer.size() < LZMA_STREAM_HEADER_SIZE) { 709dba64beSDimitry Andric return llvm::createStringError( 719dba64beSDimitry Andric llvm::inconvertibleErrorCode(), 729dba64beSDimitry Andric "size of xz-compressed blob (%lu bytes) is smaller than the " 739dba64beSDimitry Andric "LZMA_STREAM_HEADER_SIZE (%lu bytes)", 749dba64beSDimitry Andric InputBuffer.size(), LZMA_STREAM_HEADER_SIZE); 759dba64beSDimitry Andric } 769dba64beSDimitry Andric 779dba64beSDimitry Andric // Decode xz footer. 789dba64beSDimitry Andric lzma_ret xzerr = lzma_stream_footer_decode( 799dba64beSDimitry Andric &opts, InputBuffer.take_back(LZMA_STREAM_HEADER_SIZE).data()); 809dba64beSDimitry Andric if (xzerr != LZMA_OK) { 819dba64beSDimitry Andric return llvm::createStringError(llvm::inconvertibleErrorCode(), 829dba64beSDimitry Andric "lzma_stream_footer_decode()=%s", 839dba64beSDimitry Andric convertLZMACodeToString(xzerr)); 849dba64beSDimitry Andric } 859dba64beSDimitry Andric if (InputBuffer.size() < (opts.backward_size + LZMA_STREAM_HEADER_SIZE)) { 869dba64beSDimitry Andric return llvm::createStringError( 879dba64beSDimitry Andric llvm::inconvertibleErrorCode(), 889dba64beSDimitry Andric "xz-compressed buffer size (%lu bytes) too small (required at " 899dba64beSDimitry Andric "least %lu bytes) ", 909dba64beSDimitry Andric InputBuffer.size(), (opts.backward_size + LZMA_STREAM_HEADER_SIZE)); 919dba64beSDimitry Andric } 929dba64beSDimitry Andric 939dba64beSDimitry Andric // Decode xz index. 949dba64beSDimitry Andric lzma_index *xzindex; 959dba64beSDimitry Andric uint64_t memlimit(UINT64_MAX); 969dba64beSDimitry Andric size_t inpos = 0; 979dba64beSDimitry Andric xzerr = lzma_index_buffer_decode( 989dba64beSDimitry Andric &xzindex, &memlimit, nullptr, 999dba64beSDimitry Andric InputBuffer.take_back(LZMA_STREAM_HEADER_SIZE + opts.backward_size) 1009dba64beSDimitry Andric .data(), 1019dba64beSDimitry Andric &inpos, InputBuffer.size()); 1029dba64beSDimitry Andric if (xzerr != LZMA_OK) { 1039dba64beSDimitry Andric return llvm::createStringError(llvm::inconvertibleErrorCode(), 1049dba64beSDimitry Andric "lzma_index_buffer_decode()=%s", 1059dba64beSDimitry Andric convertLZMACodeToString(xzerr)); 1069dba64beSDimitry Andric } 1079dba64beSDimitry Andric 1089dba64beSDimitry Andric // Get size of uncompressed file to construct an in-memory buffer of the 1099dba64beSDimitry Andric // same size on the calling end (if needed). 1109dba64beSDimitry Andric uint64_t uncompressedSize = lzma_index_uncompressed_size(xzindex); 1119dba64beSDimitry Andric 1129dba64beSDimitry Andric // Deallocate xz index as it is no longer needed. 1139dba64beSDimitry Andric lzma_index_end(xzindex, nullptr); 1149dba64beSDimitry Andric 1159dba64beSDimitry Andric return uncompressedSize; 1169dba64beSDimitry Andric } 1179dba64beSDimitry Andric 1189dba64beSDimitry Andric llvm::Error uncompress(llvm::ArrayRef<uint8_t> InputBuffer, 1199dba64beSDimitry Andric llvm::SmallVectorImpl<uint8_t> &Uncompressed) { 1209dba64beSDimitry Andric llvm::Expected<uint64_t> uncompressedSize = getUncompressedSize(InputBuffer); 1219dba64beSDimitry Andric 1229dba64beSDimitry Andric if (auto err = uncompressedSize.takeError()) 1239dba64beSDimitry Andric return err; 1249dba64beSDimitry Andric 1259dba64beSDimitry Andric Uncompressed.resize(*uncompressedSize); 1269dba64beSDimitry Andric 1279dba64beSDimitry Andric // Decompress xz buffer to buffer. 1289dba64beSDimitry Andric uint64_t memlimit = UINT64_MAX; 1299dba64beSDimitry Andric size_t inpos = 0; 1309dba64beSDimitry Andric size_t outpos = 0; 1319dba64beSDimitry Andric lzma_ret ret = lzma_stream_buffer_decode( 1329dba64beSDimitry Andric &memlimit, 0, nullptr, InputBuffer.data(), &inpos, InputBuffer.size(), 1339dba64beSDimitry Andric Uncompressed.data(), &outpos, Uncompressed.size()); 1349dba64beSDimitry Andric if (ret != LZMA_OK) { 1359dba64beSDimitry Andric return llvm::createStringError(llvm::inconvertibleErrorCode(), 1369dba64beSDimitry Andric "lzma_stream_buffer_decode()=%s", 1379dba64beSDimitry Andric convertLZMACodeToString(ret)); 1389dba64beSDimitry Andric } 1399dba64beSDimitry Andric 1409dba64beSDimitry Andric return llvm::Error::success(); 1419dba64beSDimitry Andric } 1429dba64beSDimitry Andric 1439dba64beSDimitry Andric #endif // LLDB_ENABLE_LZMA 1449dba64beSDimitry Andric 1459dba64beSDimitry Andric } // end of namespace lzma 1469dba64beSDimitry Andric } // namespace lldb_private 147