TopSpeed TPS файл

                       О С Н О В Н О Й   T P S - Ф А Й Л

                             ФИЗИЧЕСКАЯ ОРГАНИЗАЦИЯ

                                    Заголовок

      (+0)       (+4)          (+6)           (+0Ah)          (+0Eh)
  00 00 00 00    00 00      00 05 00 00     00 05 00 00     74 4F 70 53
 UNSIGNED LONG   USHORT    UNSIGNED LONG   UNSIGNED LONG   UNSIGNED LONG
   Смещение      Размер     Длина файла     Длина файла     Метка файла
  заголовка    заголовка                                      TOPSPEED

  (+12h)      (+14h)          (+18h)                (+1Ch)
  00 00     00 00 00 06     07 00 00 00           00 00 00 00
  SHORT    UNSIGNED LONG   UNSIGNED LONG         UNSIGNED LONG
   Нули      Последний   Счетчик изменений     Верхняя управляющая
   (?)         номер           файла        страница (адрес минус 200h,
                                                деленный на 100h)

  Далее следуют 2 массива длиной (длина_заголовка-20h)/2 четырехбайтовых
чисел (ниже порядок байт перевернут):

0020h:   00000000  00000000  01000000  04000000  4D000000  22010000  22010000

0110h:   00000000  01000000  03000000  4C000000  22010000  22010000  22010000

            ^                                                 ^
   эта пара элементов                          это (длина_файла-200h)/100h,
      игнорируется (?)              эта пара чисел заполняет остаток массивов

  В файле страницы идут блоками, между которыми простанство не используется.
i-й элемент в первом массиве показывает начало каждого такого блока, i-й
элемент во втором - конец блока. i-й элемент - это смещение блока (первого
байта в первой странице для первого массива и первого байта следующей за по-
следней страницей страницы в блоке для второго массива) минус 200h (размер
заголовка), деленное на 100h. Все страницы в блоке, кроме, быть может,
последней, сжаты, если могут быть сжаты.
  Если какая-то страница в середине блока не сжата, но может быть сжата, то
блок разбивается на два так, чтобы несжатая страница была в конце блока. В этих
массивах тогда встречается конструкция вида (в примере ниже несжатая страница
находится по смещению 0200h и имеет размер 100h):

0020h:   00000000    00000000    01000000

0110h:   00000000    01000000    22010000
                         ^           ^

  В конце файла не может быть неиспользуемого пространства. Если оно по-
является, то файл укорачивается (обрезается функцией int 21h, ah=40h, cx=0).
  Неизвестно, может ли заголовок быть длиннее 200h, и если да, то что
происходит с этими массивами (скорее всего, их длина просто увеличивается).

                           Формат обычной страницы

   (+0)                   (+4)                  (+6)             (+8)
   00 02 00 00            73 00                 77 00            7F 00
     ULONG                USHORT                USHORT           USHORT
    Смещение          Длина сжатой         Длина страницы    Длина страницы
    страницы     страницы (если страница     после деком-   после декомпрес-
 (для контроля)   не сжата, то здесь по-        прессии       сии безо всех
                 вторяется следуещее поле)                      сокращений

    (+0Ah)             (+0Ch)                      (+0Dh)
    0A 00                00                          05
    USHORT              BYTE                        BYTE
 Число записей    Признак обычной   Смещение первого блока-повторителя
  на странице         страницы            Этот байт есть только когда
                 (уровень страницы)             страница сжата,
                                            т.е. поле по смещению 4 не
                                            равно полю по смещению 6
    (+0Dh/0Eh)
    ...
    Далее идут записи на странице

  Страницы в файле имеют разную длину. Длина конкретной страницы зависит от
файлового драйвера. Если при добавлении/изменении данных оказывается, что
страницы слишком длинная, она разделяется на две.
  За страницей неиспользуемое пространство до следующего кратного 0x100
смещения заполяется байтом 0xB0 и не входит в длину страницы (поля +4, +6, +8),
но резеврируется за ней и в заголовке указывается принадлежащим странице.

                          Формат управляющей страницы

   (+0)                    (+4)                (+6)             (+8)
   00 02 00 00             73 00               77 00            7F 00
     ULONG                 USHORT              USHORT           USHORT
    Смещение           Длина страницы       Длина страницы    Длина страницы
    страницы           с сокращениями       с сокращениями         без
 (для контроля)                                                 сокращений

    (+0Ah)             (+0Ch)
    0A 00                00
    USHORT              BYTE                 Байта по смещению +0Dh
 Число записей    Уровень управляющей        нет, т.к. управляющие страницы
  на странице          страницы              не сжимаются (?)
                 (0-обычная страница)

    (+0Dh)
  00 00 00 00    05 00 00 00    ...
     ULONG          ULONG
  Массив подчиненных страниц. Его размер равен числу записей на упр.странице.
  Элемент массива - это (смещение_подчиненной_страницы-200h)/100h.

    (+?)
    ...
  Далее следуют записи. Они повторяют первые записи на подчиненных страницах
(возможно укороченные, если подчиненные страницы не управляющие).
Каждой этой записи соответствует элемент в массиве подчиненных страниц.

                                 Сжатые страницы

  Если страница сжатая, то поля (+4) и (+6) заголовка страницы различаются.
В этом случае байт по смещению (+0Dh) показывает смещение относительно
байта (+Eh) первого блока-повторителя. Формат этого блока:

          00                  05                       03
         BYTE                BYTE                     BYTE
      Какой байт        Кол-во повторений     Смещение следующего
   нужно повторять         минус одно          блока-повторителя

  Смещение следующего блока-повторителя - это смещение следующего такого блока
относительно байта, последнего в этом блоке. Если блок - последний, то смещение
следующего блока указывает на последний байт страницы (не на следующий за
страницей байт 0xB0).
  Если количество повторений > 127, то непосредственно за этим байтом следует
еще один:

        3E              85           10                 03
       BYTE            BYTE         BYTE               BYTE
    Какой байт     Первый байт   Второй байт    Смещение следующего
    повторять     Кол-во повторений минус одно         блока

  Кол-во повторений тогда вычисляется по формуле

            ((второй_байт + ((первый_байт & 7F) << 1)) >> 1) + 1

  Если смещение_следующего_блока > 127, то непосредственно за этим байтом
следует еще один байт, смещение относительно последнего байта блока при этом
вычисляется по формуле

               (второй_байт + ((первый_байт & 7F) << 1)) >> 1

  Заголовок страницы не сжимается. Нормальное состояние страниц - сжатое.
Однако страница не сжимается, если не может быть сжата, т.е.после сжатия ее
длина должна быть строго меньше несжатой. Если страница не сжата, но может
быть сжата, то она указывается в заголовке. Если страница не может быть сжата,
то она в заголовке не указывается.

                          Общий формат записи на странице

      (+0)            (+1)          (+1/3)          (+1/3/5)
       С0             2A 00          09 00           . . .
  Идентификатор    Новая длина    Новая длина
                     записи        записи в          Данные
                                 управляющей
                                   странице

   Формат идентификатора:        1 1 0 0 0 1 0 0
                                 │ │ L----T-----
    указана новая длина записи --- │      │
                                   │    сколько первых байт этой
    указана новая длина записи -----    записи должно быть взято
    в управляющей странице              из предыдущей записи

  Длина новой записи присутствует только тогда, когда идентификатор & 0x80<>0,
в противном случае эначение длины берется из предыдущей записи. Длина новой
записи в управляющей странице присутствует только тогда, когда
идентификатор & 0x40 <> 0, в противном случае берется из предыдущей записи.
Для первой записи на странице эти оба значения должны быть обязательно указаны,
т.е. должно выполняться идентификатор & 0xC0 = 0xC0. Шесть младших битов иден-
тификатора показывают количество копируемых из предыдущей записи байтов.

                               Общий формат файла

 ---- Заголовок ------┐  ---->--- Блок 1
 │ ...                │  │    │-- страница 1
 │  верхняя страница  │  │    ││  .....--
 │ ...                │  │    │L-
 │                    │  │    │-- страница 2
 │ 020h:  00 00 00 00 │  │    ││  ...........------
 │        начало1 --------    │L-
 │        начало2 ---------┐  │...
 │        начало3 -------┐ │  │-- страница M
 │        ...         │  │ │  ││  ..........---
 │ 110h:  00 00 00 00 │  │ │  │L-
 │        конец1 --------+-+->L----
 │        конец2 --------+ │   неиспользуемое пространство
 │        конец3 ------┐ │ L->--- Блок 2
 │        ...         ││ │    │-- страница 1
 L---------------------│ │    ││  ...
                       │ │    │L-
                       │ │    │-- страница 2
                       │ │    ││  ...
                       │ │    │L-
                       │ │    │...
                       │ │    │-- страница N - незаархивированная
                       │ │    ││  ...
                       │ │    │L-
                       │ │    L----
                       │ L--->--- Блок 3
                       │      │-- страница 1
                       │      ││ ...
                       │      │L-
                       │      │...
                       │      │-- страница K
                       │      ││ ...
                       │      │L-
                       │      L----
                       L-----> неиспользуемое пространство
                              --- Блок L
                              ...

                              L----
                              Конец файла

   -- Заголовок ----------------┐
   │  . . . . . . . . . . . .   │
 ---< страница верхнего уровня  │
 │ │  . . . . . . . . . . . .   │
 │ L-----------------------------
 │
 │     Страница
 │     уровня N                   Страницы
 L->T-----------------┐           уровня N-1                   Страницы
    │ подчинен.стр.11-------->T-------------------┐         нулевого уровня
    │ подчинен.стр.12------┐  │ подч.стр.21--------->...->--------------------┐
    │ ...             │    │  │ подч.стр.22       │     --->записьN1=запись11 │
    │                 │    │  │ ...               │     │ │ записьN2          │
    │-----------------│    │  │                   │     │ │ ...               │
    │ запись11 ------------+-┐│-------------------│     │ L--------------------
    │ запись12 -----------┐│ L->запись21=запись11 ------- ...
    │ ...             │   ││  │ запись22          │
    L------------------   ││  │ ...               │  ...->--------------------┐
                          ││  L--------------------       ->записьM1          │
                          ││                              │ записьM2          │
                          │L->--------------------┐       │                   │
                          │   │ подч.стр.31--------->...  L--------------------
                          │   │ ...               │       ...
                          │   │-------------------│  ...->--------------------┐
                          L---->запись31=запись12---------->записьK1          │
                              │ ...               │       │ записьK2          │
                              L--------------------       │ ...               │
                              ...                         L--------------------
                                                          ...

  Все записи отсортированы в лексикографическом порядке.
  Все записи в файле отсортированы в лексикографическом порядке. Это
достигается тем, что на каждой странице записи отсортированы, в том числе и на
управляющих. На управляющих страницах записи повторяют первые записи на
соответствующих подчиненных страницах (или несколько укороченные). Физическая
организация TPS-файла сильно похожа на организацию ключевых/индексных файлов
формата CLARION 2.1.
  Замечание: судя по всему, в файле (и на каждой странице) не должно быть двух
одинаковых записей (см.записи ключей/индексов и атрибут DUP).

  При поиске записи проходится цепочка страниц от верхней управляющей до
страницы нулевого уровня, по одной странице из каждого уровня. На странице
поиск начинается от начала страницы: ищется последняя запись, которая лексико-
графически меньше искомой. Дальше для найденной записи и для каждой записи,
N первых символов которой совпадают с искомой (N - длина искомой записи),
запись ищется на подчиненной странице (или считается найденной, если это
страница нулевого уровня). Если первая запись на странице лексикографически
больше искомой, то на этой странице и на подчиненных искомой записи нет. Если
на странице нулевого уровня первая запись меньше искомой, а после последней
записи, N первых символов которой меньше искомой, сразу идет запись, которая
лексикографически больше искомой, то на этой странице и во всем файле искомой
записи нет.
  При добавлении новой записи в файл проходится цепочка страниц длиной M, где
M - уровень верхней управляющей страницы, и определяется место, куда поместить
новую запись, чтобы она не нарушала порядка сортировки.

                        ЛОГИЧЕСКАЯ ОРГАНИЗАЦИЯ БАЗ ДАННЫХ

  TPS-файл может содержать несколько таблиц данных и для каждой таблицы
данные, ключи/индексы и memo-поля.

                              Типы и форматы записей

  00-F2   - ключи/индексы
  F3      - запись базы данных
  F6      - информационная запись, содержит число записей конкретного типа
  FA      - описание таблицы
  FC      - данные memo-полей

                                   Пустая запись

  Первой записью в файле всегда идет пустая запись:  C0 00 00 00 00

                                 Запись базы данных

                                                  (+0)            (+4)
     C0           3F 00         09 00          00 00 00 01         F3
    BYTE          USHORT        USHORT            ULONG           BYTE
 Идентификатор    Длина      Длина записи    Номер таблицы     Код записи -
                 записи+9   в упр.странице,                     запись БД
                            всегда равна 9

        (+5)           (+9)
     00 00 00 1B       ...
        ULONG
    Номер записи,     Данные
  уникальное число
  для каждой записи

  При добавлении новой записи номер последней записи в заголовке файла увеличи-
вается на единицу (последний байт увеличивается первым, как в процессорах
Motorola), а затем присваивается новой записи. Таким образом достигается
уникальность. При физическом создании файла DOS номер последней записи
устанавливается в 1 (в формате Motorola).
  Длина записи в упр.странице - всегда 9.

                             Запись ключа/индекса

                                        (+0)                 (+4)
      C0          19 00     19 00    00 00 00 01              01
     BYTE         USHORT    USHORT      ULONG                BYTE
 Идентификатор                      Номер таблицы   Код записи, одновременно
                                                     порядковый номер ключа

       (+5)                    (+?)
   80 02 80 05 05  ...     00 00 00 1B
                               ULONG
      Данные              Номер записи БД

  Сортировка в ключе/индексе производится благодаря обязательной сортировке
всех записей в файле. Длина этой записи в управляющей странице равна длина
записи в обычной странице, если ключ имеет атрибут DUP, и меньше ее на 4 в
противном случае (очевидно, в TPS-файле не должно быть двух одинаковых
записей).
  Замечание: если номер записи в индексе ссылается на несуществующую запись БД
(если его исправить вручную), то при следующих построениях индекса Clarion
Database Manager'ом она иногда удалена не будет (почему?).

                                Запись memo-поля

                            (+0)           (+4)             (+5)
  C0   0C 01    0C 00    00 00 00 01        FC           00 00 00 02
 BYTE  USHORT   USHORT      ULONG          BYTE             ULONG
                      Номер таблицы   Код записи -     Номер записи БД,
                                       данные memo    к которой относится
                                                         это memo-поле

          (+9)                  (+0Ah)               (+0Ch)
           00                    00 01                ...
          BYTE                   USHORT
     Порядковый номер       Номер блока memo,      Данные memo-поля
        memo-поля          посл.байт изменяется
   (у записи может быть          первым
 больше одного memo-поля)

  Данные memo следуют блоками по 256 байт (в последнем блоке может быть меньше)
Номер блока указывается в поле (+0Ah) (последний байт которого изменяется
первым). Длина этой записи в упр.странице - всегда 12.

                               Информационная запись

                            (+0)           (+4)               (+5)
  C0   0E 00   06 00    00 00 00 01         F6                 01
 BYTE  USHORT  USHORT      ULONG           BYTE               BYTE
                       Номер таблицы    Код записи -   Код записей, к которым
                                       информационная   относится информация:
                                           запись        00-F2 - ключи/индексы
                                                         F3    - данные

        (+6)               (+0Ah)
    05 00 00 00         00 00 00 00
       ULONG                ULONG
   Число записей      Запись, к которой
   с этим кодом        было обращение

  По одной записи этого типа создается для каждого ключа/индекса и для данных
таблицы. Код записей, для которых создается эта запись, указывается в поле по
смещению +5. Длина этой записи в упр.странице - всегда 6.
  Запись, к которой было обращение, равна 0, если индекс не требует перестро-
ения, и содержит номер записи БД, к которой первый раз обратились после
последнего перестроения индекса. Всегда равно 0 для ключей и данных таблицы.

                           Описание структуры таблицы

                            (+0)         (+4)        (+5)         (+7)
  C0   1A 00   07 00    00 00 00 01       FA         00 00        01 00
 BYTE  USHORT  USHORT      ULONG         BYTE        USHORT       USHORT
                       Номер таблицы  Код записи -   Номер      Минимальная
                                       описание      блока    версия драйвера
                                       структуры    описания    для работы

  3F 00      07 00    01 00    07 00
  USHORT     USHORT   USHORT   USHORT
   Длина     Число    Число    Число
  записи в   полей     memo    ключей/
  таблице                     индексов

  Данные описания структуры следуют блоками по 512 байт (в последнем блоке
может быть меньше) (аналогично memo). Номер блока указывается в поле (+5).
Длина каждой такой записи в упр.странице - всегда 7. В поле (+7) стоит
минимальная версия драйвера для работы с файлом:
  1 = TopSpeed 1.0 из пакета Clarion 3.1
  2 = TopSpeed из пакета Clarion for Window 1.5

  Описание полей
  --------------

   (+0)          (+1)           (+3)         (+n)           (+n+2)
    12          00 00         FIELD1 00      01 00          14 00
   BYTE         USHORT         CSTRING       SHORT          SHORT
   Тип       Смещение поля     Название   Число эл-тов   Длина всего
   поля     от начала записи     поля       в массиве      массива

         (+n+4)               (+n+6)
         00 00                01 00
         USHORT               USHORT
            ?               Порядковый
  равно 1, если это поле   номер поля
    перекрывает другое      в записи
    поле (атрибут OVER)
  равно 0 в пр.случае

  Поле (+n) содержит 1, если это поле не массив, размерность для одномерного
массива и произведение размерностей для многомерного размера. Следующее поле
содержит размер всего массива, т.е.размер одного эл-та, умноженный на содер-
жимое поля (+n+2).
  Если файл имеет префикс, то он указывается в каждом имени поля, например:
"TST:FIELD1". Если префикса нет, то пишется просто "FIELD1". Префикс полей
никак не учитывается после создания.
  Замечание: если в поле (+n+4) поместить любое не равное 0 значение, то это
будет действовать также, как и единица. Однако стандартные средства помещают 1.

  Типы полей
  ----------

 Тип  Размер   Название    Описание
 ---  ------   --------    --------
  01     1      BYTE       число без знака
  02     2      SHORT      число со знаком в формате Intel 8086
  03     2      USHORT     SHORT без знака
  06     4      LONG       число со знаком в формате Intel 8086
  07     4      ULONG      LONG без знака
  08     4      SREAL      формат single сопроцессора Intel 8087
  09     8      REAL       формат double сопроцессора Intel 8087

  0A     ?      DECIMAL    дополнительные данные:

                                   (+n+8)                (+n+9)
                                     02                    05
                                    BYTE                  BYTE
                                 Число знаков         Длина одного
                              после десятич.точки   элемента массива

  DECIMAL - это число с фиксированной точкой в формате BCD, один байт содержит
  две цифры, старший ниббл старшего байта содержит знак (0-плюс, другое-минус).
  Замечание: Clarion записывает в качестве минуса 0xF. Старший байт хранится
  первым (с наименьшим смещением). Размер данных вычисляется по формуле:
      (число_знаков_до_точки + число_знаков_после_точки)/2 + 1
  Максимальная длина - 16 байт.

  12     ?      STRING      дополнительные данные:

                               (+n+8)        (+n+10)
                               14 00          00 00
                               USHORT           ?
                             Длина одного     Шаблон
                             эл-та массива    picture

       Если описываемое поле - массив, то (+n+8) - длина одного его элемента.
       Если строка имеет шаблон, то он должен быть указан в поле (+n+10), без
       знака @ и завершающийся одним нулем. Если шаблона нет, то поле (+n+10)
       содержит 2 байта: первый - нуль, второй - любое число (Clarion 3.1
       записывает 0). Почему два байта - непонятно.

  12     ?      PICTURE     дополнительные данные:

                               (+n+8)           (+n+10)
                               09 00         p####-####p 00
                               USHORT            CSTRING
                             Длина одного        picture
                             эл-та массива

  13     ?      CSTRING     дополнительные данные: см. STRING или PICTURE
                            CSTRING - строка, заканчивающаяся нулем.

  14     ?      PSTRING     дополнительные данные: см. STRING или PICTURE
                            PSTRING - строка, первый байт которой - длина
                            Размер поля PSTRING - макс.длина строки плюс 1.

  16     ?      GROUP       дополнительных данных нет

      GROUP представляется как независимое от вложенных в него полей поле.
    Оно просто перекрывает другие поля (с помощью указания смещения и размера).
    Номер ему присваивается также, как и другим полям, независимо от других
    полей. Располагается непосредственно перед подчиненными полями, которые
    следуют за ним. Номера подчиненным полям присваюваются, как будто они не
    входят в GROUP. Если группа имеет префикс, это указывается в названии
    подчиненных полей и замещает префикс файла, например: "GRP:FIRST_FIELD".
    Если группа не имеет префикса, на ее поля имеют тот же префикс, что у
    основного файла. Если и у основного файла нет префикса, то ее поля не
    имеют никакого префикса. Префикс полей группы никак не учитывается после
    создания.
      При создании массива GROUP размерность его указывается в поле (+n) в
    описании поля GROUP. Больше ссылок на то, что это массив, нет. Для
    подчиненных элементов смещение указывается как для первого элемента
    массива. Подчиненное поле из первого элемента массива может даже входить
    в ключ.

  Описание memo
  -------------

         (+0)               (+n)          (+m)        (+m+2)
      DATA.MEM 00       FILE_MEMO 00      10 27       01 00
        CSTRING            CSTRING        USHORT      USHORT
   Название внешнего      Название         Длина     Атрибуты
    файла для memo        memo-поля      memo-поля

  Если есть имя внешнего файла (external name), то оно записывается в поле (+0)
и завершается одним нулем. Если имя внешнего файла отсутствует, то поле (+0)
содержит 2 байта: первый из них - нуль, второй - любой (Clarion 3.1 пишет 1).
Пример:

          (+0)          (+n)          (+m)     (+m+2)
         00 01      FILE_MEMO 00      10 27     01 00

  Замечание: в поле (+m+2) программой, написанной на Clarion 3.1, записывается
значение 1, если memo-поле не имеет атрибута BINARY, и 2, если имеет. Clarion
Database Manager 3.1 пишет сюда всегда 1. Это поле ни программой, ни Database
Manager'ом не распознается (здесь может быть любое значение).
  Для версии драйвера 2 (Clarion for Windows 1.5) байт атрибутов представляется
так:
        0 0 0 0 0 1 0 1
                  │ │ L-- всегда 1
                  │ L---- 1 = есть атрибут BINARY
                  L------ 1 = это BLOB, 0 = это MEMO

  Для BLOB длина memo-поля равна 0.

Замечание: при импорте структуры файла CfW 1.5 нигде не учитывает байт
           атрибутов.

  Описание ключа/индекса
  ----------------------

   (+0)       (+n)      (+m)    (+m+1)        г============================┐
   00 01     KEY1 00     21     02 00         │     АТРИБУТЫ KEY/INDEX     │
     ?       CSTRING    BYTE    USHORT        │                            │
 Название   Название  Атрибуты  Число         │      0 0 1 0 0 0 0 1       │
 внешнего     ключа             полей         │        L-+     │ │ L- DUP  │
  файла,                        в ключе       │  0 = KEY       │ L--- OPT  │
 см.memo                                      │  1 = INDEX     L-- NOCASE  │
                                              │  2 = Dynamic index         │
  Дальше для кажного поля в ключе/индексе     L============================-
  следует запись

    01 00     00 00
    USHORT    USHORT
     Номер   Атрибуты        Атрибуты:  0    = ASCENDING
     поля                               не 0 = DESCENDING

  Для Dynamic index число полей всегда 0. Неизвестно, где хранятся данные
Dynamic index. Если атрибуты - не 0 (совершенно любое число), то поле считается
DESCENDING.
  Замечание: если в поле (+0) содержится 00 00, то Clarion 3.1 при импорте
структуры считает, что у ключа/индекса есть внешнее имя "". Другие значения
второго байта (00 02, 00 03 и т.д.) распознаются правильно. У memo-полей
значение 00 00 распознается правильно.

                               Название таблицы

  Последними записями в файле идут названия таблиц

                               (+0)            (+1)         (+n)
  C0   0C 00   08 00            FE            UNNAMED    00 00 00 01
 BYTE  USHORT  USHORT          BYTE            STRING       ULONG
       Длина   Длина       Показывает, что    Название    Код файла
       записи  записи       это название      таблицы     для этой
               в упр.         таблицы                      таблицы
              странице

  Байт по смещению (+0) показывает, что эта запись - название таблицы. Этим
байтом не должен начинаться ни один номер таблицы. Отчасти поэтому при
увеличении номера записи последний байт изменяется первым. Длина названия
таблицы вычисляется как длина_записи минус 5, а длина записи в упр.странице -
как длина_записи минус 4.
  При создании таблицы функцией CREATE ее номер вычисляется как номер следующей
записи (берется номер последней записи из заголовка, увеличивается на 1,
записывается обратно в заголовок и считается номером таблицы).

                   Представление полей в ключах и индексах

  ASCENDING

      BYTE, STRING,      Не меняются, GROUP рассматривается как STRING, даже
      PICTURE, GROUP     байты у входящих в нее чисел не переставляются.

      CSTRING            Неиспользуемые байты с правого края забиваются нулями.

      PSTRING            Байт длины не указывается, неиспользуемые символы
                         с правого края забиваются нулями, добавляется еще один
                         нуль с правого края, чтобы длина строки в ключе была
                         равна длине строки в записи таблицы.

      USHORT, ULONG      Байты переставляются задом наперед

      SHORT, LONG        Старший бит старшего байта инвертируется, байты
                         переставляются

      REAL, SREAL        Если число положительное, то старший бит старшего
                         байта инвертируется. В противном случае все биты
                         инвертируются. Байты переставляются.

      DECIMAL            Если число положительное, то старший бит старшего
                         байта инвертируется. В противном случае старший ниббл
                         становится равным 7, и инвертируются все остальные
                         биты

  DESCENDING

      BYTE, SHORT, LONG, USHORT, ULONG, REAL, SREAL, STRING, CSTRING,
      PSTRING, DECIMAL   То же, что и ACSENDING, только каждый бит
                         инвертируется

      Замечание: если число DECIMAL отрицательное, то старший ниббл равен
                 8, остальные биты остаются без изменения. Фактически меняем
                 знак числа, а дальше строим как для ASCENDING.
      Замечание: если число REAL/SREAL отрицательное, то просто переставляются
                 байты. Фактически меняем знак числа, а дальше строим как для
                 ASCENDING.

                                 Примечания

  Атрибуты RECLAIM, CREATE не изменяют содержимое файла, точно также, как и
процедуры LOCK, UNLOCK, HOLD, RELEASE.
  Неясно до конца, для каких целей в заголовке файла используются две длины
файла. При обработке транзакции заголовок файла копируется сразу за последней
страницей файла (т.е. по адресу, указанному в поле (+6)). За заголовком идут
еще какие-то данные (страницы). В этом новом заголовке поле (+6) остается
прежним, а поле (+0Ah) показывает новую длину файла вместе с записанными
данными. Т.е. первая из длин - длина без "неиспользуемого" в конце файла
пространства.