extc.ml 6.7 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211
  1. (*
  2. * Extc : C common OCaml bindings
  3. * Copyright (c)2004 Nicolas Cannasse
  4. *
  5. * This program is free software; you can redistribute it and/or modify
  6. * it under the terms of the GNU General Public License as published by
  7. * the Free Software Foundation; either version 2 of the License, or
  8. * (at your option) any later version.
  9. *
  10. * This program is distributed in the hope that it will be useful,
  11. * but WITHOUT ANY WARRANTY; without even the implied warranty of
  12. * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
  13. * GNU General Public License for more details.
  14. *
  15. * You should have received a copy of the GNU General Public License
  16. * along with this program; if not, write to the Free Software
  17. * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA
  18. *)
  19. type zstream
  20. type zflush =
  21. | Z_NO_FLUSH
  22. | Z_PARTIAL_FLUSH
  23. | Z_SYNC_FLUSH
  24. | Z_FULL_FLUSH
  25. | Z_FINISH
  26. type zresult = {
  27. z_finish : bool;
  28. z_read : int;
  29. z_wrote : int;
  30. }
  31. external zlib_deflate_init2 : int -> int -> zstream = "zlib_deflate_init2"
  32. external zlib_deflate : zstream -> src:string -> spos:int -> slen:int -> dst:bytes -> dpos:int -> dlen:int -> zflush -> zresult = "zlib_deflate_bytecode" "zlib_deflate"
  33. external zlib_deflate_end : zstream -> unit = "zlib_deflate_end"
  34. external zlib_inflate_init2 : int -> zstream = "zlib_inflate_init"
  35. external zlib_inflate : zstream -> src:string -> spos:int -> slen:int -> dst:bytes -> dpos:int -> dlen:int -> zflush -> zresult = "zlib_inflate_bytecode" "zlib_inflate"
  36. external zlib_inflate_end : zstream -> unit = "zlib_inflate_end"
  37. external _executable_path : string -> string = "executable_path"
  38. external get_full_path : string -> string = "get_full_path"
  39. external get_real_path : string -> string = "get_real_path"
  40. external zlib_deflate_bound : zstream -> int -> int = "zlib_deflate_bound"
  41. external zlib_crc32 : bytes -> int -> int32 = "zlib_crc32"
  42. external time : unit -> float = "sys_time"
  43. type library
  44. type sym
  45. type value
  46. external dlopen : string -> library = "sys_dlopen"
  47. external dlsym : library -> string -> sym = "sys_dlsym"
  48. external dlcall0 : sym -> value = "sys_dlcall0"
  49. external dlcall1 : sym -> value -> value = "sys_dlcall1"
  50. external dlcall2 : sym -> value -> value -> value = "sys_dlcall2"
  51. external dlcall3 : sym -> value -> value -> value -> value = "sys_dlcall3"
  52. external dlcall4 : sym -> value -> value -> value -> value -> value = "sys_dlcall4"
  53. external dlcall5 : sym -> value -> value -> value -> value -> value -> value = "sys_dlcall5_bc" "sys_dlcall5"
  54. external dlint : int -> value = "sys_dlint"
  55. external dltoint : value -> int = "sys_dltoint"
  56. external dlstring : string -> value = "%identity"
  57. external dladdr : value -> int -> value = "sys_dladdr"
  58. external dlptr : value -> value = "sys_dlptr"
  59. external dlsetptr : value -> value -> unit = "sys_dlsetptr"
  60. external dlalloc_string : value -> string = "sys_dlalloc_string"
  61. external dlmemcpy : value -> value -> int -> unit = "sys_dlmemcpy"
  62. external dlcallback : int -> value = "sys_dlcallback"
  63. external dlcaml_callback : int -> value = "sys_dlcaml_callback"
  64. external dlint32 : int32 -> value = "sys_dlint32"
  65. external getch : bool -> int = "sys_getch"
  66. external filetime : string -> float = "sys_filetime"
  67. (* support for backward compatibility *)
  68. let zlib_deflate_init lvl = zlib_deflate_init2 lvl 15
  69. let zlib_inflate_init() = zlib_inflate_init2 15
  70. let executable_path() =
  71. let p = _executable_path Sys.argv.(0) in
  72. let p1 = (try String.rindex p '/' with Not_found -> String.length p + 1) in
  73. let p2 = (try String.rindex p '\\' with Not_found -> String.length p + 1) in
  74. match min p1 p2 with
  75. | x when x = String.length p + 1 -> ""
  76. | pos ->
  77. String.sub p 0 pos ^ "/"
  78. let zlib_op op z str =
  79. let bufsize = 1 lsl 14 in
  80. let tmp = Bytes.create bufsize in
  81. let total = ref 0 in
  82. let rec loop pos len acc =
  83. let r = op z ~src:str ~spos:pos ~slen:len ~dst:tmp ~dpos:0 ~dlen:bufsize (if len = 0 then Z_FINISH else Z_SYNC_FLUSH) in
  84. total := !total + r.z_wrote;
  85. let acc = Bytes.sub tmp 0 r.z_wrote :: acc in
  86. if r.z_finish then
  87. acc
  88. else
  89. loop (pos + r.z_read) (len - r.z_read) acc
  90. in
  91. let strings = loop 0 (String.length str) [] in
  92. let big = Bytes.create !total in
  93. ignore(List.fold_left (fun p s ->
  94. let l = Bytes.length s in
  95. let p = p - l in
  96. Bytes.unsafe_blit s 0 big p l;
  97. p
  98. ) !total strings);
  99. Bytes.unsafe_to_string big
  100. let zip str =
  101. let z = zlib_deflate_init 9 in
  102. let s = zlib_op zlib_deflate z str in
  103. zlib_deflate_end z;
  104. s
  105. let unzip str =
  106. let z = zlib_inflate_init() in
  107. let s = zlib_op zlib_inflate z str in
  108. zlib_inflate_end z;
  109. s
  110. let input_zip ?(bufsize=65536) ch =
  111. let tmp_out = Bytes.create bufsize in
  112. let tmp_in = Bytes.create bufsize in
  113. let tmp_buf = Buffer.create bufsize in
  114. let buf = ref "" in
  115. let p = ref 0 in
  116. let z = zlib_inflate_init() in
  117. let rec fill_buffer() =
  118. let rec loop pos len =
  119. if len > 0 || pos = 0 then begin
  120. let r = zlib_inflate z (Bytes.unsafe_to_string tmp_in) pos len tmp_out 0 bufsize (if pos = 0 && len = 0 then Z_FINISH else Z_SYNC_FLUSH) in
  121. Buffer.add_subbytes tmp_buf tmp_out 0 r.z_wrote;
  122. loop (pos + r.z_read) (len - r.z_read);
  123. end
  124. in
  125. loop 0 (IO.input ch tmp_in 0 bufsize);
  126. p := 0;
  127. buf := Buffer.contents tmp_buf;
  128. Buffer.clear tmp_buf;
  129. in
  130. let read() =
  131. if !p = String.length !buf then fill_buffer();
  132. let c = String.unsafe_get !buf !p in
  133. incr p;
  134. c
  135. in
  136. let rec input str pos len =
  137. let b = String.length !buf - !p in
  138. if b >= len then begin
  139. String.blit !buf !p str pos len;
  140. p := !p + len;
  141. len;
  142. end else begin
  143. String.blit !buf !p str pos b;
  144. fill_buffer();
  145. if !p = String.length !buf then
  146. b
  147. else
  148. b + input str (pos + b) (len - b)
  149. end;
  150. in
  151. let close() =
  152. zlib_inflate_end z
  153. in
  154. IO.create_in ~read ~input ~close
  155. let output_zip ?(bufsize=65536) ?(level=9) ch =
  156. let z = zlib_deflate_init level in
  157. let out = Bytes.create bufsize in
  158. let tmp_out = Bytes.create bufsize in
  159. let p = ref 0 in
  160. let rec flush finish =
  161. let r = zlib_deflate z (Bytes.unsafe_to_string out) 0 !p tmp_out 0 bufsize (if finish then Z_FINISH else Z_SYNC_FLUSH) in
  162. ignore(IO.really_output ch tmp_out 0 r.z_wrote);
  163. let remain = !p - r.z_read in
  164. Bytes.blit out r.z_read out 0 remain;
  165. p := remain;
  166. if finish && not r.z_finish then flush true
  167. in
  168. let write c =
  169. if !p = bufsize then flush false;
  170. Bytes.unsafe_set out !p c;
  171. incr p
  172. in
  173. let rec output str pos len =
  174. let b = bufsize - !p in
  175. if len <= b then begin
  176. Bytes.blit str pos out !p len;
  177. p := !p + len;
  178. len
  179. end else begin
  180. Bytes.blit str pos out !p b;
  181. p := !p + b;
  182. flush false;
  183. b + output str (pos + b) (len - b);
  184. end;
  185. in
  186. let close() =
  187. flush true;
  188. zlib_deflate_end z
  189. in
  190. IO.create_out ~write ~output ~flush:(fun() -> flush false; IO.flush ch) ~close