X-Git-Url: http://nitlanguage.org diff --git a/lib/binary/binary.nit b/lib/binary/binary.nit index 9e63874..c15cb52 100644 --- a/lib/binary/binary.nit +++ b/lib/binary/binary.nit @@ -12,13 +12,13 @@ # See the License for the specific language governing permissions and # limitations under the License. -# Add reading and writing binary services +# Read and write binary data with any `Reader` and `Writer` # # ~~~ # var w = new FileWriter.open("/tmp/data.bin") # w.write "hello" # w.write_int64 123456789 -# w.write_byte 3 +# w.write_byte 3u8 # w.write_float 1.25 # w.write_double 1.234567 # w.write_bits(true, false, true) @@ -28,7 +28,7 @@ # var r = new FileReader.open("/tmp/data.bin") # assert r.read(5) == "hello" # assert r.read_int64 == 123456789 -# assert r.read_byte == 3 +# assert r.read_byte == 3u8 # assert r.read_float == 1.25 # assert r.read_double == 1.234567 # @@ -45,10 +45,13 @@ in "C" `{ #include // Android compatibility + #ifndef be32toh + #define be32toh(val) betoh32(val) + #define le32toh(val) letoh32(val) + #endif + #ifndef be64toh #define be64toh(val) betoh64(val) - #endif - #ifndef le64toh #define le64toh(val) letoh64(val) #endif `} @@ -67,7 +70,7 @@ redef abstract class Writer super BinaryStream # Write a boolean `value` on a byte, using 0 for `false` and 1 for `true` - fun write_bool(value: Bool) do write_byte if value then 1 else 0 + fun write_bool(value: Bool) do write_byte if value then 1u8 else 0u8 # Write up to 8 `Bool` in a byte # @@ -78,9 +81,9 @@ redef abstract class Writer do assert bits.length <= 8 - var int = 0 + var int = 0u8 for b in bits.length.times do - if bits[b] then int += 2**b + if bits[b] then int |= 1u8 << (7 - b) end write_byte int @@ -94,7 +97,18 @@ redef abstract class Writer fun write_string(text: Text) do write text - write_byte 0x00 + write_byte 0x00u8 + end + + # Write the length as a 64 bits integer, then the content of `text` + # + # To be used with `Reader::read_block`. + # + # Compared to `write_string`, this method supports null bytes in `text`. + fun write_block(text: Text) + do + write_int64 text.bytelen + write text end # Write a floating point `value` on 32 bits @@ -137,35 +151,61 @@ redef abstract class Reader super BinaryStream # Read a single byte and return `true` if its value is different than 0 - fun read_bool: Bool do return read_byte != 0 + # + # Returns `false` when an error is pending (`last_error != null`). + fun read_bool: Bool do return read_byte != 0u8 # Get an `Array` of 8 `Bool` by reading a single byte # # To be used with `BinaryWriter::write_bits`. + # + # Returns an array of `false` when an error is pending (`last_error != null`). fun read_bits: Array[Bool] do var int = read_byte if int == null then return new Array[Bool] - return [for b in 8.times do int.bin_and(2**b) > 0] + var arr = new Array[Bool] + for i in [7 .. 0].step(-1) do + arr.push(((int >> i) & 1u8) != 0u8) + end + return arr end # Read a null terminated string # # To be used with `Writer::write_string`. + # + # Returns a truncated string when an error is pending (`last_error != null`). fun read_string: String do - var buf = new FlatBuffer + var buf = new Bytes.empty loop var byte = read_byte - if byte == 0x00 then return buf.to_s - buf.chars.add byte.ascii + if byte == null or byte == 0u8 then + return buf.to_s + end + buf.add byte end end + # Read the length as a 64 bits integer, then the content of the block + # + # To be used with `Writer::write_block`. + # + # Returns a truncated string when an error is pending (`last_error != null`). + fun read_block: String + do + var length = read_int64 + if length == 0 then return "" + return read_bytes(length).to_s + end + # Read a floating point on 32 bits and return it as a `Float` # # Using this format may result in a loss of precision as it uses less bits # than Nit `Float`. + # + # Returns `0.0` when an error is pending (`last_error != null`). fun read_float: Float do if last_error != null then return 0.0 @@ -182,7 +222,7 @@ redef abstract class Reader end # Utility for `read_float` - private fun native_read_float(b0, b1, b2, b3: Int, big_endian: Bool): Float `{ + private fun native_read_float(b0, b1, b2, b3: Byte, big_endian: Bool): Float `{ union { unsigned char b[4]; float val; @@ -202,6 +242,8 @@ redef abstract class Reader `} # Read a floating point on 64 bits and return it as a `Float` + # + # Returns `0.0` when an error is pending (`last_error != null`). fun read_double: Float do if last_error != null then return 0.0 @@ -223,7 +265,7 @@ redef abstract class Reader end # Utility for `read_double` - private fun native_read_double(b0, b1, b2, b3, b4, b5, b6, b7: Int, big_endian: Bool): Float `{ + private fun native_read_double(b0, b1, b2, b3, b4, b5, b6, b7: Byte, big_endian: Bool): Float `{ union { unsigned char b[8]; double val; @@ -250,6 +292,8 @@ redef abstract class Reader # # Using this format may result in a loss of precision as the length of a # Nit `Int` may be less than 64 bits on some platforms. + # + # Returns `0` when an error is pending (`last_error != null`). fun read_int64: Int do if last_error != null then return 0 @@ -271,7 +315,7 @@ redef abstract class Reader end # Utility for `read_int64` - private fun native_read_int64(b0, b1, b2, b3, b4, b5, b6, b7: Int, big_endian: Bool): Int `{ + private fun native_read_int64(b0, b1, b2, b3, b4, b5, b6, b7: Byte, big_endian: Bool): Int `{ union { unsigned char b[8]; int64_t val; @@ -297,14 +341,14 @@ end redef class Int # Utility for `BinaryWriter` - private fun int64_byte_at(index: Int, big_endian: Bool): Int `{ + private fun int64_byte_at(index: Int, big_endian: Bool): Byte `{ union { unsigned char bytes[8]; int64_t val; uint64_t conv; } u; - u.val = recv; + u.val = self; if (big_endian) u.conv = htobe64(u.conv); @@ -316,14 +360,14 @@ end redef class Float # Utility for `BinaryWriter` - private fun float_byte_at(index: Int, big_endian: Bool): Int `{ + private fun float_byte_at(index: Int, big_endian: Bool): Byte `{ union { unsigned char bytes[4]; float val; uint32_t conv; } u; - u.val = recv; + u.val = self; if (big_endian) u.conv = htobe32(u.conv); @@ -333,14 +377,14 @@ redef class Float `} # Utility for `BinaryWriter` - private fun double_byte_at(index: Int, big_endian: Bool): Int `{ + private fun double_byte_at(index: Int, big_endian: Bool): Byte `{ union { unsigned char bytes[8]; double val; uint64_t conv; } u; - u.val = recv; + u.val = self; if (big_endian) u.conv = htobe64(u.conv);