# Parsing of binary data

**URL:** <https://swi-prolog.discourse.group/t/parsing-of-binary-data/1370>\
**Category:** Nice to know\
**Created:** [October 9, 2019, 9:37pm UTC](https://swi-prolog.discourse.group/t/parsing-of-binary-data/1370 "2019-10-09T21:37:20Z")\
**Posts on this page:** 1\
**Page:** 1

<div class="post-metadata">

**Author:** ![EricGT](https://avatars.discourse-cdn.com/v4/letter/e/f1d935/32.png) [@EricGT](https://swi-prolog.discourse.group/u/EricGT)\
**Post date:** [October 9, 2019, 9:37pm UTC](https://swi-prolog.discourse.group/t/parsing-of-binary-data/1370/1 "2019-10-09T21:37:20Z")

</div>

This is related to this post [Making a large prolog based knowledge base for bioinformatics/epidemiology](https://swi-prolog.discourse.group/t/making-a-large-prolog-based-knowledge-base-for-bioinformatics-epidemiology/1368)

Here are some example of the predicates used when parsing binary data files. [binary.pl](https://swi-prolog.discourse.group/uploads/short-url/2qMLZeeMcgB5VXFaVTdbNtzbHrY.pl) (9.9 KB)

```prolog
get_byte(Stream,Address,Word) :-
    seek(Stream,Address,bof,_New_address),
    get_byte(Stream,Word).
get_byte(Stream,Address0,Address,Byte) :-
    get_byte(Stream,Address0,Byte),
    Address is Address0 + 16'01.

get_word(Stream,Endian,Word) :-
    get_byte(Stream,Byte_0),
    get_byte(Stream,Byte_1),
    (
        Endian == big
    ->
        Word #= (Byte_0 << 8) + Byte_1
    ;
        Word #= (Byte_1 << 8) + Byte_0
    ).
get_word(Stream,Endian,Address,Word) :-
    seek(Stream,Address,bof,_New_address),
    get_word(Stream,Endian,Word).
get_word(Stream,Endian,Address0,Address,Word) :-
    get_word(Stream,Endian,Address0,Word),
    Address is Address0 + 16'02.

```

Example to parse the start and header of a BGEN file ([format](https://www.well.ox.ac.uk/~gav/bgen_format/spec/latest.html)).  
Example BGEN file ([link](https://bitbucket.org/gavinband/bgen/src/default/example/)) - File name: `complex.10bits.bgen`

```prolog
% -----------------------------------------------------------------------------

:- module(bgen_dcg,
    [
    ]).

% -----------------------------------------------------------------------------

:- use_module(library(dcg/basics)).

:- use_module('D:/binary.pl').

% -----------------------------------------------------------------------------

parse_bgen_file(Stream,bgen(First_variant_offset,Header),Size) :-
    Offset0 = 16'00,
    binary:get_doubleword(Stream,little,Offset0,Offset1,First_variant_offset),
    get_header(Stream,Offset1,Offset2,Header),
    Offset = Offset2,
    Size = Offset.

get_header(Stream,Offset0,Offset,header(Header_length,Variant_data_block_count,Sample_count,Magic_number,Free_data,Flags)) :-
    binary:get_doubleword(Stream,little,Offset0,Offset1,Header_length),
    binary:get_doubleword(Stream,little,Offset1,Offset2,Variant_data_block_count),
    binary:get_doubleword(Stream,little,Offset2,Offset3,Sample_count),
    binary:get_bytes(Stream,Offset3,Offset4,4,Magic_number),
    string_codes(String,Magic_number),
    assertion( String == "bgen" ),
    Free_data_size is Header_length - 20,
    binary:get_bytes(Stream,Offset4,Offset5,Free_data_size,Free_data),
    binary:get_doubleword(Stream,big,Offset5,Offset,Flags).

% -----------------------------------------------------------------------------

:- begin_tests(parse_BGEN).

test(001) :-
    Path = 'D:/complex.10bits.bgen',
    open(Path,read,Stream,[type(binary)]),
    parse_bgen_file(Stream,Data,Size),
    assertion( Data == bgen(68,header(20,10,4,`bgen`,[],150995072)) ), % NB `bgen` is a character code list not a string
    assertion( Size == 24 ).

:- end_tests(parse_BGEN).

% -------------------------------------

```

Note to Sam. The original code I sent could only do big endian, this can also do little endian.
