rippled
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
12namespace xrpl {
13
14namespace compression_algorithms {
15
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 if (LZ4_decompress_safe(
72 reinterpret_cast<char const*>(in),
73 reinterpret_cast<char*>(decompressed),
74 inSize,
75 decompressedSize) != decompressedSize)
76 Throw<std::runtime_error>("lz4Decompress: failed");
77
78 return decompressedSize;
79}
80
89template <typename InputStream>
92 InputStream& in,
93 std::size_t inSize,
94 std::uint8_t* decompressed,
95 std::size_t decompressedSize)
96{
98 std::uint8_t const* chunk = nullptr;
99 int chunkSize = 0;
100 int copiedInSize = 0;
101 auto const currentBytes = in.ByteCount();
102
103 // Use the first chunk if it is >= inSize bytes of the compressed message.
104 // Otherwise copy inSize bytes of chunks into compressed buffer and
105 // use the buffer to decompress.
106 while (in.Next(reinterpret_cast<void const**>(&chunk), &chunkSize))
107 {
108 if (copiedInSize == 0)
109 {
110 if (chunkSize >= inSize)
111 {
112 copiedInSize = inSize;
113 break;
114 }
115 compressed.resize(inSize);
116 }
117
118 chunkSize = chunkSize < (inSize - copiedInSize) ? chunkSize : (inSize - copiedInSize);
119
120 std::copy(chunk, chunk + chunkSize, compressed.data() + copiedInSize);
121
122 copiedInSize += chunkSize;
123
124 if (copiedInSize == inSize)
125 {
126 chunk = compressed.data();
127 break;
128 }
129 }
130
131 // Put back unused bytes
132 if (in.ByteCount() > (currentBytes + copiedInSize))
133 in.BackUp(in.ByteCount() - currentBytes - copiedInSize);
134
135 if ((copiedInSize == 0 && chunkSize < inSize) || (copiedInSize > 0 && copiedInSize != inSize))
136 Throw<std::runtime_error>("lz4 decompress: insufficient input size");
137
138 return lz4Decompress(chunk, inSize, decompressed, decompressedSize);
139}
140
141} // namespace compression_algorithms
142
143} // namespace xrpl
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.
Use hash_* containers for keys that do not need a cryptographically secure hashing algorithm.
Definition algorithm.h:5
T resize(T... args)