package dbase4

  1. Overview
  2. Docs

Source file memo.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
(******* Memo File support ********)
let memo_block_size = 512

let calculate_chunk_offset memo_block_size index = index * memo_block_size

(******* dBase III         ********)

let bytes_rscan_eob bs =
  let n = Bytes.length bs in
  let rec _rscan_eob bs p =
    if p > 0 then
      if (Bytes.get_int16_le bs p) = 0x1A1A then p 
      else _rscan_eob bs (p - 1)
    else -1
  in  
  _rscan_eob bs n

let rec read_cblock_chn n chn pos data =
  let rlen = In_channel.input chn data pos n in
  if rlen >= 0 then
    let p = bytes_rscan_eob data in
    if p >= 0 then Bytes.sub data 0 p
    else read_cblock_chn n chn (pos + rlen) data
  else data

let read_block_db3 (db : Base.dbf_file) index =
  match db.memo with
  | Some md ->
      let pos = calculate_chunk_offset memo_block_size index in
      In_channel.seek md (Int64.of_int pos);
      let data =
        read_cblock_chn memo_block_size md 0
          (Bytes.make (memo_block_size * 4) '\026')
      in
      Some (data)
  | None -> None

(******* dBase IV          ********)

let read_block_db4 (db : Base.dbf_file) index =
  match db.memo with
  | Some md ->
      if index > 0 then (
        let pos = calculate_chunk_offset memo_block_size index in
        In_channel.seek md (Int64.of_int pos);
        let hdr_size = 8 in
        let chunk = Base.read_chunk md hdr_size in
        let _mark = Bytes.get_int32_le chunk 0 |> Int32.to_int in
        let _len = Int32.to_int (Bytes.get_int32_le chunk 4) in
        (*assert(_mark = 589823, _msg); *)
        let _mark_check = 589823 in
        if _mark = _mark_check then
          (
            In_channel.seek md (Int64.of_int (pos + hdr_size));
            let _data = Base.read_chunk md (_len - hdr_size) in
            Some _data
          )
        else 
          ( 
            Printf.eprintf 
            "[MEMO.ERROR]: _mark expected 0x%x, got 0x%x at pos = 0x%x\n" 
            _mark_check _mark pos;          
            None 
          );
      )
      else None
  | None -> None

(* --------- *)
let load_memo_internal rider (db : Base.dbf_file) index =
  let memo_to_dbval (obs : Bytes.t option) =
    match obs with
    | Some data -> data
    | None -> Bytes.empty
  in
  memo_to_dbval (rider db index)

let load_memo (db : Base.dbf_file) index =
  match db.info.version with
  | 0x83 ->
      load_memo_internal read_block_db3 db index
  | 0x8b -> 
      load_memo_internal read_block_db4 db index
  | _ -> failwith "This dBase version is not supported"
OCaml

Innovation. Community. Security.