xref: /freebsd-src/contrib/llvm-project/lldb/source/Host/common/LZMA.cpp (revision 9dba64be9536c28e4800e06512b7f29b43ade345)
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