// ------------------------------------------------------------------------------------------------ #include "EntryDataList.hpp" #include "Module.hpp" // ------------------------------------------------------------------------------------------------ #include #include // ------------------------------------------------------------------------------------------------ #include // ------------------------------------------------------------------------------------------------ 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