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), reinterpret_cast<char*>(compressed), inSize, outCapacity);
39 if (compressedSize == 0)
40 Throw<std::runtime_error>("lz4 compress: failed");
41
42 return compressedSize;
43}
44
52inline std::size_t
54 std::uint8_t const* in,
55 std::size_t inSizeUnchecked,
56 std::uint8_t* decompressed,
57 std::size_t decompressedSizeUnchecked)
58{
59 int const inSize = static_cast<int>(inSizeUnchecked);
60 int const decompressedSize = static_cast<int>(decompressedSizeUnchecked);
61
62 if (inSize <= 0)
63 Throw<std::runtime_error>("lz4Decompress: integer overflow (input)");
64
65 if (decompressedSize <= 0)
66 Throw<std::runtime_error>("lz4Decompress: integer overflow (output)");
67
68 if (LZ4_decompress_safe(
69 reinterpret_cast<char const*>(in), reinterpret_cast<char*>(decompressed), inSize, decompressedSize) !=
70 decompressedSize)
71 Throw<std::runtime_error>("lz4Decompress: failed");
72
73 return decompressedSize;
74}
75
84template <typename InputStream>
86lz4Decompress(InputStream& in, std::size_t inSize, std::uint8_t* decompressed, std::size_t decompressedSize)
87{
89 std::uint8_t const* chunk = nullptr;
90 int chunkSize = 0;
91 int copiedInSize = 0;
92 auto const currentBytes = in.ByteCount();
93
94 // Use the first chunk if it is >= inSize bytes of the compressed message.
95 // Otherwise copy inSize bytes of chunks into compressed buffer and
96 // use the buffer to decompress.
97 while (in.Next(reinterpret_cast<void const**>(&chunk), &chunkSize))
98 {
99 if (copiedInSize == 0)
100 {
101 if (chunkSize >= inSize)
102 {
103 copiedInSize = inSize;
104 break;
105 }
106 compressed.resize(inSize);
107 }
108
109 chunkSize = chunkSize < (inSize - copiedInSize) ? chunkSize : (inSize - copiedInSize);
110
111 std::copy(chunk, chunk + chunkSize, compressed.data() + copiedInSize);
112
113 copiedInSize += chunkSize;
114
115 if (copiedInSize == inSize)
116 {
117 chunk = compressed.data();
118 break;
119 }
120 }
121
122 // Put back unused bytes
123 if (in.ByteCount() > (currentBytes + copiedInSize))
124 in.BackUp(in.ByteCount() - currentBytes - copiedInSize);
125
126 if ((copiedInSize == 0 && chunkSize < inSize) || (copiedInSize > 0 && copiedInSize != inSize))
127 Throw<std::runtime_error>("lz4 decompress: insufficient input size");
128
129 return lz4Decompress(chunk, inSize, decompressed, decompressedSize);
130}
131
132} // namespace compression_algorithms
133
134} // 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)