this repo has no description
1type order = LSB | MSB
2type error = Invalid_code of int | Unexpected_eof | Buffer_overflow
3
4let error_to_string = function
5 | Invalid_code c -> Printf.sprintf "invalid LZW code: %d" c
6 | Unexpected_eof -> "unexpected end of compressed data"
7 | Buffer_overflow -> "decompressed data too large"
8
9let clear_code = 256
10let eof_code = 257
11let initial_dict_size = 258
12let max_code_bits = 12
13let max_dict_size = 1 lsl max_code_bits
14
15type bit_reader = {
16 data : string;
17 mutable pos : int;
18 mutable bit_pos : int;
19 mutable bits_buf : int;
20 mutable bits_count : int;
21}
22
23let make_bit_reader data =
24 { data; pos = 0; bit_pos = 0; bits_buf = 0; bits_count = 0 }
25
26let read_bits_lsb reader n =
27 while reader.bits_count < n do
28 if reader.pos >= String.length reader.data then raise (Failure "eof")
29 else begin
30 let byte = Char.code reader.data.[reader.pos] in
31 reader.bits_buf <- reader.bits_buf lor (byte lsl reader.bits_count);
32 reader.bits_count <- reader.bits_count + 8;
33 reader.pos <- reader.pos + 1
34 end
35 done;
36 let result = reader.bits_buf land ((1 lsl n) - 1) in
37 reader.bits_buf <- reader.bits_buf lsr n;
38 reader.bits_count <- reader.bits_count - n;
39 result
40
41let decompress ?(order = LSB) ?(lit_width = 8) data =
42 if order <> LSB then Error (Invalid_code 0)
43 else if lit_width <> 8 then Error (Invalid_code 0)
44 else
45 try
46 let reader = make_bit_reader data in
47 let output = Buffer.create (String.length data * 2) in
48
49 let dict = Array.make max_dict_size "" in
50 for i = 0 to 255 do
51 dict.(i) <- String.make 1 (Char.chr i)
52 done;
53 dict.(clear_code) <- "";
54 dict.(eof_code) <- "";
55
56 let dict_size = ref initial_dict_size in
57 let code_bits = ref 9 in
58 let prev_string = ref "" in
59
60 let add_to_dict s =
61 if !dict_size < max_dict_size then begin
62 dict.(!dict_size) <- s;
63 incr dict_size;
64 if !dict_size >= 1 lsl !code_bits && !code_bits < max_code_bits then
65 incr code_bits
66 end
67 in
68
69 let reset_dict () =
70 dict_size := initial_dict_size;
71 code_bits := 9;
72 prev_string := ""
73 in
74
75 let rec decode_loop () =
76 let code = read_bits_lsb reader !code_bits in
77 if code = eof_code then ()
78 else if code = clear_code then begin
79 reset_dict ();
80 decode_loop ()
81 end
82 else begin
83 let current_string =
84 if code < !dict_size then dict.(code)
85 else if code = !dict_size then
86 !prev_string ^ String.make 1 !prev_string.[0]
87 else
88 raise
89 (Failure
90 (Printf.sprintf "invalid code %d >= %d" code !dict_size))
91 in
92 Buffer.add_string output current_string;
93 if !prev_string <> "" then
94 add_to_dict (!prev_string ^ String.make 1 current_string.[0]);
95 prev_string := current_string;
96 decode_loop ()
97 end
98 in
99
100 decode_loop ();
101 Ok (Buffer.contents output)
102 with
103 | Failure msg when msg = "eof" -> Error Unexpected_eof
104 | Failure msg
105 when String.length msg > 12 && String.sub msg 0 12 = "invalid code" ->
106 Error (Invalid_code 0)
107 | _ -> Error (Invalid_code 0)
108
109let decompress_lsb8 data = decompress ~order:LSB ~lit_width:8 data