mirror of
https://github.com/VCMP-SqMod/SqMod.git
synced 2025-07-28 03:31:46 +02:00
Initial implementation of the MaxmindDB module.
This commit is contained in:
@@ -2,24 +2,451 @@
|
||||
#include "Common.hpp"
|
||||
|
||||
// ------------------------------------------------------------------------------------------------
|
||||
#include <cstdio>
|
||||
#include <cstdlib>
|
||||
#include <cstring>
|
||||
|
||||
|
||||
// ------------------------------------------------------------------------------------------------
|
||||
namespace SqMod {
|
||||
|
||||
// ------------------------------------------------------------------------------------------------
|
||||
DbRef::Pointer DbRef::Create()
|
||||
// N[0] - contains least significant bits, N[3] - most significant
|
||||
static SQChar * Bin128ToDec(const Uint32 N[4])
|
||||
{
|
||||
return reinterpret_cast< Pointer >(std::malloc(sizeof(Type)));
|
||||
// log10(x) = log2(x) / log2(10) ~= log2(x) / 3.322
|
||||
static SQChar s[128 / 3 + 1 + 1];
|
||||
Uint32 n[4];
|
||||
SQChar * p = s;
|
||||
int i;
|
||||
|
||||
std::memset(s, '0', sizeof(s) - 1);
|
||||
s[sizeof(s) - 1] = '\0';
|
||||
|
||||
std::memcpy(n, N, sizeof(n));
|
||||
|
||||
for (i = 0; i < 128; i++)
|
||||
{
|
||||
int j, carry;
|
||||
|
||||
carry = (n[3] >= 0x80000000);
|
||||
// Shift n[] left, doubling it
|
||||
n[3] = ((n[3] << 1) & 0xFFFFFFFF) + (n[2] >= 0x80000000);
|
||||
n[2] = ((n[2] << 1) & 0xFFFFFFFF) + (n[1] >= 0x80000000);
|
||||
n[1] = ((n[1] << 1) & 0xFFFFFFFF) + (n[0] >= 0x80000000);
|
||||
n[0] = ((n[0] << 1) & 0xFFFFFFFF);
|
||||
|
||||
// Add s[] to itself in decimal, doubling it
|
||||
for (j = sizeof(s) - 2; j >= 0; j--)
|
||||
{
|
||||
s[j] += s[j] - '0' + carry;
|
||||
|
||||
carry = (s[j] > '9');
|
||||
|
||||
if (carry)
|
||||
{
|
||||
s[j] -= 10;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
while ((p[0] == '0') && (p < &s[sizeof(s) - 2]))
|
||||
{
|
||||
p++;
|
||||
}
|
||||
|
||||
return p;
|
||||
}
|
||||
|
||||
// ------------------------------------------------------------------------------------------------
|
||||
void DbRef::Destroy(Pointer db)
|
||||
CSStr AsTypeStr(Uint32 id)
|
||||
{
|
||||
if (db)
|
||||
switch (id)
|
||||
{
|
||||
std::free(db);
|
||||
case MMDB_DATA_TYPE_EXTENDED: return _SC("extended");
|
||||
case MMDB_DATA_TYPE_POINTER: return _SC("pointer");
|
||||
case MMDB_DATA_TYPE_UTF8_STRING: return _SC("string");
|
||||
case MMDB_DATA_TYPE_DOUBLE: return _SC("double");
|
||||
case MMDB_DATA_TYPE_BYTES: return _SC("bytes");
|
||||
case MMDB_DATA_TYPE_UINT16: return _SC("uint16");
|
||||
case MMDB_DATA_TYPE_UINT32: return _SC("uint32");
|
||||
case MMDB_DATA_TYPE_MAP: return _SC("map");
|
||||
case MMDB_DATA_TYPE_INT32: return _SC("int32");
|
||||
case MMDB_DATA_TYPE_UINT64: return _SC("uint64");
|
||||
case MMDB_DATA_TYPE_UINT128: return _SC("uint128");
|
||||
case MMDB_DATA_TYPE_ARRAY: return _SC("array");
|
||||
case MMDB_DATA_TYPE_CONTAINER: return _SC("container");
|
||||
case MMDB_DATA_TYPE_END_MARKER: return _SC("endmarker");
|
||||
case MMDB_DATA_TYPE_BOOLEAN: return _SC("boolean");
|
||||
case MMDB_DATA_TYPE_FLOAT: return _SC("float");
|
||||
default: return _SC("unknonw");
|
||||
}
|
||||
}
|
||||
|
||||
// ------------------------------------------------------------------------------------------------
|
||||
bool GetEntryAsBool(const MMDB_entry_data_s & ed)
|
||||
{
|
||||
bool value = false;
|
||||
// Identify the type of entry data
|
||||
switch (ed.type)
|
||||
{
|
||||
case MMDB_DATA_TYPE_POINTER: {
|
||||
value = ed.pointer > 0;
|
||||
} break;
|
||||
case MMDB_DATA_TYPE_UTF8_STRING: {
|
||||
if (ed.data_size > 0)
|
||||
{
|
||||
value = ConvTo< bool >::From(reinterpret_cast< CSStr >(ed.utf8_string));
|
||||
}
|
||||
} break;
|
||||
case MMDB_DATA_TYPE_DOUBLE: {
|
||||
value = ConvTo< bool >::From(ed.double_value);
|
||||
} break;
|
||||
case MMDB_DATA_TYPE_BYTES: {
|
||||
for (Uint32 i = 0; i < ed.data_size; ++i)
|
||||
{
|
||||
if (ed.bytes[i] != 0)
|
||||
{
|
||||
value = true;
|
||||
// Found somethinf that isn't 0
|
||||
break;
|
||||
}
|
||||
}
|
||||
} break;
|
||||
case MMDB_DATA_TYPE_UINT16: {
|
||||
value = ConvTo< bool >::From(ed.uint16);
|
||||
} break;
|
||||
case MMDB_DATA_TYPE_UINT32: {
|
||||
value = ConvTo< bool >::From(ed.uint16);
|
||||
} break;
|
||||
case MMDB_DATA_TYPE_INT32: {
|
||||
value = ConvTo< bool >::From(ed.uint16);
|
||||
} break;
|
||||
case MMDB_DATA_TYPE_UINT64: {
|
||||
value = ConvTo< bool >::From(ed.uint16);
|
||||
} break;
|
||||
case MMDB_DATA_TYPE_UINT128: {
|
||||
#if defined(MMDB_UINT128_IS_BYTE_ARRAY) && (MMDB_UINT128_IS_BYTE_ARRAY == 1)
|
||||
for (Uint32 i = 0; i < sizeof(ed.uint128); ++i)
|
||||
{
|
||||
if (ed.uint128[i] != 0)
|
||||
{
|
||||
value = true;
|
||||
// Found somethinf that isn't 0
|
||||
break;
|
||||
}
|
||||
}
|
||||
#else
|
||||
value = ed.uint128 > 0;
|
||||
#endif // MMDB_UINT128_IS_BYTE_ARRAY
|
||||
|
||||
} break;
|
||||
case MMDB_DATA_TYPE_BOOLEAN: {
|
||||
value = ed.boolean ? true : false;
|
||||
} break;
|
||||
case MMDB_DATA_TYPE_FLOAT: {
|
||||
value = ConvTo< bool >::From(ed.float_value);
|
||||
} break;
|
||||
default:
|
||||
STHROWF("Unsupported conversion from (%s) to (boolean)", AsTypeStr(ed.type));
|
||||
}
|
||||
// Return the extracted value
|
||||
return value;
|
||||
}
|
||||
|
||||
// ------------------------------------------------------------------------------------------------
|
||||
SQInteger GetEntryAsInteger(const MMDB_entry_data_s & ed)
|
||||
{
|
||||
SQInteger value = 0;
|
||||
// Identify the type of entry data
|
||||
switch (ed.type)
|
||||
{
|
||||
case MMDB_DATA_TYPE_POINTER: {
|
||||
value = static_cast< SQInteger >(ed.pointer);
|
||||
} break;
|
||||
case MMDB_DATA_TYPE_UTF8_STRING: {
|
||||
if (ed.data_size > 0)
|
||||
{
|
||||
value = ConvTo< SQInteger >::From(reinterpret_cast< CSStr >(ed.utf8_string));
|
||||
}
|
||||
} break;
|
||||
case MMDB_DATA_TYPE_DOUBLE: {
|
||||
value = ConvTo< SQInteger >::From(ed.double_value);
|
||||
} break;
|
||||
case MMDB_DATA_TYPE_BYTES: {
|
||||
std::memcpy(&value, ed.bytes, Clamp(ed.data_size, 0U, sizeof(value)));
|
||||
} break;
|
||||
case MMDB_DATA_TYPE_UINT16: {
|
||||
value = ConvTo< SQInteger >::From(ed.uint16);
|
||||
} break;
|
||||
case MMDB_DATA_TYPE_UINT32: {
|
||||
value = ConvTo< SQInteger >::From(ed.uint32);
|
||||
} break;
|
||||
case MMDB_DATA_TYPE_INT32: {
|
||||
value = ConvTo< SQInteger >::From(ed.int32);
|
||||
} break;
|
||||
case MMDB_DATA_TYPE_UINT64: {
|
||||
value = ConvTo< SQInteger >::From(ed.uint64);
|
||||
} break;
|
||||
case MMDB_DATA_TYPE_UINT128: {
|
||||
#if defined(MMDB_UINT128_IS_BYTE_ARRAY) && (MMDB_UINT128_IS_BYTE_ARRAY == 1)
|
||||
std::memcpy(&value, ed.uint128, sizeof(value));
|
||||
#else
|
||||
std::memcpy(&value, &ed.uint128, sizeof(value));
|
||||
#endif // MMDB_UINT128_IS_BYTE_ARRAY
|
||||
} break;
|
||||
case MMDB_DATA_TYPE_BOOLEAN: {
|
||||
value = ed.boolean ? 1 : 0;
|
||||
} break;
|
||||
case MMDB_DATA_TYPE_FLOAT: {
|
||||
value = ConvTo< SQInteger >::From(ed.float_value);
|
||||
} break;
|
||||
default:
|
||||
STHROWF("Unsupported conversion from (%s) to (integer)", AsTypeStr(ed.type));
|
||||
}
|
||||
// Return the extracted value
|
||||
return value;
|
||||
}
|
||||
|
||||
// ------------------------------------------------------------------------------------------------
|
||||
SQFloat GetEntryAsFloat(const MMDB_entry_data_s & ed)
|
||||
{
|
||||
SQFloat value = 0.0;
|
||||
// Identify the type of entry data
|
||||
switch (ed.type)
|
||||
{
|
||||
case MMDB_DATA_TYPE_POINTER: {
|
||||
value = ConvTo< SQFloat >::From(static_cast< SQInteger >(ed.pointer));
|
||||
} break;
|
||||
case MMDB_DATA_TYPE_UTF8_STRING: {
|
||||
if (ed.data_size > 0)
|
||||
{
|
||||
value = ConvTo< SQFloat >::From(reinterpret_cast< CSStr >(ed.utf8_string));
|
||||
}
|
||||
} break;
|
||||
case MMDB_DATA_TYPE_DOUBLE: {
|
||||
value = ConvTo< SQFloat >::From(ed.double_value);
|
||||
} break;
|
||||
case MMDB_DATA_TYPE_BYTES: {
|
||||
// Not our problem if the result will be junk!
|
||||
std::memcpy(&value, ed.bytes, Clamp(ed.data_size, 0U, sizeof(value)));
|
||||
} break;
|
||||
case MMDB_DATA_TYPE_UINT16: {
|
||||
value = ConvTo< SQFloat >::From(ed.uint16);
|
||||
} break;
|
||||
case MMDB_DATA_TYPE_UINT32: {
|
||||
value = ConvTo< SQFloat >::From(ed.uint32);
|
||||
} break;
|
||||
case MMDB_DATA_TYPE_INT32: {
|
||||
value = ConvTo< SQFloat >::From(ed.int32);
|
||||
} break;
|
||||
case MMDB_DATA_TYPE_UINT64: {
|
||||
value = ConvTo< SQFloat >::From(ed.uint64);
|
||||
} break;
|
||||
case MMDB_DATA_TYPE_UINT128: {
|
||||
SQInteger num;
|
||||
// Convert to integer first
|
||||
#if defined(MMDB_UINT128_IS_BYTE_ARRAY) && (MMDB_UINT128_IS_BYTE_ARRAY == 1)
|
||||
std::memcpy(&num, ed.uint128, sizeof(num));
|
||||
#else
|
||||
std::memcpy(&num, &ed.uint128, sizeof(num));
|
||||
#endif // MMDB_UINT128_IS_BYTE_ARRAY
|
||||
// Now convert to float
|
||||
value = ConvTo< SQFloat >::From(num);
|
||||
} break;
|
||||
case MMDB_DATA_TYPE_BOOLEAN: {
|
||||
value = ed.boolean ? 1.0 : 0.0;
|
||||
} break;
|
||||
case MMDB_DATA_TYPE_FLOAT: {
|
||||
value = ConvTo< SQFloat >::From(ed.float_value);
|
||||
} break;
|
||||
default:
|
||||
STHROWF("Unsupported conversion from (%s) to (float)", AsTypeStr(ed.type));
|
||||
}
|
||||
// Return the extracted value
|
||||
return value;
|
||||
}
|
||||
|
||||
// ------------------------------------------------------------------------------------------------
|
||||
Object GetEntryAsLong(const MMDB_entry_data_s & ed)
|
||||
{
|
||||
Uint64 value = 0;
|
||||
// Identify the type of entry data
|
||||
switch (ed.type)
|
||||
{
|
||||
case MMDB_DATA_TYPE_POINTER: {
|
||||
value = static_cast< Uint64 >(ed.pointer);
|
||||
} break;
|
||||
case MMDB_DATA_TYPE_UTF8_STRING: {
|
||||
if (ed.data_size > 0)
|
||||
{
|
||||
value = ConvTo< Uint64 >::From(reinterpret_cast< CSStr >(ed.utf8_string));
|
||||
}
|
||||
} break;
|
||||
case MMDB_DATA_TYPE_DOUBLE: {
|
||||
value = ConvTo< Uint64 >::From(ed.double_value);
|
||||
} break;
|
||||
case MMDB_DATA_TYPE_BYTES: {
|
||||
std::memcpy(&value, ed.bytes, Clamp(ed.data_size, 0U, sizeof(value)));
|
||||
} break;
|
||||
case MMDB_DATA_TYPE_UINT16: {
|
||||
value = ConvTo< Uint64 >::From(ed.uint16);
|
||||
} break;
|
||||
case MMDB_DATA_TYPE_UINT32: {
|
||||
value = ConvTo< Uint64 >::From(ed.uint32);
|
||||
} break;
|
||||
case MMDB_DATA_TYPE_INT32: {
|
||||
value = ConvTo< Uint64 >::From(ed.int32);
|
||||
} break;
|
||||
case MMDB_DATA_TYPE_UINT64: {
|
||||
value = ConvTo< Uint64 >::From(ed.uint64);
|
||||
} break;
|
||||
case MMDB_DATA_TYPE_UINT128: {
|
||||
#if defined(MMDB_UINT128_IS_BYTE_ARRAY) && (MMDB_UINT128_IS_BYTE_ARRAY == 1)
|
||||
std::memcpy(&value, ed.uint128, sizeof(value));
|
||||
#else
|
||||
std::memcpy(&value, &ed.uint128, sizeof(value));
|
||||
#endif // MMDB_UINT128_IS_BYTE_ARRAY
|
||||
} break;
|
||||
case MMDB_DATA_TYPE_BOOLEAN: {
|
||||
value = ed.boolean ? 1 : 0;
|
||||
} break;
|
||||
case MMDB_DATA_TYPE_FLOAT: {
|
||||
value = ConvTo< Uint64 >::From(ed.float_value);
|
||||
} break;
|
||||
default:
|
||||
STHROWF("Unsupported conversion from (%s) to (long)", AsTypeStr(ed.type));
|
||||
}
|
||||
// Obtain the initial stack size
|
||||
const StackGuard sg;
|
||||
// Push a long integer instance with the requested value on the stack
|
||||
SqMod_PushULongObject(DefaultVM::Get(), value);
|
||||
// Obtain the object from the stack and return it
|
||||
return Var< Object >(DefaultVM::Get(), -1).value;
|
||||
}
|
||||
|
||||
// ------------------------------------------------------------------------------------------------
|
||||
Object GetEntryAsString(const MMDB_entry_data_s & ed)
|
||||
{
|
||||
// Obtain the initial stack size
|
||||
const StackGuard sg;
|
||||
// The default vm
|
||||
HSQUIRRELVM vm = DefaultVM::Get();
|
||||
// Identify the type of entry data
|
||||
switch (ed.type)
|
||||
{
|
||||
case MMDB_DATA_TYPE_POINTER: {
|
||||
sq_pushstring(vm, ToStrF("%p", ed.pointer), -1);
|
||||
} break;
|
||||
case MMDB_DATA_TYPE_UTF8_STRING: {
|
||||
sq_pushstring(vm, ed.utf8_string, ed.data_size);
|
||||
} break;
|
||||
case MMDB_DATA_TYPE_DOUBLE: {
|
||||
sq_pushstring(vm, ToStrF("%f", ed.double_value), -1);
|
||||
} break;
|
||||
case MMDB_DATA_TYPE_BYTES: {
|
||||
sq_pushstring(vm, reinterpret_cast< CSStr >(ed.bytes), ed.data_size / sizeof(SQChar));
|
||||
} break;
|
||||
case MMDB_DATA_TYPE_UINT16: {
|
||||
sq_pushstring(vm, ToStrF("%u", ed.uint16), -1);
|
||||
} break;
|
||||
case MMDB_DATA_TYPE_UINT32: {
|
||||
sq_pushstring(vm, ToStrF("%u", ed.uint32), -1);
|
||||
} break;
|
||||
case MMDB_DATA_TYPE_INT32: {
|
||||
sq_pushstring(vm, ToStrF("%d", ed.int32), -1);
|
||||
} break;
|
||||
case MMDB_DATA_TYPE_UINT64: {
|
||||
sq_pushstring(vm, ToStrF("%llu", ed.uint64), -1);
|
||||
} break;
|
||||
case MMDB_DATA_TYPE_UINT128: {
|
||||
#if defined(MMDB_UINT128_IS_BYTE_ARRAY) && (MMDB_UINT128_IS_BYTE_ARRAY == 1)
|
||||
sq_pushstring(vm, Bin128ToDec(reinterpret_cast< const Uint32 * >(ed.uint128)), -1);
|
||||
#else
|
||||
sq_pushstring(vm, Bin128ToDec(reinterpret_cast< const Uint32 * >(&ed.uint128)), -1);
|
||||
#endif // MMDB_UINT128_IS_BYTE_ARRAY
|
||||
} break;
|
||||
case MMDB_DATA_TYPE_BOOLEAN: {
|
||||
sq_pushstring(vm, ed.boolean ? _SC("true") : _SC("false"), -1);
|
||||
} break;
|
||||
case MMDB_DATA_TYPE_FLOAT: {
|
||||
sq_pushstring(vm, ToStrF("%f", ed.float_value), -1);
|
||||
} break;
|
||||
default:
|
||||
STHROWF("Unsupported conversion from (%s) to (string)", AsTypeStr(ed.type));
|
||||
}
|
||||
// Obtain the object from the stack and return it
|
||||
return Var< Object >(vm, -1).value;
|
||||
}
|
||||
|
||||
// ------------------------------------------------------------------------------------------------
|
||||
Object GetEntryAsBytes(const MMDB_entry_data_s & ed)
|
||||
{
|
||||
// Obtain the initial stack size
|
||||
const StackGuard sg;
|
||||
// The result of operations
|
||||
SQRESULT res = SQ_OK;
|
||||
// The default vm
|
||||
HSQUIRRELVM vm = DefaultVM::Get();
|
||||
// Identify the type of entry data
|
||||
switch (ed.type)
|
||||
{
|
||||
case MMDB_DATA_TYPE_POINTER: {
|
||||
res = SqMod_PushBufferData(vm,
|
||||
reinterpret_cast< const char * >(&ed.pointer), sizeof(ed.pointer), 0);
|
||||
} break;
|
||||
case MMDB_DATA_TYPE_UTF8_STRING: {
|
||||
res = SqMod_PushBufferData(vm,
|
||||
reinterpret_cast< const char * >(ed.utf8_string), ed.data_size, 0);
|
||||
} break;
|
||||
case MMDB_DATA_TYPE_DOUBLE: {
|
||||
res = SqMod_PushBufferData(vm,
|
||||
reinterpret_cast< const char * >(&ed.double_value), sizeof(ed.double_value), 0);
|
||||
} break;
|
||||
case MMDB_DATA_TYPE_BYTES: {
|
||||
res = SqMod_PushBufferData(vm,
|
||||
reinterpret_cast< const char * >(ed.bytes), ed.data_size, 0);
|
||||
} break;
|
||||
case MMDB_DATA_TYPE_UINT16: {
|
||||
res = SqMod_PushBufferData(vm,
|
||||
reinterpret_cast< const char * >(&ed.uint16), sizeof(ed.uint16), 0);
|
||||
} break;
|
||||
case MMDB_DATA_TYPE_UINT32: {
|
||||
res = SqMod_PushBufferData(vm,
|
||||
reinterpret_cast< const char * >(&ed.uint32), sizeof(ed.uint32), 0);
|
||||
} break;
|
||||
case MMDB_DATA_TYPE_INT32: {
|
||||
res = SqMod_PushBufferData(vm,
|
||||
reinterpret_cast< const char * >(&ed.int32), sizeof(ed.int32), 0);
|
||||
} break;
|
||||
case MMDB_DATA_TYPE_UINT64: {
|
||||
res = SqMod_PushBufferData(vm,
|
||||
reinterpret_cast< const char * >(&ed.uint64), sizeof(ed.uint64), 0);
|
||||
} break;
|
||||
case MMDB_DATA_TYPE_UINT128: {
|
||||
res = SqMod_PushBufferData(vm,
|
||||
reinterpret_cast< const char * >(&ed.uint128), sizeof(ed.uint128), 0);
|
||||
} break;
|
||||
case MMDB_DATA_TYPE_BOOLEAN: {
|
||||
res = SqMod_PushBufferData(vm,
|
||||
reinterpret_cast< const char * >(&ed.boolean), sizeof(ed.boolean), 0);
|
||||
} break;
|
||||
case MMDB_DATA_TYPE_FLOAT: {
|
||||
res = SqMod_PushBufferData(vm,
|
||||
reinterpret_cast< const char * >(&ed.float_value),
|
||||
sizeof(ed.float_value), 0);
|
||||
} break;
|
||||
default:
|
||||
STHROWF("Unsupported conversion from (%s) to (buffer)", AsTypeStr(ed.type));
|
||||
}
|
||||
// Did we fail to push the buffer o the stack?
|
||||
if (SQ_FAILED(res))
|
||||
{
|
||||
STHROWF("Failed to convert the (%s) value to a buffer.", AsTypeStr(ed.type));
|
||||
}
|
||||
// Obtain the object from the stack and return it
|
||||
return Var< Object >(vm, -1).value;
|
||||
}
|
||||
|
||||
|
||||
} // Namespace:: SqMod
|
||||
|
Reference in New Issue
Block a user