ZIP файл состоит из трех областей:
- сжатые/несжатые данные, (последовательность структур типа
LocalFileHeader
, сами данные и необязательных DataDescriptor
)
- центральный каталог (последовательность структур
CentralDirectoryFileHeader
)
- описание центрального каталога (
End of central directory record (EOCD)
)
С начала файла идет набор из LocalFileHeader
, непосредственно данные и (необязательно) структура Data descriptor
. Затем структуры типа CentralDirectoryFileHeader
для каждого файла и папки в ZIP архиве и завершает все это структура End of central directory record
.
Local File Header
Используется для описания метаданных файла (имя файла, контрольная сумма, время и дата модификации, сжатый/несжатый размер). Как правило сразу после этой структуры следует содержимое файла.
LocalFileHeader
struct LocalFileHeader
{
// Обязательная сигнатура, равна 0x04034b50
uint32_t signature;
// Минимальная версия для распаковки
uint16_t versionToExtract;
// Битовый флаг
uint16_t generalPurposeBitFlag;
// Метод сжатия (0 - без сжатия, 8 - deflate)
uint16_t compressionMethod;
// Время модификации файла
uint16_t modificationTime;
// Дата модификации файла
uint16_t modificationDate;
// Контрольная сумма
uint32_t crc32;
// Сжатый размер
uint32_t compressedSize;
// Несжатый размер
uint32_t uncompressedSize;
// Длина название файла
uint16_t filenameLength;
// Длина поля с дополнительными данными
uint16_t extraFieldLength;
// Название файла (размером filenameLength)
uint8_t *filename;
// Дополнительные данные (размером extraFieldLength)
uint8_t *extraField;
}; |
struct LocalFileHeader
{
// Обязательная сигнатура, равна 0x04034b50
uint32_t signature;
// Минимальная версия для распаковки
uint16_t versionToExtract;
// Битовый флаг
uint16_t generalPurposeBitFlag;
// Метод сжатия (0 - без сжатия, 8 - deflate)
uint16_t compressionMethod;
// Время модификации файла
uint16_t modificationTime;
// Дата модификации файла
uint16_t modificationDate;
// Контрольная сумма
uint32_t crc32;
// Сжатый размер
uint32_t compressedSize;
// Несжатый размер
uint32_t uncompressedSize;
// Длина название файла
uint16_t filenameLength;
// Длина поля с дополнительными данными
uint16_t extraFieldLength;
// Название файла (размером filenameLength)
uint8_t *filename;
// Дополнительные данные (размером extraFieldLength)
uint8_t *extraField;
};
Сразу после этой структуры идут данные размером
compressedSize
при использовании сжатия или размером
uncompressedSize
в противном случае.
Иногда бывает невозможно вычислить данные на момент записи LocalFileHeader
, тогда в crc32
, compressedSize
и uncompressedSize
записываются нули, третий бит в generalPurposeBitFlag
ставится в единицу, а после LocalFileHeader
добавляется структура типа DataDescriptor
.
Data descriptor
Если по какой-то причине содержимое файла невозможно создать одновременно с заголовком типа LocalFileHeader
, то сразу после него следует структура DataDescriptor
, где идет находится дополнение метаданных для LocalFileHeader
(контрольная сумма, сжатый/несжатый размер).
Откровенно говоря, мне такие файлы не попадались, поэтому больше того, чем написано в википедии сказать не могу.
DataDescriptor
struct DataDescriptor
{
// Необязательная сигнатура, равна 0x08074b50
uint32_t signature;
// Контрольная сумма
uint32_t crc32;
// Сжатый размер
uint32_t compressedSize;
// Несжатый размер
uint32_t uncompressedSize;
}; |
struct DataDescriptor
{
// Необязательная сигнатура, равна 0x08074b50
uint32_t signature;
// Контрольная сумма
uint32_t crc32;
// Сжатый размер
uint32_t compressedSize;
// Несжатый размер
uint32_t uncompressedSize;
};
Central directory file header
Расширенное описание метаданных файла. Содержит дополненную версию LocalFileHeader
(добавляются поля номер диска, файловые атрибуты, смещение до LocalFileHeader
от начала ZIP файла).
CenterDirectoryFileHeader
struct CentralDirectoryFileHeader
{
// Обязательная сигнатура, равна 0x02014b50
uint32_t signature;
// Версия для создания
uint16_t versionMadeBy;
// Минимальная версия для распаковки
uint16_t versionToExtract;
// Битовый флаг
uint16_t generalPurposeBitFlag;
// Метод сжатия (0 - без сжатия, 8 - deflate)
uint16_t compressionMethod;
// Время модификации файла
uint16_t modificationTime;
// Дата модификации файла
uint16_t modificationDate;
// Контрольная сумма
uint32_t crc32;
// Сжатый размер
uint32_t compressedSize;
// Несжатый размер
uint32_t uncompressedSize;
// Длина название файла
uint16_t filenameLength;
// Длина поля с дополнительными данными
uint16_t extraFieldLength;
// Длина комментариев к файлу
uint16_t fileCommentLength;
// Номер диска
uint16_t diskNumber;
// Внутренние аттрибуты файла
uint16_t internalFileAttributes;
// Внешние аттрибуты файла
uint32_t externalFileAttributes;
// Смещение до структуры LocalFileHeader
uint32_t localFileHeaderOffset;
// Имя файла (длиной filenameLength)
uint8_t *filename;
// Дополнительные данные (длиной extraFieldLength)
uint8_t *extraField;
// Комментарий к файла (длиной fileCommentLength)
uint8_t *fileComment;
}; |
struct CentralDirectoryFileHeader
{
// Обязательная сигнатура, равна 0x02014b50
uint32_t signature;
// Версия для создания
uint16_t versionMadeBy;
// Минимальная версия для распаковки
uint16_t versionToExtract;
// Битовый флаг
uint16_t generalPurposeBitFlag;
// Метод сжатия (0 - без сжатия, 8 - deflate)
uint16_t compressionMethod;
// Время модификации файла
uint16_t modificationTime;
// Дата модификации файла
uint16_t modificationDate;
// Контрольная сумма
uint32_t crc32;
// Сжатый размер
uint32_t compressedSize;
// Несжатый размер
uint32_t uncompressedSize;
// Длина название файла
uint16_t filenameLength;
// Длина поля с дополнительными данными
uint16_t extraFieldLength;
// Длина комментариев к файлу
uint16_t fileCommentLength;
// Номер диска
uint16_t diskNumber;
// Внутренние аттрибуты файла
uint16_t internalFileAttributes;
// Внешние аттрибуты файла
uint32_t externalFileAttributes;
// Смещение до структуры LocalFileHeader
uint32_t localFileHeaderOffset;
// Имя файла (длиной filenameLength)
uint8_t *filename;
// Дополнительные данные (длиной extraFieldLength)
uint8_t *extraField;
// Комментарий к файла (длиной fileCommentLength)
uint8_t *fileComment;
};
End of central directory record (EOCD)
Эта структура записывается в конце файла. Содержит следующие поля: номер текущего диска, количество записей CentralDirectoryFileHeader
в текущем диске, общее количество записей CentralDirectoryFileHeader
.
EOCD
struct EOCD
{
// Обязательная сигнатура, равна 0x06054b50
uint32_t signature;
// Номер диска
uint16_t diskNumber;
// Номер диска, где находится начало Central Directory
uint16_t startDiskNumber;
// Количество записей в Central Directory в текущем диске
uint16_t numberCentralDirectoryRecord;
// Всего записей в Central Directory
uint16_t totalCentralDirectoryRecord;
// Размер Central Directory
uint32_t sizeOfCentralDirectory;
// Смещение Central Directory
uint32_t centralDirectoryOffset;
// Длина комментария
uint16_t commentLength;
// Комментарий (длиной commentLength)
uint8_t *comment;
}; |
struct EOCD
{
// Обязательная сигнатура, равна 0x06054b50
uint32_t signature;
// Номер диска
uint16_t diskNumber;
// Номер диска, где находится начало Central Directory
uint16_t startDiskNumber;
// Количество записей в Central Directory в текущем диске
uint16_t numberCentralDirectoryRecord;
// Всего записей в Central Directory
uint16_t totalCentralDirectoryRecord;
// Размер Central Directory
uint32_t sizeOfCentralDirectory;
// Смещение Central Directory
uint32_t centralDirectoryOffset;
// Длина комментария
uint16_t commentLength;
// Комментарий (длиной commentLength)
uint8_t *comment;
};
Папки в ZIP файле представлены двумя структурами LocalFileHeader
и CentralDirectoryFileHeader
с нулевым размером и контрольной суммой. Название папки заканчивается слешем «/».