[m-rev.] for review: reading multibyte integers from binary file streams

Julien Fischer jfischer at opturion.com
Tue Jan 8 12:43:43 AEDT 2019


Hi,

Any takers to review this one?

Cheers,
Julien.

On Fri, 4 Jan 2019, Julien Fischer wrote:

>
> For review by anyone.
>
> ---------------------
>
> Reading multibyte integers from binary file streams.
>
> Add predicates for reading multibyte integers from binary file streams.  As
> with the corresponding predicates for writing multibyte integers to binary 
> file
> streams, we provide versions for big-endian, little-endian and native byte
> orders.
>
> library/io.m:
>     Add a new type that represents possibly incomplete results when reading
>     from binary file streams.
>
>    Add the new predicates.
>
> tests/hard_coded/Mmakefile:
> tests/hard_coded/read_binary_{int,uint}{16,32,64}.{m,exp}:
>     Add tests of the new predicates.
>
> Julien.
>
> diff --git a/library/io.m b/library/io.m
> index d407c09..4b852c7 100644
> --- a/library/io.m
> +++ b/library/io.m
> @@ -108,6 +108,16 @@
>     ;        eof
>     ;        error(io.error).
>
> +    % maybe_incomplete_result is used for multibyte values read from a 
> binary
> +    % stream where it is possible for the final element in the stream to be
> +    % incomplete.
> +    %
> +:- type maybe_incomplete_result(T)
> +    --->    ok(T)
> +    ;       eof
> +    ;       incomplete(list(uint8))
> +    ;       error(io.error).
> +
>  :- type read_result(T)
>      --->    ok(T)
>     ;        eof
> @@ -872,6 +882,117 @@
> :- pred read_binary_uint8(io.binary_input_stream::in, io.result(uint8)::out,
>      io::di, io::uo) is det.
>
> +    % The following predicates read multibyte integer values from the 
> current
> +    % binary input stream or from the specified input stream.
> +    %
> +    % These names of these predicates have the form:
> +    %
> +    %    read_binary_<TYPE><SUFFIX>
> +    %
> +    % where <TYPE> is the name of one of the Mercury multibyte fixed size
> +    % integer types. <SUFFIX> is optional and specifies the byte order in
> +    % which the integer value is read from the stream.  It may be one of:
> +    %
> +    %     no suffix - native byte order of the underlying platform.
> +    %     "_le"     - little endian byte order.
> +    %     "_be"     - big endian byte order.
> +    %
> +:- pred read_binary_int16(maybe_incomplete_result(int16)::out,
> +    io::di, io::uo) is det.
> +:- pred read_binary_int16(io.binary_input_stream::in,
> +    maybe_incomplete_result(int16)::out, io::di, io::uo) is det.
> +
> +:- pred read_binary_int16_le(maybe_incomplete_result(int16)::out,
> +    io::di, io::uo) is det.
> +:- pred read_binary_int16_le(io.binary_input_stream::in,
> +    maybe_incomplete_result(int16)::out, io::di, io::uo) is det.
> +
> +:- pred read_binary_int16_be(maybe_incomplete_result(int16)::out,
> +    io::di, io::uo) is det.
> +:- pred read_binary_int16_be(io.binary_input_stream::in,
> +    maybe_incomplete_result(int16)::out, io::di, io::uo) is det.
> +
> +:- pred read_binary_uint16(maybe_incomplete_result(uint16)::out,
> +    io::di, io::uo) is det.
> +:- pred read_binary_uint16(io.binary_input_stream::in,
> +    maybe_incomplete_result(uint16)::out, io::di, io::uo) is det.
> +
> +:- pred read_binary_uint16_le(maybe_incomplete_result(uint16)::out,
> +    io::di, io::uo) is det.
> +:- pred read_binary_uint16_le(io.binary_input_stream::in,
> +    maybe_incomplete_result(uint16)::out, io::di, io::uo) is det.
> +
> +:- pred read_binary_uint16_be(maybe_incomplete_result(uint16)::out,
> +    io::di, io::uo) is det.
> +:- pred read_binary_uint16_be(io.binary_input_stream::in,
> +    maybe_incomplete_result(uint16)::out, io::di, io::uo) is det.
> +
> +%---------------------%
> +
> +:- pred read_binary_int32(maybe_incomplete_result(int32)::out,
> +    io::di, io::uo) is det.
> +:- pred read_binary_int32(io.binary_input_stream::in,
> +    maybe_incomplete_result(int32)::out, io::di, io::uo) is det.
> +
> +:- pred read_binary_int32_le(maybe_incomplete_result(int32)::out,
> +    io::di, io::uo) is det.
> +:- pred read_binary_int32_le(io.binary_input_stream::in,
> +    maybe_incomplete_result(int32)::out, io::di, io::uo) is det.
> +
> +:- pred read_binary_int32_be(maybe_incomplete_result(int32)::out,
> +    io::di, io::uo) is det.
> +:- pred read_binary_int32_be(io.binary_input_stream::in,
> +    maybe_incomplete_result(int32)::out, io::di, io::uo) is det.
> +
> +:- pred read_binary_uint32(maybe_incomplete_result(uint32)::out,
> +    io::di, io::uo) is det.
> +:- pred read_binary_uint32(io.binary_input_stream::in,
> +    maybe_incomplete_result(uint32)::out, io::di, io::uo) is det.
> +
> +:- pred read_binary_uint32_le(maybe_incomplete_result(uint32)::out,
> +    io::di, io::uo) is det.
> +:- pred read_binary_uint32_le(io.binary_input_stream::in,
> +    maybe_incomplete_result(uint32)::out, io::di, io::uo) is det.
> +
> +:- pred read_binary_uint32_be(maybe_incomplete_result(uint32)::out,
> +    io::di, io::uo) is det.
> +:- pred read_binary_uint32_be(io.binary_input_stream::in,
> +    maybe_incomplete_result(uint32)::out, io::di, io::uo) is det.
> +
> +%---------------------%
> +
> +:- pred read_binary_int64(maybe_incomplete_result(int64)::out,
> +    io::di, io::uo) is det.
> +:- pred read_binary_int64(io.binary_input_stream::in,
> +    maybe_incomplete_result(int64)::out, io::di, io::uo) is det.
> +
> +:- pred read_binary_int64_le(maybe_incomplete_result(int64)::out,
> +    io::di, io::uo) is det.
> +:- pred read_binary_int64_le(io.binary_input_stream::in,
> +    maybe_incomplete_result(int64)::out, io::di, io::uo) is det.
> +
> +:- pred read_binary_int64_be(maybe_incomplete_result(int64)::out,
> +    io::di, io::uo) is det.
> +:- pred read_binary_int64_be(io.binary_input_stream::in,
> +    maybe_incomplete_result(int64)::out, io::di, io::uo) is det.
> +
> +:- pred read_binary_uint64(maybe_incomplete_result(uint64)::out,
> +    io::di, io::uo) is det.
> +:- pred read_binary_uint64(io.binary_input_stream::in,
> +    maybe_incomplete_result(uint64)::out, io::di, io::uo) is det.
> +
> +:- pred read_binary_uint64_le(maybe_incomplete_result(uint64)::out,
> +    io::di, io::uo) is det.
> +:- pred read_binary_uint64_le(io.binary_input_stream::in,
> +    maybe_incomplete_result(uint64)::out, io::di, io::uo) is det.
> +
> +:- pred read_binary_uint64_be(maybe_incomplete_result(uint64)::out,
> +    io::di, io::uo) is det.
> +:- pred read_binary_uint64_be(io.binary_input_stream::in,
> +    maybe_incomplete_result(uint64)::out, io::di, io::uo) is det.
> +
> +%---------------------%
> +
>     %  Fill a bitmap from the current binary input stream
>     %  or from the specified binary input stream.
>     %  Return the number of bytes read. On end-of-file, the number of
> @@ -1977,6 +2098,9 @@
>  :- import_module exception.
>  :- import_module int.
>  :- import_module int8.
> +:- import_module int16.
> +:- import_module int32.
> +:- import_module int64.
>  :- import_module parser.
>  :- import_module require.
>  :- import_module stream.string_writer.
> @@ -2132,6 +2256,19 @@ using System.Security.Principal;
>  :- pragma foreign_export_enum("Java", result_code/0,
>      [prefix("ML_RESULT_CODE_"), uppercase]).
>
> +:- type maybe_incomplete_result_code
> +    --->    ok
> +    ;       eof
> +    ;       incomplete
> +    ;       error.
> +
> +:- pragma foreign_export_enum("C", maybe_incomplete_result_code/0,
> +    [prefix("ML_MAYBE_INCOMPLETE_RESULT_CODE_"), uppercase]).
> +:- pragma foreign_export_enum("C#", maybe_incomplete_result_code/0,
> +    [prefix("ML_MAYBE_INCOMPLETE_RESULT_CODE_"), uppercase]).
> +:- pragma foreign_export_enum("Java", maybe_incomplete_result_code/0,
> +    [prefix("ML_MAYBE_INCOMPLETE_RESULT_CODE_"), uppercase]).
> +
>     %  Reads a character (code point) from specified stream. This may
>     %  involve converting external character encodings into Mercury's
>     %  internal
>     %  character representation and (for text streams) converting OS line
> @@ -2383,6 +2520,825 @@ read_binary_uint8(binary_input_stream(Stream), 
> Result, !IO) :-
>          Result = error(io_error(Msg))
>     ) .
>
> +%---------------------%
> +
> +read_binary_int16(Result, !IO) :-
> +    binary_input_stream(Stream, !IO),
> +    read_binary_int16(Stream, Result, !IO).
> +
> +read_binary_int16(Stream, Result, !IO) :-
> +    ( if native_byte_order_is_big_endian then
> +        read_binary_int16_be(Stream, Result, !IO)
> +    else
> +        read_binary_int16_le(Stream, Result, !IO)
> +    ).
> +
> +:- pred native_byte_order_is_big_endian is semidet.
> +
> +:- pragma foreign_proc("C",
> +    native_byte_order_is_big_endian,
> +    [promise_pure, will_not_call_mercury, thread_safe],
> +"
> +    #if defined(MR_BIG_ENDIAN)
> +        SUCCESS_INDICATOR = MR_TRUE;
> +    #else
> +        SUCCESS_INDICATOR = MR_FALSE;
> +    #endif
> +").
> +
> +:- pragma foreign_proc("C#",
> +    native_byte_order_is_big_endian,
> +    [promise_pure, will_not_call_mercury, thread_safe],
> +"
> +    SUCCESS_INDICATOR = !(BitConverter.IsLittleEndian);
> +").
> +
> +:- pragma foreign_proc("Java",
> +    native_byte_order_is_big_endian,
> +    [promise_pure, will_not_call_mercury, thread_safe],
> +"
> +    SUCCESS_INDICATOR =
> +        (java.nio.ByteOrder.nativeOrder() == java.nio.ByteOrder.BIG_ENDIAN);
> +").
> +
> +native_byte_order_is_big_endian :-
> +    sorry($module,
> +        "native_byte_order_is_big_endian/0 NYI for Erlang").
> +
> +%---------------------%
> +
> +read_binary_int16_le(Result, !IO) :-
> +    binary_input_stream(Stream, !IO),
> +    read_binary_int16_le(Stream, Result, !IO).
> +
> +read_binary_int16_le(binary_input_stream(Stream), Result, !IO) :-
> +    do_read_binary_uint16_le(Stream, Result0, UInt16, IncompleteBytes,
> +        Error, !IO),
> +    (
> +        Result0 = ok,
> +        Int16 = cast_from_uint16(UInt16),
> +        Result = ok(Int16)
> +    ;
> +        Result0 = eof,
> +        Result = eof
> +    ;
> +        Result0 = incomplete,
> +        Result = incomplete(IncompleteBytes)
> +    ;
> +        Result0 = error,
> +        make_err_msg(Error, "read failed: ", Msg),
> +        Result = error(io_error(Msg))
> +    ).
> +
> +%---------------------%
> +
> +read_binary_int16_be(Result, !IO) :-
> +    binary_input_stream(Stream, !IO),
> +    read_binary_int16_be(Stream, Result, !IO).
> +
> +read_binary_int16_be(binary_input_stream(Stream), Result, !IO) :-
> +    do_read_binary_uint16_le(Stream, Result0, UInt16LE, IncompleteBytes,
> +        Error, !IO),
> +    (
> +        Result0 = ok,
> +        UInt16BE = reverse_bytes(UInt16LE),
> +        Int16 = cast_from_uint16(UInt16BE),
> +        Result = ok(Int16)
> +    ;
> +        Result0 = eof,
> +        Result = eof
> +    ;
> +        Result0 = incomplete,
> +        Result = incomplete(IncompleteBytes)
> +    ;
> +        Result0 = error,
> +        make_err_msg(Error, "read failed: ", Msg),
> +        Result = error(io_error(Msg))
> +    ).
> +
> +%---------------------%
> +
> +read_binary_uint16(Result, !IO) :-
> +    binary_input_stream(Stream, !IO),
> +    read_binary_uint16(Stream, Result, !IO).
> +
> +read_binary_uint16(Stream, Result, !IO) :-
> +    ( if native_byte_order_is_big_endian then
> +        read_binary_uint16_be(Stream, Result, !IO)
> +    else
> +        read_binary_uint16_le(Stream, Result, !IO)
> +    ).
> +
> +%---------------------%
> +
> +read_binary_uint16_le(Result, !IO) :-
> +    binary_input_stream(Stream, !IO),
> +    read_binary_uint16_le(Stream, Result, !IO).
> +
> +read_binary_uint16_le(binary_input_stream(Stream), Result, !IO) :-
> +    do_read_binary_uint16_le(Stream, Result0, UInt16, IncompleteBytes,
> +        Error, !IO),
> +    (
> +        Result0 = ok,
> +        Result = ok(UInt16)
> +    ;
> +        Result0 = eof,
> +        Result = eof
> +    ;
> +        Result0 = incomplete,
> +        Result = incomplete(IncompleteBytes)
> +    ;
> +        Result0 = error,
> +        make_err_msg(Error, "read failed: ", Msg),
> +        Result = error(io_error(Msg))
> +    ).
> +
> +:- pred do_read_binary_uint16_le(stream::in, 
> maybe_incomplete_result_code::out,
> +    uint16::out, list(uint8)::out, system_error::out, io::di, io::uo) is 
> det.
> +
> +:- pragma foreign_proc("C",
> +    do_read_binary_uint16_le(Stream::in, Result::out, UInt16::out,
> +        IncompleteBytes::out, Error::out, _IO0::di, _IO::uo),
> +    [will_not_call_mercury, promise_pure, thread_safe, 
> will_not_modify_trail],
> +"
> +    unsigned char buffer[2];
> +    size_t nread = MR_READ(*Stream, buffer, 2);
> +    IncompleteBytes = MR_list_empty();
> +
> +    if (nread < 2) {
> +        UInt16 = 0;
> +        if (MR_FERROR(*Stream)) {
> +            Result = ML_MAYBE_INCOMPLETE_RESULT_CODE_ERROR,
> +            Error = errno;
> +        } else if (nread > 0) {
> +            int i;
> +            Result = ML_MAYBE_INCOMPLETE_RESULT_CODE_INCOMPLETE;
> +            IncompleteBytes = MR_list_cons(buffer[0], IncompleteBytes);
> +            Error = 0;
> +        } else {
> +            Result = ML_MAYBE_INCOMPLETE_RESULT_CODE_EOF;
> +            Error = 0;
> +        }
> +    } else {
> +        Result = ML_MAYBE_INCOMPLETE_RESULT_CODE_OK;
> +        #if defined(MR_BIG_ENDIAN)
> +            ((unsigned char *) &UInt16)[0] = buffer[1];
> +            ((unsigned char *) &UInt16)[1] = buffer[0];
> +        #else
> +            UInt16 = *((uint16_t *) buffer);
> +        #endif
> +        Error = 0;
> +    }
> +").
> +
> +:- pragma foreign_proc("C#",
> +    do_read_binary_uint16_le(Stream::in, Result::out, UInt16::out,
> +        IncompleteBytes::out, Error::out, _IO0::di, _IO::uo),
> +    [will_not_call_mercury, promise_pure, thread_safe],
> +"
> +    byte[] buffer = new byte[2];
> +    io.MR_MercuryFileStruct mf = Stream;
> +    UInt16 = 0;
> +    IncompleteBytes = list.empty_list();
> +
> +    int nread = 0;
> +
> +    if (mf.putback != -1) {
> +        buffer[nread] = (byte) mf.putback;
> +        nread++;
> +        mf.putback = -1;
> +    }
> +
> +    try {
> +        for ( ; nread < 2; nread++) {
> +            int b = mf.stream.ReadByte();
> +            if (b == -1) {
> +                break;
> +            }
> +            buffer[nread] = (byte) b;
> +        }
> +        if (nread < 2) {
> +            if (nread > 0) {
> +                Result = io.ML_MAYBE_INCOMPLETE_RESULT_CODE_INCOMPLETE;
> +                IncompleteBytes = list.cons(buffer[0], IncompleteBytes);
> +            } else {
> +                Result = io.ML_MAYBE_INCOMPLETE_RESULT_CODE_EOF;
> +            }
> +        } else {
> +            Result = io.ML_MAYBE_INCOMPLETE_RESULT_CODE_OK;
> +            UInt16 = (ushort) (buffer[1] << 8 | (buffer[0] & 0x00ff));
> +        }
> +        Error = null;
> +    } catch (System.Exception e) {
> +        Result = io.ML_MAYBE_INCOMPLETE_RESULT_CODE_ERROR;
> +        Error = e;
> +    }
> +").
> +
> +:- pragma foreign_proc("Java",
> +    do_read_binary_uint16_le(Stream::in, Result::out, UInt16::out,
> +        IncompleteBytes::out, Error::out, _IO0::di, _IO::uo),
> +    [will_not_call_mercury, promise_pure, thread_safe],
> +"
> +    byte[] buffer = new byte[2];
> +    MR_BinaryInputFile mf = (MR_BinaryInputFile) Stream;
> +    UInt16 = 0;
> +    IncompleteBytes = list.empty_list();
> +
> +    try {
> +        int nread;
> +        for (nread = 0; nread < 2; nread++) {
> +            int next = mf.read_byte();
> +            if (next == -1) {
> +                break;
> +            }
> +            buffer[nread] = (byte) next;
> +        }
> +        if (nread < 2) {
> +            if (nread > 0) {
> +                Result = io.ML_MAYBE_INCOMPLETE_RESULT_CODE_INCOMPLETE;
> +                IncompleteBytes = list.cons(buffer[0], IncompleteBytes);
> +            } else {
> +                Result = io.ML_MAYBE_INCOMPLETE_RESULT_CODE_EOF;
> +            }
> +        } else {
> +            Result = io.ML_MAYBE_INCOMPLETE_RESULT_CODE_OK;
> +            UInt16 = (short) (buffer[1] << 8 | (buffer[0] & 0x00ff));
> +        }
> +        Error = null;
> +    } catch (java.lang.Exception e) {
> +        Result = io.ML_MAYBE_INCOMPLETE_RESULT_CODE_ERROR;
> +        Error = e;
> +    }
> +").
> +
> +do_read_binary_uint16_le(_, _, _, _, _, _, _) :-
> +    sorry($module, "do_read_binary_uint16_le NYI for Erlang").
> +
> +%---------------------%
> +
> +read_binary_uint16_be(Result, !IO) :-
> +    binary_input_stream(Stream, !IO),
> +    read_binary_uint16_be(Stream, Result, !IO).
> +
> +read_binary_uint16_be(binary_input_stream(Stream), Result, !IO) :-
> +    do_read_binary_uint16_le(Stream, Result0, UInt16LE, IncompleteBytes,
> +        Error, !IO),
> +    (
> +        Result0 = ok,
> +        UInt16BE = uint16.reverse_bytes(UInt16LE),
> +        Result = ok(UInt16BE)
> +    ;
> +        Result0 = eof,
> +        Result = eof
> +    ;
> +        Result0 = incomplete,
> +        Result = incomplete(IncompleteBytes)
> +    ;
> +        Result0 = error,
> +        make_err_msg(Error, "read failed: ", Msg),
> +        Result = error(io_error(Msg))
> +    ).
> +
> +%---------------------%
> +
> +read_binary_int32(Result, !IO) :-
> +    binary_input_stream(Stream, !IO),
> +    read_binary_int32(Stream, Result, !IO).
> +
> +read_binary_int32(Stream, Result, !IO) :-
> +    ( if native_byte_order_is_big_endian then
> +        read_binary_int32_be(Stream, Result, !IO)
> +    else
> +        read_binary_int32_le(Stream, Result, !IO)
> +    ).
> +
> +%---------------------%
> +
> +read_binary_int32_le(Result, !IO) :-
> +    binary_input_stream(Stream, !IO),
> +    read_binary_int32_le(Stream, Result, !IO).
> +
> +read_binary_int32_le(binary_input_stream(Stream), Result, !IO) :-
> +    do_read_binary_uint32_le(Stream, Result0, UInt32, IncompleteBytes,
> +        Error, !IO),
> +    (
> +        Result0 = ok,
> +        Int32 = cast_from_uint32(UInt32),
> +        Result = ok(Int32)
> +    ;
> +        Result0 = eof,
> +        Result = eof
> +    ;
> +        Result0 = incomplete,
> +        Result = incomplete(IncompleteBytes)
> +    ;
> +        Result0 = error,
> +        make_err_msg(Error, "read failed: ", Msg),
> +        Result = error(io_error(Msg))
> +    ).
> +
> +%---------------------%
> +
> +read_binary_int32_be(Result, !IO) :-
> +    binary_input_stream(Stream, !IO),
> +    read_binary_int32_be(Stream, Result, !IO).
> +
> +read_binary_int32_be(binary_input_stream(Stream), Result, !IO) :-
> +    do_read_binary_uint32_le(Stream, Result0, UInt32LE, IncompleteBytes,
> +        Error, !IO),
> +    (
> +        Result0 = ok,
> +        UInt32BE = reverse_bytes(UInt32LE),
> +        Int32 = cast_from_uint32(UInt32BE),
> +        Result = ok(Int32)
> +    ;
> +        Result0 = eof,
> +        Result = eof
> +    ;
> +        Result0 = incomplete,
> +        Result = incomplete(IncompleteBytes)
> +    ;
> +        Result0 = error,
> +        make_err_msg(Error, "read failed: ", Msg),
> +        Result = error(io_error(Msg))
> +    ).
> +
> +%---------------------%
> +
> +read_binary_uint32(Result, !IO) :-
> +    binary_input_stream(Stream, !IO),
> +    read_binary_uint32(Stream, Result, !IO).
> +
> +read_binary_uint32(Stream, Result, !IO) :-
> +    ( if native_byte_order_is_big_endian then
> +        read_binary_uint32_be(Stream, Result, !IO)
> +    else
> +        read_binary_uint32_le(Stream, Result, !IO)
> +    ).
> +
> +%---------------------%
> +
> +read_binary_uint32_le(Result, !IO) :-
> +    binary_input_stream(Stream, !IO),
> +    read_binary_uint32_le(Stream, Result, !IO).
> +
> +read_binary_uint32_le(binary_input_stream(Stream), Result, !IO) :-
> +    do_read_binary_uint32_le(Stream, Result0, UInt32, IncompleteBytes,
> +        Error, !IO),
> +    (
> +        Result0 = ok,
> +        Result = ok(UInt32)
> +    ;
> +        Result0 = eof,
> +        Result = eof
> +    ;
> +        Result0 = incomplete,
> +        Result = incomplete(IncompleteBytes)
> +    ;
> +        Result0 = error,
> +        make_err_msg(Error, "read failed: ", Msg),
> +        Result = error(io_error(Msg))
> +    ).
> +
> +:- pred do_read_binary_uint32_le(stream::in, 
> maybe_incomplete_result_code::out,
> +    uint32::out, list(uint8)::out, system_error::out, io::di, io::uo) is 
> det.
> +
> +:- pragma foreign_proc("C",
> +    do_read_binary_uint32_le(Stream::in, Result::out, UInt32::out,
> +        IncompleteBytes::out, Error::out, _IO0::di, _IO::uo),
> +    [will_not_call_mercury, promise_pure, thread_safe, 
> will_not_modify_trail],
> +"
> +    unsigned char buffer[4];
> +    size_t nread = MR_READ(*Stream, buffer, 4);
> +    IncompleteBytes = MR_list_empty();
> +
> +    if (nread < 4) {
> +        UInt32 = 0;
> +        if (MR_FERROR(*Stream)) {
> +            Result = ML_MAYBE_INCOMPLETE_RESULT_CODE_ERROR,
> +            Error = errno;
> +        } else if (nread > 0) {
> +            int i;
> +            Result = ML_MAYBE_INCOMPLETE_RESULT_CODE_INCOMPLETE;
> +            for (i = nread - 1; i >= 0; i--) {
> +                IncompleteBytes = MR_list_cons(buffer[i], IncompleteBytes);
> +            }
> +            Error = 0;
> +        } else {
> +            Result = ML_MAYBE_INCOMPLETE_RESULT_CODE_EOF;
> +            Error = 0;
> +        }
> +    } else {
> +        Result = ML_MAYBE_INCOMPLETE_RESULT_CODE_OK;
> +        #if defined(MR_BIG_ENDIAN)
> +            ((unsigned char *) &UInt32)[0] = buffer[3];
> +            ((unsigned char *) &UInt32)[1] = buffer[2];
> +            ((unsigned char *) &UInt32)[2] = buffer[1];
> +            ((unsigned char *) &UInt32)[3] = buffer[0];
> +        #else
> +            UInt32 = *((uint32_t *) buffer);
> +        #endif
> +        Error = 0;
> +    }
> +").
> +
> +:- pragma foreign_proc("C#",
> +    do_read_binary_uint32_le(Stream::in, Result::out, UInt32::out,
> +        IncompleteBytes::out, Error::out, _IO0::di, _IO::uo),
> +    [will_not_call_mercury, promise_pure, thread_safe],
> +"
> +    byte[] buffer = new byte[4];
> +    io.MR_MercuryFileStruct mf = Stream;
> +    UInt32 = 0;
> +    IncompleteBytes = list.empty_list();
> +
> +    int nread = 0;
> +
> +    if (mf.putback != -1) {
> +        buffer[nread] = (byte) mf.putback;
> +        nread++;
> +        mf.putback = -1;
> +    }
> +
> +    try {
> +        for ( ; nread < 4; nread++) {
> +            int b = mf.stream.ReadByte();
> +            if (b == -1) {
> +                break;
> +            }
> +            buffer[nread] = (byte) b;
> +        }
> +        if (nread < 4) {
> +            if (nread > 0) {
> +                Result = io.ML_MAYBE_INCOMPLETE_RESULT_CODE_INCOMPLETE;
> +                for (int i = nread - 1; i >= 0; i--) {
> +                    IncompleteBytes = list.cons(buffer[i], IncompleteBytes);
> +                }
> +            } else {
> +                Result = io.ML_MAYBE_INCOMPLETE_RESULT_CODE_EOF;
> +            }
> +        } else {
> +            Result = io.ML_MAYBE_INCOMPLETE_RESULT_CODE_OK;
> +            UInt32 = (uint) (buffer[3] << 24 | buffer[2] << 16 |
> +                buffer[1] << 8 | buffer[0]);
> +        }
> +        Error = null;
> +    } catch (System.Exception e) {
> +        Result = io.ML_MAYBE_INCOMPLETE_RESULT_CODE_ERROR;
> +        Error = e;
> +    }
> +").
> +
> +:- pragma foreign_proc("Java",
> +    do_read_binary_uint32_le(Stream::in, Result::out, UInt32::out,
> +        IncompleteBytes::out, Error::out, _IO0::di, _IO::uo),
> +    [will_not_call_mercury, promise_pure, thread_safe],
> +"
> +    byte[] buffer = new byte[4];
> +    MR_BinaryInputFile mf = (MR_BinaryInputFile) Stream;
> +    UInt32 = 0;
> +    IncompleteBytes = list.empty_list();
> +
> +    try {
> +        int nread;
> +        for (nread = 0; nread < 4; nread++) {
> +            int next = mf.read_byte();
> +            if (next == -1) {
> +                break;
> +            }
> +            buffer[nread] = (byte) next;
> +        }
> +        if (nread < 4) {
> +            if (nread > 0) {
> +                Result = io.ML_MAYBE_INCOMPLETE_RESULT_CODE_INCOMPLETE;
> +                for (int i = nread - 1; i >= 0; i--) {
> +                    IncompleteBytes = list.cons(buffer[i], IncompleteBytes);
> +                }
> +            } else {
> +                Result = io.ML_MAYBE_INCOMPLETE_RESULT_CODE_EOF;
> +            }
> +        } else {
> +            Result = io.ML_MAYBE_INCOMPLETE_RESULT_CODE_OK;
> +            UInt32 =
> +                (buffer[3] & 0xff) << 24 |
> +                (buffer[2] & 0xff) << 16 |
> +                (buffer[1] & 0xff) << 8  |
> +                (buffer[0] & 0xff);
> +        }
> +        Error = null;
> +    } catch (java.lang.Exception e) {
> +        Result = io.ML_MAYBE_INCOMPLETE_RESULT_CODE_ERROR;
> +        Error = e;
> +    }
> +").
> +
> +do_read_binary_uint32_le(_, _, _, _, _, _, _) :-
> +    sorry($module, "do_read_binary_uint32_le NYI for Erlang").
> +
> +%---------------------%
> +
> +read_binary_uint32_be(Result, !IO) :-
> +    binary_input_stream(Stream, !IO),
> +    read_binary_uint32_be(Stream, Result, !IO).
> +
> +read_binary_uint32_be(binary_input_stream(Stream), Result, !IO) :-
> +    do_read_binary_uint32_le(Stream, Result0, UInt32LE, IncompleteBytes,
> +        Error, !IO),
> +    (
> +        Result0 = ok,
> +        UInt32BE = uint32.reverse_bytes(UInt32LE),
> +        Result = ok(UInt32BE)
> +    ;
> +        Result0 = eof,
> +        Result = eof
> +    ;
> +        Result0 = incomplete,
> +        Result = incomplete(IncompleteBytes)
> +    ;
> +        Result0 = error,
> +        make_err_msg(Error, "read failed: ", Msg),
> +        Result = error(io_error(Msg))
> +    ).
> +
> +%---------------------%
> +
> +read_binary_int64(Result, !IO) :-
> +    binary_input_stream(Stream, !IO),
> +    read_binary_int64(Stream, Result, !IO).
> +
> +read_binary_int64(Stream, Result, !IO) :-
> +    ( if native_byte_order_is_big_endian then
> +        read_binary_int64_be(Stream, Result, !IO)
> +    else
> +        read_binary_int64_le(Stream, Result, !IO)
> +    ).
> +
> +%---------------------%
> +
> +read_binary_int64_le(Result, !IO) :-
> +    binary_input_stream(Stream, !IO),
> +    read_binary_int64_le(Stream, Result, !IO).
> +
> +read_binary_int64_le(binary_input_stream(Stream), Result, !IO) :-
> +    do_read_binary_uint64_le(Stream, Result0, UInt64, IncompleteBytes,
> +        Error, !IO),
> +    (
> +        Result0 = ok,
> +        Int64 = cast_from_uint64(UInt64),
> +        Result = ok(Int64)
> +    ;
> +        Result0 = eof,
> +        Result = eof
> +    ;
> +        Result0 = incomplete,
> +        Result = incomplete(IncompleteBytes)
> +    ;
> +        Result0 = error,
> +        make_err_msg(Error, "read failed: ", Msg),
> +        Result = error(io_error(Msg))
> +    ).
> +
> +%---------------------%
> +
> +read_binary_int64_be(Result, !IO) :-
> +    binary_input_stream(Stream, !IO),
> +    read_binary_int64_be(Stream, Result, !IO).
> +
> +read_binary_int64_be(binary_input_stream(Stream), Result, !IO) :-
> +    do_read_binary_uint64_le(Stream, Result0, UInt64LE, IncompleteBytes,
> +        Error, !IO),
> +    (
> +        Result0 = ok,
> +        UInt64BE = reverse_bytes(UInt64LE),
> +        Int64 = cast_from_uint64(UInt64BE),
> +        Result = ok(Int64)
> +    ;
> +        Result0 = eof,
> +        Result = eof
> +    ;
> +        Result0 = incomplete,
> +        Result = incomplete(IncompleteBytes)
> +    ;
> +        Result0 = error,
> +        make_err_msg(Error, "read failed: ", Msg),
> +        Result = error(io_error(Msg))
> +    ).
> +
> +%---------------------%
> +
> +read_binary_uint64(Result, !IO) :-
> +    binary_input_stream(Stream, !IO),
> +    read_binary_uint64(Stream, Result, !IO).
> +
> +read_binary_uint64(Stream, Result, !IO) :-
> +    ( if native_byte_order_is_big_endian then
> +        read_binary_uint64_be(Stream, Result, !IO)
> +    else
> +        read_binary_uint64_le(Stream, Result, !IO)
> +    ).
> +
> +%---------------------%
> +
> +read_binary_uint64_le(Result, !IO) :-
> +    binary_input_stream(Stream, !IO),
> +    read_binary_uint64_le(Stream, Result, !IO).
> +
> +read_binary_uint64_le(binary_input_stream(Stream), Result, !IO) :-
> +    do_read_binary_uint64_le(Stream, Result0, UInt64, IncompleteBytes,
> +        Error, !IO),
> +    (
> +        Result0 = ok,
> +        Result = ok(UInt64)
> +    ;
> +        Result0 = eof,
> +        Result = eof
> +    ;
> +        Result0 = incomplete,
> +        Result = incomplete(IncompleteBytes)
> +    ;
> +        Result0 = error,
> +        make_err_msg(Error, "read failed: ", Msg),
> +        Result = error(io_error(Msg))
> +    ).
> +
> +:- pred do_read_binary_uint64_le(stream::in, 
> maybe_incomplete_result_code::out,
> +    uint64::out, list(uint8)::out, system_error::out, io::di, io::uo) is 
> det.
> +
> +:- pragma foreign_proc("C",
> +    do_read_binary_uint64_le(Stream::in, Result::out, UInt64::out,
> +        IncompleteBytes::out, Error::out, _IO0::di, _IO::uo),
> +    [will_not_call_mercury, promise_pure, thread_safe, 
> will_not_modify_trail],
> +"
> +    unsigned char buffer[8];
> +    size_t nread = MR_READ(*Stream, buffer, 8);
> +    IncompleteBytes = MR_list_empty();
> +
> +    if (nread < 8) {
> +        UInt64 = 0;
> +        if (MR_FERROR(*Stream)) {
> +            Result = ML_MAYBE_INCOMPLETE_RESULT_CODE_ERROR,
> +            Error = errno;
> +        } else if (nread > 0) {
> +            int i;
> +            Result = ML_MAYBE_INCOMPLETE_RESULT_CODE_INCOMPLETE;
> +            for (i = nread - 1; i >= 0; i--) {
> +                IncompleteBytes = MR_list_cons(buffer[i], IncompleteBytes);
> +            }
> +            Error = 0;
> +        } else {
> +            Result = ML_MAYBE_INCOMPLETE_RESULT_CODE_EOF;
> +            Error = 0;
> +        }
> +    } else {
> +        Result = ML_MAYBE_INCOMPLETE_RESULT_CODE_OK;
> +        #if defined(MR_BIG_ENDIAN)
> +            ((unsigned char *) &UInt64)[0] = buffer[7];
> +            ((unsigned char *) &UInt64)[1] = buffer[6];
> +            ((unsigned char *) &UInt64)[2] = buffer[5];
> +            ((unsigned char *) &UInt64)[3] = buffer[3];
> +            ((unsigned char *) &UInt64)[4] = buffer[3];
> +            ((unsigned char *) &UInt64)[5] = buffer[2];
> +            ((unsigned char *) &UInt64)[6] = buffer[1];
> +            ((unsigned char *) &UInt64)[7] = buffer[0];
> +        #else
> +            UInt64 = *((uint64_t *) buffer);
> +        #endif
> +        Error = 0;
> +    }
> +").
> +
> +:- pragma foreign_proc("C#",
> +    do_read_binary_uint64_le(Stream::in, Result::out, UInt64::out,
> +        IncompleteBytes::out, Error::out, _IO0::di, _IO::uo),
> +    [will_not_call_mercury, promise_pure, thread_safe],
> +"
> +    byte[] buffer = new byte[8];
> +    io.MR_MercuryFileStruct mf = Stream;
> +    UInt64 = 0;
> +    IncompleteBytes = list.empty_list();
> +
> +    int nread = 0;
> +
> +    if (mf.putback != -1) {
> +        buffer[nread] = (byte) mf.putback;
> +        nread++;
> +        mf.putback = -1;
> +    }
> +
> +    try {
> +        for ( ; nread < 8; nread++) {
> +            int b = mf.stream.ReadByte();
> +            if (b == -1) {
> +                break;
> +            }
> +            buffer[nread] = (byte) b;
> +        }
> +        if (nread < 8) {
> +            if (nread > 0) {
> +                Result = io.ML_MAYBE_INCOMPLETE_RESULT_CODE_INCOMPLETE;
> +                for (int i = nread - 1; i >=0; i--) {
> +                    IncompleteBytes = list.cons(buffer[i], IncompleteBytes);
> +                }
> +            } else {
> +                Result = io.ML_MAYBE_INCOMPLETE_RESULT_CODE_EOF;
> +            }
> +        } else {
> +            Result = io.ML_MAYBE_INCOMPLETE_RESULT_CODE_OK;
> +            UInt64 = (ulong) (
> +                (ulong) buffer[7] << 56 |
> +                (ulong) buffer[6] << 48 |
> +                (ulong) buffer[5] << 40 |
> +                (ulong) buffer[4] << 32 |
> +                (ulong) buffer[3] << 24 |
> +                (ulong) buffer[2] << 16 |
> +                (ulong) buffer[1] << 8  |
> +                (ulong) buffer[0]);
> +        }
> +        Error = null;
> +    } catch (System.Exception e) {
> +        Result = io.ML_MAYBE_INCOMPLETE_RESULT_CODE_ERROR;
> +        Error = e;
> +    }
> +").
> +
> +:- pragma foreign_proc("Java",
> +    do_read_binary_uint64_le(Stream::in, Result::out, UInt64::out,
> +        IncompleteBytes::out, Error::out, _IO0::di, _IO::uo),
> +    [will_not_call_mercury, promise_pure, thread_safe],
> +"
> +    byte[] buffer = new byte[8];
> +    MR_BinaryInputFile mf = (MR_BinaryInputFile) Stream;
> +    UInt64 = 0;
> +    IncompleteBytes = list.empty_list();
> +
> +    try {
> +        int nread;
> +        for (nread = 0; nread < 8; nread++) {
> +            int next = mf.read_byte();
> +            if (next == -1) {
> +                break;
> +            }
> +            buffer[nread] = (byte) next;
> +        }
> +        if (nread < 8) {
> +            if (nread > 0) {
> +                Result = io.ML_MAYBE_INCOMPLETE_RESULT_CODE_INCOMPLETE;
> +                for (int i = nread - 1; i >= 0; i--) {
> +                    IncompleteBytes = list.cons(buffer[i], IncompleteBytes);
> +                }
> +            } else {
> +                Result = io.ML_MAYBE_INCOMPLETE_RESULT_CODE_EOF;
> +            }
> +        } else {
> +            Result = io.ML_MAYBE_INCOMPLETE_RESULT_CODE_OK;
> +            UInt64 =
> +                (long) (buffer[7] & 0xff) << 56 |
> +                (long) (buffer[6] & 0xff) << 48 |
> +                (long) (buffer[5] & 0xff) << 40 |
> +                (long) (buffer[4] & 0xff) << 32 |
> +                (long) (buffer[3] & 0xff) << 24 |
> +                (long) (buffer[2] & 0xff) << 16 |
> +                (long) (buffer[1] & 0xff) << 8  |
> +                (long) (buffer[0] & 0xff);
> +        }
> +        Error = null;
> +    } catch (java.lang.Exception e) {
> +        Result = io.ML_MAYBE_INCOMPLETE_RESULT_CODE_ERROR;
> +        Error = e;
> +    }
> +").
> +
> +do_read_binary_uint64_le(_, _, _, _, _, _, _) :-
> +    sorry($module, "do_read_binary_uint64_le NYI for Erlang").
> +
> +%---------------------%
> +
> +read_binary_uint64_be(Result, !IO) :-
> +    binary_input_stream(Stream, !IO),
> +    read_binary_uint64_be(Stream, Result, !IO).
> +
> +read_binary_uint64_be(binary_input_stream(Stream), Result, !IO) :-
> +    do_read_binary_uint64_le(Stream, Result0, UInt64LE, IncompleteBytes,
> +        Error, !IO),
> +    (
> +        Result0 = ok,
> +        UInt64BE = uint64.reverse_bytes(UInt64LE),
> +        Result = ok(UInt64BE)
> +    ;
> +        Result0 = eof,
> +        Result = eof
> +    ;
> +        Result0 = incomplete,
> +        Result = incomplete(IncompleteBytes)
> +    ;
> +        Result0 = error,
> +        make_err_msg(Error, "read failed: ", Msg),
> +        Result = error(io_error(Msg))
> +    ).
> +
> +%---------------------%
> +
>  read_bitmap(!Bitmap, BytesRead, Result, !IO) :-
>      binary_input_stream(Stream, !IO),
>      read_bitmap(Stream, !Bitmap, BytesRead, Result, !IO).
> diff --git a/tests/hard_coded/Mmakefile b/tests/hard_coded/Mmakefile
> index 78f7ef5..d99efb8 100644
> --- a/tests/hard_coded/Mmakefile
> +++ b/tests/hard_coded/Mmakefile
> @@ -303,6 +303,12 @@ ORDINARY_PROGS = \
> 	 random_permutation \
> 	 random_simple \
> 	 rational_test \
> +	read_binary_int16 \
> +	read_binary_int32 \
> +	read_binary_int64 \
> +	read_binary_uint16 \
> +	read_binary_uint32 \
> +	read_binary_uint64 \
> 	 read_min_int \
> 	 recursive_main \
> 	 redoip_clobber \
> diff --git a/tests/hard_coded/read_binary_int16.exp 
> b/tests/hard_coded/read_binary_int16.exp
> index e69de29..c54276a 100644
> --- a/tests/hard_coded/read_binary_int16.exp
> +++ b/tests/hard_coded/read_binary_int16.exp
> @@ -0,0 +1,36 @@
> +================
> +Input: []
> +Result: EOF (read big-endian)
> +================
> +Input: [0u8]
> +Result: Incomplete ([0u8]) (read big-endian)
> +================
> +Input: [1u8, 0u8] (LE: 1) (BE: 256)
> +Result: 256i16 (read big-endian)
> +================
> +Input: [255u8, 0u8] (LE: 255) (BE: -256)
> +Result: -256i16 (read big-endian)
> +================
> +Input: []
> +Result: EOF (read little-endian)
> +================
> +Input: [0u8]
> +Result: Incomplete ([0u8]) (read little-endian)
> +================
> +Input: [1u8, 0u8] (LE: 1) (BE: 256)
> +Result: 1i16 (read little-endian)
> +================
> +Input: [255u8, 0u8] (LE: 255) (BE: -256)
> +Result: 255i16 (read little-endian)
> +================
> +Input: []
> +Result: EOF (read native byte order)
> +================
> +Input: [0u8]
> +Result: Incomplete ([0u8]) (read native byte order)
> +================
> +Input: [1u8, 0u8] (LE: 1) (BE: 256)
> +Result: 1i16 (read native byte order)
> +================
> +Input: [255u8, 0u8] (LE: 255) (BE: -256)
> +Result: 255i16 (read native byte order)
> diff --git a/tests/hard_coded/read_binary_int16.m 
> b/tests/hard_coded/read_binary_int16.m
> index e69de29..171475b 100644
> --- a/tests/hard_coded/read_binary_int16.m
> +++ b/tests/hard_coded/read_binary_int16.m
> @@ -0,0 +1,143 @@
> +%---------------------------------------------------------------------------%
> +% vim: ft=mercury ts=4 sw=4 et
> +%---------------------------------------------------------------------------%
> +%
> +% Test reading of binary int16s.
> +%
> +%---------------------------------------------------------------------------%
> +
> +:- module read_binary_int16.
> +:- interface.
> +
> +:- import_module io.
> +
> +:- pred main(io::di, io::uo) is det.
> +
> +%---------------------------------------------------------------------------%
> +%---------------------------------------------------------------------------%
> +
> +:- implementation.
> +
> +:- import_module list.
> +:- import_module string.
> +:- import_module int16.
> +
> +%---------------------------------------------------------------------------%
> +
> +main(!IO) :-
> +    list.foldl(run_test(big_endian), test_cases, !IO),
> +    list.foldl(run_test(little_endian), test_cases, !IO),
> +    list.foldl(run_test(native), test_cases, !IO).
> +
> +:- pred run_test(byte_order::in, test_case::in, io::di, io::uo) is det.
> +
> +run_test(ByteOrder, TestBytes, !IO) :-
> +    io.remove_file(test_file, _, !IO),
> +    io.write_string("================\n", !IO),
> +    io.open_binary_output(test_file, OpenOutResult, !IO),
> +    (
> +        OpenOutResult = ok(OutFile),
> +        io.write_string("Input: ", !IO),
> +        io.write(TestBytes, !IO),
> +        (
> +            ( TestBytes = []
> +            ; TestBytes = [_]
> +            ; TestBytes = [_, _, _ | _]
> +            ),
> +            io.nl(!IO)
> +        ;
> +            TestBytes = [Byte1, Byte2],
> +            io.write_string(" (LE: ", !IO),
> +            io.write_int16(from_bytes_le(Byte1, Byte2), !IO),
> +            io.write_string(") (BE: ", !IO),
> +            io.write_int16(from_bytes_be(Byte1, Byte2), !IO),
> +            io.write_string(")\n", !IO)
> +        ),
> +        list.foldl(write_binary_uint8(OutFile), TestBytes, !IO),
> +        io.close_binary_output(OutFile, !IO),
> +        io.open_binary_input(test_file, OpenInResult, !IO),
> +        (
> +            OpenInResult = ok(InFile),
> +            (
> +                ByteOrder = big_endian,
> +                read_binary_int16_be(InFile, ReadResult, !IO)
> +            ;
> +                ByteOrder = little_endian,
> +                read_binary_int16_le(InFile, ReadResult, !IO)
> +            ;
> +                ByteOrder = native,
> +                read_binary_int16(InFile, ReadResult, !IO)
> +            ),
> +            (
> +                ReadResult = ok(ResultUInt16),
> +                io.write_string("Result: ", !IO),
> +                io.write(ResultUInt16, !IO),
> +                io.write_string(" (", !IO),
> +                describe_byte_order(ByteOrder, !IO),
> +                io.write_string(")\n", !IO)
> +            ;
> +                ReadResult = eof,
> +                io.write_string("Result: EOF (", !IO),
> +                describe_byte_order(ByteOrder, !IO),
> +                io.write_string(")\n", !IO)
> +            ;
> +                ReadResult = incomplete(Bytes),
> +                io.format("Result: Incomplete (%s) (", [s(string(Bytes))],
> +                    !IO),
> +                describe_byte_order(ByteOrder, !IO),
> +                io.write_string(")\n", !IO)
> +            ;
> +                ReadResult = error(IO_Error),
> +                io.format("Result: Error (%s)\n", 
> [s(io.error_message(IO_Error))],
> +                    !IO)
> +            ),
> +            io.remove_file(test_file, _, !IO)
> +        ;
> +            OpenInResult = error(IO_Error),
> +            io.format("I/O ERROR: %s\n", [s(io.error_message(IO_Error))],
> +                !IO)
> +        )
> +    ;
> +        OpenOutResult = error(IO_Error),
> +        io.format("I/O ERROR: %s\n", [s(io.error_message(IO_Error))], !IO)
> +    ).
> +
> +:- pred describe_byte_order(byte_order::in, io::di, io::uo) is det.
> +
> +describe_byte_order(ByteOrder, !IO) :-
> +    (
> +        ByteOrder = big_endian,
> +        io.write_string("read big-endian", !IO)
> +    ;
> +        ByteOrder = little_endian,
> +        io.write_string("read little-endian", !IO)
> +    ;
> +        ByteOrder = native,
> +        io.write_string("read native byte order", !IO)
> +    ).
> +
> +:- func test_file = string.
> +
> +test_file = "read_binary_int16.bin".
> +
> +%---------------------------------------------------------------------------%
> +
> +:- type byte_order
> +    --->    big_endian
> +    ;       little_endian
> +    ;       native.
> +
> +:- type test_case == list(uint8).
> +
> +:- func test_cases = list(test_case).
> +
> +test_cases = [
> +    [],
> +    [0u8],
> +    [1u8, 0u8],
> +    [0xffu8, 0u8]
> +].
> +
> +%---------------------------------------------------------------------------%
> +:- end_module read_binary_int16.
> +%---------------------------------------------------------------------------%
> diff --git a/tests/hard_coded/read_binary_int32.exp 
> b/tests/hard_coded/read_binary_int32.exp
> index e69de29..26cf1b9 100644
> --- a/tests/hard_coded/read_binary_int32.exp
> +++ b/tests/hard_coded/read_binary_int32.exp
> @@ -0,0 +1,63 @@
> +================
> +Input: []
> +Result: EOF (read big-endian)
> +================
> +Input: [1u8]
> +Result: Incomplete ([1u8]) (read big-endian)
> +================
> +Input: [1u8, 2u8]
> +Result: Incomplete ([1u8, 2u8]) (read big-endian)
> +================
> +Input: [1u8, 2u8, 3u8]
> +Result: Incomplete ([1u8, 2u8, 3u8]) (read big-endian)
> +================
> +Input: [0u8, 0u8, 0u8, 1u8] (LE: 16777216) (BE: 1)
> +Result: 1i32 (read big-endian)
> +================
> +Input: [255u8, 0u8, 0u8, 0u8] (LE: 255) (BE: -16777216)
> +Result: -16777216i32 (read big-endian)
> +================
> +Input: [1u8, 1u8, 0u8, 0u8] (LE: 257) (BE: 16842752)
> +Result: 16842752i32 (read big-endian)
> +================
> +Input: []
> +Result: EOF (read little-endian)
> +================
> +Input: [1u8]
> +Result: Incomplete ([1u8]) (read little-endian)
> +================
> +Input: [1u8, 2u8]
> +Result: Incomplete ([1u8, 2u8]) (read little-endian)
> +================
> +Input: [1u8, 2u8, 3u8]
> +Result: Incomplete ([1u8, 2u8, 3u8]) (read little-endian)
> +================
> +Input: [0u8, 0u8, 0u8, 1u8] (LE: 16777216) (BE: 1)
> +Result: 16777216i32 (read little-endian)
> +================
> +Input: [255u8, 0u8, 0u8, 0u8] (LE: 255) (BE: -16777216)
> +Result: 255i32 (read little-endian)
> +================
> +Input: [1u8, 1u8, 0u8, 0u8] (LE: 257) (BE: 16842752)
> +Result: 257i32 (read little-endian)
> +================
> +Input: []
> +Result: EOF (read native byte order)
> +================
> +Input: [1u8]
> +Result: Incomplete ([1u8]) (read native byte order)
> +================
> +Input: [1u8, 2u8]
> +Result: Incomplete ([1u8, 2u8]) (read native byte order)
> +================
> +Input: [1u8, 2u8, 3u8]
> +Result: Incomplete ([1u8, 2u8, 3u8]) (read native byte order)
> +================
> +Input: [0u8, 0u8, 0u8, 1u8] (LE: 16777216) (BE: 1)
> +Result: 16777216i32 (read native byte order)
> +================
> +Input: [255u8, 0u8, 0u8, 0u8] (LE: 255) (BE: -16777216)
> +Result: 255i32 (read native byte order)
> +================
> +Input: [1u8, 1u8, 0u8, 0u8] (LE: 257) (BE: 16842752)
> +Result: 257i32 (read native byte order)
> diff --git a/tests/hard_coded/read_binary_int32.m 
> b/tests/hard_coded/read_binary_int32.m
> index e69de29..cecad92 100644
> --- a/tests/hard_coded/read_binary_int32.m
> +++ b/tests/hard_coded/read_binary_int32.m
> @@ -0,0 +1,141 @@
> +%---------------------------------------------------------------------------%
> +% vim: ft=mercury ts=4 sw=4 et
> +%---------------------------------------------------------------------------%
> +%
> +% Test reading of binary int32s.
> +%
> +%---------------------------------------------------------------------------%
> +
> +:- module read_binary_int32.
> +:- interface.
> +
> +:- import_module io.
> +
> +:- pred main(io::di, io::uo) is det.
> +
> +%---------------------------------------------------------------------------%
> +%---------------------------------------------------------------------------%
> +
> +:- implementation.
> +
> +:- import_module list.
> +:- import_module string.
> +:- import_module int32.
> +
> +%---------------------------------------------------------------------------%
> +
> +main(!IO) :-
> +    list.foldl(run_test(big_endian), test_cases, !IO),
> +    list.foldl(run_test(little_endian), test_cases, !IO),
> +    list.foldl(run_test(native), test_cases, !IO).
> +
> +:- pred run_test(byte_order::in, test_case::in, io::di, io::uo) is det.
> +
> +run_test(ByteOrder, TestBytes, !IO) :-
> +    io.remove_file(test_file, _, !IO),
> +    io.write_string("================\n", !IO),
> +    io.open_binary_output(test_file, OpenOutResult, !IO),
> +    (
> +        OpenOutResult = ok(OutFile),
> +        io.write_string("Input: ", !IO),
> +        io.write(TestBytes, !IO),
> +        ( if TestBytes = [Byte1, Byte2, Byte3, Byte4] then
> +            io.write_string(" (LE: ", !IO),
> +            io.write_int32(from_bytes_le(Byte1, Byte2, Byte3, Byte4), !IO),
> +            io.write_string(") (BE: ", !IO),
> +            io.write_int32(from_bytes_be(Byte1, Byte2, Byte3, Byte4), !IO),
> +            io.write_string(")\n", !IO)
> +        else
> +            io.nl(!IO)
> +        ),
> +        list.foldl(write_binary_uint8(OutFile), TestBytes, !IO),
> +        io.close_binary_output(OutFile, !IO),
> +        io.open_binary_input(test_file, OpenInResult, !IO),
> +        (
> +            OpenInResult = ok(InFile),
> +            (
> +                ByteOrder = big_endian,
> +                read_binary_int32_be(InFile, ReadResult, !IO)
> +            ;
> +                ByteOrder = little_endian,
> +                read_binary_int32_le(InFile, ReadResult, !IO)
> +            ;
> +                ByteOrder = native,
> +                read_binary_int32(InFile, ReadResult, !IO)
> +            ),
> +            (
> +                ReadResult = ok(ResultUInt16),
> +                io.write_string("Result: ", !IO),
> +                io.write(ResultUInt16, !IO),
> +                io.write_string(" (", !IO),
> +                describe_byte_order(ByteOrder, !IO),
> +                io.write_string(")\n", !IO)
> +            ;
> +                ReadResult = eof,
> +                io.write_string("Result: EOF (", !IO),
> +                describe_byte_order(ByteOrder, !IO),
> +                io.write_string(")\n", !IO)
> +            ;
> +                ReadResult = incomplete(Bytes),
> +                io.format("Result: Incomplete (%s) (", [s(string(Bytes))],
> +                    !IO),
> +                describe_byte_order(ByteOrder, !IO),
> +                io.write_string(")\n", !IO)
> +            ;
> +                ReadResult = error(IO_Error),
> +                io.format("Result: Error (%s)\n", 
> [s(io.error_message(IO_Error))],
> +                    !IO)
> +            ),
> +            io.remove_file(test_file, _, !IO)
> +        ;
> +            OpenInResult = error(IO_Error),
> +            io.format("I/O ERROR: %s\n", [s(io.error_message(IO_Error))],
> +                !IO)
> +        )
> +    ;
> +        OpenOutResult = error(IO_Error),
> +        io.format("I/O ERROR: %s\n", [s(io.error_message(IO_Error))], !IO)
> +    ).
> +
> +:- pred describe_byte_order(byte_order::in, io::di, io::uo) is det.
> +
> +describe_byte_order(ByteOrder, !IO) :-
> +    (
> +        ByteOrder = big_endian,
> +        io.write_string("read big-endian", !IO)
> +    ;
> +        ByteOrder = little_endian,
> +        io.write_string("read little-endian", !IO)
> +    ;
> +        ByteOrder = native,
> +        io.write_string("read native byte order", !IO)
> +    ).
> +
> +:- func test_file = string.
> +
> +test_file = "read_binary_int32.bin".
> +
> +%---------------------------------------------------------------------------%
> +
> +:- type byte_order
> +    --->    big_endian
> +    ;       little_endian
> +    ;       native.
> +
> +:- type test_case == list(uint8).
> +
> +:- func test_cases = list(test_case).
> +
> +test_cases = [
> +    [],
> +    [1u8],
> +    [1u8, 2u8],
> +    [1u8, 2u8, 3u8],
> +    [0u8, 0u8, 0u8, 1u8],
> +    [0xffu8, 0u8, 0u8, 0u8],
> +    [1u8, 1u8, 0u8, 0u8]
> +].
> +
> +%---------------------------------------------------------------------------%
> +:- end_module read_binary_int32.
> +%---------------------------------------------------------------------------%
> diff --git a/tests/hard_coded/read_binary_int64.exp 
> b/tests/hard_coded/read_binary_int64.exp
> index e69de29..e975eab 100644
> --- a/tests/hard_coded/read_binary_int64.exp
> +++ b/tests/hard_coded/read_binary_int64.exp
> @@ -0,0 +1,108 @@
> +================
> +Input: []
> +Result: EOF (read big-endian)
> +================
> +Input: [1u8]
> +Result: Incomplete ([1u8]) (read big-endian)
> +================
> +Input: [1u8, 2u8]
> +Result: Incomplete ([1u8, 2u8]) (read big-endian)
> +================
> +Input: [1u8, 2u8, 3u8]
> +Result: Incomplete ([1u8, 2u8, 3u8]) (read big-endian)
> +================
> +Input: [1u8, 2u8, 3u8, 4u8]
> +Result: Incomplete ([1u8, 2u8, 3u8, 4u8]) (read big-endian)
> +================
> +Input: [1u8, 2u8, 3u8, 4u8, 5u8]
> +Result: Incomplete ([1u8, 2u8, 3u8, 4u8, 5u8]) (read big-endian)
> +================
> +Input: [1u8, 2u8, 3u8, 4u8, 5u8, 6u8]
> +Result: Incomplete ([1u8, 2u8, 3u8, 4u8, 5u8, 6u8]) (read big-endian)
> +================
> +Input: [1u8, 2u8, 3u8, 4u8, 5u8, 7u8]
> +Result: Incomplete ([1u8, 2u8, 3u8, 4u8, 5u8, 7u8]) (read big-endian)
> +================
> +Input: [1u8, 2u8, 3u8, 4u8, 5u8, 7u8, 8u8]
> +Result: Incomplete ([1u8, 2u8, 3u8, 4u8, 5u8, 7u8, 8u8]) (read big-endian)
> +================
> +Input: [0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 1u8] (LE: 72057594037927936) (BE: 
> 1)
> +Result: 1i64 (read big-endian)
> +================
> +Input: [255u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8] (LE: 255) (BE: 
> -72057594037927936)
> +Result: -72057594037927936i64 (read big-endian)
> +================
> +Input: [1u8, 1u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8] (LE: 257) (BE: 
> 72339069014638592)
> +Result: 72339069014638592i64 (read big-endian)
> +================
> +Input: []
> +Result: EOF (read little-endian)
> +================
> +Input: [1u8]
> +Result: Incomplete ([1u8]) (read little-endian)
> +================
> +Input: [1u8, 2u8]
> +Result: Incomplete ([1u8, 2u8]) (read little-endian)
> +================
> +Input: [1u8, 2u8, 3u8]
> +Result: Incomplete ([1u8, 2u8, 3u8]) (read little-endian)
> +================
> +Input: [1u8, 2u8, 3u8, 4u8]
> +Result: Incomplete ([1u8, 2u8, 3u8, 4u8]) (read little-endian)
> +================
> +Input: [1u8, 2u8, 3u8, 4u8, 5u8]
> +Result: Incomplete ([1u8, 2u8, 3u8, 4u8, 5u8]) (read little-endian)
> +================
> +Input: [1u8, 2u8, 3u8, 4u8, 5u8, 6u8]
> +Result: Incomplete ([1u8, 2u8, 3u8, 4u8, 5u8, 6u8]) (read little-endian)
> +================
> +Input: [1u8, 2u8, 3u8, 4u8, 5u8, 7u8]
> +Result: Incomplete ([1u8, 2u8, 3u8, 4u8, 5u8, 7u8]) (read little-endian)
> +================
> +Input: [1u8, 2u8, 3u8, 4u8, 5u8, 7u8, 8u8]
> +Result: Incomplete ([1u8, 2u8, 3u8, 4u8, 5u8, 7u8, 8u8]) (read 
> little-endian)
> +================
> +Input: [0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 1u8] (LE: 72057594037927936) (BE: 
> 1)
> +Result: 72057594037927936i64 (read little-endian)
> +================
> +Input: [255u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8] (LE: 255) (BE: 
> -72057594037927936)
> +Result: 255i64 (read little-endian)
> +================
> +Input: [1u8, 1u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8] (LE: 257) (BE: 
> 72339069014638592)
> +Result: 257i64 (read little-endian)
> +================
> +Input: []
> +Result: EOF (read native byte order)
> +================
> +Input: [1u8]
> +Result: Incomplete ([1u8]) (read native byte order)
> +================
> +Input: [1u8, 2u8]
> +Result: Incomplete ([1u8, 2u8]) (read native byte order)
> +================
> +Input: [1u8, 2u8, 3u8]
> +Result: Incomplete ([1u8, 2u8, 3u8]) (read native byte order)
> +================
> +Input: [1u8, 2u8, 3u8, 4u8]
> +Result: Incomplete ([1u8, 2u8, 3u8, 4u8]) (read native byte order)
> +================
> +Input: [1u8, 2u8, 3u8, 4u8, 5u8]
> +Result: Incomplete ([1u8, 2u8, 3u8, 4u8, 5u8]) (read native byte order)
> +================
> +Input: [1u8, 2u8, 3u8, 4u8, 5u8, 6u8]
> +Result: Incomplete ([1u8, 2u8, 3u8, 4u8, 5u8, 6u8]) (read native byte order)
> +================
> +Input: [1u8, 2u8, 3u8, 4u8, 5u8, 7u8]
> +Result: Incomplete ([1u8, 2u8, 3u8, 4u8, 5u8, 7u8]) (read native byte order)
> +================
> +Input: [1u8, 2u8, 3u8, 4u8, 5u8, 7u8, 8u8]
> +Result: Incomplete ([1u8, 2u8, 3u8, 4u8, 5u8, 7u8, 8u8]) (read native byte 
> order)
> +================
> +Input: [0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 1u8] (LE: 72057594037927936) (BE: 
> 1)
> +Result: 72057594037927936i64 (read native byte order)
> +================
> +Input: [255u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8] (LE: 255) (BE: 
> -72057594037927936)
> +Result: 255i64 (read native byte order)
> +================
> +Input: [1u8, 1u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8] (LE: 257) (BE: 
> 72339069014638592)
> +Result: 257i64 (read native byte order)
> diff --git a/tests/hard_coded/read_binary_int64.m 
> b/tests/hard_coded/read_binary_int64.m
> index e69de29..fdeb287 100644
> --- a/tests/hard_coded/read_binary_int64.m
> +++ b/tests/hard_coded/read_binary_int64.m
> @@ -0,0 +1,148 @@
> +%---------------------------------------------------------------------------%
> +% vim: ft=mercury ts=4 sw=4 et
> +%---------------------------------------------------------------------------%
> +%
> +% Test reading of binary int64s.
> +%
> +%---------------------------------------------------------------------------%
> +
> +:- module read_binary_int64.
> +:- interface.
> +
> +:- import_module io.
> +
> +:- pred main(io::di, io::uo) is det.
> +
> +%---------------------------------------------------------------------------%
> +%---------------------------------------------------------------------------%
> +
> +:- implementation.
> +
> +:- import_module list.
> +:- import_module string.
> +:- import_module int64.
> +
> +%---------------------------------------------------------------------------%
> +
> +main(!IO) :-
> +    list.foldl(run_test(big_endian), test_cases, !IO),
> +    list.foldl(run_test(little_endian), test_cases, !IO),
> +    list.foldl(run_test(native), test_cases, !IO).
> +
> +:- pred run_test(byte_order::in, test_case::in, io::di, io::uo) is det.
> +
> +run_test(ByteOrder, TestBytes, !IO) :-
> +    io.remove_file(test_file, _, !IO),
> +    io.write_string("================\n", !IO),
> +    io.open_binary_output(test_file, OpenOutResult, !IO),
> +    (
> +        OpenOutResult = ok(OutFile),
> +        io.write_string("Input: ", !IO),
> +        io.write(TestBytes, !IO),
> +        ( if
> +            TestBytes = [Byte1, Byte2, Byte3, Byte4, Byte5, Byte6, Byte7, 
> Byte8]
> +        then
> +            io.write_string(" (LE: ", !IO),
> +            io.write_int64(from_bytes_le(Byte1, Byte2, Byte3, Byte4, Byte5, 
> Byte6, Byte7, Byte8), !IO),
> +            io.write_string(") (BE: ", !IO),
> +            io.write_int64(from_bytes_be(Byte1, Byte2, Byte3, Byte4, Byte5, 
> Byte6, Byte7, Byte8), !IO),
> +            io.write_string(")\n", !IO)
> +        else
> +            io.nl(!IO)
> +        ),
> +        list.foldl(write_binary_uint8(OutFile), TestBytes, !IO),
> +        io.close_binary_output(OutFile, !IO),
> +        io.open_binary_input(test_file, OpenInResult, !IO),
> +        (
> +            OpenInResult = ok(InFile),
> +            (
> +                ByteOrder = big_endian,
> +                read_binary_int64_be(InFile, ReadResult, !IO)
> +            ;
> +                ByteOrder = little_endian,
> +                read_binary_int64_le(InFile, ReadResult, !IO)
> +            ;
> +                ByteOrder = native,
> +                read_binary_int64(InFile, ReadResult, !IO)
> +            ),
> +            (
> +                ReadResult = ok(ResultUInt16),
> +                io.write_string("Result: ", !IO),
> +                io.write(ResultUInt16, !IO),
> +                io.write_string(" (", !IO),
> +                describe_byte_order(ByteOrder, !IO),
> +                io.write_string(")\n", !IO)
> +            ;
> +                ReadResult = eof,
> +                io.write_string("Result: EOF (", !IO),
> +                describe_byte_order(ByteOrder, !IO),
> +                io.write_string(")\n", !IO)
> +            ;
> +                ReadResult = incomplete(Bytes),
> +                io.format("Result: Incomplete (%s) (", [s(string(Bytes))],
> +                    !IO),
> +                describe_byte_order(ByteOrder, !IO),
> +                io.write_string(")\n", !IO)
> +            ;
> +                ReadResult = error(IO_Error),
> +                io.format("Result: Error (%s)\n", 
> [s(io.error_message(IO_Error))],
> +                    !IO)
> +            ),
> +            io.remove_file(test_file, _, !IO)
> +        ;
> +            OpenInResult = error(IO_Error),
> +            io.format("I/O ERROR: %s\n", [s(io.error_message(IO_Error))],
> +                !IO)
> +        )
> +    ;
> +        OpenOutResult = error(IO_Error),
> +        io.format("I/O ERROR: %s\n", [s(io.error_message(IO_Error))], !IO)
> +    ).
> +
> +:- pred describe_byte_order(byte_order::in, io::di, io::uo) is det.
> +
> +describe_byte_order(ByteOrder, !IO) :-
> +    (
> +        ByteOrder = big_endian,
> +        io.write_string("read big-endian", !IO)
> +    ;
> +        ByteOrder = little_endian,
> +        io.write_string("read little-endian", !IO)
> +    ;
> +        ByteOrder = native,
> +        io.write_string("read native byte order", !IO)
> +    ).
> +
> +:- func test_file = string.
> +
> +test_file = "read_binary_int64.bin".
> +
> +%---------------------------------------------------------------------------%
> +
> +:- type byte_order
> +    --->    big_endian
> +    ;       little_endian
> +    ;       native.
> +
> +:- type test_case == list(uint8).
> +
> +:- func test_cases = list(test_case).
> +
> +test_cases = [
> +    [],
> +    [1u8],
> +    [1u8, 2u8],
> +    [1u8, 2u8, 3u8],
> +    [1u8, 2u8, 3u8, 4u8],
> +    [1u8, 2u8, 3u8, 4u8, 5u8],
> +    [1u8, 2u8, 3u8, 4u8, 5u8, 6u8],
> +    [1u8, 2u8, 3u8, 4u8, 5u8, 7u8],
> +    [1u8, 2u8, 3u8, 4u8, 5u8, 7u8, 8u8],
> +    [0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 1u8],
> +    [0xffu8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8],
> +    [1u8, 1u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8]
> +].
> +
> +%---------------------------------------------------------------------------%
> +:- end_module read_binary_int64.
> +%---------------------------------------------------------------------------%
> diff --git a/tests/hard_coded/read_binary_uint16.exp 
> b/tests/hard_coded/read_binary_uint16.exp
> index e69de29..658cef5 100644
> --- a/tests/hard_coded/read_binary_uint16.exp
> +++ b/tests/hard_coded/read_binary_uint16.exp
> @@ -0,0 +1,36 @@
> +================
> +Input: []
> +Result: EOF (read big-endian)
> +================
> +Input: [0u8]
> +Result: Incomplete ([0u8]) (read big-endian)
> +================
> +Input: [1u8, 0u8] (LE: 1) (BE: 256)
> +Result: 256u16 (read big-endian)
> +================
> +Input: [255u8, 0u8] (LE: 255) (BE: 65280)
> +Result: 65280u16 (read big-endian)
> +================
> +Input: []
> +Result: EOF (read little-endian)
> +================
> +Input: [0u8]
> +Result: Incomplete ([0u8]) (read little-endian)
> +================
> +Input: [1u8, 0u8] (LE: 1) (BE: 256)
> +Result: 1u16 (read little-endian)
> +================
> +Input: [255u8, 0u8] (LE: 255) (BE: 65280)
> +Result: 255u16 (read little-endian)
> +================
> +Input: []
> +Result: EOF (read native byte order)
> +================
> +Input: [0u8]
> +Result: Incomplete ([0u8]) (read native byte order)
> +================
> +Input: [1u8, 0u8] (LE: 1) (BE: 256)
> +Result: 1u16 (read native byte order)
> +================
> +Input: [255u8, 0u8] (LE: 255) (BE: 65280)
> +Result: 255u16 (read native byte order)
> diff --git a/tests/hard_coded/read_binary_uint16.m 
> b/tests/hard_coded/read_binary_uint16.m
> index e69de29..8a0ec6e 100644
> --- a/tests/hard_coded/read_binary_uint16.m
> +++ b/tests/hard_coded/read_binary_uint16.m
> @@ -0,0 +1,143 @@
> +%---------------------------------------------------------------------------%
> +% vim: ft=mercury ts=4 sw=4 et
> +%---------------------------------------------------------------------------%
> +%
> +% Test reading of binary uint16s.
> +%
> +%---------------------------------------------------------------------------%
> +
> +:- module read_binary_uint16.
> +:- interface.
> +
> +:- import_module io.
> +
> +:- pred main(io::di, io::uo) is det.
> +
> +%---------------------------------------------------------------------------%
> +%---------------------------------------------------------------------------%
> +
> +:- implementation.
> +
> +:- import_module list.
> +:- import_module string.
> +:- import_module uint16.
> +
> +%---------------------------------------------------------------------------%
> +
> +main(!IO) :-
> +    list.foldl(run_test(big_endian), test_cases, !IO),
> +    list.foldl(run_test(little_endian), test_cases, !IO),
> +    list.foldl(run_test(native), test_cases, !IO).
> +
> +:- pred run_test(byte_order::in, test_case::in, io::di, io::uo) is det.
> +
> +run_test(ByteOrder, TestBytes, !IO) :-
> +    io.remove_file(test_file, _, !IO),
> +    io.write_string("================\n", !IO),
> +    io.open_binary_output(test_file, OpenOutResult, !IO),
> +    (
> +        OpenOutResult = ok(OutFile),
> +        io.write_string("Input: ", !IO),
> +        io.write(TestBytes, !IO),
> +        (
> +            ( TestBytes = []
> +            ; TestBytes = [_]
> +            ; TestBytes = [_, _, _ | _]
> +            ),
> +            io.nl(!IO)
> +        ;
> +            TestBytes = [Byte1, Byte2],
> +            io.write_string(" (LE: ", !IO),
> +            io.write_uint16(from_bytes_le(Byte1, Byte2), !IO),
> +            io.write_string(") (BE: ", !IO),
> +            io.write_uint16(from_bytes_be(Byte1, Byte2), !IO),
> +            io.write_string(")\n", !IO)
> +        ),
> +        list.foldl(write_binary_uint8(OutFile), TestBytes, !IO),
> +        io.close_binary_output(OutFile, !IO),
> +        io.open_binary_input(test_file, OpenInResult, !IO),
> +        (
> +            OpenInResult = ok(InFile),
> +            (
> +                ByteOrder = big_endian,
> +                read_binary_uint16_be(InFile, ReadResult, !IO)
> +            ;
> +                ByteOrder = little_endian,
> +                read_binary_uint16_le(InFile, ReadResult, !IO)
> +            ;
> +                ByteOrder = native,
> +                read_binary_uint16(InFile, ReadResult, !IO)
> +            ),
> +            (
> +                ReadResult = ok(ResultUInt16),
> +                io.write_string("Result: ", !IO),
> +                io.write(ResultUInt16, !IO),
> +                io.write_string(" (", !IO),
> +                describe_byte_order(ByteOrder, !IO),
> +                io.write_string(")\n", !IO)
> +            ;
> +                ReadResult = eof,
> +                io.write_string("Result: EOF (", !IO),
> +                describe_byte_order(ByteOrder, !IO),
> +                io.write_string(")\n", !IO)
> +            ;
> +                ReadResult = incomplete(Bytes),
> +                io.format("Result: Incomplete (%s) (", [s(string(Bytes))],
> +                    !IO),
> +                describe_byte_order(ByteOrder, !IO),
> +                io.write_string(")\n", !IO)
> +            ;
> +                ReadResult = error(IO_Error),
> +                io.format("Result: Error (%s)\n", 
> [s(io.error_message(IO_Error))],
> +                    !IO)
> +            ),
> +            io.remove_file(test_file, _, !IO)
> +        ;
> +            OpenInResult = error(IO_Error),
> +            io.format("I/O ERROR: %s\n", [s(io.error_message(IO_Error))],
> +                !IO)
> +        )
> +    ;
> +        OpenOutResult = error(IO_Error),
> +        io.format("I/O ERROR: %s\n", [s(io.error_message(IO_Error))], !IO)
> +    ).
> +
> +:- pred describe_byte_order(byte_order::in, io::di, io::uo) is det.
> +
> +describe_byte_order(ByteOrder, !IO) :-
> +    (
> +        ByteOrder = big_endian,
> +        io.write_string("read big-endian", !IO)
> +    ;
> +        ByteOrder = little_endian,
> +        io.write_string("read little-endian", !IO)
> +    ;
> +        ByteOrder = native,
> +        io.write_string("read native byte order", !IO)
> +    ).
> +
> +:- func test_file = string.
> +
> +test_file = "read_binary_uint16.bin".
> +
> +%---------------------------------------------------------------------------%
> +
> +:- type byte_order
> +    --->    big_endian
> +    ;       little_endian
> +    ;       native.
> +
> +:- type test_case == list(uint8).
> +
> +:- func test_cases = list(test_case).
> +
> +test_cases = [
> +    [],
> +    [0u8],
> +    [1u8, 0u8],
> +    [0xffu8, 0u8]
> +].
> +
> +%---------------------------------------------------------------------------%
> +:- end_module read_binary_uint16.
> +%---------------------------------------------------------------------------%
> diff --git a/tests/hard_coded/read_binary_uint32.exp 
> b/tests/hard_coded/read_binary_uint32.exp
> index e69de29..7225201 100644
> --- a/tests/hard_coded/read_binary_uint32.exp
> +++ b/tests/hard_coded/read_binary_uint32.exp
> @@ -0,0 +1,63 @@
> +================
> +Input: []
> +Result: EOF (read big-endian)
> +================
> +Input: [1u8]
> +Result: Incomplete ([1u8]) (read big-endian)
> +================
> +Input: [1u8, 2u8]
> +Result: Incomplete ([1u8, 2u8]) (read big-endian)
> +================
> +Input: [1u8, 2u8, 3u8]
> +Result: Incomplete ([1u8, 2u8, 3u8]) (read big-endian)
> +================
> +Input: [0u8, 0u8, 0u8, 1u8] (LE: 16777216) (BE: 1)
> +Result: 1u32 (read big-endian)
> +================
> +Input: [255u8, 0u8, 0u8, 0u8] (LE: 255) (BE: 4278190080)
> +Result: 4278190080u32 (read big-endian)
> +================
> +Input: [1u8, 1u8, 0u8, 0u8] (LE: 257) (BE: 16842752)
> +Result: 16842752u32 (read big-endian)
> +================
> +Input: []
> +Result: EOF (read little-endian)
> +================
> +Input: [1u8]
> +Result: Incomplete ([1u8]) (read little-endian)
> +================
> +Input: [1u8, 2u8]
> +Result: Incomplete ([1u8, 2u8]) (read little-endian)
> +================
> +Input: [1u8, 2u8, 3u8]
> +Result: Incomplete ([1u8, 2u8, 3u8]) (read little-endian)
> +================
> +Input: [0u8, 0u8, 0u8, 1u8] (LE: 16777216) (BE: 1)
> +Result: 16777216u32 (read little-endian)
> +================
> +Input: [255u8, 0u8, 0u8, 0u8] (LE: 255) (BE: 4278190080)
> +Result: 255u32 (read little-endian)
> +================
> +Input: [1u8, 1u8, 0u8, 0u8] (LE: 257) (BE: 16842752)
> +Result: 257u32 (read little-endian)
> +================
> +Input: []
> +Result: EOF (read native byte order)
> +================
> +Input: [1u8]
> +Result: Incomplete ([1u8]) (read native byte order)
> +================
> +Input: [1u8, 2u8]
> +Result: Incomplete ([1u8, 2u8]) (read native byte order)
> +================
> +Input: [1u8, 2u8, 3u8]
> +Result: Incomplete ([1u8, 2u8, 3u8]) (read native byte order)
> +================
> +Input: [0u8, 0u8, 0u8, 1u8] (LE: 16777216) (BE: 1)
> +Result: 16777216u32 (read native byte order)
> +================
> +Input: [255u8, 0u8, 0u8, 0u8] (LE: 255) (BE: 4278190080)
> +Result: 255u32 (read native byte order)
> +================
> +Input: [1u8, 1u8, 0u8, 0u8] (LE: 257) (BE: 16842752)
> +Result: 257u32 (read native byte order)
> diff --git a/tests/hard_coded/read_binary_uint32.m 
> b/tests/hard_coded/read_binary_uint32.m
> index e69de29..c400c12 100644
> --- a/tests/hard_coded/read_binary_uint32.m
> +++ b/tests/hard_coded/read_binary_uint32.m
> @@ -0,0 +1,141 @@
> +%---------------------------------------------------------------------------%
> +% vim: ft=mercury ts=4 sw=4 et
> +%---------------------------------------------------------------------------%
> +%
> +% Test reading of binary uint32s.
> +%
> +%---------------------------------------------------------------------------%
> +
> +:- module read_binary_uint32.
> +:- interface.
> +
> +:- import_module io.
> +
> +:- pred main(io::di, io::uo) is det.
> +
> +%---------------------------------------------------------------------------%
> +%---------------------------------------------------------------------------%
> +
> +:- implementation.
> +
> +:- import_module list.
> +:- import_module string.
> +:- import_module uint32.
> +
> +%---------------------------------------------------------------------------%
> +
> +main(!IO) :-
> +    list.foldl(run_test(big_endian), test_cases, !IO),
> +    list.foldl(run_test(little_endian), test_cases, !IO),
> +    list.foldl(run_test(native), test_cases, !IO).
> +
> +:- pred run_test(byte_order::in, test_case::in, io::di, io::uo) is det.
> +
> +run_test(ByteOrder, TestBytes, !IO) :-
> +    io.remove_file(test_file, _, !IO),
> +    io.write_string("================\n", !IO),
> +    io.open_binary_output(test_file, OpenOutResult, !IO),
> +    (
> +        OpenOutResult = ok(OutFile),
> +        io.write_string("Input: ", !IO),
> +        io.write(TestBytes, !IO),
> +        ( if TestBytes = [Byte1, Byte2, Byte3, Byte4] then
> +            io.write_string(" (LE: ", !IO),
> +            io.write_uint32(from_bytes_le(Byte1, Byte2, Byte3, Byte4), !IO),
> +            io.write_string(") (BE: ", !IO),
> +            io.write_uint32(from_bytes_be(Byte1, Byte2, Byte3, Byte4), !IO),
> +            io.write_string(")\n", !IO)
> +        else
> +            io.nl(!IO)
> +        ),
> +        list.foldl(write_binary_uint8(OutFile), TestBytes, !IO),
> +        io.close_binary_output(OutFile, !IO),
> +        io.open_binary_input(test_file, OpenInResult, !IO),
> +        (
> +            OpenInResult = ok(InFile),
> +            (
> +                ByteOrder = big_endian,
> +                read_binary_uint32_be(InFile, ReadResult, !IO)
> +            ;
> +                ByteOrder = little_endian,
> +                read_binary_uint32_le(InFile, ReadResult, !IO)
> +            ;
> +                ByteOrder = native,
> +                read_binary_uint32(InFile, ReadResult, !IO)
> +            ),
> +            (
> +                ReadResult = ok(ResultUInt16),
> +                io.write_string("Result: ", !IO),
> +                io.write(ResultUInt16, !IO),
> +                io.write_string(" (", !IO),
> +                describe_byte_order(ByteOrder, !IO),
> +                io.write_string(")\n", !IO)
> +            ;
> +                ReadResult = eof,
> +                io.write_string("Result: EOF (", !IO),
> +                describe_byte_order(ByteOrder, !IO),
> +                io.write_string(")\n", !IO)
> +            ;
> +                ReadResult = incomplete(Bytes),
> +                io.format("Result: Incomplete (%s) (", [s(string(Bytes))],
> +                    !IO),
> +                describe_byte_order(ByteOrder, !IO),
> +                io.write_string(")\n", !IO)
> +            ;
> +                ReadResult = error(IO_Error),
> +                io.format("Result: Error (%s)\n", 
> [s(io.error_message(IO_Error))],
> +                    !IO)
> +            ),
> +            io.remove_file(test_file, _, !IO)
> +        ;
> +            OpenInResult = error(IO_Error),
> +            io.format("I/O ERROR: %s\n", [s(io.error_message(IO_Error))],
> +                !IO)
> +        )
> +    ;
> +        OpenOutResult = error(IO_Error),
> +        io.format("I/O ERROR: %s\n", [s(io.error_message(IO_Error))], !IO)
> +    ).
> +
> +:- pred describe_byte_order(byte_order::in, io::di, io::uo) is det.
> +
> +describe_byte_order(ByteOrder, !IO) :-
> +    (
> +        ByteOrder = big_endian,
> +        io.write_string("read big-endian", !IO)
> +    ;
> +        ByteOrder = little_endian,
> +        io.write_string("read little-endian", !IO)
> +    ;
> +        ByteOrder = native,
> +        io.write_string("read native byte order", !IO)
> +    ).
> +
> +:- func test_file = string.
> +
> +test_file = "read_binary_uint32.bin".
> +
> +%---------------------------------------------------------------------------%
> +
> +:- type byte_order
> +    --->    big_endian
> +    ;       little_endian
> +    ;       native.
> +
> +:- type test_case == list(uint8).
> +
> +:- func test_cases = list(test_case).
> +
> +test_cases = [
> +    [],
> +    [1u8],
> +    [1u8, 2u8],
> +    [1u8, 2u8, 3u8],
> +    [0u8, 0u8, 0u8, 1u8],
> +    [0xffu8, 0u8, 0u8, 0u8],
> +    [1u8, 1u8, 0u8, 0u8]
> +].
> +
> +%---------------------------------------------------------------------------%
> +:- end_module read_binary_uint32.
> +%---------------------------------------------------------------------------%
> diff --git a/tests/hard_coded/read_binary_uint64.exp 
> b/tests/hard_coded/read_binary_uint64.exp
> index e69de29..6144024 100644
> --- a/tests/hard_coded/read_binary_uint64.exp
> +++ b/tests/hard_coded/read_binary_uint64.exp
> @@ -0,0 +1,108 @@
> +================
> +Input: []
> +Result: EOF (read big-endian)
> +================
> +Input: [1u8]
> +Result: Incomplete ([1u8]) (read big-endian)
> +================
> +Input: [1u8, 2u8]
> +Result: Incomplete ([1u8, 2u8]) (read big-endian)
> +================
> +Input: [1u8, 2u8, 3u8]
> +Result: Incomplete ([1u8, 2u8, 3u8]) (read big-endian)
> +================
> +Input: [1u8, 2u8, 3u8, 4u8]
> +Result: Incomplete ([1u8, 2u8, 3u8, 4u8]) (read big-endian)
> +================
> +Input: [1u8, 2u8, 3u8, 4u8, 5u8]
> +Result: Incomplete ([1u8, 2u8, 3u8, 4u8, 5u8]) (read big-endian)
> +================
> +Input: [1u8, 2u8, 3u8, 4u8, 5u8, 6u8]
> +Result: Incomplete ([1u8, 2u8, 3u8, 4u8, 5u8, 6u8]) (read big-endian)
> +================
> +Input: [1u8, 2u8, 3u8, 4u8, 5u8, 7u8]
> +Result: Incomplete ([1u8, 2u8, 3u8, 4u8, 5u8, 7u8]) (read big-endian)
> +================
> +Input: [1u8, 2u8, 3u8, 4u8, 5u8, 7u8, 8u8]
> +Result: Incomplete ([1u8, 2u8, 3u8, 4u8, 5u8, 7u8, 8u8]) (read big-endian)
> +================
> +Input: [0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 1u8] (LE: 72057594037927936) (BE: 
> 1)
> +Result: 1u64 (read big-endian)
> +================
> +Input: [255u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8] (LE: 255) (BE: 
> 18374686479671623680)
> +Result: 18374686479671623680u64 (read big-endian)
> +================
> +Input: [1u8, 1u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8] (LE: 257) (BE: 
> 72339069014638592)
> +Result: 72339069014638592u64 (read big-endian)
> +================
> +Input: []
> +Result: EOF (read little-endian)
> +================
> +Input: [1u8]
> +Result: Incomplete ([1u8]) (read little-endian)
> +================
> +Input: [1u8, 2u8]
> +Result: Incomplete ([1u8, 2u8]) (read little-endian)
> +================
> +Input: [1u8, 2u8, 3u8]
> +Result: Incomplete ([1u8, 2u8, 3u8]) (read little-endian)
> +================
> +Input: [1u8, 2u8, 3u8, 4u8]
> +Result: Incomplete ([1u8, 2u8, 3u8, 4u8]) (read little-endian)
> +================
> +Input: [1u8, 2u8, 3u8, 4u8, 5u8]
> +Result: Incomplete ([1u8, 2u8, 3u8, 4u8, 5u8]) (read little-endian)
> +================
> +Input: [1u8, 2u8, 3u8, 4u8, 5u8, 6u8]
> +Result: Incomplete ([1u8, 2u8, 3u8, 4u8, 5u8, 6u8]) (read little-endian)
> +================
> +Input: [1u8, 2u8, 3u8, 4u8, 5u8, 7u8]
> +Result: Incomplete ([1u8, 2u8, 3u8, 4u8, 5u8, 7u8]) (read little-endian)
> +================
> +Input: [1u8, 2u8, 3u8, 4u8, 5u8, 7u8, 8u8]
> +Result: Incomplete ([1u8, 2u8, 3u8, 4u8, 5u8, 7u8, 8u8]) (read 
> little-endian)
> +================
> +Input: [0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 1u8] (LE: 72057594037927936) (BE: 
> 1)
> +Result: 72057594037927936u64 (read little-endian)
> +================
> +Input: [255u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8] (LE: 255) (BE: 
> 18374686479671623680)
> +Result: 255u64 (read little-endian)
> +================
> +Input: [1u8, 1u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8] (LE: 257) (BE: 
> 72339069014638592)
> +Result: 257u64 (read little-endian)
> +================
> +Input: []
> +Result: EOF (read native byte order)
> +================
> +Input: [1u8]
> +Result: Incomplete ([1u8]) (read native byte order)
> +================
> +Input: [1u8, 2u8]
> +Result: Incomplete ([1u8, 2u8]) (read native byte order)
> +================
> +Input: [1u8, 2u8, 3u8]
> +Result: Incomplete ([1u8, 2u8, 3u8]) (read native byte order)
> +================
> +Input: [1u8, 2u8, 3u8, 4u8]
> +Result: Incomplete ([1u8, 2u8, 3u8, 4u8]) (read native byte order)
> +================
> +Input: [1u8, 2u8, 3u8, 4u8, 5u8]
> +Result: Incomplete ([1u8, 2u8, 3u8, 4u8, 5u8]) (read native byte order)
> +================
> +Input: [1u8, 2u8, 3u8, 4u8, 5u8, 6u8]
> +Result: Incomplete ([1u8, 2u8, 3u8, 4u8, 5u8, 6u8]) (read native byte order)
> +================
> +Input: [1u8, 2u8, 3u8, 4u8, 5u8, 7u8]
> +Result: Incomplete ([1u8, 2u8, 3u8, 4u8, 5u8, 7u8]) (read native byte order)
> +================
> +Input: [1u8, 2u8, 3u8, 4u8, 5u8, 7u8, 8u8]
> +Result: Incomplete ([1u8, 2u8, 3u8, 4u8, 5u8, 7u8, 8u8]) (read native byte 
> order)
> +================
> +Input: [0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 1u8] (LE: 72057594037927936) (BE: 
> 1)
> +Result: 72057594037927936u64 (read native byte order)
> +================
> +Input: [255u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8] (LE: 255) (BE: 
> 18374686479671623680)
> +Result: 255u64 (read native byte order)
> +================
> +Input: [1u8, 1u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8] (LE: 257) (BE: 
> 72339069014638592)
> +Result: 257u64 (read native byte order)
> diff --git a/tests/hard_coded/read_binary_uint64.m 
> b/tests/hard_coded/read_binary_uint64.m
> index e69de29..165b5c9 100644
> --- a/tests/hard_coded/read_binary_uint64.m
> +++ b/tests/hard_coded/read_binary_uint64.m
> @@ -0,0 +1,148 @@
> +%---------------------------------------------------------------------------%
> +% vim: ft=mercury ts=4 sw=4 et
> +%---------------------------------------------------------------------------%
> +%
> +% Test reading of binary uint64s.
> +%
> +%---------------------------------------------------------------------------%
> +
> +:- module read_binary_uint64.
> +:- interface.
> +
> +:- import_module io.
> +
> +:- pred main(io::di, io::uo) is det.
> +
> +%---------------------------------------------------------------------------%
> +%---------------------------------------------------------------------------%
> +
> +:- implementation.
> +
> +:- import_module list.
> +:- import_module string.
> +:- import_module uint64.
> +
> +%---------------------------------------------------------------------------%
> +
> +main(!IO) :-
> +    list.foldl(run_test(big_endian), test_cases, !IO),
> +    list.foldl(run_test(little_endian), test_cases, !IO),
> +    list.foldl(run_test(native), test_cases, !IO).
> +
> +:- pred run_test(byte_order::in, test_case::in, io::di, io::uo) is det.
> +
> +run_test(ByteOrder, TestBytes, !IO) :-
> +    io.remove_file(test_file, _, !IO),
> +    io.write_string("================\n", !IO),
> +    io.open_binary_output(test_file, OpenOutResult, !IO),
> +    (
> +        OpenOutResult = ok(OutFile),
> +        io.write_string("Input: ", !IO),
> +        io.write(TestBytes, !IO),
> +        ( if
> +            TestBytes = [Byte1, Byte2, Byte3, Byte4, Byte5, Byte6, Byte7, 
> Byte8]
> +        then
> +            io.write_string(" (LE: ", !IO),
> +            io.write_uint64(from_bytes_le(Byte1, Byte2, Byte3, Byte4, Byte5, 
> Byte6, Byte7, Byte8), !IO),
> +            io.write_string(") (BE: ", !IO),
> +            io.write_uint64(from_bytes_be(Byte1, Byte2, Byte3, Byte4, Byte5, 
> Byte6, Byte7, Byte8), !IO),
> +            io.write_string(")\n", !IO)
> +        else
> +            io.nl(!IO)
> +        ),
> +        list.foldl(write_binary_uint8(OutFile), TestBytes, !IO),
> +        io.close_binary_output(OutFile, !IO),
> +        io.open_binary_input(test_file, OpenInResult, !IO),
> +        (
> +            OpenInResult = ok(InFile),
> +            (
> +                ByteOrder = big_endian,
> +                read_binary_uint64_be(InFile, ReadResult, !IO)
> +            ;
> +                ByteOrder = little_endian,
> +                read_binary_uint64_le(InFile, ReadResult, !IO)
> +            ;
> +                ByteOrder = native,
> +                read_binary_uint64(InFile, ReadResult, !IO)
> +            ),
> +            (
> +                ReadResult = ok(ResultUInt16),
> +                io.write_string("Result: ", !IO),
> +                io.write(ResultUInt16, !IO),
> +                io.write_string(" (", !IO),
> +                describe_byte_order(ByteOrder, !IO),
> +                io.write_string(")\n", !IO)
> +            ;
> +                ReadResult = eof,
> +                io.write_string("Result: EOF (", !IO),
> +                describe_byte_order(ByteOrder, !IO),
> +                io.write_string(")\n", !IO)
> +            ;
> +                ReadResult = incomplete(Bytes),
> +                io.format("Result: Incomplete (%s) (", [s(string(Bytes))],
> +                    !IO),
> +                describe_byte_order(ByteOrder, !IO),
> +                io.write_string(")\n", !IO)
> +            ;
> +                ReadResult = error(IO_Error),
> +                io.format("Result: Error (%s)\n", 
> [s(io.error_message(IO_Error))],
> +                    !IO)
> +            ),
> +            io.remove_file(test_file, _, !IO)
> +        ;
> +            OpenInResult = error(IO_Error),
> +            io.format("I/O ERROR: %s\n", [s(io.error_message(IO_Error))],
> +                !IO)
> +        )
> +    ;
> +        OpenOutResult = error(IO_Error),
> +        io.format("I/O ERROR: %s\n", [s(io.error_message(IO_Error))], !IO)
> +    ).
> +
> +:- pred describe_byte_order(byte_order::in, io::di, io::uo) is det.
> +
> +describe_byte_order(ByteOrder, !IO) :-
> +    (
> +        ByteOrder = big_endian,
> +        io.write_string("read big-endian", !IO)
> +    ;
> +        ByteOrder = little_endian,
> +        io.write_string("read little-endian", !IO)
> +    ;
> +        ByteOrder = native,
> +        io.write_string("read native byte order", !IO)
> +    ).
> +
> +:- func test_file = string.
> +
> +test_file = "read_binary_uint64.bin".
> +
> +%---------------------------------------------------------------------------%
> +
> +:- type byte_order
> +    --->    big_endian
> +    ;       little_endian
> +    ;       native.
> +
> +:- type test_case == list(uint8).
> +
> +:- func test_cases = list(test_case).
> +
> +test_cases = [
> +    [],
> +    [1u8],
> +    [1u8, 2u8],
> +    [1u8, 2u8, 3u8],
> +    [1u8, 2u8, 3u8, 4u8],
> +    [1u8, 2u8, 3u8, 4u8, 5u8],
> +    [1u8, 2u8, 3u8, 4u8, 5u8, 6u8],
> +    [1u8, 2u8, 3u8, 4u8, 5u8, 7u8],
> +    [1u8, 2u8, 3u8, 4u8, 5u8, 7u8, 8u8],
> +    [0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 1u8],
> +    [0xffu8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8],
> +    [1u8, 1u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8]
> +].
> +
> +%---------------------------------------------------------------------------%
> +:- end_module read_binary_uint64.
> +%---------------------------------------------------------------------------%
>
>


More information about the reviews mailing list