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
type error =
| Missing_start_code
| Checksum_mismatched of (int * int)
| Illegal_record_type of int
exception Error of error
let raise_error err = raise (Error err)
let decode_record_line_exn line =
if line.[0] <> ':' then raise_error Missing_start_code;
let bytes =
Ohex.decode
@@
String.sub line 1 String.(length line - 1)
in
let length = String.get_uint8 bytes 0 in
let address = String.get_uint16_be bytes 1 in
let kind = String.get_uint8 bytes 3 in
let payload = String.sub bytes 4 length in
let checksum = String.get_uint8 bytes (4 + length)
and expected_checksum =
let payload_sum_bytes =
String.fold_left (fun sum ch -> int_of_char ch + sum) 0 payload
in
-(payload_sum_bytes + address + String.length payload + kind) land 0xFF
in
if checksum <> expected_checksum then
raise_error @@ Checksum_mismatched (checksum, expected_checksum);
match kind with
| 0x00 -> Record.Data (address, payload)
| 0x01 -> Record.End_of_file
| 0x02 -> Record.Extended_segment_address String.(get_uint16_be payload 0)
| 0x04 -> Record.Extended_linear_address String.(get_uint16_be payload 0)
| 0x05 ->
Record.Start_linear_address
String.(get_int32_be payload 0 |> Int32.to_int)
| 0x03 ->
Record.Start_segment_address
{
cs = String.get_int16_be payload 0;
ip = String.get_int16_be payload 2;
}
| _ -> raise_error @@ Illegal_record_type kind
let decode_object_from_string_exn string =
String.split_on_char '\n' string |> List.map decode_record_line_exn
let[@tail_mod_cons] rec decode_object_from_channel_exn ic =
match input_line ic |> decode_record_line_exn with
| exception End_of_file -> []
| Record.End_of_file as record -> [ record ]
| record -> record :: decode_object_from_channel_exn ic