M, F, G, O und F Felder sind BLOB's (Binary Large Objects) und haben eine Variable Länge. Sie besitzen einen 10 Byte Header, der die Länge und Position des BLOB enthält und eine Modification Number, die intern von Paradox benutzt wird.
BLOB Felder werden im *.MB File gespeichert, wobei die ersten Bytes, deren Länge beim Erzeugen der Tabelle definiert werden, in der *.DB Tabelle gespiegelt werden. Wenn die Größe des BLOB kleiner als die definierte Länge in der *.DB Tabelle ist, dann werden die Daten nicht in der *.MB Tabelle gespeichert.
Header Format: LongInt für Offset
LongInt für Länge des BLOB
Word für Modification Number
Das Datum wird als Long Integer gespeichert. Es enthält die Anzahl der Tage seit dem 1.1.0001. Das Kleinste gültige Datum ist der 1.1.0100 (36160 = $0008D40). Beispiel: 4.5.1996 = 728783 = $000B1ECF. Paradox akzeptiert Daten zwischen 1.1.0100 und 31.12.9999.
Generelle Struktur
Organisation
First, Last und Free Blocks sind Integer Werte und stehen am Anfang von jedem Block. Der erste Block nach dem Header hat die Nummer 1. Alle Blocks haben die gleiche Länge. Siehe MaxTableSize. BlockOffset = BlockLength * ( BolckNumber - 1) + TableHeaderLength. Block 1 darf nie ein freier Block sein.
Die Größe eines Paradox File Headers ist immer 2048 Bytes. Der erste Teil (Offset $0000 bis $0077) hat eine Feste Länge. Der Rest hat eine Variable Länge, die von der Anzahl der Felder anhängt.
Einige der Informationen aus dem File Header scheinen nur benötigt zu werden, wenn Paradox im RAM läuft. Einige von diesen Feldern sind Pointer auf andere Felder im Header und sind nur zur Laufzeit gültig.
Die Datenblöcke sind in Records unterteilt. Die Größe eines Record wird bei der Erzeugung einer Tabelle definiert.
Die Darstellung der Zahlen im Header erfolgt im Little Endian Format (Low-Byte .. High-Byte).
Die Darstellung der Zahlen im Data Block erfolgt im Big Endian Format (High-Byte .. Low-Byte).
Common Header $0000..$0057 |
||
| Offset | Typ | Bedeutung |
| 0000 | Integer | RecordSize
Größe des Records in Bytes. |
| 0002 | Integer | HeaderSize (always $0800) |
Die HeaderSize kann geändert werden um kleinere oder größere Header zu erzeugen. Borland's TUTULITY Programm gibt jedoch dann eine Fehlermeldung aus. Paradox, die BDE und die Paradox Engine arbeiten jedoch kommentarlos mit dieser Änderung. |
| 0004 | Byte | FileType
00 = Ein Index Daten File: *.DB |
| 0005 | Byte | MaxTableSize
Dies ist die Größe eines Daten-Blocks. Wird angelegt, wenn die
Tabelle erzeugt wird. |
| 0006 | LongInt | NumRecords
Anzahl der Records in diesem File. |
| 000A | Word | UsedBlocks
Anzahl der benutzten Blöcke. |
| 000C | Word | FileBlocks
Anzahl der Daten Blocks in diesem File. (Jeder Block ist ein Zusammenschluß von Records) |
| 000E | Word | FirstBlock
Immer 1, es sei denn die Tabelle ist leer. |
| 0010 | Word | LastBlock
Nummer des letzten belegten Blockes in der Tabelle. |
| 0012 | Word | Unbekannt |
| 0014 | Byte | ModifiedFlags1
Ein Rebuild der Tabelle ist erforderlich, wenn der Wert ungleich 0 ist. |
| 0015 | Byte | IndexFieldNumber
In einem *.Xnn File eines Sekundär-Index, ist dies die Anzahl der Felder, die referenziert werden. In allen anderen Files ist dieser Wert 0. |
| 0016 | Pointer | PrimaryIndexWorkspace
Immer NIL bei DB Tabellen. |
| 001A | Pointer | Unbekannt (Suspected Pointer)
Dieses Feld ist normalerweise ein NIL Pointer. Eine Änderung wurde beim Feldtyp BCD, in einer 5.0 Tabelle beobachtet. Wahrscheinlich ist es nur ein Arbeits Pointer. |
| 001E
0020 |
Unbekannt
Die Benutzung dieser Bytes wurde bisher nur in einem *.PX File beobachtet. |
|
| 0021 | Integer | NumFields
Anzahl der Felder in dieser Tabelle. |
| 0023 | Integer | PrimaryKeyFields
Anzahl der Felder, die einen Primär-Schlüssel haben. |
| 0025 | LongInt | Encryption1
Position der Verschlüsselungs Information bei Paradox 3.0 und 3.5 (Hier steht $00000000, wenn keine Verschlüsselung vorliegt). Die Folge-Versionen speichern hier immer $FF00FF00 und den Verschlüsselungs-Code ab Offset $005C. Primär- und Sekundär Index Files speichern ihre Schlüssel auch an dieser Stelle, sie enthalten jedoch häufig 0en, weil Die Paradox Engine und die BDE überhaupt keine Index Dateien verschlüsseln. Eine Verschlüsselung kann aber durch kopieren dieser Felder in die Index Dateien trotzdem durchgeführt werden. |
| 0029 | Byte | SortOrder
$00: ASCII |
| 002A | Byte | ModifiedFlags2
Ein Rebuild der Tabelle ist erforderlich, wenn der Wert ungleich 0 ist. |
| 002B | Word | Unbekannt (immer 0) |
| 002D | Byte | ChangeCount1
Wird bei jedem File Header upgedate inkrementiert. |
| 002E | Byte | ChangeCount2
Es ist noch nicht klar, wenn dieses Feld inkrementiert wird. |
| 002F | Byte | Unbekannt |
| 0030 | ^pChar | TableNamePtr
Dies ist ein Pointer auf TableNamePtr, welcher ein Pointer auf TableName ist. Paradox benutzt dieses Feld, um einen schnelleren Zugriff auf TableName zu haben, weil auf diesen Teil der Tabelle sequentiell zugegriffen wird. Wird nur im RAM benutzt. |
| 0034 | Pointer | FldInfoPtr
Pointer auf die Liste der Feld ID's. Dieser Pointer kann benutzt werden, um den Tabellen-Header im RAM zur Laufzeit zu erreichen. Für Paradox Version > 4.0 muß $0078 subtrahiert werden, für kleinere Versionen und *.PX und *.Ynn Dateien $0058. |
| 0038 | Byte | WriteProtected
0 Schreibschutz Aus |
| 0039 | Byte | FileVersionID
$03 Version 3.0 |
| 003A | Word | MaxBlocks
Funktion ist unbekannt. Der Wert ist immer mit FileBlocks identisch (bei Offset $000C). |
| 003C | Byte | Unbekannt |
| 003D | Byte | AuxPasswords
Anzahl der Hilfs-Passworte für diese Tabelle. |
| 003E | Word | Unbekannt |
| 0040 | Pointer | CryptInfoStartPtr
Zeigt auf das CryptInfo Feld. Wenn keine Verschlüsselung durchgeführt wird, ist es immer NIL. Manchmal steht aber auch NIL drin, wenn die Tabelle verschlüsselt ist. |
| 0044 | Pointer | CryptInfoEndPtr
Zeigt auf das Ende von CryptInfo. Wenn keine Verschlüsselung durchgeführt wird, ist es immer NIL. |
| 0048 | Byte | Unbekannt |
| 0049 | LongInt | AutoInc
Dieses Feld speichert den Wert, der beim Auto-Increment- Feld-Typ "+" der Tabelle benutzt wird. |
| 004D | Word | FirstFreeBlock
Nummer des ersten freien Blocks |
| 004F | Byte | IndexUpdateRequired |
| 0050
0054 |
Unbekannt | |
| 0055 | Byte | RefIntegrity
Ein Wert von $2? bedeutet, das für diese Tabelle ein Integritäts Test durchgeführt werden sollte. |
| 0056 | Byte | Unbekannt |
| 0057 | Byte | Unbekannt |
Data File Header $0058..$0077 |
||
| Offset | Typ | Bedeutung |
| 0058 | Integer | Unbekannt (File Version ID?)
$0105..$0109 Version 4.x (meistens = $0109) |
| 005A | Integer | Unbekannt (File Version ID?)
Identisch mit $0058 |
| 005C | LongInt | Encryption2
Position der Verschlüsselungs Information bei Paradox 3.0 und 3.5 (Hier steht $00000000, wenn keine Verschlüsselung vorliegt). Die Folge-Versionen speichern hier immer $FF00FF00 und den Verschlüsselungs-Code ab Offset $005C. Primär- und Sekundär Index Files speichern ihre Schlüssel auch an dieser Stelle, sie enthalten jedoch häufig 0en, weil Die Paradox Engine und die BDE überhaupt keine Index Dateien verschlüsseln. Eine Verschlüsselung kann aber durch kopieren dieser Felder in die Index Dateien trotzdem durchgeführt werden. |
| 0060 | LongInt | FileUpdateTime (nur bei Version 4.x)
Das Format ist identisch mit dem vom Packed-Date-Time. |
| 0064 | Integer | HiFieldID
Diese Zahl ist immer NumFields + 1. |
| 0066 | Integer | HiFieldIDinfo?
Dieser Wert ist identisch mit HiFieldID, seine Funktion ist jedoch nicht bekannt. |
| 0068 | Integer | SometimesNumFields?
Hier steht meistens die Anzahl der Felder in der Tabelle, aber der Wert ist häufig 0. Warum ist nicht bekannt. |
| 006A | Integer | DosGlobalCodePage
Dies ist der Global Code Page Wert, der beim Erzeugen der Tabelle angelegt wird.
$01B5 United States Mehr Informationen sind im MS-DOS Technical Manual beim Interrupt $21, Funktion $66 zu finden. |
| 006C
006F |
Bytes | Unbekannt |
| 0070 | Integer | ChangeCount4 |
| 0072
0077 |
Bytes | Unbekannt |
| Offset | Bedeutung |
| 0058 | Paradox Tabellen Version 3.0 und 3.5 |
| 0058 | Paradox .PX und .Ynn Index Files (alle Versionen) |
| 0078 | Paradox Tabellen Version 4.0 und höher |
| 0078 | Paradox .Xnn Index Files Version 4.0 und höher |
Dies sind Sprungziele von Pointern, deshalb gibt es keinen fest spezifizierten Offset.
Common File Header |
||
| Offset | Typ | Bedeutung |
| ---- | Array | FieldInfo
type TFldInfoRec = RECORD Array[1..(NumFields)] of TFldInfoRec FieldInfo Dies sind die Feld ID's für jedes Feld in der Tabelle:
fType fSize(decimal) |
| ---- | pChar | TableNamePtr
Pointer auf die Tebellennamen, wenn der Header im RAM ist. |
| ---- | Array | FieldNamePtrArray
Array[1..(NumFields)] of pChar Dies ist ein Feld auf die Pointer, welche die Feld Namen enthalten wenn Paradox oder die BDE läuft. |
| ---- | Array | TableName
Array[1..79] of Char Dies ist der Name des Files, wenn es erzeugt wurde. Der Name ist 79 Bytes lang, aufgefüllt mit 0en. Häufig steht hier der Name RESTTEMP.DB. |
| ---- | Char[] | FieldNames
Hier stehen die Feldanamen als ASCII Sequenz. 0 terminiert. |
| ---- | Record | CryptInfo
Für verschlüsselte Tabellen stehen hier zusätzliche Informationen. Tabellen mit Hilfs-Passworten haben hier 256 Bytes zur Verfügung. Über die Bedeutung gibt es keine Informationen. Verschlüsselte Tabellen ohne Hilfs-Passworte haben hier für jedes Feld 1 Byte zur Verfügung. |
| ---- | Array | FieldNumbers
Array[1..(NumFields)] of Integer Dies könnte eine Liste mit Feldnummern sein. Änderungen haben jedoch keine Wirkung. Sie scheinen nur während der Laufzeit im Speicher benutzt zu werden. |
| ---- | Char[] | SortOrderID
Ein ASCII String der die Sort Order für diese Tabelle enthält ("ascii", "intl", usw.). |
Byte 1 bis 6 sind von der BDE Reserviert. Danach folgt eine Anzahl von Datenrecords. Die Anzahl ist von der Größe eines Records abhängig. Die Recordgröße kann aus den einzelnen Typenangaben jedes Tabelleneintrages berechnet werden. Da die Anzahl der Records nicht immer genau einen Block ausfüllen, befinden sich am Blockende eine unbestimmte Anzahl von Füllbytes.
| 0000 | Word | NextBlock
Nummer des nächsten logischen Blocks. Diese Serie von Pointer wird auch Verkettete Liste bezeichnet. Die BDE berechnet die physikalische Startadresse eines Blocks aus der Blocknummer multipliziert mit der Blockgröße okus der Größe des Headers. |
| 0002 | Word | LastBlock
Nummer des letzten Blocks. |
| 0004 | Integer | LastBlockPtr
Zeiger auf den Start des letzten Record in diesem Block. Ein Zähler für die Anzahl der aktiven Records in diesem Block. Dieses Feld enthält eine 0, wenn nur ein Record vohanden ist und eine negative Zahl (0 - RecordSize) wenn kein Record da ist. NumRecsInBlock = (LastBlockPtr / RecordSize) + 1 |
| 0006 | Record | 1. Record
Alpha Felder sind eine Folge von Zeichen, die mit 00 bis zur definierten Länge aufgefüllt sind. Alle anderen Felder werden im Big-Endian-Format angegeben. Bei positiven Zahlen ist immer das MSB gesetzt. Short Integer: 1 = $80 $01, 512 = $82 $00 Real Zahlen werden immer als 8-Byte Double Typ gespeichert. Das MSB ist immer gesetzt. Datums Felder enthalten die Anzahl der Tage seit 00.01.0000. Das MSB ist immer gesetzt. |
| ---- | Record | n. Record |
| xxxx | Dummy
nn Bytes vom letzten Record bis zum Blockende. Anzahl Bytes sind sind immer kleiner als die Recordlänge. |
Das MB File wird benutzt, um größere binäre Daten (Binary Large Object = BLOB) zu speichern.
Die Organistion der Daten ist sehr unterschiedlich zum Format der DB und PX Tabelle. Die Blöcke sind nicht als verkettete Liste organisiert und sie besitzen eine unterschiedliche Länge. Der Header ist immer 4kB groß. Die folgenden Blöcke haben immer eine Länge von einem vielfachen von 4kB.
Jeder Block beginnt mit folgenden 3 Bytes:
| Offset | Typ | Bedeutung |
| 0000 | Byte | RecordType
00 - Header Block |
| 0001 | Word | NumChunks
Anzahl der 4kB Chunks in diesem Block |
| 0003 | Record | Records |
Der BLOB Header ist der erste Block im MB File. Er ist 4096 Bytes groß und enthält folgende Felder:
BLOB Header |
||
| Offset | Typ | Bedeutung |
| 0000 | Byte | RecordType
00 - Header Block |
| 0001 | Word | BlockSize
Blockgröße dividiert mit 4. 1 für den Header. |
| 0003 | Word | ModCount
Wird auf 1 gesetzt, wenn die Tabelle restruktiriert wird. Immer wenn beim BLOB ein update gemacht wird, wird dieses Feld um 1 erhöht. Warum, weiss keiner so genau. |
| 0005
000A |
Bytes | Unbekannt |
| 000B | Word | BaseSize
Basis Größe des Daten Blocks $1000 (Vermutung) |
| 000D | Word | SubSize
Größe des untergeordneten Daten Blocks $1000 (Vermutung) |
| 000F | Byte | Unbekannt |
| 0010 | Byte | SubChunkSize
Größe des untergeordneten Chunks $10 (Vermutung) |
| 0011 | Word | NumSubs
Anzahl der untergeordneten Chunks $0040 (Vermutung) |
| 0013 | Word | SubThreshold
Grenze zwischen großen und kleinen BLOB's $0800 |
Ein einzelner BLOB Block kann irgendwo im MB File liegen.
Die Block Länge ist das kleinste vielfache von 4 kB, welche größer oder gleich der Länge vom BLOB ist.
BLOB Block |
||
| Offset | Typ | Bedeutung |
| 0000 | Byte | RecordType
02 - Einzelner BLOB Block |
| 0001 | Word | BlobSizeDiv4
Blockgröße dividiert mit 4 |
| 0003 | LongInt | BlobSize
Größe des BLOB in Byte |
| 0007 | Word | ModNumber
Wird auf 1 gesetzt, wenn die Tabelle restrukturiert wird. Immer wenn beim BLOB ein update gemacht wird, wird dieses Feld um 1 erhöht. Warum, weiss keiner so genau. |
| 0009 | Blob | Data
Blob Daten |
Ein untergeordneter Block kann irgendwo im MB File liegen.
Bis zu 64 kurze BLOB's können in diesem Typ von Block liegen.
Ein untergeordneter Block ist 4kB Lang. Er hat einen 12 Bytes Header, gefolgt von einem Array von bis zu 64 5-Byte BLOB Pointern.
Ein DB Feld, welchen ein BLOB hat, enthält den Offset des Blocks und den Index auf den Pointer Array. Der Array Pointer zeigt dann auf die Daten.
Untergeordneter Block |
||||||||||||||
| Offset | Typ | Bedeutung | ||||||||||||
| 0000 | Byte | RecordType
03 - Untergeordneter Block |
||||||||||||
| 0001 | Word | BlobSizeDiv4
Blockgröße dividiert mit 4 |
||||||||||||
| 0003
000B |
Bytes | Unbekannt | ||||||||||||
| 000C | Word | Array1
|
||||||||||||
| 0011 | Word | Array2 | ||||||||||||
| 0016 | Word | Array.. | ||||||||||||
| 0147 | Word | Array64 | ||||||||||||
| 0150 | Blob | BlobData | ||||||||||||
Ein untergeordneter Block besteht aus 16 Byte Chunks. Der erste verfügbare Chunk beginnt beim Offset von $0150. Um den Offset zu bekommen muß das erste Bytes eines Pointer Eintrage mit 16 multipliziert werden. Das nächste Byte gibt die Anzahl der Chunks an. Das letzte Byte gibt die Anzahl der Bytes im letzten Chunk an.
Beispiel: 25 03 0F 00 07
Offset = $0250
Anzahl der Chunks = 3
Anzahl Bytes im letzten Chunk = 7
Datengröße = 2 * 16 + 7 = 39 Bytes
Modifikation Number = 15
Ein freier Block kann irgendwo im MB File liegen.
Die Blocklänge ist ein vielfaches von 4kB.
Wenn da meherer freie Blöcke sind, dann befindet sich die kombinierte Länge im ersten freien Block.
Freier Block |
||
| Offset | Typ | Bedeutung |
| 0000 | Byte | RecordType
04 - Freier Block |
| 0001 | Word | BlobSizeDiv4
Blockgröße dividiert mit 4 |
| 0003 | Bytes | Keine BLOB Daten |
Wenn ein BLOB vom Typ 03 gelöscht wird, dann wird er zu einem BLOB vom Typ 04. Wenn alle BLOB's in einem Block vom Typ 02 gelöscht wurden, dann wird der Block zu einem freien Block.
Wird eine BLOB upgedatet, dann wird er nie an der gleichen Stelle gespeichert.
Generelle Struktur
Organisation
First, Last und Free Blocks sind Integer Werte und stehen am Anfang von jedem Block. Der erste Block nach dem Header hat die Nummer 1. Alle Blocks haben die gleiche Länge. Siehe MaxTableSize. BlockOffset = BlockLength * ( BolckNumber - 1) + TableHeaderLength. Block 1 darf nie eine freier Block sein.
Die Größe eines Paradox File Headers ist immer 2048 Bytes. Der erste Teil (Offset $0000 bis $0077) hat eine Feste Länge. Der Rest hat eine Variable Länge, die von der Anzahl der Felder anhängt.
Einige der Informationen aus dem File Header scheinen nur benötigt zu werden, wenn Paradox im RAM läuft. Einige von diesen Feldern sind Pointer auf andere Felder im Header und sind nur zur Laufzeit gültig.
Die Datenblöcke sind in Records unterteilt. Die Größe eines Record wird bei der Erzeugung einer Tabelle definiert.
Die Darstellung der Zahlen im Header erfolgt im Little Endian Format (Low-Byte .. High-Byte).
Das *.PX File wird angelegt, sobald der erste Record in die *.DB Tabelle geschrieben wird.
Common Header $0000..$0057 |
||
| Offset | Typ | Bedeutung |
| 0000 | Integer | RecordSize
Größe des Records in Bytes. |
| 0002 | Integer | HeaderSize (always $0800) |
Die HeaderSize kann geändert werden um kleinere oder größere Header zu erzeugen. Borland's TUTULITY Programm gibt jedoch dann eine Fehlermeldung aus. Paradox, die BDE und die Paradox Engine arbeiten jedoch kommentarlos mit dieser Änderung. |
| 0004 | Byte | FileType
00 = Ein Index Daten File: *.DB |
| 0005 | Byte | MaxTableSize
Dies ist die Größe eines Daten-Blocks. Wird angelegt, wenn die
Tabelle erzeugt wird. |
| 0006 | LongInt | NumRecords
Anzahl der Records in diesem File. |
| 000A | Word | UsedBlocks
Anzahl der benutzten Blöcke. |
| 000C | Word | FileBlocks
Anzahl der Daten Blocks in diesem File. (Jeder Block ist ein Zusammenschluß von Records) |
| 000E | Word | FirstBlock
Immer 1, es sei denn die Tabelle ist leer. |
| 0010 | Word | LastBlock
Nummer des letzten belegten Blockes in der Tabelle. |
| 0012 | Word | Unbekannt |
| 0014 | Byte | ModifiedFlags1
Ein Rebuild der Tabelle ist erforderlich, wenn der Wert ungleich 0 ist. |
| 0015 | Byte | IndexFieldNumber
In einem *.Xnn File eines Sekundär-Index, ist dies die Anzahl der Felder, die referenziert werden. In allen anderen Files ist dieser Wert 0. |
| 0016 | Pointer | PrimaryIndexWorkspace
Pointer auf den Primär-Index File Header (im RAM). |
| 001A | Pointer | Unbekannt (Suspected Pointer)
Dieses Feld ist normalerweise ein NIL Pointer. Eine Änderung wurde beim Feldtyp BCD, in einer 5.0 Tabelle beobachtet. Wahrscheinlich ist es nur ein Arbeits Pointer. |
| 001E | Word | IndexBlockNumber
Block Nummer des Index Root. |
| 0021 | Integer | NumFields
Anzahl der Felder in dieser Tabelle. |
| 0023 | Integer | PrimaryKeyFields
Anzahl der Felder, die einen Primär-Schlüssel haben. |
| 0025 | LongInt | Encryption1
Position der Verschlüsselungs Information bei Paradox 3.0 und 3.5 (Hier steht $00000000, wenn keine Verschlüsselung vorliegt). Die Folge-Versionen speichern hier immer $FF00FF00 und den Verschlüsselungs-Code ab Offset $005C. Primär- und Sekundär Index Files speichern ihre Schlüssel auch an dieser Stelle, sie enthalten jedoch häufig 0en, weil Die Paradox Engine und die BDE überhaupt keine Index Dateien verschlüsseln. Eine Verschlüsselung kann aber durch kopieren dieser Felder in die Index Dateien trotzdem durchgeführt werden. |
| 0029 | Byte | SortOrder
$00: ASCII |
| 002A | Byte | ModifiedFlags2
Ein Rebuild der Tabelle ist erforderlich, wenn der Wert ungleich 0 ist. |
| 002B | Word | Unbekannt (immer 0) |
| 002D | Byte | ChangeCount1
Wird bei jedem File Header upgedate inkrementiert. |
| 002E | Byte | ChangeCount2
Es ist noch nicht klar, wenn dieses Feld inkrementiert wird. |
| 002F | Byte | Unbekannt |
| 0030 | ^pChar | TableNamePtr
Dies ist ein Pointer auf TableNamePtr, welcher ein Pointer auf TableName ist. Paradox benutzt dieses Feld, um einen schnelleren Zugriff auf TableName zu haben, weil auf diesen Teil der Tabelle sequentiell zugegriffen wird. Wird nur im RAM benutzt. |
| 0034 | Pointer | FldInfoPtr
Pointer auf die Liste der Feld ID's. Dieser Pointer kann benutzt werden, um den Tabellen-Header im RAM zur Laufzeit zu erreichen. Für Paradox Version > 4.0 muß $0078 subtrahiert werden, für kleinere Versionen und *.PX und *.Ynn Dateien $0058. |
| 0038 | Byte | WriteProtected
0 Schreibschutz Aus |
| 0039 | Byte | FileVersionID
$03 Version 3.0 |
| 003A | Word | MaxBlocks
Funktion ist unbekannt. Der Wert ist immer mit FileBlocks identisch (bei Offset $000C). |
| 003C | Byte | Unbekannt |
| 003D | Byte | AuxPasswords
Anzahl der Hilfs-Passworte für diese Tabelle. |
| 003E | Word | Unbekannt |
| 0040 | Pointer | CryptInfoStartPtr
Zeigt auf das CryptInfo Feld. Wenn keine Verschlüsselung durchgeführt wird, ist es immer NIL. Manchmal steht aber auch NIL drin, wenn die Tabelle verschlüsselt ist. |
| 0044 | Pointer | CryptInfoEndPtr
Zeigt auf das Ende von CryptInfo. Wenn keine Verschlüsselung durchgeführt wird, ist es immer NIL. |
| 0048 | Byte | Unbekannt |
| 0049 | LongInt | AutoInc
Dieses Feld speichert den Wert, der beim Auto-Increment- Feld-Typ "+" der Tabelle benutzt wird. |
| 004D | Word | Unbekannt |
| 004F | Byte | IndexUpdateRequired |
| 0050
0054 |
Unbekannt | |
| 0055 | Byte | RefIntegrity
Ein Wert von $2? bedeutet, das für diese Tabelle ein Integritäts Test durchgeführt werden sollte. |
| 0056 | Byte | Unbekannt |
| 0057 | Byte | Unbekannt |
Gilt nur für Paradox Versionen >= 4.0
Data File Header $0058..$0077 |
||
| Offset | Typ | Bedeutung |
| 0058 | Integer | Unbekannt (File Version ID?)
$0105..$0109 Version 4.x (meistens = $0109) |
| 005A | Integer | Unbekannt (File Version ID?)
Identisch mit $0058 |
| 005C | LongInt | Encryption2
Position der Verschlüsselungs Information bei Paradox 3.0 und 3.5 (Hier steht $00000000, wenn keine Verschlüsselung vorliegt). Die Folge-Versionen speichern hier immer $FF00FF00 und den Verschlüsselungs-Code ab Offset $005C. Primär- und Sekundär Index Files speichern ihre Schlüssel auch an dieser Stelle, sie enthalten jedoch häufig 0en, weil Die Paradox Engine und die BDE überhaupt keine Index Dateien verschlüsseln. Eine Verschlüsselung kann aber durch kopieren dieser Felder in die Index Dateien trotzdem durchgeführt werden. |
| 0060 | LongInt | FileUpdateTime (nur bei Version 4.x)
Das Format ist identisch mit dem vom Packed-Date-Time. |
| 0064 | Integer | HiFieldID
Diese Zahl ist immer NumFields + 1. |
| 0066 | Integer | HiFieldIDinfo?
Dieser Wert ist identisch mit HiFieldID, seine Funktion ist jedoch nicht bekannt. |
| 0068 | Integer | SometimesNumFields?
Hier steht meistens die Anzahl der Felder in der Tabelle, aber der Wert ist häufig 0. Warum ist nicht bekannt. |
| 006A | Integer | DosGlobalCodePage
Dies ist der Global Code Page Wert, der beim Erzeugen der Tabelle angelegt wird.
$01B5 United States Mehr Informationen sind im MS-DOS Technical Manual beim Interrupt $21, Funktion $66 zu finden. |
| 006C
006F |
Bytes | Unbekannt |
| 0070 | Integer | ChangeCount4 |
| 0072
0077 |
Bytes | Unbekannt |
Byte 1 bis 6 sind von der BDE Reserviert. Danach folgt eine Anzahl von Datenrecords. Die Anzahl ist von der Größe eines Records abhängig. Die Recordgröße kann aus den einzelnen Typenangaben jedes Tabelleneintrages berechnet werden. Da die Anzahl der Records nicht immer genau einen Block ausfüllen, befinden sich am Blockende eine unbestimmte Anzahl von Füllbytes.
Es sind nur die Felder enthalten, die mit einem Index markiert wurden.
| 0000 | Word | NextBlock
Nummer des nächsten logischen Blocks. Diese Serie von Pointer wird auch Verkettete Liste bezeichnet. Die BDE berechnet die physikalische Startadresse eines Blocks aus der Blocknummer multipliziert mit der Blockgröße okus der Größe des Headers. |
|||||||||||||||
| 0002 | Word | LastBlock
Nummer des letzten Blocks. |
|||||||||||||||
| 0004 | Integer | LastBlockPtr
Zeiger auf den Start des letzten Record in diesem Block. Ein Zähler für die Anzahl der aktiven Records in diesem Block. Dieses Feld enthält eine 0, wenn nur ein Record vohanden ist und eine negative Zahl (0 - RecordSize) wenn kein Record da ist. NumRecsInBlock = (LastBlockPtr / RecordSize) + 1 |
|||||||||||||||
| 0006 | Record | 1. Record
|
|||||||||||||||
| ---- | Record | 2. Record | |||||||||||||||
| ---- | Record | n.Record |
Die Index Blocks sind als Baumstruktur gespeichert.
Beispiel:
Wir haben 10000 Records.
Der Key ist ein Integer zwischen 1 und 10000.
1 Data Block enthält 10 Records.
1 Index Block enthält 10 Indexe. Es passen zwar wesentlich mehr rein,
aber das Beispiel wird dadurch einfacher.
Wenn der erste Daten Record eingefügt wird, wird die Index Tabelle angelegt. Der Index Record enthält die Blocknummer des ersten Data Blocks (Block 1 in DB) und den Key des des ersten Records in diesem Daten Block (Key = 1).
Wenn Record 2 bis 10 eingefügt wird, werden sie im ersten Datenblock der DB abgelegt. Es wird kein weiterer Index Record angelegt.
Wenn Record 11 eingefügt wird, wird eine neuer Daten Block erzeugt. Es wird ein Index Record erzeugt, der den Key des des ersten Records des neuen Blocks (Key = 11) und die Blocknummer des zweiten Datenblocks enthält. Die Index Tabelle enthält nun zwei Records.
Wenn Daten Record 101 eingefügt wird, dann ist keine Platz mehr in diesem Block, und es wird eine neuer angelegt. Die Index Tabelle enthält jetzt zwei Blocks.
Jetzt wird ein Index Block erzeugt, der über einen Index die ersten beiden Indexblocks verwaltet. Dieser Block wird als Level 2 Index bezeichnet. Die ersten beiden Blocks werden als Level 1 Index bezeichnet. Der Lever 2 Index enthält den ersten Key von jeder Level 1 Index Tabelle. Die Struktur sieht jetzt folgendermaßen aus:
Level 2 Index Level 1 Index
Key Keys im Block
1 -----------> 1, 11,21, 31, ..., 91
101 -----------> 101
Der Level 2 Record zeigt auf einen Block im Level 1 Index. Dieser Pointer ist die Blocknummer des Level 1 Index Blocks.
Wenn Record 1001 eingefügt wird, wird ein zweiter Level 2 Index Block erzeugt und ein Level 3 Index Block wird angelegt und die Level 2 Index Blocks zu verwalten.
Nachdem 10000 Record eingefügt wurden, besitzt die Struktur folgendes aussehen:
Um einen Record über den Index zu finden, startet man beim Root Level (Level 3) Index. Jetzt wird in jedem Index Level der Key gesucht, der kleiner oder gleich dem gesuchten Key ist. Die Blocknummer aus dem Level 1 Index zeigt dann auf die gesuchte Blocknummer im Data File.
Als Beispiel wird Record 185 gesucht:
Ein X** File enthält die Daten Records für einen Sekundären Index. Es gibt einen Record für jeden Record im DB File.
Ein X** file hat das gleiche logische Format wie ein DB File.
Ein X** Daten Record enthält das Sekundär Index Feld, gefolgt vom Primär Index Feld. Ein zusätzliche Typ S Feld mit der Bezeichnung 'Hint' ist das letzte Feld im Record. Alle Felder, außer 'Hint' sin im Record Key enthalten.
Beispiel:
Wenn der Daten Record den Key 'Custid' hat, und es wird ein Sekundärer Index 'Last Name' und 'First Name' definiert, dann enthält der X** Record vier Felder: [Custid], [Last Name], [First Name] und [Hint]. Die ersten drei Felder sind im Primär Index des X** Files.
[Hint] enthält die Block Nummer des Blocks aus dem DB File, welcher mit dem Index Record verbunden ist. Dies bedeutet, das der DB Record direkt angesprochen werden kann. Er braucht nicht über die Index Tabelle aus dem PX File adressiert werden.
[HINT] ist immer ein Feld vom Typ S definiert und wird von Paradox als ein Integer behandelt. Paradox weiß, das hier eine Block Nummer leigt.
Wenn mehr als 16 Sekundär Index Felder spezifiziert werden, dann werden nur die ersten 16 im Index eingefügt.
Common Header $0000..$0057 |
||
| Offset | Typ | Bedeutung |
| 0000 | Integer | RecordSize
Größe des Records in Bytes. |
| 0002 | Integer | HeaderSize (always $0800) |
Die HeaderSize kann geändert werden um kleinere oder größere Header zu erzeugen. Borland's TUTULITY Programm gibt jedoch dann eine Fehlermeldung aus. Paradox, die BDE und die Paradox Engine arbeiten jedoch kommentarlos mit dieser Änderung. |
| 0004 | Byte | FileType
00 = Ein Index Daten File: *.DB |
| 0005 | Byte | MaxTableSize
Dies ist die Größe eines Daten-Blocks. Wird angelegt, wenn die
Tabelle erzeugt wird. |
| 0006 | LongInt | NumRecords
Anzahl der Records in diesem File. |
| 000A | Word | UsedBlocks
Anzahl der benutzten Blöcke. |
| 000C | Word | FileBlocks
Anzahl der Daten Blocks in diesem File. (Jeder Block ist ein Zusammenschluß von Records) |
| 000E | Word | FirstBlock
Immer 1, es sei denn die Tabelle ist leer. |
| 0010 | Word | LastBlock
Nummer des letzten belegten Blockes in der Tabelle. |
| 0012 | Word | Unbekannt |
| 0014 | Byte | ModifiedFlags1
Ein Rebuild der Tabelle ist erforderlich, wenn der Wert ungleich 0 ist. |
| 0015 | Byte | IndexFieldNumber
In einem *.Xnn File eines Sekundär-Index, ist dies die Anzahl der Felder, die referenziert werden. In allen anderen Files ist dieser Wert 0. |
| 0016 | Pointer | PrimaryIndexWorkspace
Immer NIL bei DB Tabellen. |
| 001A | Pointer | Unbekannt (Suspected Pointer)
Dieses Feld ist normalerweise ein NIL Pointer. Eine Änderung wurde beim Feldtyp BCD, in einer 5.0 Tabelle beobachtet. Wahrscheinlich ist es nur ein Arbeits Pointer. |
| 001E
0020 |
Unbekannt
Die Benutzung dieser Bytes wurde bisher nur in einem *.PX File beobachtet. |
|
| 0021 | Integer | NumFields
Anzahl der Felder in dieser Tabelle. |
| 0023 | Integer | PrimaryKeyFields
Anzahl der Felder, die einen Primär-Schlüssel haben. |
| 0025 | LongInt | Encryption1
Position der Verschlüsselungs Information bei Paradox 3.0 und 3.5 (Hier steht $00000000, wenn keine Verschlüsselung vorliegt). Die Folge-Versionen speichern hier immer $FF00FF00 und den Verschlüsselungs-Code ab Offset $005C. Primär- und Sekundär Index Files speichern ihre Schlüssel auch an dieser Stelle, sie enthalten jedoch häufig 0en, weil Die Paradox Engine und die BDE überhaupt keine Index Dateien verschlüsseln. Eine Verschlüsselung kann aber durch kopieren dieser Felder in die Index Dateien trotzdem durchgeführt werden. |
| 0029 | Byte | SortOrder
$00: ASCII |
| 002A | Byte | ModifiedFlags2
Ein Rebuild der Tabelle ist erforderlich, wenn der Wert ungleich 0 ist. |
| 002B | Word | Unbekannt (immer 0) |
| 002D | Byte | ChangeCount1
Wird bei jedem File Header upgedate inkrementiert. |
| 002E | Byte | ChangeCount2
Es ist noch nicht klar, wenn dieses Feld inkrementiert wird. |
| 002F | Byte | Unbekannt |
| 0030 | ^pChar | TableNamePtr
Dies ist ein Pointer auf TableNamePtr, welcher ein Pointer auf TableName ist. Paradox benutzt dieses Feld, um einen schnelleren Zugriff auf TableName zu haben, weil auf diesen Teil der Tabelle sequentiell zugegriffen wird. Wird nur im RAM benutzt. |
| 0034 | Pointer | FldInfoPtr
Pointer auf die Liste der Feld ID's. Dieser Pointer kann benutzt werden, um den Tabellen-Header im RAM zur Laufzeit zu erreichen. Für Paradox Version > 4.0 muß $0078 subtrahiert werden, für kleinere Versionen und *.PX und *.Ynn Dateien $0058. |
| 0038 | Byte | WriteProtected
0 Schreibschutz Aus |
| 0039 | Byte | FileVersionID
$03 Version 3.0 |
| 003A | Word | MaxBlocks
Funktion ist unbekannt. Der Wert ist immer mit FileBlocks identisch (bei Offset $000C). |
| 003C | Byte | Unbekannt |
| 003D | Byte | AuxPasswords
Anzahl der Hilfs-Passworte für diese Tabelle. |
| 003E | Word | Unbekannt |
| 0040 | Pointer | CryptInfoStartPtr
Zeigt auf das CryptInfo Feld. Wenn keine Verschlüsselung durchgeführt wird, ist es immer NIL. Manchmal steht aber auch NIL drin, wenn die Tabelle verschlüsselt ist. |
| 0044 | Pointer | CryptInfoEndPtr
Zeigt auf das Ende von CryptInfo. Wenn keine Verschlüsselung durchgeführt wird, ist es immer NIL. |
| 0048 | Byte | Unbekannt |
| 0049 | LongInt | AutoInc
Dieses Feld speichert den Wert, der beim Auto-Increment- Feld-Typ "+" der Tabelle benutzt wird. |
| 004D | Word | FirstFreeBlock
Nummer des ersten freien Blocks |
| 004F | Byte | IndexUpdateRequired |
| 0050
0054 |
Unbekannt | |
| 0055 | Byte | RefIntegrity
Ein Wert von $2? bedeutet, das für diese Tabelle ein Integritäts Test durchgeführt werden sollte. |
| 0056 | Byte | Unbekannt |
| 0057 | Byte | Unbekannt |
| 0058 | Bytes | Start des Feld-Beschreibungs-Array |
Das Feld-Beschreibungs-Array enthält 2 Bytes für jedes Feld.
Feldnamen beginnen bei einem Offset von 120 ($78) plus 83 Bytes plus 6 Bytes für die Feldnummern. Die Feldnamen entsprechen der Reihenfolge der Feldnummern. Jeder Feldname ist ein nullterminierter String.
Bei einem zusammengesetzten Index (mehr als 1 Sekundär Index Feld) hat das Feld den gleichen Namen wie im DB File.
Bei einem einfachen Index (nur 1 Sekundär Index Feld) wird der Name durch 'Sec Key' ersetzt.
Der Primär Key Feldname ligt hinter den Sekundär Feldnamen. 'Hint' liegt hinter den Primär Key Feldnamen.
Direkt hinter dem nullterminierten 'Hint' liegt eine Reihe von nn 2-Byte Integers, wobei nn die Anzahl der Felder in diesem Record sind. Der erste Integer Wert enthält die Anzahl der Felder im Sekundären Index.
Direkt hinter den Integers, liegt ein nullterminierter String der die Sort Order enthält, z.B 'ascii'.
Im X** Header Block wird kein Sekundär Index Daten Record gespeichert.
Der Datenblock hat das gleiche Format wie der Datenblock vom DB File:
Byte 1 bis 6 sind von der BDE Reserviert. Danach folgt eine Anzahl von Datenrecords. Die Anzahl ist von der Größe eines Records abhängig. Die Recordgröße kann aus den einzelnen Typenangaben jedes Tabelleneintrages berechnet werden. Da die Anzahl der Records nicht immer genau einen Block ausfüllen, befinden sich am Blockende eine unbestimmte Anzahl von Füllbytes.
| 0000 | Word | NextBlock
Nummer des nächsten logischen Blocks. Diese Serie von Pointer wird auch Verkettete Liste bezeichnet. Die BDE berechnet die physikalische Startadresse eines Blocks aus der Blocknummer multipliziert mit der Blockgröße okus der Größe des Headers. |
| 0002 | Word | LastBlock
Nummer des letzten Blocks. |
| 0004 | Integer | LastBlockPtr
Zeiger auf den Start des letzten Record in diesem Block. Ein Zähler für die Anzahl der aktiven Records in diesem Block. Dieses Feld enthält eine 0, wenn nur ein Record vohanden ist und eine negative Zahl (0 - RecordSize) wenn kein Record da ist. NumRecsInBlock = (LastBlockPtr / RecordSize) + 1 |
| 0006 | Record | 1. Record
Alpha Felder sind eine Folge von Zeichen, die mit 00 bis zur definierten Länge aufgefüllt sind. Alle anderen Felder werden im Big-Endian-Format angegeben. Bei positiven Zahlen ist immer das MSB gesetzt. Short Integer: 1 = $80 $01, 512 = $82 $00 Real Zahlen werden immer als 8-Byte Double Typ gespeichert. Das MSB ist immer gesetzt. Datums Felder enthalten die Anzahl der Tage seit 00.01.0000. Das MSB ist immer gesetzt. |
| ---- | Record | n. Record |
| xxxx | Bytes | Dummy
nn Bytes vom letzten Record bis zum Blockende. Anzahl Bytes sind sind immer kleiner als die Recordlänge. |
Das Y** File ist der Primär Indes für ein X** File.
Sein logisches Format ist identisch mit dem vom PX File.
Die Beschreibung ist identisch mit der vom PX File.
Die Länge des Index Records ist um 6 Bytes größer als die Summe der Länge der Key Felder.
In diesem Block werden keine Index Records gespeichert.
Es ist das gleiche Format wie der Index Block beim PX File.