mirror of
https://github.com/love2d/love.git
synced 2026-08-15 15:51:12 +02:00
Added love.math.encode(format, data | string [, linelength]) and love.math.decode(format, data | string). Current formats are "base64" and "hex". The optional line length only applies to base64 and specifies the maximum number of characters per line in the encoded string.
Removed the variant of love.filesystem.newFileData which decoded a base64-encoded string since it's redundant. --HG-- branch : minor
This commit is contained in:
@@ -73,23 +73,5 @@ const std::string &FileData::getExtension() const
|
||||
return extension;
|
||||
}
|
||||
|
||||
bool FileData::getConstant(const char *in, Decoder &out)
|
||||
{
|
||||
return decoders.find(in, out);
|
||||
}
|
||||
|
||||
bool FileData::getConstant(Decoder in, const char *&out)
|
||||
{
|
||||
return decoders.find(in, out);
|
||||
}
|
||||
|
||||
StringMap<FileData::Decoder, FileData::DECODE_MAX_ENUM>::Entry FileData::decoderEntries[] =
|
||||
{
|
||||
{"file", FileData::FILE},
|
||||
{"base64", FileData::BASE64},
|
||||
};
|
||||
|
||||
StringMap<FileData::Decoder, FileData::DECODE_MAX_ENUM> FileData::decoders(FileData::decoderEntries, sizeof(FileData::decoderEntries));
|
||||
|
||||
} // filesystem
|
||||
} // love
|
||||
|
||||
@@ -22,10 +22,11 @@
|
||||
#define LOVE_FILESYSTEM_FILE_DATA_H
|
||||
|
||||
// LOVE
|
||||
#include <string>
|
||||
#include "common/Data.h"
|
||||
#include "common/StringMap.h"
|
||||
#include "common/int.h"
|
||||
#include "common/Exception.h"
|
||||
|
||||
#include <string>
|
||||
|
||||
namespace love
|
||||
{
|
||||
@@ -36,13 +37,6 @@ class FileData : public Data
|
||||
{
|
||||
public:
|
||||
|
||||
enum Decoder
|
||||
{
|
||||
FILE,
|
||||
BASE64,
|
||||
DECODE_MAX_ENUM
|
||||
}; // Decoder
|
||||
|
||||
FileData(uint64 size, const std::string &filename);
|
||||
|
||||
virtual ~FileData();
|
||||
@@ -54,9 +48,6 @@ public:
|
||||
const std::string &getFilename() const;
|
||||
const std::string &getExtension() const;
|
||||
|
||||
static bool getConstant(const char *in, Decoder &out);
|
||||
static bool getConstant(Decoder in, const char *&out);
|
||||
|
||||
private:
|
||||
|
||||
// The actual data.
|
||||
@@ -71,9 +62,6 @@ private:
|
||||
// The extension (without dot). Used to identify file type.
|
||||
std::string extension;
|
||||
|
||||
static StringMap<Decoder, DECODE_MAX_ENUM>::Entry decoderEntries[];
|
||||
static StringMap<Decoder, DECODE_MAX_ENUM> decoders;
|
||||
|
||||
}; // FileData
|
||||
|
||||
} // filesystem
|
||||
|
||||
@@ -60,6 +60,13 @@ bool Filesystem::isAndroidSaveExternal() const
|
||||
return useExternal;
|
||||
}
|
||||
|
||||
FileData *Filesystem::newFileData(const void *data, size_t size, const char *filename) const
|
||||
{
|
||||
FileData *fd = new FileData(size, std::string(filename));
|
||||
memcpy(fd->getData(), data, size);
|
||||
return fd;
|
||||
}
|
||||
|
||||
bool Filesystem::isRealDirectory(const std::string &path) const
|
||||
{
|
||||
#ifdef LOVE_WINDOWS
|
||||
|
||||
@@ -128,13 +128,7 @@ public:
|
||||
* @param size The size of the data.
|
||||
* @param filename The full filename used to file type identification.
|
||||
**/
|
||||
virtual FileData *newFileData(void *data, unsigned int size, const char *filename) const = 0;
|
||||
|
||||
/**
|
||||
* Creates a new FileData object from base64 data.
|
||||
* @param b64 The base64 data.
|
||||
**/
|
||||
virtual FileData *newFileData(const char *b64, const char *filename) const = 0;
|
||||
virtual FileData *newFileData(const void *data, size_t size, const char *filename) const;
|
||||
|
||||
/**
|
||||
* Gets the current working directory.
|
||||
|
||||
@@ -457,30 +457,6 @@ love::filesystem::File *Filesystem::newFile(const char *filename) const
|
||||
return new File(filename);
|
||||
}
|
||||
|
||||
FileData *Filesystem::newFileData(void *data, unsigned int size, const char *filename) const
|
||||
{
|
||||
FileData *fd = new FileData(size, std::string(filename));
|
||||
|
||||
// Copy the data into FileData.
|
||||
memcpy(fd->getData(), data, size);
|
||||
|
||||
return fd;
|
||||
}
|
||||
|
||||
FileData *Filesystem::newFileData(const char *b64, const char *filename) const
|
||||
{
|
||||
int size = (int) strlen(b64);
|
||||
int outsize = 0;
|
||||
char *dst = b64_decode(b64, size, outsize);
|
||||
FileData *fd = new FileData(outsize, std::string(filename));
|
||||
|
||||
// Copy the data into FileData.
|
||||
memcpy(fd->getData(), dst, outsize);
|
||||
delete [] dst;
|
||||
|
||||
return fd;
|
||||
}
|
||||
|
||||
const char *Filesystem::getWorkingDirectory()
|
||||
{
|
||||
if (cwd.empty())
|
||||
|
||||
@@ -64,9 +64,6 @@ public:
|
||||
|
||||
File *newFile(const char *filename) const;
|
||||
|
||||
FileData *newFileData(void *data, unsigned int size, const char *filename) const;
|
||||
FileData *newFileData(const char *b64, const char *filename) const;
|
||||
|
||||
const char *getWorkingDirectory();
|
||||
std::string getUserDirectory();
|
||||
std::string getAppdataDirectory();
|
||||
|
||||
@@ -242,26 +242,9 @@ int w_newFileData(lua_State *L)
|
||||
size_t length = 0;
|
||||
const char *str = luaL_checklstring(L, 1, &length);
|
||||
const char *filename = luaL_checkstring(L, 2);
|
||||
const char *decstr = lua_isstring(L, 3) ? lua_tostring(L, 3) : 0;
|
||||
|
||||
FileData::Decoder decoder = FileData::FILE;
|
||||
|
||||
if (decstr && !FileData::getConstant(decstr, decoder))
|
||||
return luaL_error(L, "Invalid FileData decoder: %s", decstr);
|
||||
|
||||
FileData *t = 0;
|
||||
|
||||
switch (decoder)
|
||||
{
|
||||
case FileData::FILE:
|
||||
t = instance()->newFileData((void *)str, (int)length, filename);
|
||||
break;
|
||||
case FileData::BASE64:
|
||||
t = instance()->newFileData(str, filename);
|
||||
break;
|
||||
default:
|
||||
return luaL_error(L, "Invalid FileData decoder: %s", decstr);
|
||||
}
|
||||
FileData *t = nullptr;
|
||||
luax_catchexcept(L, [&](){ t = instance()->newFileData(str, length, filename); });
|
||||
|
||||
luax_pushtype(L, FILESYSTEM_FILE_DATA_ID, t);
|
||||
t->release();
|
||||
|
||||
@@ -23,6 +23,7 @@
|
||||
|
||||
// LOVE
|
||||
#include "common/Data.h"
|
||||
#include "common/StringMap.h"
|
||||
#include "filesystem/FileData.h"
|
||||
#include "thread/threads.h"
|
||||
|
||||
|
||||
+159
-35
@@ -21,6 +21,8 @@
|
||||
// LOVE
|
||||
#include "MathModule.h"
|
||||
#include "common/Vector.h"
|
||||
#include "common/b64.h"
|
||||
#include "common/int.h"
|
||||
#include "BezierCurve.h"
|
||||
|
||||
// STL
|
||||
@@ -34,49 +36,129 @@ using love::Vertex;
|
||||
|
||||
namespace
|
||||
{
|
||||
// check if an angle is oriented counter clockwise
|
||||
inline bool is_oriented_ccw(const Vertex &a, const Vertex &b, const Vertex &c)
|
||||
|
||||
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
|
||||
{
|
||||
// return det(b-a, c-a) >= 0
|
||||
return ((b.x - a.x) * (c.y - a.y) - (b.y - a.y) * (c.x - a.x)) >= 0;
|
||||
dst = new char[dstlen + 1];
|
||||
}
|
||||
catch (std::exception &)
|
||||
{
|
||||
throw love::Exception("Out of memory.");
|
||||
}
|
||||
|
||||
// check if a and b are on the same side of the line c->d
|
||||
bool on_same_side(const Vertex &a, const Vertex &b, const Vertex &c, const Vertex &d)
|
||||
for (size_t i = 0; i < srclen; i++)
|
||||
{
|
||||
float px = d.x - c.x, py = d.y - c.y;
|
||||
// return det(p, a-c) * det(p, b-c) >= 0
|
||||
float l = px * (a.y - c.y) - py * (a.x - c.x);
|
||||
float m = px * (b.y - c.y) - py * (b.x - c.x);
|
||||
return l * m >= 0;
|
||||
love::uint8 b = src[i];
|
||||
dst[i * 2 + 0] = hexchars[b >> 4];
|
||||
dst[i * 2 + 1] = hexchars[b & 0xF];
|
||||
}
|
||||
|
||||
// checks is p is contained in the triangle abc
|
||||
inline bool point_in_triangle(const Vertex &p, const Vertex &a, const Vertex &b, const Vertex &c)
|
||||
{
|
||||
return on_same_side(p,a, b,c) && on_same_side(p,b, a,c) && on_same_side(p,c, a,b);
|
||||
}
|
||||
|
||||
// checks if any vertex in `vertices' is in the triangle abc.
|
||||
bool any_point_in_triangle(const list<const Vertex *> &vertices, const Vertex &a, const Vertex &b, const Vertex &c)
|
||||
{
|
||||
list<const Vertex *>::const_iterator it, end = vertices.end();
|
||||
for (it = vertices.begin(); it != end; ++it)
|
||||
{
|
||||
const Vertex *p = *it;
|
||||
if ((p != &a) && (p != &b) && (p != &c) && point_in_triangle(*p, a,b,c)) // oh god...
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
inline bool is_ear(const Vertex &a, const Vertex &b, const Vertex &c, const list<const Vertex *> &vertices)
|
||||
{
|
||||
return is_oriented_ccw(a,b,c) && !any_point_in_triangle(vertices, a,b,c);
|
||||
}
|
||||
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;
|
||||
}
|
||||
|
||||
// check if an angle is oriented counter clockwise
|
||||
inline bool is_oriented_ccw(const Vertex &a, const Vertex &b, const Vertex &c)
|
||||
{
|
||||
// return det(b-a, c-a) >= 0
|
||||
return ((b.x - a.x) * (c.y - a.y) - (b.y - a.y) * (c.x - a.x)) >= 0;
|
||||
}
|
||||
|
||||
// check if a and b are on the same side of the line c->d
|
||||
bool on_same_side(const Vertex &a, const Vertex &b, const Vertex &c, const Vertex &d)
|
||||
{
|
||||
float px = d.x - c.x, py = d.y - c.y;
|
||||
// return det(p, a-c) * det(p, b-c) >= 0
|
||||
float l = px * (a.y - c.y) - py * (a.x - c.x);
|
||||
float m = px * (b.y - c.y) - py * (b.x - c.x);
|
||||
return l * m >= 0;
|
||||
}
|
||||
|
||||
// checks is p is contained in the triangle abc
|
||||
inline bool point_in_triangle(const Vertex &p, const Vertex &a, const Vertex &b, const Vertex &c)
|
||||
{
|
||||
return on_same_side(p,a, b,c) && on_same_side(p,b, a,c) && on_same_side(p,c, a,b);
|
||||
}
|
||||
|
||||
// checks if any vertex in `vertices' is in the triangle abc.
|
||||
bool any_point_in_triangle(const list<const Vertex *> &vertices, const Vertex &a, const Vertex &b, const Vertex &c)
|
||||
{
|
||||
list<const Vertex *>::const_iterator it, end = vertices.end();
|
||||
for (it = vertices.begin(); it != end; ++it)
|
||||
{
|
||||
const Vertex *p = *it;
|
||||
if ((p != &a) && (p != &b) && (p != &c) && point_in_triangle(*p, a,b,c)) // oh god...
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
inline bool is_ear(const Vertex &a, const Vertex &b, const Vertex &c, const list<const Vertex *> &vertices)
|
||||
{
|
||||
return is_oriented_ccw(a,b,c) && !any_point_in_triangle(vertices, a,b,c);
|
||||
}
|
||||
|
||||
} // anonymous namespace
|
||||
|
||||
namespace love
|
||||
{
|
||||
namespace math
|
||||
@@ -270,5 +352,47 @@ char *Math::decompress(Compressor::Format format, const char *cbytes, size_t com
|
||||
return compressor->decompress(format, cbytes, compressedsize, rawsize);
|
||||
}
|
||||
|
||||
char *Math::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 *Math::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);
|
||||
}
|
||||
}
|
||||
|
||||
bool Math::getConstant(const char *in, EncodeFormat &out)
|
||||
{
|
||||
return encoders.find(in, out);
|
||||
}
|
||||
|
||||
bool Math::getConstant(EncodeFormat in, const char *&out)
|
||||
{
|
||||
return encoders.find(in, out);
|
||||
}
|
||||
|
||||
StringMap<Math::EncodeFormat, Math::ENCODE_MAX_ENUM>::Entry Math::encoderEntries[] =
|
||||
{
|
||||
{ "base64", ENCODE_BASE64 },
|
||||
{ "hex", ENCODE_HEX },
|
||||
};
|
||||
|
||||
StringMap<Math::EncodeFormat, Math::ENCODE_MAX_ENUM> Math::encoders(Math::encoderEntries, sizeof(Math::encoderEntries));
|
||||
|
||||
} // math
|
||||
} // love
|
||||
|
||||
@@ -30,6 +30,7 @@
|
||||
#include "common/math.h"
|
||||
#include "common/Vector.h"
|
||||
#include "common/int.h"
|
||||
#include "common/StringMap.h"
|
||||
|
||||
// Noise
|
||||
#include "libraries/noise1234/noise1234.h"
|
||||
@@ -53,6 +54,13 @@ private:
|
||||
|
||||
public:
|
||||
|
||||
enum EncodeFormat
|
||||
{
|
||||
ENCODE_BASE64,
|
||||
ENCODE_HEX,
|
||||
ENCODE_MAX_ENUM
|
||||
};
|
||||
|
||||
virtual ~Math();
|
||||
|
||||
RandomGenerator *getRandomGenerator()
|
||||
@@ -152,12 +160,21 @@ public:
|
||||
**/
|
||||
char *decompress(Compressor::Format format, const char *cbytes, size_t compressedsize, size_t &rawsize);
|
||||
|
||||
char *encode(EncodeFormat format, const char *src, size_t srclen, size_t &dstlen, size_t linelen = 0);
|
||||
char *decode(EncodeFormat format, const char *src, size_t srclen, size_t &dstlen);
|
||||
|
||||
static bool getConstant(const char *in, EncodeFormat &out);
|
||||
static bool getConstant(EncodeFormat in, const char *&out);
|
||||
|
||||
static Math instance;
|
||||
|
||||
private:
|
||||
|
||||
Math();
|
||||
|
||||
static StringMap<EncodeFormat, ENCODE_MAX_ENUM>::Entry encoderEntries[];
|
||||
static StringMap<EncodeFormat, ENCODE_MAX_ENUM> encoders;
|
||||
|
||||
}; // Math
|
||||
|
||||
inline float Math::noise(float x) const
|
||||
|
||||
@@ -24,6 +24,7 @@
|
||||
#include "wrap_CompressedData.h"
|
||||
#include "MathModule.h"
|
||||
#include "BezierCurve.h"
|
||||
#include "common/b64.h"
|
||||
|
||||
#include <cmath>
|
||||
#include <iostream>
|
||||
@@ -385,6 +386,72 @@ int w_decompress(lua_State *L)
|
||||
return 1;
|
||||
}
|
||||
|
||||
int w_encode(lua_State *L)
|
||||
{
|
||||
const char *formatstr = luaL_checkstring(L, 1);
|
||||
Math::EncodeFormat format;
|
||||
if (!Math::getConstant(formatstr, format))
|
||||
return luaL_error(L, "Invalid encode format: %s", formatstr);
|
||||
|
||||
size_t srclen = 0;
|
||||
const char *src = nullptr;
|
||||
|
||||
if (luax_istype(L, 2, DATA_ID))
|
||||
{
|
||||
Data *data = luax_totype<Data>(L, 2, DATA_ID);
|
||||
src = (const char *) data->getData();
|
||||
srclen = data->getSize();
|
||||
}
|
||||
else
|
||||
src = luaL_checklstring(L, 2, &srclen);
|
||||
|
||||
size_t linelen = (size_t) luaL_optinteger(L, 3, 0);
|
||||
|
||||
size_t dstlen = 0;
|
||||
char *dst = nullptr;
|
||||
luax_catchexcept(L, [&](){ dst = Math::instance.encode(format, src, srclen, dstlen, linelen); });
|
||||
|
||||
if (dst != nullptr)
|
||||
lua_pushlstring(L, dst, dstlen);
|
||||
else
|
||||
lua_pushstring(L, "");
|
||||
|
||||
delete[] dst;
|
||||
return 1;
|
||||
}
|
||||
|
||||
int w_decode(lua_State *L)
|
||||
{
|
||||
const char *formatstr = luaL_checkstring(L, 1);
|
||||
Math::EncodeFormat format;
|
||||
if (!Math::getConstant(formatstr, format))
|
||||
return luaL_error(L, "Invalid decode format: %s", formatstr);
|
||||
|
||||
size_t srclen = 0;
|
||||
const char *src = nullptr;
|
||||
|
||||
if (luax_istype(L, 2, DATA_ID))
|
||||
{
|
||||
Data *data = luax_totype<Data>(L, 2, DATA_ID);
|
||||
src = (const char *) data->getData();
|
||||
srclen = data->getSize();
|
||||
}
|
||||
else
|
||||
src = luaL_checklstring(L, 2, &srclen);
|
||||
|
||||
size_t dstlen = 0;
|
||||
char *dst = nullptr;
|
||||
luax_catchexcept(L, [&](){ dst = Math::instance.decode(format, src, srclen, dstlen); });
|
||||
|
||||
if (dst != nullptr)
|
||||
lua_pushlstring(L, dst, dstlen);
|
||||
else
|
||||
lua_pushstring(L, "");
|
||||
|
||||
delete[] dst;
|
||||
return 1;
|
||||
}
|
||||
|
||||
// C functions in a struct, necessary for the FFI versions of math functions.
|
||||
struct FFI_Math
|
||||
{
|
||||
@@ -441,6 +508,8 @@ static const luaL_Reg functions[] =
|
||||
{ "noise", w_noise },
|
||||
{ "compress", w_compress },
|
||||
{ "decompress", w_decompress },
|
||||
{ "encode", w_encode },
|
||||
{ "decode", w_decode },
|
||||
{ 0, 0 }
|
||||
};
|
||||
|
||||
|
||||
Reference in New Issue
Block a user