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