The PARADOX File Structure

来源:https://www.cnblogs.com/88223100/archive/2020/03/13/The-PARADOX-File-Structure.html
-Advertisement-
Play Games

This document describes the internal formats of the Paradox data and index files ...


 The PARADOX File Structure                         Compiled by Randy Beck
 ==========================                               [email protected]
                                                  http://www.randybeck.com

    I haven't made changes to this description for a long while, but not
    much has changed.  The latest revision concerns the tableName field,
    which I've discovered has lengthened in Paradox 7, and then another
    revision to that same field yet again.

    I'm not aware of any changes after Paradox 7.  But if anybody knows of
    anything different in Paradox 8 and 9 then please let me know.

    I should say here that many of the fields are listed here as pointers
    while the file is in memory.  I first made this connection back when
    Paradox 4 was still the state of the art.  I have not verified that
    this remains true, but a quick glance at some of the fields makes me
    think it's probably still true.


 This document details the binary file format for Paradox data files.
 There are still a few unknowns, but the important items are covered.

 I refer to the older table format as 3.0 tables and the newer ones as 4.0
 through 7.0, but I believe that most of the 3.0 information may also apply
 to the earlier versions.

 Pascal terms are used to describe data types:
     byte is 1 byte unsigned;
     integer is a 2-byte signed integer;
     word is a 2-byte unsigned integer;
     longint is a 4-byte signed integer;
     char is a 1-byte character;
     pchar is a pointer to a character;
     ^ modifies any type definition to a pointer to that type;
     ^pchar is a pointer to a pointer to a character.

 All pointers are 4-byte pointers.

 Please send additions and corrections to:

     Randy Beck
     P.O. Box 530433
     DeBary, FL 32753-0433
     USA

     email: [email protected]

 Distribute this freely, but please leave my name and address
 intact so that others may add information.




 GENERAL FILE STRUCTURE
 ======================

    ============================
    |     Header               |
    |     Data Block 0         |
    |     Data Block 1         |
    |     Data Block 2         |
    |     ...                  |
    |     Data Block n         |
    ============================

 The size of the Paradox file header is usually 2048 bytes (see headerSize
 at file offset 0002).  The first portion (offsets 0000 to $0057) has fixed
 field locations.  The next section ($0058 to $0077) was new to Paradox 4.0
 data files.  The rest varies in size -- depending upon the upon the number
 of fields -- and is listed sequentially.

 Some of the information in the file header seems to be needed only while
 it is being used by Paradox in RAM.  A few of these fields are pointers to
 other fields in the header, and are valid only during run-time.  They are
 listed here anyway, although their meaning is subject to change and they
 serve little purpose for third-party software.

 The data area which follows is divided into record blocks.  These use 1024,
 2048, 3072 or 4096 bytes each, depending upon the maximum table size set
 when the table was created.  The field structure of the data area is itself
 unusual in that each data field is arranged in hi-byte to low-byte order.

 Note:  This hi-byte to low-byte arrangement only applies to the user data
 in the table.  Everything else uses the normal low-byte to hi-byte format.

 The structure of primary and secondary index files generally follows that
 of Paradox version 3 data files.




 Paradox Common File Header  -- offsets 0000 to 0057
 ==========================

 With some noted exceptions, this part of the description is common to data
 and index files.  Offsets in this list are given in hexadecimal.  Other
 numbers should be assumed as listed in decimal format unless preceded by a
 dollar sign ('$').

 offset  type        usage
==============================================================================
| 0000 | integer     recordSize                                              |
|      |                                                                     |
|      |        This is the size of a user record in this table.             |
|      |                                                                     |
|      |        For primary index files, each "record" is actually the       |
|      |        field or fields in the index, plus three integers which      |
|      |        are not referenced in the header.                            |
|      |                                                                     |
|      |        Secondary index files also have additional fields, but       |
|      |        these are listed in the header.                              |
|      |                                                                     |
+------+---------------------------------------------------------------------+
| 0002 | integer     headerSize (always $0800)                               |
|      |                                                                     |
|      |        You can change headerSize, and move the data blocks          |
|      |        accordingly, to create larger or smaller table headers.      |
|      |        Borland's TUTILITY program would flag an error, but          |
|      |        Paradox, the Borland Database Engine and the Paradox         |
|      |        Engine will all still work with these tables.                |
|      |                                                                     |
+------+---------------------------------------------------------------------+
| 0004 | byte        fileType                                                |
|      |                                                                     |
|      |           0 = this is an indexed .DB data file                      |
|      |           1 = this is a primary index .PX file                      |
|      |           2 = this is a non-indexed .DB data file                   |
|      |           3 = this is a non-incrementing secondary index .Xnn file  |
|      |           4 = this is a secondary index .Ynn file (inc or non-inc)  |
|      |           5 = this is an incrementing secondary index .Xnn file     |
|      |           6 = this is a non-incrementing secondary index .XGn file  |
|      |           7 = this is a secondary index .YGn file (inc or non inc)  |
|      |           8 = this is an incrementing secondary index .XGn file     |
|      |                                                                     |
+------+---------------------------------------------------------------------+
| 0005 | byte        maxTableSize                                            |
|      |                                                                     |
|      |        This is the "maximum table size" determined when this        |
|      |        table was created.  It really indicates the size of each     |
|      |        block of records in the data section of the table.           |
|      |                                                                     |
|      |           1 =   64M    (block size = $0400 bytes)                   |
|      |           2 =  128M    (block size = $0800 bytes)                   |
|      |           3 =  192M    (block size = $0C00 bytes)                   |
|      |           4 =  256M    (block size = $1000 bytes)                   |
|      |                                                                     |
+------+---------------------------------------------------------------------+
| 0006 | longint     numRecords                                              |
|      |                                                                     |
|      |        This is the number of records in this file.                  |
|      |                                                                     |
+------+---------------------------------------------------------------------+
| 000A | word        nextBlock                                               |
|      |                                                                     |
|      |        I'm not certain what this really is, but it seems to be      |
|      |        the same as fileBlocks unless there is an empty block in     |
|      |        the table.                                                   |
|      |                                                                     |
+------+---------------------------------------------------------------------+
| 000C | word        fileBlocks                                              |
|      |                                                                     |
|      |        This is the number of data blocks in the file.               |
|      |        (Each "block" is a cluster of records.)                      |
|      |                                                                     |
+------+---------------------------------------------------------------------+
| 000E | word        firstBlock                                              |
|      |                                                                     |
|      |        Always 1 unless the table is empty.                          |
|      |                                                                     |
+------+---------------------------------------------------------------------+
| 0010 | word        lastBlock                                               |
|      |                                                                     |
|      |        This works out to the number of blocks that the table        |
|      |        would contain if every block was packed.                     |
|      |                                                                     |
+------+---------------------------------------------------------------------+
| 0012 | word        unknown                                                 |
|      |                                                                     |
|      |        The value of this field seems to the change when records     |
|      |        or blocks have been added to the table, but I still haven't  |
|      |        figured it out.                                              |
|      |                                                                     |
+------+---------------------------------------------------------------------+
| 0014 | byte        modifiedFlags1                                          |
|      |                                                                     |
|      |        A rebuild is required if this is not zero.                   |
|      |                                                                     |
+------+---------------------------------------------------------------------+
| 0015 | byte        indexFieldNumber                                        |
|      |                                                                     |
|      |        In the .Xnn file of a secondary index, this is the number    |
|      |        of the field it is referencing.                              |
|      |                                                                     |
|      |        This will be zero in the other files.                        |
|      |                                                                     |
+------+---------------------------------------------------------------------+
| 0016 | pointer     primaryIndexWorkspace                                   |
|      |                                                                     |
|      |        Pointer to the primary index file header (in RAM).           |
|      |        This will be a NIL if there is no primary index.             |
|      |                                                                     |
+------+---------------------------------------------------------------------+
| 001A | pointer     unknown  (suspected pointer)                            |
|      |                                                                     |
|      |        This field is usually a NIL pointer.  I've only seen it      |
|      |        used in 5.0 tables with BCD field types.  It is probably     |
|      |        just a workspace pointer.                                    |
|      |                                                                     |
+------+---------------------------------------------------------------------+
| 001E...0020        unknown                                                 |
|      |                                                                     |
|      |        I have only seen these three bytes used in .PX files.        |
|      |                                                                     |


+------+---------------------------------------------------------------------+
| 0021 | integer     numFields                                               |
|      |                                                                     |
|      |        This is the number of fields in the table.  If this is an    |
|      |        index file, then it would only be the number of fields in    |
|      |        this index.                                                  |
|      |                                                                     |
+------+---------------------------------------------------------------------+
| 0023 | integer     primaryKeyFields                                        |
|      |                                                                     |
|      |        This is the number of fields in the file's primary key.      |
|      |        It will be a zero for .PX and .Ynn files; and 2 for .Xnn     |
|      |        secondary index files.                                       |
|      |                                                                     |
+------+---------------------------------------------------------------------+
| 0025 | longint     encryption1                                             |
|      |                                                                     |
|      |        This was where the encryption information was stored for     |
|      |        versions 3.0 and 3.5.  (It was a zero if not encrypted.)     |
|      |                                                                     |
|      |        Subsequent versions store the value $FF00FF00 here, and      |
|      |        move the encryption code to offset $005C.  Even so, these    |
|      |        newer versions still maintain this information at both       |
|      |        locations while working in RAM.                              |
|      |                                                                     |
|      |        Primary and .Ynn secondary index files always use this       |
|      |        field to store the encryption code, but it is often a        |
|      |        zero because the Paradox Engine and the Borland Database     |
|      |        Engine do not always encrypt index files.  You can encrypt   |
|      |        unencrypted index files by following these steps:            |
|      |                                                                     |
|      |           Begin with an empty encrypted table;                      |
|      |           Truncate the index files to headerSize;                   |
|      |           Zeroize nextBlock, fileBlocks, firstBlock and lastBlock;  |
|      |           Copy four bytes from the .DB data file's encryption1      |
|      |               field (for version 3), or the encryption2 field       |
|      |               (for versions 4 and above) into the encryption1       |
|      |               or encryption2 field of the index file;               |
|      |           Test thoroughly.                                          |
|      |                                                                     |
|      |                                                                     |
+------+---------------------------------------------------------------------+
| 0029 | byte        sortOrder                                               |
|      |                                                                     |
|      |           $00:  ASCII                                               |
|      |           $B7:  International                                       |
|      |           $82:  Norwegian/Danish                                    |
|      |           $E6:  Norwegian/Danish (4.0)                              |
|      |           $F0:  Swedish/Finnish                                     |
|      |                                                                     |
+------+---------------------------------------------------------------------+
| 002A | byte        modifiedFlags2                                          |
|      |                                                                     |
|      |        A rebuild is required if this is not zero.                   |
|      |                                                                     |
+------+---------------------------------------------------------------------+
| 002B...002C        unknown    (always 0)                                   |
+------+---------------------------------------------------------------------+
| 002D | byte        changeCount1                                            |
|      |                                                                     |
|      |        This is incremented whenever the file header is updated.     |
|      |                                                                     |
+------+---------------------------------------------------------------------+
| 002E | byte        changeCount2                                            |
|      |                                                                     |
|      |        I'm not certain when this is incremented.                    |
|      |                                                                     |
+------+---------------------------------------------------------------------+
| 002F | byte        unknown                                                 |
+------+---------------------------------------------------------------------+
| 0030 | ^pchar      tableNamePtrPtr                                         |
|      |                                                                     |
|      |        This is a pointer to tableNamePtr, which is a pointer to     |
|      |        tableName.  Paradox uses this field to gain faster access    |
|      |        to tableName because that part of the header is accessed     |
|      |        sequentially.                                                |
|      |                                                                     |
+------+---------------------------------------------------------------------+
| 0034 | pointer     fldInfoPtr                                              |
|      |                                                                     |
|      |        Pointer to the list of field identifiers.  This is listed    |
|      |        in the accompanying Pascal record definition as a            |
|      |        PFldInfoRec type.                                            |
|      |                                                                     |
|      |        You can use this pointer value to locate the table header    |
|      |        in memory during run time.  Just subtract $0078 from this    |
|      |        value (for 4.0+ tables), or $0058 (for .PX and .Ynn index    |
|      |        files and version 3.0 tables).                               |
|      |                                                                     |
+------+---------------------------------------------------------------------+
| 0038 | byte        writeProtected                                          |
|      |                                                                     |
|      |           0        write protection OFF                             |
|      |           1        write protection ON                              |
|      |                                                                     |
+------+---------------------------------------------------------------------+
| 0039 | byte        fileVersionID                                           |
|      |                                                                     |
|      |           $03      version 3.0                                      |
|      |           $04      version 3.5                                      |
|      |           $05..09  version 4.x   (usually = $09)                    |
|      |           $0A,$0B  version 5.x                                      |
|      |           $0C      version 7.x                                      |
|      |                                                                     |
+------+---------------------------------------------------------------------+
| 003A | word        maxBlocks                                               |
|      |                                                                     |
|      |        I don't know what this is for.  It is usually the same       |
|      |        as fileBlocks (at offset 000C).                              |
|      |                                                                     |
+------+---------------------------------------------------------------------+
| 003C | byte        unknown                                                 |
+------+---------------------------------------------------------------------+
| 003D | byte        auxPasswords                                            |
|      |                                                                     |
|      |        Number of auxiliary passwords assigned to the table.         |
|      |                                                                     |
+------+---------------------------------------------------------------------+
| 003E...003F        unknown                                                 |
+------+---------------------------------------------------------------------+
| 0040 | pointer     cryptInfoStartPtr                                       |
|      |                                                                     |
|      |        Points to cryptInfo field.  It is always NIL when not        |
|      |        encrypted.  It is sometimes NIL even when encrypted.         |
|      |                                                                     |
+------+---------------------------------------------------------------------+
| 0044 | pointer     cryptInfoEndPtr                                         |
|      |                                                                     |
|      |        Points to end of cryptInfo.  This is NIL if not encrypted.   |
|      |                                                                     |
+------+---------------------------------------------------------------------+
| 0048 | byte        unknown                                                 |
+------+---------------------------------------------------------------------+
| 0049 | longint     autoInc                                                 |
|      |                                                                     |
|      |        This long integer stores the value used for the next auto    |
|      |        incrementing field in tables with a "+" autoincrementing     |
|      |        field type.                                                  |
|      |                                                                     |
|      |        Formerly used as a modification count.                       |
|      |                                                                     |
|      |        My thanks to Orlando Ruiz for informing me of this change.   |
|      |                                                                     |
+------+---------------------------------------------------------------------+
| 004D...004E        unknown                                                 |
+------+---------------------------------------------------------------------+
| 004F | byte        indexUpdateRequired                                     |
+------+---------------------------------------------------------------------+
| 0050...0054        unknown                                                 |
+------+---------------------------------------------------------------------+
| 0055 | byte        refIntegrity                                            |
|      |                                                                     |
|      |        A value here (=2?) denotes that this table uses              |
|      |        referential integrity checks.                                |
|      |                                                                     |
|      |                                                                     |
|      |             inxDirection (sec'y index file only)                    |
|      |                                                                     |
|      |        Secondary .Xnn index files of v7.0 tables use this           |
|      |        field to indicate sort order direction:                      |
|      |                                                                     |
|      |           $01      ascending sort                                   |
|      |           $11      descending sort                                  |
|      |                                                                     |
+------+---------------------------------------------------------------------+
| 0056...0057        unknown                                                 |
==============================================================================





 Paradox 4+ Data File Header -- offsets 0058 to 0077
 ===========================

 This part of the description applies only to .DB data files and .Xnn index
 files for Paradox versions 4.0 and later.

 offset  type        usage
==============================================================================
| 0058 | integer     unknown  (file version ID?)                             |
|      |                                                                     |
|      |           $0105..$0109  version 4.x   (usually = $0109)             |
|      |           $010A, $010B  version 5.x   (usually = $010B)             |
|      |           $010C         version 7.0                                 |
|      |                                                                     |
+------+---------------------------------------------------------------------+
| 005A | integer     unknown  (file version ID?)                             |
|      |                                                                     |
|      |        same values as at 0058                                       |
|      |                                                                     |
+------+---------------------------------------------------------------------+
| 005C | longint     encryption2                                             |
|      |                                                                     |
|      |        This will be zero if not encrypted.                          |
|      |        See encryption1 at offset 0025.                              |
|      |                                                                     |
+------+---------------------------------------------------------------------+
| 0060 | longint     fileUpdateTime (4.x only)                               |
|      |                                                                     |
|      |        Format similar to a packed date and time.                    |
|      |        I don't know what this does in 5.0 tables.                   |
|      |                                                                     |
+------+---------------------------------------------------------------------+
| 0064 | integer     hiFieldID                                               |
|      |                                                                     |
|      |        This number is always numFields + 1.                         |
|      |                                                                     |
+------+---------------------------------------------------------------------+
| 0066 | integer     hiFieldIDinfo?                                          |
|      |                                                                     |
|      |        This is related to hiFieldID (above), but I don't really     |
|      |        know what it's for.                                          |
|      |                                                                     |
+------+---------------------------------------------------------------------+
| 0068 | integer     sometimesNumFields?                                     |
|      |                                                                     |
|      |        This is sometimes the number of fields in the table, but     |
|      |        is often just a zero.  I don't know why.                     |
|      |                                                                     |
+------+---------------------------------------------------------------------+
| 006A | integer     dosGlobalCodePage                                       |
|      |                                                                     |
|      |        This was the Global Code Page when this table was created.   |
|      |                                                                     |
|      |           $01B5   United States                                     |
|      |           $02E1   Greek 1                                           |
|      |           $0352   Multilingual (Latin I)                            |
|      |           $0354   Eastern European (Latin II)                       |
|      |           $0359   Turkish                                           |
|      |           $035C   Portuguese                                        |
|      |           $035D   Icelandic                                         |
|      |           $035F   Canadian French                                   |
|      |           $0361   Nordic                                            |
|      |           $0365   Greek 2                                           |
|      |                                                                     |
|      |        Refer to an MS-DOS technical reference about interrupt $21,  |
|      |        function $66, for more information about this.               |
|      |                                                                     |
+------+---------------------------------------------------------------------+
| 006C...006F        unknown                                                 |
+------+---------------------------------------------------------------------+
| 0070 | integer     changeCount4                                            |
+------+---------------------------------------------------------------------+
| 0072...0077        unknown                                                 |
==============================================================================





 Paradox Common File Header  -- continued
 ==========================

 The file header continues sequentially.  Since the number of fields varies,
 there are no subsequent fixed offsets.

 This section begins where the previous section left off:

 offset
==============================================================================
| 0058   Paradox tables version 3.0 and 3.5                                  |
| 0058   Paradox .PX and .Ynn index files (any listed version)               |
| 0078   Paradox tables version 4.0 and above                                |
| 0078   Paradox .Xnn index files version 4.0 and above                      |
==============================================================================

         type                                   usage
==============================================================================
| ---- | array[1..(numFields)] of TFldInfoRec   fieldInfo                    |
|      |                                                                     |
|      |        type  TFldInfoRec  = RECORD                                  |
|      |                  fType   : byte;                                    |
|      |                  fSize   : byte;                                    |
|      |              end;                                                   |
|      |                                                                     |
|      |        These are the field identifiers for each field in the        |
|      |        table:                                                       |
|      |                                                                     |
|      |           fType  fSize(decimal)                                     |
|      |           -------------------------                                 |
|      |            $01     v   "A"  Alpha                                   |
|      |            $02     4   "D"  Date                                    |
|      |            $03     2   "S"  Short integer                           |
|      |            $04     4   "I"  Long integer                            |
|      |            $05     8   "$"  currency                                |
|      |            $06     8   "N"  Number                                  |
|      |            $09     1   "L"  Logical                                 |
|      |            $0C     v   "M"  Memo BLOb                               |
|      |            $0D     v   "B"  Binary Large Object                     |
|      |            $0E     v   "F"  Formatted Memo BLOb                     |
|      |            $0F     v   "O"  OLE                                     |
|      |            $10     v   "G"  Graphic BLOb                            |
|      |            $14     4   "T"  Time                                    |
|      |            $15     8   "@"  Timestamp                               |
|      |            $16     4   "+"  Autoincrement                           |
|      |            $17    17*  "#"  BCD                                     |
|      |            $18     v   "Y"  Bytes                                   |
|      |                                                                     |
|      |        The fSize given for BCD fields is not used for field size.   |
|      |        Instead, fSize denotes the number of digits following the    |
|      |        decimal point.  BCD fields are always 17 bytes long.         |
|      |                                                                     |
+------+---------------------------------------------------------------------+
| ---- | pchar                                  tableNamePtr                 |
|      |                                                                     |
|      |        Pointer to tableName when header is in RAM.                  |
|      |                                                                     |
+======+=====================================================================+
| ---- | array[1..(numFields)] of pchar         fieldNamePtrArray            |
|      |                                                                     |
|      |      * These pointers are not present in the index files. *         |
|      |                                                                     |
|      |        This is an array of pointers that reference the field names  |
|      |        when Paradox (or one of the engines) is running.  The size   |
|      |        of this array depends upon the number of fields.             |
|      |                                                                     |
+======+=====================================================================+
| ---- | array[1..(length varies)] of char      tableName                    |
|      |                                                                     |
|      |        This was the name this file was assigned when created.       |
|      |                                                                     |
|      |        Most tables will use 79 bytes, padded with zeroes.           |
|      |        This was extended with Paradox 7 to 261 bytes.               |
|      |                                                                     |
|      |        NOTE:  It was previously listed here as 271 bytes but        |
|      |               I received a heads-up from George Thackray that       |
|      |               this was in error.  It may also be that there's       |
|      |               there are more variations.                            |
|      |                                                                     |
==============================================================================
|                                                                            |
|     The rest of this information does not apply to .PX and .Ynn files.     |
|                                                                            |
==============================================================================
| ---- | char[]                                 fieldNames                   |
|      |                                                                     |
|      |        These are the ASCIIZ field name(s), arranged sequentially.   |
|      |                                                                     |
+------+---------------------------------------------------------------------+
| ---- | record                                 cryptInfo                    |
|      |                                                                     |
|      |        Encrypted tables would have additional data here.            |
|      |                                                                     |
|      |        Tables with auxiliary passwords would have 256 bytes here    |
|      |        (about which I have no information).                         |
|      |        Encrypted tables without auxiliary passwords would have      |
|      |        one byte for each field here.                                |
|      |                                                                     |
+------+---------------------------------------------------------------------+
| ---- | array[1..(numFields)] of integer       fieldNumbers                 |
|      |                                                                     |
|      |        These seem to be field numbers.  Changing these numbers      |
|      |        in my limited experiments seemed to cause no change in       |
|      |        behavior.  TUTILITY didn't seem to mind either.              |
|      |                                                                     |
|      |        I define this as an array, but the size is determined by     |
|      |        the number of fields in the table.                           |
|      |                                                                     |
+------+---------------------------------------------------------------------+
| ---- | char[]      sortOrderID                                             |
|      |                                                                     |
|      |        An ASCIIZ string representing the sort order for this        |
|      |        table ("ascii", "intl", etc.).                               |
|      |                                                                     |
==============================================================================






 Paradox Data Blocks
 ===================

 The data area begins at offset headerSize (usually $0800).  It is divided
 into blocks of 1024, 2048, 3072 or 4096 bytes -- depending upon the maximum
 table size set when the table was created.

 The entire data block will be encrypted if the table is encrypted.

  byte   type      usage
==============================================================================
| 0000 | word      nextBlock (block number + ???)                            |
|      |                                                                     |
|      |        I don't know what this does.                                 |
|      |                                                                     |
+------+---------------------------------------------------------------------+
| 0002 | word      blockNumber                                               |
|      |                                                                     |
|      |        The first block is numbered zero.                            |
|      |                                                                     |
+------+---------------------------------------------------------------------+
| 0004 | integer   addDataSize                                               |
|      |                                                                     |
|      |        This represents the amount of data in this block -- in       |
|      |        addition to one record length.                               |
|      |                                                                     |
|      |        This will be a zero if there is one record in this block,    |
|      |        and a negative number if there are no records.               |
|      |                                                                     |
|      |           numRecsInBlock = (addDataSize / recordSize) + 1           |
|      |                                                                     |
==============================================================================
| 0006.......      fileData                                                  |
|                                                                            |
|               Block size varies according to maxTableSize (at 0005):       |
|                  maxTableSize =  1  (64M):   block size = $0400 bytes      |
|                  maxTableSize =  2 (128M):   block size = $0800 bytes      |
|                  maxTableSize =  3 (192M):   block size = $0C00 bytes      |
|                  maxTableSize =  4 (256M):   block size = $1000 bytes      |
|                                                                            |
|                                                                            |
|   The records in the data area are arranged in field order.  Alpha fields  |
|   are arrays of characters, padded with zeroes.  Other fields seem to be   |
|   arranged in hi-byte to low-byte order, with the first byte's high bit    |
|   set for positive numbers.                                                |
|                                                                            |
|   For example, the number 1 stored as a 2-byte Short integer field is      |
|   arranged this way:  $80, 01.  And the integer 256 would be stored as:    |
|   $81, 00.                                                                 |
|                                                                            |
|   Floating point Number and currency fields are 8-byte DOUBLE types,       |
|   hi-byte to low-byte, with the first byte's high bit set.                 |
|                                                                            |
|   Date fields are stored as the number of days since JAN-0-0000, in high-  |
|   byte to low-byte order with the first byte's high bit set.               |
|                                                                            |
|                                                                            |
|   If you are wondering why the first byte's high bit is set for positive   |
|   numbers, recall from the Paradox Engine's documentation that a "blank"   |
|   SHORT (2-byte) integer is assigned the value of $8000.  By using the     |
|   hi-byte to low-byte format, and by reversing the first byte's high bit,  |
|   the value $8000 is converted to all zeroes.  So a record stored as all   |
|   zeroes is actually all blanks.                                           |
|                                                                            |
|                                                                            |
|   The records in primary index files contain the field or fields in the    |
|   index -- plus three integers that are not described in the header's      |
|   fieldInfo area.                                                          |
|                                                                            |
|                                                                            |
==============================================================================





 Sample Program with Paradox File Header Defined as a Pascal Record
 ==================================================================

 The rest of this text may be copied to a separate file as source code.


Program PXFMT;

(*
    This program will list the field values in the given table.

      Usage:  PXFMT <tablename.db>

    The file name's extension is mandatory.  It also works with index
    files, and displays the index record's three additional fields.

    It will stop if there are any errors.
 *)

uses  Dos, Crt, Objects;

const
    { Paradox codes for field types }
    pxfAlpha        = $01;
    pxfDate         = $02;
    pxfShort        = $03;
    pxfLong         = $04;
    pxfCurrency     = $05;
    pxfNumber       = $06;
    pxfLogical      = $09;
    pxfMemoBLOb     = $0C;
    pxfBLOb         = $0D;
    pxfFmtMemoBLOb  = $0E;
    pxfOLE          = $0F;
    pxfGraphic      = $10;
    pxfTime         = $14;
    pxfTimestamp    = $15;
    pxfAutoInc      = $16;
    pxfBCD          = $17;
    pxfBytes        = $18;


type
    { field information record used in TPxHeader below }
    PFldInfoRec         = ^TFldInfoRec;
    TFldInfoRec         =  RECORD
        fType   : byte;
        fSize   : byte;
    end;


    PPxHeader           = ^TPxHeader;
    TPxHeader           =  RECORD
        recordSize              :  word;
        headerSize              :  word;
        fileType                :  byte;
        maxTableSize            :  byte;
        numRecords              :  longint;
        nextBlock               :  word;
        fileBlocks              :  word;
        firstBlock              :  word;
        lastBlock               :  word;
        unknown12x13            :  word;
        modifiedFlags1          :  byte;
        indexFieldNumber	:  byte;
        primaryIndexWorkspace   :  pointer;
        unknownPtr1A            :  pointer;
        unknown1Ex20            :  array[$001E..$0020] of byte;
        numFields               :  integer;
        primaryKeyFields        :  integer;
        encryption1             :  longint;
        sortOrder               :  byte;
        modifiedFlags2          :  byte;
        unknown2Bx2C            :  array[$002B..$002C] of byte;
        changeCount1            :  byte;
        changeCount2            :  byte;
        unknown2F               :  byte;
        tableNamePtrPtr         : ^pchar;
        fldInfoPtr              :  PFldInfoRec;
        writeProtected          :  byte;
        fileVersionID           :  byte;
        maxBlocks               :  word;
        unknown3C               :  byte;
        auxPasswords            :  byte;
        unknown3Ex3F            :  array[$003E..$003F] of byte;
        cryptInfoStartPtr       :  pointer;
        cryptInfoEndPtr         :  pointer;
        unknown48               :  byte;
        autoInc                 :  longint;
        unknown4Dx4E            :  array[$004D..$004E] of byte;
        indexUpdateRequired     :  byte;
        unknown50x54            :  array[$0050..$0054] of byte;
        refIntegrity            :  byte;
        unknown56x57            :  array[$0056..$0057] of byte;
        case INTEGER of
          3:   (fieldInfo35     :  array[1..255] of TFldInfoRec);
          4:   (fileVerID2      :  integer;
                fileVerID3      :  integer;
                encryption2     :  longint;
                fileUpdateTime  :  longint;  { 4.0 only }
                hiFieldID       :  word;
                hiFieldIDinfo   :  word;
                sometimesNumFields:integer;
                dosCodePage     :  word;
                unknown6Cx6F    :  array[$006C..$006F] of byte;
                changeCount4    :  integer;
                unknown72x77    :  array[$0072..$0077] of byte;
                fieldInfo       :  array[1..255] of TFldInfoRec);

      { This is only the first part of the file header.  The last field
        is described as an array of 255 elements, but its size is really
        determined by the number of fields in the table.  The actual
        table header has more information that follows. }

    end;


    PDataBlock  = ^TDataBlock;
    TDataBlock  =  RECORD
        nextBlock     : word;
        blockNumber   : word;
        addDataSize   : integer;
        fileData      : array[0..$0FF9] of byte;
        { fileData size varies according to maxTableSize }
    end;




procedure ConvertPxField(var N;  F: PFldInfoRec);
{ This will convert both ways, but blanks will be turned to zeroes. }
{ Warning:  Not all field types are converted. }
type TNRec= array[0..16] of byte;
var  i    : integer;
     size : integer;
     NRec : TNRec;

    function ItsBlank : boolean;
    var  i : integer;
    begin
      ItsBlank := TRUE;
      For i := 0 to pred(size) do If TNRec(N)[i] <> 0 then ItsBlank := FALSE;
    end;

begin
  If F^.fType = pxfBCD then { BCD field size value not used for field size }
    size := 17
   else
    size := F^.fSize;
  If (F^.fType in [pxfDate..pxfNumber, pxfTime..pxfAutoInc]) and
     not ItsBlank  { leave blank fields as all zeroes }
   then
    begin
    TNRec(N)[0] := TNRec(N)[0] xor $80;
    For i := 0 to pred(size) do
      NRec[pred(size-i)] := TNRec(N)[i];
    Move(NRec, N, size);
    end;
end;


procedure ConvertPxRecord(Hdr: PPxHeader; P: pointer);
const  IndexF : TFldInfoRec = (fType: pxfShort;  fSize: sizeof(INTEGER));
var  i    : integer;
     F    : PFldInfoRec;
begin
  F := Hdr^.fldInfoPtr;  { begin with the first field identifier }
  For i := 1 to Hdr^.numFields do
    begin
    ConvertPxField(P^, F);
    If F^.fType = pxfBCD then { BCD field size value not used for field size }
      Inc(ptrrec(P).ofs, 17)
     else
      Inc(ptrrec(P).ofs, F^.fSize);
    Inc(ptrrec(F).ofs, sizeof(F^));
    end;
  If Hdr^.fileType = 1 then  { convert primary index information }
    begin
    For i := 1 to 3 do
      begin
      ConvertPxField(P^, @IndexF);
      Inc(ptrrec(P).ofs, 2);
      end;
    end;
end;


procedure WritePxField(var N;  F: PFldInfoRec);
{ not all field types are supported here }
var  i    : integer;
     A    : string;
begin
  Case F^.fType of
    pxfAlpha, pxfMemoBLOb:
      begin
      Move(N, A[1], F^.fSize);
      A[0] := char(F^.fSize);
      For i := length(A) downto 1 do
        If (A[i] = #0) then A[0] := char(pred(i));
      write('"', A, '"');
      end;
    pxfShort:             write(integer(N));
    pxfLong, pxfAutoInc:  write(longint(N));
    pxfCurrency:          write('$', double(N):1:2);
    pxfNumber:            write(double(N):1:3);

    { the rest of the field types are not translated }
    pxfDate:              write('<Date:',longint(N),'>');
    pxfLogical:           write('<Logical:',byte(N),'>');
    pxfBLOb:              write('<BLOb>');
    pxfFmtMemoBLOb:       write('<FormattedBLOb>');
    pxfOLE:               write('<OLE>');
    pxfGraphic:           write('<Graphic>');
    pxfTime:              write('<Time:',longint(N),'>');
    pxfTimestamp:         write('<TimeStamp:',longint(N),'>');
    pxfBCD:               write('<BCD>');
    pxfBytes:             write('<Bytes>');
   else                   write('<unknown>');
    end;
end;


procedure WritePxRecord(Hdr: PPxHeader; P: pointer);
const  IndexF : TFldInfoRec = (fType: pxfShort;  fSize: sizeof(INTEGER));
var  i    : integer;
     F    : PFldInfoRec;
begin
  F := Hdr^.fldInfoPtr;  { begin with the first field identifier }
  For i := 1 to Hdr^.numFields do
    begin
    If i > 1 then write(', ');
    WritePxField(P^, F);
    If F^.fType = pxfBCD then { BCD field size value not used for field size }
      Inc(ptrrec(P).ofs, 17)
     else
      Inc(ptrrec(P).ofs, F^.fSize);
    Inc(ptrrec(F).ofs, sizeof(F^));
    end;
  If Hdr^.fileType = 1 then  { display primary index information }
    begin
    For i := 1 to 3 do
      begin
      If i = 1 then write(';  index fields: ') else write(', ');
      WritePxField(P^, @IndexF);
      Inc(ptrrec(P).ofs, 2);
      end;
    end;
  writeln;
end;


procedure ReadBlock(var S: TStream; Hdr: PPxHeader; var AData );
begin
  S.Read(AData, Hdr^.maxTableSize * $0400)
end;


procedure SeekBlock(var S: TStream; Hdr: PPxHeader; ABlock: word);
var  L   : longint;
begin
  L := ABlock;
  L := (L * Hdr^.maxTableSize * $0400) + Hdr^.headerSize;
  S.Seek(L);
end;



procedure ReadAllRecords(var S: TStream);
var  i      : integer;
     num,z  : word;
     Block  : PDataBlock;
     F      : TFldInfoRec;
     Hdr    : PPxHeader;

    function  FileFormatIsOK : boolean;
    begin
      FileFormatIsOK := (Hdr^.maxTableSize >= 1) and (Hdr^.maxTableSize <= 4)
    end;

    function  FileIsEncrypted : boolean;
    begin
      If (Hdr^.fileVersionID <= 4) or not (Hdr^.fileType in [0,2,3,5]) then
        FileIsEncrypted := (Hdr^.encryption1 <> 0)
       else
        FileIsEncrypted := (Hdr^.encryption2 <> 0)
    end;

begin
  New(Hdr);
  S.Seek(0);
  S.Read(Hdr^, sizeof(Hdr^));
  If (S.Status = stOK) and FileFormatIsOK then
    begin

    { assign the header's fldInfoPtr field }
    If (Hdr^.fileVersionID <= 4) or not (Hdr^.fileType in [0,2,3,5]) then
      Hdr^.fldInfoPtr := addr(Hdr^.fieldInfo35)
     else
      Hdr^.fldInfoPtr := addr(Hdr^.fieldInfo);

    If FileIsEncrypted then
      writeln('This file is encrypted.')
     else
      begin
      New(Block);
      num := 0;
      While (S.Status = stOK) and (num < Hdr^.fileBlocks) do
        begin
        SeekBlock(S, Hdr, num);
        ReadBlock(S, Hdr, Block^);
        If (S.Status = stOK) and (Block^.addDataSize >= 0) then
          begin
          z := 0;
          For i := 0 to (Block^.addDataSize div Hdr^.recordSize) do
            begin
            ConvertPxRecord(Hdr, addr(Block^.fileData[z]));
            WritePxRecord(Hdr, addr(Block^.fileData[z]));
            Inc(z, Hdr^.recordSize);
            end;
          end;
        Inc(num);
        end;

      Dispose(Block);
      end;

    end;
end;


var  Stream   : TBufStream;

Begin
  Assign(Output, '');
  Rewrite(Output);
  Stream.Init(paramstr(1), stOpenRead, 4096);
  ReadAllRecords(Stream);
  If Stream.Status <> stOK then
    writeln(^M^J'Error:  Status=', Stream.Status, ';  Error=', Stream.ErrorInfo);
  Stream.Done;
End.

PASCAL代碼實現:

Program PXFMT;

(*
    This program will list the field values in the given table.

      Usage:  PXFMT <tablename.db>

    The file name's extension is mandatory.  It also works with index
    files, and displays the index record's three additional fields.

    It will stop if there are any errors.
 *)

uses  Dos, Crt, Objects;

const
    { Paradox codes for field types }
    pxfAlpha        = $01;
    pxfDate         = $02;
    pxfShort        = $03;
    pxfLong         = $04;
    pxfCurrency     = $05;
    pxfNumber       = $06;
    pxfLogical      = $09;
    pxfMemoBLOb     = $0C;
    pxfBLOb         = $0D;
    pxfFmtMemoBLOb  = $0E;
    pxfOLE          = $0F;
    pxfGraphic      = $10;
    pxfTime         = $14;
    pxfTimestamp    = $15;
    pxfAutoInc      = $16;
    pxfBCD          = $17;
    pxfBytes        = $18;


type
    { field information record used in TPxHeader below }
    PFldInfoRec         = ^TFldInfoRec;
    TFldInfoRec         =  RECORD
        fType   : byte;
        fSize   : byte;
    end;


    PPxHeader           = ^TPxHeader;
    TPxHeader           =  RECORD
        recordSize              :  word;
        headerSize              :  word;
        fileType                :  byte;
        maxTableSize            :  byte;
        numRecords              :  longint;
        nextBlock               :  word;
        fileBlocks              :  word;
        firstBlock              :  word;
        lastBlock               :  word;
        unknown12x13            :  word;
        modifiedFlags1          :  byte;
        indexFieldNumber    :  byte;
        primaryIndexWorkspace   :  pointer;
        unknownPtr1A            :  pointer;
        unknown1Ex20            :  array[$001E..$0020] of byte;
        numFields               :  integer;
        primaryKeyFields        :  integer;
        encryption1             :  longint;
        sortOrder               :  byte;
        modifiedFlags2          :  byte;
        unknown2Bx2C            :  array[$002B..$002C] of byte;
        changeCount1            :  byte;
        changeCount2            :  byte;
        unknown2F               :  byte;
        tableNamePtrPtr         : ^pchar;
        fldInfoPtr              :  PFldInfoRec;
        writeProtected          :  byte;
        fileVersionID           :  byte;
        maxBlocks               :  word;
        unknown3C               :  byte;
        auxPasswords            :  byte;
        unknown3Ex3F            :  array[$003E..$003F] of byte;
        cryptInfoStartPtr       :  pointer;
        cryptInfoEndPtr         :  pointer;
        unknown48               :  byte;
        autoIncVal              :  longint;
        unknown4Dx4E            :  array[$004D..$004E] of byte;
        indexUpdateRequired     :  byte;
        unknown50x54            :  array[$0050..$0054] of byte;
        refIntegrity            :  byte;
        unknown56x57            :  array[$0056..$0057] of byte;
        case INTEGER of
          3:   (fieldInfo35     :  array[1..255] of TFldInfoRec);
          4:   (fileVerID2      :  integer;
                fileVerID3      :  integer;
                encryption2     :  longint;
                fileUpdateTime  :  longint;  { 4.0 only }
                hiFieldID       :  word;
                hiFieldIDinfo   :  word;
                sometimesNumFields:integer;
                dosCodePage     :  word;
                unknown6Cx6F    :  array[$006C..$006F] of byte;
                changeCount4    :  integer;
                unknown72x77    :  array[$0072..$0077] of byte;
                fieldInfo       :  array[1..255] of TFldInfoRec);

      { This is only the first part of the file header.  The last field
        is described as an array of 255 elements, but its size is really
        determined by the number of fields in the table.  The actual
        table header has more information that follows. }

    end;


    PDataBlock  = ^TDataBlock;
    TDataBlock  =  RECORD
        nextBlock     : word;
        blockNumber   : word;
        addDataSize   : integer;
        fileData      : array[0..$0FF9] of byte;
        { fileData size varies according to maxTableSize }
    end;




procedure ConvertPxField(var N;  F: PFldInfoRec);
{ This will convert both ways, but blanks will be turned to zeroes. }
{ Warning:  Not all field types are converted. }
type TNRec= array[0..16] of byte;
var  i    : integer;
     size : integer;
     NRec : TNRec;

    function ItsBlank : boolean;
    var  i : integer;
    begin
      ItsBlank := TRUE;
      For i := 0 	   

您的分享是我們最大的動力!

-Advertisement-
Play Games
更多相關文章
  • 常用分頁查詢sql 先介紹一個面試題,查詢表中第200-300條數據。應用既是分頁查詢,先通過子查詢對數據進行標記,如oracle通過rownum進行標記,再取一個區間的數據。 一,ORACLE 關鍵字 rownum 規則: select * from (select a.*,rownum rc f ...
  • 慢查詢日誌中long_query_time 與log_queries_not_using_indexes與min_examined_row_limit 關係分析 參數介紹: long_query_time:慢查詢日誌記錄超時的時間,無論是不是有索引,單位秒。 log_queries_not_usin ...
  • 第九章 存儲過程 初識存儲過程 存儲過程(Stored Procedure)是在大型資料庫系統中,一組為了完成特定功能的SQL 語句集,存儲在資料庫中,經過第一次編譯後調用不需要再次編譯,用戶通過指定存儲過程的名字並給出參數(如果該存儲過程帶有參數)來執行它。存儲過程是資料庫中的一個重要對象。 包含 ...
  • 目前負責的一個項目,需要維護一個電話號碼對比庫,表名為phone_bak1,以下稱為a表,量級為3000萬條。還有另外一張表存儲電話白名單,表名為phone_delete,以下稱為b表,量級為3000條左右。 目的呢,是要從a表中排除掉在b表中的電話號碼。 我直接使用以下語句: DELETE FRO ...
  • 資料庫版本及優勢 3.4版本在性能和安全性等方面較3.2版本均有不同程度的提升; 4.0版本更適用於金融等對事務有依賴且使用NoSQL特性的場景; 4.2版本採用二段提交方式,保證分片集群事務的ACID特性,極大拓展了適用的業務場景。更多詳情請參見下表。 資料庫版本優勢 3.4版本 更快的主備同步 ...
  • 場景 Centos中Redis的下載編譯與安裝(超詳細): https://blog.csdn.net/BADAO_LIUMANG_QIZHI/article/details/103967334 Redis的啟動和關閉(前臺啟動和後臺啟動): https://blog.csdn.net/BADAO_ ...
  • [20200312]不要設置net.ipv4.tcp_tw_recycle=1.txt--//昨天認真看了2篇blog:https://vincent.bernat.ch/en/blog/2014-tcp-time-wait-state-linux--//中文翻譯:http://www.cnxct. ...
  • 場景 Centos中Redis的下載編譯與安裝(超詳細): https://blog.csdn.net/BADAO_LIUMANG_QIZHI/article/details/103967334 Redis的啟動和關閉(前臺啟動和後臺啟動): https://blog.csdn.net/BADAO_ ...
一周排行
    -Advertisement-
    Play Games
  • 移動開發(一):使用.NET MAUI開發第一個安卓APP 對於工作多年的C#程式員來說,近來想嘗試開發一款安卓APP,考慮了很久最終選擇使用.NET MAUI這個微軟官方的框架來嘗試體驗開發安卓APP,畢竟是使用Visual Studio開發工具,使用起來也比較的順手,結合微軟官方的教程進行了安卓 ...
  • 前言 QuestPDF 是一個開源 .NET 庫,用於生成 PDF 文檔。使用了C# Fluent API方式可簡化開發、減少錯誤並提高工作效率。利用它可以輕鬆生成 PDF 報告、發票、導出文件等。 項目介紹 QuestPDF 是一個革命性的開源 .NET 庫,它徹底改變了我們生成 PDF 文檔的方 ...
  • 項目地址 項目後端地址: https://github.com/ZyPLJ/ZYTteeHole 項目前端頁面地址: ZyPLJ/TreeHoleVue (github.com) https://github.com/ZyPLJ/TreeHoleVue 目前項目測試訪問地址: http://tree ...
  • 話不多說,直接開乾 一.下載 1.官方鏈接下載: https://www.microsoft.com/zh-cn/sql-server/sql-server-downloads 2.在下載目錄中找到下麵這個小的安裝包 SQL2022-SSEI-Dev.exe,運行開始下載SQL server; 二. ...
  • 前言 隨著物聯網(IoT)技術的迅猛發展,MQTT(消息隊列遙測傳輸)協議憑藉其輕量級和高效性,已成為眾多物聯網應用的首選通信標準。 MQTTnet 作為一個高性能的 .NET 開源庫,為 .NET 平臺上的 MQTT 客戶端與伺服器開發提供了強大的支持。 本文將全面介紹 MQTTnet 的核心功能 ...
  • Serilog支持多種接收器用於日誌存儲,增強器用於添加屬性,LogContext管理動態屬性,支持多種輸出格式包括純文本、JSON及ExpressionTemplate。還提供了自定義格式化選項,適用於不同需求。 ...
  • 目錄簡介獲取 HTML 文檔解析 HTML 文檔測試參考文章 簡介 動態內容網站使用 JavaScript 腳本動態檢索和渲染數據,爬取信息時需要模擬瀏覽器行為,否則獲取到的源碼基本是空的。 本文使用的爬取步驟如下: 使用 Selenium 獲取渲染後的 HTML 文檔 使用 HtmlAgility ...
  • 1.前言 什麼是熱更新 游戲或者軟體更新時,無需重新下載客戶端進行安裝,而是在應用程式啟動的情況下,在內部進行資源或者代碼更新 Unity目前常用熱更新解決方案 HybridCLR,Xlua,ILRuntime等 Unity目前常用資源管理解決方案 AssetBundles,Addressable, ...
  • 本文章主要是在C# ASP.NET Core Web API框架實現向手機發送驗證碼簡訊功能。這裡我選擇是一個互億無線簡訊驗證碼平臺,其實像阿裡雲,騰訊雲上面也可以。 首先我們先去 互億無線 https://www.ihuyi.com/api/sms.html 去註冊一個賬號 註冊完成賬號後,它會送 ...
  • 通過以下方式可以高效,並保證數據同步的可靠性 1.API設計 使用RESTful設計,確保API端點明確,並使用適當的HTTP方法(如POST用於創建,PUT用於更新)。 設計清晰的請求和響應模型,以確保客戶端能夠理解預期格式。 2.數據驗證 在伺服器端進行嚴格的數據驗證,確保接收到的數據符合預期格 ...