Database (.fdb)
You can use the tools collection from assembly to work with FDB files.
Note
There is a converter from fdb to sqlite available, see the Tools section. This file type has no relation to firebird database files of the same extension.
Note
- It seems like:
Tables are sorted by their name in ascii representation. Uppercase letters then underscore then lowercase letters.
Tables themselves are hash maps. Use id % row_count to get the appropriate row_info, then follow the linked_row_info until all entries with that ID are found.
When the primary key is a string, a dedicated hash function is used to determin the index of the row_info slot.
Strings are stored spearately for each row, even if they have the same content. This makes for a great amount of redundancy in the file, but keeps editing simple.
Note
- id:
fdb
- file-extension:
fdb
- endian:
le
- imports:
../common/common
Sequence
[u4] num_tables
[u4] ofs_table
Instance tables
[table]
ofs_table
num_tables
Type table
Sequence
[u4] ofs_table_desc
[u4] ofs_hash_table
Instance table_desc
[table_description]
ofs_table_desc
Instance hash_table
[hash_table]
ofs_hash_table
Type table_description
Sequence
[u4] num_columns
[text] table_name
[u4] ofs_columns
Instance columns
[column_description]
ofs_columns
num_columns
Type column_description
Sequence
[u4:variant_type] data_type
[text] column_name
Type hash_table
Sequence
[u4] table_size
[u4] ofs_buckets
Instance buckets
[hash_bucket]
ofs_buckets
table_size
Type hash_bucket
Sequence
[u4] ofs_data
Instance data
ofs_data != 0xffffffff
[list_rows]
ofs_data
Type list_rows
Sequence
[u4] ofs_row_data
[u4] ofs_next_data
Instance row_data
[row_data]
ofs_row_data
Instance next_data
ofs_next_data != 0xffffffff
[list_rows]
ofs_next_data
Type row_data
Sequence
[u4] num_data
[u4] ofs_data_array
Instance data_array
[variant_data]
ofs_data_array
num_data
Type variant_data
Sequence
[u4:variant_type] data_type
[switch-on:data_type] data
Type Cases variant_type::null null_data
variant_type::i32 s4
variant_type::u32 u4
variant_type::real f4
variant_type::nvarchar text
variant_type::bool common::bool
variant_type::i64 i64
variant_type::u64 u64
variant_type::text text
Type null_data
Sequence
[0, 0, 0, 0]
null_data
Type i64
Sequence
[u4] ofs_i64
Instance i64
[s8]
ofs_i64
Type u64
Sequence
[u4] ofs_u64
Instance u64
[u8]
ofs_u64
Type text
Sequence
[u4] ofs_text
Instance text
[strz]
ofs_text
ascii
Enum variant_type
- 0:
null
- 1:
i32
- 2:
u32
- 3:
real
- 4:
nvarchar
- 5:
bool
- 6:
i64
- 7:
u64
- 8:
text
Note
Address pointers can be -1 which most likely means an invalid address (just skip those)
Strings types (TEXT and VARCHAR) are always null-terminated (with some over allocated bytes afterwards it seems, apparently string length are filled to be modulo 4 = 0?)
Strings and int64 (BIGINT) types are always stored with an additional address pointer, like this: [pointer]->[data]
SQLite Conversion
lcdr’s tools rely on https://www.sqlite.org/datatype3.html#determination_of_column_affinity to assign the type of columns in SQLite while preserving the original type:
SQLITE_TYPE = {}
SQLITE_TYPE[0] = "none"
SQLITE_TYPE[1] = "int32"
SQLITE_TYPE[3] = "real"
SQLITE_TYPE[4] = "text_4"
SQLITE_TYPE[5] = "int_bool"
SQLITE_TYPE[6] = "int64"
SQLITE_TYPE[8] = "text_8"