Source file decompress_window.ml
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
module Buffer = Decompress_buffer
module Safe = Decompress_safe
type ('a, 'crc) t =
{ rpos: int
; wpos: int
; size: int
; buffer: ([Safe.ro | Safe.wo], 'a) Safe.t
; crc: Optint.t
; crc_witness: 'crc checksum
; buffer_witness: 'a Buffer.t }
and 'crc checksum =
| Adler32 : adler32 checksum
| Crc32 : crc32 checksum
| None : none checksum
and adler32 = A
and crc32 = B
and none = C
let adler32 = Adler32
let crc32 = Crc32
let none = None
module Crc = struct
type 'a t = 'a checksum
let default : type k. k t -> Optint.t = function
| Adler32 -> Checkseum.Adler32.default
| Crc32 -> Checkseum.Crc32.default
| None -> Optint.zero
let update_none _buf _witness _off _len crc = crc
let update : type k.
k t
-> 'i Buffer.t
-> ([> Safe.ro], 'i) Safe.t
-> int
-> int
-> Optint.t
-> Optint.t =
fun kind buf witness off len crc ->
match kind with
| Adler32 -> Safe.adler32 buf witness off len crc
| Crc32 -> Safe.crc32 buf witness off len crc
| None -> update_none buf witness off len crc
let digest_bytes_none _buf _off _len crc = crc
let digest_bytes : type k. k t -> bytes -> int -> int -> Optint.t -> Optint.t
=
fun kind buf off len crc ->
match kind with
| Adler32 -> Checkseum.Adler32.digest_bytes buf off len crc
| Crc32 -> Checkseum.Crc32.digest_bytes buf off len crc
| None -> digest_bytes_none buf off len crc
end
let create ~crc ~witness:buffer_witness =
let size = 1 lsl 15 in
{ rpos= 0
; wpos= 0
; size= size + 1
; buffer= Safe.rw buffer_witness (Buffer.create buffer_witness (size + 1))
; crc= Crc.default crc
; crc_witness= crc
; buffer_witness }
let crc {crc; _} = crc
let reset t = {t with rpos= 0; wpos= 0; crc= Crc.default t.crc_witness}
let available_to_write {wpos; rpos; size; _} =
if wpos >= rpos then size - (wpos - rpos) - 1 else rpos - wpos - 1
let drop n ({rpos; size; _} as t) =
{t with rpos= (if rpos + n < size then rpos + n else rpos + n - size)}
let move n ({wpos; size; _} as t) =
{t with wpos= (if wpos + n < size then wpos + n else wpos + n - size)}
external hack : ('a, 'i) Safe.t -> (Safe.ro, 'i) Safe.t = "%identity"
let write buf off dst dst_off len t =
let t =
if len > available_to_write t then drop (len - available_to_write t) t
else t
in
let pre = t.size - t.wpos in
let = len - pre in
if extra > 0 then (
Safe.blit2 t.buffer_witness buf off t.buffer t.wpos dst dst_off pre ;
Safe.blit2 t.buffer_witness buf (off + pre) t.buffer 0 dst (dst_off + pre)
extra )
else Safe.blit2 t.buffer_witness buf off t.buffer t.wpos dst dst_off len ;
move len
{ t with
crc=
Crc.update t.crc_witness t.buffer_witness (hack dst) dst_off len t.crc
}
let write_char chr t =
let t =
if 1 > available_to_write t then drop (1 - available_to_write t) t else t
in
Safe.set t.buffer_witness t.buffer t.wpos chr ;
move 1
{t with crc= Crc.digest_bytes t.crc_witness (Bytes.make 1 chr) 0 1 t.crc}
let fill_char chr len t =
let t =
if len > available_to_write t then drop (len - available_to_write t) t
else t
in
let pre = t.size - t.wpos in
let = len - pre in
if extra > 0 then (
Safe.fill t.buffer_witness t.buffer t.wpos pre chr ;
Safe.fill t.buffer_witness t.buffer 0 extra chr )
else Safe.fill t.buffer_witness t.buffer t.wpos len chr ;
move len
{ t with
crc= Crc.digest_bytes t.crc_witness (Bytes.make len chr) 0 len t.crc }
let rec sanitize n ({size; _} as t) =
if n < 0 then sanitize (size + n) t
else if n >= 0 && n < size then n
else sanitize (n - size) t
let ( % ) n t =
if n < t.size then sanitize n t else raise (Failure "Window.( % )")