Pure OCaml implementation of the Brotli compression algorithm
at main 92 lines 2.9 kB view raw
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