/Users/buildslave/jenkins/workspace/coverage/llvm-project/lldb/source/Host/common/LZMA.cpp
Line | Count | Source (jump to first uncovered line) |
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 | 2 | bool isAvailable() { return true; } |
36 | | |
37 | 1 | static const char *convertLZMACodeToString(lzma_ret Code) { |
38 | 1 | switch (Code) { |
39 | 0 | case LZMA_STREAM_END: |
40 | 0 | return "lzma error: LZMA_STREAM_END"; |
41 | 0 | case LZMA_NO_CHECK: |
42 | 0 | return "lzma error: LZMA_NO_CHECK"; |
43 | 0 | case LZMA_UNSUPPORTED_CHECK: |
44 | 0 | return "lzma error: LZMA_UNSUPPORTED_CHECK"; |
45 | 0 | case LZMA_GET_CHECK: |
46 | 0 | return "lzma error: LZMA_GET_CHECK"; |
47 | 0 | case LZMA_MEM_ERROR: |
48 | 0 | return "lzma error: LZMA_MEM_ERROR"; |
49 | 0 | case LZMA_MEMLIMIT_ERROR: |
50 | 0 | return "lzma error: LZMA_MEMLIMIT_ERROR"; |
51 | 0 | case LZMA_FORMAT_ERROR: |
52 | 0 | return "lzma error: LZMA_FORMAT_ERROR"; |
53 | 0 | case LZMA_OPTIONS_ERROR: |
54 | 0 | return "lzma error: LZMA_OPTIONS_ERROR"; |
55 | 1 | case LZMA_DATA_ERROR: |
56 | 1 | return "lzma error: LZMA_DATA_ERROR"; |
57 | 0 | case LZMA_BUF_ERROR: |
58 | 0 | return "lzma error: LZMA_BUF_ERROR"; |
59 | 0 | case LZMA_PROG_ERROR: |
60 | 0 | return "lzma error: LZMA_PROG_ERROR"; |
61 | 0 | default: |
62 | 0 | llvm_unreachable("unknown or unexpected lzma status code"); |
63 | 1 | } |
64 | 1 | } |
65 | | |
66 | | llvm::Expected<uint64_t> |
67 | 2 | getUncompressedSize(llvm::ArrayRef<uint8_t> InputBuffer) { |
68 | 2 | lzma_stream_flags opts{}; |
69 | 2 | if (InputBuffer.size() < LZMA_STREAM_HEADER_SIZE) { |
70 | 0 | return llvm::createStringError( |
71 | 0 | llvm::inconvertibleErrorCode(), |
72 | 0 | "size of xz-compressed blob (%lu bytes) is smaller than the " |
73 | 0 | "LZMA_STREAM_HEADER_SIZE (%lu bytes)", |
74 | 0 | InputBuffer.size(), LZMA_STREAM_HEADER_SIZE); |
75 | 0 | } |
76 | | |
77 | | // Decode xz footer. |
78 | 2 | lzma_ret xzerr = lzma_stream_footer_decode( |
79 | 2 | &opts, InputBuffer.take_back(LZMA_STREAM_HEADER_SIZE).data()); |
80 | 2 | if (xzerr != LZMA_OK) { |
81 | 0 | return llvm::createStringError(llvm::inconvertibleErrorCode(), |
82 | 0 | "lzma_stream_footer_decode()=%s", |
83 | 0 | convertLZMACodeToString(xzerr)); |
84 | 0 | } |
85 | 2 | if (InputBuffer.size() < (opts.backward_size + LZMA_STREAM_HEADER_SIZE)) { |
86 | 0 | return llvm::createStringError( |
87 | 0 | llvm::inconvertibleErrorCode(), |
88 | 0 | "xz-compressed buffer size (%lu bytes) too small (required at " |
89 | 0 | "least %lu bytes) ", |
90 | 0 | InputBuffer.size(), (opts.backward_size + LZMA_STREAM_HEADER_SIZE)); |
91 | 0 | } |
92 | | |
93 | | // Decode xz index. |
94 | 2 | lzma_index *xzindex; |
95 | 2 | uint64_t memlimit(UINT64_MAX); |
96 | 2 | size_t inpos = 0; |
97 | 2 | xzerr = lzma_index_buffer_decode( |
98 | 2 | &xzindex, &memlimit, nullptr, |
99 | 2 | InputBuffer.take_back(LZMA_STREAM_HEADER_SIZE + opts.backward_size) |
100 | 2 | .data(), |
101 | 2 | &inpos, InputBuffer.size()); |
102 | 2 | if (xzerr != LZMA_OK) { |
103 | 0 | return llvm::createStringError(llvm::inconvertibleErrorCode(), |
104 | 0 | "lzma_index_buffer_decode()=%s", |
105 | 0 | convertLZMACodeToString(xzerr)); |
106 | 0 | } |
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 | 2 | uint64_t uncompressedSize = lzma_index_uncompressed_size(xzindex); |
111 | | |
112 | | // Deallocate xz index as it is no longer needed. |
113 | 2 | lzma_index_end(xzindex, nullptr); |
114 | | |
115 | 2 | return uncompressedSize; |
116 | 2 | } |
117 | | |
118 | | llvm::Error uncompress(llvm::ArrayRef<uint8_t> InputBuffer, |
119 | 2 | llvm::SmallVectorImpl<uint8_t> &Uncompressed) { |
120 | 2 | llvm::Expected<uint64_t> uncompressedSize = getUncompressedSize(InputBuffer); |
121 | | |
122 | 2 | if (auto err = uncompressedSize.takeError()) |
123 | 0 | return err; |
124 | | |
125 | 2 | Uncompressed.resize(*uncompressedSize); |
126 | | |
127 | | // Decompress xz buffer to buffer. |
128 | 2 | uint64_t memlimit = UINT64_MAX; |
129 | 2 | size_t inpos = 0; |
130 | 2 | size_t outpos = 0; |
131 | 2 | lzma_ret ret = lzma_stream_buffer_decode( |
132 | 2 | &memlimit, 0, nullptr, InputBuffer.data(), &inpos, InputBuffer.size(), |
133 | 2 | Uncompressed.data(), &outpos, Uncompressed.size()); |
134 | 2 | if (ret != LZMA_OK) { |
135 | 1 | return llvm::createStringError(llvm::inconvertibleErrorCode(), |
136 | 1 | "lzma_stream_buffer_decode()=%s", |
137 | 1 | convertLZMACodeToString(ret)); |
138 | 1 | } |
139 | | |
140 | 1 | return llvm::Error::success(); |
141 | 2 | } |
142 | | |
143 | | #endif // LLDB_ENABLE_LZMA |
144 | | |
145 | | } // end of namespace lzma |
146 | | } // namespace lldb_private |