mirror of
https://github.com/love2d/love.git
synced 2026-08-19 20:19:42 +02:00
293 lines
6.4 KiB
C++
293 lines
6.4 KiB
C++
/**
|
|
* Copyright (c) 2006-2024 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 <cmath>
|
|
#include <list>
|
|
#include <iostream>
|
|
|
|
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()
|
|
: Module(M_DATA, "love.data")
|
|
{
|
|
}
|
|
|
|
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<EncodeFormat, ENCODE_MAX_ENUM>::Entry encoderEntries[] =
|
|
{
|
|
{ "base64", ENCODE_BASE64 },
|
|
{ "hex", ENCODE_HEX },
|
|
};
|
|
|
|
static StringMap<EncodeFormat, ENCODE_MAX_ENUM> encoders(encoderEntries, sizeof(encoderEntries));
|
|
|
|
static StringMap<ContainerType, CONTAINER_MAX_ENUM>::Entry containerEntries[] =
|
|
{
|
|
{ "data", CONTAINER_DATA },
|
|
{ "string", CONTAINER_STRING },
|
|
};
|
|
|
|
static StringMap<ContainerType, CONTAINER_MAX_ENUM> 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<std::string> 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<std::string> getConstants(ContainerType)
|
|
{
|
|
return containers.getNames();
|
|
}
|
|
|
|
} // data
|
|
} // love
|