/** * Copyright (c) 2006-2022 LOVE Development Team * * This software is provided 'as-is', without any express or implied * warranty. In no event will the authors be held liable for any damages * arising from the use of this software. * * Permission is granted to anyone to use this software for any purpose, * including commercial applications, and to alter it and redistribute it * freely, subject to the following restrictions: * * 1. The origin of this software must not be misrepresented; you must not * claim that you wrote the original software. If you use this software * in a product, an acknowledgment in the product documentation would be * appreciated but is not required. * 2. Altered source versions must be plainly marked as such, and must not be * misrepresented as being the original software. * 3. This notice may not be removed or altered from any source distribution. **/ // LOVE #include "DataModule.h" #include "common/b64.h" #include "common/int.h" #include "common/StringMap.h" // STL #include #include #include namespace { static const char hexchars[] = "0123456789abcdef"; char *bytesToHex(const love::uint8 *src, size_t srclen, size_t &dstlen) { dstlen = srclen * 2; if (dstlen == 0) return nullptr; char *dst = nullptr; try { dst = new char[dstlen + 1]; } catch (std::exception &) { throw love::Exception("Out of memory."); } for (size_t i = 0; i < srclen; i++) { love::uint8 b = src[i]; dst[i * 2 + 0] = hexchars[b >> 4]; dst[i * 2 + 1] = hexchars[b & 0xF]; } dst[dstlen] = '\0'; return dst; } love::uint8 nibble(char c) { if (c >= '0' && c <= '9') return (love::uint8) (c - '0'); if (c >= 'A' && c <= 'F') return (love::uint8) (c - 'A' + 0x0a); if (c >= 'a' && c <= 'f') return (love::uint8) (c - 'a' + 0x0a); return 0; } love::uint8 *hexToBytes(const char *src, size_t srclen, size_t &dstlen) { if (srclen >= 2 && src[0] == '0' && (src[1] == 'x' || src[1] == 'X')) { src += 2; srclen -= 2; } dstlen = (srclen + 1) / 2; if (dstlen == 0) return nullptr; love::uint8 *dst = nullptr; try { dst = new love::uint8[dstlen]; } catch (std::exception &) { throw love::Exception("Out of memory."); } for (size_t i = 0; i < dstlen; i++) { dst[i] = nibble(src[i * 2]) << 4; if (i * 2 + 1 < srclen) dst[i] |= nibble(src[i * 2 + 1]); } return dst; } } // anonymous namespace namespace love { namespace data { CompressedData *compress(Compressor::Format format, const char *rawbytes, size_t rawsize, int level) { Compressor *compressor = Compressor::getCompressor(format); if (compressor == nullptr) throw love::Exception("Invalid compression format."); size_t compressedsize = 0; char *cbytes = compressor->compress(format, rawbytes, rawsize, level, compressedsize); CompressedData *data = nullptr; try { data = new CompressedData(format, cbytes, compressedsize, rawsize, true); } catch (love::Exception &) { delete[] cbytes; throw; } return data; } char *decompress(CompressedData *data, size_t &decompressedsize) { size_t rawsize = data->getDecompressedSize(); char *rawbytes = decompress(data->getFormat(), (const char *) data->getData(), data->getSize(), rawsize); decompressedsize = rawsize; return rawbytes; } char *decompress(Compressor::Format format, const char *cbytes, size_t compressedsize, size_t &rawsize) { Compressor *compressor = Compressor::getCompressor(format); if (compressor == nullptr) throw love::Exception("Invalid compression format."); return compressor->decompress(format, cbytes, compressedsize, rawsize); } char *encode(EncodeFormat format, const char *src, size_t srclen, size_t &dstlen, size_t linelen) { switch (format) { case ENCODE_BASE64: default: return b64_encode(src, srclen, linelen, dstlen); case ENCODE_HEX: return bytesToHex((const uint8 *) src, srclen, dstlen); } } char *decode(EncodeFormat format, const char *src, size_t srclen, size_t &dstlen) { switch (format) { case ENCODE_BASE64: default: return b64_decode(src, srclen, dstlen); case ENCODE_HEX: return (char *) hexToBytes(src, srclen, dstlen); } } std::string hash(HashFunction::Function function, Data *input) { return hash(function, (const char*) input->getData(), input->getSize()); } std::string hash(HashFunction::Function function, const char *input, uint64_t size) { HashFunction::Value output; hash(function, input, size, output); return std::string(output.data, output.size); } void hash(HashFunction::Function function, Data *input, HashFunction::Value &output) { hash(function, (const char*) input->getData(), input->getSize(), output); } void hash(HashFunction::Function function, const char *input, uint64_t size, HashFunction::Value &output) { HashFunction *hashfunction = HashFunction::getHashFunction(function); if (hashfunction == nullptr) throw love::Exception("Invalid hash function."); hashfunction->hash(function, input, size, output); } DataModule::DataModule() { } DataModule::~DataModule() { } DataView *DataModule::newDataView(Data *data, size_t offset, size_t size) { return new DataView(data, offset, size); } ByteData *DataModule::newByteData(size_t size) { return new ByteData(size); } ByteData *DataModule::newByteData(const void *d, size_t size) { return new ByteData(d, size); } ByteData *DataModule::newByteData(void *d, size_t size, bool own) { return new ByteData(d, size, own); } static StringMap::Entry encoderEntries[] = { { "base64", ENCODE_BASE64 }, { "hex", ENCODE_HEX }, }; static StringMap encoders(encoderEntries, sizeof(encoderEntries)); static StringMap::Entry containerEntries[] = { { "data", CONTAINER_DATA }, { "string", CONTAINER_STRING }, }; static StringMap containers(containerEntries, sizeof(containerEntries)); bool getConstant(const char *in, EncodeFormat &out) { return encoders.find(in, out); } bool getConstant(EncodeFormat in, const char *&out) { return encoders.find(in, out); } std::vector getConstants(EncodeFormat) { return encoders.getNames(); } bool getConstant(const char *in, ContainerType &out) { return containers.find(in, out); } bool getConstant(ContainerType in, const char *&out) { return containers.find(in, out); } std::vector getConstants(ContainerType) { return containers.getNames(); } } // data } // love