···11+open Zstd_stubs
22+33+module Size_t = Unsigned.Size_t
44+module F = C.Functions
55+module T = C.Types
66+77+exception Error of string
88+99+let version () =
1010+ let n = F.version_number () in
1111+ (n / 10_000, (n / 100) mod 100, n mod 100)
1212+1313+let bracket res destroy k =
1414+ let r = try k res with exn -> let () = destroy res in raise exn in
1515+ let () = destroy res in
1616+ r
1717+1818+let check r = if F.is_error r then raise (Error (F.get_error_name r))
1919+2020+let free_cctx x = check (F.free_cctx x)
2121+let free_dctx x = check (F.free_dctx x)
2222+2323+let compress ~level ?dict s =
2424+ let open Ctypes in
2525+ let len = Size_t.of_int (String.length s) in
2626+ let dst_size = F.compress_bound len in
2727+ let dst = allocate_n char ~count:(Size_t.to_int dst_size) in
2828+ let r =
2929+ match dict with
3030+ | None -> F.compress (to_voidp dst) dst_size s len level
3131+ | Some dict ->
3232+ let dlen = Size_t.of_int (String.length dict) in
3333+ bracket (F.create_cctx ()) free_cctx begin fun cctx ->
3434+ F.compress_using_dict cctx (to_voidp dst) dst_size s len dict dlen level
3535+ end
3636+ in
3737+ check r;
3838+ string_from_ptr dst ~length:(Size_t.to_int r)
3939+4040+let decompress orig ?dict s =
4141+ let open Ctypes in
4242+ let dst = allocate_n char ~count:orig in
4343+ let r =
4444+ match dict with
4545+ | None -> F.decompress (to_voidp dst) (Size_t.of_int orig) s (Size_t.of_int (String.length s))
4646+ | Some dict ->
4747+ let dlen = Size_t.of_int (String.length dict) in
4848+ bracket (F.create_dctx ()) free_dctx begin fun dctx ->
4949+ F.decompress_using_dict dctx (to_voidp dst) (Size_t.of_int orig) s (Size_t.of_int (String.length s)) dict dlen
5050+ end
5151+ in
5252+ check r;
5353+ string_from_ptr dst ~length:(Size_t.to_int r)
5454+5555+let get_decompressed_size s =
5656+ let r = F.get_frame_content_size s (Size_t.of_int (String.length s)) in
5757+ if r = T.content_size_error then
5858+ raise (Error "content size error")
5959+ else if r = T.content_size_unknown then
6060+ raise (Error "content size unknown")
6161+ else
6262+ Unsigned.ULLong.to_int r
+18
vendor/opam/zstd/src/zstd.mli
···11+(** Zstandard - fast lossless compression algorithm *)
22+33+exception Error of string
44+55+val version : unit -> (int * int * int)
66+77+(** [dict] optional pre-defined dictionary content (see dictBuilder) *)
88+val compress : level:int -> ?dict:string -> string -> string
99+1010+(**
1111+ [decompress orig_size ?dict s]
1212+1313+ [orig_size] specifies size of buffer for decompression (not less than original size of uncompressed [s])
1414+ [dict] must be identical to the one used during compression, otherwise uncompressed data will be corrupted.
1515+*)
1616+val decompress : int -> ?dict:string -> string -> string
1717+1818+val get_decompressed_size : string -> int
···11+open ExtLib
22+open Printf
33+44+let test (name,src) =
55+ let orig = String.length src in
66+ let a = Array.init 20 (fun level -> Zstd.compress ~level src) in
77+ a |> Array.iteri begin fun i s ->
88+ assert (Zstd.get_decompressed_size s = orig);
99+ let s = Zstd.decompress orig s in
1010+ if s <> src then failwith @@ sprintf "%s : level %d failed" name i;
1111+ end;
1212+ let best = Array.fold_left (fun m s -> min m (String.length s)) (String.length a.(0)) a in
1313+ let best_level = Array.findi (fun s -> String.length s = best) a in
1414+ printf "%50s : best compression %02.1fx at level %d : %d -> %d\n" name (float orig /. float best) best_level orig best
1515+1616+let () =
1717+ let file f = try Some (f, Std.input_file f) with _ -> None in
1818+ let inputs = [
1919+ file "/bin/bash";
2020+ file Sys.executable_name;
2121+ file "/etc/ld.so.cache";
2222+ file "/etc/mailcap";
2323+ Some ("environment", String.concat " " @@ Array.to_list @@ Unix.environment ());
2424+ ] |> List.filter_map (fun x -> x)
2525+ in
2626+ List.iter test inputs
+30
vendor/opam/zstd/zstd.opam
···11+opam-version: "2.0"
22+maintainer: "ygrek@autistici.org"
33+homepage: "https://github.com/ygrek/ocaml-zstd"
44+license: "BSD-3-Clause"
55+authors: [ "ygrek" ]
66+tags: [ "org:ygrek" "clib:zstd" ]
77+doc: [ "https://ygrek.org/p/ocaml-zstd/api/index.html" ]
88+dev-repo: "git+https://github.com/ygrek/ocaml-zstd.git"
99+bug-reports: "https://github.com/ygrek/ocaml-zstd/issues"
1010+build: [
1111+ ["dune" "subst"] {dev}
1212+ ["dune" "build" "-p" name "-j" jobs
1313+ "@install"
1414+ "@doc" {with-doc}
1515+ "@runtest" {with-test}]
1616+]
1717+depends: [
1818+ "ocaml"
1919+ "dune" {>= "3.7"}
2020+ "ctypes" {>= "0.13.0"}
2121+ "integers"
2222+ ("extlib" {with-test} | "extlib-compat" {with-test})
2323+ "base-unix" {with-test}
2424+ "conf-zstd"
2525+]
2626+synopsis: "Bindings to zstd compression library"
2727+description: """
2828+Zstd, short for Zstandard, is a fast lossless compression algorithm,
2929+targeting real-time compression scenarios at zlib-level compression ratio.
3030+See http://zstd.net/ for more info."""