part of archive; | |
class GZipEncoder { | |
static const int SIGNATURE = 0x8b1f; | |
static const int DEFLATE = 8; | |
static const int FLAG_TEXT = 0x01; | |
static const int FLAG_HCRC = 0x02; | |
static const int FLAG_EXTRA = 0x04; | |
static const int FLAG_NAME = 0x08; | |
static const int FLAG_COMMENT = 0x10; | |
// enum OperatingSystem | |
static const int OS_FAT = 0; | |
static const int OS_AMIGA = 1; | |
static const int OS_VMS = 2; | |
static const int OS_UNIX = 3; | |
static const int OS_VM_CMS = 4; | |
static const int OS_ATARI_TOS = 5; | |
static const int OS_HPFS = 6; | |
static const int OS_MACINTOSH = 7; | |
static const int OS_Z_SYSTEM = 8; | |
static const int OS_CP_M = 9; | |
static const int OS_TOPS_20 = 10; | |
static const int OS_NTFS = 11; | |
static const int OS_QDOS = 12; | |
static const int OS_ACORN_RISCOS = 13; | |
static const int OS_UNKNOWN = 255; | |
List<int> encode(data, {int level, dynamic output}) { | |
dynamic output_stream = output != null ? output : new OutputStream(); | |
// The GZip format has the following structure: | |
// Offset Length Contents | |
// 0 2 bytes magic header 0x1f, 0x8b (\037 \213) | |
// 2 1 byte compression method | |
// 0: store (copied) | |
// 1: compress | |
// 2: pack | |
// 3: lzh | |
// 4..7: reserved | |
// 8: deflate | |
// 3 1 byte flags | |
// bit 0 set: file probably ascii text | |
// bit 1 set: continuation of multi-part gzip file, part number present | |
// bit 2 set: extra field present | |
// bit 3 set: original file name present | |
// bit 4 set: file comment present | |
// bit 5 set: file is encrypted, encryption header present | |
// bit 6,7: reserved | |
// 4 4 bytes file modification time in Unix format | |
// 8 1 byte extra flags (depend on compression method) | |
// 9 1 byte OS type | |
// [ | |
// 2 bytes optional part number (second part=1) | |
// ]? | |
// [ | |
// 2 bytes optional extra field length (e) | |
// (e)bytes optional extra field | |
// ]? | |
// [ | |
// bytes optional original file name, zero terminated | |
// ]? | |
// [ | |
// bytes optional file comment, zero terminated | |
// ]? | |
// [ | |
// 12 bytes optional encryption header | |
// ]? | |
// bytes compressed data | |
// 4 bytes crc32 | |
// 4 bytes uncompressed input size modulo 2^32 | |
output_stream.writeUint16(SIGNATURE); | |
output_stream.writeByte(DEFLATE); | |
int flags = 0; | |
int fileModTime = new DateTime.now().millisecondsSinceEpoch ~/ 1000; | |
int extraFlags = 0; | |
int osType = OS_UNKNOWN; | |
output_stream.writeByte(flags); | |
output_stream.writeUint32(fileModTime); | |
output_stream.writeByte(extraFlags); | |
output_stream.writeByte(osType); | |
Deflate deflate; | |
if (data is List<int>) { | |
deflate = new Deflate(data, level: level, output: output_stream); | |
} else { | |
deflate = new Deflate.buffer(data, level: level, output: output_stream); | |
} | |
if (output_stream is OutputStream) { | |
List<int> compressed = deflate.getBytes(); | |
output_stream.writeBytes(compressed); | |
} else { | |
deflate.finish(); | |
} | |
output_stream.writeUint32(deflate.crc32); | |
output_stream.writeUint32(data.length); | |
if (output_stream is OutputStream) { | |
return output_stream.getBytes(); | |
} else { | |
return null; | |
} | |
} | |
} |