Commit ea9ded8758
Changed files (8)
lib
lib/std/compress/xz/block.zig
@@ -1,11 +1,10 @@
-const std = @import("std");
-const check = @import("check.zig");
+const std = @import("../../std.zig");
const lzma = @import("lzma.zig");
-const multibyte = @import("multibyte.zig");
const Allocator = std.mem.Allocator;
const Crc32 = std.hash.Crc32;
const Crc64 = std.hash.crc.Crc64Xz;
const Sha256 = std.crypto.hash.sha2.Sha256;
+const xz = std.compress.xz;
const DecodeError = error{
CorruptInput,
@@ -16,8 +15,8 @@ const DecodeError = error{
Overflow,
};
-pub fn decoder(allocator: Allocator, reader: anytype, check_kind: check.Kind) !Decoder(@TypeOf(reader)) {
- return Decoder(@TypeOf(reader)).init(allocator, reader, check_kind);
+pub fn decoder(allocator: Allocator, reader: anytype, check: xz.Check) !Decoder(@TypeOf(reader)) {
+ return Decoder(@TypeOf(reader)).init(allocator, reader, check);
}
pub fn Decoder(comptime ReaderType: type) type {
@@ -31,17 +30,17 @@ pub fn Decoder(comptime ReaderType: type) type {
allocator: Allocator,
inner_reader: ReaderType,
- check_kind: check.Kind,
+ check: xz.Check,
err: ?Error,
accum: lzma.LzAccumBuffer,
lzma_state: lzma.DecoderState,
block_count: usize,
- fn init(allocator: Allocator, in_reader: ReaderType, check_kind: check.Kind) !Self {
+ fn init(allocator: Allocator, in_reader: ReaderType, check: xz.Check) !Self {
return Self{
.allocator = allocator,
.inner_reader = in_reader,
- .check_kind = check_kind,
+ .check = check,
.err = null,
.accum = .{},
.lzma_state = try lzma.DecoderState.init(allocator),
@@ -116,10 +115,10 @@ pub fn Decoder(comptime ReaderType: type) type {
return error.Unsupported;
if (flags.has_packed_size)
- packed_size = try multibyte.readInt(header_reader);
+ packed_size = try std.leb.readULEB128(u64, header_reader);
if (flags.has_unpacked_size)
- unpacked_size = try multibyte.readInt(header_reader);
+ unpacked_size = try std.leb.readULEB128(u64, header_reader);
const FilterId = enum(u64) {
lzma2 = 0x21,
@@ -128,7 +127,7 @@ pub fn Decoder(comptime ReaderType: type) type {
const filter_id = @intToEnum(
FilterId,
- try multibyte.readInt(header_reader),
+ try std.leb.readULEB128(u64, header_reader),
);
if (@enumToInt(filter_id) >= 0x4000_0000_0000_0000)
@@ -137,7 +136,7 @@ pub fn Decoder(comptime ReaderType: type) type {
if (filter_id != .lzma2)
return error.Unsupported;
- const properties_size = try multibyte.readInt(header_reader);
+ const properties_size = try std.leb.readULEB128(u64, header_reader);
if (properties_size != 1)
return error.CorruptInput;
@@ -177,8 +176,7 @@ pub fn Decoder(comptime ReaderType: type) type {
return error.CorruptInput;
}
- // Check
- switch (self.check_kind) {
+ switch (self.check) {
.none => {},
.crc32 => {
const hash_a = Crc32.hash(unpacked_bytes);
lib/std/compress/xz/check.zig
@@ -1,7 +0,0 @@
-pub const Kind = enum(u4) {
- none = 0x00,
- crc32 = 0x01,
- crc64 = 0x04,
- sha256 = 0x0A,
- _,
-};
lib/std/compress/xz/lzma.zig
@@ -1,6 +1,6 @@
// Ported from https://github.com/gendx/lzma-rs
-const std = @import("std");
+const std = @import("../../std.zig");
const assert = std.debug.assert;
const Allocator = std.mem.Allocator;
const ArrayListUnmanaged = std.ArrayListUnmanaged;
lib/std/compress/xz/multibyte.zig
@@ -1,23 +0,0 @@
-const Multibyte = packed struct(u8) {
- value: u7,
- more: bool,
-};
-
-pub fn readInt(reader: anytype) !u64 {
- const max_size = 9;
-
- var chunk = try reader.readStruct(Multibyte);
- var num: u64 = chunk.value;
- var i: u6 = 0;
-
- while (chunk.more) {
- chunk = try reader.readStruct(Multibyte);
- i += 1;
- if (i >= max_size or @bitCast(u8, chunk) == 0x00)
- return error.CorruptInput;
-
- num |= @as(u64, chunk.value) << (i * 7);
- }
-
- return num;
-}
lib/std/compress/xz/stream.zig
@@ -1,136 +0,0 @@
-const std = @import("std");
-const block = @import("block.zig");
-const check = @import("check.zig");
-const multibyte = @import("multibyte.zig");
-const Allocator = std.mem.Allocator;
-const Crc32 = std.hash.Crc32;
-
-test {
- _ = @import("stream_test.zig");
-}
-
-const Flags = packed struct(u16) {
- reserved1: u8,
- check_kind: check.Kind,
- reserved2: u4,
-};
-
-pub fn stream(allocator: Allocator, reader: anytype) !Stream(@TypeOf(reader)) {
- return Stream(@TypeOf(reader)).init(allocator, reader);
-}
-
-pub fn Stream(comptime ReaderType: type) type {
- return struct {
- const Self = @This();
-
- pub const Error = ReaderType.Error || block.Decoder(ReaderType).Error;
- pub const Reader = std.io.Reader(*Self, Error, read);
-
- allocator: Allocator,
- block_decoder: block.Decoder(ReaderType),
- in_reader: ReaderType,
-
- fn init(allocator: Allocator, source: ReaderType) !Self {
- const Header = extern struct {
- magic: [6]u8,
- flags: Flags,
- crc32: u32,
- };
-
- const header = try source.readStruct(Header);
-
- if (!std.mem.eql(u8, &header.magic, &.{ 0xFD, '7', 'z', 'X', 'Z', 0x00 }))
- return error.BadHeader;
-
- if (header.flags.reserved1 != 0 or header.flags.reserved2 != 0)
- return error.BadHeader;
-
- const hash = Crc32.hash(std.mem.asBytes(&header.flags));
- if (hash != header.crc32)
- return error.WrongChecksum;
-
- return Self{
- .allocator = allocator,
- .block_decoder = try block.decoder(allocator, source, header.flags.check_kind),
- .in_reader = source,
- };
- }
-
- pub fn deinit(self: *Self) void {
- self.block_decoder.deinit();
- }
-
- pub fn reader(self: *Self) Reader {
- return .{ .context = self };
- }
-
- pub fn read(self: *Self, buffer: []u8) Error!usize {
- if (buffer.len == 0)
- return 0;
-
- const r = try self.block_decoder.read(buffer);
- if (r != 0)
- return r;
-
- const index_size = blk: {
- var hasher = std.compress.hashedReader(self.in_reader, Crc32.init());
- hasher.hasher.update(&[1]u8{0x00});
-
- var counter = std.io.countingReader(hasher.reader());
- counter.bytes_read += 1;
-
- const counting_reader = counter.reader();
-
- const record_count = try multibyte.readInt(counting_reader);
- if (record_count != self.block_decoder.block_count)
- return error.CorruptInput;
-
- var i: usize = 0;
- while (i < record_count) : (i += 1) {
- // TODO: validate records
- _ = try multibyte.readInt(counting_reader);
- _ = try multibyte.readInt(counting_reader);
- }
-
- while (counter.bytes_read % 4 != 0) {
- if (try counting_reader.readByte() != 0)
- return error.CorruptInput;
- }
-
- const hash_a = hasher.hasher.final();
- const hash_b = try counting_reader.readIntLittle(u32);
- if (hash_a != hash_b)
- return error.WrongChecksum;
-
- break :blk counter.bytes_read;
- };
-
- const Footer = extern struct {
- crc32: u32,
- backward_size: u32,
- flags: Flags,
- magic: [2]u8,
- };
-
- const footer = try self.in_reader.readStruct(Footer);
- const backward_size = (footer.backward_size + 1) * 4;
- if (backward_size != index_size)
- return error.CorruptInput;
-
- if (footer.flags.reserved1 != 0 or footer.flags.reserved2 != 0)
- return error.CorruptInput;
-
- var hasher = Crc32.init();
- hasher.update(std.mem.asBytes(&footer.backward_size));
- hasher.update(std.mem.asBytes(&footer.flags));
- const hash = hasher.final();
- if (hash != footer.crc32)
- return error.WrongChecksum;
-
- if (!std.mem.eql(u8, &footer.magic, &.{ 'Y', 'Z' }))
- return error.CorruptInput;
-
- return 0;
- }
- };
-}
lib/std/compress/xz/stream_test.zig → lib/std/compress/xz/test.zig
@@ -1,11 +1,11 @@
-const std = @import("std");
+const std = @import("../../std.zig");
const testing = std.testing;
-const stream = @import("stream.zig").stream;
+const xz = std.compress.xz;
fn decompress(data: []const u8) ![]u8 {
var in_stream = std.io.fixedBufferStream(data);
- var xz_stream = try stream(testing.allocator, in_stream.reader());
+ var xz_stream = try xz.decompress(testing.allocator, in_stream.reader());
defer xz_stream.deinit();
return xz_stream.reader().readAllAlloc(testing.allocator, std.math.maxInt(usize));
lib/std/compress/xz.zig
@@ -1,5 +1,142 @@
-pub usingnamespace @import("xz/stream.zig");
+const std = @import("std");
+const block = @import("xz/block.zig");
+const Allocator = std.mem.Allocator;
+const Crc32 = std.hash.Crc32;
+
+pub const Flags = packed struct(u16) {
+ reserved1: u8,
+ check_kind: Check,
+ reserved2: u4,
+};
+
+pub const Header = extern struct {
+ magic: [6]u8,
+ flags: Flags,
+ crc32: u32,
+};
+
+pub const Footer = extern struct {
+ crc32: u32,
+ backward_size: u32,
+ flags: Flags,
+ magic: [2]u8,
+};
+
+pub const Check = enum(u4) {
+ none = 0x00,
+ crc32 = 0x01,
+ crc64 = 0x04,
+ sha256 = 0x0A,
+ _,
+};
+
+pub fn decompress(allocator: Allocator, reader: anytype) !Decompress(@TypeOf(reader)) {
+ return Decompress(@TypeOf(reader)).init(allocator, reader);
+}
+
+pub fn Decompress(comptime ReaderType: type) type {
+ return struct {
+ const Self = @This();
+
+ pub const Error = ReaderType.Error || block.Decoder(ReaderType).Error;
+ pub const Reader = std.io.Reader(*Self, Error, read);
+
+ allocator: Allocator,
+ block_decoder: block.Decoder(ReaderType),
+ in_reader: ReaderType,
+
+ fn init(allocator: Allocator, source: ReaderType) !Self {
+ const header = try source.readStruct(Header);
+
+ if (!std.mem.eql(u8, &header.magic, &.{ 0xFD, '7', 'z', 'X', 'Z', 0x00 }))
+ return error.BadHeader;
+
+ if (header.flags.reserved1 != 0 or header.flags.reserved2 != 0)
+ return error.BadHeader;
+
+ const hash = Crc32.hash(std.mem.asBytes(&header.flags));
+ if (hash != header.crc32)
+ return error.WrongChecksum;
+
+ return Self{
+ .allocator = allocator,
+ .block_decoder = try block.decoder(allocator, source, header.flags.check_kind),
+ .in_reader = source,
+ };
+ }
+
+ pub fn deinit(self: *Self) void {
+ self.block_decoder.deinit();
+ }
+
+ pub fn reader(self: *Self) Reader {
+ return .{ .context = self };
+ }
+
+ pub fn read(self: *Self, buffer: []u8) Error!usize {
+ if (buffer.len == 0)
+ return 0;
+
+ const r = try self.block_decoder.read(buffer);
+ if (r != 0)
+ return r;
+
+ const index_size = blk: {
+ var hasher = std.compress.hashedReader(self.in_reader, Crc32.init());
+ hasher.hasher.update(&[1]u8{0x00});
+
+ var counter = std.io.countingReader(hasher.reader());
+ counter.bytes_read += 1;
+
+ const counting_reader = counter.reader();
+
+ const record_count = try std.leb.readULEB128(u64, counting_reader);
+ if (record_count != self.block_decoder.block_count)
+ return error.CorruptInput;
+
+ var i: usize = 0;
+ while (i < record_count) : (i += 1) {
+ // TODO: validate records
+ _ = try std.leb.readULEB128(u64, counting_reader);
+ _ = try std.leb.readULEB128(u64, counting_reader);
+ }
+
+ while (counter.bytes_read % 4 != 0) {
+ if (try counting_reader.readByte() != 0)
+ return error.CorruptInput;
+ }
+
+ const hash_a = hasher.hasher.final();
+ const hash_b = try counting_reader.readIntLittle(u32);
+ if (hash_a != hash_b)
+ return error.WrongChecksum;
+
+ break :blk counter.bytes_read;
+ };
+
+ const footer = try self.in_reader.readStruct(Footer);
+ const backward_size = (footer.backward_size + 1) * 4;
+ if (backward_size != index_size)
+ return error.CorruptInput;
+
+ if (footer.flags.reserved1 != 0 or footer.flags.reserved2 != 0)
+ return error.CorruptInput;
+
+ var hasher = Crc32.init();
+ hasher.update(std.mem.asBytes(&footer.backward_size));
+ hasher.update(std.mem.asBytes(&footer.flags));
+ const hash = hasher.final();
+ if (hash != footer.crc32)
+ return error.WrongChecksum;
+
+ if (!std.mem.eql(u8, &footer.magic, &.{ 'Y', 'Z' }))
+ return error.CorruptInput;
+
+ return 0;
+ }
+ };
+}
test {
- _ = @import("xz/stream.zig");
+ _ = @import("xz/test.zig");
}
lib/std/compress.zig
@@ -3,6 +3,7 @@ const std = @import("std.zig");
pub const deflate = @import("compress/deflate.zig");
pub const gzip = @import("compress/gzip.zig");
pub const zlib = @import("compress/zlib.zig");
+pub const xz = @import("compress/xz.zig");
pub fn HashedReader(
comptime ReaderType: anytype,
@@ -38,4 +39,5 @@ test {
_ = deflate;
_ = gzip;
_ = zlib;
+ _ = xz;
}