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