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