authorgravatar for squeek502@hotmail.comRyan Liptak <squeek502@hotmail.com> 2021-10-01 22:01:31-07:00
committergravatar for squeek502@hotmail.comRyan Liptak <squeek502@hotmail.com> 2021-10-01 22:07:11-07:00
log933fd5110d787b8ffd757eac496f59afbf357f07
tree8c2c649cec815f8b6461a115e167067e9d9628d5
parentc4cd592f0e1eeff5a4056796610d97010ae4e38c

deflate: Better Huffman.construct errors and error handling

This brings construct error handling in line with puff.c

1 files changed, 33 insertions(+), 6 deletions(-)

lib/std/compress/deflate.zig+33-6
...@@ -45,7 +45,9 @@ const Huffman = struct {...@@ -45,7 +45,9 @@ const Huffman = struct {
4545
46 min_code_len: u16,46 min_code_len: u16,
4747
48 fn construct(self: *Huffman, code_length: []const u16) !void {48 const ConstructError = error{ Oversubscribed, IncompleteSet };
49
50 fn construct(self: *Huffman, code_length: []const u16) ConstructError!void {
49 for (self.count) |*val| {51 for (self.count) |*val| {
50 val.* = 0;52 val.* = 0;
51 }53 }
...@@ -70,7 +72,7 @@ const Huffman = struct {...@@ -70,7 +72,7 @@ const Huffman = struct {
70 // Make sure the number of codes with this length isn't too high.72 // Make sure the number of codes with this length isn't too high.
71 left -= @as(isize, @bitCast(i16, val));73 left -= @as(isize, @bitCast(i16, val));
72 if (left < 0)74 if (left < 0)
73 return error.InvalidTree;75 return error.Oversubscribed;
74 }76 }
7577
76 // Compute the offset of the first symbol represented by a code of a78 // Compute the offset of the first symbol represented by a code of a
...@@ -125,6 +127,9 @@ const Huffman = struct {...@@ -125,6 +127,9 @@ const Huffman = struct {
125127
126 self.last_code = codes[PREFIX_LUT_BITS + 1];128 self.last_code = codes[PREFIX_LUT_BITS + 1];
127 self.last_index = offset[PREFIX_LUT_BITS + 1] - self.count[PREFIX_LUT_BITS + 1];129 self.last_index = offset[PREFIX_LUT_BITS + 1] - self.count[PREFIX_LUT_BITS + 1];
130
131 if (left > 0)
132 return error.IncompleteSet;
128 }133 }
129};134};
130135
...@@ -322,7 +327,13 @@ pub fn InflateStream(comptime ReaderType: type) type {...@@ -322,7 +327,13 @@ pub fn InflateStream(comptime ReaderType: type) type {
322 try lencode.construct(len_lengths[0..]);327 try lencode.construct(len_lengths[0..]);
323328
324 const dist_lengths = [_]u16{5} ** MAXDCODES;329 const dist_lengths = [_]u16{5} ** MAXDCODES;
325 try distcode.construct(dist_lengths[0..]);330 distcode.construct(dist_lengths[0..]) catch |err| switch (err) {
331 // This error is expected because we only compute distance codes
332 // 0-29, which is fine since "distance codes 30-31 will never actually
333 // occur in the compressed data" (from section 3.2.6 of RFC1951).
334 error.IncompleteSet => {},
335 else => return err,
336 };
326 }337 }
327338
328 self.hlen = &lencode;339 self.hlen = &lencode;
...@@ -357,7 +368,7 @@ pub fn InflateStream(comptime ReaderType: type) type {...@@ -357,7 +368,7 @@ pub fn InflateStream(comptime ReaderType: type) type {
357 lengths[val] = @intCast(u16, try self.readBits(3));368 lengths[val] = @intCast(u16, try self.readBits(3));
358 }369 }
359370
360 try lencode.construct(lengths[0..]);371 lencode.construct(lengths[0..]) catch return error.InvalidTree;
361 }372 }
362373
363 // Read the length/literal and distance code length tables.374 // Read the length/literal and distance code length tables.
...@@ -406,8 +417,24 @@ pub fn InflateStream(comptime ReaderType: type) type {...@@ -406,8 +417,24 @@ pub fn InflateStream(comptime ReaderType: type) type {
406 if (lengths[256] == 0)417 if (lengths[256] == 0)
407 return error.MissingEOBCode;418 return error.MissingEOBCode;
408419
409 try self.huffman_tables[0].construct(lengths[0..nlen]);420 self.huffman_tables[0].construct(lengths[0..nlen]) catch |err| switch (err) {
410 try self.huffman_tables[1].construct(lengths[nlen .. nlen + ndist]);421 error.Oversubscribed => return error.InvalidTree,
422 error.IncompleteSet => {
423 // incomplete code ok only for single length 1 code
424 if (nlen != self.huffman_tables[0].count[0] + self.huffman_tables[0].count[1]) {
425 return error.InvalidTree;
426 }
427 },
428 };
429 self.huffman_tables[1].construct(lengths[nlen .. nlen + ndist]) catch |err| switch (err) {
430 error.Oversubscribed => return error.InvalidTree,
431 error.IncompleteSet => {
432 // incomplete code ok only for single length 1 code
433 if (ndist != self.huffman_tables[1].count[0] + self.huffman_tables[1].count[1]) {
434 return error.InvalidTree;
435 }
436 },
437 };
411438
412 self.hlen = &self.huffman_tables[0];439 self.hlen = &self.huffman_tables[0];
413 self.hdist = &self.huffman_tables[1];440 self.hdist = &self.huffman_tables[1];