12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576777879808182838485868788899091929394959697989910010110210310410510610710810911011111211311411511611711811912012112212312412512612712812913013113213313413513613713813914014114214314414514614714814915015115215315415515615715815916016116216316416516616716816917017117217317417517617717817918018118218318418518618718818919019119219319419519619719819920020120220320420520620720820921021121221321421521621721821922022122222322422522622722822923023123223323423523623723823924024124224324424524624724824925025125225325425525625725825926026126226326426526626726826927027127227327427527627727827928028128228328428528628728828929029129229329429529629729829930030130230330430530630730830931031131231331431531631731831932032132232332432532632732832933033133233333433533633733833934034134234334434534634734834935035135235335435535635735835936036136236336436536636736836937037137237337437537637737837938038138238338438538638738838939039139239339439539639739839940040140240340440540640740840941041141241341441541641741841942042142242342442542642742842943043143243343443543643743843944044144244344444544644744844945045145245345445545645745845946046146246346446546646746846947047147247347447547647747847948048148248348448548648748848949049149249349449549649749849950050150250350450550650750850951051151251351451551651751851952052152252352452552652752852953053153253353453553653753853954054154254354454554654754854955055155255355455555655755855956056156256356456556656756856957057157257357457557657757857958058158258358458558658758858959059159259359459559659759859960060160260360460560660760860961061161261361461561661761861962062162262362462562662762862963063163263363463563663763863964064164264364464564664764864965065165265365465565665765865966066166266366466566666766866967067167267367467567667767867968068168268368468568668768868969069169269369469569669769869970070170270370470570670770870971071171271371471571671771871972072172272372472572672772872973073173273373473573673773873974074174274374474574674774874975075175275375475575675775875976076176276376476576676776876977077177277377477577677777877978078178278378478578678778878979079179279379479579679779879980080180280380480580680780880981081181281381481581681781881982082182282382482582682782882983083183283383483583683783883984084184284384484584684784884985085185285385485585685785885986086186286386486586686786886987087187287387487587687787887988088188288388488588688788888989089189289389489589689789889990090190290390490590690790890991091191291391491591691791891992092192292392492592692792892993093193293393493593693793893994094194294394494594694794894995095195295395495595695795895996096196296396496596696796896997097197297397497597697797897998098198298398498598698798898999099199299399499599699799899910001001100210031004100510061007100810091010101110121013101410151016101710181019102010211022102310241025102610271028102910301031103210331034103510361037103810391040104110421043104410451046104710481049105010511052105310541055105610571058105910601061106210631064106510661067106810691070107110721073107410751076107710781079108010811082108310841085108610871088108910901091109210931094109510961097109810991100110111021103110411051106110711081109111011111112111311141115111611171118111911201121112211231124112511261127112811291130113111321133113411351136113711381139114011411142114311441145114611471148114911501151115211531154115511561157115811591160116111621163116411651166116711681169117011711172117311741175117611771178117911801181118211831184118511861187118811891190119111921193119411951196119711981199120012011202120312041205120612071208120912101211121212131214121512161217121812191220122112221223122412251226122712281229123012311232123312341235123612371238123912401241124212431244124512461247124812491250125112521253125412551256125712581259126012611262126312641265126612671268126912701271127212731274127512761277127812791280128112821283128412851286128712881289129012911292129312941295129612971298129913001301130213031304130513061307130813091310131113121313131413151316131713181319132013211322132313241325132613271328132913301331133213331334133513361337133813391340134113421343134413451346134713481349135013511352135313541355135613571358135913601361136213631364136513661367136813691370137113721373137413751376137713781379138013811382138313841385138613871388138913901391139213931394139513961397139813991400140114021403140414051406140714081409141014111412141314141415141614171418141914201421142214231424142514261427142814291430143114321433143414351436143714381439144014411442144314441445144614471448144914501451145214531454145514561457145814591460146114621463146414651466146714681469147014711472147314741475147614771478147914801481148214831484148514861487148814891490149114921493149414951496149714981499150015011502150315041505150615071508150915101511151215131514151515161517151815191520152115221523152415251526152715281529153015311532153315341535153615371538153915401541154215431544154515461547154815491550155115521553155415551556155715581559156015611562156315641565156615671568156915701571157215731574157515761577157815791580158115821583158415851586158715881589159015911592159315941595159615971598159916001601160216031604160516061607160816091610161116121613161416151616161716181619162016211622162316241625162616271628162916301631163216331634163516361637163816391640164116421643164416451646164716481649165016511652165316541655165616571658165916601661166216631664166516661667166816691670167116721673167416751676167716781679168016811682168316841685168616871688168916901691169216931694169516961697169816991700170117021703170417051706170717081709171017111712171317141715171617171718171917201721172217231724172517261727172817291730173117321733173417351736173717381739174017411742174317441745174617471748174917501751175217531754175517561757175817591760176117621763176417651766176717681769177017711772177317741775177617771778177917801781178217831784178517861787178817891790179117921793179417951796179717981799180018011802180318041805180618071808180918101811181218131814181518161817181818191820182118221823182418251826182718281829183018311832183318341835183618371838183918401841184218431844184518461847184818491850185118521853185418551856185718581859186018611862186318641865186618671868186918701871187218731874187518761877187818791880188118821883188418851886188718881889189018911892189318941895189618971898189919001901190219031904190519061907190819091910191119121913191419151916191719181919192019211922192319241925192619271928192919301931193219331934193519361937193819391940194119421943194419451946194719481949195019511952195319541955195619571958195919601961196219631964196519661967196819691970197119721973197419751976197719781979198019811982198319841985198619871988198919901991199219931994199519961997199819992000200120022003200420052006200720082009201020112012201320142015201620172018201920202021202220232024202520262027202820292030203120322033203420352036203720382039204020412042204320442045204620472048204920502051205220532054205520562057205820592060206120622063206420652066206720682069207020712072207320742075207620772078207920802081208220832084208520862087208820892090209120922093209420952096209720982099210021012102210321042105210621072108210921102111211221132114211521162117211821192120212121222123212421252126212721282129213021312132213321342135213621372138213921402141214221432144214521462147214821492150215121522153215421552156215721582159216021612162216321642165216621672168216921702171217221732174217521762177217821792180218121822183218421852186218721882189219021912192219321942195219621972198219922002201220222032204220522062207220822092210221122122213221422152216221722182219222022212222222322242225222622272228222922302231223222332234223522362237223822392240224122422243224422452246224722482249225022512252225322542255225622572258225922602261226222632264226522662267226822692270227122722273227422752276227722782279228022812282228322842285228622872288228922902291229222932294229522962297229822992300230123022303230423052306230723082309231023112312231323142315231623172318231923202321232223232324232523262327232823292330233123322333233423352336233723382339234023412342234323442345234623472348234923502351235223532354235523562357235823592360236123622363236423652366236723682369237023712372237323742375237623772378237923802381238223832384238523862387238823892390239123922393239423952396239723982399240024012402240324042405240624072408240924102411241224132414241524162417241824192420242124222423242424252426242724282429243024312432243324342435243624372438243924402441244224432444244524462447244824492450245124522453245424552456245724582459246024612462246324642465246624672468246924702471247224732474247524762477247824792480248124822483248424852486248724882489249024912492249324942495249624972498249925002501250225032504250525062507250825092510251125122513251425152516251725182519252025212522252325242525252625272528252925302531253225332534253525362537253825392540254125422543254425452546254725482549255025512552255325542555255625572558255925602561256225632564 |
- // Copyright (c) 2001, 2002, 2003, 2006 Per M.A. Bothner and Brainfood Inc.
- // This is free software; for terms and warranty disclaimer see ./COPYING.
- package gnu.lists;
- import gnu.text.Char;
- /** A compact representation of a tree, that is a nested list structure.
- * The data structure can store anything that can be emitted to a Consumer.
- * This data structure is optimized for efficient forwards traversal
- * through the data structure, not random access.
- * It does have an "insertion point"; insertions and deletions are
- * efficient through the use of a buffer gap.
- * It is a reasonable choice for a "DOM" for XML data.
- */
- public class TreeList extends AbstractSequence<Object>
- implements
- /* #ifdef JAVA5 */
- Appendable,
- /* #endif */
- XConsumer, PositionConsumer, Consumable
- {
- // Some public fields and methods are public which probably shouldn't be,
- // for the sake of XMLFilter. FIXME. Perhaps an abstract class
- // in gnu.lists that XMLFilter extend?
- public Object[] objects;
- public int oindex;
- public char[] data;
- public int gapStart;
- public int gapEnd;
- /** If non-zero, gap is in an attribute starting (1 less than) here. */
- public int attrStart;
- /** If non-zero, gap is in an document starting (1 less than) here. */
- public int docStart;
- public TreeList()
- {
- reserveObjects(20);
- gapEnd = 200;
- data = new char[gapEnd];
- }
- /**
- * Make a copy of a sub-range of a TreeList.
- * @param list the TreeList to copy
- * @param startPosition start of range, as a raw index in data
- * @param endPosition end of range, as a raw index in data
- */
- public TreeList(TreeList list, int startPosition, int endPosition)
- {
- this();
- list.consumeIRange(startPosition, endPosition, this);
- }
- public TreeList(TreeList list)
- {
- this(list, 0, list.data.length);
- }
- public void clear()
- {
- gapStart = 0;
- gapEnd = data.length;
- attrStart = 0;
- if (gapEnd > 1500)
- {
- gapEnd = 200;
- data = new char[gapEnd];
- }
- objects = null;
- oindex = 0;
- reserveObjects(0);
- }
- // The data array contains an encoding of values, as follows:
- // 0x0000 ... 0x9FFF: A single Unicode character.
- // 0xAXXX: BEGIN_ELEMENT_SHORT
- // 0xBXXX: negative integer ((short)0x0XXX<<4)>>4, range -4096 to -1
- // 0xCXXX: positive integer 0x0XXX, in the range 0 to 4095
- // 0xDXXX: positive integer 0x1XXX, in the range 4096 to 8191
- // 0xEXXX:: OBJECT_REF_SHORT. The object in objects[0xXXX].
- // 0xF0XX: A byte (encoded character or char fragment) ((byte) 0xXX).
- // 0xF100 ... 0xF101: A Boolean (BOOL_FALSE, BOOL_TRUE)
- // 0xF102 A B: INT_FOLLOWS - 32-bit int (big-endian)
- // 0xF103 A B C D: LONG_FOLLOWS 64-bit long int (big-endian)
- // 0xF104 A B: FLOAT_FOLLOWS 32-bit float (big-endian)
- // 0xF105 A B C D: DOUBLE_FOLLOWS 64-bit double (big-endian)
- // 0xF106: CHAR_FOLLOWS
- // 0xF108: BEGIN_ELEMENT_LONG
- // 0xF109: BEGIN_ATTRIBUTE_LONG
- // 0xF10A: END_ATTRIBUTE
- // 0xF10B: END_ELEMENT_SHORT
- // 0xF10C: END_ELEMENT_LONG
- // 0xF10D A B: OBJECT_REF_FOLLOWS: The object in objects[(A,B)].
- // 0xF10E A B: POSITION_REF_FOLLOWS: The TreePosition in objects[(A,B)].
- // 0xF10F A B C D: POSITION_PAIR_FOLLOWS
- // 0xF110 BEGIN_DOCUMENT
- // 0xF111 END_DOCUMENT
- // 0xF112 BEGIN_ENTITY
- // 0xF113 END_ENTITY
- // 0xF114 PROCESSING_INSTRUCTION
- // 0xF115 CDATA_SECTION
- // 0xF116 JOINER
- // 0xF117 COMMENT
- // 0xF118 DOCUMENT_URI: Not a node, but a property of the previous document.
- /** The largest Unicode character that can be encoded in one char. */
- public static final int MAX_CHAR_SHORT = 0x9FFF;
- /** The smallest integer that can use the short int encoding. */
- static final int MIN_INT_SHORT = -0x1000; // -4096
- /** The largest integer that can use the short int encoding. */
- static final int MAX_INT_SHORT = 0x1FFF; // 8191
- /** The value used to encode the integer zero. */
- static final int INT_SHORT_ZERO = 0xC000;
- /** The value used to encode the object in objects[0]. */
- static final int OBJECT_REF_SHORT = 0xE000;
- /** The maximum offset in the objects array for a short object-ref. */
- static final int OBJECT_REF_SHORT_INDEX_MAX = 0xFFF;
- /** Followed by 2 chars that provide an index into objects. */
- static final char OBJECT_REF_FOLLOWS = 0xF10D;
- /** Followed by 2 chars that provide an index into objects. */
- static final char POSITION_REF_FOLLOWS = 0xF10E;
- /** A position triple referencing some other "nodes".
- * Followed by index of sequence (2 chars), and ipos (2 chars). */
- protected static final char POSITION_PAIR_FOLLOWS = 0xF10F;
- /** Encoding prefix that indicates a byte value. */
- static final int BYTE_PREFIX = 0xF000;
- /** The value used to encode false. */
- static final char BOOL_FALSE = 0xF100;
- /** The value used to encode true. */
- static final char BOOL_TRUE = 0xF101;
- /** A 32-bit integer, non-compact form.
- *
- * [INT_FOLLOWS]
- * [word1], [word2]: The big-endian bits of the integer.
- */
- public static final int INT_FOLLOWS = 0xF102;
- /** A 64-bit long integer.
- *
- * [LONG_FOLLOWS]
- * [word1], [word2], [word3], [word4]: The big-endian bits of the long.
- */
- static final int LONG_FOLLOWS = 0xF103;
- /** A 32-bit float floating-pointer number.
- *
- * [FLOAT_FOLLOWS]
- * [word1], [word2]: The big-endian bits of the float.
- */
- static final int FLOAT_FOLLOWS = 0xF104;
- /** A 64-bit double floating-pointer number.
- *
- * [DOUBLE_FOLLOWS]
- * [word1], [word2], [word3], [word4]: The big-endian bits of the double.
- */
- static final int DOUBLE_FOLLOWS = 0xF105;
- /** A 16-bit (non-compact) Unicode char follows. */
- static final int CHAR_FOLLOWS = 0xF106;
- /** A comment node follows.
- * [COMMENT]
- * [length] 2 shorts
- * [comment text], (length) number of characters.
- */
- static final int COMMENT = 0xF117;
- /** A processing-instruction node follows.
- * [PROCESSING_INSTRUCTION]
- * [target] 2 shorts, where objects[target] is the target as a String.
- * [length] 2 shorts.
- * [comment text], (length) number of characters.
- */
- protected static final int PROCESSING_INSTRUCTION = 0xF114;
- /** A CDATA node follows.
- * [CDATA_SECTION]
- * [length] 2 shorts
- * [comment text], (length) number of characters.
- */
- static final int CDATA_SECTION = 0xF115;
- /** Suppress spacing between non-node items. */
- static final int JOINER = 0xF116;
- /** The beginning of an attribute.
- * [BEGIN_ATTRIBUTE_LONG]
- * [index], 2 shorts, where objects[index] is the attribute type name
- * and objects[index+1] is the attribute type object.
- * [end_offset], 2 shorts, giving the location of the following
- * END_ATTRIBUTE. If the attribute straddles the gap, then
- * end_offset is a negative offset relative to data.length.
- * (Therefore allocating more space for the gap does not require
- * adjusting end_offset.) Otherwise, the end_offset is relative
- * to the BEGIN_ATTRIBUTE_LONG word.
- */
- protected static final int BEGIN_ATTRIBUTE_LONG = 0xF109;
- public static final int BEGIN_ATTRIBUTE_LONG_SIZE = 5;
- /** The end of an attribute of a node. */
- static final int END_ATTRIBUTE = 0xF10A;
- public static final int END_ATTRIBUTE_SIZE = 1;
- /** Beginning of a document (or top-level value).
- * Used to distinguish a document from its element node.
- * [end_offset], 2 shorts, giving the location of the following
- * END_DOCUMENT. If the attribute straddles the gap, then
- * end_offset is a negative offset relative to data.length.
- * (Therefore allocating more space for the gap does not require
- * adjusting end_offset.) Otherwise, the end_offset is relative
- * to the BEGIN_DOCUMENT word.
- * [parent_offset], in 2 shorts. The parent node, or -1 if no parent.
- * Otherwise, a negative value is a relative offset, while a non-negative
- * value is absolute. (Use the latter when gap is between this node and
- * its parent. The parent would normally be a BEGIN_ENTITY.
- */
- protected static final int BEGIN_DOCUMENT = 0xF110;
- /** End of a document. */
- protected static final int END_DOCUMENT = 0xF111;
- /** Start of an entity (typically a file, possibly included).
- * [base_uri], 2 shorts, given an index of a base-uri object
- * [parent_offset], in 2 shorts, encoded as for BEGIN_DOCUMENT.
- */
- public static final int BEGIN_ENTITY = 0xF112;
- public static final int BEGIN_ENTITY_SIZE = 5;
- protected static final int END_ENTITY = 0xF113;
- /** The document-uri property of a node.
- * This is not an actual value, but it is a property of the previous
- * document node, or the surrounding node just after a BEGIN_XXX entry.
- * [DOCUMENT_URI]
- * [index]. 2 shorts, where objects[index] is the document-uri value.
- */
- protected static final int DOCUMENT_URI = 0xF118;
- /** Beginning of an element, compact form.
- *
- * [BEGIN_ELEMENT_SHORT + index], where objects[index] is the element's
- * type name and objects[index+1] is the type object.
- * [end_offset], the unsigned offset (from the initial word)
- * to the corresponding END_ELEMENT_SHORT.
- * [parent_offset], the (unsigned absolute value of the) offset
- * to the outer BEGIN_ELEMENT_SHORT/BEGIN_ELEMENT_LONG/BEGIN_DOCUMENT.
- *. (If these is no parent, then parent_offset==0.)
- *
- * This should is used when {@code index < BEGIN_ELEMENT_SHORT_INDEX_MAX},
- * both end_offset and parent_offset fit in 16 bits,
- * and the element does not straddle the gap.
- */
- protected static final int BEGIN_ELEMENT_SHORT = 0xA000;
- protected static final int BEGIN_ELEMENT_SHORT_INDEX_MAX = 0xFFF;
- /** End of an element, compact form.
- *
- * [END_ELEMENT_SHORT]
- * [begin_offset], the unsigned absolute value of the offset to the
- * matching BEGIN. (This is the same as the matching end_offset.)
- *
- */
- protected static final int END_ELEMENT_SHORT = 0xF10B;
- /** Begin of an element, non-compact form.
- *
- * [BEGIN_ELEMENT_LONG]
- * [end_offset], in 2 shorts. The position of the matching END_ELEMENT_LONG.
- * If the element straddles the gap, then end_offset is a negative offset
- * relative to data.length. (Therefore allocating more space for the
- * gap does not require adjusting any end_offset.) If the element and
- * and its children are all on the same side of the gap, then end_offset
- * is a positive offset relative to the BEGIN_ELEMENT_LONG word. (Hence
- * shifting an entire element when the gap is moved does not require
- * changing its end_offset.)
- *
- * Note that the space taken by a BEGIN_ELEMENT_LONG is the same that
- * needed for a BEGIN_ELEMENT_SHORT (but a END_ELEMENT_LONG takes much
- * more space than a END_ELEMENT_SHORT). This is to make it easier
- * to convert a BEGIN_ELEMENT_LONG to a BEGIN_ELEMENT_SHORT or vice
- * versa, as needed.
- */
- protected static final int BEGIN_ELEMENT_LONG = 0xF108;
- /** End of n element, non-compact form.
- *
- * [END_ELEMENT_LONG]
- * [index], 2 shorts where objects[index] is the element's type name and
- * objects[index+1] is the type object.
- * [begin_offset], in 2 shorts. The position of the matching
- * BEGIN_ELEMENT_LONG. If the element straddles the gap, then begin_offset
- * is the actual index (i.e. relative to the start of data) of the
- * matching BEGIN_ELEMENT_LONG. (Therefore allocating more space for the
- * gap does not require adjusting begin_offset.) If the element does not
- * straddle the gap, then begin_offset is a negative offset relative
- * to the END_ELEMENT_LONG word. (Hence shifting an entire element when
- * the gap is moved does not require changing its begin_offset.)
- * relative to data.length.
- * [parent_offset], in 2 shorts. The position of the outer BEGIN_ELEMENT_LONG,
- * BEGIN_ELEMENT_SHORT or BEGIN_DOCUMENT. If the difference straddles
- * the gap (i.e. either this element straddles the gap or the parent element
- * does and the gap precedes this element), then parent_offset is the
- * actual index of the parent element. Otherwise, then parent_offset is a
- * negative offset relative to the END_ELEMENT_LONG word.
- */
- protected static final int END_ELEMENT_LONG = 0xF10C;
- int currentParent = -1;
- public void ensureSpace(int needed)
- {
- int avail = gapEnd - gapStart;
- if (needed > avail)
- {
- int oldSize = data.length;
- int neededSize = oldSize - avail + needed;
- int newSize = 2 * oldSize;
- if (newSize < neededSize)
- newSize = neededSize;
- char[] tmp = new char[newSize];
- if (gapStart > 0)
- System.arraycopy(data, 0, tmp, 0, gapStart);
- int afterGap = oldSize - gapEnd;
- if (afterGap > 0)
- System.arraycopy(data, gapEnd, tmp, newSize - afterGap, afterGap);
- gapEnd = newSize - afterGap;
- data = tmp;
- }
- }
- public final void reserveObjects(int needed) {
- int newLength;
- Object[] tmp;
- if (objects == null) {
- newLength = needed > 100 ? needed : 100;
- tmp = new Object[newLength];
- } else {
- int oldLength = objects.length;
- if (oldLength < oindex + needed) {
- int grow = oldLength >> 1;
- if (needed > grow)
- grow = needed;
- newLength = oldLength + grow;
- } else if (oldLength > 2 * (oindex + needed) + 100) {
- newLength = oindex + needed + 100;
- }
- else
- return;
- tmp = new Object[newLength];
- System.arraycopy(objects, 0, tmp, 0, oindex);
- }
- objects = tmp;
- }
- public int find (Object arg1)
- {
- if (oindex == objects.length)
- reserveObjects(1);
- objects[oindex] = arg1;
- return oindex++;
- }
- /** Get a 32-bit int from the data array. */
- final protected int getIntN(int index)
- {
- return (data[index] << 16) | (data[index + 1] & 0xFFFF);
- }
- /** Get a 64-bit long from the data array. */
- final protected long getLongN(int index)
- {
- char[] data = this.data; // Optimization.
- return (data[index] & 0xFFFFL) << 48
- | (data[index+1] & 0xFFFFL) << 32
- | (data[index+2] & 0xFFFFL) << 16
- | (data[index+3] & 0xFFFFL);
- }
- final public void setIntN(int index, int i)
- {
- data[index] = (char) (i >> 16);
- data[index+1] = (char) i;
- }
- public void writePosition(SeqPosition position)
- {
- ensureSpace(3);
- // FIXME - no need for find to search in this case!
- int index = find(position.copy());
- data[gapStart++] = POSITION_REF_FOLLOWS;
- setIntN(gapStart, index);
- gapStart += 2;
- }
- public void writePosition(AbstractSequence seq, int ipos)
- {
- ensureSpace(5);
- data[gapStart] = POSITION_PAIR_FOLLOWS;
- int seq_index = find(seq);
- setIntN(gapStart+1, seq_index);
- setIntN(gapStart+3, ipos);
- gapStart += 5;
- }
- public void writeObject(Object v)
- {
- if (gapEnd - gapStart < 3)
- ensureSpace(3);
- int index = find(v);
- if (index < 0x1000)
- data[gapStart++] = (char) (OBJECT_REF_SHORT | index);
- else
- {
- data[gapStart++] = OBJECT_REF_FOLLOWS;
- setIntN(gapStart, index);
- gapStart += 2;
- }
- }
- /** Write/set the document-uri property of the current document.
- * Only allowed immediately following startDocument. */
- public void writeDocumentUri (Object uri)
- {
- ensureSpace(3);
- int index = find(uri);
- data[gapStart++] = DOCUMENT_URI;
- setIntN(gapStart, index);
- gapStart += 2;
- }
- public void writeComment(char[] chars, int offset, int length)
- {
- ensureSpace(3+length);
- int i = gapStart;
- data[i++] = COMMENT;
- setIntN(i, length);
- i += 2;
- System.arraycopy(chars, offset, data, i, length);
- gapStart = i + length;
- }
- public void writeComment(String comment, int offset, int length)
- {
- ensureSpace(3+length);
- int i = gapStart;
- data[i++] = COMMENT;
- setIntN(i, length);
- i += 2;
- comment.getChars(offset, offset+length, data, i);
- gapStart = i + length;
- }
- public void writeProcessingInstruction(String target, char[] content,
- int offset, int length)
- {
- ensureSpace(5+length);
- int i = gapStart;
- data[i++] = PROCESSING_INSTRUCTION;
- int index = find(target);
- setIntN(i, index);
- setIntN(i+2, length);
- i += 4;
- System.arraycopy(content, offset, data, i, length);
- gapStart = i + length;
- }
- public void writeProcessingInstruction(String target, String content,
- int offset, int length)
- {
- ensureSpace(5+length);
- int i = gapStart;
- data[i++] = PROCESSING_INSTRUCTION;
- int index = find(target);
- setIntN(i, index);
- setIntN(i+2, length);
- i += 4;
- content.getChars(offset, offset+length, data, i);
- gapStart = i + length;
- }
- public void startElement (Object type)
- {
- startElement(find(type));
- }
- public void startDocument ()
- {
- ensureSpace(5+1);
- gapEnd--;
- int p = gapStart;
- data[p] = BEGIN_DOCUMENT;
- if (docStart != 0)
- throw new Error("nested document");
- docStart = p+1;
- setIntN(p+1, gapEnd - data.length);
- setIntN(p+3, currentParent == -1 ? -1 : currentParent-p); // parent_offset
- currentParent = p;
- gapStart = p + 5;
- currentParent = p;
- data[gapEnd] = END_DOCUMENT;
- }
- public void endDocument()
- {
- if (data[gapEnd] != END_DOCUMENT || docStart <= 0
- || data[currentParent] != BEGIN_DOCUMENT)
- throw new Error("unexpected endDocument");
- // Move the END_DOCUMENT to before the gap.
- gapEnd++;
- setIntN(docStart, gapStart - docStart + 1);
- docStart = 0;
- data[gapStart++] = END_DOCUMENT;
- int parent = getIntN(currentParent+3);
- currentParent = parent >= -1 ? parent : currentParent + parent;
- }
- public void beginEntity (Object base)
- {
- // Ideally, we want to ignore a beginEnity if and only if it is redundant.
- // There are also problems in the current implementation with
- // nested (or maybe any non-top-level?) BEGIN_ENTITY nodes.
- // So for now, let's keep it simple.
- if (gapStart != 0)
- return;
- ensureSpace(BEGIN_ENTITY_SIZE+1);
- gapEnd--;
- int p = gapStart;
- data[p] = BEGIN_ENTITY;
- setIntN(p+1, find(base));
- setIntN(p+3, currentParent == -1 ? -1 : currentParent-p); // parent_offset
- gapStart = p + 5;
- currentParent = p;
- data[gapEnd] = END_ENTITY;
- }
- public void endEntity ()
- {
- // See comment in beginEntity.
- if (gapEnd + 1 != data.length || data[gapEnd] != END_ENTITY)
- return;
- if (/*data[gapEnd] != END_ENTITY || */
- data[currentParent] != BEGIN_ENTITY)
- throw new Error("unexpected endEntity");
- // Move the END_ENTITY to before the gap.
- gapEnd++;
- data[gapStart++] = END_ENTITY;
- int parent = getIntN(currentParent+3);
- currentParent = parent >= -1 ? parent : currentParent + parent;
- }
- public void startElement(int index)
- {
- ensureSpace(3 + 7);
- gapEnd -= 7;
- data[gapStart++] = BEGIN_ELEMENT_LONG;
- setIntN(gapStart, gapEnd - data.length); // end_offset
- gapStart += 2;
- data[gapEnd] = END_ELEMENT_LONG;
- setIntN(gapEnd + 1, index); // begin_offset
- setIntN(gapEnd + 3, gapStart - 3); // begin_offset
- setIntN(gapEnd + 5, currentParent); // parent_offset
- currentParent = gapStart - 3;
- }
- public void setElementName (int elementIndex, int nameIndex)
- {
- if (data[elementIndex] == BEGIN_ELEMENT_LONG)
- {
- int j = getIntN(elementIndex+1);
- elementIndex = j + (j < 0 ? data.length : elementIndex);
- }
- if (elementIndex < gapEnd)
- throw new Error("setElementName before gapEnd");
- setIntN(elementIndex + 1, nameIndex);
- }
- public void endElement ()
- {
- if (data[gapEnd] != END_ELEMENT_LONG)
- throw new Error("unexpected endElement");
- int index = getIntN(gapEnd + 1);
- int begin = getIntN(gapEnd + 3);
- int parent = getIntN(gapEnd + 5);
- currentParent = parent;
- gapEnd += 7;
- int offset = gapStart - begin;
- int parentOffset = begin - parent;
- if (index < BEGIN_ELEMENT_SHORT_INDEX_MAX
- && offset < 0x10000 && parentOffset < 0x10000)
- {
- data[begin] = (char) (BEGIN_ELEMENT_SHORT | index);
- data[begin + 1] = (char) offset; // end_offset
- data[begin + 2] = (char) parentOffset;
- data[gapStart] = END_ELEMENT_SHORT;
- data[gapStart + 1] = (char) offset; // begin_offset
- gapStart += 2;
- }
- else
- {
- data[begin] = BEGIN_ELEMENT_LONG;
- setIntN(begin + 1, offset);
- data[gapStart] = END_ELEMENT_LONG;
- setIntN(gapStart + 1, index);
- setIntN(gapStart + 3, - offset);
- if (parent >= gapStart || begin <= gapStart)
- parent -= gapStart;
- setIntN(gapStart + 5, parent);
- gapStart += 7;
- }
- }
- public void startAttribute (Object attrType)
- {
- startAttribute(find(attrType));
- }
- public void startAttribute (int index)
- {
- /* This needs to be tested. FIXME. Anyway only solves limited problem.
- // If there is whitespace and nothing else between the BEGIN_ELEMENT_LONG
- // and the current position, get rid of the spaces.
- int i = currentParent;
- if (i > 0 && (i += 3) < gapStart)
- {
- for (int j = i; ; j++)
- {
- if (j == gapStart)
- {
- gapStart = i;
- break;
- }
- char c = data[j];
- if (c != ' ' && c != '\t' && c != '\n' && c != '\r')
- break;
- }
- }
- */
- ensureSpace(5 + 1);
- gapEnd--;
- data[gapStart++] = BEGIN_ATTRIBUTE_LONG;
- if (attrStart != 0)
- throw new Error("nested attribute");
- attrStart = gapStart;
- setIntN(gapStart, index);
- setIntN(gapStart + 2, gapEnd - data.length);
- gapStart += 4;
- data[gapEnd] = END_ATTRIBUTE;
- }
- public void setAttributeName (int attrIndex, int nameIndex)
- {
- setIntN(attrIndex + 1, nameIndex);
- }
- public void endAttribute()
- {
- if (attrStart <= 0)
- return;
- if (data[gapEnd] != END_ATTRIBUTE)
- throw new Error("unexpected endAttribute");
- // Move the END_ATTRIBUTES to before the gap.
- gapEnd++;
- setIntN(attrStart+2, gapStart - attrStart + 1);
- attrStart = 0;
- data[gapStart++] = END_ATTRIBUTE;
- }
- public Consumer append (char c)
- {
- write(c);
- return this;
- }
- public void write (int c)
- {
- ensureSpace(3);
- if (c <= MAX_CHAR_SHORT)
- data[gapStart++] = (char) c;
- else if (c < 0x10000)
- {
- data[gapStart++] = CHAR_FOLLOWS;
- data[gapStart++] = (char) c;
- }
- else
- Char.print(c, this);
- }
- public void writeBoolean(boolean v)
- {
- ensureSpace(1);
- data[gapStart++] = v ? BOOL_TRUE : BOOL_FALSE;
- }
- public void writeByte(int v)
- {
- ensureSpace(1);
- data[gapStart++] = (char) (BYTE_PREFIX + (v & 0xFF));
- }
- public void writeInt(int v) {
- if (v >= MIN_INT_SHORT && v <= MAX_INT_SHORT) {
- ensureSpace(1);
- data[gapStart++] = (char) (INT_SHORT_ZERO + v);
- } else
- writeIntForce32(v);
- }
- public void writeIntForce32(int v) {
- ensureSpace(3);
- int pos = gapStart;
- data[pos++] = INT_FOLLOWS;
- setIntN(pos, v);
- gapStart = pos + 2;
- }
- public void writeLong(long v)
- {
- ensureSpace(5);
- data[gapStart++] = LONG_FOLLOWS;
- data[gapStart++] = (char) (v >>> 48);
- data[gapStart++] = (char) (v >>> 32);
- data[gapStart++] = (char) (v >>> 16);
- data[gapStart++] = (char) v;
- }
- public void writeFloat(float v)
- {
- ensureSpace(3);
- int i = Float.floatToIntBits(v);
- data[gapStart++] = FLOAT_FOLLOWS;
- data[gapStart++] = (char) (i >>> 16);
- data[gapStart++] = (char) i;
- }
- public void writeDouble(double v)
- {
- ensureSpace(5);
- long l = Double.doubleToLongBits(v);
- data[gapStart++] = DOUBLE_FOLLOWS;
- data[gapStart++] = (char) (l >>> 48);
- data[gapStart++] = (char) (l >>> 32);
- data[gapStart++] = (char) (l >>> 16);
- data[gapStart++] = (char) l;
- }
- public boolean ignoring()
- {
- return false;
- }
- public void writeJoiner ()
- {
- ensureSpace(1);
- data[gapStart++] = JOINER;
- }
- public void write(char[] buf, int off, int len)
- {
- if (len == 0)
- writeJoiner();
- ensureSpace(len);
- while (len > 0)
- {
- char ch = buf[off++];
- len--;
- if (ch <= MAX_CHAR_SHORT)
- data[gapStart++] = ch;
- else
- {
- write(ch);
- ensureSpace(len);
- }
- }
- }
- public void write (String str)
- {
- write(str, 0, str.length());
- }
- /* #ifdef use:java.lang.CharSequence */
- public void write (CharSequence str, int start, int length)
- /* #else */
- // public void write (String str, int start, int length)
- /* #endif */
- {
- if (length == 0)
- writeJoiner();
- ensureSpace(length);
- while (length > 0)
- {
- char ch = str.charAt(start++);
- length--;
- if (ch <= MAX_CHAR_SHORT)
- data[gapStart++] = ch;
- else
- {
- write(ch);
- ensureSpace(length);
- }
- }
- }
- public void writeCDATA (char[] chars, int offset, int length)
- {
- ensureSpace(3+length);
- int i = gapStart;
- data[i++] = CDATA_SECTION;
- setIntN(i, length);
- i += 2;
- System.arraycopy(chars, offset, data, i, length);
- gapStart = i + length;
- }
- /* #ifdef use:java.lang.CharSequence */
- public Consumer append (CharSequence csq)
- {
- if (csq == null)
- csq = "null";
- return append(csq, 0, csq.length());
- }
- public Consumer append (CharSequence csq, int start, int end)
- {
- if (csq == null)
- csq = "null";
- for (int i = start; i < end; i++)
- append(csq.charAt(i));
- return this;
- }
- /* #else */
- // public Consumer append (String str)
- // {
- // if (str == null)
- // str = "null";
- // int len = str.length();
- // for (int i = 0; i < len; i++)
- // append(str.charAt(i));
- // return this;
- // }
- /* #endif */
- public boolean isEmpty()
- {
- // FIXME does not work if we allow comment() entries!
- int pos = gapStart == 0 ? gapEnd : 0;
- return pos == data.length;
- }
- public int size()
- {
- int size = 0;
- int i = 0;
- for (;;)
- {
- i = nextPos(i);
- if (i == 0)
- return size;
- size++;
- }
- }
- public int createPos(int index, boolean isAfter)
- {
- return createRelativePos(0, index, isAfter);
- }
- public final int posToDataIndex (int ipos)
- {
- if (ipos == -1)
- return data.length;
- int index = ipos >>> 1;
- if ((ipos & 1) != 0)
- index--;
- if (index == gapStart)
- index += gapEnd - gapStart;
- if ((ipos & 1) != 0)
- {
- index = nextDataIndex(index);
- if (index < 0)
- return data.length;
- if (index == gapStart)
- index += gapEnd - gapStart;
- }
- return index;
- }
- public int firstChildPos (int ipos)
- {
- int index = gotoChildrenStart(posToDataIndex(ipos));
- if (index < 0)
- return 0;
- return index << 1;
- }
- public final int gotoChildrenStart(int index)
- {
- if (index == data.length)
- return -1;
- char datum = data[index];
- if ((datum >= BEGIN_ELEMENT_SHORT
- && datum <= BEGIN_ELEMENT_SHORT+BEGIN_ELEMENT_SHORT_INDEX_MAX)
- || datum == BEGIN_ELEMENT_LONG)
- index += 3;
- else if (datum == BEGIN_DOCUMENT || datum == BEGIN_ENTITY)
- index += 5;
- else
- return -1;
- for (;;)
- {
- if (index >= gapStart)
- index += gapEnd - gapStart;
- datum = data[index];
- if (datum == BEGIN_ATTRIBUTE_LONG)
- {
- int end = getIntN(index+3);
- index = end + (end < 0 ? data.length : index);
- }
- else if (datum == END_ATTRIBUTE || datum == JOINER)
- index++;
- else if (datum == DOCUMENT_URI)
- index += 3;
- else
- break;
- }
- return index;
- }
- public int parentPos (int ipos)
- {
- int index = posToDataIndex(ipos);
- for (;;)
- {
- index = parentOrEntityI(index);
- if (index == -1)
- return -1;
- if (data[index] != BEGIN_ENTITY)
- return index << 1;
- }
- }
- public int parentOrEntityPos (int ipos)
- {
- int index = parentOrEntityI(posToDataIndex(ipos));
- return index < 0 ? -1 : index << 1;
- }
- public int parentOrEntityI (int index)
- {
- if (index == data.length)
- return -1;
- char datum = data[index];
- if (datum == BEGIN_DOCUMENT || datum == BEGIN_ENTITY)
- {
- int parent_offset = getIntN(index+3);
- if (parent_offset >= -1)
- return parent_offset;
- else
- return index + parent_offset;
- }
- if (datum >= BEGIN_ELEMENT_SHORT
- && datum <= BEGIN_ELEMENT_SHORT+BEGIN_ELEMENT_SHORT_INDEX_MAX)
- {
- int parent_offset = data[index+2];
- return parent_offset == 0 ? -1 : index - parent_offset;
- }
- if (datum == BEGIN_ELEMENT_LONG)
- {
- int end_offset = getIntN(index+1);
- end_offset += end_offset < 0 ? data.length : index;
- int parent_offset = getIntN(end_offset+5);
- if (parent_offset == 0)
- return -1;
- if (parent_offset < 0)
- parent_offset += end_offset;
- return parent_offset;
- }
- for (;;)
- {
- if (index == gapStart)
- index = gapEnd;
- if (index == data.length)
- return -1;
- datum = data[index];
- switch (datum)
- {
- case END_ELEMENT_SHORT:
- return index - data[index+1];
- case END_ELEMENT_LONG:
- int begin_offset = getIntN(index+3);
- if (begin_offset < 0)
- begin_offset += index;
- return begin_offset;
- case END_ATTRIBUTE:
- index++;
- continue;
- case END_DOCUMENT:
- return -1;
- default:
- index = nextDataIndex(index);
- }
- if (index < 0)
- break;
- }
- return -1;
- }
- public int getAttributeCount (int parent)
- {
- int n = 0;
- for (int attr = firstAttributePos(parent);
- attr != 0 && getNextKind(attr) == Sequence.ATTRIBUTE_VALUE;
- attr = nextPos(attr))
- n++;
- return n;
- }
- public boolean gotoAttributesStart(TreePosition pos)
- {
- int index = gotoAttributesStart(pos.ipos >> 1);
- if (index < 0)
- return false;
- pos.push(this, index << 1);
- return true;
- }
- public int firstAttributePos (int ipos)
- {
- int index = gotoAttributesStart(posToDataIndex(ipos));
- return index < 0 ? 0 : index << 1;
- }
- public int gotoAttributesStart(int index)
- {
- if (index >= gapStart)
- index += gapEnd - gapStart;
- if (index == data.length)
- return -1;
- char datum = data[index];
- if ((datum >= BEGIN_ELEMENT_SHORT
- && datum <= BEGIN_ELEMENT_SHORT+BEGIN_ELEMENT_SHORT_INDEX_MAX)
- || datum == BEGIN_ELEMENT_LONG)
- return index + 3;
- else
- return -1;
- }
- public Object get (int index)
- {
- int i = 0;
- while (--index >= 0)
- {
- i = nextPos(i);
- if (i == 0)
- throw new IndexOutOfBoundsException();
- }
- return getPosNext(i);
- }
- public boolean consumeNext(int ipos, Consumer out)
- {
- if (! hasNext(ipos))
- return false;
- int start = posToDataIndex(ipos);
- int end = nextNodeIndex(start, -1 >>> 1);
- if (end == start)
- end = nextDataIndex(start);
- if (end >= 0)
- consumeIRange(start, end, out);
- return true;
- }
- public void consumePosRange(int startPos, int endPos, Consumer out)
- {
- consumeIRange(posToDataIndex(startPos), posToDataIndex(endPos), out);
- }
- public int consumeIRange(int startPosition, int endPosition, Consumer out)
- {
- int pos = startPosition;
- int limit = startPosition <= gapStart && endPosition > gapStart ? gapStart
- : endPosition;
- int index;
- for (;;)
- {
- if (pos >= limit)
- {
- if (pos == gapStart && endPosition > gapEnd)
- {
- pos = gapEnd;
- limit = endPosition;
- }
- else
- break;
- }
- char datum = data[pos++];
- if (datum <= MAX_CHAR_SHORT)
- {
- int start = pos - 1;
- int lim = limit;
- for (;;)
- {
- if (pos >= lim)
- break;
- datum = data[pos++];
- if (datum > MAX_CHAR_SHORT)
- {
- pos--;
- break;
- }
- }
- out.write(data, start, pos - start);
- continue;
- }
- if (datum >= OBJECT_REF_SHORT
- && datum <= OBJECT_REF_SHORT+OBJECT_REF_SHORT_INDEX_MAX)
- {
- out.writeObject(objects[datum-OBJECT_REF_SHORT]);
- continue;
- }
- if (datum >= BEGIN_ELEMENT_SHORT
- && datum <= BEGIN_ELEMENT_SHORT+BEGIN_ELEMENT_SHORT_INDEX_MAX)
- {
- index = datum-BEGIN_ELEMENT_SHORT;
- out.startElement(objects[index]);
- pos += 2;
- continue;
- }
- /*
- if ((datum & 0xFF00) == BYTE_PREFIX)
- {
- out.writeByte((byte) datum);
- continue;
- }
- */
- if (datum >= INT_SHORT_ZERO + MIN_INT_SHORT
- && datum <= INT_SHORT_ZERO + MAX_INT_SHORT)
- {
- out.writeInt(datum - INT_SHORT_ZERO);
- continue;
- }
- switch (datum)
- {
- case BEGIN_DOCUMENT:
- out.startDocument();
- pos += 4;
- continue;
- case END_DOCUMENT:
- out.endDocument();
- continue;
- case BEGIN_ENTITY:
- if (out instanceof TreeList)
- ((TreeList) out).beginEntity(objects[getIntN(pos)]);
- pos += 4;
- continue;
- case END_ENTITY:
- if (out instanceof TreeList)
- ((TreeList) out).endEntity();
- continue;
- case DOCUMENT_URI:
- if (out instanceof TreeList)
- ((TreeList) out).writeDocumentUri(objects[getIntN(pos)]);
- pos += 2;
- continue;
- case COMMENT:
- {
- int length = getIntN(pos);
- pos += 2;
- if (out instanceof XConsumer)
- ((XConsumer) out).writeComment(data, pos, length);
- pos += length;
- }
- continue;
- case CDATA_SECTION:
- {
- int length = getIntN(pos);
- pos += 2;
- if (out instanceof XConsumer)
- ((XConsumer) out).writeCDATA(data, pos, length);
- else
- out.write(data, pos, length);
- pos += length;
- }
- continue;
- case PROCESSING_INSTRUCTION:
- {
- String target = (String) objects[getIntN(pos)];
- int length = getIntN(pos+2);
- pos += 4;
- if (out instanceof XConsumer)
- ((XConsumer) out).writeProcessingInstruction(target, data,
- pos, length);
- pos += length;
- }
- continue;
- case BOOL_FALSE:
- case BOOL_TRUE:
- out.writeBoolean(datum != BOOL_FALSE);
- continue;
- case JOINER:
- out.write("");
- continue;
- case CHAR_FOLLOWS:
- out.write(data, pos, 1 + datum - CHAR_FOLLOWS);
- pos++;
- continue;
- case POSITION_PAIR_FOLLOWS:
- {
- AbstractSequence seq = (AbstractSequence) objects[getIntN(pos)];
- int ipos = getIntN(pos+2);
- if (out instanceof PositionConsumer)
- ((PositionConsumer) out).writePosition(seq, ipos);
- else
- out.writeObject(seq.getIteratorAtPos(ipos));
- pos += 4;
- }
- continue;
- case POSITION_REF_FOLLOWS:
- if (out instanceof PositionConsumer)
- {
- ((PositionConsumer) out).writePosition((SeqPosition) objects[getIntN(pos)]);
- pos += 2;
- continue;
- }
- // ... else fall through ...
- case OBJECT_REF_FOLLOWS:
- out.writeObject(objects[getIntN(pos)]);
- pos += 2;
- continue;
- case END_ELEMENT_SHORT:
- pos++;
- out.endElement();
- continue;
- case BEGIN_ELEMENT_LONG:
- index = getIntN(pos);
- index += index >= 0 ? pos - 1 : data.length;
- pos += 2;
- index = getIntN(index + 1);
- out.startElement(objects[index]);
- continue;
- case END_ELEMENT_LONG:
- index = getIntN(pos);
- out.endElement();
- pos += 6;
- continue;
- case BEGIN_ATTRIBUTE_LONG:
- index = getIntN(pos);
- out.startAttribute(objects[index]);
- pos += 4;
- continue;
- case END_ATTRIBUTE:
- out.endAttribute();
- continue;
- case INT_FOLLOWS:
- out.writeInt(getIntN(pos));
- pos += 2;
- continue;
- case FLOAT_FOLLOWS:
- out.writeFloat(Float.intBitsToFloat(getIntN(pos)));
- pos += 2;
- continue;
- case LONG_FOLLOWS:
- out.writeLong(getLongN(pos));
- pos += 4;
- continue;
- case DOUBLE_FOLLOWS:
- out.writeDouble(Double.longBitsToDouble(getLongN(pos)));
- pos += 4;
- continue;
- default:
- throw new Error("unknown code:"+(int) datum);
- }
- }
- return pos;
- }
- public void toString (String sep, StringBuffer sbuf)
- {
- int pos = 0;
- int limit = gapStart;
- int index;
- boolean seen = false;
- boolean inStartTag = false;
- boolean inAttribute = false;
- for (;;)
- {
- if (pos >= limit)
- {
- if (pos == gapStart)
- {
- pos = gapEnd;
- limit = data.length;
- if (pos == limit)
- break;
- }
- else
- break;
- }
- char datum = data[pos++];
- if (datum <= MAX_CHAR_SHORT)
- {
- int start = pos - 1;
- int lim = limit;
- for (;;)
- {
- if (pos >= lim)
- break;
- datum = data[pos++];
- if (datum > MAX_CHAR_SHORT)
- {
- pos--;
- break;
- }
- }
- if (inStartTag) { sbuf.append('>'); inStartTag = false; }
- sbuf.append(data, start, pos - start);
- seen = false;
- continue;
- }
- if (datum >= OBJECT_REF_SHORT
- && datum <= OBJECT_REF_SHORT+OBJECT_REF_SHORT_INDEX_MAX)
- {
- if (inStartTag) { sbuf.append('>'); inStartTag = false; }
- if (seen) sbuf.append(sep); else seen = true;
- sbuf.append(objects[datum-OBJECT_REF_SHORT]);
- continue;
- }
- if (datum >= BEGIN_ELEMENT_SHORT
- && datum <= BEGIN_ELEMENT_SHORT+BEGIN_ELEMENT_SHORT_INDEX_MAX)
- {
- if (inStartTag) { sbuf.append('>'); inStartTag = false; }
- index = datum-BEGIN_ELEMENT_SHORT;
- if (seen) sbuf.append(sep);
- sbuf.append('<');
- sbuf.append(objects[index].toString());
- pos += 2;
- seen = false;
- inStartTag = true;
- continue;
- }
- if (datum >= INT_SHORT_ZERO + MIN_INT_SHORT
- && datum <= INT_SHORT_ZERO + MAX_INT_SHORT)
- {
- if (inStartTag) { sbuf.append('>'); inStartTag = false; }
- if (seen) sbuf.append(sep); else seen = true;
- sbuf.append(datum - INT_SHORT_ZERO);
- continue;
- }
- switch (datum)
- {
- case BEGIN_DOCUMENT:
- case BEGIN_ENTITY:
- pos += 4;
- continue;
- case DOCUMENT_URI:
- pos += 2;
- continue;
- case COMMENT:
- if (inStartTag) { sbuf.append('>'); inStartTag = false; }
- index = getIntN(pos); // comment length
- pos += 2;
- sbuf.append("<!--");
- sbuf.append(data, pos, index);
- sbuf.append("-->");
- pos += index;
- continue;
- case CDATA_SECTION:
- if (inStartTag) { sbuf.append('>'); inStartTag = false; }
- index = getIntN(pos); // comment length
- pos += 2;
- sbuf.append("<![CDATA[");
- sbuf.append(data, pos, index);
- sbuf.append("]]>");
- pos += index;
- continue;
- case PROCESSING_INSTRUCTION:
- if (inStartTag) { sbuf.append('>'); inStartTag = false; }
- sbuf.append("<?");
- index = getIntN(pos); // target
- pos += 2;
- sbuf.append(objects[index]);
- index = getIntN(pos); // comment length
- pos += 2;
- if (index > 0)
- {
- sbuf.append(' ');
- sbuf.append(data, pos, index);
- pos += index;
- }
- sbuf.append("?>");
- continue;
- case END_DOCUMENT:
- case END_ENTITY:
- continue;
- case BOOL_FALSE:
- case BOOL_TRUE:
- if (inStartTag) { sbuf.append('>'); inStartTag = false; }
- if (seen) sbuf.append(sep); else seen = true;
- sbuf.append(datum != BOOL_FALSE);
- continue;
- case JOINER:
- continue;
- case CHAR_FOLLOWS:
- if (inStartTag) { sbuf.append('>'); inStartTag = false; }
- sbuf.append(data, pos, 1 + datum - CHAR_FOLLOWS);
- seen = false;
- pos++;
- continue;
- case POSITION_PAIR_FOLLOWS:
- if (inStartTag) { sbuf.append('>'); inStartTag = false; }
- if (seen) sbuf.append(sep); else seen = true;
- {
- AbstractSequence seq = (AbstractSequence) objects[getIntN(pos)];
- int ipos = getIntN(pos+2);
- // This could lead to to a lot of copying. FIXME.
- sbuf.append(seq.getIteratorAtPos(ipos));
- pos += 4;
- }
- continue;
- case POSITION_REF_FOLLOWS:
- case OBJECT_REF_FOLLOWS:
- if (inStartTag) { sbuf.append('>'); inStartTag = false; }
- if (seen) sbuf.append(sep); else seen = true;
- sbuf.append(objects[getIntN(pos)]);
- pos += 2;
- continue;
- case BEGIN_ELEMENT_LONG:
- index = getIntN(pos);
- index += index >= 0 ? pos - 1 : data.length;
- pos += 2;
- index = getIntN(index + 1);
- if (inStartTag) sbuf.append('>');
- else if (seen) sbuf.append(sep);
- sbuf.append('<');
- sbuf.append(objects[index]);
- seen = false;
- inStartTag = true;
- continue;
- case END_ELEMENT_LONG:
- case END_ELEMENT_SHORT:
- if (datum == END_ELEMENT_SHORT)
- {
- index = data[pos++];
- index = data[pos - 2 - index] - BEGIN_ELEMENT_SHORT;
- }
- else
- {
- index = getIntN(pos);
- pos += 6;
- }
- if (inStartTag)
- sbuf.append("/>");
- else
- {
- sbuf.append("</");
- sbuf.append(objects[index]);
- sbuf.append('>');
- }
- inStartTag = false;
- seen = true;
- continue;
- case BEGIN_ATTRIBUTE_LONG:
- index = getIntN(pos);
- sbuf.append(' ');
- sbuf.append(objects[index]);
- sbuf.append("=\"");
- inAttribute = true;
- inStartTag = false;
- pos += 4;
- continue;
- case END_ATTRIBUTE:
- sbuf.append('"');
- inAttribute = false;
- inStartTag = true;
- seen = false;
- continue;
- case INT_FOLLOWS:
- if (inStartTag) { sbuf.append('>'); inStartTag = false; }
- if (seen) sbuf.append(sep); else seen = true;
- sbuf.append(getIntN(pos));
- pos += 2;
- continue;
- case FLOAT_FOLLOWS:
- if (inStartTag) { sbuf.append('>'); inStartTag = false; }
- if (seen) sbuf.append(sep); else seen = true;
- sbuf.append(Float.intBitsToFloat(getIntN(pos)));
- pos += 2;
- continue;
- case LONG_FOLLOWS:
- if (inStartTag) { sbuf.append('>'); inStartTag = false; }
- if (seen) sbuf.append(sep); else seen = true;
- sbuf.append(getLongN(pos));
- pos += 4;
- continue;
- case DOUBLE_FOLLOWS:
- if (inStartTag) { sbuf.append('>'); inStartTag = false; }
- if (seen) sbuf.append(sep); else seen = true;
- sbuf.append(Double.longBitsToDouble(getLongN(pos)));
- pos += 4;
- continue;
- default:
- throw new Error("unknown code:"+(int) datum);
- }
- }
- }
- public boolean hasNext(int ipos)
- {
- int index = posToDataIndex(ipos);
- if (index == data.length)
- return false;
- char ch = data[index];
- return ch != END_ATTRIBUTE && ch != END_ELEMENT_SHORT
- && ch != END_ELEMENT_LONG && ch != END_DOCUMENT;
- }
- public int getNextKind(int ipos)
- {
- return getNextKindI(posToDataIndex(ipos));
- }
- public int getNextKindI (int index)
- {
- if (index == data.length)
- return Sequence.EOF_VALUE;
- char datum = data[index];
- if (datum <= MAX_CHAR_SHORT)
- return Sequence.CHAR_VALUE;
- if (datum >= OBJECT_REF_SHORT
- && datum <= OBJECT_REF_SHORT+OBJECT_REF_SHORT_INDEX_MAX)
- return Sequence.OBJECT_VALUE;
- if (datum >= BEGIN_ELEMENT_SHORT
- && datum <= BEGIN_ELEMENT_SHORT+BEGIN_ELEMENT_SHORT_INDEX_MAX)
- return Sequence.ELEMENT_VALUE;
- if ((datum & 0xFF00) == BYTE_PREFIX)
- return Sequence.TEXT_BYTE_VALUE;
- if (datum >= INT_SHORT_ZERO + MIN_INT_SHORT
- && datum <= INT_SHORT_ZERO + MAX_INT_SHORT)
- return Sequence.INT_S32_VALUE;
- switch (datum)
- {
- case BOOL_FALSE:
- case BOOL_TRUE:
- return Sequence.BOOLEAN_VALUE;
- case INT_FOLLOWS:
- return Sequence.INT_S32_VALUE;
- case LONG_FOLLOWS:
- return Sequence.INT_S64_VALUE;
- case FLOAT_FOLLOWS:
- return Sequence.FLOAT_VALUE;
- case DOUBLE_FOLLOWS:
- return Sequence.DOUBLE_VALUE;
- case CHAR_FOLLOWS:
- return Sequence.CHAR_VALUE;
- case BEGIN_DOCUMENT:
- return Sequence.DOCUMENT_VALUE;
- case BEGIN_ENTITY:
- return getNextKind((index+BEGIN_ENTITY_SIZE) << 1);
- case BEGIN_ELEMENT_LONG:
- return Sequence.ELEMENT_VALUE;
- case END_ELEMENT_SHORT:
- case END_ELEMENT_LONG:
- case END_ATTRIBUTE:
- case END_DOCUMENT:
- case END_ENTITY:
- return Sequence.EOF_VALUE;
- case BEGIN_ATTRIBUTE_LONG:
- return Sequence.ATTRIBUTE_VALUE;
- case CDATA_SECTION:
- return Sequence.CDATA_VALUE;
- case COMMENT:
- return Sequence.COMMENT_VALUE;
- case PROCESSING_INSTRUCTION:
- return Sequence.PROCESSING_INSTRUCTION_VALUE;
- case DOCUMENT_URI: // FIXME
- case POSITION_REF_FOLLOWS: // FIXME
- case POSITION_PAIR_FOLLOWS:
- case OBJECT_REF_FOLLOWS:
- case JOINER: // FIXME
- default:
- return Sequence.OBJECT_VALUE;
- }
- }
- public Object getNextTypeObject (int ipos)
- {
- int index = posToDataIndex(ipos);
- char datum;
- for (;;)
- {
- if (index == data.length)
- return null;
- datum = data[index];
- if (datum != BEGIN_ENTITY)
- break;
- index += BEGIN_ENTITY_SIZE;
- }
- if (datum >= BEGIN_ELEMENT_SHORT
- && datum <= BEGIN_ELEMENT_SHORT+BEGIN_ELEMENT_SHORT_INDEX_MAX)
- index = datum-BEGIN_ELEMENT_SHORT;
- else if (datum == BEGIN_ELEMENT_LONG)
- {
- int j = getIntN(index+1);
- j += j < 0 ? data.length : index;
- index = getIntN(j + 1);
- }
- else if (datum == BEGIN_ATTRIBUTE_LONG)
- index = getIntN(index + 1);
- else if (datum == PROCESSING_INSTRUCTION)
- index = getIntN(index + 1);
- else
- return null;
- return index < 0 ? null : objects[index];
- }
- public Object getPosPrevious(int ipos)
- {
- if ((ipos & 1) != 0 && ipos != -1)
- return getPosNext(ipos - 3);
- else
- return super.getPosPrevious(ipos);
- }
- private Object copyToList(int startPosition, int endPosition)
- {
- return new TreeList(this, startPosition, endPosition);
- }
- /** Return following value (like getPosNext), as an integer. */
- public int getPosNextInt (int ipos)
- {
- int index = posToDataIndex(ipos);
- if (index < data.length)
- {
- char datum = data[index];
- if (datum >= INT_SHORT_ZERO + MIN_INT_SHORT
- && datum <= INT_SHORT_ZERO + MAX_INT_SHORT)
- return datum-INT_SHORT_ZERO;
- if (datum == INT_FOLLOWS)
- return getIntN(index+1);
- }
- return ((Number) getPosNext(ipos)).intValue();
- }
- public Object getPosNext(int ipos)
- {
- int index = posToDataIndex(ipos);
- if (index == data.length)
- return Sequence.eofValue;
- char datum = data[index];
- if (datum <= MAX_CHAR_SHORT)
- return Convert.toObject(datum);
- if (datum >= OBJECT_REF_SHORT
- && datum <= OBJECT_REF_SHORT+OBJECT_REF_SHORT_INDEX_MAX)
- return objects[datum-OBJECT_REF_SHORT];
- if (datum >= BEGIN_ELEMENT_SHORT
- && datum <= BEGIN_ELEMENT_SHORT+BEGIN_ELEMENT_SHORT_INDEX_MAX)
- return copyToList(index, index + data[index+1] + 2);
- /*
- if ((datum & 0xFF00) == BYTE_PREFIX)
- return Sequence.TEXT_BYTE_VALUE;
- */
- if (datum >= INT_SHORT_ZERO + MIN_INT_SHORT
- && datum <= INT_SHORT_ZERO + MAX_INT_SHORT)
- return Convert.toObject(datum-INT_SHORT_ZERO);
- switch (datum)
- {
- case BEGIN_DOCUMENT:
- {
- int end_offset = getIntN(index+1);
- end_offset += end_offset < 0 ? data.length : index;
- end_offset++;
- /* Need to be careful about this.
- if (index == 0
- && (end_offset == data.length
- || (end_offset == gapStart && gapEnd == data.length)))
- return this;
- */
- return copyToList(index, end_offset);
- }
- case BOOL_FALSE:
- case BOOL_TRUE:
- return Convert.toObject(datum != BOOL_FALSE);
- case INT_FOLLOWS:
- return Convert.toObject(getIntN(index+1));
- case LONG_FOLLOWS:
- return Convert.toObject(getLongN(index+1));
- case FLOAT_FOLLOWS:
- return Convert.toObject(Float.intBitsToFloat(getIntN(index+1)));
- case DOUBLE_FOLLOWS:
- return Convert.toObject(Double.longBitsToDouble(getLongN(index+1)));
- case CHAR_FOLLOWS:
- return Convert.toObject(data[index+1]);
- case BEGIN_ATTRIBUTE_LONG:
- {
- int end_offset = getIntN(index+3);
- end_offset += end_offset < 0 ? data.length : index;
- return copyToList(index, end_offset+1);
- }
- case BEGIN_ELEMENT_LONG:
- {
- int end_offset = getIntN(index+1);
- end_offset += end_offset < 0 ? data.length : index;
- return copyToList(index, end_offset+7);
- }
- case END_ELEMENT_SHORT:
- case END_ELEMENT_LONG:
- case END_ATTRIBUTE:
- case END_DOCUMENT:
- return Sequence.eofValue;
- case POSITION_REF_FOLLOWS:
- case OBJECT_REF_FOLLOWS:
- return objects[getIntN(index+1)];
- case JOINER:
- return "";
- case POSITION_PAIR_FOLLOWS: //FIXME
- AbstractSequence seq = (AbstractSequence) objects[getIntN(index+1)];
- ipos = getIntN(index+3);
- return seq.getIteratorAtPos(ipos);
- default:
- throw unsupported("getPosNext, code="+Integer.toHexString(datum));
- }
- }
- public void stringValue (int startIndex, int endIndex, StringBuffer sbuf)
- {
- int index = startIndex;
- while (index < endIndex && index >= 0)
- index = stringValue(false, index, sbuf);
- }
- public int stringValue(int index, StringBuffer sbuf)
- {
- int next = nextNodeIndex(index, -1 >>> 1);
- if (next > index)
- {
- stringValue(index, next, sbuf);
- return index;
- }
- else
- return stringValue(false, index, sbuf);
- }
- public int stringValue(boolean inElement, int index, StringBuffer sbuf)
- {
- Object value = null;
- int doChildren = 0, j;
- if (index >= gapStart)
- index += gapEnd - gapStart;
- if (index == data.length)
- return -1;
- char datum = data[index];
- index++;
- boolean spaceNeeded = false;
- if (datum <= MAX_CHAR_SHORT)
- {
- sbuf.append(datum);
- return index;
- }
- if (datum >= OBJECT_REF_SHORT
- && datum <= OBJECT_REF_SHORT+OBJECT_REF_SHORT_INDEX_MAX)
- {
- if (spaceNeeded)
- sbuf.append(' ');
- value = objects[datum-OBJECT_REF_SHORT];
- spaceNeeded = false;
- }
- else if (datum >= BEGIN_ELEMENT_SHORT
- && datum <= BEGIN_ELEMENT_SHORT+BEGIN_ELEMENT_SHORT_INDEX_MAX)
- {
- doChildren = index + 2;
- index = data[index] + index + 1;
- }
- else if ((datum & 0xFF00) == BYTE_PREFIX)
- {
- sbuf.append(datum & 0xFF);
- return index;
- }
- else if (datum >= INT_SHORT_ZERO + MIN_INT_SHORT
- && datum <= INT_SHORT_ZERO + MAX_INT_SHORT)
- {
- sbuf.append((int) datum - INT_SHORT_ZERO);
- return index;
- }
- else
- {
- switch (datum)
- {
- case DOCUMENT_URI:
- return index + 2;
- case PROCESSING_INSTRUCTION:
- index += 2;
- /* ... fall through ... */
- case CDATA_SECTION:
- case COMMENT:
- {
- int length = getIntN(index);
- index += 2;
- if (! inElement || datum == CDATA_SECTION)
- sbuf.append(data, index, length);
- return index + length;
- }
- case BOOL_FALSE:
- case BOOL_TRUE:
- if (spaceNeeded)
- sbuf.append(' ');
- sbuf.append(datum != BOOL_FALSE);
- spaceNeeded = true;
- return index;
- case INT_FOLLOWS:
- if (spaceNeeded)
- sbuf.append(' ');
- sbuf.append(getIntN(index));
- spaceNeeded = true;
- return index + 2;
- case LONG_FOLLOWS:
- if (spaceNeeded)
- sbuf.append(' ');
- sbuf.append(getLongN(index));
- spaceNeeded = true;
- return index + 4;
- case FLOAT_FOLLOWS:
- if (spaceNeeded)
- sbuf.append(' ');
- sbuf.append(Float.intBitsToFloat(getIntN(index)));
- spaceNeeded = true;
- return index + 2;
- case DOUBLE_FOLLOWS:
- if (spaceNeeded)
- sbuf.append(' ');
- sbuf.append(Double.longBitsToDouble(getLongN(index)));
- spaceNeeded = true;
- return index + 4;
- case CHAR_FOLLOWS:
- spaceNeeded = false;
- sbuf.append(data[index]);
- return index + 1;
- case BEGIN_DOCUMENT:
- case BEGIN_ENTITY:
- doChildren = index + 4;
- index = nextDataIndex(index-1);
- break;
- case BEGIN_ELEMENT_LONG:
- spaceNeeded = false;
- doChildren = index + 2;
- j = getIntN(index);
- j += j < 0 ? data.length : index-1;
- index = j + 7;
- break;
- case JOINER:
- spaceNeeded = false;
- break;
- case END_ELEMENT_SHORT:
- case END_ELEMENT_LONG:
- case END_ATTRIBUTE:
- case END_DOCUMENT:
- case END_ENTITY:
- return -1;
- case BEGIN_ATTRIBUTE_LONG:
- if (! inElement)
- doChildren = index + 4;
- int end = getIntN(index+2);
- index = end + (end < 0 ? data.length + 1: index);
- break;
- case POSITION_PAIR_FOLLOWS:
- {
- AbstractSequence seq = (AbstractSequence) objects[getIntN(index)];
- int ipos = getIntN(index+2);
- ((TreeList) seq).stringValue(inElement, ipos >> 1, sbuf);
- index += 4;
- }
- break;
- case POSITION_REF_FOLLOWS:
- case OBJECT_REF_FOLLOWS:
- default:
- throw new Error("unimplemented: "+Integer.toHexString(datum)+" at:"+index);
- }
- }
- if (value != null)
- sbuf.append(value);
- if (doChildren > 0)
- {
- do
- {
- doChildren = stringValue(true, doChildren, sbuf);
- }
- while (doChildren >= 0);
- }
- return index;
- }
- public int createRelativePos(int istart, int offset, boolean isAfter)
- {
- if (isAfter)
- {
- if (offset == 0)
- {
- if ((istart & 1) != 0)
- return istart;
- if (istart == 0)
- return 1;
- }
- offset--;
- }
- if (offset < 0)
- throw unsupported("backwards createRelativePos");
- int pos = posToDataIndex(istart);
- while (--offset >= 0)
- {
- pos = nextDataIndex(pos);
- if (pos < 0)
- throw new IndexOutOfBoundsException();
- }
- if (pos >= gapEnd)
- pos -= gapEnd - gapStart;
- return isAfter ? ((pos + 1) << 1) | 1 : (pos << 1);
- }
- /** Skip all primitive content nodes. */
- public final int nextNodeIndex (int pos, int limit)
- {
- if ((limit | 0x80000000) == -1) // kludge
- limit = data.length;
- for (;;)
- {
- if (pos == gapStart)
- pos = gapEnd;
- if (pos >= limit)
- return pos;
- char datum = data[pos];
- if (datum <= MAX_CHAR_SHORT
- || (datum >= OBJECT_REF_SHORT
- && datum <= OBJECT_REF_SHORT+OBJECT_REF_SHORT_INDEX_MAX)
- || (datum >= INT_SHORT_ZERO + MIN_INT_SHORT
- && datum <= INT_SHORT_ZERO + MAX_INT_SHORT)
- || (datum & 0xFF00) == BYTE_PREFIX)
- {
- pos++;
- continue;
- }
- if (datum >= BEGIN_ELEMENT_SHORT
- && datum <= BEGIN_ELEMENT_SHORT+BEGIN_ELEMENT_SHORT_INDEX_MAX)
- return pos;
- switch (datum)
- {
- case DOCUMENT_URI:
- pos += 3;
- break;
- case JOINER:
- pos += 1;
- break;
- case PROCESSING_INSTRUCTION:
- case COMMENT:
- case BEGIN_DOCUMENT:
- case BEGIN_ELEMENT_LONG:
- case BEGIN_ATTRIBUTE_LONG:
- return pos;
- case BEGIN_ENTITY:
- pos += 5;
- break;
- case END_ELEMENT_SHORT:
- case END_ELEMENT_LONG:
- case END_ATTRIBUTE:
- case END_DOCUMENT:
- case END_ENTITY:
- return pos;
- case CDATA_SECTION:
- default:
- pos = nextDataIndex(pos);
- continue;
- }
- }
- }
- public int nextMatching(int startPos, ItemPredicate predicate,
- int endPos, boolean descend)
- {
- int start = posToDataIndex(startPos);
- int limit = posToDataIndex(endPos);
- int pos = start;
- if (predicate instanceof NodePredicate)
- pos = nextNodeIndex(pos, limit);
- boolean checkAttribute = false; // true if attribute nodes could match.
- boolean checkNode;
- boolean checkText;
- boolean checkElement; // true if element nodes could match.
- if (predicate instanceof ElementPredicate)
- {
- checkNode = true;
- checkElement = true;
- checkText = false;
- }
- else if (predicate instanceof AttributePredicate)
- {
- checkNode = true;
- checkElement = false;
- checkText = false;
- }
- else
- {
- checkNode = true;
- checkElement = true;
- checkText = true;
- }
- int next;
- for (;; pos = next)
- {
- if (pos == gapStart)
- pos = gapEnd;
- if (pos >= limit && limit != -1)
- return 0;
- int j;
- char datum = data[pos];
- if (datum <= MAX_CHAR_SHORT
- || (datum >= OBJECT_REF_SHORT
- && datum <= OBJECT_REF_SHORT+OBJECT_REF_SHORT_INDEX_MAX)
- || (datum >= INT_SHORT_ZERO + MIN_INT_SHORT
- && datum <= INT_SHORT_ZERO + MAX_INT_SHORT))
- {
- if (checkText && predicate.isInstancePos(this, pos << 1))
- {
- if (pos >= gapEnd)
- pos -= gapEnd - gapStart;
- return pos << 1;
- }
- next = pos + 1;
- continue;
- }
- switch (datum)
- {
- case DOCUMENT_URI:
- next = pos + 3;
- continue;
- case BEGIN_DOCUMENT:
- next = pos + 5;
- if (checkNode) break;
- continue;
- case BEGIN_ENTITY:
- next = pos + 5;
- continue;
- case POSITION_REF_FOLLOWS:
- case OBJECT_REF_FOLLOWS:
- case INT_FOLLOWS:
- case FLOAT_FOLLOWS:
- next = pos + 3;
- if (checkText) break;
- continue;
- case CHAR_FOLLOWS:
- next = pos + 2;
- continue;
- case END_ELEMENT_SHORT:
- if (! descend)
- return 0;
- next = pos + 2;
- continue;
- case POSITION_PAIR_FOLLOWS:
- next = pos + 5;
- if (checkText) break;
- continue;
- case END_ELEMENT_LONG:
- if (! descend)
- return 0;
- next = pos + 7;
- continue;
- case END_ATTRIBUTE:
- case END_DOCUMENT:
- if (! descend)
- return 0;
- /* ... fall through ...*/
- case END_ENTITY:
- next = pos + 1;
- continue;
- case BEGIN_ATTRIBUTE_LONG:
- if (checkNode)
- {
- j = getIntN(pos+3);
- next = j + 1 + (j < 0 ? data.length : pos);
- }
- else
- next = pos + 5;
- if (checkAttribute) break;
- continue;
- case BOOL_FALSE:
- case BOOL_TRUE:
- next = pos + 1;
- if (checkText) break;
- continue;
- case JOINER:
- next = pos + 1;
- continue;
- case LONG_FOLLOWS:
- case DOUBLE_FOLLOWS:
- next = pos + 5;
- if (checkText) break;
- continue;
- case PROCESSING_INSTRUCTION:
- next = pos + 5 + getIntN(pos+3);
- if (checkNode) break;
- continue;
- case COMMENT:
- next = pos + 3 + getIntN(pos+1);
- if (checkNode) break;
- continue;
- case CDATA_SECTION:
- next = pos + 3 + getIntN(pos+1);
- if (checkText) break;
- continue;
- case BEGIN_ELEMENT_LONG:
- if (descend)
- next = pos + 3;
- else
- {
- j = getIntN(pos+1);
- next = j + (j < 0 ? data.length : pos) + 7;
- }
- if (checkElement) break;
- continue;
- default:
- if (datum >= BEGIN_ELEMENT_SHORT
- && datum <= BEGIN_ELEMENT_SHORT+BEGIN_ELEMENT_SHORT_INDEX_MAX)
- {
- if (descend)
- next = pos + 3;
- else
- next = pos + data[pos+1] + 2;
- if (checkElement) break;
- }
- else
- throw new Error("unknown code:"+(int) datum);
- continue;
- }
- if (pos > start && predicate.isInstancePos(this, pos << 1))
- {
- if (pos >= gapEnd)
- pos -= gapEnd - gapStart;
- return pos << 1;
- }
- }
- }
- public int nextPos (int position)
- {
- int index = posToDataIndex(position);
- if (index == data.length)
- return 0;
- if (index >= gapEnd)
- index -= gapEnd - gapStart;
- return (index << 1) + 3;
- }
- public final int nextDataIndex(int pos)
- {
- if (pos == gapStart)
- pos = gapEnd;
- if (pos == data.length)
- return -1;
- int j;
- char datum = data[pos++];
- if (datum <= MAX_CHAR_SHORT
- || (datum >= OBJECT_REF_SHORT
- && datum <= OBJECT_REF_SHORT+OBJECT_REF_SHORT_INDEX_MAX)
- || (datum >= INT_SHORT_ZERO + MIN_INT_SHORT
- && datum <= INT_SHORT_ZERO + MAX_INT_SHORT))
- return pos;
- if (datum >= BEGIN_ELEMENT_SHORT
- && datum <= BEGIN_ELEMENT_SHORT+BEGIN_ELEMENT_SHORT_INDEX_MAX)
- return data[pos] + pos + 1;
- switch (datum)
- {
- case BEGIN_DOCUMENT:
- j = getIntN(pos);
- j += j < 0 ? data.length : pos-1;
- return j + 1;
- case BEGIN_ENTITY:
- j = pos + (BEGIN_ENTITY_SIZE-1);
- for (;;)
- {
- if (j == gapStart)
- j = gapEnd;
- if (j == data.length)
- return -1; // actually error.
- if (data[j] == END_ENTITY)
- return j + 1;
- j = nextDataIndex(j);
- }
- case BOOL_FALSE:
- case BOOL_TRUE:
- case JOINER:
- return pos;
- case CHAR_FOLLOWS:
- return pos + 1;
- case POSITION_REF_FOLLOWS:
- case OBJECT_REF_FOLLOWS:
- case INT_FOLLOWS:
- case FLOAT_FOLLOWS:
- return pos + 2;
- case POSITION_PAIR_FOLLOWS:
- return pos + 4;
- case END_ELEMENT_SHORT:
- case END_ELEMENT_LONG:
- case END_ATTRIBUTE:
- case END_DOCUMENT:
- case END_ENTITY:
- return -1;
- case BEGIN_ELEMENT_LONG:
- j = getIntN(pos);
- j += j < 0 ? data.length : pos-1;
- return j + 7;
- case BEGIN_ATTRIBUTE_LONG:
- j = getIntN(pos+2);
- j += j < 0 ? data.length : pos-1;
- return j + 1;
- case LONG_FOLLOWS:
- case DOUBLE_FOLLOWS:
- return pos + 4;
- case PROCESSING_INSTRUCTION:
- pos += 2;
- // ... fall through ...
- case CDATA_SECTION:
- case COMMENT:
- return pos + 2 + getIntN(pos);
- default:
- throw new Error("unknown code:"+Integer.toHexString((int) datum));
- }
- }
- public Object documentUriOfPos (int pos)
- {
- int index = posToDataIndex(pos);
- if (index == data.length)
- return null;
- if (data[index] == BEGIN_DOCUMENT)
- {
- int next = index + 5;
- if (next == gapStart)
- next = gapEnd;
- if (next < data.length && data[next] == DOCUMENT_URI)
- return objects[getIntN(next+1)];
- }
- return null;
- }
- /** Compare two positions, and indicate their relative order. */
- public int compare(int ipos1, int ipos2)
- {
- // It's difficult to optimize this, because because if (say) isAfter(ipos1)
- // then we need nextDataIndex((ipos1>>>1)-1). In that case comparing
- // (ipos1>>>1)-1 and (pos2>>>1)-1 tells us nothing, since the former
- // could be a BEGIN_ELEMENT, while the latter might be a node inside
- // the element.
- int i1 = posToDataIndex(ipos1);
- int i2 = posToDataIndex(ipos2);
- return i1 < i2 ? -1 : i1 > i2 ? 1 : 0;
- }
- protected int getIndexDifference(int ipos1, int ipos0)
- {
- int i0 = posToDataIndex(ipos0);
- int i1 = posToDataIndex(ipos1);
- boolean negate = false;
- if (i0 > i1)
- {
- negate = true;
- int i = i1; i1 = i0; i0 = i;
- }
- int i = 0;
- while (i0 < i1)
- {
- i0 = nextDataIndex(i0);
- i++;
- }
- return negate ? -i : i;
- }
- public int nextIndex(int ipos)
- {
- return getIndexDifference(ipos, startPos());
- }
-
- public int hashCode()
- {
- // Calculating a real hashCode is real pain.
- return System.identityHashCode(this);
- }
- public void consume(Consumer out)
- {
- consumeIRange(0, data.length, out);
- }
- public void statistics ()
- {
- java.io.PrintWriter out = new java.io.PrintWriter(System.out);
- statistics(out);
- out.flush();
- }
- public void statistics (java.io.PrintWriter out)
- {
- out.print("data array length: "); out.println(data.length);
- out.print("data array gap: "); out.println(gapEnd-gapStart);
- out.print("object array length: "); out.println(objects.length);
- }
- // /* DEBUGGING
- public void dump ()
- {
- java.io.PrintWriter out = new java.io.PrintWriter(System.out);
- dump(out);
- out.flush();
- }
- public void dump (java.io.PrintWriter out)
- {
- out.println(getClass().getName()+" @"+Integer.toHexString(System.identityHashCode(this))
- + " gapStart:"+gapStart+" gapEnd:"+gapEnd+" length:"+data.length);
- dump(out, 0, data.length);
- }
- public void dump (java.io.PrintWriter out, int start, int limit)
- {
- int toskip = 0;
- // Skip follow-on words.
- boolean skipFollowingWords = true;
- for (int i = start; i < limit; i++)
- {
-
- if (i < gapStart || i >= gapEnd)
- {
- int j; long l;
- int ch = data[i];
- out.print(""+i+": 0x"+Integer.toHexString(ch)+'='+((short) ch));
- if (--toskip < 0)
- {
- if (ch <= MAX_CHAR_SHORT)
- {
- if (ch >= ' ' && ch < 127)
- out.print("='"+((char)ch)+"'");
- else if (ch=='\n')
- out.print("='\\n'");
- else
- out.print("='\\u"+Integer.toHexString(ch)+"'");
- }
- else if (ch >= OBJECT_REF_SHORT
- && ch <= OBJECT_REF_SHORT+OBJECT_REF_SHORT_INDEX_MAX)
- {
- ch = ch - OBJECT_REF_SHORT;
- Object obj = objects[ch];
- out.print("=Object#");
- out.print((int)ch);
- out.print('=');
- out.print(obj);
- if (obj != null) {
- out.print(':');
- out.print(obj.getClass().getName());
- }
- out.print('@');
- out.print(Integer.toHexString(System.identityHashCode(obj)));
- }
- else if (ch >= BEGIN_ELEMENT_SHORT
- && ch <= BEGIN_ELEMENT_SHORT+BEGIN_ELEMENT_SHORT_INDEX_MAX)
- {
- ch = ch - BEGIN_ELEMENT_SHORT;
- j = data[i+1] + i;
- out.print("=BEGIN_ELEMENT_SHORT end:"+j+" index#"+((int)ch)+"=<"+objects[ch]+'>');
- toskip = 2;
- }
- else if (ch >= INT_SHORT_ZERO + MIN_INT_SHORT
- && ch <= INT_SHORT_ZERO + MAX_INT_SHORT)
- {
- out.print("= INT_SHORT:"+(ch-INT_SHORT_ZERO));
- }
- else
- {
- switch (ch)
- {
- case INT_FOLLOWS:
- j = getIntN(i+1);
- out.print("=INT_FOLLOWS value:"+j);
- toskip = 2;
- break;
- case LONG_FOLLOWS:
- l = getLongN(i+1);
- out.print("=LONG_FOLLOWS value:"+l);
- toskip = 4;
- break;
- case FLOAT_FOLLOWS:
- j = getIntN(i+1);
- out.write("=FLOAT_FOLLOWS value:"
- +Float.intBitsToFloat(j));
- toskip = 2;
- break;
- case DOUBLE_FOLLOWS:
- l = getLongN(i+1);
- out.print("=DOUBLE_FOLLOWS value:"
- +Double.longBitsToDouble(l));
- toskip = 4;
- break;
- case BEGIN_DOCUMENT:
- j = getIntN(i+1);
- j += j < 0 ? data.length : i;
- out.print("=BEGIN_DOCUMENT end:");
- out.print(j);
- out.print(" parent:");
- j = getIntN(i+3);
- out.print(j);
- toskip = 4;
- break;
- case BEGIN_ENTITY:
- j = getIntN(i+1);
- out.print("=BEGIN_ENTITY base:");
- out.print(j);
- out.print(" parent:");
- j = getIntN(i+3);
- out.print(j);
- toskip = 4;
- break;
- case END_ENTITY:
- out.print("=END_ENTITY");
- break;
- case DOCUMENT_URI:
- out.print("=DOCUMENT_URI: ");
- j = getIntN(i+1);
- out.print(objects[j]);
- toskip = 2;
- break;
- case COMMENT:
- out.print("=COMMENT: '");
- j = getIntN(i+1);
- out.write(data, i+3, j);
- out.print('\'');
- toskip = 2+j;
- break;
- case CDATA_SECTION:
- out.print("=CDATA: '");
- j = getIntN(i+1);
- out.write(data, i+3, j);
- out.print('\'');
- toskip = 2+j;
- break;
- case PROCESSING_INSTRUCTION:
- out.print("=PROCESSING_INSTRUCTION: ");
- j = getIntN(i+1);
- out.print(objects[j]);
- out.print(" '");
- j = getIntN(i+3);
- out.write(data, i+5, j);
- out.print('\'');
- toskip = 4+j;
- break;
- case END_DOCUMENT:
- out.print("=END_DOCUMENT");
- break;
- case BOOL_FALSE: out.print("= false"); break;
- case BOOL_TRUE: out.print("= true"); break;
- case JOINER: out.print("= joiner"); break;
- case CHAR_FOLLOWS:
- out.print("=CHAR_FOLLOWS"); toskip = 1; break;
- case POSITION_REF_FOLLOWS:
- case OBJECT_REF_FOLLOWS:
- toskip = 2; break;
- case END_ELEMENT_SHORT:
- out.print("=END_ELEMENT_SHORT begin:");
- j = i - data[i+1];
- out.print(j);
- j = data[j] - BEGIN_ELEMENT_SHORT;
- out.print(" -> #");
- out.print(j);
- out.print("=<");
- out.print(objects[j]);
- out.print('>');
- toskip = 1; break;
- case BEGIN_ELEMENT_LONG:
- j = getIntN(i+1);
- j += j < 0 ? data.length : i;
- out.print("=BEGIN_ELEMENT_LONG end:");
- out.print(j);
- j = getIntN(j + 1);
- out.print(" -> #");
- out.print(j);
- if (j >= 0 && j+1 < objects.length)
- out.print("=<"+objects[j]+'>');
- else
- out.print("=<out-of-bounds>");
- toskip = 2;
- break;
- case END_ELEMENT_LONG:
- j = getIntN(i+1);
- out.print("=END_ELEMENT_LONG name:"+j
- +"=<"+objects[j]+'>');
- j = getIntN(i+3);
- j = j < 0 ? i + j : j;
- out.print(" begin:"+j);
- j = getIntN(i+5);
- j = j < 0 ? i + j : j;
- out.print(" parent:"+j);
- toskip = 6;
- break;
- case BEGIN_ATTRIBUTE_LONG:
- j = getIntN(i+1);
- out.print("=BEGIN_ATTRIBUTE name:"+j
- +"="+objects[j]);
- j = getIntN(i+3);
- j += j < 0 ? data.length : i;
- out.print(" end:"+j);
- toskip = 4;
- break;
- case END_ATTRIBUTE: out.print("=END_ATTRIBUTE"); break;
- case POSITION_PAIR_FOLLOWS:
- out.print("=POSITION_PAIR_FOLLOWS seq:");
- {
- j = getIntN(i+1); out.print(j);
- out.print('=');
- Object seq = objects[j];
- out.print(seq==null?null:seq.getClass().getName());
- out.print('@');
- if (seq == null) out.print("null");
- else out.print(Integer.toHexString(System.identityHashCode(seq)));
- out.print(" ipos:");
- out.print(getIntN(i+3));
- }
- toskip = 4;
- /*
- AbstractSequence seq = (AbstractSequence) objects[getIntN(i+1)];
- ipos = getIntN(i+3);
- */
- break;
- }
- }
- }
- out.println();
- if (skipFollowingWords && toskip > 0)
- {
- i += toskip;
- toskip = 0;
- }
- }
- }
- }
- // DEBUGGING */
- }
|