1
0
mirror of https://github.com/VCMP-SqMod/SqMod.git synced 2025-06-21 01:27:14 +02:00

Update MaxMind DB library to current master.

This commit is contained in:
Sandu Liviu Catalin
2019-08-17 15:47:43 +03:00
parent 33ed902a72
commit 8769051980
8 changed files with 436 additions and 524 deletions

180
external/MaxmindDB/data-pool.c vendored Normal file
View File

@ -0,0 +1,180 @@
#include "data-pool.h"
#include "maxminddb.h"
#include <stdbool.h>
#include <stddef.h>
#include <stdlib.h>
static bool can_multiply(size_t const, size_t const, size_t const);
// Allocate an MMDB_data_pool_s. It initially has space for size
// MMDB_entry_data_list_s structs.
MMDB_data_pool_s *data_pool_new(size_t const size)
{
MMDB_data_pool_s *const pool = calloc(1, sizeof(MMDB_data_pool_s));
if (!pool) {
return NULL;
}
if (size == 0 ||
!can_multiply(SIZE_MAX, size, sizeof(MMDB_entry_data_list_s))) {
data_pool_destroy(pool);
return NULL;
}
pool->size = size;
pool->blocks[0] = calloc(pool->size, sizeof(MMDB_entry_data_list_s));
if (!pool->blocks[0]) {
data_pool_destroy(pool);
return NULL;
}
pool->blocks[0]->pool = pool;
pool->sizes[0] = size;
pool->block = pool->blocks[0];
return pool;
}
// Determine if we can multiply m*n. We can do this if the result will be below
// the given max. max will typically be SIZE_MAX.
//
// We want to know if we'll wrap around.
static bool can_multiply(size_t const max, size_t const m, size_t const n)
{
if (m == 0) {
return false;
}
return n <= max / m;
}
// Clean up the data pool.
void data_pool_destroy(MMDB_data_pool_s *const pool)
{
if (!pool) {
return;
}
for (size_t i = 0; i <= pool->index; i++) {
free(pool->blocks[i]);
}
free(pool);
}
// Claim a new struct from the pool. Doing this may cause the pool's size to
// grow.
MMDB_entry_data_list_s *data_pool_alloc(MMDB_data_pool_s *const pool)
{
if (!pool) {
return NULL;
}
if (pool->used < pool->size) {
MMDB_entry_data_list_s *const element = pool->block + pool->used;
pool->used++;
return element;
}
// Take it from a new block of memory.
size_t const new_index = pool->index + 1;
if (new_index == DATA_POOL_NUM_BLOCKS) {
// See the comment about not growing this on DATA_POOL_NUM_BLOCKS.
return NULL;
}
if (!can_multiply(SIZE_MAX, pool->size, 2)) {
return NULL;
}
size_t const new_size = pool->size * 2;
if (!can_multiply(SIZE_MAX, new_size, sizeof(MMDB_entry_data_list_s))) {
return NULL;
}
pool->blocks[new_index] = calloc(new_size, sizeof(MMDB_entry_data_list_s));
if (!pool->blocks[new_index]) {
return NULL;
}
// We don't need to set this, but it's useful for introspection in tests.
pool->blocks[new_index]->pool = pool;
pool->index = new_index;
pool->block = pool->blocks[pool->index];
pool->size = new_size;
pool->sizes[pool->index] = pool->size;
MMDB_entry_data_list_s *const element = pool->block;
pool->used = 1;
return element;
}
// Turn the structs in the array-like pool into a linked list.
//
// Before calling this function, the list isn't linked up.
MMDB_entry_data_list_s *data_pool_to_list(MMDB_data_pool_s *const pool)
{
if (!pool) {
return NULL;
}
if (pool->index == 0 && pool->used == 0) {
return NULL;
}
for (size_t i = 0; i <= pool->index; i++) {
MMDB_entry_data_list_s *const block = pool->blocks[i];
size_t size = pool->sizes[i];
if (i == pool->index) {
size = pool->used;
}
for (size_t j = 0; j < size - 1; j++) {
MMDB_entry_data_list_s *const cur = block + j;
cur->next = block + j + 1;
}
if (i < pool->index) {
MMDB_entry_data_list_s *const last = block + size - 1;
last->next = pool->blocks[i + 1];
}
}
return pool->blocks[0];
}
#ifdef TEST_DATA_POOL
#include <libtap/tap.h>
#include <maxminddb_test_helper.h>
static void test_can_multiply(void);
int main(void)
{
plan(NO_PLAN);
test_can_multiply();
done_testing();
}
static void test_can_multiply(void)
{
{
ok(can_multiply(SIZE_MAX, 1, SIZE_MAX), "1*SIZE_MAX is ok");
}
{
ok(!can_multiply(SIZE_MAX, 2, SIZE_MAX), "2*SIZE_MAX is not ok");
}
{
ok(can_multiply(SIZE_MAX, 10240, sizeof(MMDB_entry_data_list_s)),
"1024 entry_data_list_s's are okay");
}
}
#endif

52
external/MaxmindDB/data-pool.h vendored Normal file
View File

@ -0,0 +1,52 @@
#ifndef DATA_POOL_H
#define DATA_POOL_H
#include "maxminddb.h"
#include <stdbool.h>
#include <stddef.h>
// This should be large enough that we never need to grow the array of pointers
// to blocks. 32 is enough. Even starting out of with size 1 (1 struct), the
// 32nd element alone will provide 2**32 structs as we exponentially increase
// the number in each block. Being confident that we do not have to grow the
// array lets us avoid writing code to do that. That code would be risky as it
// would rarely be hit and likely not be well tested.
#define DATA_POOL_NUM_BLOCKS 32
// A pool of memory for MMDB_entry_data_list_s structs. This is so we can
// allocate multiple up front rather than one at a time for performance
// reasons.
//
// The order you add elements to it (by calling data_pool_alloc()) ends up as
// the order of the list.
//
// The memory only grows. There is no support for releasing an element you take
// back to the pool.
typedef struct MMDB_data_pool_s {
// Index of the current block we're allocating out of.
size_t index;
// The size of the current block, counting by structs.
size_t size;
// How many used in the current block, counting by structs.
size_t used;
// The current block we're allocating out of.
MMDB_entry_data_list_s *block;
// The size of each block.
size_t sizes[DATA_POOL_NUM_BLOCKS];
// An array of pointers to blocks of memory holding space for list
// elements.
MMDB_entry_data_list_s *blocks[DATA_POOL_NUM_BLOCKS];
} MMDB_data_pool_s;
MMDB_data_pool_s *data_pool_new(size_t const);
void data_pool_destroy(MMDB_data_pool_s *const);
MMDB_entry_data_list_s *data_pool_alloc(MMDB_data_pool_s *const);
MMDB_entry_data_list_s *data_pool_to_list(MMDB_data_pool_s *const);
#endif

View File

@ -1,6 +1,7 @@
#if HAVE_CONFIG_H
#include <config.h>
#endif
#include "data-pool.h"
#include "maxminddb.h"
#include "maxminddb-compat-util.h"
#include <assert.h>
@ -13,6 +14,9 @@
#include <sys/stat.h>
#ifdef _WIN32
#ifndef UNICODE
#define UNICODE
#endif
#include <windows.h>
#include <ws2ipdef.h>
#else
@ -26,8 +30,6 @@
#ifdef MMDB_DEBUG
#define LOCAL
#define NO_PROTO
#define DEBUG_FUNC
#define DEBUG_MSG(msg) fprintf(stderr, msg "\n")
#define DEBUG_MSGF(fmt, ...) fprintf(stderr, fmt "\n", __VA_ARGS__)
#define DEBUG_BINARY(fmt, byte) \
@ -43,7 +45,6 @@
#define DEBUG_NL fprintf(stderr, "\n")
#else
#define LOCAL static
#define NO_PROTO static
#define DEBUG_MSG(...)
#define DEBUG_MSGF(...)
#define DEBUG_BINARY(...)
@ -51,7 +52,7 @@
#endif
#ifdef MMDB_DEBUG
DEBUG_FUNC char *byte_to_binary(uint8_t byte)
char *byte_to_binary(uint8_t byte)
{
char *bits = malloc(sizeof(char) * 9);
if (NULL == bits) {
@ -66,7 +67,7 @@ DEBUG_FUNC char *byte_to_binary(uint8_t byte)
return bits;
}
DEBUG_FUNC char *type_num_to_name(uint8_t num)
char *type_num_to_name(uint8_t num)
{
switch (num) {
case 0:
@ -130,13 +131,14 @@ typedef struct record_info_s {
/* This is 128kb */
#define METADATA_BLOCK_MAX_SIZE 131072
/* *INDENT-OFF* */
/* --prototypes automatically generated by dev-bin/regen-prototypes.pl - don't remove this comment */
// 64 leads us to allocating 4 KiB on a 64bit system.
#define MMDB_POOL_INIT_SIZE 64
LOCAL int map_file(MMDB_s *const mmdb);
LOCAL const uint8_t *find_metadata(const uint8_t *file_content,
ssize_t file_size, uint32_t *metadata_size);
LOCAL int read_metadata(MMDB_s *mmdb);
LOCAL MMDB_s make_fake_metadata_db(MMDB_s *mmdb);
LOCAL MMDB_s make_fake_metadata_db(const MMDB_s *const mmdb);
LOCAL int value_for_key_as_uint16(MMDB_entry_s *start, char *key,
uint16_t *value);
LOCAL int value_for_key_as_uint32(MMDB_entry_s *start, char *key,
@ -150,34 +152,38 @@ LOCAL int populate_languages_metadata(MMDB_s *mmdb, MMDB_s *metadata_db,
LOCAL int populate_description_metadata(MMDB_s *mmdb, MMDB_s *metadata_db,
MMDB_entry_s *metadata_start);
LOCAL int resolve_any_address(const char *ipstr, struct addrinfo **addresses);
LOCAL int find_address_in_search_tree(MMDB_s *mmdb, uint8_t *address,
LOCAL int find_address_in_search_tree(const MMDB_s *const mmdb,
uint8_t *address,
sa_family_t address_family,
MMDB_lookup_result_s *result);
LOCAL record_info_s record_info_for_database(MMDB_s *mmdb);
LOCAL int find_ipv4_start_node(MMDB_s *mmdb);
LOCAL uint8_t maybe_populate_result(MMDB_s *mmdb, uint32_t record,
LOCAL record_info_s record_info_for_database(const MMDB_s *const mmdb);
LOCAL int find_ipv4_start_node(MMDB_s *const mmdb);
LOCAL uint8_t maybe_populate_result(const MMDB_s *const mmdb, uint32_t record,
uint16_t netmask,
MMDB_lookup_result_s *result);
LOCAL uint8_t record_type(MMDB_s *const mmdb, uint64_t record);
LOCAL uint8_t record_type(const MMDB_s *const mmdb, uint64_t record);
LOCAL uint32_t get_left_28_bit_record(const uint8_t *record);
LOCAL uint32_t get_right_28_bit_record(const uint8_t *record);
LOCAL uint32_t data_section_offset_for_record(MMDB_s *const mmdb,
LOCAL uint32_t data_section_offset_for_record(const MMDB_s *const mmdb,
uint64_t record);
LOCAL int path_length(va_list va_path);
LOCAL int lookup_path_in_array(const char *path_elem, MMDB_s *mmdb,
LOCAL int lookup_path_in_array(const char *path_elem, const MMDB_s *const mmdb,
MMDB_entry_data_s *entry_data);
LOCAL int lookup_path_in_map(const char *path_elem, MMDB_s *mmdb,
LOCAL int lookup_path_in_map(const char *path_elem, const MMDB_s *const mmdb,
MMDB_entry_data_s *entry_data);
LOCAL int skip_map_or_array(MMDB_s *mmdb, MMDB_entry_data_s *entry_data);
LOCAL int decode_one_follow(MMDB_s *mmdb, uint32_t offset,
LOCAL int skip_map_or_array(const MMDB_s *const mmdb,
MMDB_entry_data_s *entry_data);
LOCAL int decode_one(MMDB_s *mmdb, uint32_t offset,
LOCAL int decode_one_follow(const MMDB_s *const mmdb, uint32_t offset,
MMDB_entry_data_s *entry_data);
LOCAL int decode_one(const MMDB_s *const mmdb, uint32_t offset,
MMDB_entry_data_s *entry_data);
LOCAL int get_ext_type(int raw_ext_type);
LOCAL uint32_t get_ptr_from(uint8_t ctrl, uint8_t const *const ptr,
int ptr_size);
LOCAL int get_entry_data_list(MMDB_s *mmdb, uint32_t offset,
LOCAL int get_entry_data_list(const MMDB_s *const mmdb,
uint32_t offset,
MMDB_entry_data_list_s *const entry_data_list,
MMDB_data_pool_s *const pool,
int depth);
LOCAL float get_ieee754_float(const uint8_t *restrict p);
LOCAL double get_ieee754_double(const uint8_t *restrict p);
@ -186,7 +192,6 @@ LOCAL uint32_t get_uint24(const uint8_t *p);
LOCAL uint32_t get_uint16(const uint8_t *p);
LOCAL uint64_t get_uintX(const uint8_t *p, int length);
LOCAL int32_t get_sintX(const uint8_t *p, int length);
LOCAL MMDB_entry_data_list_s *new_entry_data_list(void);
LOCAL void free_mmdb_struct(MMDB_s *const mmdb);
LOCAL void free_languages_metadata(MMDB_s *mmdb);
LOCAL void free_descriptions_metadata(MMDB_s *mmdb);
@ -195,8 +200,6 @@ LOCAL MMDB_entry_data_list_s *dump_entry_data_list(
int *status);
LOCAL void print_indentation(FILE *stream, int i);
LOCAL char *bytes_to_hex(uint8_t *bytes, uint32_t size);
/* --prototypes end - don't remove this comment-- */
/* *INDENT-ON* */
#define CHECKED_DECODE_ONE(mmdb, offset, entry_data) \
do { \
@ -228,6 +231,7 @@ int MMDB_open(const char *const filename, uint32_t flags, MMDB_s *const mmdb)
mmdb->data_section = NULL;
mmdb->metadata.database_type = NULL;
mmdb->metadata.languages.count = 0;
mmdb->metadata.languages.names = NULL;
mmdb->metadata.description.count = 0;
mmdb->filename = mmdb_strdup(filename);
@ -241,7 +245,7 @@ int MMDB_open(const char *const filename, uint32_t flags, MMDB_s *const mmdb)
}
mmdb->flags = flags;
if (MMDB_SUCCESS != (status = map_file(mmdb)) ) {
if (MMDB_SUCCESS != (status = map_file(mmdb))) {
goto cleanup;
}
@ -297,6 +301,15 @@ int MMDB_open(const char *const filename, uint32_t flags, MMDB_s *const mmdb)
mmdb->ipv4_start_node.node_value = 0;
mmdb->ipv4_start_node.netmask = 0;
// We do this immediately as otherwise there is a race to set
// ipv4_start_node.node_value and ipv4_start_node.netmask.
if (mmdb->metadata.ip_version == 6) {
status = find_ipv4_start_node(mmdb);
if (status != MMDB_SUCCESS) {
goto cleanup;
}
}
cleanup:
if (MMDB_SUCCESS != status) {
int saved_errno = errno;
@ -308,13 +321,33 @@ int MMDB_open(const char *const filename, uint32_t flags, MMDB_s *const mmdb)
#ifdef _WIN32
LOCAL LPWSTR utf8_to_utf16(const char *utf8_str)
{
int wide_chars = MultiByteToWideChar(CP_UTF8, 0, utf8_str, -1, NULL, 0);
wchar_t *utf16_str = (wchar_t *)malloc(wide_chars * sizeof(wchar_t));
if (MultiByteToWideChar(CP_UTF8, 0, utf8_str, -1, utf16_str,
wide_chars) < 1) {
free(utf16_str);
return NULL;
}
return utf16_str;
}
LOCAL int map_file(MMDB_s *const mmdb)
{
DWORD size;
int status = MMDB_SUCCESS;
HANDLE mmh = NULL;
HANDLE fd = CreateFileA(mmdb->filename, GENERIC_READ, FILE_SHARE_READ, NULL,
OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, NULL);
HANDLE fd = INVALID_HANDLE_VALUE;
LPWSTR utf16_filename = utf8_to_utf16(mmdb->filename);
if (!utf16_filename) {
status = MMDB_FILE_OPEN_ERROR;
goto cleanup;
}
fd = CreateFile(utf16_filename, GENERIC_READ, FILE_SHARE_READ, NULL,
OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, NULL);
if (fd == INVALID_HANDLE_VALUE) {
status = MMDB_FILE_OPEN_ERROR;
goto cleanup;
@ -324,7 +357,7 @@ LOCAL int map_file(MMDB_s *const mmdb)
status = MMDB_FILE_OPEN_ERROR;
goto cleanup;
}
mmh = CreateFileMappingA(fd, NULL, PAGE_READONLY, 0, size, NULL);
mmh = CreateFileMapping(fd, NULL, PAGE_READONLY, 0, size, NULL);
/* Microsoft documentation for CreateFileMapping indicates this returns
NULL not INVALID_HANDLE_VALUE on error */
if (NULL == mmh) {
@ -350,18 +383,23 @@ LOCAL int map_file(MMDB_s *const mmdb)
CloseHandle(mmh);
}
errno = saved_errno;
free(utf16_filename);
return status;
}
#else
#else // _WIN32
LOCAL int map_file(MMDB_s *const mmdb)
{
ssize_t size;
int status = MMDB_SUCCESS;
int fd = open(mmdb->filename, O_RDONLY);
int flags = O_RDONLY;
#ifdef O_CLOEXEC
flags |= O_CLOEXEC;
#endif
int fd = open(mmdb->filename, flags);
struct stat s;
if (fd < 0 || fstat(fd, &s)) {
status = MMDB_FILE_OPEN_ERROR;
@ -398,7 +436,7 @@ LOCAL int map_file(MMDB_s *const mmdb)
return status;
}
#endif
#endif // _WIN32
LOCAL const uint8_t *find_metadata(const uint8_t *file_content,
ssize_t file_size, uint32_t *metadata_size)
@ -548,7 +586,7 @@ LOCAL int read_metadata(MMDB_s *mmdb)
return MMDB_SUCCESS;
}
LOCAL MMDB_s make_fake_metadata_db(MMDB_s *mmdb)
LOCAL MMDB_s make_fake_metadata_db(const MMDB_s *const mmdb)
{
MMDB_s fake_metadata_db = {
.data_section = mmdb->metadata_section,
@ -796,7 +834,7 @@ LOCAL int populate_description_metadata(MMDB_s *mmdb, MMDB_s *metadata_db,
return status;
}
MMDB_lookup_result_s MMDB_lookup_string(MMDB_s *const mmdb,
MMDB_lookup_result_s MMDB_lookup_string(const MMDB_s *const mmdb,
const char *const ipstr,
int *const gai_error,
int *const mmdb_error)
@ -842,7 +880,7 @@ LOCAL int resolve_any_address(const char *ipstr, struct addrinfo **addresses)
}
MMDB_lookup_result_s MMDB_lookup_sockaddr(
MMDB_s *const mmdb,
const MMDB_s *const mmdb,
const struct sockaddr *const sockaddr,
int *const mmdb_error)
{
@ -882,7 +920,8 @@ MMDB_lookup_result_s MMDB_lookup_sockaddr(
return result;
}
LOCAL int find_address_in_search_tree(MMDB_s *mmdb, uint8_t *address,
LOCAL int find_address_in_search_tree(const MMDB_s *const mmdb,
uint8_t *address,
sa_family_t address_family,
MMDB_lookup_result_s *result)
{
@ -899,10 +938,7 @@ LOCAL int find_address_in_search_tree(MMDB_s *mmdb, uint8_t *address,
uint16_t start_bit = max_depth0;
if (mmdb->metadata.ip_version == 6 && address_family == AF_INET) {
int mmdb_error = find_ipv4_start_node(mmdb);
if (MMDB_SUCCESS != mmdb_error) {
return mmdb_error;
}
/* ipv4 start node values set at open */
DEBUG_MSGF("IPv4 start node is %u (netmask %u)",
mmdb->ipv4_start_node.node_value,
mmdb->ipv4_start_node.netmask);
@ -966,7 +1002,7 @@ LOCAL int find_address_in_search_tree(MMDB_s *mmdb, uint8_t *address,
return MMDB_CORRUPT_SEARCH_TREE_ERROR;
}
LOCAL record_info_s record_info_for_database(MMDB_s *mmdb)
LOCAL record_info_s record_info_for_database(const MMDB_s *const mmdb)
{
record_info_s record_info = {
.record_length = mmdb->full_record_byte_size,
@ -992,7 +1028,7 @@ LOCAL record_info_s record_info_for_database(MMDB_s *mmdb)
return record_info;
}
LOCAL int find_ipv4_start_node(MMDB_s *mmdb)
LOCAL int find_ipv4_start_node(MMDB_s *const mmdb)
{
/* In a pathological case of a database with a single node search tree,
* this check will be true even after we've found the IPv4 start node, but
@ -1026,7 +1062,7 @@ LOCAL int find_ipv4_start_node(MMDB_s *mmdb)
return MMDB_SUCCESS;
}
LOCAL uint8_t maybe_populate_result(MMDB_s *mmdb, uint32_t record,
LOCAL uint8_t maybe_populate_result(const MMDB_s *const mmdb, uint32_t record,
uint16_t netmask,
MMDB_lookup_result_s *result)
{
@ -1048,7 +1084,7 @@ LOCAL uint8_t maybe_populate_result(MMDB_s *mmdb, uint32_t record,
return type;
}
LOCAL uint8_t record_type(MMDB_s *const mmdb, uint64_t record)
LOCAL uint8_t record_type(const MMDB_s *const mmdb, uint64_t record)
{
uint32_t node_count = mmdb->metadata.node_count;
@ -1088,7 +1124,7 @@ LOCAL uint32_t get_right_28_bit_record(const uint8_t *record)
return value & 0xfffffff;
}
int MMDB_read_node(MMDB_s *const mmdb, uint32_t node_number,
int MMDB_read_node(const MMDB_s *const mmdb, uint32_t node_number,
MMDB_search_node_s *const node)
{
record_info_s record_info = record_info_for_database(mmdb);
@ -1125,7 +1161,7 @@ int MMDB_read_node(MMDB_s *const mmdb, uint32_t node_number,
return MMDB_SUCCESS;
}
LOCAL uint32_t data_section_offset_for_record(MMDB_s *const mmdb,
LOCAL uint32_t data_section_offset_for_record(const MMDB_s *const mmdb,
uint64_t record)
{
return (uint32_t)record - mmdb->metadata.node_count -
@ -1192,7 +1228,7 @@ int MMDB_aget_value(MMDB_entry_s *const start,
MMDB_entry_data_s *const entry_data,
const char *const *const path)
{
MMDB_s *mmdb = start->mmdb;
const MMDB_s *const mmdb = start->mmdb;
uint32_t offset = start->offset;
memset(entry_data, 0, sizeof(MMDB_entry_data_s));
@ -1245,7 +1281,8 @@ int MMDB_aget_value(MMDB_entry_s *const start,
return MMDB_SUCCESS;
}
LOCAL int lookup_path_in_array(const char *path_elem, MMDB_s *mmdb,
LOCAL int lookup_path_in_array(const char *path_elem,
const MMDB_s *const mmdb,
MMDB_entry_data_s *entry_data)
{
uint32_t size = entry_data->data_size;
@ -1254,12 +1291,20 @@ LOCAL int lookup_path_in_array(const char *path_elem, MMDB_s *mmdb,
int saved_errno = errno;
errno = 0;
int array_index = strtol(path_elem, &first_invalid, 10);
if (array_index < 0 || ERANGE == errno) {
if (ERANGE == errno) {
errno = saved_errno;
return MMDB_INVALID_LOOKUP_PATH_ERROR;
}
errno = saved_errno;
if (array_index < 0) {
array_index += size;
if (array_index < 0) {
return MMDB_LOOKUP_PATH_DOES_NOT_MATCH_DATA_ERROR;
}
}
if (*first_invalid || (uint32_t)array_index >= size) {
return MMDB_LOOKUP_PATH_DOES_NOT_MATCH_DATA_ERROR;
}
@ -1281,7 +1326,8 @@ LOCAL int lookup_path_in_array(const char *path_elem, MMDB_s *mmdb,
return MMDB_SUCCESS;
}
LOCAL int lookup_path_in_map(const char *path_elem, MMDB_s *mmdb,
LOCAL int lookup_path_in_map(const char *path_elem,
const MMDB_s *const mmdb,
MMDB_entry_data_s *entry_data)
{
uint32_t size = entry_data->data_size;
@ -1322,7 +1368,8 @@ LOCAL int lookup_path_in_map(const char *path_elem, MMDB_s *mmdb,
return MMDB_LOOKUP_PATH_DOES_NOT_MATCH_DATA_ERROR;
}
LOCAL int skip_map_or_array(MMDB_s *mmdb, MMDB_entry_data_s *entry_data)
LOCAL int skip_map_or_array(const MMDB_s *const mmdb,
MMDB_entry_data_s *entry_data)
{
if (entry_data->type == MMDB_DATA_TYPE_MAP) {
uint32_t size = entry_data->data_size;
@ -1348,7 +1395,7 @@ LOCAL int skip_map_or_array(MMDB_s *mmdb, MMDB_entry_data_s *entry_data)
return MMDB_SUCCESS;
}
LOCAL int decode_one_follow(MMDB_s *mmdb, uint32_t offset,
LOCAL int decode_one_follow(const MMDB_s *const mmdb, uint32_t offset,
MMDB_entry_data_s *entry_data)
{
CHECKED_DECODE_ONE(mmdb, offset, entry_data);
@ -1378,7 +1425,7 @@ LOCAL int decode_one_follow(MMDB_s *mmdb, uint32_t offset,
}
#if !MMDB_UINT128_IS_BYTE_ARRAY
NO_PROTO mmdb_uint128_t get_uint128(const uint8_t *p, int length)
LOCAL mmdb_uint128_t get_uint128(const uint8_t *p, int length)
{
mmdb_uint128_t value = 0;
while (length-- > 0) {
@ -1389,7 +1436,7 @@ NO_PROTO mmdb_uint128_t get_uint128(const uint8_t *p, int length)
}
#endif
LOCAL int decode_one(MMDB_s *mmdb, uint32_t offset,
LOCAL int decode_one(const MMDB_s *const mmdb, uint32_t offset,
MMDB_entry_data_s *entry_data)
{
const uint8_t *mem = mmdb->data_section;
@ -1619,7 +1666,7 @@ LOCAL uint32_t get_ptr_from(uint8_t ctrl, uint8_t const *const ptr,
}
int MMDB_get_metadata_as_entry_data_list(
MMDB_s *const mmdb, MMDB_entry_data_list_s **const entry_data_list)
const MMDB_s *const mmdb, MMDB_entry_data_list_s **const entry_data_list)
{
MMDB_s metadata_db = make_fake_metadata_db(mmdb);
@ -1634,15 +1681,33 @@ int MMDB_get_metadata_as_entry_data_list(
int MMDB_get_entry_data_list(
MMDB_entry_s *start, MMDB_entry_data_list_s **const entry_data_list)
{
*entry_data_list = new_entry_data_list();
if (NULL == *entry_data_list) {
MMDB_data_pool_s *const pool = data_pool_new(MMDB_POOL_INIT_SIZE);
if (!pool) {
return MMDB_OUT_OF_MEMORY_ERROR;
}
return get_entry_data_list(start->mmdb, start->offset, *entry_data_list, 0);
MMDB_entry_data_list_s *const list = data_pool_alloc(pool);
if (!list) {
data_pool_destroy(pool);
return MMDB_OUT_OF_MEMORY_ERROR;
}
int const status = get_entry_data_list(start->mmdb, start->offset, list,
pool, 0);
*entry_data_list = data_pool_to_list(pool);
if (!*entry_data_list) {
data_pool_destroy(pool);
return MMDB_OUT_OF_MEMORY_ERROR;
}
return status;
}
LOCAL int get_entry_data_list(MMDB_s *mmdb, uint32_t offset,
LOCAL int get_entry_data_list(const MMDB_s *const mmdb,
uint32_t offset,
MMDB_entry_data_list_s *const entry_data_list,
MMDB_data_pool_s *const pool,
int depth)
{
if (depth >= MAXIMUM_DATA_STRUCTURE_DEPTH) {
@ -1672,7 +1737,7 @@ LOCAL int get_entry_data_list(MMDB_s *mmdb, uint32_t offset,
int status =
get_entry_data_list(mmdb, last_offset, entry_data_list,
depth);
pool, depth);
if (MMDB_SUCCESS != status) {
DEBUG_MSG("get_entry_data_list on pointer failed.");
return status;
@ -1685,26 +1750,22 @@ LOCAL int get_entry_data_list(MMDB_s *mmdb, uint32_t offset,
{
uint32_t array_size = entry_data_list->entry_data.data_size;
uint32_t array_offset = entry_data_list->entry_data.offset_to_next;
MMDB_entry_data_list_s *previous = entry_data_list;
while (array_size-- > 0) {
MMDB_entry_data_list_s *entry_data_list_to = previous->next =
new_entry_data_list();
if (NULL == entry_data_list_to) {
MMDB_entry_data_list_s *entry_data_list_to =
data_pool_alloc(pool);
if (!entry_data_list_to) {
return MMDB_OUT_OF_MEMORY_ERROR;
}
int status =
get_entry_data_list(mmdb, array_offset, entry_data_list_to,
depth);
pool, depth);
if (MMDB_SUCCESS != status) {
DEBUG_MSG("get_entry_data_list on array element failed.");
return status;
}
array_offset = entry_data_list_to->entry_data.offset_to_next;
while (previous->next) {
previous = previous->next;
}
}
entry_data_list->entry_data.offset_to_next = array_offset;
@ -1715,45 +1776,33 @@ LOCAL int get_entry_data_list(MMDB_s *mmdb, uint32_t offset,
uint32_t size = entry_data_list->entry_data.data_size;
offset = entry_data_list->entry_data.offset_to_next;
MMDB_entry_data_list_s *previous = entry_data_list;
while (size-- > 0) {
MMDB_entry_data_list_s *entry_data_list_to = previous->next =
new_entry_data_list();
if (NULL == entry_data_list_to) {
MMDB_entry_data_list_s *list_key = data_pool_alloc(pool);
if (!list_key) {
return MMDB_OUT_OF_MEMORY_ERROR;
}
int status =
get_entry_data_list(mmdb, offset, entry_data_list_to,
depth);
get_entry_data_list(mmdb, offset, list_key, pool, depth);
if (MMDB_SUCCESS != status) {
DEBUG_MSG("get_entry_data_list on map key failed.");
return status;
}
while (previous->next) {
previous = previous->next;
}
offset = list_key->entry_data.offset_to_next;
offset = entry_data_list_to->entry_data.offset_to_next;
entry_data_list_to = previous->next =
new_entry_data_list();
if (NULL == entry_data_list_to) {
MMDB_entry_data_list_s *list_value = data_pool_alloc(pool);
if (!list_value) {
return MMDB_OUT_OF_MEMORY_ERROR;
}
status = get_entry_data_list(mmdb, offset, entry_data_list_to,
status = get_entry_data_list(mmdb, offset, list_value, pool,
depth);
if (MMDB_SUCCESS != status) {
DEBUG_MSG("get_entry_data_list on map element failed.");
return status;
}
while (previous->next) {
previous = previous->next;
}
offset = entry_data_list_to->entry_data.offset_to_next;
offset = list_value->entry_data.offset_to_next;
}
entry_data_list->entry_data.offset_to_next = offset;
}
@ -1832,22 +1881,12 @@ LOCAL int32_t get_sintX(const uint8_t *p, int length)
return (int32_t)get_uintX(p, length);
}
LOCAL MMDB_entry_data_list_s *new_entry_data_list(void)
{
/* We need calloc here in order to ensure that the ->next pointer in the
* struct doesn't point to some random address. */
return calloc(1, sizeof(MMDB_entry_data_list_s));
}
void MMDB_free_entry_data_list(MMDB_entry_data_list_s *const entry_data_list)
{
if (entry_data_list == NULL) {
return;
}
if (entry_data_list->next) {
MMDB_free_entry_data_list(entry_data_list->next);
}
free(entry_data_list);
data_pool_destroy(entry_data_list->pool);
}
void MMDB_close(MMDB_s *const mmdb)
@ -1885,7 +1924,7 @@ LOCAL void free_mmdb_struct(MMDB_s *const mmdb)
LOCAL void free_languages_metadata(MMDB_s *mmdb)
{
if (!mmdb->metadata.languages.count) {
if (!mmdb->metadata.languages.names) {
return;
}