rippled
Loading...
Searching...
No Matches
CompressionAlgorithms.h
1#ifndef XRPL_COMPRESSIONALGORITHMS_H_INCLUDED
2#define XRPL_COMPRESSIONALGORITHMS_H_INCLUDED
3
4#include <xrpl/basics/contract.h>
5
6#include <lz4.h>
7
8#include <algorithm>
9#include <cstdint>
10#include <stdexcept>
11#include <vector>
12
13namespace ripple {
14
15namespace compression_algorithms {
16
25template <typename BufferFactory>
27lz4Compress(void const* in, std::size_t inSize, BufferFactory&& bf)
28{
29 if (inSize > UINT32_MAX)
30 Throw<std::runtime_error>("lz4 compress: invalid size");
31
32 auto const outCapacity = LZ4_compressBound(inSize);
33
34 // Request the caller to allocate and return the buffer to hold compressed
35 // data
36 auto compressed = bf(outCapacity);
37
38 auto compressedSize = LZ4_compress_default(
39 reinterpret_cast<char const*>(in),
40 reinterpret_cast<char*>(compressed),
41 inSize,
42 outCapacity);
43 if (compressedSize == 0)
44 Throw<std::runtime_error>("lz4 compress: failed");
45
46 return compressedSize;
47}
48
56inline std::size_t
58 std::uint8_t const* in,
59 std::size_t inSizeUnchecked,
60 std::uint8_t* decompressed,
61 std::size_t decompressedSizeUnchecked)
62{
63 int const inSize = static_cast<int>(inSizeUnchecked);
64 int const decompressedSize = static_cast<int>(decompressedSizeUnchecked);
65
66 if (inSize <= 0)
67 Throw<std::runtime_error>("lz4Decompress: integer overflow (input)");
68
69 if (decompressedSize <= 0)
70 Throw<std::runtime_error>("lz4Decompress: integer overflow (output)");
71
72 if (LZ4_decompress_safe(
73 reinterpret_cast<char const*>(in),
74 reinterpret_cast<char*>(decompressed),
75 inSize,
76 decompressedSize) != decompressedSize)
77 Throw<std::runtime_error>("lz4Decompress: failed");
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)
120 ? chunkSize
121 : (inSize - copiedInSize);
122
123 std::copy(chunk, chunk + chunkSize, compressed.data() + copiedInSize);
124
125 copiedInSize += chunkSize;
126
127 if (copiedInSize == inSize)
128 {
129 chunk = compressed.data();
130 break;
131 }
132 }
133
134 // Put back unused bytes
135 if (in.ByteCount() > (currentBytes + copiedInSize))
136 in.BackUp(in.ByteCount() - currentBytes - copiedInSize);
137
138 if ((copiedInSize == 0 && chunkSize < inSize) ||
139 (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 compression_algorithms
146
147} // namespace ripple
148
149#endif // XRPL_COMPRESSIONALGORITHMS_H_INCLUDED
T copy(T... args)
T data(T... args)
std::size_t lz4Compress(void const *in, std::size_t inSize, BufferFactory &&bf)
LZ4 block compression.
std::size_t lz4Decompress(std::uint8_t const *in, std::size_t inSizeUnchecked, std::uint8_t *decompressed, std::size_t decompressedSizeUnchecked)
Use hash_* containers for keys that do not need a cryptographically secure hashing algorithm.
Definition algorithm.h:6
T resize(T... args)