Files
narya/src/main/as/com/threerings/io/FrameReader.as
T
Dave Hoover f32e7aa322 Auld Lang Syne
git-svn-id: svn+ssh://src.earth.threerings.net/narya/trunk@6760 542714f4-19e9-0310-aa3c-eee0fc999fb1
2012-01-03 18:45:14 +00:00

117 lines
4.2 KiB
ActionScript

//
// $Id$
//
// Narya library - tools for developing networked games
// Copyright (C) 2002-2012 Three Rings Design, Inc., All Rights Reserved
// http://code.google.com/p/narya/
//
// This library is free software; you can redistribute it and/or modify it
// under the terms of the GNU Lesser General Public License as published
// by the Free Software Foundation; either version 2.1 of the License, or
// (at your option) any later version.
//
// This library is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
// Lesser General Public License for more details.
//
// You should have received a copy of the GNU Lesser General Public
// License along with this library; if not, write to the Free Software
// Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
package com.threerings.io {
import flash.events.EventDispatcher;
import flash.events.ProgressEvent;
import flash.net.Socket;
import flash.utils.ByteArray;
import flash.utils.Endian;
import com.threerings.util.Log;
/**
* Reads socket data until a complete frame is available.
* This dispatches a FrameAvailableEvent.FRAME_AVAILABLE once a frame
* has been fully read off the socket and is ready for decoding.
*/
public class FrameReader extends EventDispatcher
{
public function FrameReader (socket :Socket)
{
_socket = socket;
_socket.addEventListener(ProgressEvent.SOCKET_DATA, socketHasData);
}
/**
* Stop listening on the socket.
*/
public function shutdown () :void
{
_socket.removeEventListener(ProgressEvent.SOCKET_DATA, socketHasData);
}
/**
* Called when our socket has data that we can read.
*/
protected function socketHasData (event :ProgressEvent) :void
{
try {
readAvailable();
} catch (e :Error) {
Log.getLog(this).warning("Error reading socket data", e);
}
}
protected function readAvailable () :void
{
if (ObjectInputStream.DEBUG) {
Log.getLog(this).debug("socketHasData(" + _socket.bytesAvailable + ")");
}
while (_socket.connected && _socket.bytesAvailable > 0) {
if (_curData == null) {
if (_socket.bytesAvailable < HEADER_SIZE) {
// if there are less bytes available than a header, let's
// just leave them on the socket until we can read the length
// all at once
return;
}
// the length specified is the length of the entire frame,
// including the length of the bytes used to encode the length.
// (I think this is pretty silly).
// So for our purposes we subtract 4 bytes so we know how much
// more data is in the frame.
_length = _socket.readInt() - HEADER_SIZE;
_curData = new ByteArray();
_curData.endian = Endian.BIG_ENDIAN;
}
// read bytes: either as much as possible or up to the end of the frame
var toRead :int = Math.min(_length - _curData.length, _socket.bytesAvailable);
// Just in case, if the amount needed is 0, don't do anything!
// Passing 0 causes it to read *all available bytes*.
if (toRead != 0) {
_socket.readBytes(_curData, _curData.length, toRead);
}
if (_length === _curData.length) {
// we have now read a complete frame, let us dispatch the data
_curData.position = 0; // move the read pointer to the beginning
if (ObjectInputStream.DEBUG) {
Log.getLog(this).debug("+ FrameAvailable");
}
dispatchEvent(new FrameAvailableEvent(_curData));
_curData = null; // clear, so we know we need to first read length
}
}
}
protected var _socket :Socket;
protected var _curData :ByteArray;
protected var _length :int;
/** The number of bytes in the frame header (a 32-bit integer). */
protected const HEADER_SIZE :int = 4;
}
}