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.