From bf91088ca504078df8e355d410b01bd8a288d3ba Mon Sep 17 00:00:00 2001 From: Lucas Bajolet Date: Thu, 21 May 2015 14:23:02 -0400 Subject: [PATCH] lib: Various fixes on lib with the new file and stream API Signed-off-by: Lucas Bajolet --- contrib/online_ide/sources/nit/pnacl_nit.nit | 4 +- lib/bitmap/bitmap.nit | 30 ++++----- lib/pnacl.nit | 6 +- lib/socket/socket.nit | 25 ++++++-- lib/socket/socket_c.nit | 10 ++- lib/websocket/websocket.nit | 86 +++++++++++++------------- 6 files changed, 87 insertions(+), 74 deletions(-) diff --git a/contrib/online_ide/sources/nit/pnacl_nit.nit b/contrib/online_ide/sources/nit/pnacl_nit.nit index 74c7be0..2017a0b 100644 --- a/contrib/online_ide/sources/nit/pnacl_nit.nit +++ b/contrib/online_ide/sources/nit/pnacl_nit.nit @@ -72,7 +72,7 @@ redef class FileReader self.path = path var file = sys.files[path] prepare_buffer(file.length) - _buffer.append(file) + path.copy_to_native(_buffer, file.length, 0, 0) end redef fun close @@ -82,7 +82,7 @@ redef class FileReader redef fun fill_buffer do - _buffer.clear + buffer_reset end_reached = true end diff --git a/lib/bitmap/bitmap.nit b/lib/bitmap/bitmap.nit index 0343b8e..9be1bc2 100644 --- a/lib/bitmap/bitmap.nit +++ b/lib/bitmap/bitmap.nit @@ -123,14 +123,20 @@ class Bitmap # =============== Bitmap header ================ for x in [0..13] do - bitmap_header[x] = fileReader.read(1)[0].ascii + var b = fileReader.read_byte + if b == null then + return + end + bitmap_header[x] = b end self.file_size = get_value(bitmap_header.subarray(2, 4)) self.data_offset = get_value(bitmap_header.subarray(10, 4)) # =============== DIB header ================ for x in [0..39] do - dib_header[x] = fileReader.read(1)[0].ascii + var b = fileReader.read_byte + if b == null then return + dib_header[x] = b end var dib_size = get_value(dib_header.subarray(0, 4)) # only support BITMAPINFOHEADER @@ -159,9 +165,11 @@ class Bitmap var row = new Array[Int].with_capacity(self.width) for y in [0..self.width[ do - var red = fileReader.read(1)[0].ascii * 256 * 256 - var green = fileReader.read(1)[0].ascii * 256 - var blue = fileReader.read(1)[0].ascii + var bts = fileReader.read_bytes(3) + if bts.length != 3 then return + var red = bts[0] << 16 + var green = bts[1] << 8 + var blue = bts[2] row.add(red + green + blue) end self.data.add(row) @@ -170,18 +178,6 @@ class Bitmap fileReader.close end #end of load_from_file method - # Reads in a series of bytes from the FileReader when loading a Bitmap from a file - # FileReader.read(1) is used due to https://github.com/privat/nit/issues/1264 - private fun read_chars(fr: FileReader, howMany: Int): String - do - var s = "" - for x in [1..howMany] - do - s += fr.read(1) - end - return s - end - # Converts the value contained in two or four bytes into an Int. Since Nit # does not have a byte type, Int is used private fun get_value(array: Array[Int]): Int diff --git a/lib/pnacl.nit b/lib/pnacl.nit index 516c860..248a4d4 100644 --- a/lib/pnacl.nit +++ b/lib/pnacl.nit @@ -653,9 +653,11 @@ class PnaclStream # fill_buffer now checks for a message in the message queue which is filled by user inputs. redef fun fill_buffer do - _buffer.clear _buffer_pos = 0 - _buffer.append check_message.to_s + var nns = check_message + var nslen = nns.cstring_length + _buffer_length = nslen + nns.copy_to(buffer, nslen, 0, 0) end end diff --git a/lib/socket/socket.nit b/lib/socket/socket.nit index b3cb2f9..d553540 100644 --- a/lib/socket/socket.nit +++ b/lib/socket/socket.nit @@ -57,7 +57,7 @@ class TCPStream # Creates a socket connection to host `host` on port `port` init connect(host: String, port: Int) do - _buffer = new FlatBuffer + _buffer = new NativeString(1024) _buffer_pos = 0 socket = new NativeSocket.socket(new NativeSocketAddressFamilies.af_inet, new NativeSocketTypes.sock_stream, new NativeSocketProtocolFamilies.pf_null) @@ -84,7 +84,7 @@ class TCPStream # Creates a client socket, this is meant to be used by accept only private init server_side(h: SocketAcceptResult) do - _buffer = new FlatBuffer + _buffer = new NativeString(1024) _buffer_pos = 0 socket = h.socket addrin = h.addr_in @@ -110,7 +110,7 @@ class TCPStream # timeout : Time in milliseconds before stopping to wait for events fun ready_to_read(timeout: Int): Bool do - if _buffer_pos < _buffer.length then return true + if _buffer_pos < _buffer_length then return true if end_reached then return false var events = [new NativeSocketPollValues.pollin] return pollin(events, timeout).length != 0 @@ -153,6 +153,11 @@ class TCPStream socket.write_byte value end + redef fun write_bytes(s) do + if closed then return + socket.write(s.to_s) + end + fun write_ln(msg: Text) do if end_reached then return @@ -162,7 +167,7 @@ class TCPStream redef fun fill_buffer do - _buffer.clear + _buffer_length = 0 _buffer_pos = 0 if not connected then return var read = socket.read @@ -170,7 +175,17 @@ class TCPStream close end_reached = true end - _buffer.append(read) + enlarge(_buffer_capacity + read.length) + read.copy_to_native(_buffer, read.length, 0, 0) + _buffer_length = read.length + end + + fun enlarge(len: Int) do + if _buffer_capacity >= len then return + while _buffer_capacity < len do _buffer_capacity *= 2 + var ns = new NativeString(_buffer_capacity) + _buffer.copy_to(ns, _buffer_length - _buffer_pos, _buffer_pos, 0) + _buffer = ns end redef fun close diff --git a/lib/socket/socket_c.nit b/lib/socket/socket_c.nit index a574485..627fb06 100644 --- a/lib/socket/socket_c.nit +++ b/lib/socket/socket_c.nit @@ -137,16 +137,14 @@ extern class NativeSocket `{ int* `} return write(*recv, &value, 1); `} - fun read: String import NativeString.to_s_with_length `{ + fun read: String import NativeString.to_s_with_length, NativeString.to_s_with_copy `{ static char c[1024]; - int n = read(*recv, c, 1024); + int n = read(*recv, c, 1023); if(n < 0) { return NativeString_to_s_with_length("",0); } - char* ret = malloc(n + 1); - memcpy(ret, c, n); - ret[n] = '\0'; - return NativeString_to_s_with_length(ret, n); + c[n] = 0; + return NativeString_to_s_with_copy(c); `} # Sets an option for the socket diff --git a/lib/websocket/websocket.nit b/lib/websocket/websocket.nit index a22c5b2..6eac618 100644 --- a/lib/websocket/websocket.nit +++ b/lib/websocket/websocket.nit @@ -23,6 +23,7 @@ import sha1 import base64 intrude import standard::stream +intrude import standard::bytes # Websocket compatible listener # @@ -65,8 +66,10 @@ class WebsocketConnection super TCPStream init do - _buffer = new FlatBuffer + _buffer = new NativeString(1024) _buffer_pos = 0 + _buffer_capacity = 1024 + _buffer_length = 0 var headers = parse_handshake var resp = handshake_response(headers) @@ -119,22 +122,28 @@ class WebsocketConnection end # Frames a text message to be sent to a client - private fun frame_message(msg: String): String + private fun frame_message(msg: String): Bytes do - var ans_buffer = new FlatBuffer + var ans_buffer = new Bytes.with_capacity(msg.length) # Flag for final frame set to 1 # opcode set to 1 (for text) - ans_buffer.add(129.ascii) + ans_buffer.add(129) if msg.length < 126 then - ans_buffer.add(msg.length.ascii) + ans_buffer.add(msg.length) end if msg.length >= 126 and msg.length <= 65535 then - ans_buffer.add(126.ascii) - ans_buffer.add(msg.length.rshift(8).ascii) - ans_buffer.add(msg.length.ascii) + ans_buffer.add(126) + ans_buffer.add(msg.length.rshift(8)) + ans_buffer.add(msg.length) end - ans_buffer.append(msg) - return ans_buffer.to_s + if msg isa FlatString then + ans_buffer.append_ns_from(msg.items, msg.length, msg.index_from) + else + for i in msg.substrings do + ans_buffer.append_ns_from(i.as(FlatString).items, i.length, i.as(FlatString).index_from) + end + end + return ans_buffer end # Reads an HTTP frame @@ -149,6 +158,7 @@ class WebsocketConnection # Gets the message from the client, unpads it and reconstitutes the message private fun unpad_message do var fin = false + var bf = new Bytes.empty while not fin do var fst_byte = client.read_byte var snd_byte = client.read_byte @@ -174,10 +184,10 @@ class WebsocketConnection if fin_flag != 0 then fin = true var opcode = fst_byte.bin_and(15) if opcode == 9 then - _buffer.add(138.ascii) - _buffer.add('\0') - client.write(_buffer.to_s) - _buffer_pos += 2 + bf.add(138) + bf.add(0) + client.write(bf.to_s) + _buffer_pos = _buffer_length return end if opcode == 8 then @@ -192,76 +202,68 @@ class WebsocketConnection var len = snd_byte.bin_and(127) var payload_ext_len = 0 if len == 126 then - var tmp = client.read(2) + var tmp = client.read_bytes(2) if tmp.length != 2 then last_error = new IOError("Error: received interrupted frame") client.close return end - payload_ext_len = tmp[1].ascii + tmp[0].ascii.lshift(8) + payload_ext_len = tmp[1] + tmp[0].lshift(8) else if len == 127 then # 64 bits for length are not supported, # only the last 32 will be interpreted as a Nit Integer - var tmp = client.read(8) + var tmp = client.read_bytes(8) if tmp.length != 8 then last_error = new IOError("Error: received interrupted frame") client.close return end for pos in [0 .. tmp.length[ do - var i = tmp[pos].ascii + var i = tmp[pos] payload_ext_len += i.lshift(8 * (7 - pos)) end end if mask_flag != 0 then + var mask = client.read_bytes(4).items if payload_ext_len != 0 then - var msg = client.read(payload_ext_len+4) - var mask = msg.substring(0,4) - _buffer.append(unmask_message(mask, msg.substring(4, payload_ext_len))) - else - if len == 0 then - return - end - var msg = client.read(len+4) - var mask = msg.substring(0,4) - _buffer.append(unmask_message(mask, msg.substring(4, len))) + len = payload_ext_len end + var msg = client.read_bytes(len).items + bf.append_ns(unmask_message(mask, msg, len), len) end end + _buffer = bf.items + _buffer_length = bf.length end # Unmasks a message sent by a client - private fun unmask_message(key: String, message: String): String + private fun unmask_message(key: NativeString, message: NativeString, len: Int): NativeString do - var return_message = new FlatBuffer.with_capacity(message.length) - var msg_iter = message.chars.iterator + var return_message = new NativeString(len) - while msg_iter.is_ok do - return_message.chars[msg_iter.index] = msg_iter.item.ascii.bin_xor(key.chars[msg_iter.index%4].ascii).ascii - msg_iter.next + for i in [0 .. len[ do + return_message[i] = message[i].ascii.bin_xor(key[i%4].ascii).ascii end - return return_message.to_s + return return_message end # Checks if a connection to a client is available redef fun connected do return client.connected - redef fun write(msg) - do - client.write(frame_message(msg.to_s)) - end + redef fun write_bytes(s) do client.write_bytes(frame_message(s.to_s)) + + redef fun write(msg) do client.write(frame_message(msg.to_s).to_s) redef fun is_writable do return client.connected redef fun fill_buffer do - _buffer.clear - _buffer_pos = 0 + buffer_reset unpad_message end - redef fun end_reached do return client._buffer_pos >= client._buffer.length and client.end_reached + redef fun end_reached do return client._buffer_pos >= client._buffer_length and client.end_reached # Is there some data available to be read ? fun can_read(timeout: Int): Bool do return client.ready_to_read(timeout) -- 1.7.9.5