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_tablenum_tablesType table
Sequence
[u4] ofs_table_desc
[u4] ofs_hash_table
Instance table_desc
[table_description]
ofs_table_descInstance hash_table
[hash_table]
ofs_hash_tableType table_description
Sequence
[u4] num_columns
[text] table_name
[u4] ofs_columns
Instance columns
[column_description]
ofs_columnsnum_columnsType 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_bucketstable_sizeType hash_bucket
Sequence
[u4] ofs_data
Instance data
ofs_data != 0xffffffff[list_rows]
ofs_dataType list_rows
Sequence
[u4] ofs_row_data
[u4] ofs_next_data
Instance row_data
[row_data]
ofs_row_dataInstance next_data
ofs_next_data != 0xffffffff[list_rows]
ofs_next_dataType row_data
Sequence
[u4] num_data
[u4] ofs_data_array
Instance data_array
[variant_data]
ofs_data_arraynum_dataType variant_data
Sequence
[u4:variant_type] data_type
[switch-on:data_type] data
Type Cases variant_type::null null_datavariant_type::i32 s4variant_type::u32 u4variant_type::real f4variant_type::nvarchar textvariant_type::bool common::boolvariant_type::i64 i64variant_type::u64 u64variant_type::text text
Type null_data
Sequence
[0, 0, 0, 0]null_data
Type i64
Sequence
[u4] ofs_i64
Instance i64
[s8]
ofs_i64Type u64
Sequence
[u4] ofs_u64
Instance u64
[u8]
ofs_u64Type text
Sequence
[u4] ofs_text
Instance text
[strz]
ofs_textasciiEnum 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"