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
32namespace
33{
34
35static const char hexchars[] = "0123456789abcdef";
36
37char *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
65love::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
79love::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
115namespace love
116{
117namespace data
118{
119
120CompressedData *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
145char *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
156char *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
166char *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
178char *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
190std::string hash(HashFunction::Function function, Data *input)
191{
192 return hash(function, (const char*) input->getData(), input->getSize());
193}
194
195std::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
202void hash(HashFunction::Function function, Data *input, HashFunction::Value &output)
203{
204 hash(function, (const char*) input->getData(), input->getSize(), output);
205}
206
207void 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
216DataModule::DataModule()
217{
218}
219
220DataModule::~DataModule()
221{
222}
223
224DataView *DataModule::newDataView(Data *data, size_t offset, size_t size)
225{
226 return new DataView(data, offset, size);
227}
228
229ByteData *DataModule::newByteData(size_t size)
230{
231 return new ByteData(size);
232}
233
234ByteData *DataModule::newByteData(const void *d, size_t size)
235{
236 return new ByteData(d, size);
237}
238
239ByteData *DataModule::newByteData(void *d, size_t size, bool own)
240{
241 return new ByteData(d, size, own);
242}
243
244static StringMap<EncodeFormat, ENCODE_MAX_ENUM>::Entry encoderEntries[] =
245{
246 { "base64", ENCODE_BASE64 },
247 { "hex", ENCODE_HEX },
248};
249
250static StringMap<EncodeFormat, ENCODE_MAX_ENUM> encoders(encoderEntries, sizeof(encoderEntries));
251
252static StringMap<ContainerType, CONTAINER_MAX_ENUM>::Entry containerEntries[] =
253{
254 { "data", CONTAINER_DATA },
255 { "string", CONTAINER_STRING },
256};
257
258static StringMap<ContainerType, CONTAINER_MAX_ENUM> containers(containerEntries, sizeof(containerEntries));
259
260bool getConstant(const char *in, EncodeFormat &out)
261{
262 return encoders.find(in, out);
263}
264
265bool getConstant(EncodeFormat in, const char *&out)
266{
267 return encoders.find(in, out);
268}
269
270std::vector<std::string> getConstants(EncodeFormat)
271{
272 return encoders.getNames();
273}
274
275bool getConstant(const char *in, ContainerType &out)
276{
277 return containers.find(in, out);
278}
279
280bool getConstant(ContainerType in, const char *&out)
281{
282 return containers.find(in, out);
283}
284
285std::vector<std::string> getConstants(ContainerType)
286{
287 return containers.getNames();
288}
289
290} // data
291} // love
292