Databases (.DBF) - Memo files (.DBT) - Index files (.NTX) - Mem files (.MEM)
number is intended for C/C++ programs. They start
(for instance char cText) with zero, the position starts
(for instance for Clipper substring after lowlevel access) with 1.
Type B = byte
Type W = word, 2 bytes, high value byte last
Type DW = doubleword, 4 bytes, sequence: lowest to highest byte
1.1. Header (32 bytes):
|Year||1||2||1||B||Year of last change, only two digits!|
|Month||2||3||1||B||Month of last change|
|Day||3||4||1||B||Day of last change|
|Start||8||9||2||W||Address of start of data
(addresses start at 0!)
|RecLength||10||11||2||W||Record length (incl. 1 byte, "deleted flag")|
|12||13||20||B||Reserved, unimportant, always 00H?|
1.2. Field entries (32 bytes), one entry per existing field:
|Fieldname||0||1||11||B||Field name, ends with 00H,
maybe trailed by some smut
|Fieldposition||12||13||4||DW||Field position in record,
unused by Clipper
but probably used by Foxpro
|Fielddec||17||18||1||B||Number of digits after decimal point|
for field type 'C' Fieldlength and Fielddec together as
type 'W' as field length for fields bigger than 255 chars.
Effective length: Fielddec * 256 + Fieldlength
|18||19||14||Byte||Unused by Clipper|
1.3. End of header:
Clipper: two bytes: ASCII 13 = 0DH and ASCII 0 = 00H
byte: ASCII 13 = 0DH, Visual Foxpro sometimes reserves
263 additional bytes between header and data,
but they are always included in field "Start" (DW byte 8 and 9).
If those bytes exist the name of the DBC file follows to which this DBF belongs.
The first byte
contains always a blank (" ", ASCII 32, 020H)
for undeleted records or an asterisk ("*", ASCII 42, 02AH) for deleted ones.
This byte is always included in the Fieldlength word (Byte 10 and 11)!
The field contents follow. There is no separation character between the fields!
Character, right padded with spaces if necessary
Date, always 8 bytes, saved as YYYYMMDD
Logical, 1 byte, saved as "T" or "F"
Memo, 10 byte pointer to the first 512 byte block in the DBT file
Numerical, saved with decimal point!
1.5. End of
data: one byte, CTRL-Z = ASCII 26 = 1AH.
Remark This byte may or may not be there!
1.6. Programming example in Clipper
1.7. Programming example in C
2. Structure of Clipper memo files (.DBT):
2.1. Header (512 bytes):
|Countl||0||1||4||DW||Next new block number =
of used 512 byte blocks
(last block may be only partially filled,
therefore the file size may not be a multiple of 512!)
|4||5||508||Bytes||don't mind, reserved, may contain smut|
You get the address
of the data for a certain record in the DBF file by multiplying
the above mentioned
10 byte pointer by 512. There you'll find the data. They're valid up to (but excluding) the first
CTRL-Z (ASCII 26 = 01AH).
Maximum size data for one record = 64 KB = 128 blocks with 512 bytes each!
Maximum size DBT file = 32 MB!
Remark: If the memofield of a record is empty there will be reserved 512 bytes anyway!
Remark: If the memofield gets bigger beyond the end of the block the data will be copied to the end of the DBT file (if it's not already the last block). The old blocks won't be used anymore. This space is lost until you do a PACK or a COPY.
Of course you regain the space too with a ZAP <vbg>.
3. Structure of Clipper index files (.NTX):
index files use a modified B+ tree algorithm.
Usually only the leafs have key values.
With Clipper the root and the nodes also have key values.
An NTX file
has exactly one header block and contains data in at least one
and at max three levels
depending on the following number: record count times (keylength + 8).
All data will be saved in blocks of 1024 bytes.
There is exactly one header block and exactly one block for level 1.
Blocks for level 2 and 3 exist only when needed. Then there may be lots of them.
3.1. Header (1024 bytes):
|Version||2||3||2||W||Some people say that
this field contains
the Clipper version. That can't be because
I found at least 20 different values in my
databases (all Clipper 5.2e).
|FirstPage||4||5||4||DW||Address of page level 1|
|FreePage||8||9||4||DW||Start of chain of free
if there are any otherwise zero
|Entrylength||12||13||2||W||Length of entry = key
length + 8
(4 bytes address next indexblock + 4 bytes
recordnumber in DBF file, see below)
|Keylength||14||15||2||W||Length of key not of key expression!|
|Decimaldigits||16||17||2||W||Decimal digits if there are any in the index|
|MaxEntries||18||19||2||W||Maximum number of index entries per index page|
|MinEntries||20||21||2||W||Minimum number of index
entries per index page,
needed to balance the index tree
|Key||22||23||257||B||keyexpression delimited with 00H, after that smut|
|Unique||279||280||1||B||Unique index = 01H, 00H otherwise|
|4||5||744||B||Unimportant, reserved, may contain smut|
3.2. Level 1-3 (1024 bytes):
|Count||0||1||2||W||Count of valid entries
Important: if the level is not the lowest one used
you have to add 1. Why? Because!
|Entrypointer||2||3||2||W||n * entrypointer, n =
MaxEntries (see last table)
Remark: maybe a lot of these entries contain data,
only the first n are valid!
The pointer is meant to be inside this block only!
indexentries, n = MaxEntries (see 3.1.)
structure indexentry (see 3.3.)
Remark: maybe a lot of these entries contain data,
only those are valid that are pointed to by a pointer!
3.3. Indexentry (8 bytes + keylength):
|Address||0||1||4||DW||Address = 0 if lowest
otherwise the address of the block of the next level
|Recordnumber||4||5||4||DW||If # 0 you'll find the
record with the key (next field)
in the DBF file under this recordnumber
|Key||8||9||Key with length (3.1.) without 00H!|
The key of
an index entry (if not lowest level!) is truly greater than all
of the subordinate block whose address is in the same indexentry.
index entry of level 1 has an empty key, 00H.
In the according subordinate block are the keys with the highest values!
3.4. Free blocks:
to theory free blocks (after deleting or so) will be chained and
The block number of the first free block is in the header (see 3.1.).
I personally never have seen that Clipper really has free blocks.
But maybe I'm packing my databases too frequently?!
3.5. Access to the data in the DBF file according to the record number found in the NTX file:
get the address of the record in the DBF file you may
compute like this:
3.6. Example for an index file (all values hexadecimal):
|Header||address 1. page: 00 00 0C 00
maximum entries per page: 4C
minimum entries: 26
|level 0||address: 00 00 0C 00
count: 03 (add 1 because it's not the lowest level!)
entry pointer 1: 00 BD
entry pointer 2: 00 9C
entry pointer 3: 00 B2
entry pointer 4: 00 A7
|level 1||address: 00 00 04 00
count: 26H(1 addieren!)
entry pointer 1: 00 F4
entry pointer 27H: 00 E9
|address: 00 00 10 00
count: 31H (1 addieren!)
entry pointer 1: 00 E9
entry pointer 32H: 01 A0
|level 2||address: 00 00 24 00
entry pointer 1: 00 C8
entry pointer 36H: 01 20
|...||address: 00 00 08 20
entry pointer 1: 00 D3
entry pointer 28H: 00 FF
|...||address: 00 00 06 24
entry pointer 1: 00 DE
entry pointer 38H: 02 33
4. Structure of Clipper mem files (.MEM):
and every variable that has been saved with "SAVE TO"
there is a header (4.1.), that's really similar to the field
entries of the DBF file (s. 1.2). Surprise, surprise!
After the header there are the data (variable length depending on the data type) as shown in (4.2.).
End of informations s. 4.3.
4.1. Header for variables:
|NameOfVariable||0||1||11||B||Name of variable
delimited with 00H,
probably followed by some smut
high bit is set here. So you have to subtract 128
from this value to get the type
|12||13||4||DW||don't care, reserved|
|LengthOfVariable||16||17||1||B||Length of variable|
|For type of
variable 'C' LengthOfVariable and DecOfVariable
will be taken as word for strings greater than 255 bytes.
Effectiv length: DecOfVariable * 256 + LengthOfVariable
|18||19||14||B||don't care, reserved, unused?|
4.2. Content of variables, data:
as many digits as stated in the length field, the
trailing byte 00H
always 8 bytes, saved as number of day in IEEE format,
not so easily readable,
Logical, 1 byte, 01H = .true., 00H = .false.
always 8 bytes, saved in IEEE format,
4.3. Last byte: CTRL-Z = ASCII 26 = 01AH
Program to dump a Mem file