Pure OCaml implementation of the Brotli compression algorithm
1(* Pure OCaml implementation of Brotli compression (RFC 7932) *)
2
3(* Re-export error types from decoder *)
4type error = Brotli_decode.error =
5 | Invalid_stream_header
6 | Invalid_meta_block_header
7 | Invalid_huffman_code
8 | Invalid_distance
9 | Invalid_backward_reference
10 | Invalid_context_map
11 | Truncated_input
12 | Output_overrun
13
14exception Brotli_error = Brotli_decode.Brotli_error
15
16let error_to_string = Brotli_decode.error_to_string
17
18(* Low-allocation API *)
19
20let compress_into ?(quality=1) ~src ~src_pos ~src_len ~dst ~dst_pos () =
21 Brotli_encode.compress_into ~quality ~src ~src_pos ~src_len ~dst ~dst_pos ()
22
23let decompress_into ~src ~src_pos ~src_len ~dst ~dst_pos =
24 Brotli_decode.decompress_into ~src ~src_pos ~src_len ~dst ~dst_pos
25
26(* Utilities *)
27
28let max_compressed_length = Brotli_encode.max_compressed_length
29
30(* Simple string API *)
31
32let compress ?(quality = 1) s =
33 let src = Bytes.unsafe_of_string s in
34 let src_len = String.length s in
35 let max_len = max_compressed_length src_len in
36 let dst = Bytes.create max_len in
37 let len = Brotli_encode.compress_into ~quality ~src ~src_pos:0 ~src_len ~dst ~dst_pos:0 () in
38 Bytes.sub_string dst 0 len
39
40let decompress s =
41 try
42 let src = Bytes.unsafe_of_string s in
43 let src_len = String.length s in
44 (* Estimate decompressed size - start with 4x input size *)
45 let initial_size = max 256 (src_len * 4) in
46 let dst = ref (Bytes.create initial_size) in
47 let rec try_decompress size =
48 try
49 dst := Bytes.create size;
50 let len = decompress_into ~src ~src_pos:0 ~src_len ~dst:!dst ~dst_pos:0 in
51 Ok (Bytes.sub_string !dst 0 len)
52 with
53 | Brotli_error Output_overrun ->
54 (* Double buffer size and retry *)
55 if size > 256 * 1024 * 1024 then
56 Error "Output too large"
57 else
58 try_decompress (size * 2)
59 in
60 try_decompress initial_size
61 with
62 | Brotli_error e -> Error (error_to_string e)
63 | Bit_reader.End_of_input -> Error "Truncated input"
64
65let decompress_exn s =
66 match decompress s with
67 | Ok result -> result
68 | Error msg -> failwith msg
69
70(* Streaming compression API *)
71type streaming_encoder = Brotli_encode.streaming_encoder
72
73let create_streaming_encoder = Brotli_encode.create_streaming_encoder
74let streaming_write = Brotli_encode.streaming_write
75let streaming_finish = Brotli_encode.streaming_finish
76let streaming_bytes_written = Brotli_encode.streaming_bytes_written
77
78(* Constants *)
79let min_quality = 0
80let max_quality = 11
81let default_quality = 1
82let max_window_bits = 22
83
84(* Debug module for testing *)
85module Debug = struct
86 type command = Brotli_encode.command =
87 | InsertCopy of { lit_start: int; lit_len: int; copy_len: int; distance: int; dist_code: int option }
88 | Literals of { start: int; len: int }
89
90 let generate_commands src src_pos src_len =
91 Brotli_encode.generate_commands src src_pos src_len
92end