Краткое описание формата файлов *.1CD (файловых баз 1Сv8)

После того, как я выложил свою программку Tool_1CD ( http://infostart.ru/projects/3851/ ), оказалось, что интерес к формату файлов 1CD достаточно велик. Поэтому для всех желающих продолжить разбираться с форматом, или желающих написать свою программу, выкладываю свои текущие знания об этом формате.
2 тыс. 197

После того, как я выложил свою программку Tool_1CD ( http://infostart.ru/projects/3851/ ), оказалось, что интерес к формату файлов 1CD достаточно велик. Поэтому для всех желающих продолжить разбираться с форматом, или желающих написать свою программу, выкладываю свои текущие знания об этом формате.

Описание формата приведено в терминах языка C. Размер типа char – 1 байт, размер типа short int – 2 байта, размер типа int и unsigned int – 4 байта. Префиксом 0x обозначаются шестнадцатеричные числа.

Файлы баз *.1CD состоят из блоков длиной 4096 байт (0x1000). Соответственно, длина файла всегда кратна 4096.

Блок 0

Нулевой блок имеет следующую структуру:

struct {

char sig[8]; // сигнатура “1CDBMSV8”

char ver1;

char ver2;

char ver3;

char ver4;

unsigned int length;

int unknown;

}

Первые 8 байт – сигнатура базы «1CDBMSV8».

Следующие 4 байта - это версия базы. На данный момент мне встречались только версия «8.0.5.0» (ver1 = 8, ver2 = 0, ver3 = 5, ver4 = 0) – это базы 1Cv8.0 и версия «8.1.0.0» (ver1 = 8, ver2 = 1, ver3 = 0, ver4 = 0) – это базы 1Cv8.1 и 1Cv8.2.

Следующие 4 байт – длина базы (файла) в блоках.

Предназначение поля unknown неизвестно, всегда содержит 1.

Объекты

Вся остальная информация в базе хранится в объектах (файлах базы). Каждый объект состоит из одного или более блоков. У каждого объекта есть один заголовочный блок, блоки с таблицей размещения, и собственно данные. Второе и третье может отсутствовать.

Структура первого блока каждого объекта такова:

struct {

char sig[8]; // сигнатура “1CDBOBV8”

int length; // длина содержимого объекта

int version1;

int version2;

unsigned int version;

unsigned int blocks[1018];

}

Первые 8 байт – сигнатура базы «1CDBOBV8».

Есть 2 типа объектов.

Блок 1. Таблица свободных блоков

Первый тип объекта – это таблица свободных блоков. Признаком этого блока является поле version равное 0. Такой объект в базе всегда один, и его заголовочный блок располагается всегда в блоке со смещением 1 (т.е. по адресу 0x1000). Длина данных такого объекта равна (length * 4) байт.

В blocks содержатся номера блоков, в которых собственно и находится содержимое таблицы свободных блоков. Значащими являются ненулевые значения в массиве blocks. Содержимое таблицы свободных блоков – это просто массив номеров свободных блоков:

unsigned int free_blocks[length];

Таким образом, в базе содержатся ровно length свободных блоков.

Когда системе требуется новый блок для данных, то она берет последний свободный блок из массива free_blocks и уменьшает length на 1. Если свободных блоков нет, то он создается в конце файла базы. Блоки, содержащиеся в массиве blocks, не являются свободными, а принадлежат объекту – таблице свободных блоков. В blocks может содержаться больше блоков, чем необходимо для хранения массива free_blocks.

Остальные объекты

Второй тип объектов характеризуется ненулевым значением поля version. Вся информация в базе, кроме блока 0 и таблицы свободных блоков хранится именно в таких объектах.

В поле length содержится длина в байтах данных объекта.

В массиве blocks находятся индексы блоков, содержащих таблицу размещения данных объекта. Каждый блок, указанный в blocks, и являющийся частью таблицы размещения, имеет следующую структуру:

struct {

int numblocks;

unsigned int datablocks[1023];

}

Поле numblocks указывает количество реальных значений в datablocks (от 1 до 1023). В datablocks содержатся индексы блоков, в которых находится собственно содержимое объекта (данные). Так как в одном блоке таблицы размещения может быть указано максимум 1023 блока с данными, то соответственно, максимальная длина данных, указанных в одном блоке таблицы размещения равна 1023 * 4096 = 4190208 байт (0x3ff * 0x1000 = 0x3ff000). Таким образом, из длины содержимого объекта length мы можем определить количество фактических значений в blocks. Если length равен 0, то в blocks нет значащих данных, иначе количество значений в blocks равно (length - 1) / 0x3ff000 + 1 (деление целочисленное, без остатка). А также можно вычислить максимальную длину данных одного объекта: 4190208 * 1018 = 4265631744 байт (1018 – максимальное количество значений в массиве blocks), это совсем немного меньше 4х гигабайт.

Повторим, в заголовочном блоке объекта находится массив blocks, содержащий индексы блоков с таблицей размещения. А в таблице размещения находятся блоки, содержащие сами данные.

Блок 2. Корневой объект

Последним объектом с предопределенным расположением является корневой объект. Заголовочный блок корневого объекта располагается в блоке с индексом 2. Все остальные объекты базы могут быть получены через корневой объект. Структура данных этого объекта зависит от версии базы, хотя и различается несильно. Для версии базы «8.0.5.0» эта структура выглядит так:

struct {

char lang[8];

int numblocks;

int tableblocks[numblocks];

}

Для версии «8.1.0.0» структура выглядит так:

struct {

char lang[32];

int numblocks;

int tableblocks[numblocks];

}

Т.е. различаются эти структуры только длиной поля lang. В поле lang содержится код языка базы. Код языка базы представляет собой строку в ANSI-кодировке. Мне встречались только базы с кодами «ru_RU» и «en». На что влияют эти коды языка, я не знаю, возможно, на порядок сортировки строк при построении индексов.

В поле numblocks содержится количество элементов в массиве tableblocks. В массиве же tableblocks содержатся индексы объектов, содержащих все таблицы данных. Т.е. таблиц в базе ровно numblocks.

Объект таблицы

Каждый объект таблицы, указанный в корневом объекте, содержит просто текстовое описание таблицы в Unicode. Вот пример описания таблицы:

{"_Reference4",0,

{"Fields",

{"_IDRREF","B",0,16,0,"CS"},

{"_VERSION","RV",0,0,0,"CS"},

{"_MARKED","L",0,0,0,"CS"},

{"_ISMETADATA","L",0,0,0,"CS"},

{"_CODE","NC",0,9,0,"CI"},

{"_DESCRIPTION","NVC",0,25,0,"CI"},

{"_FLD7","I",1,0,0,"CS"}

},

{"Indexes",

{"_IDRREFIDX",1,

{"_IDRREF",16}

},

{"_REFERENCE4_CODE_SR",0,

{"_CODE",9},

{"_IDRREF",16}

},

{"_REFERENCE4_DESCR_SR",0,

{"_DESCRIPTION",25},

{"_IDRREF",16}

}

},

{"Recordlock","0"},

{"Files",118,119,96}

}

Как видно из этого примера, здесь присутствуют имя таблицы (_Reference4), раздел описания полей таблицы (Fields), раздел описания индексов (Indexes), параметр Recordlock и раздел Files.

В разделе Files всегда содержатся три числа, которые содержат индексы заголовочных блоков объектов (по порядку) с записями таблицы, Blob-данными (строки неограниченной длины и двоичные данные) и индексами. Если какого-либо объекта у таблицы нет, то соответствующее число равно нулю.

В разделе Fields содержатся описания полей таблицы. Описание каждого поля содержит (по порядку): имя поля (FieldName), тип поля (FieldType), признак использования NULL (NullExists), длину (FieldLength), точность (FieldPrecision) и признак регистрочувствительности (FieldCaseSensitive).

Сколько байт занимает каждое поле в записи, и как его интерпретировать, зависит от параметров поля. Во-первых, если NullExists у поля равен 1, то первый байт поля является признаком NULL. Значение 0 этого байта означает, что поле не содержит значение (т.е. содержит NULL). В противном случае, поле содержит значение. Если же NullExists равен 0, то такого байта в поле нет.

Далее, размер и формат поля зависит от типа поля. Типы поля бывают такими:

  • «B» - двоичные данные. Длина поля равна FieldLength байт.
  • «L» - булево. Длина поля 1 байт. Нулевое значение байта означает Ложь, иначе Истина.
  • «N» - число. Длина поля в байтах равна Цел((FieldLength + 2) / 2). Числа хранятся в двоично-десятичном виде. Первый полубайт означает знак числа. 0 – число отрицательное, 1 – положительное. Каждый следующий полубайт соответствует одной десятичной цифре. Всего цифр FieldLength. Десятичная точка находится в FieldPrecision цифрах справа. Например, FieldLength = 5, FieldPrecision = 3. Байты 0x18, 0x47, 0x23 означают число 84.723, а байты 0x00, 0x00, 0x91 представляют число -0.091.
  • «NC» - строка фиксированной длины. Длина поля равна FieldLength * 2 байт. Представляет собой строку в формате Unicode (каждый символ занимает 2 байта).
  • «NVC» - строка переменной длины. Длина поля равна FieldLength * 2 + 2 байт. Первые 2 байта содержат длину строки (максимум FieldLength). Оставшиеся байты представляет собой строку в формате Unicode (каждый символ занимает 2 байта).
  • «RV» - версия. Длина поля 16 байт. Предположительно содержит четыре числа int.
  • «NT» - строка неограниченной длины. Длина поля 8 байт. Первые четыре байта содержат начальный индекс блока в объекте Blob таблицы, вторые четыре – длину данных в объекте Blob. В объекте Blob содержится строка в формате Unicode.
  • «I» - двоичные данные неограниченной длины. Длина поля 8 байт. Первые четыре байта содержат начальный индекс блока в объекте Blob таблицы, вторые четыре – длину данных в объекте Blob.
  • «DT» - дата-время. Длина поля 7 байт. Содержит данные в двоично-десятичном виде. Первые 2 байта содержат четыре цифры года, третий байт – две цифры месяца, четвертый байт – день, пятый – часы, шестой – минуты и седьмой – секунды, все также по 2 цифры.

Зная теперь длину в байтах каждого поля можно посчитать общую длину одной записи таблицы и смещение каждого поля в записи. Но для этого необходимо учесть следующее. Если в описании полей таблицы нет поля с типом версия (RV), но при этом параметр Recordlock равен 1, то в записи присутствует дополнительное поле, которое я для себя называю короткая скрытая версия. Длина этого поля равна 8 байт. В каждой записи самый первый байт – это признак удаленности записи (признак, что запись не занята). Если этот байт равен 1, то запись свободна, а следующие 4 байта содержат индекс следующей свободной записи. Из этого следует, что запись не может быть короче пяти байт. Если же первый байт записи содержит 0, то далее в записи следуют значения полей. Причем порядок полей определяется таким образом: превым всегда идет поле версии (или описанное в разделе Fields с типом RV или поле скрытой короткой версии), затем все остальные поля в том порядке, как они описаны в разделе Fields.

Объект записей таблицы

Содержимое объекта записей таблицы содержит просто массив записей. Таким образом, длина данных этого объекта всегда кратна длине одной записи. Первая (точнее нулевая) запись всегда помечена как свободная, она содержит индекс следующей свободной записи (или 0, если таких нет). Т.е. с нее начинается цепочка свободных записей таблицы.

Объект Blob таблицы

Объект содержит Blob-данные таблицы (строки неограниченной длины и двоичные данные неограниченной длины). Содержимое этого объекта состоит из блоков (не путать с блоками, из которых состоит файл 1CD) длиной 256 байт (0x100). Т.е. это просто массив блоков длиной 256 каждый. Поэтому длина данных объекта всегда кратна 256. Структура каждого блока объекта такова:

struct {

unsigned int nextblock;

short int length;

char[250] data;

}

Поле nextblock содержит индекс следующего блока, содержащего продолжение данных, или 0, если следующего блока нет. Поле length содержит длину данных в этом блоке (максимум 250). Поле data содержит сами данные. Нулевой блок всегда считается свободным, в поле nextblock он содержит индекс следующего свободного блока. Таким образом, с нулевого блока начинается цепочка свободных блоков.

В записях таблицы в полях с типом «NT» и «I» содержится индекс первого блока, с которого начинаются данные, относящиеся к этому полю данной записи.

Объект индексов таблицы

На данный момент структура индексов до конца не изучена.

Начать дискуссию

Примеры задач для обязательного курса «Начинающий предприниматель»

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

Примеры задач для обязательного курса «Начинающий предприниматель»
4
319

Курсы повышения
квалификации

20
Официальное удостоверение с занесением в госреестр Рособрнадзора

Зачем Бенефициара объявляют в международный розыск?

Мнение налогового адвоката

Экономика России

В 2023 году дефицит федерального бюджета составил почти 3,23 трлн рублей

Минфин засекретил часть расходов федерального бюджета, за 2023 год они составили 32,35 трлн рублей. Тогда как на доходы пришлось 29,12 трлн.

Лучшие спикеры, новый каждый день
Банкротство

Совокупные долги банкротов выросли в 2 раза

За 2023 год суд признал порядка 7,3 тысяч компаний несостоятельными. Их задолженность достигла 3,98 трлн рублей.

Общество

На что обратить внимание при покупке загородного дома, дачи или участка

Федеральная нотариальная палата (ФНП) разъяснила, на что обратить внимание при покупке дачи или земельного участка.

Маркетплейсы

У Wildberries появились брендированные грузовики

Автомобили с фирменными логотипами будут доставлять заказы со складов и сортировочных центров до ПВЗ.

Опытом делятся эксперты-практики, без воды

Новые штрафы для бизнеса, банки против маркетплейсов и директор с лапками. Что обсуждали сегодня бухгалтеры. 😺«Ночной бухгалтер» № 1667

Бизнес больше не может звонить и отправлять рассылки по смс и e-mail без предварительного согласия абонента. Банкам не нравится, что маркетплейсы проводят платежи через собственную структуру. Компания ищет сотрудника с лапками, который будет создавать уют, контролировать запасы вкусняшек и обниматься. А также другие новости дня для бухгалтера.

Иллюстрация: создана при помощи ИИ playground.com / Елена Балаклицкая
1
139
Банки

Данные об иностранных поставщиках платежных услуг станут закрытыми

Центробанк закроет доступ к перечню иностранных поставщиков платежных услуг до конца 2024 года.

Бесплатно с Социальные пособия

Новый порядок назначения пособия по уходу за ребенком в 2024 году. Мини-курс

Как назначается пособие по уходу за ребенком по новым правилам в 2024 году, какие документы нужно предоставить, рассказываем в мини-курсе и приводим форму уведомления о прекращение права сотрудника на получение ежемесячного пособия.

Новый порядок назначения пособия по уходу за ребенком в 2024 году. Мини-курс
Бесплатно с КоАП РФ

Новые штрафы в КоАП: за «холодные» звонки могут наказать на миллион, как избежать наказания

17 апреля 2024 года вступили в силу поправки в КоАП. Рассказываем, при каких условиях могут оштрафовать за обзвоны, письма и рассылку смс  и как не попасть под санкции.

Новые штрафы в КоАП: за «холодные» звонки могут наказать на миллион, как избежать наказания

Новостной дайджест: правила переводов с Сбербанке, новые меры поддержки МСБ, план Минэкономразвития, изменения в налогах, форум «Создай НАШЕ»

Самое интересное и важное за день в новостном дайджесте.

46
Банки

RBI: Европейский центральный банк потребует быстрее свернуть бизнес в РФ

Raiffeisen Bank International ждет требования от ЕЦБ ускорить процесс сокращения бизнеса в России.

Миникурсы, текстовые и видеоинструкции для бухгалтеров
Импорт

Вводится режим «параллельного импорта» для зарубежных патентов

Импорт параллельного характера позволяет ввозить в РФ иностранные товары без получения на это согласия от производителя. Такой импорт считается параллельным, так как он осуществляется независимо от официальных каналов через дистрибьюторов.

Иллюстрация: Вера Ревина/Клерк.ру
Мошенничество

Доверительные отношения между ИП и его бухгалтером обошлись предпринимателю в 20,6 млн рублей ущерба

Бухгалтер из Краснодарского края предстанет перед судом по обвинению в неправомерном обороте средств платежей и мошенничестве.

194

Что такое системное мышление и как руководителю научиться использовать его на практике

Мы живем в мире систем. Рабочий коллектив, проектная группа, спортивная команда, семья, зрители в театре, пользователи приложения — мы всегда находимся во взаимодействии с другими людьми и организациями или участвуем в процессах, а значит ведем системную деятельность. И этой деятельностью важно научиться управлять, чтобы достигать своих целей.

Иллюстрация: Вера Ревина/Клерк.ру
Обзоры новостей

⚡️ Итоги дня: «Яндекс» будет продавать товары для взрослых, Китай урезал поставки, а россияне стали чаще пить растворимый кофе и есть лапшу быстрого приготовления

Подготовили обзор главных событий дня. Все самое интересное, что писали и обсуждали в сети, в одной подборке.

1
92
Бухгалтеры

Авито ищет бухгалтеров и специалистов по финансам

Разбирайте горячие вакансии от крупной компании. Авито нужен специалист казначейства, бухгалтер и старший бухгалтер!

Отпуска

Как уйти в отпуск в 2024 году: как написать и подать заявление и рассчитать отпускные

Каждый работник имеет право на отпуск. Рассказываем, какие отпуска бывают, как написать заявление на каждый из них, как оплачивается период отдыха и когда работодатель может отказать в его предоставлении.

Иллюстрация: Вера Ревина/Клерк.ру
Маркетплейсы

Госдума защитит трудовые права работников маркетплейсов

Работодатели скрывают трудовые отношения с сотрудниками маркетплейсов под договорами с самозанятыми. Из-за этого работники не получают отпускных и больничных.

78

Интересные материалы

Бухгалтеры

🔥 Безлимитных консультаций больше не будет! Успейте купить подписку «Клерк.Премиум» с безлимитными консультациями

Воспользуйтесь шансом купить подписку с безлимитными консультациями экспертов «Клерка» до 22 апреля, чтобы задавать вопросы без ограничений.