Line data Source code
1 : /**
2 : Copyright (c) 2017-2022 Roman Katuntsev <sbkarr@stappler.org>
3 : Copyright (c) 2023 Stappler LLC <admin@stappler.dev>
4 :
5 : Permission is hereby granted, free of charge, to any person obtaining a copy
6 : of this software and associated documentation files (the "Software"), to deal
7 : in the Software without restriction, including without limitation the rights
8 : to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9 : copies of the Software, and to permit persons to whom the Software is
10 : furnished to do so, subject to the following conditions:
11 :
12 : The above copyright notice and this permission notice shall be included in
13 : all copies or substantial portions of the Software.
14 :
15 : THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16 : IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17 : FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18 : AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19 : LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20 : OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
21 : THE SOFTWARE.
22 : **/
23 :
24 : #ifndef STAPPLER_DATA_SPDATADECODE_H_
25 : #define STAPPLER_DATA_SPDATADECODE_H_
26 :
27 : #include "SPDataDecodeCbor.h"
28 : #include "SPDataDecodeJson.h"
29 : #include "SPDataDecodeSerenity.h"
30 :
31 : #ifdef MODULE_STAPPLER_FILESYSTEM
32 : #include "SPFilesystem.h"
33 : #endif
34 :
35 : namespace STAPPLER_VERSIONIZED stappler::data {
36 :
37 : enum class DataFormat {
38 : Unknown,
39 : Json,
40 : Cbor,
41 : Serenity,
42 :
43 : CborBase64,
44 :
45 : LZ4_Short,
46 : LZ4_Word,
47 : #ifdef MODULE_STAPPLER_BROTLI_LIB
48 : Brotli_Short,
49 : Brotli_Word,
50 : #endif
51 :
52 : // for future implementations
53 : // Encrypt,
54 : };
55 :
56 40872 : inline DataFormat detectDataFormat(const uint8_t *ptr, size_t size, uint8_t &padding) {
57 40872 : if (size > 3 && ptr[0] == 0xd9 && ptr[1] == 0xd9 && ptr[2] == 0xf7) {
58 20700 : return DataFormat::Cbor;
59 20172 : } else if (size > 4 && ptr[0] == '2' && ptr[1] == 'd' && ptr[2] == 'n' && ptr[3] == '3') {
60 0 : return DataFormat::CborBase64;
61 20172 : } else if (size > 3 && ptr[0] == 'L' && ptr[1] == 'Z' && ptr[2] == '4') {
62 1574 : switch (ptr[3]) {
63 25 : case 'S': padding = 0; return DataFormat::LZ4_Short; break;
64 0 : case 'T': padding = 1; return DataFormat::LZ4_Short; break;
65 50 : case 'U': padding = 2; return DataFormat::LZ4_Short; break;
66 0 : case 'V': padding = 3; return DataFormat::LZ4_Short; break;
67 475 : case 'W': padding = 0; return DataFormat::LZ4_Word; break;
68 400 : case 'X': padding = 1; return DataFormat::LZ4_Word; break;
69 375 : case 'Y': padding = 2; return DataFormat::LZ4_Word; break;
70 250 : case 'Z': padding = 3; return DataFormat::LZ4_Word; break;
71 : }
72 : #ifdef MODULE_STAPPLER_BROTLI_LIB
73 18598 : } else if (size > 3 && ptr[0] == 'S' && ptr[1] == 'B' && ptr[2] == 'r') {
74 625 : switch (ptr[3]) {
75 25 : case 'S': padding = 0; return DataFormat::Brotli_Short; break;
76 0 : case 'T': padding = 1; return DataFormat::Brotli_Short; break;
77 0 : case 'U': padding = 2; return DataFormat::Brotli_Short; break;
78 0 : case 'V': padding = 3; return DataFormat::Brotli_Short; break;
79 150 : case 'W': padding = 0; return DataFormat::Brotli_Word; break;
80 150 : case 'X': padding = 1; return DataFormat::Brotli_Word; break;
81 150 : case 'Y': padding = 2; return DataFormat::Brotli_Word; break;
82 150 : case 'Z': padding = 3; return DataFormat::Brotli_Word; break;
83 : }
84 : #endif
85 17973 : } else if (ptr[0] == '(') {
86 150 : return DataFormat::Serenity;
87 : } else {
88 17823 : return DataFormat::Json;
89 : }
90 0 : return DataFormat::Unknown;
91 : }
92 :
93 : size_t decompress(const uint8_t *srcData, size_t srcSize, uint8_t *dstData, size_t dstSize);
94 :
95 : size_t getDecompressedSize(const uint8_t *, size_t);
96 :
97 : template <typename Interface>
98 : auto decompressLZ4(const uint8_t *, size_t, bool sh) -> ValueTemplate<Interface>;
99 :
100 : template <typename Interface>
101 : auto decompressBrotli(const uint8_t *, size_t, bool sh) -> ValueTemplate<Interface>;
102 :
103 : template <typename Interface>
104 72 : auto decompress(const uint8_t *d, size_t size) -> typename Interface::BytesType {
105 72 : if (auto s = decompress(d, size, nullptr, 0)) {
106 72 : typename Interface::BytesType res; res.resize(s);
107 72 : if (decompress(d, size, res.data(), res.size()) == s) {
108 72 : return res;
109 : }
110 72 : }
111 0 : return typename Interface::BytesType();
112 : }
113 :
114 : template <typename Interface, typename StringType>
115 42325 : auto read(const StringType &data, const StringView &key = StringView()) -> ValueTemplate<Interface> {
116 42325 : if (data.size() == 0) {
117 1750 : return ValueTemplate<Interface>();
118 : }
119 40575 : uint8_t padding = 0;
120 40575 : auto ff = detectDataFormat((const uint8_t *)data.data(), data.size(), padding);
121 40575 : switch (ff) {
122 20700 : case DataFormat::Cbor:
123 20700 : return cbor::read<Interface>(data);
124 : break;
125 17825 : case DataFormat::Json:
126 35650 : return json::read<Interface>(StringView((char *)data.data(), data.size()));
127 : break;
128 150 : case DataFormat::Serenity:
129 300 : return serenity::read<Interface>(StringView((char *)data.data(), data.size()));
130 : break;
131 0 : case DataFormat::CborBase64:
132 0 : return read<Interface>(base64::decode<Interface>(CoderSource(data)), key);
133 : break;
134 75 : case DataFormat::LZ4_Short:
135 75 : return decompressLZ4<Interface>((const uint8_t *)data.data() + 4, data.size() - 4 - padding, true);
136 : break;
137 1200 : case DataFormat::LZ4_Word:
138 1200 : return decompressLZ4<Interface>((const uint8_t *)data.data() + 4, data.size() - 4 - padding, false);
139 : break;
140 : #ifdef MODULE_STAPPLER_BROTLI_LIB
141 25 : case DataFormat::Brotli_Short:
142 25 : return decompressBrotli<Interface>((const uint8_t *)data.data() + 4, data.size() - 4 - padding, true);
143 : break;
144 600 : case DataFormat::Brotli_Word:
145 600 : return decompressBrotli<Interface>((const uint8_t *)data.data() + 4, data.size() - 4 - padding, false);
146 : break;
147 : #endif
148 0 : default:
149 0 : break;
150 : }
151 0 : return ValueTemplate<Interface>();
152 : }
153 :
154 : #ifdef MODULE_STAPPLER_FILESYSTEM
155 : template <typename Interface>
156 12725 : auto readFile(StringView filename, const StringView &key = StringView()) -> ValueTemplate<Interface> {
157 12725 : return read<Interface>(filesystem::readIntoMemory<Interface>(filename));
158 : }
159 : #endif
160 : }
161 :
162 : #endif /* STAPPLER_DATA_SPDATADECODE_H_ */
|