Чтобы соответствовать требованиям выравнивания базовой платформы, структуры могут иметь байты "заполнения" между элементами, так что каждый элемент начинается с правильно выровненного адреса.
Есть несколько способов обойти это: один - прочитать каждый элемент заголовка отдельно, используя член соответствующего размера:
fread(&p.signature, sizeof p.signature, 1, file);
fread(&p.version, sizeof p.version, 1, file);
...
Другой вариант - использовать битовые поля в определении структуры; на них не распространяются ограничения заполнения. Недостатком является то, что битовые поля должны быть unsigned int
или int
или, по состоянию на C99, _Bool
; вам может потребоваться привести необработанные данные к целевому типу, чтобы правильно их интерпретировать:
typedef struct {
unsigned int signature : 32;
unsigned int version : 16;
unsigned int bit_flag; : 16;
unsigned int compression_method : 16;
unsigned int time : 16;
unsigned int date : 16;
unsigned int crc : 32;
unsigned int compressed_size : 32;
unsigned int uncompressed_size : 32;
unsigned int name_length : 16;
unsigned int extra_field_length : 16;
} ZIP_local_file_header;
Вам также может потребоваться выполнить некоторую замену байтов в каждом элементе, если файл был написан с прямым порядком байтов, но ваша система имеет младший порядок байтов.
Обратите внимание, что name
и extra field
не являются частью определения структуры; когда вы читаете из файла, вы не будете читать указатель значения для имени и дополнительного поля, вы будете читать фактическое содержимое имени и дополнительное поле Поскольку вы не знаете размеры этих полей до тех пор, пока не прочитаете остальную часть заголовка, вам следует отложить их чтение до тех пор, пока вы не прочтете структуру выше. Что-то вроде
ZIP_local_file_header p;
char *name = NULL;
char *extra = NULL;
...
fread(&p, sizeof p, 1, file);
if (name = malloc(p.name_length + 1))
{
fread(name, p.name_length, 1, file);
name[p.name_length] = 0;
}
if (extra = malloc(p.extra_field_length + 1))
{
fread(extra, p.extra_field_length, 1, file);
extra[p.extra_field_length] = 0;
}