ZIP-Archiv
ZIP ist ein Archiv- und Container-Format, das 1989 von Phil Katz (PKWARE) entworfen wurde. Eine ZIP-Datei bΓΌndelt mehrere Dateien und Ordner und komprimiert sie β ΓΌblicherweise mit DEFLATE, demselben Verfahren, das auch in PNG steckt.
Das Besondere am Aufbau: ZIP wird βvon hintenβ gelesen. Am Dateiende steht das End of Central Directory (EOCD). Es verweist auf das Central Directory β ein Inhaltsverzeichnis aller enthaltenen EintrΓ€ge. So lΓ€sst sich ein Archiv schnell durchsuchen, ohne alle Daten zu lesen.
Jeder Eintrag besteht aus einem Local File Header direkt vor den komprimierten Daten und einem zugehΓΆrigen Eintrag im zentralen Verzeichnis. Alle Mehrbyte-Zahlen sind Little-Endian.
50 4B 03 04 Β βΒ P K \x03 \x04π§© Aufbau des Archivs
Header + Daten je Datei, danach das zentrale Inhaltsverzeichnis und der Abschluss.
π Ablaufdiagramm (ASCII)
Wichtig: Ein Reader beginnt am Ende der Datei beim EOCD.
ββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ
β PK 03 04 Local File Header (Datei A) β
β ββ Methode, CRC-32, comp/uncomp GrΓΆΓe, Name β
β <DEFLATE> komprimierte Daten von Datei A β
ββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ€
β PK 03 04 Local File Header (Datei B) β
β <DEFLATE> komprimierte Daten von Datei B β
ββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ€
β PK 01 02 Central Directory Entry (Datei A) ββ Offset βββ β
β PK 01 02 Central Directory Entry (Datei B) β β β
βββββββββββββββββββββββββββββββββββββββββββββββββ β β
β PK 05 06 End Of Central Directory ββββββββββββββββββββββ β
β (#EintrΓ€ge, GrΓΆΓe & Offset des Central Directory) β
ββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ
β² Leser startet HIER (am Dateiende) und springt rΓΌckwΓ€rtsπ Tabellen & Referenz
Die drei Kernsignaturen (Little-Endian)
| Hex | ASCII | Record |
|---|---|---|
| 50 4B 03 04 | PKβ₯β¦ | Local File Header |
| 50 4B 01 02 | PKβΊβ» | Central Directory Header |
| 50 4B 05 06 | PKβ£β | End of Central Directory |
| 50 4B 07 08 | PKβ’β’ | Data Descriptor (optional) |
Wichtige Kompressionsmethoden
| Code | Methode | Bemerkung |
|---|---|---|
| 0 | Stored | unkomprimiert (nur gespeichert) |
| 8 | Deflate | Standard β LZ77 + Huffman (wie PNG) |
| 9 | Deflate64 | erweiterte Variante |
| 12 | BZIP2 | selten |
| 14 | LZMA | hohe Kompression, optional |
β¨οΈ C-Strukturen & Auslese-Code
Die struct-Definitionen entsprechen exakt dem Byte-Layout der Records.
#include <stdint.h>
#pragma pack(push, 1) /* exakt am Byte-Layout ausrichten */
typedef struct {
uint32_t signature; /* 0x04034B50 ("PK\3\4") */
uint16_t version_needed;
uint16_t flags;
uint16_t compression; /* 0 = Stored, 8 = Deflate */
uint16_t mod_time;
uint16_t mod_date;
uint32_t crc32; /* PrΓΌfsumme der unkompr. Daten */
uint32_t comp_size; /* komprimierte GrΓΆΓe */
uint32_t uncomp_size; /* OriginalgrΓΆΓe */
uint16_t name_len; /* LΓ€nge des Dateinamens */
uint16_t extra_len; /* LΓ€nge des Extra-Feldes */
/* char filename[name_len]; */
/* char extra[extra_len]; */
} zip_local_header_t;
#pragma pack(pop)βΉοΈ Achtung: ZIP speichert alle Zahlen Little-Endian. signature == 0x04034B50, wenn als uint32 gelesen.
#pragma pack(push, 1)
typedef struct {
uint32_t signature; /* 0x02014B50 ("PK\1\2") */
uint16_t version_made_by;
uint16_t version_needed;
uint16_t flags;
uint16_t compression;
uint16_t mod_time, mod_date;
uint32_t crc32;
uint32_t comp_size, uncomp_size;
uint16_t name_len, extra_len, comment_len;
uint16_t disk_start;
uint16_t internal_attr;
uint32_t external_attr;
uint32_t local_header_offset; /* Position des Local Headers */
} zip_central_header_t;
typedef struct {
uint32_t signature; /* 0x06054B50 ("PK\5\6") */
uint16_t disk_number;
uint16_t cd_start_disk;
uint16_t cd_entries_disk;
uint16_t cd_entries_total; /* Anzahl EintrΓ€ge im Archiv */
uint32_t cd_size; /* GrΓΆΓe des Central Directory */
uint32_t cd_offset; /* Offset zum Central Directory */
uint16_t comment_len;
} zip_eocd_t;
#pragma pack(pop)#include <stdio.h>
/* Sucht 0x06054B50 ("PK\5\6") rΓΌckwΓ€rts und liefert dessen Offset. */
long zip_find_eocd(FILE *f) {
fseek(f, 0, SEEK_END);
long size = ftell(f);
long max_back = size < 65557 ? size : 65557; /* 22 + max. Kommentar */
for (long off = size - 22; off >= size - max_back; off--) {
fseek(f, off, SEEK_SET);
uint32_t sig;
fread(&sig, 4, 1, f);
if (sig == 0x06054B50) return off; /* gefunden */
}
return -1; /* keine gΓΌltige ZIP-Struktur */
}βΉοΈ Da ein Kommentar folgen kann, sucht man die EOCD-Signatur rΓΌckwΓ€rts vom Dateiende.