package core_kernel

  1. Overview
  2. Docs
Industrial strength alternative to OCaml's standard library

Install

Dune Dependency

Authors

Maintainers

Sources

core_kernel-v0.15.0.tar.gz
sha256=34a0288f16027c6b90e4ad16cb5cc677d7063d310faf918748ce70f1745116c0

doc/src/core_kernel.binary_packing/binary_packing.ml.html

Source file binary_packing.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
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
484
485
486
487
488
489
490
491
492
493
494
495
496
497
498
499
500
501
502
503
504
505
506
507
508
509
510
511
512
513
514
515
516
517
518
519
520
521
522
523
524
525
526
527
528
529
530
531
532
533
534
535
536
537
538
539
540
541
542
543
544
545
546
547
548
549
550
551
552
553
554
555
556
557
558
559
560
561
562
563
564
565
566
567
568
569
570
571
572
573
574
575
576
577
578
579
580
581
582
583
584
585
586
587
588
589
590
591
592
593
594
595
596
597
598
599
600
601
602
603
604
605
606
607
608
609
610
611
612
613
614
615
616
617
618
619
620
621
622
623
624
625
626
627
628
629
630
631
632
633
634
635
636
637
638
639
640
641
642
643
644
645
646
647
648
649
650
651
652
653
654
655
656
657
658
659
660
661
662
663
664
665
666
667
668
669
670
671
672
673
674
675
676
677
678
679
open! Core
open! Import
module Core_char = Char
module Char = Caml.Char
module Int32 = Caml.Int32
module Int64 = Caml.Int64

let arch_sixtyfour = Sys.word_size_in_bits = 64
let signed_max = Int32.to_int Int32.max_int
let unsigned_max = Int64.to_int 0xffff_ffffL

type endian =
  [ `Big_endian
  | `Little_endian
  ]
[@@deriving compare, hash, sexp]

(* Computes the offset based on the total number of bytes, the byte order, and the
   byte number. The byte number is ordered by decreasing significance starting at zero
   (big endian). So the most significant byte is 0, and the least significant byte is (len
   - 1). *)

exception Binary_packing_invalid_byte_number of int * int [@@deriving sexp]

let offset ~len ~byte_order byte_nr =
  if byte_nr >= len || byte_nr < 0
  then raise (Binary_packing_invalid_byte_number (byte_nr, len));
  match byte_order with
  | `Little_endian -> len - 1 - byte_nr
  | `Big_endian -> byte_nr
;;

exception Pack_unsigned_8_argument_out_of_range of int [@@deriving sexp]

let pack_unsigned_8 ~buf ~pos n =
  if n > 0xFF || n < 0
  then raise (Pack_unsigned_8_argument_out_of_range n)
  else Bytes.set buf pos (Char.unsafe_chr n)
;;

let unpack_unsigned_8 ~buf ~pos = Char.code (Bytes.get buf pos)

exception Pack_signed_8_argument_out_of_range of int [@@deriving sexp]

let pack_signed_8 ~buf ~pos n =
  if n > 0x7F || n < -0x80
  then raise (Pack_signed_8_argument_out_of_range n)
  else Bytes.set buf pos (Char.unsafe_chr n)
;;

let unpack_signed_8 ~buf ~pos =
  let n = unpack_unsigned_8 ~buf ~pos in
  if n >= 0x80 then -(0x100 - n) else n
;;

exception Pack_unsigned_16_argument_out_of_range of int [@@deriving sexp]

let pack_unsigned_16 ~byte_order ~buf ~pos n =
  if n >= 0x10000 || n < 0
  then raise (Pack_unsigned_16_argument_out_of_range n)
  else (
    Bytes.set
      buf
      (pos + offset ~len:2 ~byte_order 0)
      (Char.unsafe_chr (0xFF land (n asr 8)));
    Bytes.set buf (pos + offset ~len:2 ~byte_order 1) (Char.unsafe_chr (0xFF land n)))
;;

let pack_unsigned_16_big_endian ~buf ~pos n =
  if n >= 0x10000 || n < 0
  then raise (Pack_unsigned_16_argument_out_of_range n)
  else (
    Bytes.set buf pos (Char.unsafe_chr (0xFF land (n lsr 8)));
    Bytes.set buf (pos + 1) (Char.unsafe_chr (0xFF land n)))
;;

let pack_unsigned_16_little_endian ~buf ~pos n =
  if n >= 0x10000 || n < 0
  then raise (Pack_unsigned_16_argument_out_of_range n)
  else (
    Bytes.set buf (pos + 1) (Char.unsafe_chr (0xFF land (n lsr 8)));
    Bytes.set buf pos (Char.unsafe_chr (0xFF land n)))
;;

exception Pack_signed_16_argument_out_of_range of int [@@deriving sexp]

let pack_signed_16 ~byte_order ~buf ~pos n =
  if n > 0x7FFF || n < -0x8000
  then raise (Pack_signed_16_argument_out_of_range n)
  else (
    Bytes.set
      buf
      (pos + offset ~len:2 ~byte_order 0)
      (Char.unsafe_chr (0xFF land (n asr 8)));
    Bytes.set buf (pos + offset ~len:2 ~byte_order 1) (Char.unsafe_chr (0xFF land n)))
;;

let pack_signed_16_big_endian ~buf ~pos n =
  if n > 0x7FFF || n < -0x8000
  then raise (Pack_signed_16_argument_out_of_range n)
  else (
    Bytes.set buf pos (Char.unsafe_chr (0xFF land (n asr 8)));
    Bytes.set buf (pos + 1) (Char.unsafe_chr (0xFF land n)))
;;

let pack_signed_16_little_endian ~buf ~pos n =
  if n > 0x7FFF || n < -0x8000
  then raise (Pack_signed_16_argument_out_of_range n)
  else (
    Bytes.set buf (pos + 1) (Char.unsafe_chr (0xFF land (n asr 8)));
    Bytes.set buf pos (Char.unsafe_chr (0xFF land n)))
;;

let unpack_unsigned_16 ~byte_order ~buf ~pos =
  let b1 = Char.code (Bytes.get buf (pos + offset ~len:2 ~byte_order 0)) lsl 8 in
  let b2 = Char.code (Bytes.get buf (pos + offset ~len:2 ~byte_order 1)) in
  b1 lor b2
;;

let unpack_signed_16 ~byte_order ~buf ~pos =
  let n = unpack_unsigned_16 ~byte_order ~buf ~pos in
  if n >= 0x8000 then -(0x10000 - n) else n
;;

let unpack_unsigned_16_big_endian ~buf ~pos =
  let b1 = Char.code (Bytes.get buf pos) lsl 8 in
  let b2 = Char.code (Bytes.get buf (pos + 1)) in
  b1 lor b2
;;

let unpack_unsigned_16_little_endian ~buf ~pos =
  let b1 = Char.code (Bytes.get buf (pos + 1)) lsl 8 in
  let b2 = Char.code (Bytes.get buf pos) in
  b1 lor b2
;;

let unpack_signed_16_big_endian ~buf ~pos =
  let n = unpack_unsigned_16_big_endian ~buf ~pos in
  if n >= 0x8000 then -(0x10000 - n) else n
;;

let unpack_signed_16_little_endian ~buf ~pos =
  let n = unpack_unsigned_16_little_endian ~buf ~pos in
  if n >= 0x8000 then -(0x10000 - n) else n
;;

exception Pack_unsigned_32_argument_out_of_range of int [@@deriving sexp]

let check_unsigned_32_in_range n =
  if arch_sixtyfour
  then (
    if n > unsigned_max || n < 0 then raise (Pack_unsigned_32_argument_out_of_range n))
  else if n < 0
  then raise (Pack_unsigned_32_argument_out_of_range n)
;;

let pack_unsigned_32_int ~byte_order ~buf ~pos n =
  assert (Sys.word_size_in_bits = 64);
  check_unsigned_32_in_range n;
  Bytes.set
    buf
    (pos + offset ~len:4 ~byte_order 0)
    (Char.unsafe_chr (0xFF land (n asr 24)));
  (* MSB *)
  Bytes.set
    buf
    (pos + offset ~len:4 ~byte_order 1)
    (Char.unsafe_chr (0xFF land (n asr 16)));
  Bytes.set
    buf
    (pos + offset ~len:4 ~byte_order 2)
    (Char.unsafe_chr (0xFF land (n asr 8)));
  Bytes.set buf (pos + offset ~len:4 ~byte_order 3) (Char.unsafe_chr (0xFF land n))
;;

(* LSB *)

let pack_unsigned_32_int_big_endian ~buf ~pos n =
  check_unsigned_32_in_range n;
  Bytes.set buf pos (Char.unsafe_chr (0xFF land (n lsr 24)));
  (* MSB *)
  Bytes.set buf (pos + 3) (Char.unsafe_chr (0xFF land n));
  (* LSB *)
  Bytes.unsafe_set buf (pos + 1) (Char.unsafe_chr (0xFF land (n lsr 16)));
  Bytes.unsafe_set buf (pos + 2) (Char.unsafe_chr (0xFF land (n lsr 8)))
;;

let pack_unsigned_32_int_little_endian ~buf ~pos n =
  check_unsigned_32_in_range n;
  Bytes.set buf (pos + 3) (Char.unsafe_chr (0xFF land (n lsr 24)));
  (* MSB *)
  Bytes.set buf pos (Char.unsafe_chr (0xFF land n));
  (* LSB *)
  Bytes.unsafe_set buf (pos + 2) (Char.unsafe_chr (0xFF land (n lsr 16)));
  Bytes.unsafe_set buf (pos + 1) (Char.unsafe_chr (0xFF land (n lsr 8)))
;;

exception Pack_signed_32_argument_out_of_range of int [@@deriving sexp]

let check_signed_32_in_range n =
  if arch_sixtyfour
  then
    if n > signed_max || n < -(signed_max + 1)
    then raise (Pack_signed_32_argument_out_of_range n)
;;

let pack_signed_32_int ~byte_order ~buf ~pos n =
  assert (Sys.word_size_in_bits = 64);
  check_signed_32_in_range n;
  Bytes.set
    buf
    (pos + offset ~len:4 ~byte_order 0)
    (Char.unsafe_chr (0xFF land (n asr 24)));
  (* MSB *)
  Bytes.set
    buf
    (pos + offset ~len:4 ~byte_order 1)
    (Char.unsafe_chr (0xFF land (n asr 16)));
  Bytes.set
    buf
    (pos + offset ~len:4 ~byte_order 2)
    (Char.unsafe_chr (0xFF land (n asr 8)));
  Bytes.set buf (pos + offset ~len:4 ~byte_order 3) (Char.unsafe_chr (0xFF land n))
;;

(* LSB *)

let pack_signed_32_int_big_endian ~buf ~pos n =
  check_signed_32_in_range n;
  Bytes.set buf pos (Char.unsafe_chr (0xFF land (n asr 24)));
  (* MSB *)
  Bytes.set buf (pos + 3) (Char.unsafe_chr (0xFF land n));
  (* LSB *)
  Bytes.unsafe_set buf (pos + 1) (Char.unsafe_chr (0xFF land (n asr 16)));
  Bytes.unsafe_set buf (pos + 2) (Char.unsafe_chr (0xFF land (n asr 8)))
;;

let pack_signed_32_int_little_endian ~buf ~pos n =
  check_signed_32_in_range n;
  Bytes.set buf (pos + 3) (Char.unsafe_chr (0xFF land (n asr 24)));
  (* MSB *)
  Bytes.set buf pos (Char.unsafe_chr (0xFF land n));
  (* LSB *)
  Bytes.unsafe_set buf (pos + 2) (Char.unsafe_chr (0xFF land (n asr 16)));
  Bytes.unsafe_set buf (pos + 1) (Char.unsafe_chr (0xFF land (n asr 8)))
;;

let pack_signed_32 ~byte_order ~buf ~pos n =
  Bytes.set
    buf
    (pos + offset ~len:4 ~byte_order 0)
    (Char.unsafe_chr (0xFF land Int32.to_int (Int32.shift_right n 24)));
  Bytes.set
    buf
    (pos + offset ~len:4 ~byte_order 1)
    (Char.unsafe_chr (0xFF land Int32.to_int (Int32.shift_right n 16)));
  Bytes.set
    buf
    (pos + offset ~len:4 ~byte_order 2)
    (Char.unsafe_chr (0xFF land Int32.to_int (Int32.shift_right n 8)));
  Bytes.set
    buf
    (pos + offset ~len:4 ~byte_order 3)
    (Char.unsafe_chr (0xFF land Int32.to_int n))
;;

let unpack_signed_32 ~byte_order ~buf ~pos =
  let b1 =
    (* MSB *)
    Int32.shift_left
      (Int32.of_int (Char.code (Bytes.get buf (pos + offset ~len:4 ~byte_order 0))))
      24
  in
  let b2 = Char.code (Bytes.get buf (pos + offset ~len:4 ~byte_order 1)) lsl 16 in
  let b3 = Char.code (Bytes.get buf (pos + offset ~len:4 ~byte_order 2)) lsl 8 in
  let b4 = Char.code (Bytes.get buf (pos + offset ~len:4 ~byte_order 3)) in
  (* LSB *)
  Int32.logor b1 (Int32.of_int (b2 lor b3 lor b4))
;;

let unpack_unsigned_32_int ~byte_order ~buf ~pos =
  assert (Sys.word_size_in_bits = 64);
  let b1 = Char.code (Bytes.get buf (pos + offset ~len:4 ~byte_order 0)) lsl 24 in
  (* msb *)
  let b2 = Char.code (Bytes.get buf (pos + offset ~len:4 ~byte_order 1)) lsl 16 in
  let b3 = Char.code (Bytes.get buf (pos + offset ~len:4 ~byte_order 2)) lsl 8 in
  let b4 = Char.code (Bytes.get buf (pos + offset ~len:4 ~byte_order 3)) in
  (* lsb *)
  b1 lor b2 lor b3 lor b4
;;

let unpack_unsigned_32_int_big_endian ~buf ~pos =
  let b1 = Char.code (Bytes.get buf pos) lsl 24 in
  (* msb *)
  let b4 = Char.code (Bytes.get buf (pos + 3)) in
  (* lsb *)
  let b2 = Char.code (Bytes.unsafe_get buf (pos + 1)) lsl 16 in
  let b3 = Char.code (Bytes.unsafe_get buf (pos + 2)) lsl 8 in
  b1 lor b2 lor b3 lor b4
;;

let unpack_unsigned_32_int_little_endian ~buf ~pos =
  let b1 = Char.code (Bytes.get buf (pos + 3)) lsl 24 in
  (* msb *)
  let b4 = Char.code (Bytes.get buf pos) in
  (* lsb *)
  let b2 = Char.code (Bytes.unsafe_get buf (pos + 2)) lsl 16 in
  let b3 = Char.code (Bytes.unsafe_get buf (pos + 1)) lsl 8 in
  b1 lor b2 lor b3 lor b4
;;

let unpack_signed_32_int ~byte_order ~buf ~pos =
  let n = unpack_unsigned_32_int ~byte_order ~buf ~pos in
  if arch_sixtyfour && n > signed_max then -(((signed_max + 1) lsl 1) - n) else n
;;

let unpack_signed_32_int_big_endian ~buf ~pos =
  let n = unpack_unsigned_32_int_big_endian ~buf ~pos in
  if arch_sixtyfour && n > signed_max then n - (unsigned_max + 1) else n
;;

let unpack_signed_32_int_little_endian ~buf ~pos =
  let n = unpack_unsigned_32_int_little_endian ~buf ~pos in
  if arch_sixtyfour && n > signed_max then n - (unsigned_max + 1) else n
;;

let pack_signed_64 ~byte_order ~buf ~pos v =
  let top3 = Int64.to_int (Int64.shift_right v 40) in
  let mid3 = Int64.to_int (Int64.shift_right v 16) in
  let bot2 = Int64.to_int v in
  Bytes.set
    buf
    (pos + offset ~len:8 ~byte_order 0)
    (Char.unsafe_chr (0xFF land (top3 lsr 16)));
  Bytes.set
    buf
    (pos + offset ~len:8 ~byte_order 1)
    (Char.unsafe_chr (0xFF land (top3 lsr 8)));
  Bytes.set buf (pos + offset ~len:8 ~byte_order 2) (Char.unsafe_chr (0xFF land top3));
  Bytes.set
    buf
    (pos + offset ~len:8 ~byte_order 3)
    (Char.unsafe_chr (0xFF land (mid3 lsr 16)));
  Bytes.set
    buf
    (pos + offset ~len:8 ~byte_order 4)
    (Char.unsafe_chr (0xFF land (mid3 lsr 8)));
  Bytes.set buf (pos + offset ~len:8 ~byte_order 5) (Char.unsafe_chr (0xFF land mid3));
  Bytes.set
    buf
    (pos + offset ~len:8 ~byte_order 6)
    (Char.unsafe_chr (0xFF land (bot2 lsr 8)));
  Bytes.set buf (pos + offset ~len:8 ~byte_order 7) (Char.unsafe_chr (0xFF land bot2))
;;

let pack_signed_64_big_endian ~buf ~pos v =
  (* Safely set the first and last bytes, so that we verify the string bounds. *)
  Bytes.set
    buf
    pos
    (Char.unsafe_chr (Int64.to_int (Int64.logand 0xFFL (Int64.shift_right_logical v 56))));
  Bytes.set buf (pos + 7) (Char.unsafe_chr (Int64.to_int (Int64.logand 0xFFL v)));
  (* Now we can use [unsafe_set] for the intermediate bytes. *)
  Bytes.unsafe_set
    buf
    (pos + 1)
    (Char.unsafe_chr (Int64.to_int (Int64.logand 0xFFL (Int64.shift_right_logical v 48))));
  Bytes.unsafe_set
    buf
    (pos + 2)
    (Char.unsafe_chr (Int64.to_int (Int64.logand 0xFFL (Int64.shift_right_logical v 40))));
  Bytes.unsafe_set
    buf
    (pos + 3)
    (Char.unsafe_chr (Int64.to_int (Int64.logand 0xFFL (Int64.shift_right_logical v 32))));
  Bytes.unsafe_set
    buf
    (pos + 4)
    (Char.unsafe_chr (Int64.to_int (Int64.logand 0xFFL (Int64.shift_right_logical v 24))));
  Bytes.unsafe_set
    buf
    (pos + 5)
    (Char.unsafe_chr (Int64.to_int (Int64.logand 0xFFL (Int64.shift_right_logical v 16))));
  Bytes.unsafe_set
    buf
    (pos + 6)
    (Char.unsafe_chr (Int64.to_int (Int64.logand 0xFFL (Int64.shift_right_logical v 8))))
;;

let pack_signed_64_little_endian ~buf ~pos v =
  (* Safely set the first and last bytes, so that we verify the string bounds. *)
  Bytes.set buf pos (Char.unsafe_chr (Int64.to_int (Int64.logand 0xFFL v)));
  Bytes.set
    buf
    (pos + 7)
    (Char.unsafe_chr (Int64.to_int (Int64.logand 0xFFL (Int64.shift_right_logical v 56))));
  (* Now we can use [unsafe_set] for the intermediate bytes. *)
  Bytes.unsafe_set
    buf
    (pos + 1)
    (Char.unsafe_chr (Int64.to_int (Int64.logand 0xFFL (Int64.shift_right_logical v 8))));
  Bytes.unsafe_set
    buf
    (pos + 2)
    (Char.unsafe_chr (Int64.to_int (Int64.logand 0xFFL (Int64.shift_right_logical v 16))));
  Bytes.unsafe_set
    buf
    (pos + 3)
    (Char.unsafe_chr (Int64.to_int (Int64.logand 0xFFL (Int64.shift_right_logical v 24))));
  Bytes.unsafe_set
    buf
    (pos + 4)
    (Char.unsafe_chr (Int64.to_int (Int64.logand 0xFFL (Int64.shift_right_logical v 32))));
  Bytes.unsafe_set
    buf
    (pos + 5)
    (Char.unsafe_chr (Int64.to_int (Int64.logand 0xFFL (Int64.shift_right_logical v 40))));
  Bytes.unsafe_set
    buf
    (pos + 6)
    (Char.unsafe_chr (Int64.to_int (Int64.logand 0xFFL (Int64.shift_right_logical v 48))))
;;

let unpack_signed_64 ~byte_order ~buf ~pos =
  Int64.logor
    (Int64.logor
       (Int64.shift_left
          (Int64.of_int
             ((Char.code (Bytes.get buf (pos + offset ~len:8 ~byte_order 0)) lsl 16)
              lor (Char.code (Bytes.get buf (pos + offset ~len:8 ~byte_order 1)) lsl 8)
              lor Char.code (Bytes.get buf (pos + offset ~len:8 ~byte_order 2))))
          40)
       (Int64.shift_left
          (Int64.of_int
             ((Char.code (Bytes.get buf (pos + offset ~len:8 ~byte_order 3)) lsl 16)
              lor (Char.code (Bytes.get buf (pos + offset ~len:8 ~byte_order 4)) lsl 8)
              lor Char.code (Bytes.get buf (pos + offset ~len:8 ~byte_order 5))))
          16))
    (Int64.of_int
       ((Char.code (Bytes.get buf (pos + offset ~len:8 ~byte_order 6)) lsl 8)
        lor Char.code (Bytes.get buf (pos + offset ~len:8 ~byte_order 7))))
;;

let unpack_signed_64_big_endian ~buf ~pos =
  (* Do bounds checking only on the first and last bytes *)
  let b1 = Char.code (Bytes.get buf pos)
  and b8 = Char.code (Bytes.get buf (pos + 7)) in
  let b2 = Char.code (Bytes.unsafe_get buf (pos + 1))
  and b3 = Char.code (Bytes.unsafe_get buf (pos + 2))
  and b4 = Char.code (Bytes.unsafe_get buf (pos + 3))
  and b5 = Char.code (Bytes.unsafe_get buf (pos + 4))
  and b6 = Char.code (Bytes.unsafe_get buf (pos + 5))
  and b7 = Char.code (Bytes.unsafe_get buf (pos + 6)) in
  if arch_sixtyfour
  then (
    let i1 = Int64.of_int b1
    and i2 =
      Int64.of_int
        ((b2 lsl 48)
         lor (b3 lsl 40)
         lor (b4 lsl 32)
         lor (b5 lsl 24)
         lor (b6 lsl 16)
         lor (b7 lsl 8)
         lor b8)
    in
    Int64.(logor i2 (shift_left i1 56)))
  else (
    let i1 = Int64.of_int ((b1 lsl 8) lor b2)
    and i2 = Int64.of_int ((b3 lsl 16) lor (b4 lsl 8) lor b5)
    and i3 = Int64.of_int ((b6 lsl 16) lor (b7 lsl 8) lor b8) in
    Int64.(logor i3 (logor (shift_left i2 24) (shift_left i1 48))))
;;

let unpack_signed_64_little_endian ~buf ~pos =
  (* Do bounds checking only on the first and last bytes *)
  let b1 = Char.code (Bytes.get buf pos)
  and b8 = Char.code (Bytes.get buf (pos + 7)) in
  let b2 = Char.code (Bytes.unsafe_get buf (pos + 1))
  and b3 = Char.code (Bytes.unsafe_get buf (pos + 2))
  and b4 = Char.code (Bytes.unsafe_get buf (pos + 3))
  and b5 = Char.code (Bytes.unsafe_get buf (pos + 4))
  and b6 = Char.code (Bytes.unsafe_get buf (pos + 5))
  and b7 = Char.code (Bytes.unsafe_get buf (pos + 6)) in
  if arch_sixtyfour
  then (
    let i1 =
      Int64.of_int
        (b1
         lor (b2 lsl 8)
         lor (b3 lsl 16)
         lor (b4 lsl 24)
         lor (b5 lsl 32)
         lor (b6 lsl 40)
         lor (b7 lsl 48))
    and i2 = Int64.of_int b8 in
    Int64.(logor i1 (shift_left i2 56)))
  else (
    let i1 = Int64.of_int (b1 lor (b2 lsl 8) lor (b3 lsl 16))
    and i2 = Int64.of_int (b4 lor (b5 lsl 8) lor (b6 lsl 16))
    and i3 = Int64.of_int (b7 lor (b8 lsl 8)) in
    Int64.(logor i1 (logor (shift_left i2 24) (shift_left i3 48))))
;;

let pack_signed_64_int ~byte_order ~buf ~pos n =
  assert (Sys.word_size_in_bits = 64);
  Bytes.set
    buf
    (pos + offset ~len:8 ~byte_order 0)
    (Char.unsafe_chr (0xFF land (n asr 56)));
  Bytes.set
    buf
    (pos + offset ~len:8 ~byte_order 1)
    (Char.unsafe_chr (0xFF land (n asr 48)));
  Bytes.set
    buf
    (pos + offset ~len:8 ~byte_order 2)
    (Char.unsafe_chr (0xFF land (n asr 40)));
  Bytes.set
    buf
    (pos + offset ~len:8 ~byte_order 3)
    (Char.unsafe_chr (0xFF land (n asr 32)));
  Bytes.set
    buf
    (pos + offset ~len:8 ~byte_order 4)
    (Char.unsafe_chr (0xFF land (n asr 24)));
  Bytes.set
    buf
    (pos + offset ~len:8 ~byte_order 5)
    (Char.unsafe_chr (0xFF land (n asr 16)));
  Bytes.set
    buf
    (pos + offset ~len:8 ~byte_order 6)
    (Char.unsafe_chr (0xFF land (n asr 8)));
  Bytes.set buf (pos + offset ~len:8 ~byte_order 7) (Char.unsafe_chr (0xFF land n))
;;

(* It's important to use [asr] not [lsr] in [pack_signed_64_int_big_endian] and
   [pack_signed_64_int_little_endian] so that the most significant byte is encoded
   correctly.  (It might be helpful to think about this as widening, i.e. sign
   extending, the number to 64 bits and then doing the right shift by 56.)
*)

let pack_signed_64_int_big_endian ~buf ~pos v =
  (* Safely set the first and last bytes, so that we verify the string bounds. *)
  Bytes.set buf pos (Char.unsafe_chr (0xFF land (v asr 56)));
  Bytes.set buf (pos + 7) (Char.unsafe_chr (0xFF land v));
  (* Now we can use [unsafe_set] for the intermediate bytes. *)
  Bytes.unsafe_set buf (pos + 1) (Char.unsafe_chr (0xFF land (v asr 48)));
  Bytes.unsafe_set buf (pos + 2) (Char.unsafe_chr (0xFF land (v asr 40)));
  Bytes.unsafe_set buf (pos + 3) (Char.unsafe_chr (0xFF land (v asr 32)));
  Bytes.unsafe_set buf (pos + 4) (Char.unsafe_chr (0xFF land (v asr 24)));
  Bytes.unsafe_set buf (pos + 5) (Char.unsafe_chr (0xFF land (v asr 16)));
  Bytes.unsafe_set buf (pos + 6) (Char.unsafe_chr (0xFF land (v asr 8)))
;;

let pack_signed_64_int_little_endian ~buf ~pos v =
  (* Safely set the first and last bytes, so that we verify the string bounds. *)
  Bytes.set buf pos (Char.unsafe_chr (0xFF land v));
  Bytes.set buf (pos + 7) (Char.unsafe_chr (0xFF land (v asr 56)));
  (* Now we can use [unsafe_set] for the intermediate bytes. *)
  Bytes.unsafe_set buf (pos + 1) (Char.unsafe_chr (0xFF land (v asr 8)));
  Bytes.unsafe_set buf (pos + 2) (Char.unsafe_chr (0xFF land (v asr 16)));
  Bytes.unsafe_set buf (pos + 3) (Char.unsafe_chr (0xFF land (v asr 24)));
  Bytes.unsafe_set buf (pos + 4) (Char.unsafe_chr (0xFF land (v asr 32)));
  Bytes.unsafe_set buf (pos + 5) (Char.unsafe_chr (0xFF land (v asr 40)));
  Bytes.unsafe_set buf (pos + 6) (Char.unsafe_chr (0xFF land (v asr 48)))
;;

let unpack_signed_64_int ~byte_order ~buf ~pos =
  assert (Sys.word_size_in_bits = 64);
  (Char.code (Bytes.get buf (pos + offset ~len:8 ~byte_order 0)) lsl 56)
  lor (Char.code (Bytes.get buf (pos + offset ~len:8 ~byte_order 1)) lsl 48)
  lor (Char.code (Bytes.get buf (pos + offset ~len:8 ~byte_order 2)) lsl 40)
  lor (Char.code (Bytes.get buf (pos + offset ~len:8 ~byte_order 3)) lsl 32)
  lor (Char.code (Bytes.get buf (pos + offset ~len:8 ~byte_order 4)) lsl 24)
  lor (Char.code (Bytes.get buf (pos + offset ~len:8 ~byte_order 5)) lsl 16)
  lor (Char.code (Bytes.get buf (pos + offset ~len:8 ~byte_order 6)) lsl 8)
  lor Char.code (Bytes.get buf (pos + offset ~len:8 ~byte_order 7))
;;

exception Unpack_signed_64_int_most_significant_byte_too_large of int [@@deriving sexp]

let check_highest_order_byte_range byte =
  if byte < 64 || byte >= 192
  then ()
  else raise (Unpack_signed_64_int_most_significant_byte_too_large byte)
;;

let unpack_signed_64_int_big_endian ~buf ~pos =
  assert (Sys.word_size_in_bits = 64);
  (* Do bounds checking only on the first and last bytes *)
  let b1 = Char.code (Bytes.get buf pos)
  and b8 = Char.code (Bytes.get buf (pos + 7)) in
  let b2 = Char.code (Bytes.unsafe_get buf (pos + 1))
  and b3 = Char.code (Bytes.unsafe_get buf (pos + 2))
  and b4 = Char.code (Bytes.unsafe_get buf (pos + 3))
  and b5 = Char.code (Bytes.unsafe_get buf (pos + 4))
  and b6 = Char.code (Bytes.unsafe_get buf (pos + 5))
  and b7 = Char.code (Bytes.unsafe_get buf (pos + 6)) in
  check_highest_order_byte_range b1;
  (b1 lsl 56)
  lor (b2 lsl 48)
  lor (b3 lsl 40)
  lor (b4 lsl 32)
  lor (b5 lsl 24)
  lor (b6 lsl 16)
  lor (b7 lsl 8)
  lor b8
;;

let unpack_signed_64_int_little_endian ~buf ~pos =
  assert (Sys.word_size_in_bits = 64);
  (* Do bounds checking only on the first and last bytes *)
  let b1 = Char.code (Bytes.get buf pos)
  and b8 = Char.code (Bytes.get buf (pos + 7)) in
  let b2 = Char.code (Bytes.unsafe_get buf (pos + 1))
  and b3 = Char.code (Bytes.unsafe_get buf (pos + 2))
  and b4 = Char.code (Bytes.unsafe_get buf (pos + 3))
  and b5 = Char.code (Bytes.unsafe_get buf (pos + 4))
  and b6 = Char.code (Bytes.unsafe_get buf (pos + 5))
  and b7 = Char.code (Bytes.unsafe_get buf (pos + 6)) in
  check_highest_order_byte_range b8;
  b1
  lor (b2 lsl 8)
  lor (b3 lsl 16)
  lor (b4 lsl 24)
  lor (b5 lsl 32)
  lor (b6 lsl 40)
  lor (b7 lsl 48)
  lor (b8 lsl 56)
;;

let pack_float ~byte_order ~buf ~pos f =
  pack_signed_64 ~byte_order ~buf ~pos (Int64.bits_of_float f)
;;

let unpack_float ~byte_order ~buf ~pos =
  Int64.float_of_bits (unpack_signed_64 ~byte_order ~buf ~pos)
;;

let rec last_nonmatch_plus_one ~buf ~min_pos ~pos ~char =
  let pos' = pos - 1 in
  if pos' >= min_pos && Core_char.( = ) (Bytes.get buf pos') char
  then last_nonmatch_plus_one ~buf ~min_pos ~pos:pos' ~char
  else pos
;;

let unpack_tail_padded_fixed_string ?(padding = '\x00') ~buf ~pos ~len () =
  let data_end =
    last_nonmatch_plus_one ~buf ~min_pos:pos ~pos:(pos + len) ~char:padding
  in
  Bytes.To_string.sub buf ~pos ~len:(data_end - pos)
;;

exception
  Pack_tail_padded_fixed_string_argument_too_long of
    [ `s of string ] * [ `longer_than ] * [ `len of int ]
[@@deriving sexp]

let pack_tail_padded_fixed_string ?(padding = '\x00') ~buf ~pos ~len s =
  let slen = String.length s in
  if slen > len
  then
    raise (Pack_tail_padded_fixed_string_argument_too_long (`s s, `longer_than, `len len))
  else (
    Bytes.From_string.blit ~src:s ~dst:buf ~src_pos:0 ~dst_pos:pos ~len:slen;
    if slen < len
    then (
      let diff = len - slen in
      Bytes.fill buf ~pos:(pos + slen) ~len:diff padding))
;;

module Private = struct
  let last_nonmatch_plus_one = last_nonmatch_plus_one

  exception
    Unpack_signed_64_int_most_significant_byte_too_large = Unpack_signed_64_int_most_significant_byte_too_large
end
OCaml

Innovation. Community. Security.