Skip to content

Instantly share code, notes, and snippets.

@jamesu
Created March 19, 2012 13:43
Show Gist options
  • Star 4 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save jamesu/2112670 to your computer and use it in GitHub Desktop.
Save jamesu/2112670 to your computer and use it in GitHub Desktop.
Javascript Byte IO for haXe using ArrayBuffers
// Example usage
class Example
{
public static function test()
{
var bytes = new JSByteIO(new ArrayBuffer(128));
// Writing and reading a line
bytes.writeString("HELLO WORLD\n");
bytes.seek(0, Seek.SeekBegin);
trace(bytes.readLine()); // HELLO WORLD
// Numbers
bytes.seek(0, Seek.SeekBegin);
bytes.writeInt32(-100);
bytes.writeInt16(-100);
bytes.writeInt8(-100);
bytes.writeUInt32(100);
bytes.writeUInt16(100);
bytes.writeUInt8(100);
bytes.writeFloat(1234.5);
trace(bytes.tell()); // 18
bytes.seek(0, Seek.SeekBegin);
trace(bytes.readInt32()); // -100
trace(bytes.readInt16()); // -100
trace(bytes.readInt8()); // -100
trace(bytes.readUInt32()); // 100
trace(bytes.readUInt16()); // 100
trace(bytes.readUInt8()); // 100
trace(bytes.readFloat()); // 1234.5
// Generic bytes
bytes.writeBytes(bytes.bytes, 0, 18);
trace(bytes.tell()); // 36
bytes.seek(18, Seek.SeekBegin);
trace(bytes.readInt32()); // -100
trace(bytes.readInt16()); // -100
trace(bytes.readInt8()); // -100
trace(bytes.readUInt32()); // 100
trace(bytes.readUInt16()); // 100
trace(bytes.readUInt8()); // 100
trace(bytes.readFloat()); // 1234.5
}
}
/*
JSByteIO - Javascript stream reader using ArrayBuffers
Copyright (C) 2012 James S Urquhart (jamesu at gmail.com)
Licensed under the MIT License.
*/
import js.XMLHttpRequest;
enum Seek
{
SeekEnd;
SeekCur;
SeekBegin;
}
class JSByteIO
{
public var data : ArrayBuffer;
public var bytes : Uint8Array;
public var pos: Int;
// Temp buffers used for conversion
private var conversionBuffer: ArrayBuffer;
private var conversionUChar : Uint8Array;
private var conversionChar : Int8Array;
private var conversionUShort: Uint16Array;
private var conversionShort: Int16Array;
private var conversionUInt: Uint32Array;
private var conversionInt: Int32Array;
private var floatConversion: Float32Array;
public function new(?theData: ArrayBuffer)
{
data = theData;
bytes = new Uint8Array(theData);
pos = 0;
conversionBuffer = new ArrayBuffer(16);
conversionUChar = new Uint8Array(conversionBuffer);
conversionChar = new Int8Array(conversionBuffer);
conversionUShort = new Uint16Array(conversionBuffer);
conversionShort = new Int16Array(conversionBuffer);
conversionUInt = new Uint32Array(conversionBuffer);
conversionInt = new Int32Array(conversionBuffer);
floatConversion = new Float32Array(conversionBuffer);
}
public function close() : Void
{
data = null;
bytes = null;
}
// Input
public function read(nbytes : Int) : Uint8Array
{
var buf = new Uint8Array(nbytes);
var i=0;
while( nbytes > 0 ) {
buf[i] = bytes[pos];
i += 1;
pos += 1;
nbytes -= 1;
}
return buf;
}
public function readStringBytes(nbytes : Int)
{
var buf = new StringBuf();
for (i in 0...nbytes)
buf.addChar(this.readUInt8());
return buf.toString();
}
public function readUInt8() {
if( this.pos + 1 > this.bytes.length )
throw new Eof();
var c = bytes[pos];
pos += 1;
return c;
}
public function readBytes(s : Uint8Array, p : Int, len : Int) : Int
{
var count: Int = 0;
var i: Int = p;
var j: Int = 0;
var end = p+len;
var start = this.pos;
for (i in p...end) {
if (this.pos >= data.length)
break;
s[i] = this.bytes[this.pos++];
}
return this.pos-start;
}
public function readFloat() : Float {
var n = this.readUInt32();
conversionInt.set([n], 0);
return floatConversion[0];
}
public function readInt8() : Int {
var n = readUInt8();
conversionChar[0] = n;
return conversionChar[0];
}
public function readInt16() : Int {
conversionUChar[0] = readUInt8();
conversionUChar[1] = readUInt8();
return conversionShort[0];
}
public function readUInt16() : Int {
conversionUChar[0] = readUInt8();
conversionUChar[1] = readUInt8();
return conversionUShort[0];
}
public function readInt32() {
conversionUChar[0] = readUInt8();
conversionUChar[1] = readUInt8();
conversionUChar[2] = readUInt8();
conversionUChar[3] = readUInt8();
return conversionInt[0];
}
public function readUInt32() {
conversionUChar[0] = readUInt8();
conversionUChar[1] = readUInt8();
conversionUChar[2] = readUInt8();
conversionUChar[3] = readUInt8();
return conversionUInt[0];
}
public function readLine() : String
{
var buf = new StringBuf();
var last : Int;
var c : Int = 0;
try {
while( true ) {
last = readUInt8();
if (last == 10 || last == 0) break;
if (last != 13) { buf.addChar( last ); c++; }
}
} catch( e : Dynamic ) {
}
return c == 0 ? null : buf.toString();
}
public function prepare(nbytes : Int) : Void
{
var i = nbytes - 1;
while (i >= 0)
{
bytes[i] = 0;
i -= 1;
}
}
public function writeString(s : Dynamic) : Void
{
var i = 0;
for (i in 0...s.length)
{
writeUInt8(s.charCodeAt(i));
}
}
public function write(s : Uint8Array) : Void
{
var i = 0;
for (i in 0...s.length)
{
writeUInt8(s[i]);
}
}
public function writeBytes(s : Uint8Array, p : Int, len : Int) : Int
{
var opos: Int = pos;
try
{
write(s.subarray(p, len));
}
catch (e: Dynamic)
{
return 0;
}
return pos - opos;
}
public function writeUInt8(c : Int) : Void
{
if (this.pos + 1 > this.bytes.length)
throw new Eof();
bytes[pos] = c;
pos += 1;
}
public function writeFloat(x : Float) : Void
{
floatConversion[0] = x;
writeUInt8(conversionUChar[0]);
writeUInt8(conversionUChar[1]);
writeUInt8(conversionUChar[2]);
writeUInt8(conversionUChar[3]);
}
public function writeInt16(x : Int) : Void
{
conversionShort[0] = x;
writeUInt8(conversionUChar[0]);
writeUInt8(conversionUChar[1]);
}
public function writeInt32(x : Int) : Void
{
conversionInt[0] = x;
writeUInt8(conversionUChar[0]);
writeUInt8(conversionUChar[1]);
writeUInt8(conversionUChar[2]);
writeUInt8(conversionUChar[3]);
}
public function writeInt8(x : Int) : Void
{
conversionChar[0] = x;
writeUInt8(conversionUChar[0]);
}
public function writeUInt16(x : Int) : Void
{
conversionUShort[0] = x;
writeUInt8(conversionUChar[0]);
writeUInt8(conversionUChar[1]);
}
public function writeUInt32(x : Int) : Void
{
conversionUInt[0] = x;
writeUInt8(conversionUChar[0]);
writeUInt8(conversionUChar[1]);
writeUInt8(conversionUChar[2]);
writeUInt8(conversionUChar[3]);
}
public function seek(p : Int, pos : Seek) : Void
{
switch (pos)
{
case SeekEnd:
this.pos = bytes.length - p;
case SeekCur:
this.pos += p;
case SeekBegin:
this.pos = p;
}
}
public function tell() : Int
{
return pos;
}
// Static utils
public static function fromURL(url: String) : JSByteIO
{
// Grab data from url
var req: Dynamic = new XMLHttpRequest();
req.open("GET", url, false);
req.responseType = "arraybuffer";
req.send(null);
var res = new JSByteIO(req.response);
trace("XMLHttpRequest: Loaded " + res.bytes.length + " bytes (Type = '" + req.getResponseHeader("Content-Type") + "')");
return res;
}
}
// Types necessary for JSByteIO
enum Error {
Blocked;
Closed;
Overflow;
Custom( e : Dynamic );
}
class Eof
{
public function new()
{
}
public function toString() : String
{
return "EOF";
}
}
extern class ArrayBuffer {
public var length: Int;
public function new(size: Int) : Void;
}
extern class TypedArray implements Array<Dynamic> {
public var length: Int;
public function set(array: Dynamic, offset: Int) : Void;
// So the code doesn't complain
/**
Returns a new Array by appending [a] to [this].
**/
function concat( a : Array<Dynamic> ) : Array<Dynamic>;
/**
Returns a representation of an array with [sep] for separating each element.
**/
function join( sep : String ) : String;
/**
Removes the last element of the array and returns it.
**/
function pop() : Null<Dynamic>;
/**
Adds the element [x] at the end of the array.
**/
function push(x : Dynamic) : Int;
/**
Reverse the order of elements of the Array.
**/
function reverse() : Void;
/**
Removes the first element and returns it.
**/
function shift() : Null<Dynamic>;
/**
Copies the range of the array starting at [pos] up to,
but not including, [end]. Both [pos] and [end] can be
negative to count from the end: -1 is the last item in
the array.
**/
function slice( pos : Int, ?end : Int ) : Array<Dynamic>;
/**
Sort the Array according to the comparison function [f].
[f(x,y)] should return [0] if [x == y], [>0] if [x > y]
and [<0] if [x < y].
**/
function sort( f : Dynamic -> Dynamic -> Int ) : Void;
/**
Removes [len] elements starting from [pos] an returns them.
**/
function splice( pos : Int, len : Int ) : Array<Dynamic>;
/**
Returns a displayable representation of the Array content.
**/
function toString() : String;
/**
Adds the element [x] at the start of the array.
**/
function unshift( x : Dynamic ) : Void;
/**
Inserts the element [x] at the position [pos].
All elements after [pos] are moved one index ahead.
**/
function insert( pos : Int, x : Dynamic ) : Void;
/**
Removes the first occurence of [x].
Returns false if [x] was not present.
Elements are compared by using standard equality.
**/
function remove( x : Dynamic ) : Bool;
/**
Returns a copy of the Array. Dynamic values are not
copied, only the Array structure.
**/
function copy() : Array<Dynamic>;
/**
Returns an iterator of the Array values.
**/
function iterator() : Iterator<Null<Dynamic>>;
}
extern class Float32Array extends TypedArray {
public function subarray(begin: Int, end: Int) : Float32Array;
public function new(data: Dynamic, ?offset: Int , ?length: Int) : Void;
}
extern class Int8Array extends TypedArray {
public function subarray(begin: Int, end: Int) : Int8Array;
public function new(data: Dynamic, ?offset: Int , ?length: Int) : Void;
}
extern class Int16Array extends TypedArray {
public function subarray(begin: Int, end: Int) : Int16Array;
public function new(data: Dynamic, ?offset: Int , ?length: Int) : Void;
}
extern class Int32Array extends TypedArray {
public function subarray(begin: Int, end: Int) : Int32Array;
public function new(data: Dynamic, ?offset: Int , ?length: Int) : Void;
}
extern class Uint8Array extends TypedArray {
public function subarray(begin: Int, end: Int) : Uint8Array;
public function new(data: Dynamic, ?offset: Int , ?length: Int) : Void;
}
extern class Uint16Array extends TypedArray {
public function subarray(begin: Int, end: Int) : Uint16Array;
public function new(data: Dynamic, ?offset: Int , ?length: Int) : Void;
}
extern class Uint32Array extends TypedArray {
public function subarray(begin: Int, end: Int) : Uint32Array;
public function new(data: Dynamic, ?offset: Int , ?length: Int) : Void;
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment