Nachfolgend die Spezifikation für C4Group-Dateien. Das Original ist hier zu finden, damit aber eine Weiterentwicklung der Dokumentation möglich ist, schreibe ich das hier noch einmal nieder.
C4Group ist der Name des Gruppendatei-Formats, in dem die Spieldaten von Clonk gepackt sind, also Szenarien (c4s), Rundenordner (c4f), Objektdefinitionen (c4d) usw.
Gruppendateien können im Entwicklermodus des Menüsystems geöffnet, bearbeitet, entpackt und gepackt oder zerlegt werden.
Aufbau
C4Group-Dateien haben folgenden Aufbau:- GZIP-Header (mit geänderten Magic Bytes 0x1e und 0x8c)
- Deflate-komprimierter Datenbereich.
- GZIP-Footer (CRC32 und unkomprimierte Länge)
Header
Der Datenbereich beginnt mit dem 204 Byte langen Header des Hauptordners (root) der Gruppendatei. Jeder Ordner innerhalb einer Gruppendatei beginnt mit seinem Header, der Informationen über ihn liefert. Er ist auf folgende Weise verschlüsselt:for position = 0 to Datenlänge - 2 step 3
Vertausche(puffer[position], puffer[position + 2])
next
for position = 0 to Datenlänge - 1
puffer[position] = puffer[position] xor 0xED
next
Beispielimplementierungen Verschlüsselung
In C#
void MemScramble(byte[] buffer)
{
int i;
byte tmp;
for (i = 0; i < buffer.Length; i++)
buffer[i] ^= 237;
for (i = 0; (i + 2) < buffer.Length; i += 3)
{
tmp = buffer[i];
buffer[i] = buffer[i + 2];
buffer[i + 2] = tmp;
}
}
In C
void mem_scramble(char* data, unsigned int length) {
for(char* ptr = data; ptr < data + length; ptr += 3) {
char tmp = *ptr; *ptr = *(ptr + 2) ^ 0xED; *(ptr + 2) = tmp ^ 0xED;
*(ptr + 1) ^= 0xED;
}
for(unsigned int i = length % 3; i>0; i--)
data[length - i] ^= 0xED;
}
In Python
def mem_scramble(data : bytes) -> bytes:
data = bytearray(data)
i = 0
while (i + 2) < len(data):
data[i], data[i + 2] = data[i + 2], data[i]
i += 3
i = 0
while i < len(data):
data[i] = data[i] ^ 0xED
i += 1
return bytes(data)
In PHP5
/**
* Decrypts the group header
* @param $data
*/
function memScramble(array &$data) {
for($i = 0; $i < count($data); $i++) {
$data[$i] ^= 237;
}
for($i = 0; ($i + 2) < count($data); $i += 3) {
$tmp = $data[$i];
$data[$i] = $data[$i + 2];
$data[$i + 2] = $tmp;
}
}
In Node.js
let memScramble = function(chunk) {
for(let i = 0; i < chunk.length; i += 3) {
[chunk[i], chunk[i + 2]] = [chunk[i+2], chunk[i]];
}
for(let i = 0; i < chunk.length; i++) {
chunk[i] ^= 0xED;
}
}
Aufbau des Headers
Offset (in Bytes) | Größe (in Bytes) | Datentyp | Beschreibung (Clonk Rage) | Beschreibung (OpenClonk) | Beschreibung (LegacyClonk) |
---|---|---|---|---|---|
0 | 25 | String | Muss RedWolf Design GrpFolder sein. |
||
25 | 3 | - | Reserviert | ||
28 | 4 | Integer | Versionsnummer 1. Muss 1 sein. |
||
32 | 4 | Integer | Versionsnummer 2. Muss 2 sein. |
||
36 | 4 | Integer | Anzahl der Unterordner und Dateien. | ||
40 | 32 | String | Name des Autors. | Reserviert | |
72 | 32 | - | Reserviert | Reserviert | |
104 | 4 | time_t (Integer) | Erstellungsdatum | Reserviert | |
108 | 4 | Integer |
1234567 falls die Gruppe ein Originalpaket ist, oder ein beliebiger anderer Wert andernfalls. |
Reserviert | |
112 | 92 | - | Reserviert | Reserviert |
Aufbau des Inhaltsverzeichnisses
Offset (in Bytes) | Größe (in Bytes) | Datentyp | Beschreibung (Clonk Rage) | Beschreibung (OpenClonk) | Beschreibung (LegacyClonk) |
---|---|---|---|---|---|
0 | 257 | String | Dateiname | ||
257 | 3 | - | Reserviert | ||
260 | 4 | Integer | Gibt an, ob die Datei gepackt ist. Sollte 1 sein. | Reserviert | |
264 | 4 | Boolean |
0 wenn der Eintrag eine Datei ist, 1 wenn es sich um einen Ordner handelt. |
||
268 | 4 | Integer | Dateigröße | ||
272 | 4 | - | Reserviert | ||
276 | 4 | Integer | Abstand des Dateiinhalts vom Ende des Inhaltsverzeichnisses. | ||
280 | 4 | time_t (Integer) | Datum der letzten Modifikation. | Reserviert | |
284 | 1 | Byte |
0 : Keine Prüfsumme vorhanden.1 : Prüfsumme des Dateiinhalts.2 : Prüfsumme über Dateiinhalt und Dateiname. |
||
285 | 4 | Unsigned Integer | CRC32-Prüfsumme. | ||
289 | 1 | Byte | Gibt an ob die Datei ausführbar ist. (Wird nur unter Linux benötigt)0 : Nicht ausführbar1-255 : Ausführbar |
||
290 | 26 | - | Reserviert |
Hiernach folgt der Deflate-komprimierte Datenbereich.
Nachteile
C4Group ist ein progressiv komprimiertes Format, d.h. wenn eine Datei entpackt werden soll, muss die C4Group-Datei vom Anfang bis zu der angefragten Datei entpackt werden. Dadurch werden auch nicht benötigte Dateien entpackt, die dann wieder verworfen werden. Außerdem muss die C4Group-Datei jedesmal zurück an den Anfang springen, wenn eine Datei angefragt wird, die vor der aktuellen Leseposition liegt.Changelog
Datum | Art der Änderung | Änderung |
---|---|---|
1998-05-30T00:00:00Z | added | C4Group new magic (load old/new, save new), file version 1.2. |
1998-12-22T00:00:00Z | added | C4Group creation stamp |
1999-05-23T00:00:00Z | added | C4Group::EntryTime |
2004-03-28T00:00:00Z | added | Automatic contents checksum creation and caching. |
2006-05-13T00:00:00Z | changed | C4Group: use file names for crc, too. |
2006-07-25T00:00:00Z | changed | C4Group: Calc new-style CRC32 of entries using entry filename instead of group filename. |
PS: Dies ist ein Wikipost. Damit ist jedem angemeldeten Nutzer das Bearbeiten dieses Posts möglich.