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

Julien Fischer jfischer at opturion.com
Tue Jan 8 15:02:56 AEDT 2019



On Tue, 8 Jan 2019, Zoltan Somogyi wrote:

> On Tue, 8 Jan 2019 01:43:43 +0000 (UTC), Julien Fischer <jfischer at opturion.com> wrote:
>> Any takers to review this one?
>
> I will have a look if you send me the diff as an attachment, though
> someone else should check the Java and C# versions.

Attached.

> I would have done this earlier, but I thought your email was soliciting
> feedback only on the return types.

No, that was the previous mail.

Julien.
-------------- next part --------------
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.
-------------- next part --------------
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