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