xrpld
Loading...
Searching...
No Matches
CompressionAlgorithms.h
1#pragma once
2
3#include <xrpl/basics/contract.h>
4
5#include <lz4.h>
6
7#include <algorithm>
8#include <cstddef>
9#include <cstdint>
10#include <stdexcept>
11#include <vector>
12
14
24template <typename BufferFactory>
26lz4Compress(void const* in, std::size_t inSize, BufferFactory&& bf)
27{
28 if (inSize > UINT32_MAX)
29 Throw<std::runtime_error>("lz4 compress: invalid size");
30
31 auto const outCapacity = LZ4_compressBound(inSize);
32
33 // Request the caller to allocate and return the buffer to hold compressed
34 // data
35 auto compressed = bf(outCapacity);
36
37 auto compressedSize = LZ4_compress_default(
38 reinterpret_cast<char const*>(in),
39 reinterpret_cast<char*>(compressed),
40 inSize,
41 outCapacity);
42 if (compressedSize == 0)
43 Throw<std::runtime_error>("lz4 compress: failed");
44
45 return compressedSize;
46}
47
55inline std::size_t
57 std::uint8_t const* in,
58 std::size_t inSizeUnchecked,
59 std::uint8_t* decompressed,
60 std::size_t decompressedSizeUnchecked)
61{
62 int const inSize = static_cast<int>(inSizeUnchecked);
63 int const decompressedSize = static_cast<int>(decompressedSizeUnchecked);
64
65 if (inSize <= 0)
66 Throw<std::runtime_error>("lz4Decompress: integer overflow (input)");
67
68 if (decompressedSize <= 0)
69 Throw<std::runtime_error>("lz4Decompress: integer overflow (output)");
70
71 // NOLINTNEXTLINE(readability-suspicious-call-argument)
72 if (LZ4_decompress_safe(
73 reinterpret_cast<char const*>(in),
74 reinterpret_cast<char*>(decompressed),
75 inSize,
76 decompressedSize) != decompressedSize)
77 {
78 Throw<std::runtime_error>("lz4Decompress: failed");
79 }
80
81 return decompressedSize;
82}
83
93template <typename InputStream>
96 InputStream& in,
97 std::size_t inSize,
98 std::uint8_t* decompressed,
99 std::size_t decompressedSize)
100{
101 std::vector<std::uint8_t> compressed;
102 std::uint8_t const* chunk = nullptr;
103 int chunkSize = 0;
104 int copiedInSize = 0;
105 auto const currentBytes = in.ByteCount();
106
107 // Use the first chunk if it is >= inSize bytes of the compressed message.
108 // Otherwise copy inSize bytes of chunks into compressed buffer and
109 // use the buffer to decompress.
110 while (in.Next(reinterpret_cast<void const**>(&chunk), &chunkSize))
111 {
112 if (copiedInSize == 0)
113 {
114 if (chunkSize >= inSize)
115 {
116 copiedInSize = inSize;
117 break;
118 }
119 compressed.resize(inSize);
120 }
121
122 chunkSize = chunkSize < (inSize - copiedInSize) ? chunkSize : (inSize - copiedInSize);
123
124 std::copy(chunk, chunk + chunkSize, compressed.data() + copiedInSize);
125
126 copiedInSize += chunkSize;
127
128 if (copiedInSize == inSize)
129 {
130 chunk = compressed.data();
131 break;
132 }
133 }
134
135 // Put back unused bytes
136 if (in.ByteCount() > (currentBytes + copiedInSize))
137 in.BackUp(in.ByteCount() - currentBytes - copiedInSize);
138
139 if ((copiedInSize == 0 && chunkSize < inSize) || (copiedInSize > 0 && copiedInSize != inSize))
140 Throw<std::runtime_error>("lz4 decompress: insufficient input size");
141
142 return lz4Decompress(chunk, inSize, decompressed, decompressedSize);
143}
144
145} // namespace xrpl::compression_algorithms
T copy(T... args)
T data(T... args)
std::size_t lz4Decompress(std::uint8_t const *in, std::size_t inSizeUnchecked, std::uint8_t *decompressed, std::size_t decompressedSizeUnchecked)
std::size_t lz4Compress(void const *in, std::size_t inSize, BufferFactory &&bf)
LZ4 block compression.
XRPL_NO_SANITIZE_ADDRESS void Throw(Args &&... args)
Definition contract.h:52
T resize(T... args)