1 jls.loader.provide('jls.lang.ByteBuffer'); 2 3 jls.loader.require('jls.lang.Buffer'); 4 jls.loader.require('jls.lang.IllegalArgumentException'); 5 jls.loader.require('jls.lang.BufferOverflowException'); 6 jls.loader.require('jls.lang.BufferUnderflowException'); 7 jls.loader.require('jls.io.cs.Charset'); 8 9 /** 10 * @augments jls.lang.Buffer 11 * @class The buffer class provides facilities to get and put datas from/to a native byte array. 12 */ 13 jls.lang.ByteBuffer = jls.lang.Class.create(jls.lang.Buffer, /** @lends jls.lang.ByteBuffer.prototype */ 14 { 15 initialize : function($super, barray, offset, length, limit, position) { 16 if (! (barray instanceof _native.core.ByteArray)) { 17 throw new jls.lang.Exception('Invalid barray argument (' + (typeof barray) + ')'); 18 } 19 this._barray = barray; 20 offset = offset || 0; 21 var capacity = (typeof length != 'undefined') ? length : this._barray.size() - offset; 22 $super(capacity, limit, position, offset); 23 this._byteOrder = jls.lang.ByteBuffer.DEFAULT_BYTE_ORDER; 24 }, 25 /** 26 * Returns the native byte array of this buffer. 27 * 28 * @returns {_native.core.ByteArray} The native byte array. 29 */ 30 byteArray : function() { 31 return this._barray; 32 }, 33 /** 34 * Free the associated byte array. 35 * 36 * @returns {jls.lang.Buffer} This buffer. 37 */ 38 free : function() { 39 this._barray.free(); 40 return this; 41 }, 42 /** 43 * Creates a new buffer sharing the native byte array. 44 * 45 * @returns {jls.lang.Buffer} The new buffer. 46 */ 47 duplicate : function() { 48 return new jls.lang.ByteBuffer(this._barray, this._offset, this._capacity, this._limit, this._position); 49 }, 50 /** 51 * Creates a new buffer starting at the current position and with the remaining bytes. 52 * 53 * @returns {jls.lang.Buffer} The new buffer. 54 */ 55 slice : function() { 56 return new jls.lang.ByteBuffer(this._barray, this.position(), this.remaining()); 57 }, 58 /** 59 * Puts a byte into this buffer at the current position, and then increments the position. 60 * 61 * @param {Number} b The byte to put. 62 * @returns {jls.lang.Buffer} This buffer. 63 */ 64 putByte : function(b) { 65 if (this.remaining() < 1) { 66 throw new jls.lang.BufferOverflowException(); 67 } 68 this._barray.put(this.offset(), b); 69 this._position++; 70 return this; 71 }, 72 /** 73 * Gets a byte from this buffer at the current position, and then increments the position. 74 * 75 * @param {Boolean} signed Whether the byte to get is signed. 76 * @returns {Number} The byte. 77 */ 78 getByte : function(signed) { 79 if (this.remaining() < 1) { 80 throw new jls.lang.BufferUnderflowException(); 81 } 82 var b = this._barray.get(this.offset()); 83 this._position++; 84 return (signed && (b >= 0x80)) ? b - 0x100 : b; 85 }, 86 putString : function(s, csn) { 87 if (this.remaining() < s.length) { 88 throw new jls.lang.BufferOverflowException(); 89 } 90 // TODO Use cache 91 var cs = csn ? jls.io.cs.Charset.forName(csn) : jls.io.cs.Charset.defaultCharset(); 92 var encoder = cs.newEncoder(); 93 var cb = jls.lang.CharBuffer.wrap(s); 94 encoder.encode(cb, this); 95 return this; 96 }, 97 getString : function(csn) { 98 // TODO Use cache 99 var cs = csn ? jls.io.cs.Charset.forName(csn) : jls.io.cs.Charset.defaultCharset(); 100 var decoder = cs.newDecoder(); 101 var cb = decoder.decode(this); 102 cb.flip(); 103 return cb.getString(); 104 }, 105 putBuffer : function(buffer, length) { 106 length = length || buffer.remaining(); 107 if (this.remaining() < length) { 108 throw new jls.lang.BufferOverflowException(); 109 } 110 this._barray.memcpy(this.offset(), buffer.byteArray(), buffer.position(), length); 111 this._position += length; 112 //buffer.incrementPosition(length); 113 return this; 114 }, 115 putByteArray : function(ba) { 116 if (this.remaining() < ba.length) { 117 throw new jls.lang.BufferOverflowException(); 118 } 119 for (var i = 0; i < ba.length; i++) { 120 this._barray.put(this.offset() + i, ba[i]); 121 } 122 this._position += ba.length; 123 return this; 124 }, 125 getByteArray : function(length) { 126 if (length) { 127 if (this.remaining() < length) { 128 throw new jls.lang.BufferUnderflowException(); 129 } 130 } else { 131 length = this.remaining(); 132 } 133 var ba = []; 134 for (var i = 0; i < length; i++) { 135 ba.push(this._barray.get(this.offset() + i)); 136 } 137 this._position += length; 138 return ba; 139 }, 140 getByteOrder : function() { 141 return this._byteOrder; 142 }, 143 setByteOrder : function(byteOrder) { 144 this._byteOrder = byteOrder; 145 }, 146 putShort : function(value) { 147 if (this._byteOrder == jls.lang.ByteBuffer.BIG_ENDIAN) { 148 this.putByte((value >> 8) & 0xff); 149 this.putByte(value & 0xff); 150 } else { 151 this.putByte(value & 0xff); 152 this.putByte((value >> 8) & 0xff); 153 } 154 }, 155 getShort : function(signed) { 156 var value; 157 if (this._byteOrder == jls.lang.ByteBuffer.BIG_ENDIAN) { 158 value = this.getByte() << 8; 159 value |= this.getByte(); 160 } else { 161 value = this.getByte(); 162 value |= this.getByte() << 8; 163 } 164 return (signed && (value >= 0x8000)) ? value - 0x10000 : value; 165 }, 166 putInt : function(value) { 167 if (this._byteOrder == jls.lang.ByteBuffer.BIG_ENDIAN) { 168 this.putByte((value >> 24) & 0xff); 169 this.putByte((value >> 16) & 0xff); 170 this.putByte((value >> 8) & 0xff); 171 this.putByte(value & 0xff); 172 } else { 173 this.putByte(value & 0xff); 174 this.putByte((value >> 8) & 0xff); 175 this.putByte((value >> 16) & 0xff); 176 this.putByte((value >> 24) & 0xff); 177 } 178 }, 179 getInt : function(signed) { 180 var value; 181 if (this._byteOrder == jls.lang.ByteBuffer.BIG_ENDIAN) { 182 value = this.getByte() << 24; 183 value |= this.getByte() << 16; 184 value |= this.getByte() << 8; 185 value |= this.getByte(); 186 } else { 187 value = this.getByte(); 188 value |= this.getByte() << 8; 189 value |= this.getByte() << 16; 190 value |= this.getByte() << 24; 191 } 192 return (signed && (value >= 0x80000000)) ? value - 0x100000000 : value; 193 }, 194 /* 195 * Bitwise operators treat their operands as a set of 32 bits (zeros and ones), rather than as decimal, 196 * hexadecimal, or octal numbers. For example, the decimal number nine has a binary representation of 1001. 197 * Bitwise operators perform their operations on such binary representations, but they return standard JavaScript numerical values. 198 */ 199 putLong : function(value) { 200 // var hi = (value - (value % 0x100000000)) / 0x100000000; 201 var hi = value / 0x100000000; 202 if (value >= 0) { 203 hi = Math.floor(hi); 204 } else { 205 hi = Math.ceil(hi); 206 if (hi == 0) { 207 hi = -1; // -0 ! 208 } 209 } 210 if (this._byteOrder == jls.lang.ByteBuffer.BIG_ENDIAN) { 211 this.putByte((hi >> 24) & 0xff); 212 this.putByte((hi >> 16) & 0xff); 213 this.putByte((hi >> 8) & 0xff); 214 this.putByte(hi & 0xff); 215 this.putByte((value >> 24) & 0xff); 216 this.putByte((value >> 16) & 0xff); 217 this.putByte((value >> 8) & 0xff); 218 this.putByte(value & 0xff); 219 } else { 220 this.putByte(value & 0xff); 221 this.putByte((value >> 8) & 0xff); 222 this.putByte((value >> 16) & 0xff); 223 this.putByte((value >> 24) & 0xff); 224 this.putByte(hi & 0xff); 225 this.putByte((hi >> 8) & 0xff); 226 this.putByte((hi >> 16) & 0xff); 227 this.putByte((hi >> 24) & 0xff); 228 } 229 }, 230 getLong : function(signed) { 231 var value; 232 if (this._byteOrder == jls.lang.ByteBuffer.BIG_ENDIAN) { 233 value = this.getByte() * 0x100000000000000; 234 value |= this.getByte() * 0x1000000000000; 235 value |= this.getByte() * 0x10000000000; 236 value |= this.getByte() * 0x100000000; 237 value |= this.getByte() << 24; 238 value |= this.getByte() << 16; 239 value |= this.getByte() << 8; 240 value |= this.getByte(); 241 } else { 242 value = this.getByte(); 243 value |= this.getByte() << 8; 244 value |= this.getByte() << 16; 245 value |= this.getByte() << 24; 246 value |= this.getByte() * 0x100000000; 247 value |= this.getByte() * 0x10000000000; 248 value |= this.getByte() * 0x1000000000000; 249 value |= this.getByte() * 0x100000000000000; 250 } 251 return (signed && (value >= 0x8000000000000000)) ? value - 0x10000000000000000 : value; 252 }, 253 putPointer : function(value) { 254 switch (jls.lang.ByteBuffer.POINTER_SIZE) { 255 case 4: 256 this.putInt(value); 257 break; 258 case 8: 259 this.putLong(value); 260 break; 261 default: 262 throw new jls.lang.Exception('Unimplemented pointer size (' + jls.lang.ByteBuffer.POINTER_SIZE + ')'); 263 } 264 }, 265 getPointer : function() { 266 switch (jls.lang.ByteBuffer.POINTER_SIZE) { 267 case 4: 268 return this.getInt(false); 269 case 8: 270 return this.getLong(false); 271 default: 272 throw new jls.lang.Exception('Unimplemented pointer size (' + jls.lang.ByteBuffer.POINTER_SIZE + ')'); 273 } 274 } 275 }); 276 277 Object.extend(jls.lang.ByteBuffer, /** @lends jls.lang.ByteBuffer */ 278 { 279 /** 280 * Allocates a new buffer. 281 * 282 * @param {Number} capacity The capacity of the byte array. 283 * @returns {jls.lang.Buffer} The new buffer. 284 */ 285 allocate : function(capacity) { 286 return jls.lang.ByteBuffer.wrap(new _native.core.ByteArray(capacity)); 287 }, 288 /** 289 * Wraps an existing native byte array into a new buffer. 290 * 291 * @param {ByteArray} barray The native byte array to wrap. 292 * @param {Number} offset The offset of the byte array to use for this buffer. 293 * @param {Number} length The length of the buffer. 294 * @returns {jls.lang.Buffer} The new buffer. 295 */ 296 wrap : function(barray, offset, length) { 297 offset = offset || 0; 298 length = length || (barray.size() - offset); 299 return new jls.lang.ByteBuffer(barray, offset, length); 300 }, 301 /** 302 * TODO Remove 303 * @deprecated 304 */ 305 fromString : function(s) { 306 var buffer = jls.lang.ByteBuffer.allocate(s.length * 2); 307 buffer.putString(s); 308 buffer.flip(); 309 return buffer; 310 }, 311 // Byte order constants. 312 /* 313 * The bytes are ordered from most significant to least significant. 314 */ 315 BIG_ENDIAN : 1, 316 /* 317 * The bytes are ordered from least significant to most significant. 318 */ 319 LITTLE_ENDIAN : 2, 320 DEFAULT_BYTE_ORDER : (_native.core.properties['cpu.endian'] == 'big' ? 1 : 2), 321 POINTER_SIZE : parseInt(_native.core.properties['cpu.pointer.size']) 322 }); 323 324