0001: // Copyright (c) 2001 Per M.A. Bothner and Brainfood Inc.
0002: // This is free software; for terms and warranty disclaimer see ./COPYING.
0003:
0004: package gnu.lists;
0005:
0006: /** A compact representation of a tree, that is a nested list structure.
0007: * The data structure can store anything that can be emitted to a Consumer.
0008: * This data structure is optimized for efficient forwards traversal
0009: * through the data structure, not random access.
0010: * It does have an "insertion point"; insertions and deletions are
0011: * efficient through the use of a buffer gap.
0012: * It is a reasonable choice for a "DOM" for XML data.
0013: */
0014:
0015: public class TreeList extends AbstractSequence implements Consumer,
0016: PositionConsumer, Consumable {
0017: // Some public fields and methods are public which probably shouldn't be,
0018: // for the sake of NamespaceResolver. FIXME. Perhaps an abstract class
0019: // in gnu.lists that NamespaceResolver could extend?
0020:
0021: public Object[] objects;
0022: static final Object availObject = new String("(AVAIL");
0023: public char[] data;
0024: public int gapStart;
0025: public int gapEnd;
0026:
0027: /** If non-zero, gap is in an attribute starting (1 less than) here. */
0028: public int attrStart;
0029:
0030: public TreeList() {
0031: resizeObjects();
0032: gapEnd = 200;
0033: data = new char[gapEnd];
0034: }
0035:
0036: /**
0037: * Make a copy of a sub-range of a TreeList.
0038: * @param list the TreeList to copy
0039: * @param startPosition start of range, as a raw index in data
0040: * @param endPosition end of range, as a raw index in data
0041: */
0042: public TreeList(TreeList list, int startPosition, int endPosition) {
0043: this ();
0044: list.consumeRange(startPosition, endPosition, this );
0045: }
0046:
0047: public TreeList(TreeList list) {
0048: this (list, 0, list.data.length);
0049: }
0050:
0051: public void clear() {
0052: gapStart = 0;
0053: gapEnd = data.length;
0054: attrStart = 0;
0055: if (gapEnd > 1500) {
0056: gapEnd = 200;
0057: data = new char[gapEnd];
0058: }
0059: objects = null;
0060: resizeObjects();
0061: }
0062:
0063: // The data array contains an encoding of values, as follows:
0064: // 0x0000 ... 0x9FFF: A single Unicode character.
0065: // 0xAXXX: BEGIN_GROUP_SHORT
0066: // 0xBXXX: negative integer ((short)0x0XXX<<4)>>4, range -4096 to -1
0067: // 0xCXXX: positive integer 0x0XXX, in the range 0 to 4095
0068: // 0xDXXX: positive integer 0x1XXX, in the range 4096 to 8191
0069: // 0xEXXX:: OBJECT_REF_SHORT. The object in objects[0xXXX].
0070: // 0xF0XX: A byte (encoded character or char fragment) ((byte) 0xXX).
0071: // 0xF100 ... 0xF101: A Boolean (BOOL_FALSE, BOOL_TRUE)
0072: // 0xF102 A B: INT_FOLLOWS - 32-bit int (big-endian)
0073: // 0xF103 A B C D: LONG_FOLLOWS 64-bit long int (big-endian)
0074: // 0xF104 A B: FLOAT_FOLLOWS 32-bit float (big-endian)
0075: // 0xF105 A B C D: DOUBLE_FOLLOWS 64-bit double (big-endian)
0076: // 0xF106: CHAR_FOLLOWS
0077: // 0xF107: CHAR_PAIR_FOLLOWS
0078: // 0xF108: BEGIN_GROUP_LONG
0079: // 0xF109: BEGIN_ATTRIBUTE_LONG
0080: // 0xF10A: END_ATTRIBUTE
0081: // 0xF10B: END_GROUP_SHORT
0082: // 0xF10C: END_GROUP_LONG
0083: // 0xF10D A B: OBJECT_REF_FOLLOWS: The object in objects[(A,B)].
0084: // 0xF10E A B: POSITION_REF_FOLLOWS: The TreePosition in objects[(A,B)].
0085: // 0xF10F A B C D E F: POSITION_TRIPLE_FOLLOWS
0086: // 0xF110 BEGIN_DOCUMENT
0087:
0088: /** The largest Unicode character that can be encoded in one char. */
0089: static final int MAX_CHAR_SHORT = 0x9FFF;
0090:
0091: /** The smallest integer that can use the short int encoding. */
0092: static final int MIN_INT_SHORT = -0x1000; // -4096
0093:
0094: /** The largest integer that can use the short int encoding. */
0095: static final int MAX_INT_SHORT = 0x1FFF; // 8191
0096:
0097: /** The value used to encode the integer zero. */
0098: static final int INT_SHORT_ZERO = 0xC000;
0099:
0100: /** The value used to encode the object in objects[0]. */
0101: static final int OBJECT_REF_SHORT = 0xE000;
0102:
0103: /** The maximum offset in the objects array for a short object-ref. */
0104: static final int OBJECT_REF_SHORT_INDEX_MAX = 0xFFF;
0105:
0106: /** Followed by 2 chars that provide an index into objects. */
0107: static final char OBJECT_REF_FOLLOWS = 0xF10D;
0108:
0109: /** Followed by 2 chars that provide an index into objects. */
0110: static final char POSITION_REF_FOLLOWS = 0xF10E;
0111:
0112: /** A position triple referenceing some other "nodes".
0113: * Followed by index of squence (2 chars), ipos (2 chars), and
0114: * index of xpos or -1 if xpos==null (2 chars). */
0115: static final char POSITION_TRIPLE_FOLLOWS = 0xF10F;
0116:
0117: /** Encoding prefix that indicates a byte value. */
0118: static final int BYTE_PREFIX = 0xF000;
0119:
0120: /** The value used to encode false. */
0121: static final char BOOL_FALSE = 0xF100;
0122:
0123: /** The value used to encode true. */
0124: static final char BOOL_TRUE = 0xF101;
0125:
0126: /** A 32-bit integer, non-compact form.
0127: *
0128: * [INT_FOLLOWS]
0129: * [word1], [word2]: The big-endian bits of the integer.
0130: */
0131: static final int INT_FOLLOWS = 0xF102;
0132:
0133: /** A 64-bit long integer.
0134: *
0135: * [LONG_FOLLOWS]
0136: * [word1], [word2], [word3], [word4]: The big-endian bits of the long.
0137: */
0138: static final int LONG_FOLLOWS = 0xF103;
0139:
0140: /** A 64-bit float floating-pointer number.
0141: *
0142: * [FLOAT_FOLLOWS]
0143: * [word1], [word2]: The big-endian bits of the float.
0144: */
0145: static final int FLOAT_FOLLOWS = 0xF104;
0146:
0147: /** A 64-bit double floating-pointer number.
0148: *
0149: * [DOUBLE_FOLLOWS]
0150: * [word1], [word2], [word3], [word4]: The big-endian bits of the double.
0151: */
0152: static final int DOUBLE_FOLLOWS = 0xF105;
0153:
0154: /** A 16-bit (non-compact) Unicode char follows. */
0155: static final int CHAR_FOLLOWS = 0xF106;
0156:
0157: /** A surrogate pair follows. (not implemented). */
0158: static final int CHAR_PAIR_FOLLOWS = CHAR_FOLLOWS + 1;
0159:
0160: /** The beginning of an attribute.
0161: * [BEGIN_ATTRIBUTE_LONG]
0162: * [index], 2 shorts, where objects[index] is the attribute type name
0163: * and objects[index+1] is the attribute type object.
0164: * [end_offset], 2 shorts, giving the location of the following
0165: * END_ATTRIBUTE. If the attribute straddles the gap, then
0166: * end_offset is a negative offset relative to data.length.
0167: * (Therefore allocating more space for the gap does not require
0168: * adjusting end_offset.) Otherwise, the end_offset is relative
0169: * to the BEGIN_ATTRIBUTE_LONG word.
0170: */
0171: static final int BEGIN_ATTRIBUTE_LONG = 0xF109;
0172:
0173: /** The end of an attribute of a node. */
0174: static final int END_ATTRIBUTE = 0xF10A;
0175:
0176: /** Beginning of a document.
0177: * No parameters. Used to distinguish a document from its element node.
0178: */
0179: static final int BEGIN_DOCUMENT = 0xF110;
0180:
0181: /** Beginning of a group, compact form.
0182: *
0183: * [BEGIN_GROUP_SHORT + index], where objects[index] is the group's
0184: * type name and objects[index+1] is the type object.
0185: * [end_offset], the unsigned offset (from the initial word)
0186: * to the corresponding END_GROUP_SHORT.
0187: * [parent_offset], the (unsigned absolute value of the) offset
0188: * to the outer BEGIN_GROUP_SHORT/BEGIN_GROUP_LONG. (If this is the
0189: * outermost group, then parent_offset==0.)
0190: *
0191: * This should is used when index < BEGIN_GROUP_SHORT_INDEX_MAX,
0192: * both end_offset and parent_offset fit in 16 bits,
0193: * and the group does not straddle the gap.
0194: */
0195: static final int BEGIN_GROUP_SHORT = 0xA000;
0196: static final int BEGIN_GROUP_SHORT_INDEX_MAX = 0xFFF;
0197:
0198: /** End of a group, compact form.
0199: *
0200: * [END_GROUP_SHORT]
0201: * [begin_offset], the unsigned absolute value of the offset to the
0202: * matching BEGIN. (This is the same as the matching end_offset.)
0203: *
0204: */
0205: static final int END_GROUP_SHORT = 0xF10B;
0206:
0207: /** Begin of a group, non-compact form.
0208: *
0209: * [BEGIN_GROUP_LONG]
0210: * [end_offset], in 2 shorts. The position of the matching END_GROUP_LONG.
0211: * If the group straddles the gap, then end_offset is a negative offset
0212: * relative to data.length. (Therefore allocating more space for the
0213: * gap does not require adjusting any end_offset.) If the group and
0214: * and its children are all on the same side of the gap, then end_offset
0215: * is a positive offset relative to the BEGIN_GROUP_LONG word. (Hence
0216: * shifting an entire group when the gap is moved does not require
0217: * changing its end_offset.)
0218: *
0219: * Note that the space taken by a BEGIN_GROUP_LONG is the same that
0220: * needed for a BEGIN_GROUP_SHORT (but a END_GROUP_LONG takes much
0221: * more space than a END_GROUP_SHORT). This is to make it easier
0222: * to convert a BEGIN_GROUP_LONG to a BEGIN_GROUP_SHORT or vice
0223: * versa, as needed.
0224: */
0225: static final int BEGIN_GROUP_LONG = 0xF108;
0226:
0227: /** End of a group, non-compact form.
0228: *
0229: * [END_GROUP_LONG]
0230: * [index], 2 shorts where objects[index] is the group's type name and
0231: * objects[index+1] is the type object.
0232: * [begin_offset], in 2 shorts. The position of the matching
0233: * BEGIN_GROUP_LONG. If the group straddles the gap, then begin_offset
0234: * is the actual index (i.e. relative to the start of data) of the
0235: * matching BEGIN_GROUP_LONG. (Therefore allocating more space for the
0236: * gap does not require adjusting begin_offset.) If the group does not
0237: * straddle the gap, then begin_offset is a negative offset relative
0238: * to the END_GROUP_LONG word. (Hence shifting an entire group when
0239: * the gap is moved does not require changing its begin_offset.)
0240: * relative to data.length.
0241: * [parent_offset], in 2 shorts. The position of the outer BEGIN_GROUP_LONG
0242: * or BEGIN_GROUP_SHORT. If the difference straddles the gap (i.e.
0243: * either this group straddles the gap or the parent group does and the
0244: * gap precedes this group), then parent_offset is the actual index
0245: * of the parent group. Otherwise, then parent_offset is a negative
0246: * offset relative to the END_GROUP_LONG word.
0247: */
0248: static final int END_GROUP_LONG = 0xF10C;
0249:
0250: int currentBeginGroup = 0;
0251:
0252: public void ensureSpace(int needed) {
0253: int avail = gapEnd - gapStart;
0254: if (needed > avail) {
0255: int oldSize = data.length;
0256: int neededSize = oldSize - avail + needed;
0257: int newSize = 2 * oldSize;
0258: if (newSize < neededSize)
0259: newSize = neededSize;
0260: char[] tmp = new char[newSize];
0261: if (gapStart > 0)
0262: System.arraycopy(data, 0, tmp, 0, gapStart);
0263: int afterGap = oldSize - gapEnd;
0264: if (afterGap > 0)
0265: System.arraycopy(data, gapEnd, tmp, newSize - afterGap,
0266: afterGap);
0267: gapEnd = newSize - afterGap;
0268: data = tmp;
0269: }
0270: }
0271:
0272: public final void resizeObjects() {
0273: int oldLength;
0274: int newLength;
0275: Object[] tmp;
0276: if (objects == null) {
0277: oldLength = 0;
0278: newLength = 100;
0279: tmp = new Object[newLength];
0280: } else {
0281: oldLength = objects.length;
0282: newLength = 2 * oldLength;
0283: tmp = new Object[newLength];
0284: System.arraycopy(objects, 0, tmp, 0, oldLength);
0285: }
0286: Object availObject = this .availObject;
0287: for (int i = oldLength; i < newLength; i++)
0288: tmp[i] = availObject;
0289: objects = tmp;
0290: }
0291:
0292: protected int find(Object arg1) {
0293: // FIXME - linear search!
0294: int i = 0;
0295: int len = objects.length;
0296: Object availObject = this .availObject;
0297: int avail = -1;
0298: for (; i < len; i++) {
0299: Object obj = objects[i];
0300: if (obj == arg1)
0301: return i;
0302: if (obj == availObject && avail < 0)
0303: avail = i;
0304: }
0305: if (avail >= 0) {
0306: objects[avail] = arg1;
0307: return avail;
0308: }
0309: resizeObjects();
0310: objects[len] = arg1;
0311: return len;
0312: }
0313:
0314: protected int find(Object arg1, Object arg2) {
0315: // FIXME - linear search!
0316: int i = 0;
0317: int len = objects.length;
0318: Object availObject = this .availObject; // Optimization.
0319: int avail = -1;
0320: Object[] objects = this .objects; // Optimization.
0321: for (; i + 1 < len; i++) {
0322: Object obj1 = objects[i];
0323: if (obj1 == arg1 && objects[i + 1] == arg2)
0324: return i;
0325: if (avail < 0 && obj1 == availObject
0326: && objects[i + 1] == availObject)
0327: avail = i;
0328: }
0329: if (avail >= 0) {
0330: objects[avail] = arg1;
0331: objects[avail + 1] = arg2;
0332: return avail;
0333: }
0334: resizeObjects();
0335: objects = this .objects;
0336: objects[len] = arg1;
0337: objects[len + 1] = arg2;
0338: return len;
0339: }
0340:
0341: /** Get a 32-bit int from the data array. */
0342: final protected int getIntN(int index) {
0343: return (data[index] << 16) | (data[index + 1]);
0344: }
0345:
0346: /** Get a 64-bit long from the data array. */
0347: final protected long getLongN(int index) {
0348: char[] data = this .data; // Optimization.
0349: return ((data[index] << 48) | (data[index + 1] << 32)
0350: | (data[index + 2] << 16) | data[index + 3]);
0351: }
0352:
0353: final public void setIntN(int index, int i) {
0354: data[index] = (char) (i >> 16);
0355: data[index + 1] = (char) i;
0356: }
0357:
0358: public boolean consume(TreePosition position) {
0359: ensureSpace(3);
0360: // FIXME - no need for find to search in this case!
0361: int index = find(new TreePosition(position));
0362: data[gapStart++] = POSITION_REF_FOLLOWS;
0363: setIntN(gapStart, index);
0364: gapStart += 2;
0365: return true;
0366: }
0367:
0368: public boolean writePosition(AbstractSequence seq, int ipos,
0369: Object xpos) {
0370: ensureSpace(7);
0371: data[gapStart] = POSITION_TRIPLE_FOLLOWS;
0372: int seq_index = find(seq);
0373: int xpos_index = xpos == null ? -1 : find(xpos);
0374: setIntN(gapStart + 1, seq_index);
0375: setIntN(gapStart + 3, ipos);
0376: setIntN(gapStart + 5, xpos_index);
0377: gapStart += 7;
0378: return true;
0379: }
0380:
0381: public void writeObject(Object v) {
0382: if (v instanceof SeqPosition) {
0383: // A SeqPosition is used as a temporary cursor (see NodeType),
0384: // so we need to save the current position.
0385: SeqPosition pos = (SeqPosition) v;
0386: writePosition(pos.sequence, pos.ipos, pos.xpos);
0387: return;
0388: }
0389: ensureSpace(3);
0390: int index = find(v);
0391: if (index < 0x1000)
0392: data[gapStart++] = (char) (OBJECT_REF_SHORT | index);
0393: else {
0394: data[gapStart++] = OBJECT_REF_FOLLOWS;
0395: setIntN(gapStart, index);
0396: gapStart += 2;
0397: }
0398: }
0399:
0400: public void beginGroup(String typeName, Object type) {
0401: beginGroup(find(typeName, type));
0402: }
0403:
0404: public void beginDocument() {
0405: ensureSpace(1);
0406: data[gapStart++] = BEGIN_DOCUMENT;
0407: }
0408:
0409: public void endDocument() {
0410: }
0411:
0412: public void beginGroup(int index) {
0413: ensureSpace(3 + 7);
0414: gapEnd -= 7;
0415: data[gapStart++] = BEGIN_GROUP_LONG;
0416: setIntN(gapStart, gapEnd - data.length); // end_offset
0417: gapStart += 2;
0418: data[gapEnd] = END_GROUP_LONG;
0419: setIntN(gapEnd + 1, index); // begin_offset
0420: setIntN(gapEnd + 3, gapStart - 3); // begin_offset
0421: setIntN(gapEnd + 5, currentBeginGroup); // parent_offset
0422: currentBeginGroup = gapStart - 3;
0423: }
0424:
0425: public void endGroup(String typeName) {
0426: if (data[gapEnd] != END_GROUP_LONG)
0427: throw new Error("unexpected endGroup " + typeName);
0428: int index = getIntN(gapEnd + 1);
0429: int begin = getIntN(gapEnd + 3);
0430: int parent = getIntN(gapEnd + 5);
0431: gapEnd += 7;
0432: int offset = gapStart - begin;
0433: int parentOffset = begin - parent;
0434: if (index < BEGIN_GROUP_SHORT_INDEX_MAX && offset < 0x10000
0435: && parentOffset < 0x10000) {
0436: data[begin] = (char) (BEGIN_GROUP_SHORT | index);
0437: data[begin + 1] = (char) offset; // end_offset
0438: data[begin + 2] = (char) parentOffset;
0439: data[gapStart] = END_GROUP_SHORT;
0440: data[gapStart + 1] = (char) offset; // begin_offset
0441: gapStart += 2;
0442: } else {
0443: data[begin] = BEGIN_GROUP_LONG;
0444: setIntN(begin + 1, offset);
0445: data[gapStart] = END_GROUP_LONG;
0446: setIntN(gapStart + 1, index);
0447: setIntN(gapStart + 3, -offset);
0448: if (parent >= gapStart || begin <= gapStart)
0449: parent -= gapStart;
0450: setIntN(gapStart + 5, parent);
0451: gapStart += 7;
0452: }
0453: currentBeginGroup = parent;
0454: }
0455:
0456: public void beginAttribute(String attrName, Object attrType) {
0457: beginAttribute(find(attrName, attrType));
0458: }
0459:
0460: public void beginAttribute(int index) {
0461: ensureSpace(5 + 1);
0462: gapEnd--;
0463: data[gapStart++] = BEGIN_ATTRIBUTE_LONG;
0464: if (attrStart != 0)
0465: throw new Error("nested attribute");
0466: attrStart = gapStart;
0467: setIntN(gapStart, index);
0468: setIntN(gapStart + 2, gapEnd - data.length);
0469: gapStart += 4;
0470: data[gapEnd] = END_ATTRIBUTE;
0471: }
0472:
0473: public void endAttribute() {
0474: if (data[gapEnd] != END_ATTRIBUTE || attrStart <= 0)
0475: throw new Error("unexpected endAttribute");
0476: // Move the END_ATTRIBUTES to before the gap.
0477: gapEnd++;
0478: setIntN(attrStart + 2, gapStart - attrStart + 1);
0479: attrStart = 0;
0480: data[gapStart++] = END_ATTRIBUTE;
0481: }
0482:
0483: public void writeChar(int i) {
0484: ensureSpace(3);
0485: if (i <= MAX_CHAR_SHORT)
0486: data[gapStart++] = (char) i;
0487: else if (i < 0x10000) {
0488: data[gapStart++] = CHAR_FOLLOWS;
0489: data[gapStart++] = (char) i;
0490: } else {
0491: data[gapStart++] = CHAR_PAIR_FOLLOWS;
0492: // write surrogates FIXME.
0493: }
0494: }
0495:
0496: public void writeBoolean(boolean v) {
0497: ensureSpace(1);
0498: data[gapStart++] = v ? BOOL_TRUE : BOOL_FALSE;
0499: }
0500:
0501: public void writeByte(int v) {
0502: ensureSpace(1);
0503: data[gapStart++] = (char) (BYTE_PREFIX + (v & 0xFF));
0504: }
0505:
0506: public void writeInt(int v) {
0507: ensureSpace(3);
0508: if (v >= MIN_INT_SHORT && v <= MAX_INT_SHORT)
0509: data[gapStart++] = (char) (INT_SHORT_ZERO + v);
0510: else {
0511: data[gapStart++] = INT_FOLLOWS;
0512: setIntN(gapStart, v);
0513: gapStart += 2;
0514: }
0515: }
0516:
0517: public void writeLong(long v) {
0518: ensureSpace(5);
0519: data[gapStart++] = LONG_FOLLOWS;
0520: data[gapStart++] = (char) (v >>> 48);
0521: data[gapStart++] = (char) (v >>> 32);
0522: data[gapStart++] = (char) (v >>> 16);
0523: data[gapStart++] = (char) v;
0524: }
0525:
0526: public void writeFloat(float v) {
0527: ensureSpace(3);
0528: int i = Float.floatToIntBits(v);
0529: data[gapStart++] = FLOAT_FOLLOWS;
0530: data[gapStart++] = (char) (i >>> 16);
0531: data[gapStart++] = (char) i;
0532: }
0533:
0534: public void writeDouble(double v) {
0535: ensureSpace(5);
0536: long l = Double.doubleToLongBits(v);
0537: data[gapStart++] = DOUBLE_FOLLOWS;
0538: data[gapStart++] = (char) (l >>> 48);
0539: data[gapStart++] = (char) (l >>> 32);
0540: data[gapStart++] = (char) (l >>> 16);
0541: data[gapStart++] = (char) l;
0542: }
0543:
0544: public boolean ignoring() {
0545: return false;
0546: }
0547:
0548: public void writeChars(String str) {
0549: int len = str.length();
0550: for (int i = 0; i < len; i++)
0551: writeChar(str.charAt(i));
0552: }
0553:
0554: public void write(char[] buf, int off, int len) {
0555: ensureSpace(len);
0556: while (len > 0) {
0557: char ch = buf[off++];
0558: len--;
0559: if (ch <= MAX_CHAR_SHORT)
0560: data[gapStart++] = ch;
0561: else {
0562: writeChar(ch);
0563: ensureSpace(len);
0564: }
0565: }
0566: }
0567:
0568: public boolean isEmpty() {
0569: // FIXME does not work if we allow comment() entries!
0570: int pos = gapStart == 0 ? gapEnd : 0;
0571: return pos == data.length;
0572: }
0573:
0574: public int size() {
0575: int size = 0;
0576: int i = 0;
0577: for (;;) {
0578: i = nextDataIndex(i);
0579: if (i < 0)
0580: return size;
0581: size++;
0582: }
0583: }
0584:
0585: protected void makePosition(int index, boolean isAfter,
0586: PositionContainer posSet, int posNumber) {
0587: int i = 0;
0588: while (--index >= 0) {
0589: i = nextDataIndex(i);
0590: if (i < 0)
0591: throw new IndexOutOfBoundsException();
0592: }
0593: posSet.setPosition(posNumber, (i << 1) | (isAfter ? 1 : 0),
0594: null);
0595: posSet.setSequence(posNumber, this );
0596: }
0597:
0598: public boolean gotoChildrenStart(TreePosition pos) {
0599: int index = gotoChildrenStart(pos.ipos >> 1);
0600: if (index < 0)
0601: return false;
0602: pos.push(this , index << 1, null);
0603: return true;
0604: }
0605:
0606: public int gotoChildrenStart(int index) {
0607: if (index >= gapStart)
0608: index += gapEnd - gapStart;
0609: if (index == data.length)
0610: return -1;
0611: char datum = data[index];
0612: if ((datum >= BEGIN_GROUP_SHORT && datum <= BEGIN_GROUP_SHORT
0613: + BEGIN_GROUP_SHORT_INDEX_MAX)
0614: || datum == BEGIN_GROUP_LONG)
0615: index += 3;
0616: else if (datum == BEGIN_DOCUMENT)
0617: return index + 1;
0618: else
0619: return -1;
0620: for (;;) {
0621: if (index >= gapStart)
0622: index += gapEnd - gapStart;
0623: datum = data[index];
0624: if (datum == BEGIN_ATTRIBUTE_LONG) {
0625: int end = getIntN(index + 3);
0626: index = end + (end < 0 ? data.length : index);
0627: } else if (datum == END_ATTRIBUTE)
0628: index++;
0629: else
0630: break;
0631: }
0632: return index;
0633: }
0634:
0635: public boolean gotoAttributesStart(TreePosition pos) {
0636: int index = gotoAttributesStart(pos.ipos >> 1);
0637: if (index < 0)
0638: return false;
0639: pos.push(this , index << 1, null);
0640: return true;
0641: }
0642:
0643: public int gotoAttributesStart(int index) {
0644: if (index >= gapStart)
0645: index += gapEnd - gapStart;
0646: if (index == data.length)
0647: return -1;
0648: char datum = data[index];
0649: if ((datum >= BEGIN_GROUP_SHORT && datum <= BEGIN_GROUP_SHORT
0650: + BEGIN_GROUP_SHORT_INDEX_MAX)
0651: || datum == BEGIN_GROUP_LONG)
0652: return index + 3;
0653: else
0654: return -1;
0655: }
0656:
0657: public Object get(int index) {
0658: throw unsupported("get");
0659: }
0660:
0661: public boolean consumeNext(int ipos, Object xpos, Consumer out) {
0662: if (!hasNext(ipos, xpos))
0663: return false;
0664: int start = ipos >> 1;
0665: int end = nextDataIndex(start);
0666: if (end >= 0)
0667: consumeRange(start, end, out);
0668: return true;
0669: }
0670:
0671: public int consumeRange(int startPosition, int endPosition,
0672: Consumer out) {
0673: int pos = startPosition;
0674: int limit = startPosition <= gapStart && endPosition > gapStart ? gapStart
0675: : endPosition;
0676: int index;
0677: for (;;) {
0678: if (pos >= limit) {
0679: if (pos == gapStart && endPosition > gapEnd) {
0680:
0681: pos = gapEnd;
0682: limit = endPosition;
0683: } else
0684: break;
0685: }
0686:
0687: char datum = data[pos++];
0688:
0689: if (datum <= MAX_CHAR_SHORT) {
0690: int start = pos - 1;
0691: int lim = limit;
0692: for (;;) {
0693: if (pos >= lim)
0694: break;
0695: datum = data[pos++];
0696: if (datum > MAX_CHAR_SHORT) {
0697: pos--;
0698: break;
0699: }
0700: }
0701: out.write(data, start, pos - start);
0702: continue;
0703: }
0704: if (datum >= OBJECT_REF_SHORT
0705: && datum <= OBJECT_REF_SHORT
0706: + OBJECT_REF_SHORT_INDEX_MAX) {
0707: out.writeObject(objects[datum - OBJECT_REF_SHORT]);
0708: continue;
0709: }
0710: if (datum >= BEGIN_GROUP_SHORT
0711: && datum <= BEGIN_GROUP_SHORT
0712: + BEGIN_GROUP_SHORT_INDEX_MAX) {
0713: index = datum - BEGIN_GROUP_SHORT;
0714: out.beginGroup(objects[index].toString(),
0715: objects[index + 1]);
0716: pos += 2;
0717: continue;
0718: }
0719: /*
0720: if ((datum & 0xFF00) == BYTE_PREFIX)
0721: {
0722: out.writeByte((byte) datum);
0723: continue;
0724: }
0725: */
0726: if (datum >= INT_SHORT_ZERO + MIN_INT_SHORT
0727: && datum <= INT_SHORT_ZERO + MAX_INT_SHORT) {
0728: out.writeInt(datum - INT_SHORT_ZERO);
0729: continue;
0730: }
0731: switch (datum) {
0732: case BEGIN_DOCUMENT:
0733: continue;
0734: case BOOL_FALSE:
0735: case BOOL_TRUE:
0736: out.writeBoolean(datum != BOOL_FALSE);
0737: continue;
0738: case CHAR_FOLLOWS:
0739: out.write(data, pos, 1 + datum - CHAR_FOLLOWS);
0740: pos++;
0741: continue;
0742: case CHAR_PAIR_FOLLOWS:
0743: out.write(data, pos, 1 + datum - CHAR_FOLLOWS);
0744: pos += 2;
0745: continue;
0746: case POSITION_TRIPLE_FOLLOWS: {
0747: AbstractSequence seq = (AbstractSequence) objects[getIntN(pos)];
0748: int ipos = getIntN(pos + 2);
0749: int xpos_index = getIntN(pos + 4);
0750: Object xpos = xpos_index < 0 ? null
0751: : objects[xpos_index];
0752: if (out instanceof PositionConsumer)
0753: ((PositionConsumer) out).writePosition(seq, ipos,
0754: xpos);
0755: else
0756: out.writeObject(SeqPosition.make(seq, ipos, xpos));
0757: pos += 6;
0758: }
0759: continue;
0760: case POSITION_REF_FOLLOWS:
0761: if (out instanceof PositionConsumer) {
0762: ((PositionConsumer) out)
0763: .consume((TreePosition) objects[getIntN(pos)]);
0764: pos += 2;
0765: continue;
0766: }
0767: // ... else fall through ...
0768: case OBJECT_REF_FOLLOWS:
0769: out.writeObject(objects[getIntN(pos)]);
0770: pos += 2;
0771: continue;
0772: case END_GROUP_SHORT:
0773: index = data[pos++];
0774: index = data[pos - 2 - index] - BEGIN_GROUP_SHORT;
0775: out.endGroup(objects[index].toString());
0776: continue;
0777: case BEGIN_GROUP_LONG:
0778: index = getIntN(pos);
0779: pos += 2;
0780: index += index >= 0 ? pos - 1 : data.length;
0781: index = getIntN(index + 1);
0782: out.beginGroup(objects[index].toString(),
0783: objects[index + 1]);
0784: continue;
0785: case END_GROUP_LONG:
0786: index = getIntN(pos);
0787: out.endGroup(objects[index].toString());
0788: pos += 6;
0789: continue;
0790: case BEGIN_ATTRIBUTE_LONG:
0791: index = getIntN(pos);
0792: out.beginAttribute(objects[index].toString(),
0793: objects[index + 1]);
0794: pos += 4;
0795: continue;
0796: case END_ATTRIBUTE:
0797: out.endAttribute();
0798: continue;
0799: case INT_FOLLOWS:
0800: writeInt(getIntN(pos));
0801: pos += 2;
0802: continue;
0803: case FLOAT_FOLLOWS:
0804: writeFloat(Float.intBitsToFloat(getIntN(pos)));
0805: pos += 2;
0806: continue;
0807: case LONG_FOLLOWS:
0808: writeLong(getLongN(pos));
0809: pos += 4;
0810: continue;
0811: case DOUBLE_FOLLOWS:
0812: writeDouble(Double.longBitsToDouble(getLongN(pos)));
0813: pos += 4;
0814: continue;
0815: default:
0816: dump();
0817: throw new Error("unknown code:" + (int) datum);
0818: }
0819: }
0820: return pos;
0821: }
0822:
0823: public boolean hasNext(int ipos, Object xpos) {
0824: int index = ipos >>> 1;
0825: if (index >= gapStart)
0826: index += gapEnd - gapStart;
0827: if (index == data.length)
0828: return false;
0829: char ch = data[index];
0830: return ch != END_ATTRIBUTE && ch != END_GROUP_SHORT
0831: && ch != END_GROUP_LONG;
0832: }
0833:
0834: public int getNextKind(int ipos, Object xpos) {
0835: int index = ipos >>> 1;
0836: if (index >= gapStart)
0837: index += gapEnd - gapStart;
0838: if (index == data.length)
0839: return Sequence.EOF_VALUE;
0840: char datum = data[index];
0841: if (datum <= MAX_CHAR_SHORT)
0842: return Sequence.CHAR_VALUE;
0843: if (datum >= OBJECT_REF_SHORT
0844: && datum <= OBJECT_REF_SHORT
0845: + OBJECT_REF_SHORT_INDEX_MAX)
0846: return Sequence.OBJECT_VALUE;
0847: if (datum >= BEGIN_GROUP_SHORT
0848: && datum <= BEGIN_GROUP_SHORT
0849: + BEGIN_GROUP_SHORT_INDEX_MAX)
0850: return Sequence.GROUP_VALUE;
0851: if ((datum & 0xFF00) == BYTE_PREFIX)
0852: return Sequence.TEXT_BYTE_VALUE;
0853: if (datum >= INT_SHORT_ZERO + MIN_INT_SHORT
0854: && datum <= INT_SHORT_ZERO + MAX_INT_SHORT)
0855: return Sequence.INT_S32_VALUE;
0856: switch (datum) {
0857: case BOOL_FALSE:
0858: case BOOL_TRUE:
0859: return Sequence.BOOLEAN_VALUE;
0860: case INT_FOLLOWS:
0861: return Sequence.INT_S32_VALUE;
0862: case LONG_FOLLOWS:
0863: return Sequence.INT_S64_VALUE;
0864: case FLOAT_FOLLOWS:
0865: return Sequence.FLOAT_VALUE;
0866: case DOUBLE_FOLLOWS:
0867: return Sequence.DOUBLE_VALUE;
0868: case CHAR_FOLLOWS:
0869: case CHAR_PAIR_FOLLOWS:
0870: return Sequence.CHAR_VALUE;
0871: case BEGIN_DOCUMENT:
0872: return Sequence.DOCUMENT_VALUE;
0873: case BEGIN_GROUP_LONG:
0874: return Sequence.GROUP_VALUE;
0875: case END_GROUP_SHORT:
0876: case END_GROUP_LONG:
0877: case END_ATTRIBUTE:
0878: return Sequence.EOF_VALUE;
0879: case BEGIN_ATTRIBUTE_LONG:
0880: return Sequence.ATTRIBUTE_VALUE;
0881: case POSITION_REF_FOLLOWS: // FIXME
0882: case POSITION_TRIPLE_FOLLOWS:
0883: case OBJECT_REF_FOLLOWS:
0884: default:
0885: return Sequence.OBJECT_VALUE;
0886: }
0887:
0888: }
0889:
0890: protected int getNextTypeIndex(int ipos, Object xpos) {
0891: int index = ipos >>> 1;
0892: if (index >= gapStart)
0893: index += gapEnd - gapStart;
0894: if (index == data.length)
0895: return Sequence.EOF_VALUE;
0896: char datum = data[index];
0897: if (datum >= BEGIN_GROUP_SHORT
0898: && datum <= BEGIN_GROUP_SHORT
0899: + BEGIN_GROUP_SHORT_INDEX_MAX)
0900: return datum - BEGIN_GROUP_SHORT;
0901: else if (datum == BEGIN_GROUP_LONG
0902: || datum == BEGIN_ATTRIBUTE_LONG)
0903: return getIntN(index + 1);
0904: return -1;
0905: }
0906:
0907: public String getNextTypeName(int ipos, Object xpos) {
0908: int index = getNextTypeIndex(ipos, xpos);
0909: return index < 0 ? null : (String) objects[index];
0910: }
0911:
0912: public Object getNextTypeObject(int ipos, Object xpos) {
0913: int index = getNextTypeIndex(ipos, xpos);
0914: return index < 0 ? null : objects[index + 1];
0915: }
0916:
0917: public Object getNext(int ipos, Object xpos) {
0918: int index = ipos >>> 1;
0919: if (index >= gapStart)
0920: index += gapEnd - gapStart;
0921: if (index == data.length)
0922: return Sequence.eofValue;
0923: char datum = data[index];
0924: if (datum <= MAX_CHAR_SHORT)
0925: return Convert.toObject(datum);
0926: if (datum >= OBJECT_REF_SHORT
0927: && datum <= OBJECT_REF_SHORT
0928: + OBJECT_REF_SHORT_INDEX_MAX)
0929: return objects[datum - OBJECT_REF_SHORT];
0930: if (datum >= BEGIN_GROUP_SHORT
0931: && datum <= BEGIN_GROUP_SHORT
0932: + BEGIN_GROUP_SHORT_INDEX_MAX)
0933: return new TreeList(this , index, index + data[index + 1]
0934: + 2);
0935: /*
0936: if ((datum & 0xFF00) == BYTE_PREFIX)
0937: return Sequence.TEXT_BYTE_VALUE;
0938: */
0939: if (datum >= INT_SHORT_ZERO + MIN_INT_SHORT
0940: && datum <= INT_SHORT_ZERO + MAX_INT_SHORT)
0941: return Convert.toObject(datum - INT_SHORT_ZERO);
0942: switch (datum) {
0943: case BEGIN_DOCUMENT:
0944: return this ; // ???
0945: case BOOL_FALSE:
0946: case BOOL_TRUE:
0947: return Convert.toObject(datum != BOOL_FALSE);
0948: case INT_FOLLOWS:
0949: return Convert.toObject(getIntN(index + 1));
0950: case LONG_FOLLOWS:
0951: return Convert.toObject(getLongN(index + 1));
0952: case FLOAT_FOLLOWS:
0953: return Convert.toObject(Float
0954: .intBitsToFloat(getIntN(index + 1)));
0955: case DOUBLE_FOLLOWS:
0956: return Convert.toObject(Double
0957: .longBitsToDouble(getLongN(index + 1)));
0958: case CHAR_FOLLOWS:
0959: return Convert.toObject(data[index + 1]);
0960: /*
0961: case CHAR_PAIR_FOLLOWS:
0962: return Sequence.CHAR_VALUE;
0963: */
0964: case BEGIN_ATTRIBUTE_LONG: {
0965: int end_offset = getIntN(index + 3);
0966: end_offset += end_offset < 0 ? data.length : index;
0967: return new TreeList(this , index, end_offset + 1);
0968: }
0969: case BEGIN_GROUP_LONG: {
0970: int end_offset = getIntN(index + 1);
0971: end_offset += end_offset < 0 ? data.length : index;
0972: return new TreeList(this , index, end_offset + 7);
0973: }
0974: case END_GROUP_SHORT:
0975: case END_GROUP_LONG:
0976: case END_ATTRIBUTE:
0977: return Sequence.eofValue;
0978: case POSITION_REF_FOLLOWS:
0979: case OBJECT_REF_FOLLOWS:
0980: return objects[getIntN(index + 1)];
0981: case POSITION_TRIPLE_FOLLOWS: //FIXME
0982: AbstractSequence seq = (AbstractSequence) objects[getIntN(index + 1)];
0983: ipos = getIntN(index + 3);
0984: int xpos_index = getIntN(index + 5);
0985: xpos = xpos_index < 0 ? null : objects[xpos_index];
0986: return SeqPosition.make(seq, ipos, xpos);
0987: default:
0988: throw unsupported("getNext, code="
0989: + Integer.toHexString(datum));
0990: }
0991: }
0992:
0993: public int stringValue(int index, StringBuffer sbuf) {
0994: return stringValue(false, index, sbuf);
0995: }
0996:
0997: public int stringValue(boolean inGroup, int index, StringBuffer sbuf) {
0998: Object value = null;
0999: int doChildren = 0;
1000: if (index >= gapStart)
1001: index += gapEnd - gapStart;
1002: if (index == data.length)
1003: return -1;
1004: char datum = data[index];
1005: index++;
1006: if (datum <= MAX_CHAR_SHORT) {
1007: sbuf.append(datum);
1008: return index;
1009: }
1010: if (datum >= OBJECT_REF_SHORT
1011: && datum <= OBJECT_REF_SHORT
1012: + OBJECT_REF_SHORT_INDEX_MAX) {
1013: value = objects[datum - OBJECT_REF_SHORT];
1014: } else if (datum >= BEGIN_GROUP_SHORT
1015: && datum <= BEGIN_GROUP_SHORT
1016: + BEGIN_GROUP_SHORT_INDEX_MAX) {
1017: doChildren = index + 2;
1018: index = data[index] + index + 1;
1019: } else if ((datum & 0xFF00) == BYTE_PREFIX) {
1020: sbuf.append(datum & 0xFF);
1021: return index;
1022: } else if (datum >= INT_SHORT_ZERO + MIN_INT_SHORT
1023: && datum <= INT_SHORT_ZERO + MAX_INT_SHORT) {
1024: sbuf.append((int) datum - INT_SHORT_ZERO);
1025: return index;
1026: } else {
1027: switch (datum) {
1028: case BOOL_FALSE:
1029: case BOOL_TRUE:
1030: sbuf.append(datum != BOOL_FALSE);
1031: return index;
1032: case INT_FOLLOWS:
1033: sbuf.append(getIntN(index + 1));
1034: return index + 2;
1035: case LONG_FOLLOWS:
1036: sbuf.append(getLongN(index + 1));
1037: return index + 4;
1038: case FLOAT_FOLLOWS:
1039: sbuf.append(Float.intBitsToFloat(getIntN(index + 1)));
1040: return index + 2;
1041: case DOUBLE_FOLLOWS:
1042: sbuf.append(Double
1043: .longBitsToDouble(getLongN(index + 1)));
1044: return index + 4;
1045: case CHAR_FOLLOWS:
1046: sbuf.append(data[index + 1]);
1047: return index + 1;
1048: case BEGIN_DOCUMENT:
1049: doChildren = 1;
1050: index = data.length;
1051: break;
1052: case BEGIN_GROUP_LONG:
1053: doChildren = index + 2;
1054: int j = getIntN(index);
1055: j += j < 0 ? data.length : index - 1;
1056: index = j + 7;
1057: break;
1058: case END_GROUP_SHORT:
1059: case END_GROUP_LONG:
1060: case END_ATTRIBUTE:
1061: return -1;
1062: case BEGIN_ATTRIBUTE_LONG:
1063: if (!inGroup)
1064: doChildren = index + 4;
1065: int end = getIntN(index + 2);
1066: index = end + (end < 0 ? data.length + 1 : index);
1067: break;
1068: case POSITION_REF_FOLLOWS:
1069: case POSITION_TRIPLE_FOLLOWS:
1070: case OBJECT_REF_FOLLOWS:
1071: case CHAR_PAIR_FOLLOWS:
1072: default:
1073: throw new Error("unimplemented");
1074: }
1075: }
1076: if (value != null)
1077: sbuf.append(value);
1078: if (doChildren > 0) {
1079: do {
1080: doChildren = stringValue(true, doChildren, sbuf);
1081: } while (doChildren >= 0);
1082: }
1083: return index;
1084: }
1085:
1086: protected void makeRelativePosition(int istart, Object xstart,
1087: int offset, boolean isAfter, PositionContainer posSet,
1088: int posNumber) {
1089: if (offset < 0)
1090: throw unsupported("backwards makeRelativePostion");
1091: int pos = istart >>> 1;
1092: while (--offset >= 0) {
1093: pos = nextDataIndex(pos);
1094: if (pos < 0)
1095: throw new IndexOutOfBoundsException();
1096: }
1097: posSet.setPosition(posNumber, (pos << 1) | (isAfter ? 1 : 0),
1098: null);
1099: }
1100:
1101: public int nextDataIndex(int pos) {
1102: if (pos == gapStart)
1103: pos = gapEnd;
1104: if (pos == data.length)
1105: return -1;
1106: int j;
1107: char datum = data[pos++];
1108: if (datum <= MAX_CHAR_SHORT
1109: || (datum >= OBJECT_REF_SHORT && datum <= OBJECT_REF_SHORT
1110: + OBJECT_REF_SHORT_INDEX_MAX)
1111: || (datum >= INT_SHORT_ZERO + MIN_INT_SHORT && datum <= INT_SHORT_ZERO
1112: + MAX_INT_SHORT))
1113: return pos;
1114: if (datum >= BEGIN_GROUP_SHORT
1115: && datum <= BEGIN_GROUP_SHORT
1116: + BEGIN_GROUP_SHORT_INDEX_MAX)
1117: return data[pos] + pos + 1;
1118: switch (datum) {
1119: case BEGIN_DOCUMENT:
1120: return data.length;
1121: case BOOL_FALSE:
1122: case BOOL_TRUE:
1123: return pos;
1124: case CHAR_FOLLOWS:
1125: return pos + 1;
1126: case POSITION_REF_FOLLOWS:
1127: case OBJECT_REF_FOLLOWS:
1128: case CHAR_PAIR_FOLLOWS:
1129: case INT_FOLLOWS:
1130: return pos + 2;
1131: case POSITION_TRIPLE_FOLLOWS:
1132: return pos + 6;
1133: case END_GROUP_SHORT:
1134: case END_GROUP_LONG:
1135: case END_ATTRIBUTE:
1136: return -1;
1137: case BEGIN_GROUP_LONG:
1138: j = getIntN(pos);
1139: j += j < 0 ? data.length : pos - 1;
1140: return j + 7;
1141: case BEGIN_ATTRIBUTE_LONG:
1142: j = getIntN(pos + 2);
1143: j += j < 0 ? data.length : pos - 1;
1144: return j + 1;
1145: case LONG_FOLLOWS:
1146: case DOUBLE_FOLLOWS:
1147: return pos + 4;
1148: default:
1149: throw new Error("unknown code:" + (int) datum);
1150: }
1151: }
1152:
1153: public void consume(Consumer out) {
1154: consumeRange(0, data.length, out);
1155: }
1156:
1157: // /* DEBUGGING
1158: public void dump() {
1159: java.io.PrintWriter out = new java.io.PrintWriter(System.out);
1160: dump(out);
1161: out.flush();
1162: }
1163:
1164: public void dump(java.io.PrintWriter out) {
1165: out.println("TreeList @" + System.identityHashCode(this )
1166: + " gapStart:" + gapStart + " gapEnd:" + gapEnd
1167: + " length:" + data.length);
1168: int toskip = 0;
1169: for (int i = 0; i < data.length; i++) {
1170:
1171: if (i < gapStart || i >= gapEnd) {
1172: int j;
1173: long l;
1174: int ch = data[i];
1175: out.print("" + i + ": 0x" + Integer.toHexString(ch)
1176: + '=' + ((short) ch));
1177: if (--toskip < 0) {
1178: if (ch <= MAX_CHAR_SHORT) {
1179: if (ch >= ' ' && ch < 127)
1180: out.print("='" + ((char) ch) + "'");
1181: else if (ch == '\n')
1182: out.print("='\\n'");
1183: else
1184: out.print("='\\u" + Integer.toHexString(ch)
1185: + "'");
1186: } else if (ch >= OBJECT_REF_SHORT
1187: && ch <= OBJECT_REF_SHORT
1188: + OBJECT_REF_SHORT_INDEX_MAX) {
1189: ch = ch - OBJECT_REF_SHORT;
1190: Object obj = objects[ch];
1191: out.print("=Object#" + ((int) ch) + '=' + obj
1192: + ':' + obj.getClass().getName());
1193: } else if (ch >= BEGIN_GROUP_SHORT
1194: && ch <= BEGIN_GROUP_SHORT
1195: + BEGIN_GROUP_SHORT_INDEX_MAX) {
1196: ch = ch - BEGIN_GROUP_SHORT;
1197: out.print("=BEGIN_GROUP_SHORT index#"
1198: + ((int) ch) + "=<" + objects[ch]
1199: + "::" + objects[ch + 1] + '>');
1200: toskip = 2;
1201: } else if (ch >= INT_SHORT_ZERO + MIN_INT_SHORT
1202: && ch <= INT_SHORT_ZERO + MAX_INT_SHORT) {
1203: out.print("= INT_SHORT:"
1204: + (ch - INT_SHORT_ZERO));
1205: } else {
1206: switch (ch) {
1207: case INT_FOLLOWS:
1208: j = getIntN(i + 1);
1209: out.print("=INT_FOLLOWS value:" + j);
1210: toskip = 2;
1211: break;
1212: case LONG_FOLLOWS:
1213: l = getLongN(i + 1);
1214: out.print("=LONG_FOLLOWS value:" + l);
1215: toskip = 4;
1216: break;
1217: case FLOAT_FOLLOWS:
1218: j = getIntN(i + 1);
1219: out.print("=FLOAT_FOLLOWS value:"
1220: + Float.intBitsToFloat(j));
1221: toskip = 2;
1222: break;
1223: case DOUBLE_FOLLOWS:
1224: l = getLongN(i + 1);
1225: out.print("=DOUBLE_FOLLOWS value:"
1226: + Double.longBitsToDouble(l));
1227: toskip = 4;
1228: break;
1229: case BEGIN_DOCUMENT:
1230: out.print("=BEGIN_DOCUMENT");
1231: break;
1232: case BOOL_FALSE:
1233: out.print("= false");
1234: break;
1235: case BOOL_TRUE:
1236: out.print("= true");
1237: break;
1238: case CHAR_FOLLOWS:
1239: out.print("=CHAR_FOLLOWS");
1240: toskip = 1;
1241: break;
1242: case CHAR_PAIR_FOLLOWS:
1243: out.print("=CHAR_PAIR_FOLLOWS");
1244: toskip = 2;
1245: break;
1246: case POSITION_REF_FOLLOWS:
1247: case OBJECT_REF_FOLLOWS:
1248: toskip = 2;
1249: break;
1250: case END_GROUP_SHORT:
1251: out.print("=END_GROUP_SHORT begin:");
1252: j = i - data[i + 1];
1253: out.print(j);
1254: j = data[j] - BEGIN_GROUP_SHORT;
1255: out.print(" -> #" + j + "=<" + objects[j]
1256: + '>');
1257: toskip = 1;
1258: break;
1259: case BEGIN_GROUP_LONG:
1260: j = getIntN(i + 1);
1261: j += j < 0 ? data.length : i;
1262: out.print("=BEGIN_GROUP_LONG end:" + j);
1263: j = getIntN(j + 1);
1264: out.print(" -> #" + j + "=<" + objects[j]
1265: + "::" + objects[j + 1] + '>');
1266: toskip = 2;
1267: break;
1268: case END_GROUP_LONG:
1269: j = getIntN(i + 1);
1270: out.print("=END_GROUP_LONG name:" + j
1271: + "=<" + objects[j] + '>');
1272: j = getIntN(i + 3);
1273: j = j < 0 ? i + j : j;
1274: out.print(" begin:" + j);
1275: j = getIntN(i + 5);
1276: j = j < 0 ? i + j : j;
1277: out.print(" parent:" + j);
1278: toskip = 6;
1279: break;
1280: case BEGIN_ATTRIBUTE_LONG:
1281: j = getIntN(i + 1);
1282: out.print("=BEGIN_ATTRIBUTE name:" + j
1283: + "=" + objects[j]);
1284: j = getIntN(i + 3);
1285: j += j < 0 ? data.length : i;
1286: out.print(" end:" + j);
1287: toskip = 4;
1288: break;
1289: case END_ATTRIBUTE:
1290: out.print("=END_ATTRIBUTE");
1291: break;
1292: case POSITION_TRIPLE_FOLLOWS:
1293: out.print("=POSITION_TRIPLE_FOLLOWS seq:");
1294: {
1295: j = getIntN(i + 1);
1296: out.print(j);
1297: out.print("=@");
1298: Object seq = objects[j];
1299: if (seq == null)
1300: out.print("null");
1301: else
1302: out.print(System
1303: .identityHashCode(seq));
1304: out.print(" ipos:");
1305: out.print(getIntN(i + 3));
1306: out.print(" xpos:");
1307: out.print(getIntN(i + 5));
1308: }
1309: toskip = 6;
1310: /*
1311: AbstractSequence seq = (AbstractSequence) objects[getIntN(i+1)];
1312: ipos = getIntN(i+3);
1313: int xpos_index = getIntN(i+5);
1314: xpos = xpos_index < 0 ? null : objects[xpos_index];
1315: */
1316: break;
1317: }
1318: }
1319: }
1320: out.println();
1321: if (false && toskip > 0) {
1322: i += toskip;
1323: toskip = 0;
1324: }
1325: }
1326: }
1327: }
1328: // DEBUGGING */
1329: }
|