1
0
mirror of https://github.com/VCMP-SqMod/SqMod.git synced 2024-11-14 11:47:15 +01:00
SqMod/modules/mmdb/Common.cpp
2016-11-14 14:06:30 +02:00

453 lines
16 KiB
C++

// ------------------------------------------------------------------------------------------------
#include "Common.hpp"
// ------------------------------------------------------------------------------------------------
#include <cstdio>
#include <cstdlib>
#include <cstring>
// ------------------------------------------------------------------------------------------------
namespace SqMod {
// ------------------------------------------------------------------------------------------------
// N[0] - contains least significant bits, N[3] - most significant
static SQChar * Bin128ToDec(const Uint32 N[4])
{
// 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;
}
// ------------------------------------------------------------------------------------------------
CSStr AsTypeStr(Uint32 id)
{
switch (id)
{
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