1
0
mirror of https://github.com/VCMP-SqMod/SqMod.git synced 2025-06-16 07:07:13 +02:00

Migrated the host module to C++ exceptions as well.

Also enabled the latest C++ revision in the project.
Replaced the Random library with the one provided by C++11.
Implemented a simple AES256 encryption class.
Various other fixes and improvements.
This commit is contained in:
Sandu Liviu Catalin
2016-03-10 05:57:13 +02:00
parent 3162221e7f
commit 70e5f0ba21
124 changed files with 14873 additions and 14062 deletions

View File

@ -33,7 +33,7 @@ Int32 Document::Cmp(const Document & o) const
{
if (m_Doc == o.m_Doc)
return 0;
else if (this > &o)
else if (m_Doc.m_Ptr > o.m_Doc.m_Ptr)
return 1;
else
return -1;

View File

@ -109,14 +109,6 @@ public:
return m_Doc;
}
/* --------------------------------------------------------------------------------------------
* See whether any data has been loaded into this document.
*/
bool IsEmpty() const
{
return m_Doc->IsEmpty();
}
/* --------------------------------------------------------------------------------------------
* Return the number of active references to this document instance.
*/
@ -125,6 +117,14 @@ public:
return m_Doc.Count();
}
/* --------------------------------------------------------------------------------------------
* See whether any data has been loaded into this document.
*/
bool IsEmpty() const
{
return m_Doc->IsEmpty();
}
/* --------------------------------------------------------------------------------------------
* Deallocate all memory stored by this document.
*/

View File

@ -18,7 +18,7 @@ Int32 Entries::Cmp(const Entries & o) const
{
if (m_Elem == o.m_Elem)
return 0;
else if (this > &o)
else if (m_List.size() > o.m_List.size())
return 1;
else
return -1;

120
modules/mmdb/Common.cpp Normal file
View File

@ -0,0 +1,120 @@
// ------------------------------------------------------------------------------------------------
#include "Common.hpp"
#include "Module.hpp"
// ------------------------------------------------------------------------------------------------
#include <cfloat>
#include <climits>
#include <cstdlib>
#include <cstdarg>
// ------------------------------------------------------------------------------------------------
#include <sqrat.h>
// ------------------------------------------------------------------------------------------------
namespace SqMod {
// ------------------------------------------------------------------------------------------------
static SQChar g_Buffer[4096]; // Common buffer to reduce memory allocations.
// ------------------------------------------------------------------------------------------------
SStr GetTempBuff()
{
return g_Buffer;
}
// ------------------------------------------------------------------------------------------------
Uint32 GetTempBuffSize()
{
return sizeof(g_Buffer);
}
// ------------------------------------------------------------------------------------------------
void SqThrowF(CSStr str, ...)
{
// Initialize the argument list
va_list args;
va_start (args, str);
// Write the requested contents
if (snprintf(g_Buffer, sizeof(g_Buffer), str, args) < 0)
strcpy(g_Buffer, "Unknown error has occurred");
// Release the argument list
va_end(args);
// Throw the exception with the resulted message
throw Sqrat::Exception(g_Buffer);
}
// ------------------------------------------------------------------------------------------------
CSStr FmtStr(CSStr str, ...)
{
// Initialize the argument list
va_list args;
va_start (args, str);
// Write the requested contents
if (snprintf(g_Buffer, sizeof(g_Buffer), str, args) < 0)
g_Buffer[0] = 0; /* make sure the string is terminated */
// Release the argument list
va_end(args);
// Return the data from the buffer
return g_Buffer;
}
// ------------------------------------------------------------------------------------------------
StackGuard::StackGuard(HSQUIRRELVM vm)
: m_Top(sq_gettop(vm)), m_VM(vm)
{
/* ... */
}
// ------------------------------------------------------------------------------------------------
StackGuard::~StackGuard()
{
sq_pop(m_VM, sq_gettop(m_VM) - m_Top);
}
// ------------------------------------------------------------------------------------------------
DbRef::Pointer DbRef::Create()
{
return reinterpret_cast< Pointer >(malloc(sizeof(Type)));
}
// ------------------------------------------------------------------------------------------------
void DbRef::Destroy(Pointer db)
{
if (db)
free(db);
}
// ------------------------------------------------------------------------------------------------
const char NumLimit< char >::Min = CHAR_MIN;
const signed char NumLimit< signed char >::Min = SCHAR_MIN;
const unsigned char NumLimit< unsigned char >::Min = 0;
const signed short NumLimit< signed short >::Min = SHRT_MIN;
const unsigned short NumLimit< unsigned short >::Min = 0;
const signed int NumLimit< signed int >::Min = INT_MIN;
const unsigned int NumLimit< unsigned int >::Min = 0;
const signed long NumLimit< signed long >::Min = LONG_MIN;
const unsigned long NumLimit< unsigned long >::Min = 0;
const signed long long NumLimit< signed long long >::Min = LLONG_MIN;
const unsigned long long NumLimit< unsigned long long >::Min = 0;
const float NumLimit< float >::Min = FLT_MIN;
const double NumLimit< double >::Min = DBL_MIN;
const long double NumLimit< long double >::Min = LDBL_MIN;
// ------------------------------------------------------------------------------------------------
const char NumLimit< char >::Max = CHAR_MAX;
const signed char NumLimit< signed char >::Max = SCHAR_MAX;
const unsigned char NumLimit< unsigned char >::Max = UCHAR_MAX;
const signed short NumLimit< signed short >::Max = SHRT_MAX;
const unsigned short NumLimit< unsigned short >::Max = USHRT_MAX;
const signed int NumLimit< signed int >::Max = INT_MAX;
const unsigned int NumLimit< unsigned int >::Max = UINT_MAX;
const signed long NumLimit< signed long >::Max = LONG_MAX;
const unsigned long NumLimit< unsigned long >::Max = ULONG_MAX;
const signed long long NumLimit< signed long long >::Max = LLONG_MAX;
const unsigned long long NumLimit< unsigned long long >::Max = ULLONG_MAX;
const float NumLimit< float >::Max = FLT_MAX;
const double NumLimit< double >::Max = DBL_MAX;
const long double NumLimit< long double >::Max = LDBL_MAX;
} // Namespace:: SqMod

453
modules/mmdb/Common.hpp Normal file
View File

@ -0,0 +1,453 @@
#ifndef _SQMMDB_COMMON_HPP_
#define _SQMMDB_COMMON_HPP_
// ------------------------------------------------------------------------------------------------
#include "ModBase.hpp"
// ------------------------------------------------------------------------------------------------
#include <cassert>
#include <cmath>
// ------------------------------------------------------------------------------------------------
#include <maxminddb.h>
// ------------------------------------------------------------------------------------------------
namespace SqMod {
/* ------------------------------------------------------------------------------------------------
* SOFTWARE INFORMATION
*/
#define SQMMDB_NAME "Squirrel MaxmindDB Module"
#define SQMMDB_AUTHOR "Sandu Liviu Catalin (S.L.C)"
#define SQMMDB_COPYRIGHT "Copyright (C) 2016 Sandu Liviu Catalin"
#define SQMMDB_HOST_NAME "SqModMMDBHost"
#define SQMMDB_VERSION 001
#define SQMMDB_VERSION_STR "0.0.1"
#define SQMMDB_VERSION_MAJOR 0
#define SQMMDB_VERSION_MINOR 0
#define SQMMDB_VERSION_PATCH 1
/* ------------------------------------------------------------------------------------------------
* Forward declarations.
*/
class Database;
class SockAddr;
class EntryDataList;
class LookupResult;
/* ------------------------------------------------------------------------------------------------
* Retrieve the temporary buffer.
*/
SStr GetTempBuff();
/* ------------------------------------------------------------------------------------------------
* Retrieve the size of the temporary buffer.
*/
Uint32 GetTempBuffSize();
/* ------------------------------------------------------------------------------------------------
* Throw a formatted exception.
*/
void SqThrowF(CSStr str, ...);
/* ------------------------------------------------------------------------------------------------
* Generate a formatted string.
*/
CSStr FmtStr(CSStr str, ...);
/* ------------------------------------------------------------------------------------------------
* Implements RAII to restore the VM stack to it's initial size on function exit.
*/
struct StackGuard
{
/* --------------------------------------------------------------------------------------------
* Base constructor.
*/
StackGuard(HSQUIRRELVM vm);
/* --------------------------------------------------------------------------------------------
* Destructor.
*/
~StackGuard();
private:
/* --------------------------------------------------------------------------------------------
* Copy constructor.
*/
StackGuard(const StackGuard &);
/* --------------------------------------------------------------------------------------------
* Move constructor.
*/
StackGuard(StackGuard &&);
/* --------------------------------------------------------------------------------------------
* Copy assignment operator.
*/
StackGuard & operator = (const StackGuard &);
/* --------------------------------------------------------------------------------------------
* Move assignment operator.
*/
StackGuard & operator = (StackGuard &&);
private:
// --------------------------------------------------------------------------------------------
Int32 m_Top; /* The top of the stack when this instance was created. */
HSQUIRRELVM m_VM; /* The VM where the stack should be restored. */
};
/* ------------------------------------------------------------------------------------------------
* Manages a reference counted INI document instance.
*/
class DbRef
{
// --------------------------------------------------------------------------------------------
friend class Database;
public:
// --------------------------------------------------------------------------------------------
typedef MMDB_s Type; // The managed type.
// --------------------------------------------------------------------------------------------
typedef Type* Pointer; // Pointer to the managed type.
typedef const Type* ConstPtr; // Constant pointer to the managed type.
// --------------------------------------------------------------------------------------------
typedef Type& Reference; // Reference to the managed type.
typedef const Type& ConstRef; // Constant reference to the managed type.
// --------------------------------------------------------------------------------------------
typedef unsigned int Counter; // Reference counter type.
private:
// --------------------------------------------------------------------------------------------
Pointer m_Ptr; // The document reader, writer and manager instance.
Counter* m_Ref; // Reference count to the managed instance.
/* --------------------------------------------------------------------------------------------
* Creates a database structure.
*/
static Pointer Create();
/* --------------------------------------------------------------------------------------------
* Destroyes the specified database structure.
*/
static void Destroy(Pointer db);
/* --------------------------------------------------------------------------------------------
* Grab a strong reference to a document instance.
*/
void Grab()
{
if (m_Ptr)
++(*m_Ref);
}
/* --------------------------------------------------------------------------------------------
* Drop a strong reference to a document instance.
*/
void Drop()
{
if (m_Ptr && --(*m_Ref) == 0)
{
MMDB_close(m_Ptr);
Destroy(m_Ptr);
delete m_Ref;
m_Ptr = NULL;
m_Ref = NULL;
}
}
/* --------------------------------------------------------------------------------------------
* Base constructor.
*/
DbRef(bool make)
: m_Ptr(make ? Create() : NULL), m_Ref(m_Ptr ? new Counter(1) : NULL)
{
/* ... */
}
public:
/* --------------------------------------------------------------------------------------------
* Default constructor (null).
*/
DbRef()
: m_Ptr(NULL), m_Ref(NULL)
{
/* ... */
}
/* --------------------------------------------------------------------------------------------
* Copy constructor.
*/
DbRef(const DbRef & o)
: m_Ptr(o.m_Ptr), m_Ref(o.m_Ref)
{
Grab();
}
/* --------------------------------------------------------------------------------------------
* Move constructor.
*/
DbRef(DbRef && o)
: m_Ptr(o.m_Ptr), m_Ref(o.m_Ref)
{
o.m_Ptr = NULL;
o.m_Ref = NULL;
}
/* --------------------------------------------------------------------------------------------
* Destructor.
*/
~DbRef()
{
Drop();
}
/* --------------------------------------------------------------------------------------------
* Copy assignment operator.
*/
DbRef & operator = (const DbRef & o)
{
if (m_Ptr != o.m_Ptr)
{
Drop();
m_Ptr = o.m_Ptr;
m_Ref = o.m_Ref;
Grab();
}
return *this;
}
/* --------------------------------------------------------------------------------------------
* Move assignment operator.
*/
DbRef & operator = (DbRef && o)
{
if (m_Ptr != o.m_Ptr)
{
m_Ptr = o.m_Ptr;
m_Ref = o.m_Ref;
o.m_Ptr = NULL;
o.m_Ref = NULL;
}
return *this;
}
/* --------------------------------------------------------------------------------------------
* Perform an equality comparison between two document instances.
*/
bool operator == (const DbRef & o) const
{
return (m_Ptr == o.m_Ptr);
}
/* --------------------------------------------------------------------------------------------
* Perform an inequality comparison between two document instances.
*/
bool operator != (const DbRef & o) const
{
return (m_Ptr != o.m_Ptr);
}
/* --------------------------------------------------------------------------------------------
* Implicit conversion to boolean for use in boolean operations.
*/
operator bool () const
{
return m_Ptr;
}
/* --------------------------------------------------------------------------------------------
* Implicit conversion to the managed instance pointer.
*/
operator Pointer ()
{
return m_Ptr;
}
/* --------------------------------------------------------------------------------------------
* Implicit conversion to the managed instance pointer.
*/
operator ConstPtr () const
{
return m_Ptr;
}
/* --------------------------------------------------------------------------------------------
* Implicit conversion to the managed instance reference.
*/
operator Reference ()
{
assert(m_Ptr);
return *m_Ptr;
}
/* --------------------------------------------------------------------------------------------
* Implicit conversion to the managed instance reference.
*/
operator ConstRef () const
{
assert(m_Ptr);
return *m_Ptr;
}
/* --------------------------------------------------------------------------------------------
* Member operator for dereferencing the managed pointer.
*/
Pointer operator -> () const
{
assert(m_Ptr);
return m_Ptr;
}
/* --------------------------------------------------------------------------------------------
* Indirection operator for obtaining a reference of the managed pointer.
*/
Reference operator * () const
{
assert(m_Ptr);
return *m_Ptr;
}
/* --------------------------------------------------------------------------------------------
* Retrieve the raw handle structure pointer.
*/
Pointer DbPtr()
{
return m_Ptr;
}
/* --------------------------------------------------------------------------------------------
* Retrieve the raw handle structure pointer.
*/
Pointer DbPtr() const
{
return m_Ptr;
}
/* --------------------------------------------------------------------------------------------
* Retrieve the number of active references to the managed instance.
*/
Counter Count() const
{
return (m_Ptr && m_Ref) ? (*m_Ref) : 0;
}
};
// ------------------------------------------------------------------------------------------------
template < typename T > struct NumLimit;
// ------------------------------------------------------------------------------------------------
template <> struct NumLimit< char > { static const char Min, Max; };
template <> struct NumLimit< signed char > { static const signed char Min, Max; };
template <> struct NumLimit< unsigned char > { static const unsigned char Min, Max; };
template <> struct NumLimit< signed short > { static const signed short Min, Max; };
template <> struct NumLimit< unsigned short > { static const unsigned short Min, Max; };
template <> struct NumLimit< signed int > { static const signed int Min, Max; };
template <> struct NumLimit< unsigned int > { static const unsigned int Min, Max; };
template <> struct NumLimit< signed long > { static const signed long Min, Max; };
template <> struct NumLimit< unsigned long > { static const unsigned long Min, Max; };
template <> struct NumLimit< signed long long > { static const signed long long Min, Max; };
template <> struct NumLimit< unsigned long long > { static const unsigned long long Min, Max; };
template <> struct NumLimit< float > { static const float Min, Max; };
template <> struct NumLimit< double > { static const double Min, Max; };
template <> struct NumLimit< long double > { static const long double Min, Max; };
// ------------------------------------------------------------------------------------------------
template< typename T > inline bool EpsEq(const T a, const T b)
{
return abs(a - b) <= 0;
}
template <> inline bool EpsEq(const Float32 a, const Float32 b)
{
return fabs(a - b) <= 0.000001f;
}
template <> inline bool EpsEq(const Float64 a, const Float64 b)
{
return fabs(a - b) <= 0.000000001d;
}
// ------------------------------------------------------------------------------------------------
template< typename T > inline bool EpsLt(const T a, const T b)
{
return !EpsEq(a, b) && (a < b);
}
template <> inline bool EpsLt(const Float32 a, const Float32 b)
{
return !EpsEq(a, b) && (a - b) < 0.000001f;
}
template <> inline bool EpsLt(const Float64 a, const Float64 b)
{
return !EpsEq(a, b) && (a - b) < 0.000000001d;
}
// ------------------------------------------------------------------------------------------------
template< typename T > inline bool EpsGt(const T a, const T b)
{
return !EpsEq(a, b) && (a > b);
}
template <> inline bool EpsGt(const Float32 a, const Float32 b)
{
return !EpsEq(a, b) && (a - b) > 0.000001f;
}
template <> inline bool EpsGt(const Float64 a, const Float64 b)
{
return !EpsEq(a, b) && (a - b) > 0.000000001d;
}
// ------------------------------------------------------------------------------------------------
template< typename T > inline bool EpsLtEq(const T a, const T b)
{
return !EpsEq(a, b) || (a < b);
}
template <> inline bool EpsLtEq(const Float32 a, const Float32 b)
{
return !EpsEq(a, b) || (a - b) < 0.000001f;
}
template <> inline bool EpsLtEq(const Float64 a, const Float64 b)
{
return !EpsEq(a, b) || (a - b) < 0.000000001d;
}
// ------------------------------------------------------------------------------------------------
template< typename T > inline bool EpsGtEq(const T a, const T b)
{
return !EpsEq(a, b) || (a > b);
}
template <> inline bool EpsGtEq(const Float32 a, const Float32 b)
{
return !EpsEq(a, b) || (a - b) > 0.000001f;
}
template <> inline bool EpsGtEq(const Float64 a, const Float64 b)
{
return !EpsEq(a, b) || (a - b) > 0.000000001d;
}
// ------------------------------------------------------------------------------------------------
template< typename T > inline T Clamp(T val, T min, T max)
{
return val < min ? min : (val > max ? max : val);
}
} // Namespace:: SqMod
#endif // _SQMMDB_COMMON_HPP_

116
modules/mmdb/Database.cpp Normal file
View File

@ -0,0 +1,116 @@
// ------------------------------------------------------------------------------------------------
#include "Database.hpp"
#include "SockAddr.hpp"
#include "LookupResult.hpp"
#include "Module.hpp"
// ------------------------------------------------------------------------------------------------
#include <sqrat.h>
// ------------------------------------------------------------------------------------------------
namespace SqMod {
// ------------------------------------------------------------------------------------------------
SQInteger Database::Typename(HSQUIRRELVM vm)
{
static const SQChar name[] = _SC("SqMMDBDatabase");
sq_pushstring(vm, name, sizeof(name));
return 1;
}
// ------------------------------------------------------------------------------------------------
void Database::Validate() const
{
// Is the document handle valid?
if (!m_Db)
SqThrowF("Invalid Maxmind database reference");
}
// ------------------------------------------------------------------------------------------------
Int32 Database::Cmp(const Database & o) const
{
if (m_Db == o.m_Db)
return 0;
else if (m_Db.m_Ptr > o.m_Db.m_Ptr)
return 1;
else
return -1;
}
// ------------------------------------------------------------------------------------------------
void Database::Open(CSStr filepath)
{
Open(filepath, 0);
}
// ------------------------------------------------------------------------------------------------
void Database::Open(CSStr filepath, Uint32 flags)
{
// Is there a database handle available?
if (!m_Db)
m_Db = DbRef(true); // Create a database handle
// Check if the database handle could be allocated one more time
if (!m_Db)
SqThrowF("Unable to create a Maxmind database reference");
// Are there any other references?
else if (m_Db.Count() > 1)
// To load new values now, would mean to cause undefined behavior in existing references
SqThrowF("Loading is disabled while database is referenced");
// Validate the specified file path
else if (!filepath || strlen(filepath) <= 0)
SqThrowF("Invalid database file path");
// Let's attempt to open the specified database
const Int32 status = MMDB_open(filepath, flags, m_Db.m_Ptr);
// Validate the result of the operation
if (status != MMDB_SUCCESS)
{
// Release the database reference
m_Db.Drop();
// Now it's safe to throw the error
SqThrowF("Unable to open the specified database [%s]", MMDB_strerror(status));
}
}
// ------------------------------------------------------------------------------------------------
LookupResult Database::LookupString(CSStr addr)
{
// Validate the database handle
Validate();
// Validate the specified string
if (!addr || strlen(addr) <= 0)
SqThrowF("Invalid address string");
// Dummy variables to obtain the status codes
int gai_error, mmdb_error;
// Attempt to perform the actual lookup
MMDB_lookup_result_s result = MMDB_lookup_string(m_Db, addr, &gai_error, &mmdb_error);
// Validate the result of the getaddrinfo() function call
if (gai_error != 0)
SqThrowF("Unable to resolve address (%s) because [%s]", addr, gai_strerror(gai_error));
// Validate the lookup status code
else if (mmdb_error != MMDB_SUCCESS)
SqThrowF("Unable to lookup address (%s) because [%s]", addr, MMDB_strerror(mmdb_error));
// Now it's safe to return the lookup result
return LookupResult(m_Db, result);
}
// ------------------------------------------------------------------------------------------------
LookupResult Database::LookupSockAddr(SockAddr & addr)
{
// Validate the database handle
Validate();
// Validate the specified socket address
if (!addr.IsValid())
SqThrowF("Invalid address instance");
// Dummy variable to obtain the status codes
int mmdb_error;
// Attempt to perform the actual lookup
MMDB_lookup_result_s result = MMDB_lookup_sockaddr(m_Db, addr.GetHandle()->ai_addr, &mmdb_error);
// Validate the lookup status code
if (mmdb_error != MMDB_SUCCESS)
SqThrowF("Unable to lookup address (%s) because [%s]",
addr.GetAddress(), MMDB_strerror(mmdb_error));
// Now it's safe to return the lookup result
return LookupResult(m_Db, result);
}
} // Namespace:: SqMod

132
modules/mmdb/Database.hpp Normal file
View File

@ -0,0 +1,132 @@
#ifndef _SQMMDB_DATABASE_HPP_
#define _SQMMDB_DATABASE_HPP_
// ------------------------------------------------------------------------------------------------
#include "Common.hpp"
// ------------------------------------------------------------------------------------------------
namespace SqMod {
/* ------------------------------------------------------------------------------------------------
* Class that can read/write and alter the contents of INI files.
*/
class Database
{
protected:
/* --------------------------------------------------------------------------------------------
* Copy constructor. (disabled)
*/
Database(const Database &);
/* --------------------------------------------------------------------------------------------
* Copy assignment operator. (disabled)
*/
Database & operator = (const Database &);
/* --------------------------------------------------------------------------------------------
* Validate the document reference and throw an error if invalid.
*/
void Validate() const;
private:
// ---------------------------------------------------------------------------------------------
DbRef m_Db; /* The main INI document instance. */
public:
/* --------------------------------------------------------------------------------------------
* Default constructor.
*/
Database()
: m_Db()
{
/* ... */
}
/* --------------------------------------------------------------------------------------------
* Base constructor.
*/
Database(CSStr filepath)
: m_Db()
{
Open(filepath, 0);
}
/* --------------------------------------------------------------------------------------------
* Base constructor.
*/
Database(CSStr filepath, Uint32 flags)
: m_Db()
{
Open(filepath, flags);
}
/* --------------------------------------------------------------------------------------------
* Destructor.
*/
~Database()
{
/* ... */
}
/* --------------------------------------------------------------------------------------------
* Used by the script engine to compare two instances of this type.
*/
Int32 Cmp(const Database & o) const;
/* --------------------------------------------------------------------------------------------
* Used by the script engine to convert an instance of this type to a string.
*/
CSStr ToString() const
{
return _SC("");
}
/* --------------------------------------------------------------------------------------------
* Used by the script engine to retrieve the name from instances of this type.
*/
static SQInteger Typename(HSQUIRRELVM vm);
/* --------------------------------------------------------------------------------------------
* See whether this instance references a valid INI document.
*/
bool IsValid() const
{
return m_Db;
}
/* --------------------------------------------------------------------------------------------
* Return the number of active references to this document instance.
*/
Uint32 GetRefCount() const
{
return m_Db.Count();
}
/* --------------------------------------------------------------------------------------------
* Attempt to open the specified database.
*/
void Open(CSStr filepath);
/* --------------------------------------------------------------------------------------------
* Attempt to open the specified database.
*/
void Open(CSStr filepath, Uint32 addr);
/* --------------------------------------------------------------------------------------------
* Look up an IP address that is passed in as a null-terminated string.
*/
LookupResult LookupString(CSStr addr);
/* --------------------------------------------------------------------------------------------
* Looks up an IP address that has already been resolved by getaddrinfo().
*/
LookupResult LookupSockAddr(SockAddr & sockaddr);
};
} // Namespace:: SqMod
#endif // _SQMMDB_DATABASE_HPP_

View File

@ -0,0 +1,382 @@
// ------------------------------------------------------------------------------------------------
#include "EntryDataList.hpp"
#include "Module.hpp"
// ------------------------------------------------------------------------------------------------
#include <cstdio>
#include <cstdlib>
// ------------------------------------------------------------------------------------------------
#include <sqrat.h>
// ------------------------------------------------------------------------------------------------
namespace SqMod {
// ------------------------------------------------------------------------------------------------
SQInteger EntryDataList::Typename(HSQUIRRELVM vm)
{
static const SQChar name[] = _SC("SqMMDBEntryDataList");
sq_pushstring(vm, name, sizeof(name));
return 1;
}
// ------------------------------------------------------------------------------------------------
void EntryDataList::Validate() const
{
// Is the document handle valid?
if (!m_Db)
SqThrowF("Invalid Maxmind database reference");
// Do we have a valid list?
else if (!m_List)
SqThrowF("Invalid entry data list");
}
// ------------------------------------------------------------------------------------------------
void EntryDataList::ValidateElem() const
{
// Is the document handle valid?
if (!m_Db)
SqThrowF("Invalid Maxmind database reference");
// Do we have a valid list?
else if (!m_List)
SqThrowF("Invalid entry data list");
// Do we have a valid element?
else if (!m_Elem)
SqThrowF("Invalid entry data element");
}
// ------------------------------------------------------------------------------------------------
void EntryDataList::ValidateData() const
{
// Is the document handle valid?
if (!m_Db)
SqThrowF("Invalid Maxmind database reference");
// Do we have a valid list?
else if (!m_List)
SqThrowF("Invalid entry data list");
// Do we have a valid element?
else if (!m_Elem)
SqThrowF("Invalid entry data element");
// Do we have some valid data?
else if (!m_Elem->entry_data.has_data)
SqThrowF("Entry data element has no data");
}
// ------------------------------------------------------------------------------------------------
CSStr EntryDataList::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");
}
}
// ------------------------------------------------------------------------------------------------
EntryDataList::~EntryDataList()
{
// Do we have to free any list?
if (m_List)
MMDB_free_entry_data_list(m_List);
}
// ------------------------------------------------------------------------------------------------
Int32 EntryDataList::Cmp(const EntryDataList & o) const
{
if (m_List == o.m_List)
return 0;
else if (m_List > o.m_List)
return 1;
else
return -1;
}
// ------------------------------------------------------------------------------------------------
Uint32 EntryDataList::GetCount() const
{
// Do we even have a list?
if (!m_List)
return 0;
// Get the start of the list
Pointer elem = m_List;
// Prepare a counter
Uint32 count = 1;
// Loop through list elements
while ((elem = elem->next)) ++count;
// Return the counter
return count;
}
// ------------------------------------------------------------------------------------------------
bool EntryDataList::Next()
{
// Validate the database and list handle
Validate();
// Do we have a valid element currently?
if (m_Elem)
return (m_Elem = m_Elem->next);
// Nothing to advance
return false;
}
// ------------------------------------------------------------------------------------------------
bool EntryDataList::Advance(Int32 n)
{
// Validate the database and list handle
Validate();
// Do we have a valid element currently?
if (m_Elem)
// Attempt to skip as many elements as possible
while ((n > 0) && (m_Elem = m_Elem->next)) --n;
// Return whether we have a valid element
return m_Elem;
}
// ------------------------------------------------------------------------------------------------
void EntryDataList::Reset()
{
// Validate the database and list handle
Validate();
// Go back to the first element
m_Elem = m_List;
}
// ------------------------------------------------------------------------------------------------
CSStr EntryDataList::GetString() const
{
// Validate the database, list and element handle
ValidateData();
// Attempt to perform the requested conversion
switch (m_Elem->entry_data.type)
{
case MMDB_DATA_TYPE_UTF8_STRING:
return m_Elem->entry_data.utf8_string;
case MMDB_DATA_TYPE_DOUBLE:
return FmtStr("%f", m_Elem->entry_data.double_value);
case MMDB_DATA_TYPE_UINT16:
return FmtStr("%u", m_Elem->entry_data.uint16);
case MMDB_DATA_TYPE_UINT32:
return FmtStr("%u", m_Elem->entry_data.uint32);
case MMDB_DATA_TYPE_INT32:
return FmtStr("%d", m_Elem->entry_data.int32);
case MMDB_DATA_TYPE_UINT64:
return FmtStr("%llu", m_Elem->entry_data.uint64);
case MMDB_DATA_TYPE_BOOLEAN:
return m_Elem->entry_data.boolean ? _SC("true") : _SC("false");
case MMDB_DATA_TYPE_FLOAT:
return FmtStr("%f", m_Elem->entry_data.float_value);
default:
SqThrowF("Unsupported conversion from (%s) to (string)", AsTypeStr(m_Elem->entry_data.type));
}
// Shouldn't really reach this point
return _SC("");
}
// ------------------------------------------------------------------------------------------------
SQInteger EntryDataList::GetInteger() const
{
// Validate the database, list and element handle
ValidateData();
// Attempt to perform the requested conversion
switch (m_Elem->entry_data.type)
{
#ifdef _SQ64
case MMDB_DATA_TYPE_UTF8_STRING:
return strtoll(m_Elem->entry_data.utf8_string, NULL, 10);
case MMDB_DATA_TYPE_DOUBLE:
return llround(m_Elem->entry_data.double_value);
case MMDB_DATA_TYPE_UINT16:
return m_Elem->entry_data.uint16;
case MMDB_DATA_TYPE_UINT32:
return m_Elem->entry_data.uint32;
case MMDB_DATA_TYPE_INT32:
return m_Elem->entry_data.int32;
case MMDB_DATA_TYPE_UINT64:
return Clamp(m_Elem->entry_data.uint64, 0, Uint64(NumLimit< SQInteger >::Max));
case MMDB_DATA_TYPE_BOOLEAN:
return m_Elem->entry_data.boolean ? 1 : 0;
case MMDB_DATA_TYPE_FLOAT:
return llround(m_Elem->entry_data.float_value);
default:
SqThrowF("Unsupported conversion from (%s) to (int32)", AsTypeStr(m_Elem->entry_data.type));
#else
case MMDB_DATA_TYPE_UTF8_STRING:
return strtol(m_Elem->entry_data.utf8_string, NULL, 10);
case MMDB_DATA_TYPE_DOUBLE:
return lround(m_Elem->entry_data.double_value);
case MMDB_DATA_TYPE_UINT16:
return m_Elem->entry_data.uint16;
case MMDB_DATA_TYPE_UINT32:
return Clamp(m_Elem->entry_data.uint32, 0U, Uint32(NumLimit< SQInteger >::Max));
case MMDB_DATA_TYPE_INT32:
return m_Elem->entry_data.int32;
case MMDB_DATA_TYPE_UINT64:
return Clamp(m_Elem->entry_data.uint64, 0ULL, Uint64(NumLimit< SQInteger >::Max));
case MMDB_DATA_TYPE_BOOLEAN:
return m_Elem->entry_data.boolean ? 1 : 0;
case MMDB_DATA_TYPE_FLOAT:
return lround(m_Elem->entry_data.float_value);
default:
SqThrowF("Unsupported conversion from (%s) to (int64)", AsTypeStr(m_Elem->entry_data.type));
#endif // _SQ64
}
// Shouldn't really reach this point
return 0;
}
// ------------------------------------------------------------------------------------------------
SQFloat EntryDataList::GetFloat() const
{
// Validate the database, list and element handle
ValidateData();
// Attempt to perform the requested conversion
switch (m_Elem->entry_data.type)
{
#ifdef SQUSEDOUBLE
case MMDB_DATA_TYPE_UTF8_STRING:
return static_cast< SQFloat >(strtod(m_Elem->entry_data.utf8_string, NULL));
#else
return static_cast< SQFloat >(strtof(m_Elem->entry_data.utf8_string, NULL));
#endif // SQUSEDOUBLE
case MMDB_DATA_TYPE_DOUBLE:
return static_cast< SQFloat >(m_Elem->entry_data.double_value);
case MMDB_DATA_TYPE_UINT16:
return static_cast< SQFloat >(m_Elem->entry_data.uint16);
case MMDB_DATA_TYPE_UINT32:
return static_cast< SQFloat >(round(m_Elem->entry_data.uint32));
case MMDB_DATA_TYPE_INT32:
return static_cast< SQFloat >(round(m_Elem->entry_data.int32));
case MMDB_DATA_TYPE_UINT64:
return static_cast< SQFloat >(round(m_Elem->entry_data.uint64));
case MMDB_DATA_TYPE_BOOLEAN:
return m_Elem->entry_data.boolean ? 1.0 : 0.0;
case MMDB_DATA_TYPE_FLOAT:
return static_cast< SQFloat >(m_Elem->entry_data.float_value);
default:
SqThrowF("Unsupported conversion from (%s) to (float)", AsTypeStr(m_Elem->entry_data.type));
}
// Shouldn't really reach this point
return 0.0;
}
// ------------------------------------------------------------------------------------------------
Object EntryDataList::GetLong() const
{
// Validate the database, list and element handle
ValidateData();
// Where the long number is retrieved
Uint64 longint = 0;
Int64 slong = 0;
// Attempt to perform the requested conversion
switch (m_Elem->entry_data.type)
{
case MMDB_DATA_TYPE_UTF8_STRING:
longint = strtoull(m_Elem->entry_data.utf8_string, NULL, 10);
break;
case MMDB_DATA_TYPE_DOUBLE:
{
slong = llround(m_Elem->entry_data.double_value);
longint = slong >= 0 ? slong : 0;
} break;
case MMDB_DATA_TYPE_UINT16:
longint = m_Elem->entry_data.uint16;
break;
case MMDB_DATA_TYPE_UINT32:
longint = m_Elem->entry_data.uint32;
break;
case MMDB_DATA_TYPE_INT32:
longint = m_Elem->entry_data.int32 >= 0 ? m_Elem->entry_data.int32 : 0;
break;
case MMDB_DATA_TYPE_UINT64:
longint = m_Elem->entry_data.uint64;
break;
case MMDB_DATA_TYPE_BOOLEAN:
longint = m_Elem->entry_data.boolean ? 1 : 0;
break;
case MMDB_DATA_TYPE_FLOAT:
{
slong = llround(m_Elem->entry_data.float_value);
longint = slong >= 0 ? slong : 0;
}
break;
default:
SqThrowF("Unsupported conversion from (%s) to (uint64)", AsTypeStr(m_Elem->entry_data.type));
}
// Obtain the initial stack size
const StackGuard sg(_SqVM);
// Push a long integer instance with the requested value on the stack
_SqMod->PushULongObject(_SqVM, longint);
// Get the object from the stack and return it
return Var< Object >(_SqVM, -1).value;
}
// ------------------------------------------------------------------------------------------------
bool EntryDataList::GetBool() const
{
// Validate the database, list and element handle
ValidateData();
// Attempt to perform the requested conversion
switch (m_Elem->entry_data.type)
{
case MMDB_DATA_TYPE_UTF8_STRING:
return !!(m_Elem->entry_data.utf8_string);
case MMDB_DATA_TYPE_DOUBLE:
return EpsGt(m_Elem->entry_data.double_value, 0.0d);
case MMDB_DATA_TYPE_UINT16:
return (m_Elem->entry_data.uint16 > 0);
case MMDB_DATA_TYPE_UINT32:
return (m_Elem->entry_data.uint32 > 0);
case MMDB_DATA_TYPE_INT32:
return (m_Elem->entry_data.int32 > 0);
case MMDB_DATA_TYPE_UINT64:
return (m_Elem->entry_data.uint64 > 0);
case MMDB_DATA_TYPE_BOOLEAN:
return m_Elem->entry_data.boolean;
case MMDB_DATA_TYPE_FLOAT:
return EpsGt(m_Elem->entry_data.float_value, 0.0f);
default:
SqThrowF("Unsupported conversion from (%s) to (boolean)", AsTypeStr(m_Elem->entry_data.type));
}
// Shouldn't really reach this point
return false;
}
// ------------------------------------------------------------------------------------------------
void EntryDataList::DumpTo(CSStr filepath, Int32 indent) const
{
// Validate the database and list handle
Validate();
// Validate the specified file path
if (!filepath || strlen(filepath) <= 0)
SqThrowF("Invalid file path");
// Attempt to open the specified file
FILE * fp = fopen(filepath, "w");
// Validate the file handle
if (!fp)
SqThrowF("Unable to open file %s", filepath);
// Attempt to dump the entry data list
Int32 status = MMDB_dump_entry_data_list(fp, m_List, indent);
// Close the file handle
fclose(fp);
// Validate the result of the operation
if (status != MMDB_SUCCESS)
// Now it's safe to throw the error
SqThrowF("Unable to dump the list [%s]", MMDB_strerror(status));
}
} // Namespace:: SqMod

View File

@ -0,0 +1,291 @@
#ifndef _SQMMDB_LOOKUPRESULT_HPP_
#define _SQMMDB_LOOKUPRESULT_HPP_
// ------------------------------------------------------------------------------------------------
#include "Common.hpp"
// ------------------------------------------------------------------------------------------------
namespace SqMod {
/* ------------------------------------------------------------------------------------------------
* Class that can be used to traverse a list of results.
*/
class EntryDataList
{
protected:
// --------------------------------------------------------------------------------------------
typedef MMDB_entry_data_list_s Type; // The managed type.
// --------------------------------------------------------------------------------------------
typedef Type* Pointer; // Pointer to the managed type.
typedef const Type* ConstPtr; // Constant pointer to the managed type.
// --------------------------------------------------------------------------------------------
typedef Type& Reference; // Reference to the managed type.
typedef const Type& ConstRef; // Constant reference to the managed type.
/* --------------------------------------------------------------------------------------------
* Validate the database pointer and list handle and throw an error if invalid.
*/
void Validate() const;
/* --------------------------------------------------------------------------------------------
* Do a regular validation and also validate the currently processed element.
*/
void ValidateElem() const;
/* --------------------------------------------------------------------------------------------
* Do a regular validation and also validate the currently processed element data.
*/
void ValidateData() const;
/* --------------------------------------------------------------------------------------------
* Used to retrieve the string representation of the specified type identifier.
*/
static CSStr AsTypeStr(Uint32 id);
private:
// ---------------------------------------------------------------------------------------------
DbRef m_Db; /* The database from which this list comes from. */
Pointer m_List; /* The managed entry data list. */
Pointer m_Elem; /* The currently processed element from the list. */
/* --------------------------------------------------------------------------------------------
* Base constructor.
*/
EntryDataList(const DbRef & db, Pointer list)
: m_Db(db), m_List(list), m_Elem(list)
{
/* ... */
}
public:
/* --------------------------------------------------------------------------------------------
* Default constructor.
*/
EntryDataList();
/* --------------------------------------------------------------------------------------------
* Copy constructor. (disabled)
*/
EntryDataList(const EntryDataList &) = delete;
/* --------------------------------------------------------------------------------------------
* Move constructor.
*/
EntryDataList(EntryDataList && o)
: m_Db(o.m_Db)
, m_List(o.m_List)
, m_Elem(o.m_Elem)
{
o.m_List = nullptr;
o.m_Elem = nullptr;
}
/* --------------------------------------------------------------------------------------------
* Destructor.
*/
~EntryDataList();
/* --------------------------------------------------------------------------------------------
* Copy assignment operator. (disabled)
*/
EntryDataList & operator = (const EntryDataList &) = delete;
/* --------------------------------------------------------------------------------------------
* Move assignment operator.
*/
EntryDataList & operator = (EntryDataList && o)
{
if (m_List != o.m_List)
{
m_Db = o.m_Db;
m_List = o.m_List;
m_Elem = o.m_Elem;
o.m_List = nullptr;
o.m_Elem = nullptr;
}
return *this;
}
/* --------------------------------------------------------------------------------------------
* Retrieve the internal entry data list structure pointer.
*/
Pointer GetHandle()
{
return m_List;
}
/* --------------------------------------------------------------------------------------------
* Retrieve the internal entry data list structure pointer.
*/
Pointer GetHandle() const
{
return m_List;
}
/* --------------------------------------------------------------------------------------------
* Used by the script engine to compare two instances of this type.
*/
Int32 Cmp(const EntryDataList & o) const;
/* --------------------------------------------------------------------------------------------
* Used by the script engine to convert an instance of this type to a string.
*/
CSStr ToString() const
{
return m_Elem ? AsTypeStr(m_Elem->entry_data.type) : _SC("invalid");
}
/* --------------------------------------------------------------------------------------------
* Used by the script engine to retrieve the name from instances of this type.
*/
static SQInteger Typename(HSQUIRRELVM vm);
/* --------------------------------------------------------------------------------------------
* See whether this instance references a valid database and entry data list structure.
*/
bool IsValid() const
{
return m_Db && m_List;
}
/* --------------------------------------------------------------------------------------------
* See whether a valid element is currently processed.
*/
bool HaveElement() const
{
return m_Elem;
}
/* --------------------------------------------------------------------------------------------
* Used to retrieve the type of the current element as a string.
*/
CSStr TypeStr() const
{
// Validate the database and list handle
Validate();
// return the requested information
return m_Elem ? AsTypeStr(m_Elem->entry_data.type) : _SC("invalid");
}
/* --------------------------------------------------------------------------------------------
* Return the total entries in the list.
*/
Uint32 GetCount() const;
/* --------------------------------------------------------------------------------------------
* Go to the next element.
*/
bool Next();
/* --------------------------------------------------------------------------------------------
* Advance a certain number of elements.
*/
bool Advance(Int32 n);
/* --------------------------------------------------------------------------------------------
* Go back to the first element in the list.
*/
void Reset();
/* --------------------------------------------------------------------------------------------
* See whether a valid element is currently processed.
*/
bool HasData() const
{
// Validate the database, list and element handle
ValidateElem();
// Return the requested information
return m_Elem->entry_data.has_data;
}
/* --------------------------------------------------------------------------------------------
* Retrieve the type identifier of the current element.
*/
SQInteger GetType() const
{
// Validate the database, list and element handle
ValidateElem();
// Return the requested information
return static_cast< SQInteger >(m_Elem->entry_data.type);
}
/* --------------------------------------------------------------------------------------------
* Retrieve the offset of the current element.
*/
SQInteger GetOffset() const
{
// Validate the database, list and element handle
ValidateElem();
// Return the requested information
return static_cast< SQInteger >(m_Elem->entry_data.offset);
}
/* --------------------------------------------------------------------------------------------
* Retrieve the offset of the next element.
*/
SQInteger GetOffsetToNext() const
{
// Validate the database, list and element handle
ValidateElem();
// Return the requested information
return static_cast< SQInteger >(m_Elem->entry_data.offset_to_next);
}
/* --------------------------------------------------------------------------------------------
* Retrieve the offset of the next element.
*/
SQInteger DataSize() const
{
// Validate the database, list and element handle
ValidateElem();
// Return the requested information
return static_cast< SQInteger >(m_Elem->entry_data.data_size);
}
/* --------------------------------------------------------------------------------------------
* Retrieve the value from the current element as a string.
*/
CSStr GetString() const;
/* --------------------------------------------------------------------------------------------
* Retrieve the value from the current element as a native integer.
*/
SQInteger GetInteger() const;
/* --------------------------------------------------------------------------------------------
* Retrieve the value from the current element as a floating point.
*/
SQFloat GetFloat() const;
/* --------------------------------------------------------------------------------------------
* Retrieve the value from the current element as a long integer.
*/
Object GetLong() const;
/* --------------------------------------------------------------------------------------------
* Retrieve the value from the current element as a boolean.
*/
bool GetBool() const;
/* --------------------------------------------------------------------------------------------
* Dumpt the contents of the list to the specified list.
*/
void DumpTo(CSStr filepath)
{
DumpTo(filepath, 0);
}
/* --------------------------------------------------------------------------------------------
* Dumpt the contents of the list to the specified list.
*/
void DumpTo(CSStr filepath, Int32 indent) const;
};
} // Namespace:: SqMod
#endif // _SQMMDB_LOOKUPRESULT_HPP_

View File

@ -0,0 +1,54 @@
// ------------------------------------------------------------------------------------------------
#include "LookupResult.hpp"
#include "Module.hpp"
// ------------------------------------------------------------------------------------------------
namespace SqMod {
// ------------------------------------------------------------------------------------------------
SQInteger LookupResult::Typename(HSQUIRRELVM vm)
{
static const SQChar name[] = _SC("SqMMDBLookupResult");
sq_pushstring(vm, name, sizeof(name));
return 1;
}
// ------------------------------------------------------------------------------------------------
void LookupResult::Validate() const
{
// Is the document handle valid?
if (!m_Db)
SqThrowF("Invalid Maxmind database reference");
}
// ------------------------------------------------------------------------------------------------
LookupResult::LookupResult()
: m_Db(), m_Result()
{
memset(&m_Result, 0, sizeof(Type));
}
// ------------------------------------------------------------------------------------------------
Int32 LookupResult::Cmp(const LookupResult & o) const
{
if (m_Db == o.m_Db)
return 0;
else if (m_Db.DbPtr() > o.m_Db.DbPtr())
return 1;
else
return -1;
}
// ------------------------------------------------------------------------------------------------
EntryDataList LookupResult::GetValueA(CSStr path, Array & arr) const
{
}
// ------------------------------------------------------------------------------------------------
EntryDataList LookupResult::GetValueT(CSStr path, Table & tbl) const
{
}
} // Namespace:: SqMod

View File

@ -0,0 +1,164 @@
#ifndef _SQMMDB_LOOKUPRESULT_HPP_
#define _SQMMDB_LOOKUPRESULT_HPP_
// ------------------------------------------------------------------------------------------------
#include "Common.hpp"
// ------------------------------------------------------------------------------------------------
namespace SqMod {
/* ------------------------------------------------------------------------------------------------
* Class that can hold and be used to work with lookup results.
*/
class LookupResult
{
// --------------------------------------------------------------------------------------------
friend class Database; // Only a valid database instance can construct this type.
protected:
// --------------------------------------------------------------------------------------------
typedef MMDB_lookup_result_s Type; // The managed type.
// --------------------------------------------------------------------------------------------
typedef Type* Pointer; // Pointer to the managed type.
typedef const Type* ConstPtr; // Constant pointer to the managed type.
// --------------------------------------------------------------------------------------------
typedef Type& Reference; // Reference to the managed type.
typedef const Type& ConstRef; // Constant reference to the managed type.
/* --------------------------------------------------------------------------------------------
* Validate the database pointer and throw an error if invalid.
*/
void Validate() const;
private:
// ---------------------------------------------------------------------------------------------
DbRef m_Db; /* The database from which this result comes from. */
Type m_Result; /* The managed result structure. */
/* --------------------------------------------------------------------------------------------
* Construct and take ownership of a certain result.
*/
LookupResult(const DbRef & db, Reference result)
: m_Db(db), m_Result(result)
{
/* ... */
}
public:
/* --------------------------------------------------------------------------------------------
* Default constructor. (null)
*/
LookupResult();
/* --------------------------------------------------------------------------------------------
* Copy constructor.
*/
LookupResult(const LookupResult &) = default;
/* --------------------------------------------------------------------------------------------
* Move constructor.
*/
LookupResult(LookupResult &&) = default;
/* --------------------------------------------------------------------------------------------
* Destructor.
*/
~LookupResult()
{
/* We let the smart reference deal with deallocations if necessary. */
}
/* --------------------------------------------------------------------------------------------
* Copy assignment operator.
*/
LookupResult & operator = (const LookupResult &) = default;
/* --------------------------------------------------------------------------------------------
* Move assignment operator.
*/
LookupResult & operator = (LookupResult &&) = default;
/* --------------------------------------------------------------------------------------------
* Retrieve the internal result structure reference.
*/
Reference GetHandle()
{
return m_Result;
}
/* --------------------------------------------------------------------------------------------
* Retrieve the internal result structure reference.
*/
ConstRef GetHandle() const
{
return m_Result;
}
/* --------------------------------------------------------------------------------------------
* Used by the script engine to compare two instances of this type.
*/
Int32 Cmp(const LookupResult & o) const;
/* --------------------------------------------------------------------------------------------
* Used by the script engine to convert an instance of this type to a string.
*/
CSStr ToString() const
{
return FmtStr("%u", m_Result.entry.offset);
}
/* --------------------------------------------------------------------------------------------
* Used by the script engine to retrieve the name from instances of this type.
*/
static SQInteger Typename(HSQUIRRELVM vm);
/* --------------------------------------------------------------------------------------------
* See whether this instance references a valid database and result structure.
*/
bool IsValid() const
{
return m_Db && m_Result.found_entry;
}
/* --------------------------------------------------------------------------------------------
* See whether the result contains a valid entry in the associated database.
*/
bool FoundEntry() const
{
// Validate the database handle
Validate();
// Return the requested information
return m_Result.found_entry;
}
/* --------------------------------------------------------------------------------------------
* Retrieve the net-mask from the result structure.
*/
SQInteger GetNetMask() const
{
// Validate the database handle
Validate();
// Return the requested information
return static_cast< SQInteger >(m_Result.netmask);
}
/* --------------------------------------------------------------------------------------------
* Lookup data in the associated result using an array as the path.
*/
EntryDataList GetValueA(CSStr path, Array & arr) const;
/* --------------------------------------------------------------------------------------------
* Lookup data in the associated result using a table as the path.
*/
EntryDataList GetValueT(CSStr path, Table & tbl) const;
};
} // Namespace:: SqMod
#endif // _SQMMDB_LOOKUPRESULT_HPP_

302
modules/mmdb/Module.cpp Normal file
View File

@ -0,0 +1,302 @@
// --------------------------------------------------------------------------------------------
#include "Module.hpp"
#include "Common.hpp"
// --------------------------------------------------------------------------------------------
#include <sqrat.h>
// --------------------------------------------------------------------------------------------
#include <stdio.h>
#include <stdlib.h>
#include <stdarg.h>
// --------------------------------------------------------------------------------------------
#if defined(WIN32) || defined(_WIN32)
#include <Windows.h>
#endif
namespace SqMod {
// --------------------------------------------------------------------------------------------
PluginFuncs* _Func = NULL;
PluginCallbacks* _Clbk = NULL;
PluginInfo* _Info = NULL;
// --------------------------------------------------------------------------------------------
HSQAPI _SqAPI = NULL;
HSQEXPORTS _SqMod = NULL;
HSQUIRRELVM _SqVM = NULL;
/* ------------------------------------------------------------------------------------------------
* Bind speciffic functions to certain server events.
*/
void BindCallbacks();
/* ------------------------------------------------------------------------------------------------
* Undo changes made with BindCallbacks().
*/
void UnbindCallbacks();
/* --------------------------------------------------------------------------------------------
* Register the module API under the specified virtual machine.
*/
void RegisterAPI(HSQUIRRELVM vm);
/* --------------------------------------------------------------------------------------------
* Initialize the plugin by obtaining the API provided by the host plugin.
*/
void OnSquirrelInitialize()
{
// Attempt to import the plugin API exported by the host plugin
_SqMod = sq_api_import(_Func);
// Did we failed to obtain the plugin exports?
if(!_SqMod)
OutputError("Failed to attach [%s] on host plugin.", SQMMDB_NAME);
else
{
// Obtain the Squirrel API
_SqAPI = _SqMod->GetSquirrelAPI();
// Expand the Squirrel API into global functions
sq_api_expand(_SqAPI);
}
}
/* --------------------------------------------------------------------------------------------
* Load the module on the virtual machine provided by the host module.
*/
void OnSquirrelLoad()
{
// Make sure that we have a valid plugin API
if (!_SqMod)
return; /* Unable to proceed. */
// Obtain the Squirrel API and VM
_SqVM = _SqMod->GetSquirrelVM();
// Make sure that a valid virtual machine exists
if (!_SqVM)
return; /* Unable to proceed. */
// Set this as the default database
DefaultVM::Set(_SqVM);
// Register the module API
RegisterAPI(_SqVM);
// Notify about the current status
OutputMessage("Registered: %s", SQMMDB_NAME);
}
/* --------------------------------------------------------------------------------------------
* The virtual machine is about to be terminated and script resources should be released.
*/
void OnSquirrelTerminate()
{
OutputMessage("Terminating: %s", SQMMDB_NAME);
// Release the current database (if any)
DefaultVM::Set(NULL);
// Release script resources...
}
/* --------------------------------------------------------------------------------------------
* Validate the module API to make sure we don't run into issues.
*/
bool CheckAPIVer(CCStr ver)
{
// Obtain the numeric representation of the API version
long vernum = strtol(ver, NULL, 10);
// Check against version mismatch
if (vernum == SQMOD_API_VER)
return true;
// Log the incident
OutputError("API version mismatch on %s", SQMMDB_NAME);
OutputMessage("=> Requested: %ld Have: %ld", vernum, SQMOD_API_VER);
// Invoker should not attempt to communicate through the module API
return false;
}
/* --------------------------------------------------------------------------------------------
* React to command sent by other plugins.
*/
static int OnInternalCommand(unsigned int type, const char * text)
{
switch(type)
{
case SQMOD_INITIALIZE_CMD:
if (CheckAPIVer(text))
OnSquirrelInitialize();
break;
case SQMOD_LOAD_CMD:
OnSquirrelLoad();
break;
case SQMOD_TERMINATE_CMD:
OnSquirrelTerminate();
break;
default: break;
}
return 1;
}
/* --------------------------------------------------------------------------------------------
* The server was initialized and this plugin was loaded successfully.
*/
static int OnInitServer()
{
return 1;
}
static void OnShutdownServer(void)
{
// The server may still send callbacks
UnbindCallbacks();
}
// ------------------------------------------------------------------------------------------------
void BindCallbacks()
{
_Clbk->OnInitServer = OnInitServer;
_Clbk->OnInternalCommand = OnInternalCommand;
_Clbk->OnShutdownServer = OnShutdownServer;
}
// ------------------------------------------------------------------------------------------------
void UnbindCallbacks()
{
_Clbk->OnInitServer = NULL;
_Clbk->OnInternalCommand = NULL;
_Clbk->OnShutdownServer = NULL;
}
// --------------------------------------------------------------------------------------------
void RegisterAPI(HSQUIRRELVM vm)
{
}
// --------------------------------------------------------------------------------------------
void OutputMessageImpl(const char * msg, va_list args)
{
#if defined(WIN32) || defined(_WIN32)
HANDLE hstdout = GetStdHandle(STD_OUTPUT_HANDLE);
CONSOLE_SCREEN_BUFFER_INFO csb_before;
GetConsoleScreenBufferInfo( hstdout, &csb_before);
SetConsoleTextAttribute(hstdout, FOREGROUND_GREEN);
printf("[SQMOD] ");
SetConsoleTextAttribute(hstdout, FOREGROUND_GREEN | FOREGROUND_BLUE | FOREGROUND_RED | FOREGROUND_INTENSITY);
vprintf(msg, args);
puts("");
SetConsoleTextAttribute(hstdout, csb_before.wAttributes);
#else
printf("%c[0;32m[SQMOD]%c[0;37m", 27, 27, msg);
vprintf(msg, args);
puts("");
#endif
}
// --------------------------------------------------------------------------------------------
void OutputErrorImpl(const char * msg, va_list args)
{
#if defined(WIN32) || defined(_WIN32)
HANDLE hstdout = GetStdHandle(STD_OUTPUT_HANDLE);
CONSOLE_SCREEN_BUFFER_INFO csb_before;
GetConsoleScreenBufferInfo( hstdout, &csb_before);
SetConsoleTextAttribute(hstdout, FOREGROUND_RED | FOREGROUND_INTENSITY);
printf("[SQMOD] ");
SetConsoleTextAttribute(hstdout, FOREGROUND_GREEN | FOREGROUND_BLUE | FOREGROUND_RED | FOREGROUND_INTENSITY);
vprintf(msg, args);
puts("");
SetConsoleTextAttribute(hstdout, csb_before.wAttributes);
#else
printf("%c[0;32m[SQMOD]%c[0;37m", 27, 27, msg);
vprintf(msg, args);
puts("");
#endif
}
// --------------------------------------------------------------------------------------------
void OutputDebug(const char * msg, ...)
{
#ifdef _DEBUG
// Initialize the arguments list
va_list args;
va_start(args, msg);
// Call the output function
OutputMessageImpl(msg, args);
// Finalize the arguments list
va_end(args);
#else
SQMOD_UNUSED_VAR(msg);
#endif
}
// --------------------------------------------------------------------------------------------
void OutputMessage(const char * msg, ...)
{
// Initialize the arguments list
va_list args;
va_start(args, msg);
// Call the output function
OutputMessageImpl(msg, args);
// Finalize the arguments list
va_end(args);
}
// --------------------------------------------------------------------------------------------
void OutputError(const char * msg, ...)
{
// Initialize the arguments list
va_list args;
va_start(args, msg);
// Call the output function
OutputErrorImpl(msg, args);
// Finalize the arguments list
va_end(args);
}
} // Namespace:: SqMod
// --------------------------------------------------------------------------------------------
SQMOD_API_EXPORT unsigned int VcmpPluginInit(PluginFuncs* functions, PluginCallbacks* callbacks, PluginInfo* info)
{
using namespace SqMod;
// Output plugin header
puts("");
OutputMessage("--------------------------------------------------------------------");
OutputMessage("Plugin: %s", SQMMDB_NAME);
OutputMessage("Author: %s", SQMMDB_AUTHOR);
OutputMessage("Legal: %s", SQMMDB_COPYRIGHT);
OutputMessage("--------------------------------------------------------------------");
puts("");
// Attempt to find the host plugin ID
int host_plugin_id = functions->FindPlugin((char *)(SQMOD_HOST_NAME));
// See if our plugin was loaded after the host plugin
if (host_plugin_id < 0)
{
OutputError("%s could find the host plugin", SQMMDB_NAME);
// Don't load!
return SQMOD_FAILURE;
}
// Should never reach this point but just in case
else if (host_plugin_id > (info->nPluginId))
{
OutputError("%s loaded after the host plugin", SQMMDB_NAME);
// Don't load!
return SQMOD_FAILURE;
}
// Store server proxies
_Func = functions;
_Clbk = callbacks;
_Info = info;
// Assign plugin information
_Info->uPluginVer = SQMMDB_VERSION;
strcpy(_Info->szName, SQMMDB_HOST_NAME);
// Bind callbacks
BindCallbacks();
// Notify that the plugin was successfully loaded
OutputMessage("Successfully loaded %s", SQMMDB_NAME);
// Dummy spacing
puts("");
// Done!
return SQMOD_SUCCESS;
}

41
modules/mmdb/Module.hpp Normal file
View File

@ -0,0 +1,41 @@
#ifndef _SQMMDB_MODULE_HPP_
#define _SQMMDB_MODULE_HPP_
// ------------------------------------------------------------------------------------------------
#include "SqMod.h"
// ------------------------------------------------------------------------------------------------
namespace SqMod {
/* ------------------------------------------------------------------------------------------------
* Proxies to comunicate with the server.
*/
extern PluginFuncs* _Func;
extern PluginCallbacks* _Clbk;
extern PluginInfo* _Info;
/* ------------------------------------------------------------------------------------------------
* Proxies to comunicate with the Squirrel plugin.
*/
extern HSQAPI _SqAPI;
extern HSQEXPORTS _SqMod;
extern HSQUIRRELVM _SqVM;
/* ------------------------------------------------------------------------------------------------
* Output a message only if the _DEBUG was defined.
*/
void OutputDebug(const char * msg, ...);
/* ------------------------------------------------------------------------------------------------
* Output a formatted user message to the console.
*/
void OutputMessage(const char * msg, ...);
/* ------------------------------------------------------------------------------------------------
* Output a formatted error message to the console.
*/
void OutputError(const char * msg, ...);
} // Namespace:: SqMod
#endif // _SQMMDB_MODULE_HPP_

68
modules/mmdb/SockAddr.cpp Normal file
View File

@ -0,0 +1,68 @@
// ------------------------------------------------------------------------------------------------
#include "Sockaddr.hpp"
#include "Module.hpp"
// ------------------------------------------------------------------------------------------------
namespace SqMod {
// ------------------------------------------------------------------------------------------------
SQInteger SockAddr::Typename(HSQUIRRELVM vm)
{
static const SQChar name[] = _SC("SqMMDBSockAddr");
sq_pushstring(vm, name, sizeof(name));
return 1;
}
// ------------------------------------------------------------------------------------------------
void SockAddr::Validate() const
{
// Is the document handle valid?
if (!m_Handle)
SqThrowF("Invalid sockaddr structure handle");
}
// ------------------------------------------------------------------------------------------------
SockAddr::SockAddr(CSStr addr)
: m_Handle(NULL), m_Addres(_SC(""))
{
struct addrinfo hints;
// Configure the hints structure
hints.ai_family = AF_UNSPEC;
hints.ai_flags = AI_NUMERICHOST;
// We set ai_socktype so that we only get one result back
hints.ai_socktype = SOCK_STREAM;
// Attempt to obtain information about the specified address
Int32 status = getaddrinfo(addr, NULL, &hints, &m_Handle);
// Validate the success of the operation
if (!status)
{
// See if we must free any handles (just in case)
if (m_Handle)
freeaddrinfo(m_Handle);
// Now it's safe to throw the error
SqThrowF("Unable to query the specified address for information [%s]", gai_strerror(status));
}
// Save the specified string address
m_Addres.assign(addr ? addr : _SC(""));
}
// ------------------------------------------------------------------------------------------------
SockAddr::~SockAddr()
{
if (m_Handle)
freeaddrinfo(m_Handle);
}
// ------------------------------------------------------------------------------------------------
Int32 SockAddr::Cmp(const SockAddr & o) const
{
if (m_Handle == o.m_Handle)
return 0;
else if (m_Handle > o.m_Handle)
return 1;
else
return -1;
}
} // Namespace:: SqMod

147
modules/mmdb/Sockaddr.hpp Normal file
View File

@ -0,0 +1,147 @@
#ifndef _SQMMDB_SOCKADDR_HPP_
#define _SQMMDB_SOCKADDR_HPP_
// ------------------------------------------------------------------------------------------------
#include "Common.hpp"
// ------------------------------------------------------------------------------------------------
namespace SqMod {
/* ------------------------------------------------------------------------------------------------
* Class that can obtain information from string addresses and be used repeatedly thereafter.
*/
class SockAddr
{
protected:
// --------------------------------------------------------------------------------------------
typedef struct addrinfo Type; // The managed type.
// --------------------------------------------------------------------------------------------
typedef Type* Pointer; // Pointer to the managed type.
typedef const Type* ConstPtr; // Constant pointer to the managed type.
// --------------------------------------------------------------------------------------------
typedef Type& Reference; // Reference to the managed type.
typedef const Type& ConstRef; // Constant reference to the managed type.
/* --------------------------------------------------------------------------------------------
* Validate the sockaddr pointer and throw an error if invalid.
*/
void Validate() const;
private:
// ---------------------------------------------------------------------------------------------
Pointer m_Handle; /* The managed sockaddr structure. */
String m_Addres; /* The address that was queried for information. */
public:
/* --------------------------------------------------------------------------------------------
* Default constructor.
*/
SockAddr()
: m_Handle(NULL), m_Addres(_SC(""))
{
/* ... */
}
/* --------------------------------------------------------------------------------------------
* Base constructor.
*/
SockAddr(CSStr addr);
/* --------------------------------------------------------------------------------------------
* Copy constructor. (disabled)
*/
SockAddr(const SockAddr &) = delete;
/* --------------------------------------------------------------------------------------------
* Move constructor.
*/
SockAddr(SockAddr && o)
: m_Handle(o.m_Handle)
, m_Addres(o.m_Addres)
{
o.m_Handle = nullptr;
}
/* --------------------------------------------------------------------------------------------
* Destructor.
*/
~SockAddr();
/* --------------------------------------------------------------------------------------------
* Copy assignment operator. (disabled)
*/
SockAddr & operator = (const SockAddr &) = delete;
/* --------------------------------------------------------------------------------------------
* Move assignment operator.
*/
SockAddr & operator = (SockAddr && o)
{
if (m_Handle != o.m_Handle)
{
m_Handle = o.m_Handle;
m_Addres = o.m_Addres;
o.m_Handle = nullptr;
}
return *this;
}
/* --------------------------------------------------------------------------------------------
* Retrieve the internal addrinfo structure pointer.
*/
Pointer GetHandle()
{
return m_Handle;
}
/* --------------------------------------------------------------------------------------------
* Retrieve the internal addrinfo structure pointer.
*/
Pointer GetHandle() const
{
return m_Handle;
}
/* --------------------------------------------------------------------------------------------
* Used by the script engine to compare two instances of this type.
*/
Int32 Cmp(const SockAddr & o) const;
/* --------------------------------------------------------------------------------------------
* Used by the script engine to convert an instance of this type to a string.
*/
CSStr ToString() const
{
return m_Addres.c_str();
}
/* --------------------------------------------------------------------------------------------
* Used by the script engine to retrieve the name from instances of this type.
*/
static SQInteger Typename(HSQUIRRELVM vm);
/* --------------------------------------------------------------------------------------------
* See whether this instance references a valid addrinfo structure.
*/
bool IsValid() const
{
return m_Handle;
}
/* --------------------------------------------------------------------------------------------
* Retrieve the associated string address.
*/
CSStr GetAddress() const
{
return m_Addres.c_str();
}
};
} // Namespace:: SqMod
#endif // _SQMMDB_SOCKADDR_HPP_

View File

@ -389,7 +389,7 @@ SQInteger Connection::ExecF(HSQUIRRELVM vm)
SQRESULT ret = sqstd_format(vm, 3, &len, &sql);
// Did the format failed?
if (SQ_FAILED(ret))
return ret;
return ret; // Propagate the exception
// Attempt to execute the resulted query
if ((inst.value->m_Handle = sqlite3_exec(inst.value->m_Handle, sql, NULL, NULL, NULL)) != SQLITE_OK)
{
@ -399,7 +399,7 @@ SQInteger Connection::ExecF(HSQUIRRELVM vm)
// Push the result onto the stack
sq_pushinteger(vm, sqlite3_changes(inst.value->m_Handle));
}
// All methods of retrieving the message value failed
// All methods of retrieving the string value failed
else
return sq_throwerror(vm, "Unable to extract the query string");
// At this point we should have a return value on the stack
@ -455,14 +455,14 @@ SQInteger Connection::QueueF(HSQUIRRELVM vm)
SQRESULT ret = sqstd_format(vm, 3, &len, &sql);
// Did the format failed?
if (SQ_FAILED(ret))
return ret;
return ret; // Propagate the exception
// Is there even a query to queue?
else if (IsQueryEmpty(sql))
return sq_throwerror(vm,"No query to queue");
// Attempt to queue the specified query
inst.value->m_Handle->mQueue.push_back(sql);
}
// All methods of retrieving the message value failed
// All methods of retrieving the string value failed
else
return sq_throwerror(vm, "Unable to extract the query string");
// This function does not return a value
@ -519,7 +519,7 @@ SQInteger Connection::QueryF(HSQUIRRELVM vm)
SQRESULT ret = sqstd_format(vm, 3, &len, &sql);
// Did the format failed?
if (SQ_FAILED(ret))
return ret;
return ret; // Propagate the exception
// Attempt to create a statement with the specified query
try
{
@ -530,7 +530,7 @@ SQInteger Connection::QueryF(HSQUIRRELVM vm)
return sq_throwerror(vm, e.Message().c_str());
}
}
// All methods of retrieving the message value failed
// All methods of retrieving the string value failed
else
return sq_throwerror(vm, "Unable to extract the query string");
// At this point we should have a return value on the stack