Coverage Report

Created: 2022-01-22 13:19

/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