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 //jls.logger.info('ByteBuffer.putBuffer(' + length + ')'); 108 if (this.remaining() < length) { 109 throw new jls.lang.BufferOverflowException(); 110 } 111 this._barray.memcpy(this.offset(), buffer.byteArray(), buffer.position(), length); 112 this._position += length; 113 buffer.incrementPosition(length); 114 return this; 115 }, 116 putByteArray : function(ba) { 117 if (this.remaining() < ba.length) { 118 throw new jls.lang.BufferOverflowException(); 119 } 120 for (var i = 0; i < ba.length; i++) { 121 this._barray.put(this.offset() + i, ba[i]); 122 } 123 this._position += ba.length; 124 return this; 125 }, 126 getByteArray : function(length) { 127 if (length) { 128 if (this.remaining() < length) { 129 throw new jls.lang.BufferUnderflowException(); 130 } 131 } else { 132 length = this.remaining(); 133 } 134 var ba = []; 135 for (var i = 0; i < length; i++) { 136 ba.push(this._barray.get(this.offset() + i)); 137 } 138 this._position += length; 139 return ba; 140 }, 141 getByteOrder : function() { 142 return this._byteOrder; 143 }, 144 setByteOrder : function(byteOrder) { 145 this._byteOrder = byteOrder; 146 }, 147 putShort : function(value) { 148 if (this._byteOrder == jls.lang.ByteBuffer.BIG_ENDIAN) { 149 this.putByte((value >> 8) & 0xff); 150 this.putByte(value & 0xff); 151 } else { 152 this.putByte(value & 0xff); 153 this.putByte((value >> 8) & 0xff); 154 } 155 }, 156 getShort : function(signed) { 157 var value; 158 if (this._byteOrder == jls.lang.ByteBuffer.BIG_ENDIAN) { 159 value = this.getByte() << 8; 160 value |= this.getByte(); 161 } else { 162 value = this.getByte(); 163 value |= this.getByte() << 8; 164 } 165 return (signed && (value >= 0x8000)) ? value - 0x10000 : value; 166 }, 167 putInt : function(value) { 168 if (this._byteOrder == jls.lang.ByteBuffer.BIG_ENDIAN) { 169 this.putByte((value >> 24) & 0xff); 170 this.putByte((value >> 16) & 0xff); 171 this.putByte((value >> 8) & 0xff); 172 this.putByte(value & 0xff); 173 } else { 174 this.putByte(value & 0xff); 175 this.putByte((value >> 8) & 0xff); 176 this.putByte((value >> 16) & 0xff); 177 this.putByte((value >> 24) & 0xff); 178 } 179 }, 180 getInt : function(signed) { 181 var value; 182 if (this._byteOrder == jls.lang.ByteBuffer.BIG_ENDIAN) { 183 value = this.getByte() << 24; 184 value |= this.getByte() << 16; 185 value |= this.getByte() << 8; 186 value |= this.getByte(); 187 } else { 188 value = this.getByte(); 189 value |= this.getByte() << 8; 190 value |= this.getByte() << 16; 191 value |= this.getByte() << 24; 192 } 193 return (signed && (value >= 0x80000000)) ? value - 0x100000000 : value; 194 }, 195 /* 196 * Bitwise operators treat their operands as a set of 32 bits (zeros and ones), rather than as decimal, 197 * hexadecimal, or octal numbers. For example, the decimal number nine has a binary representation of 1001. 198 * Bitwise operators perform their operations on such binary representations, but they return standard JavaScript numerical values. 199 */ 200 putLong : function(value) { 201 // var hi = (value - (value % 0x100000000)) / 0x100000000; 202 var hi = value / 0x100000000; 203 if (value >= 0) { 204 hi = Math.floor(hi); 205 } else { 206 hi = Math.ceil(hi); 207 if (hi == 0) { 208 hi = -1; // -0 ! 209 } 210 } 211 if (this._byteOrder == jls.lang.ByteBuffer.BIG_ENDIAN) { 212 this.putByte((hi >> 24) & 0xff); 213 this.putByte((hi >> 16) & 0xff); 214 this.putByte((hi >> 8) & 0xff); 215 this.putByte(hi & 0xff); 216 this.putByte((value >> 24) & 0xff); 217 this.putByte((value >> 16) & 0xff); 218 this.putByte((value >> 8) & 0xff); 219 this.putByte(value & 0xff); 220 } else { 221 this.putByte(value & 0xff); 222 this.putByte((value >> 8) & 0xff); 223 this.putByte((value >> 16) & 0xff); 224 this.putByte((value >> 24) & 0xff); 225 this.putByte(hi & 0xff); 226 this.putByte((hi >> 8) & 0xff); 227 this.putByte((hi >> 16) & 0xff); 228 this.putByte((hi >> 24) & 0xff); 229 } 230 }, 231 getLong : function(signed) { 232 var value; 233 if (this._byteOrder == jls.lang.ByteBuffer.BIG_ENDIAN) { 234 value = this.getByte() * 0x100000000000000; 235 value |= this.getByte() * 0x1000000000000; 236 value |= this.getByte() * 0x10000000000; 237 value |= this.getByte() * 0x100000000; 238 value |= this.getByte() << 24; 239 value |= this.getByte() << 16; 240 value |= this.getByte() << 8; 241 value |= this.getByte(); 242 } else { 243 value = this.getByte(); 244 value |= this.getByte() << 8; 245 value |= this.getByte() << 16; 246 value |= this.getByte() << 24; 247 value |= this.getByte() * 0x100000000; 248 value |= this.getByte() * 0x10000000000; 249 value |= this.getByte() * 0x1000000000000; 250 value |= this.getByte() * 0x100000000000000; 251 } 252 return (signed && (value >= 0x8000000000000000)) ? value - 0x10000000000000000 : value; 253 }, 254 putPointer : function(value) { 255 switch (jls.lang.ByteBuffer.POINTER_SIZE) { 256 case 4: 257 this.putInt(value); 258 break; 259 case 8: 260 this.putLong(value); 261 break; 262 default: 263 throw new jls.lang.Exception('Unimplemented pointer size (' + jls.lang.ByteBuffer.POINTER_SIZE + ')'); 264 } 265 }, 266 getPointer : function() { 267 switch (jls.lang.ByteBuffer.POINTER_SIZE) { 268 case 4: 269 return this.getInt(false); 270 case 8: 271 return this.getLong(false); 272 default: 273 throw new jls.lang.Exception('Unimplemented pointer size (' + jls.lang.ByteBuffer.POINTER_SIZE + ')'); 274 } 275 } 276 }); 277 278 Object.extend(jls.lang.ByteBuffer, /** @lends jls.lang.ByteBuffer */ 279 { 280 /** 281 * Allocates a new buffer. 282 * 283 * @param {Number} capacity The capacity of the byte array. 284 * @returns {jls.lang.Buffer} The new buffer. 285 */ 286 allocate : function(capacity) { 287 return jls.lang.ByteBuffer.wrap(new _native.core.ByteArray(capacity)); 288 }, 289 /** 290 * Wraps an existing native byte array into a new buffer. 291 * 292 * @param {ByteArray} barray The native byte array to wrap. 293 * @param {Number} offset The offset of the byte array to use for this buffer. 294 * @param {Number} length The length of the buffer. 295 * @returns {jls.lang.Buffer} The new buffer. 296 */ 297 wrap : function(barray, offset, length) { 298 offset = offset || 0; 299 length = length || (barray.size() - offset); 300 return new jls.lang.ByteBuffer(barray, offset, length); 301 }, 302 /** 303 * TODO Remove 304 * @deprecated 305 */ 306 fromString : function(s, csn) { 307 var buffer = jls.lang.ByteBuffer.allocate(s.length * 2); 308 buffer.putString(s, csn); 309 buffer.flip(); 310 return buffer; 311 }, 312 // Byte order constants. 313 /* 314 * The bytes are ordered from most significant to least significant. 315 */ 316 BIG_ENDIAN : 1, 317 /* 318 * The bytes are ordered from least significant to most significant. 319 */ 320 LITTLE_ENDIAN : 2, 321 DEFAULT_BYTE_ORDER : (_native.core.properties['cpu.endian'] == 'big' ? 1 : 2), 322 POINTER_SIZE : parseInt(_native.core.properties['cpu.pointer.size']) 323 }); 324 325