001: /*
002: * $Id: AnyBinary.java,v 1.47 2002/09/16 08:05:02 jkl Exp $
003: *
004: * Copyright (c) 2002 Njet Communications Ltd. All Rights Reserved.
005: *
006: * Use is subject to license terms, as defined in
007: * Anvil Sofware License, Version 1.1. See LICENSE
008: * file, or http://njet.org/license-1.1.txt
009: */
010: package anvil.core;
011:
012: import java.io.Writer;
013: import java.io.IOException;
014: import java.io.OutputStream;
015: import java.io.ByteArrayOutputStream;
016: import java.util.Comparator;
017: import anvil.script.Context;
018: import anvil.java.util.BindingEnumeration;
019: import anvil.util.Conversions;
020:
021: /// @class binary
022: /// Binary is an efficient implemtation of variable length array of bytes.
023:
024: /**
025: * class AnyBinary
026: *
027: * @author: Jani Lehtimäki
028: */
029: public class AnyBinary extends AnySequence {
030:
031: /// @constructor binary
032: /// Creates and returns efficient array of bytes. Indexing of
033: /// binary always starts from zero.
034: /// @synopsis binary binary(range dimension)
035: /// @synopsis binary binary(string data)
036: /// @synopsis binary binary(buffer data)
037: /// @synopsis binary binary(object data, ...)
038: /// @param dimension Length of array as range (e.g. ..100).
039: /// @param data Datas to initialize array with
040: public static final Object[] newInstance = { "element1", "elements" };
041:
042: public static final Any newInstance(Any data, Any[] rest) {
043: if (data.isRange()) {
044: return new AnyBinary(new byte[data.sizeOf()]);
045: } else if (data.isString() || data.isBuffer()) {
046: return new AnyBinary(data.toBinary());
047: } else if (data.isBinary()) {
048: return data.copy();
049: }
050: int length = rest.length;
051: byte[] array = new byte[length + 1];
052: array[0] = (byte) data.toInt();
053: for (int i = 0; i < length; i++) {
054: array[i + 1] = (byte) rest[i].toInt();
055: }
056: return new AnyBinary(array);
057: }
058:
059: protected byte[] _array;
060: protected int _size;
061:
062: public AnyBinary() {
063: _array = new byte[0];
064: _size = 0;
065: }
066:
067: public AnyBinary(byte[] array) {
068: _array = array;
069: _size = array.length;
070: }
071:
072: public boolean isCompatible(Any element) {
073: int t = element.typeOf();
074: return (t == IS_BINARY) || (t == IS_STRING) || (t == IS_BUFFER);
075: }
076:
077: public int getSize() {
078: return _size;
079: }
080:
081: public AnySequence setSize(int size) {
082: _size = size;
083: return this ;
084: }
085:
086: public AnySequence clear() {
087: java.util.Arrays.fill(_array, 0, _size, (byte) 0);
088: _size = 0;
089: return this ;
090: }
091:
092: public void ensureCapacity(int size) {
093: if (_array.length < size) {
094: byte[] array = new byte[size + (size / 8)];
095: System.arraycopy(_array, 0, array, 0, _size);
096: _array = array;
097: }
098: }
099:
100: public Any getElement(int index) {
101: return Any.create(_array[index]);
102: }
103:
104: public AnySequence setElement(int index, Any element) {
105: _array[index] = element.toByte();
106: return this ;
107: }
108:
109: public AnySequence crop(int start, int length) {
110: System.arraycopy(_array, start, _array, 0, length);
111: setSize(length);
112: return this ;
113: }
114:
115: public AnySequence getSlice(int start, int length) {
116: byte[] slice = new byte[length];
117: System.arraycopy(_array, start, slice, 0, length);
118: return new AnyBinary(slice);
119: }
120:
121: public AnySequence deleteSlice(int start, int length) {
122: byte[] array = _array;
123: int size = _size;
124: if (start + length < size) {
125: System.arraycopy(array, start + length, array, start, size
126: - (start + length));
127: }
128: setSize(size - length);
129: return this ;
130: }
131:
132: public AnySequence setSlice(int start, int length, Any element) {
133: int size = _size;
134: ensureCapacity(size - length + 1);
135: byte[] array = _array;
136: if (start + length < size) {
137: System.arraycopy(array, start + length, array, start + 1,
138: size - (start + length));
139: }
140: array[start] = element.toByte();
141: setSize(size + 1 - length);
142: return this ;
143: }
144:
145: public AnySequence setSlice(int start, int length,
146: AnySequence sequence) {
147: byte[] seq = sequence.toBinary();
148: int seq_length = sequence.getSize();
149: int size = _size;
150: ensureCapacity(size - length + seq_length);
151: byte[] array = _array;
152: if (start + length < size) {
153: System.arraycopy(array, start + length, array, start
154: + seq_length, size - (start + length));
155: }
156: System.arraycopy(seq, 0, array, start, seq_length);
157: setSize(size + seq_length - length);
158: return this ;
159: }
160:
161: public AnySequence append(AnySequence sequence) {
162: byte[] seq = sequence.toBinary();
163: int seq_length = sequence.getSize();
164: int size = _size;
165: ensureCapacity(size + seq_length);
166: byte[] array = _array;
167: System.arraycopy(seq, 0, array, size, seq_length);
168: setSize(size + seq_length);
169: return this ;
170: }
171:
172: public AnySequence append(Any element) {
173: int size = _size;
174: ensureCapacity(size + 1);
175: _array[size] = element.toByte();
176: setSize(size + 1);
177: return this ;
178: }
179:
180: public AnySequence createSequence(Any element) {
181: return new AnyBinary(new byte[] { element.toByte() });
182: }
183:
184: public AnySequence createEmptySequence() {
185: return new AnyBinary(new byte[0]);
186: }
187:
188: public int compareAt(AnySequence sequence, int start, int length) {
189: byte[] haystack = _array;
190: byte[] needle = sequence.toBinary();
191: int delta;
192: for (int i = 0; i < length; i++) {
193: delta = haystack[start + i] - needle[i];
194: if (delta != 0) {
195: return (delta < 0) ? -1 : ((delta > 0) ? 1 : 0);
196: }
197: }
198: return 0;
199: }
200:
201: public int compareAt(Any element, int start) {
202: int delta = _array[start] - element.toByte();
203: return (delta < 0) ? -1 : ((delta > 0) ? 1 : 0);
204: }
205:
206: public AnySequence fill(Any fill, int start, int length) {
207: java.util.Arrays.fill(_array, start, start + length, fill
208: .toByte());
209: return this ;
210: }
211:
212: public AnySequence sort(int start, int length, Comparator comparator) {
213: java.util.Arrays.sort(_array, start, start + length);
214: return this ;
215: }
216:
217: public int search(Any element, Comparator comparator) {
218: return java.util.Arrays.binarySearch(_array, element.toByte());
219: }
220:
221: public AnySequence swap(int index1, int index2) {
222: byte[] array = _array;
223: byte any = array[index1];
224: array[index1] = array[index2];
225: array[index2] = any;
226: return this ;
227: }
228:
229: public final anvil.script.ClassType classOf() {
230: return __class__;
231: }
232:
233: public int typeOf() {
234: return IS_BINARY;
235: }
236:
237: public boolean isBinary() {
238: return true;
239: }
240:
241: public byte[] toBinary() {
242: return _array;
243: }
244:
245: public byte[] toByteArray() {
246: if (_size < _array.length) {
247: byte[] array = new byte[_size];
248: System.arraycopy(_array, 0, array, 0, _size);
249: return array;
250: } else {
251: return _array;
252: }
253: }
254:
255: public Object toObject() {
256: return _array;
257: }
258:
259: public String toString() {
260: return new String(_array);
261: }
262:
263: public Writer toAnvil(Writer writer) throws IOException {
264: byte[] array = _array;
265: final int n = _size;
266: writer.write("new anvil.lang.binary(");
267: for (int i = 0; i < n; i++) {
268: if (i > 0) {
269: writer.write(',');
270: writer.write(' ');
271: }
272: writer.write(Integer.toString(array[i]));
273: }
274: writer.write(')');
275: return writer;
276: }
277:
278: public Writer toJava(Writer writer) throws IOException {
279: byte[] array = _array;
280: final int n = _size;
281: writer.write("new anvil.core.AnyBinary(new byte[]{");
282: for (int i = 0; i < n; i++) {
283: if (i > 0) {
284: writer.write(',');
285: writer.write(' ');
286: }
287: writer.write(Integer.toString(array[i]));
288: }
289: writer.write('}');
290: writer.write(')');
291: return writer;
292: }
293:
294: public anvil.codec.Code toCode(anvil.codec.Code code) {
295: anvil.codec.ConstantPool pool = code.getPool();
296: int clazz = pool.addClass("anvil/core/AnyBinary");
297: code.anew(clazz);
298: code.dup();
299: byte[] array = _array;
300: final int n = _size;
301: code.iconst(n);
302: code.newarray(code.T_BYTE);
303: for (int i = 0; i < n; i++) {
304: code.dup();
305: code.iconst(i);
306: code.iconst(array[i]);
307: code.bastore();
308: }
309: code.invokespecial(pool.addMethodRef(clazz, "<init>", "([B)V"));
310: return code;
311: }
312:
313: public int hashCode() {
314: byte[] array = _array;
315: int n = _size;
316: int h = 0;
317: for (int i = 0; i < n; i++) {
318: h += (i + 1) * array[i];
319: }
320: return h;
321: }
322:
323: public boolean equals(Object obj) {
324: if (this == obj) {
325: return true;
326: }
327: if (obj instanceof AnyBinary) {
328: byte[] a = _array;
329: int length = a.length;
330: byte[] b = ((AnyBinary) obj)._array;
331: if (length == b.length) {
332: for (int i = 0; i < length; i++) {
333: if (a[i] != b[i]) {
334: return false;
335: }
336: }
337: return true;
338: }
339: }
340: return false;
341: }
342:
343: protected int compare(Any other) {
344: return new String(_array).compareTo(other.toString());
345: }
346:
347: public Object clone() {
348: return copy();
349: }
350:
351: public Any copy() {
352: int length = _size;
353: byte[] array = new byte[length];
354: System.arraycopy(_array, 0, array, 0, length);
355: return new AnyBinary(array);
356: }
357:
358: public synchronized void serialize(Serializer serializer)
359: throws IOException {
360: if (serializer.register(this )) {
361: return;
362: }
363: serializer.write('b');
364: int n = _size;
365: serializer.write(n);
366: serializer.write(':');
367: serializer.write(_array);
368: }
369:
370: public static final AnyBinary unserialize(Unserializer unserializer)
371: throws UnserializationException {
372: int arrayLength = (int) unserializer.getLong();
373: if (arrayLength < 0 || arrayLength >= unserializer._data.length) {
374: throw new UnserializationException();
375: }
376:
377: byte[] data = unserializer._data;
378: int length = data.length;
379: int pos = unserializer._pos;
380: if ((pos + arrayLength) > length) {
381: throw new UnserializationException();
382: }
383: int begin = pos;
384: pos += arrayLength;
385: unserializer._pos = pos;
386: byte[] array = new byte[arrayLength];
387: if (arrayLength > 0) {
388: System.arraycopy(data, begin, array, 0, arrayLength);
389: }
390: AnyBinary binary = new AnyBinary(array);
391: unserializer.register(binary);
392: return binary;
393: }
394:
395: /// @method unserialize
396: /// Unserializes the serialized data contained in this binary.
397: /// @synopsis object unserialize()
398: /// @throws CorruptedSerialization If serialization is corrupted
399: public Any m_unserialize(Context context) {
400: try {
401: return Serialization.unserialize(context, _array, 0, _size);
402: } catch (UnserializationException e) {
403: throw context.CorruptedSerialization();
404: }
405:
406: }
407:
408: /// @method toHex
409: /// Converts contents of this binary to hexadecimal representation.
410: /// @synopsis string toHex()
411: public Any m_toHex() {
412: return Any.create(anvil.util.Conversions.toHex(_array));
413: }
414:
415: /// @method toInt
416: /// Converts the contents of binary at given offset to integer
417: /// of given byte width. If width is negative the byteorder
418: /// is reversed. Maximum width is eight (8).
419: /// If offset is omitted zero (0) is used instead.
420: /// @synopsis int toInt(width)
421: /// @synopsis int toInt(width, offset)
422: public static final Object[] p_toInt = { null, "width", "*offset",
423: null };
424:
425: public Any m_toInt(Context context, int width, Any offset) {
426: if (width == 0) {
427: return ZERO;
428: }
429: if (width < -8 || width > 8) {
430: throw context.BadParameter("Invalid width: " + width);
431: }
432:
433: byte[] array = _array;
434: int size = _size;
435: int pos = (offset != null) ? offset.toInt() : 0;
436:
437: long r = 0;
438: if (width > 0) {
439: if (pos < 0 || pos >= size) {
440: throw context.BadParameter("Invalid offset: " + pos);
441: }
442: for (int i = 0; i < width && pos < size; i++) {
443: r <<= 8;
444: r |= array[pos++] & 0xff;
445: }
446: } else {
447: width = -width;
448: pos += width - 1;
449: if (pos < 0 || pos >= size) {
450: throw context.BadParameter("Invalid offset: " + pos);
451: }
452: for (int i = 0; i < width && pos >= 0; i++) {
453: r <<= 8;
454: r |= array[pos--] & 0xff;
455: }
456: }
457: return Any.create(r);
458: }
459:
460: transient public static final anvil.script.compiler.NativeClass __class__ = new anvil.script.compiler.NativeClass(
461: "binary", AnyBinary.class,
462: AnySequence.__class__,
463: //DOC{{
464: ""
465: + " @class binary\n"
466: + " Binary is an efficient implemtation of variable length array of bytes.\n"
467: + " @constructor binary\n"
468: + " Creates and returns efficient array of bytes. Indexing of\n"
469: + " binary always starts from zero.\n"
470: + " @synopsis binary binary(range dimension)\n"
471: + " @synopsis binary binary(string data)\n"
472: + " @synopsis binary binary(buffer data)\n"
473: + " @synopsis binary binary(object data, ...)\n"
474: + " @param dimension Length of array as range (e.g. ..100). \n"
475: + " @param data Datas to initialize array with\n"
476: + " @method unserialize\n"
477: + " Unserializes the serialized data contained in this binary.\n"
478: + " @synopsis object unserialize()\n"
479: + " @throws CorruptedSerialization If serialization is corrupted\n"
480: + " @method toHex\n"
481: + " Converts contents of this binary to hexadecimal representation.\n"
482: + " @synopsis string toHex()\n"
483: + " @method toInt\n"
484: + " Converts the contents of binary at given offset to integer\n"
485: + " of given byte width. If width is negative the byteorder\n"
486: + " is reversed. Maximum width is eight (8).\n"
487: + " If offset is omitted zero (0) is used instead.\n"
488: + " @synopsis int toInt(width)\n"
489: + " @synopsis int toInt(width, offset)\n"
490: //}}DOC
491: );
492:
493: }
|