From c1db56c369a0efcf106f4cd7d39a675091e26b40 Mon Sep 17 00:00:00 2001 From: Alice39s Date: Sat, 27 Jun 2026 23:51:07 +0900 Subject: [PATCH] feat(erlang): add xdb header parser helper module --- binding/erlang/src/ip2region_xdb.erl | 57 ++++++++++++++++++++++ binding/erlang/test/ip2region_xdb_test.erl | 16 ++++++ 2 files changed, 73 insertions(+) create mode 100644 binding/erlang/src/ip2region_xdb.erl create mode 100644 binding/erlang/test/ip2region_xdb_test.erl diff --git a/binding/erlang/src/ip2region_xdb.erl b/binding/erlang/src/ip2region_xdb.erl new file mode 100644 index 0000000..fc0f14e --- /dev/null +++ b/binding/erlang/src/ip2region_xdb.erl @@ -0,0 +1,57 @@ +%%%------------------------------------------------------------------- +%% Copyright 2022 The Ip2Region Authors. All rights reserved. +%% Use of this source code is governed by a Apache2.0-style +%% license that can be found in the LICENSE file. +%% +%% @doc +%% ip2region xdb binary format helpers. +%% @end +%%%------------------------------------------------------------------- +-module(ip2region_xdb). + +-export([parse_header/1]). +-export([header_version/1, header_index_policy/1, header_created_at/1, + header_start_index_ptr/1, header_end_index_ptr/1, + header_ip_version/1, header_runtime_ptr_bytes/1]). +-export([segment_index_size/1]). + +-include("ip2region.hrl"). + +-record(xdb_header, { + version :: non_neg_integer(), + index_policy :: non_neg_integer(), + created_at :: non_neg_integer(), + start_index_ptr :: non_neg_integer(), + end_index_ptr :: non_neg_integer(), + ip_version :: non_neg_integer(), + runtime_ptr_bytes :: non_neg_integer() +}). + +-spec parse_header(binary()) -> {ok, #xdb_header{}} | {error, invalid_header}. +parse_header(Bin) when is_binary(Bin), byte_size(Bin) >= 20 -> + <> = Bin, + {ok, #xdb_header{ + version = Version, + index_policy = IndexPolicy, + created_at = CreatedAt, + start_index_ptr = StartIndexPtr, + end_index_ptr = EndIndexPtr, + ip_version = IpVersion, + runtime_ptr_bytes = RuntimePtrBytes + }}; +parse_header(_) -> + {error, invalid_header}. + +header_version(#xdb_header{version = V}) -> V. +header_index_policy(#xdb_header{index_policy = P}) -> P. +header_created_at(#xdb_header{created_at = T}) -> T. +header_start_index_ptr(#xdb_header{start_index_ptr = P}) -> P. +header_end_index_ptr(#xdb_header{end_index_ptr = P}) -> P. +header_ip_version(#xdb_header{ip_version = V}) -> V. +header_runtime_ptr_bytes(#xdb_header{runtime_ptr_bytes = B}) -> B. + +-spec segment_index_size(ipv4 | ipv6) -> pos_integer(). +segment_index_size(ipv4) -> ?XDB_SEGMENT_INDEX_SIZE_V4; +segment_index_size(ipv6) -> ?XDB_SEGMENT_INDEX_SIZE_V6. diff --git a/binding/erlang/test/ip2region_xdb_test.erl b/binding/erlang/test/ip2region_xdb_test.erl new file mode 100644 index 0000000..1ce5a70 --- /dev/null +++ b/binding/erlang/test/ip2region_xdb_test.erl @@ -0,0 +1,16 @@ +-module(ip2region_xdb_test). +-include_lib("eunit/include/eunit.hrl"). + +header_parse_test() -> + HeaderBin = <<3:16/little, 1:16/little, 123456:32/little, + 1000:32/little, 2000:32/little, 6:16/little, 4:16/little, + 0:((256-20)*8)>>, + {ok, Header} = ip2region_xdb:parse_header(HeaderBin), + ?assertEqual(3, ip2region_xdb:header_version(Header)), + ?assertEqual(6, ip2region_xdb:header_ip_version(Header)), + ?assertEqual(1000, ip2region_xdb:header_start_index_ptr(Header)), + ?assertEqual(2000, ip2region_xdb:header_end_index_ptr(Header)). + +version_constants_test() -> + ?assertEqual(14, ip2region_xdb:segment_index_size(ipv4)), + ?assertEqual(38, ip2region_xdb:segment_index_size(ipv6)).