1 | /** |
2 | * Copyright (c) 2006-2023 LOVE Development Team |
3 | * |
4 | * This software is provided 'as-is', without any express or implied |
5 | * warranty. In no event will the authors be held liable for any damages |
6 | * arising from the use of this software. |
7 | * |
8 | * Permission is granted to anyone to use this software for any purpose, |
9 | * including commercial applications, and to alter it and redistribute it |
10 | * freely, subject to the following restrictions: |
11 | * |
12 | * 1. The origin of this software must not be misrepresented; you must not |
13 | * claim that you wrote the original software. If you use this software |
14 | * in a product, an acknowledgment in the product documentation would be |
15 | * appreciated but is not required. |
16 | * 2. Altered source versions must be plainly marked as such, and must not be |
17 | * misrepresented as being the original software. |
18 | * 3. This notice may not be removed or altered from any source distribution. |
19 | **/ |
20 | |
21 | // LOVE |
22 | #include "DataModule.h" |
23 | #include "common/b64.h" |
24 | #include "common/int.h" |
25 | #include "common/StringMap.h" |
26 | |
27 | // STL |
28 | #include <cmath> |
29 | #include <list> |
30 | #include <iostream> |
31 | |
32 | namespace |
33 | { |
34 | |
35 | static const char hexchars[] = "0123456789abcdef" ; |
36 | |
37 | char *bytesToHex(const love::uint8 *src, size_t srclen, size_t &dstlen) |
38 | { |
39 | dstlen = srclen * 2; |
40 | |
41 | if (dstlen == 0) |
42 | return nullptr; |
43 | |
44 | char *dst = nullptr; |
45 | try |
46 | { |
47 | dst = new char[dstlen + 1]; |
48 | } |
49 | catch (std::exception &) |
50 | { |
51 | throw love::Exception("Out of memory." ); |
52 | } |
53 | |
54 | for (size_t i = 0; i < srclen; i++) |
55 | { |
56 | love::uint8 b = src[i]; |
57 | dst[i * 2 + 0] = hexchars[b >> 4]; |
58 | dst[i * 2 + 1] = hexchars[b & 0xF]; |
59 | } |
60 | |
61 | dst[dstlen] = '\0'; |
62 | return dst; |
63 | } |
64 | |
65 | love::uint8 nibble(char c) |
66 | { |
67 | if (c >= '0' && c <= '9') |
68 | return (love::uint8) (c - '0'); |
69 | |
70 | if (c >= 'A' && c <= 'F') |
71 | return (love::uint8) (c - 'A' + 0x0a); |
72 | |
73 | if (c >= 'a' && c <= 'f') |
74 | return (love::uint8) (c - 'a' + 0x0a); |
75 | |
76 | return 0; |
77 | } |
78 | |
79 | love::uint8 *hexToBytes(const char *src, size_t srclen, size_t &dstlen) |
80 | { |
81 | if (srclen >= 2 && src[0] == '0' && (src[1] == 'x' || src[1] == 'X')) |
82 | { |
83 | src += 2; |
84 | srclen -= 2; |
85 | } |
86 | |
87 | dstlen = (srclen + 1) / 2; |
88 | |
89 | if (dstlen == 0) |
90 | return nullptr; |
91 | |
92 | love::uint8 *dst = nullptr; |
93 | try |
94 | { |
95 | dst = new love::uint8[dstlen]; |
96 | } |
97 | catch (std::exception &) |
98 | { |
99 | throw love::Exception("Out of memory." ); |
100 | } |
101 | |
102 | for (size_t i = 0; i < dstlen; i++) |
103 | { |
104 | dst[i] = nibble(src[i * 2]) << 4; |
105 | |
106 | if (i * 2 + 1 < srclen) |
107 | dst[i] |= nibble(src[i * 2 + 1]); |
108 | } |
109 | |
110 | return dst; |
111 | } |
112 | |
113 | } // anonymous namespace |
114 | |
115 | namespace love |
116 | { |
117 | namespace data |
118 | { |
119 | |
120 | CompressedData *compress(Compressor::Format format, const char *rawbytes, size_t rawsize, int level) |
121 | { |
122 | Compressor *compressor = Compressor::getCompressor(format); |
123 | |
124 | if (compressor == nullptr) |
125 | throw love::Exception("Invalid compression format." ); |
126 | |
127 | size_t compressedsize = 0; |
128 | char *cbytes = compressor->compress(format, rawbytes, rawsize, level, compressedsize); |
129 | |
130 | CompressedData *data = nullptr; |
131 | |
132 | try |
133 | { |
134 | data = new CompressedData(format, cbytes, compressedsize, rawsize, true); |
135 | } |
136 | catch (love::Exception &) |
137 | { |
138 | delete[] cbytes; |
139 | throw; |
140 | } |
141 | |
142 | return data; |
143 | } |
144 | |
145 | char *decompress(CompressedData *data, size_t &decompressedsize) |
146 | { |
147 | size_t rawsize = data->getDecompressedSize(); |
148 | |
149 | char *rawbytes = decompress(data->getFormat(), (const char *) data->getData(), |
150 | data->getSize(), rawsize); |
151 | |
152 | decompressedsize = rawsize; |
153 | return rawbytes; |
154 | } |
155 | |
156 | char *decompress(Compressor::Format format, const char *cbytes, size_t compressedsize, size_t &rawsize) |
157 | { |
158 | Compressor *compressor = Compressor::getCompressor(format); |
159 | |
160 | if (compressor == nullptr) |
161 | throw love::Exception("Invalid compression format." ); |
162 | |
163 | return compressor->decompress(format, cbytes, compressedsize, rawsize); |
164 | } |
165 | |
166 | char *encode(EncodeFormat format, const char *src, size_t srclen, size_t &dstlen, size_t linelen) |
167 | { |
168 | switch (format) |
169 | { |
170 | case ENCODE_BASE64: |
171 | default: |
172 | return b64_encode(src, srclen, linelen, dstlen); |
173 | case ENCODE_HEX: |
174 | return bytesToHex((const uint8 *) src, srclen, dstlen); |
175 | } |
176 | } |
177 | |
178 | char *decode(EncodeFormat format, const char *src, size_t srclen, size_t &dstlen) |
179 | { |
180 | switch (format) |
181 | { |
182 | case ENCODE_BASE64: |
183 | default: |
184 | return b64_decode(src, srclen, dstlen); |
185 | case ENCODE_HEX: |
186 | return (char *) hexToBytes(src, srclen, dstlen); |
187 | } |
188 | } |
189 | |
190 | std::string hash(HashFunction::Function function, Data *input) |
191 | { |
192 | return hash(function, (const char*) input->getData(), input->getSize()); |
193 | } |
194 | |
195 | std::string hash(HashFunction::Function function, const char *input, uint64_t size) |
196 | { |
197 | HashFunction::Value output; |
198 | hash(function, input, size, output); |
199 | return std::string(output.data, output.size); |
200 | } |
201 | |
202 | void hash(HashFunction::Function function, Data *input, HashFunction::Value &output) |
203 | { |
204 | hash(function, (const char*) input->getData(), input->getSize(), output); |
205 | } |
206 | |
207 | void hash(HashFunction::Function function, const char *input, uint64_t size, HashFunction::Value &output) |
208 | { |
209 | HashFunction *hashfunction = HashFunction::getHashFunction(function); |
210 | if (hashfunction == nullptr) |
211 | throw love::Exception("Invalid hash function." ); |
212 | |
213 | hashfunction->hash(function, input, size, output); |
214 | } |
215 | |
216 | DataModule::DataModule() |
217 | { |
218 | } |
219 | |
220 | DataModule::~DataModule() |
221 | { |
222 | } |
223 | |
224 | DataView *DataModule::newDataView(Data *data, size_t offset, size_t size) |
225 | { |
226 | return new DataView(data, offset, size); |
227 | } |
228 | |
229 | ByteData *DataModule::newByteData(size_t size) |
230 | { |
231 | return new ByteData(size); |
232 | } |
233 | |
234 | ByteData *DataModule::newByteData(const void *d, size_t size) |
235 | { |
236 | return new ByteData(d, size); |
237 | } |
238 | |
239 | ByteData *DataModule::newByteData(void *d, size_t size, bool own) |
240 | { |
241 | return new ByteData(d, size, own); |
242 | } |
243 | |
244 | static StringMap<EncodeFormat, ENCODE_MAX_ENUM>::Entry encoderEntries[] = |
245 | { |
246 | { "base64" , ENCODE_BASE64 }, |
247 | { "hex" , ENCODE_HEX }, |
248 | }; |
249 | |
250 | static StringMap<EncodeFormat, ENCODE_MAX_ENUM> encoders(encoderEntries, sizeof(encoderEntries)); |
251 | |
252 | static StringMap<ContainerType, CONTAINER_MAX_ENUM>::Entry containerEntries[] = |
253 | { |
254 | { "data" , CONTAINER_DATA }, |
255 | { "string" , CONTAINER_STRING }, |
256 | }; |
257 | |
258 | static StringMap<ContainerType, CONTAINER_MAX_ENUM> containers(containerEntries, sizeof(containerEntries)); |
259 | |
260 | bool getConstant(const char *in, EncodeFormat &out) |
261 | { |
262 | return encoders.find(in, out); |
263 | } |
264 | |
265 | bool getConstant(EncodeFormat in, const char *&out) |
266 | { |
267 | return encoders.find(in, out); |
268 | } |
269 | |
270 | std::vector<std::string> getConstants(EncodeFormat) |
271 | { |
272 | return encoders.getNames(); |
273 | } |
274 | |
275 | bool getConstant(const char *in, ContainerType &out) |
276 | { |
277 | return containers.find(in, out); |
278 | } |
279 | |
280 | bool getConstant(ContainerType in, const char *&out) |
281 | { |
282 | return containers.find(in, out); |
283 | } |
284 | |
285 | std::vector<std::string> getConstants(ContainerType) |
286 | { |
287 | return containers.getNames(); |
288 | } |
289 | |
290 | } // data |
291 | } // love |
292 | |