|
1 /* |
|
2 * Copyright (c) 2004, 2013, Oracle and/or its affiliates. All rights reserved. |
|
3 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. |
|
4 * |
|
5 * This code is free software; you can redistribute it and/or modify it |
|
6 * under the terms of the GNU General Public License version 2 only, as |
|
7 * published by the Free Software Foundation. Oracle designates this |
|
8 * particular file as subject to the "Classpath" exception as provided |
|
9 * by Oracle in the LICENSE file that accompanied this code. |
|
10 * |
|
11 * This code is distributed in the hope that it will be useful, but WITHOUT |
|
12 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or |
|
13 * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License |
|
14 * version 2 for more details (a copy is included in the LICENSE file that |
|
15 * accompanied this code). |
|
16 * |
|
17 * You should have received a copy of the GNU General Public License version |
|
18 * 2 along with this work; if not, write to the Free Software Foundation, |
|
19 * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. |
|
20 * |
|
21 * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA |
|
22 * or visit www.oracle.com if you need additional information or have any |
|
23 * questions. |
|
24 * |
|
25 * THIS FILE WAS MODIFIED BY SUN MICROSYSTEMS, INC. |
|
26 */ |
|
27 |
|
28 package com.sun.xml.internal.fastinfoset.stax; |
|
29 |
|
30 import com.sun.xml.internal.fastinfoset.Decoder; |
|
31 import com.sun.xml.internal.fastinfoset.DecoderStateTables; |
|
32 import com.sun.xml.internal.fastinfoset.EncodingConstants; |
|
33 import com.sun.xml.internal.fastinfoset.OctetBufferListener; |
|
34 import com.sun.xml.internal.fastinfoset.QualifiedName; |
|
35 import com.sun.xml.internal.fastinfoset.algorithm.BuiltInEncodingAlgorithmFactory; |
|
36 import com.sun.xml.internal.fastinfoset.sax.AttributesHolder; |
|
37 import com.sun.xml.internal.fastinfoset.util.CharArray; |
|
38 import com.sun.xml.internal.fastinfoset.util.CharArrayString; |
|
39 import java.io.IOException; |
|
40 import java.io.InputStream; |
|
41 import java.util.Iterator; |
|
42 import java.util.NoSuchElementException; |
|
43 import javax.xml.namespace.NamespaceContext; |
|
44 import javax.xml.namespace.QName; |
|
45 import javax.xml.stream.Location; |
|
46 import javax.xml.stream.XMLStreamException; |
|
47 import javax.xml.stream.XMLStreamReader; |
|
48 import com.sun.xml.internal.org.jvnet.fastinfoset.EncodingAlgorithm; |
|
49 import com.sun.xml.internal.org.jvnet.fastinfoset.EncodingAlgorithmException; |
|
50 import com.sun.xml.internal.org.jvnet.fastinfoset.EncodingAlgorithmIndexes; |
|
51 import com.sun.xml.internal.org.jvnet.fastinfoset.FastInfosetException; |
|
52 import com.sun.xml.internal.fastinfoset.CommonResourceBundle; |
|
53 import com.sun.xml.internal.fastinfoset.org.apache.xerces.util.XMLChar; |
|
54 import com.sun.xml.internal.fastinfoset.util.DuplicateAttributeVerifier; |
|
55 import java.util.logging.Level; |
|
56 import java.util.logging.Logger; |
|
57 import com.sun.xml.internal.org.jvnet.fastinfoset.stax.FastInfosetStreamReader; |
|
58 |
|
59 /** |
|
60 * The Fast Infoset StAX parser. |
|
61 * <p> |
|
62 * Instantiate this parser to parse a fast infoset document in accordance |
|
63 * with the StAX API. |
|
64 * |
|
65 * <p> |
|
66 * More than one fast infoset document may be decoded from the |
|
67 * {@link java.io.InputStream}. |
|
68 */ |
|
69 public class StAXDocumentParser extends Decoder |
|
70 implements XMLStreamReader, FastInfosetStreamReader, OctetBufferListener { |
|
71 private static final Logger logger = Logger.getLogger(StAXDocumentParser.class.getName()); |
|
72 |
|
73 protected static final int INTERNAL_STATE_START_DOCUMENT = 0; |
|
74 protected static final int INTERNAL_STATE_START_ELEMENT_TERMINATE = 1; |
|
75 protected static final int INTERNAL_STATE_SINGLE_TERMINATE_ELEMENT_WITH_NAMESPACES = 2; |
|
76 protected static final int INTERNAL_STATE_DOUBLE_TERMINATE_ELEMENT = 3; |
|
77 protected static final int INTERNAL_STATE_END_DOCUMENT = 4; |
|
78 protected static final int INTERNAL_STATE_VOID = -1; |
|
79 |
|
80 protected int _internalState; |
|
81 |
|
82 /** |
|
83 * Current event |
|
84 */ |
|
85 protected int _eventType; |
|
86 |
|
87 /** |
|
88 * Stack of qualified names and namespaces |
|
89 */ |
|
90 protected QualifiedName[] _qNameStack = new QualifiedName[32]; |
|
91 protected int[] _namespaceAIIsStartStack = new int[32]; |
|
92 protected int[] _namespaceAIIsEndStack = new int[32]; |
|
93 protected int _stackCount = -1; |
|
94 |
|
95 protected String[] _namespaceAIIsPrefix = new String[32]; |
|
96 protected String[] _namespaceAIIsNamespaceName = new String[32]; |
|
97 protected int[] _namespaceAIIsPrefixIndex = new int[32]; |
|
98 protected int _namespaceAIIsIndex; |
|
99 |
|
100 /** |
|
101 * Namespaces associated with START_ELEMENT or END_ELEMENT |
|
102 */ |
|
103 protected int _currentNamespaceAIIsStart; |
|
104 protected int _currentNamespaceAIIsEnd; |
|
105 |
|
106 /** |
|
107 * Qualified name associated with START_ELEMENT or END_ELEMENT. |
|
108 */ |
|
109 protected QualifiedName _qualifiedName; |
|
110 |
|
111 /** |
|
112 * List of attributes |
|
113 */ |
|
114 protected AttributesHolder _attributes = new AttributesHolder(); |
|
115 |
|
116 protected boolean _clearAttributes = false; |
|
117 |
|
118 /** |
|
119 * Characters associated with event. |
|
120 */ |
|
121 protected char[] _characters; |
|
122 protected int _charactersOffset; |
|
123 |
|
124 protected String _algorithmURI; |
|
125 protected int _algorithmId; |
|
126 protected boolean _isAlgorithmDataCloned; |
|
127 protected byte[] _algorithmData; |
|
128 protected int _algorithmDataOffset; |
|
129 protected int _algorithmDataLength; |
|
130 |
|
131 /** |
|
132 * State for processing instruction |
|
133 */ |
|
134 protected String _piTarget; |
|
135 protected String _piData; |
|
136 |
|
137 protected NamespaceContextImpl _nsContext = new NamespaceContextImpl(); |
|
138 |
|
139 protected String _characterEncodingScheme; |
|
140 |
|
141 protected StAXManager _manager; |
|
142 |
|
143 public StAXDocumentParser() { |
|
144 reset(); |
|
145 _manager = new StAXManager(StAXManager.CONTEXT_READER); |
|
146 } |
|
147 |
|
148 public StAXDocumentParser(InputStream s) { |
|
149 this(); |
|
150 setInputStream(s); |
|
151 _manager = new StAXManager(StAXManager.CONTEXT_READER); |
|
152 } |
|
153 |
|
154 public StAXDocumentParser(InputStream s, StAXManager manager) { |
|
155 this(s); |
|
156 _manager = manager; |
|
157 } |
|
158 |
|
159 @Override |
|
160 public void setInputStream(InputStream s) { |
|
161 super.setInputStream(s); |
|
162 reset(); |
|
163 } |
|
164 |
|
165 @Override |
|
166 public void reset() { |
|
167 super.reset(); |
|
168 if (_internalState != INTERNAL_STATE_START_DOCUMENT && |
|
169 _internalState != INTERNAL_STATE_END_DOCUMENT) { |
|
170 |
|
171 for (int i = _namespaceAIIsIndex - 1; i >= 0; i--) { |
|
172 _prefixTable.popScopeWithPrefixEntry(_namespaceAIIsPrefixIndex[i]); |
|
173 } |
|
174 |
|
175 _stackCount = -1; |
|
176 |
|
177 _namespaceAIIsIndex = 0; |
|
178 _characters = null; |
|
179 _algorithmData = null; |
|
180 } |
|
181 |
|
182 _characterEncodingScheme = "UTF-8"; |
|
183 _eventType = START_DOCUMENT; |
|
184 _internalState = INTERNAL_STATE_START_DOCUMENT; |
|
185 } |
|
186 |
|
187 protected void resetOnError() { |
|
188 super.reset(); |
|
189 |
|
190 if (_v != null) { |
|
191 _prefixTable.clearCompletely(); |
|
192 } |
|
193 _duplicateAttributeVerifier.clear(); |
|
194 |
|
195 _stackCount = -1; |
|
196 |
|
197 _namespaceAIIsIndex = 0; |
|
198 _characters = null; |
|
199 _algorithmData = null; |
|
200 |
|
201 _eventType = START_DOCUMENT; |
|
202 _internalState = INTERNAL_STATE_START_DOCUMENT; |
|
203 } |
|
204 |
|
205 // -- XMLStreamReader Interface ------------------------------------------- |
|
206 |
|
207 public Object getProperty(java.lang.String name) |
|
208 throws java.lang.IllegalArgumentException { |
|
209 if (_manager != null) { |
|
210 return _manager.getProperty(name); |
|
211 } |
|
212 return null; |
|
213 } |
|
214 |
|
215 public int next() throws XMLStreamException { |
|
216 try { |
|
217 if (_internalState != INTERNAL_STATE_VOID) { |
|
218 switch (_internalState) { |
|
219 case INTERNAL_STATE_START_DOCUMENT: |
|
220 decodeHeader(); |
|
221 processDII(); |
|
222 |
|
223 _internalState = INTERNAL_STATE_VOID; |
|
224 break; |
|
225 case INTERNAL_STATE_START_ELEMENT_TERMINATE: |
|
226 if (_currentNamespaceAIIsEnd > 0) { |
|
227 for (int i = _currentNamespaceAIIsEnd - 1; i >= _currentNamespaceAIIsStart; i--) { |
|
228 _prefixTable.popScopeWithPrefixEntry(_namespaceAIIsPrefixIndex[i]); |
|
229 } |
|
230 _namespaceAIIsIndex = _currentNamespaceAIIsStart; |
|
231 } |
|
232 |
|
233 // Pop information off the stack |
|
234 popStack(); |
|
235 |
|
236 _internalState = INTERNAL_STATE_VOID; |
|
237 return _eventType = END_ELEMENT; |
|
238 case INTERNAL_STATE_SINGLE_TERMINATE_ELEMENT_WITH_NAMESPACES: |
|
239 // Undeclare namespaces |
|
240 for (int i = _currentNamespaceAIIsEnd - 1; i >= _currentNamespaceAIIsStart; i--) { |
|
241 _prefixTable.popScopeWithPrefixEntry(_namespaceAIIsPrefixIndex[i]); |
|
242 } |
|
243 _namespaceAIIsIndex = _currentNamespaceAIIsStart; |
|
244 _internalState = INTERNAL_STATE_VOID; |
|
245 break; |
|
246 case INTERNAL_STATE_DOUBLE_TERMINATE_ELEMENT: |
|
247 // Undeclare namespaces |
|
248 if (_currentNamespaceAIIsEnd > 0) { |
|
249 for (int i = _currentNamespaceAIIsEnd - 1; i >= _currentNamespaceAIIsStart; i--) { |
|
250 _prefixTable.popScopeWithPrefixEntry(_namespaceAIIsPrefixIndex[i]); |
|
251 } |
|
252 _namespaceAIIsIndex = _currentNamespaceAIIsStart; |
|
253 } |
|
254 |
|
255 if (_stackCount == -1) { |
|
256 _internalState = INTERNAL_STATE_END_DOCUMENT; |
|
257 return _eventType = END_DOCUMENT; |
|
258 } |
|
259 |
|
260 // Pop information off the stack |
|
261 popStack(); |
|
262 |
|
263 _internalState = (_currentNamespaceAIIsEnd > 0) ? |
|
264 INTERNAL_STATE_SINGLE_TERMINATE_ELEMENT_WITH_NAMESPACES : |
|
265 INTERNAL_STATE_VOID; |
|
266 return _eventType = END_ELEMENT; |
|
267 case INTERNAL_STATE_END_DOCUMENT: |
|
268 throw new NoSuchElementException(CommonResourceBundle.getInstance().getString("message.noMoreEvents")); |
|
269 } |
|
270 } |
|
271 |
|
272 // Reset internal state |
|
273 _characters = null; |
|
274 _algorithmData = null; |
|
275 _currentNamespaceAIIsEnd = 0; |
|
276 |
|
277 // Process information item |
|
278 final int b = read(); |
|
279 switch(DecoderStateTables.EII(b)) { |
|
280 case DecoderStateTables.EII_NO_AIIS_INDEX_SMALL: |
|
281 processEII(_elementNameTable._array[b], false); |
|
282 return _eventType; |
|
283 case DecoderStateTables.EII_AIIS_INDEX_SMALL: |
|
284 processEII(_elementNameTable._array[b & EncodingConstants.INTEGER_3RD_BIT_SMALL_MASK], true); |
|
285 return _eventType; |
|
286 case DecoderStateTables.EII_INDEX_MEDIUM: |
|
287 processEII(processEIIIndexMedium(b), (b & EncodingConstants.ELEMENT_ATTRIBUTE_FLAG) > 0); |
|
288 return _eventType; |
|
289 case DecoderStateTables.EII_INDEX_LARGE: |
|
290 processEII(processEIIIndexLarge(b), (b & EncodingConstants.ELEMENT_ATTRIBUTE_FLAG) > 0); |
|
291 return _eventType; |
|
292 case DecoderStateTables.EII_LITERAL: |
|
293 { |
|
294 final QualifiedName qn = processLiteralQualifiedName( |
|
295 b & EncodingConstants.LITERAL_QNAME_PREFIX_NAMESPACE_NAME_MASK, |
|
296 _elementNameTable.getNext()); |
|
297 _elementNameTable.add(qn); |
|
298 processEII(qn, (b & EncodingConstants.ELEMENT_ATTRIBUTE_FLAG) > 0); |
|
299 return _eventType; |
|
300 } |
|
301 case DecoderStateTables.EII_NAMESPACES: |
|
302 processEIIWithNamespaces((b & EncodingConstants.ELEMENT_ATTRIBUTE_FLAG) > 0); |
|
303 return _eventType; |
|
304 case DecoderStateTables.CII_UTF8_SMALL_LENGTH: |
|
305 _octetBufferLength = (b & EncodingConstants.OCTET_STRING_LENGTH_7TH_BIT_SMALL_MASK) |
|
306 + 1; |
|
307 processUtf8CharacterString(b); |
|
308 return _eventType = CHARACTERS; |
|
309 case DecoderStateTables.CII_UTF8_MEDIUM_LENGTH: |
|
310 _octetBufferLength = read() + EncodingConstants.OCTET_STRING_LENGTH_7TH_BIT_SMALL_LIMIT; |
|
311 processUtf8CharacterString(b); |
|
312 return _eventType = CHARACTERS; |
|
313 case DecoderStateTables.CII_UTF8_LARGE_LENGTH: |
|
314 _octetBufferLength = ((read() << 24) | |
|
315 (read() << 16) | |
|
316 (read() << 8) | |
|
317 read()) |
|
318 + EncodingConstants.OCTET_STRING_LENGTH_7TH_BIT_MEDIUM_LIMIT; |
|
319 processUtf8CharacterString(b); |
|
320 return _eventType = CHARACTERS; |
|
321 case DecoderStateTables.CII_UTF16_SMALL_LENGTH: |
|
322 _octetBufferLength = (b & EncodingConstants.OCTET_STRING_LENGTH_7TH_BIT_SMALL_MASK) |
|
323 + 1; |
|
324 processUtf16CharacterString(b); |
|
325 return _eventType = CHARACTERS; |
|
326 case DecoderStateTables.CII_UTF16_MEDIUM_LENGTH: |
|
327 _octetBufferLength = read() + EncodingConstants.OCTET_STRING_LENGTH_7TH_BIT_SMALL_LIMIT; |
|
328 processUtf16CharacterString(b); |
|
329 return _eventType = CHARACTERS; |
|
330 case DecoderStateTables.CII_UTF16_LARGE_LENGTH: |
|
331 _octetBufferLength = ((read() << 24) | |
|
332 (read() << 16) | |
|
333 (read() << 8) | |
|
334 read()) |
|
335 + EncodingConstants.OCTET_STRING_LENGTH_7TH_BIT_MEDIUM_LIMIT; |
|
336 processUtf16CharacterString(b); |
|
337 return _eventType = CHARACTERS; |
|
338 case DecoderStateTables.CII_RA: |
|
339 { |
|
340 final boolean addToTable = (b & EncodingConstants.CHARACTER_CHUNK_ADD_TO_TABLE_FLAG) > 0; |
|
341 |
|
342 _identifier = (b & 0x02) << 6; |
|
343 final int b2 = read(); |
|
344 _identifier |= (b2 & 0xFC) >> 2; |
|
345 |
|
346 decodeOctetsOnSeventhBitOfNonIdentifyingStringOnThirdBit(b2); |
|
347 |
|
348 decodeRestrictedAlphabetAsCharBuffer(); |
|
349 |
|
350 if (addToTable) { |
|
351 _charactersOffset = _characterContentChunkTable.add(_charBuffer, _charBufferLength); |
|
352 _characters = _characterContentChunkTable._array; |
|
353 } else { |
|
354 _characters = _charBuffer; |
|
355 _charactersOffset = 0; |
|
356 } |
|
357 return _eventType = CHARACTERS; |
|
358 } |
|
359 case DecoderStateTables.CII_EA: |
|
360 { |
|
361 final boolean addToTable = (b & EncodingConstants.CHARACTER_CHUNK_ADD_TO_TABLE_FLAG) > 0; |
|
362 // Decode encoding algorithm integer |
|
363 _algorithmId = (b & 0x02) << 6; |
|
364 final int b2 = read(); |
|
365 _algorithmId |= (b2 & 0xFC) >> 2; |
|
366 |
|
367 decodeOctetsOnSeventhBitOfNonIdentifyingStringOnThirdBit(b2); |
|
368 processCIIEncodingAlgorithm(addToTable); |
|
369 |
|
370 if (_algorithmId == EncodingAlgorithmIndexes.CDATA) { |
|
371 return _eventType = CDATA; |
|
372 } |
|
373 |
|
374 return _eventType = CHARACTERS; |
|
375 } |
|
376 case DecoderStateTables.CII_INDEX_SMALL: |
|
377 { |
|
378 final int index = b & EncodingConstants.INTEGER_4TH_BIT_SMALL_MASK; |
|
379 _characterContentChunkTable._cachedIndex = index; |
|
380 |
|
381 _characters = _characterContentChunkTable._array; |
|
382 _charactersOffset = _characterContentChunkTable._offset[index]; |
|
383 _charBufferLength = _characterContentChunkTable._length[index]; |
|
384 return _eventType = CHARACTERS; |
|
385 } |
|
386 case DecoderStateTables.CII_INDEX_MEDIUM: |
|
387 { |
|
388 final int index = (((b & EncodingConstants.INTEGER_4TH_BIT_MEDIUM_MASK) << 8) | read()) |
|
389 + EncodingConstants.INTEGER_4TH_BIT_SMALL_LIMIT; |
|
390 _characterContentChunkTable._cachedIndex = index; |
|
391 |
|
392 _characters = _characterContentChunkTable._array; |
|
393 _charactersOffset = _characterContentChunkTable._offset[index]; |
|
394 _charBufferLength = _characterContentChunkTable._length[index]; |
|
395 return _eventType = CHARACTERS; |
|
396 } |
|
397 case DecoderStateTables.CII_INDEX_LARGE: |
|
398 { |
|
399 final int index = (((b & EncodingConstants.INTEGER_4TH_BIT_LARGE_MASK) << 16) | |
|
400 (read() << 8) | |
|
401 read()) |
|
402 + EncodingConstants.INTEGER_4TH_BIT_MEDIUM_LIMIT; |
|
403 _characterContentChunkTable._cachedIndex = index; |
|
404 |
|
405 _characters = _characterContentChunkTable._array; |
|
406 _charactersOffset = _characterContentChunkTable._offset[index]; |
|
407 _charBufferLength = _characterContentChunkTable._length[index]; |
|
408 return _eventType = CHARACTERS; |
|
409 } |
|
410 case DecoderStateTables.CII_INDEX_LARGE_LARGE: |
|
411 { |
|
412 final int index = ((read() << 16) | |
|
413 (read() << 8) | |
|
414 read()) |
|
415 + EncodingConstants.INTEGER_4TH_BIT_LARGE_LIMIT; |
|
416 _characterContentChunkTable._cachedIndex = index; |
|
417 |
|
418 _characters = _characterContentChunkTable._array; |
|
419 _charactersOffset = _characterContentChunkTable._offset[index]; |
|
420 _charBufferLength = _characterContentChunkTable._length[index]; |
|
421 return _eventType = CHARACTERS; |
|
422 } |
|
423 case DecoderStateTables.COMMENT_II: |
|
424 processCommentII(); |
|
425 return _eventType; |
|
426 case DecoderStateTables.PROCESSING_INSTRUCTION_II: |
|
427 processProcessingII(); |
|
428 return _eventType; |
|
429 case DecoderStateTables.UNEXPANDED_ENTITY_REFERENCE_II: |
|
430 { |
|
431 processUnexpandedEntityReference(b); |
|
432 // Skip the reference |
|
433 return next(); |
|
434 } |
|
435 case DecoderStateTables.TERMINATOR_DOUBLE: |
|
436 if (_stackCount != -1) { |
|
437 // Pop information off the stack |
|
438 popStack(); |
|
439 |
|
440 _internalState = INTERNAL_STATE_DOUBLE_TERMINATE_ELEMENT; |
|
441 return _eventType = END_ELEMENT; |
|
442 } |
|
443 |
|
444 _internalState = INTERNAL_STATE_END_DOCUMENT; |
|
445 return _eventType = END_DOCUMENT; |
|
446 case DecoderStateTables.TERMINATOR_SINGLE: |
|
447 if (_stackCount != -1) { |
|
448 // Pop information off the stack |
|
449 popStack(); |
|
450 |
|
451 if (_currentNamespaceAIIsEnd > 0) { |
|
452 _internalState = INTERNAL_STATE_SINGLE_TERMINATE_ELEMENT_WITH_NAMESPACES; |
|
453 } |
|
454 return _eventType = END_ELEMENT; |
|
455 } |
|
456 |
|
457 _internalState = INTERNAL_STATE_END_DOCUMENT; |
|
458 return _eventType = END_DOCUMENT; |
|
459 default: |
|
460 throw new FastInfosetException(CommonResourceBundle.getInstance().getString("message.IllegalStateDecodingEII")); |
|
461 } |
|
462 } catch (IOException e) { |
|
463 resetOnError(); |
|
464 logger.log(Level.FINE, "next() exception", e); |
|
465 throw new XMLStreamException(e); |
|
466 } catch (FastInfosetException e) { |
|
467 resetOnError(); |
|
468 logger.log(Level.FINE, "next() exception", e); |
|
469 throw new XMLStreamException(e); |
|
470 } catch (RuntimeException e) { |
|
471 resetOnError(); |
|
472 logger.log(Level.FINE, "next() exception", e); |
|
473 throw e; |
|
474 } |
|
475 } |
|
476 |
|
477 private final void processUtf8CharacterString(final int b) throws IOException { |
|
478 if ((b & EncodingConstants.CHARACTER_CHUNK_ADD_TO_TABLE_FLAG) > 0) { |
|
479 _characterContentChunkTable.ensureSize(_octetBufferLength); |
|
480 _characters = _characterContentChunkTable._array; |
|
481 _charactersOffset = _characterContentChunkTable._arrayIndex; |
|
482 decodeUtf8StringAsCharBuffer(_characterContentChunkTable._array, _charactersOffset); |
|
483 _characterContentChunkTable.add(_charBufferLength); |
|
484 } else { |
|
485 decodeUtf8StringAsCharBuffer(); |
|
486 _characters = _charBuffer; |
|
487 _charactersOffset = 0; |
|
488 } |
|
489 } |
|
490 |
|
491 private final void processUtf16CharacterString(final int b) throws IOException { |
|
492 decodeUtf16StringAsCharBuffer(); |
|
493 if ((b & EncodingConstants.CHARACTER_CHUNK_ADD_TO_TABLE_FLAG) > 0) { |
|
494 _charactersOffset = _characterContentChunkTable.add(_charBuffer, _charBufferLength); |
|
495 _characters = _characterContentChunkTable._array; |
|
496 } else { |
|
497 _characters = _charBuffer; |
|
498 _charactersOffset = 0; |
|
499 } |
|
500 } |
|
501 |
|
502 private void popStack() { |
|
503 // Pop information off the stack |
|
504 _qualifiedName = _qNameStack[_stackCount]; |
|
505 _currentNamespaceAIIsStart = _namespaceAIIsStartStack[_stackCount]; |
|
506 _currentNamespaceAIIsEnd = _namespaceAIIsEndStack[_stackCount]; |
|
507 _qNameStack[_stackCount--] = null; |
|
508 } |
|
509 |
|
510 /** Test if the current event is of the given type and if the namespace and name match the current namespace and name of the current event. |
|
511 * If the namespaceURI is null it is not checked for equality, if the localName is null it is not checked for equality. |
|
512 * @param type the event type |
|
513 * @param namespaceURI the uri of the event, may be null |
|
514 * @param localName the localName of the event, may be null |
|
515 * @throws XMLStreamException if the required values are not matched. |
|
516 */ |
|
517 public final void require(int type, String namespaceURI, String localName) |
|
518 throws XMLStreamException { |
|
519 if( type != _eventType) |
|
520 throw new XMLStreamException(CommonResourceBundle.getInstance().getString("message.eventTypeNotMatch", new Object[]{getEventTypeString(type)})); |
|
521 if( namespaceURI != null && !namespaceURI.equals(getNamespaceURI()) ) |
|
522 throw new XMLStreamException(CommonResourceBundle.getInstance().getString("message.namespaceURINotMatch", new Object[]{namespaceURI})); |
|
523 if(localName != null && !localName.equals(getLocalName())) |
|
524 throw new XMLStreamException(CommonResourceBundle.getInstance().getString("message.localNameNotMatch", new Object[]{localName})); |
|
525 } |
|
526 |
|
527 /** Reads the content of a text-only element. Precondition: |
|
528 * the current event is START_ELEMENT. Postcondition: |
|
529 * The current event is the corresponding END_ELEMENT. |
|
530 * @throws XMLStreamException if the current event is not a START_ELEMENT or if |
|
531 * a non text element is encountered |
|
532 */ |
|
533 public final String getElementText() throws XMLStreamException { |
|
534 |
|
535 if(getEventType() != START_ELEMENT) { |
|
536 throw new XMLStreamException( |
|
537 CommonResourceBundle.getInstance().getString("message.mustBeOnSTARTELEMENT"), getLocation()); |
|
538 } |
|
539 //current is StartElement, move to the next |
|
540 next(); |
|
541 return getElementText(true); |
|
542 } |
|
543 /** |
|
544 * @param startElementRead flag if start element has already been read |
|
545 */ |
|
546 public final String getElementText(boolean startElementRead) throws XMLStreamException { |
|
547 if (!startElementRead) { |
|
548 throw new XMLStreamException( |
|
549 CommonResourceBundle.getInstance().getString("message.mustBeOnSTARTELEMENT"), getLocation()); |
|
550 } |
|
551 int eventType = getEventType(); |
|
552 StringBuilder content = new StringBuilder(); |
|
553 while(eventType != END_ELEMENT ) { |
|
554 if(eventType == CHARACTERS |
|
555 || eventType == CDATA |
|
556 || eventType == SPACE |
|
557 || eventType == ENTITY_REFERENCE) { |
|
558 content.append(getText()); |
|
559 } else if(eventType == PROCESSING_INSTRUCTION |
|
560 || eventType == COMMENT) { |
|
561 // skipping |
|
562 } else if(eventType == END_DOCUMENT) { |
|
563 throw new XMLStreamException(CommonResourceBundle.getInstance().getString("message.unexpectedEOF")); |
|
564 } else if(eventType == START_ELEMENT) { |
|
565 throw new XMLStreamException( |
|
566 CommonResourceBundle.getInstance().getString("message.getElementTextExpectTextOnly"), getLocation()); |
|
567 } else { |
|
568 throw new XMLStreamException( |
|
569 CommonResourceBundle.getInstance().getString("message.unexpectedEventType")+ getEventTypeString(eventType), getLocation()); |
|
570 } |
|
571 eventType = next(); |
|
572 } |
|
573 return content.toString(); |
|
574 } |
|
575 |
|
576 /** Skips any white space (isWhiteSpace() returns true), COMMENT, |
|
577 * or PROCESSING_INSTRUCTION, |
|
578 * until a START_ELEMENT or END_ELEMENT is reached. |
|
579 * If other than white space characters, COMMENT, PROCESSING_INSTRUCTION, START_ELEMENT, END_ELEMENT |
|
580 * are encountered, an exception is thrown. This method should |
|
581 * be used when processing element-only content seperated by white space. |
|
582 * This method should |
|
583 * be used when processing element-only content because |
|
584 * the parser is not able to recognize ignorable whitespace if |
|
585 * then DTD is missing or not interpreted. |
|
586 * @return the event type of the element read |
|
587 * @throws XMLStreamException if the current event is not white space |
|
588 */ |
|
589 public final int nextTag() throws XMLStreamException { |
|
590 next(); |
|
591 return nextTag(true); |
|
592 } |
|
593 /** if the current tag has already read, such as in the case EventReader's |
|
594 * peek() has been called, the current cursor should not move before the loop |
|
595 */ |
|
596 public final int nextTag(boolean currentTagRead) throws XMLStreamException { |
|
597 int eventType = getEventType(); |
|
598 if (!currentTagRead) { |
|
599 eventType = next(); |
|
600 } |
|
601 while((eventType == CHARACTERS && isWhiteSpace()) // skip whitespace |
|
602 || (eventType == CDATA && isWhiteSpace()) |
|
603 || eventType == SPACE |
|
604 || eventType == PROCESSING_INSTRUCTION |
|
605 || eventType == COMMENT) { |
|
606 eventType = next(); |
|
607 } |
|
608 if (eventType != START_ELEMENT && eventType != END_ELEMENT) { |
|
609 throw new XMLStreamException(CommonResourceBundle.getInstance().getString("message.expectedStartOrEnd"), getLocation()); |
|
610 } |
|
611 return eventType; |
|
612 } |
|
613 |
|
614 public final boolean hasNext() throws XMLStreamException { |
|
615 return (_eventType != END_DOCUMENT); |
|
616 } |
|
617 |
|
618 public void close() throws XMLStreamException { |
|
619 try { |
|
620 super.closeIfRequired(); |
|
621 } catch (IOException ex) { |
|
622 } |
|
623 } |
|
624 |
|
625 public final String getNamespaceURI(String prefix) { |
|
626 String namespace = getNamespaceDecl(prefix); |
|
627 if (namespace == null) { |
|
628 if (prefix == null) { |
|
629 throw new IllegalArgumentException(CommonResourceBundle.getInstance().getString("message.nullPrefix")); |
|
630 } |
|
631 return null; // unbound |
|
632 } |
|
633 return namespace; |
|
634 } |
|
635 |
|
636 public final boolean isStartElement() { |
|
637 return (_eventType == START_ELEMENT); |
|
638 } |
|
639 |
|
640 public final boolean isEndElement() { |
|
641 return (_eventType == END_ELEMENT); |
|
642 } |
|
643 |
|
644 public final boolean isCharacters() { |
|
645 return (_eventType == CHARACTERS); |
|
646 } |
|
647 |
|
648 /** |
|
649 * Returns true if the cursor points to a character data event that consists of all whitespace |
|
650 * Application calling this method needs to cache the value and avoid calling this method again |
|
651 * for the same event. |
|
652 * @return true if the cursor points to all whitespace, false otherwise |
|
653 */ |
|
654 public final boolean isWhiteSpace() { |
|
655 if(isCharacters() || (_eventType == CDATA)){ |
|
656 char [] ch = this.getTextCharacters(); |
|
657 int start = this.getTextStart(); |
|
658 int length = this.getTextLength(); |
|
659 for (int i = start; i < start + length; i++){ |
|
660 if(!XMLChar.isSpace(ch[i])){ |
|
661 return false; |
|
662 } |
|
663 } |
|
664 return true; |
|
665 } |
|
666 return false; |
|
667 } |
|
668 |
|
669 public final String getAttributeValue(String namespaceURI, String localName) { |
|
670 if (_eventType != START_ELEMENT) { |
|
671 throw new IllegalStateException(CommonResourceBundle.getInstance().getString("message.invalidCallingGetAttributeValue")); |
|
672 } |
|
673 |
|
674 if (localName == null) |
|
675 throw new IllegalArgumentException(); |
|
676 |
|
677 // Search for the attributes in _attributes |
|
678 if (namespaceURI != null) { |
|
679 for (int i = 0; i < _attributes.getLength(); i++) { |
|
680 if (_attributes.getLocalName(i).equals(localName) && |
|
681 _attributes.getURI(i).equals(namespaceURI)) { |
|
682 return _attributes.getValue(i); |
|
683 } |
|
684 } |
|
685 } else { |
|
686 for (int i = 0; i < _attributes.getLength(); i++) { |
|
687 if (_attributes.getLocalName(i).equals(localName)) { |
|
688 return _attributes.getValue(i); |
|
689 } |
|
690 } |
|
691 } |
|
692 |
|
693 return null; |
|
694 } |
|
695 |
|
696 public final int getAttributeCount() { |
|
697 if (_eventType != START_ELEMENT) { |
|
698 throw new IllegalStateException(CommonResourceBundle.getInstance().getString("message.invalidCallingGetAttributeValue")); |
|
699 } |
|
700 |
|
701 return _attributes.getLength(); |
|
702 } |
|
703 |
|
704 public final javax.xml.namespace.QName getAttributeName(int index) { |
|
705 if (_eventType != START_ELEMENT) { |
|
706 throw new IllegalStateException(CommonResourceBundle.getInstance().getString("message.invalidCallingGetAttributeValue")); |
|
707 } |
|
708 return _attributes.getQualifiedName(index).getQName(); |
|
709 } |
|
710 |
|
711 public final String getAttributeNamespace(int index) { |
|
712 if (_eventType != START_ELEMENT) { |
|
713 throw new IllegalStateException(CommonResourceBundle.getInstance().getString("message.invalidCallingGetAttributeValue")); |
|
714 } |
|
715 |
|
716 return _attributes.getURI(index); |
|
717 } |
|
718 |
|
719 public final String getAttributeLocalName(int index) { |
|
720 if (_eventType != START_ELEMENT) { |
|
721 throw new IllegalStateException(CommonResourceBundle.getInstance().getString("message.invalidCallingGetAttributeValue")); |
|
722 } |
|
723 return _attributes.getLocalName(index); |
|
724 } |
|
725 |
|
726 public final String getAttributePrefix(int index) { |
|
727 if (_eventType != START_ELEMENT) { |
|
728 throw new IllegalStateException(CommonResourceBundle.getInstance().getString("message.invalidCallingGetAttributeValue")); |
|
729 } |
|
730 return _attributes.getPrefix(index); |
|
731 } |
|
732 |
|
733 public final String getAttributeType(int index) { |
|
734 if (_eventType != START_ELEMENT) { |
|
735 throw new IllegalStateException(CommonResourceBundle.getInstance().getString("message.invalidCallingGetAttributeValue")); |
|
736 } |
|
737 return _attributes.getType(index); |
|
738 } |
|
739 |
|
740 public final String getAttributeValue(int index) { |
|
741 if (_eventType != START_ELEMENT) { |
|
742 throw new IllegalStateException(CommonResourceBundle.getInstance().getString("message.invalidCallingGetAttributeValue")); |
|
743 } |
|
744 return _attributes.getValue(index); |
|
745 } |
|
746 |
|
747 public final boolean isAttributeSpecified(int index) { |
|
748 return false; // non-validating parser |
|
749 } |
|
750 |
|
751 public final int getNamespaceCount() { |
|
752 if (_eventType == START_ELEMENT || _eventType == END_ELEMENT) { |
|
753 return (_currentNamespaceAIIsEnd > 0) ? (_currentNamespaceAIIsEnd - _currentNamespaceAIIsStart) : 0; |
|
754 } else { |
|
755 throw new IllegalStateException(CommonResourceBundle.getInstance().getString("message.invalidCallingGetNamespaceCount")); |
|
756 } |
|
757 } |
|
758 |
|
759 public final String getNamespacePrefix(int index) { |
|
760 if (_eventType == START_ELEMENT || _eventType == END_ELEMENT) { |
|
761 return _namespaceAIIsPrefix[_currentNamespaceAIIsStart + index]; |
|
762 } else { |
|
763 throw new IllegalStateException(CommonResourceBundle.getInstance().getString("message.invalidCallingGetNamespacePrefix")); |
|
764 } |
|
765 } |
|
766 |
|
767 public final String getNamespaceURI(int index) { |
|
768 if (_eventType == START_ELEMENT || _eventType == END_ELEMENT) { |
|
769 return _namespaceAIIsNamespaceName[_currentNamespaceAIIsStart + index]; |
|
770 } else { |
|
771 throw new IllegalStateException(CommonResourceBundle.getInstance().getString("message.invalidCallingGetNamespacePrefix")); |
|
772 } |
|
773 } |
|
774 |
|
775 public final NamespaceContext getNamespaceContext() { |
|
776 return _nsContext; |
|
777 } |
|
778 |
|
779 public final int getEventType() { |
|
780 return _eventType; |
|
781 } |
|
782 |
|
783 public final String getText() { |
|
784 if (_characters == null) { |
|
785 checkTextState(); |
|
786 } |
|
787 |
|
788 if (_characters == _characterContentChunkTable._array) { |
|
789 return _characterContentChunkTable.getString(_characterContentChunkTable._cachedIndex); |
|
790 } else { |
|
791 return new String(_characters, _charactersOffset, _charBufferLength); |
|
792 } |
|
793 } |
|
794 |
|
795 public final char[] getTextCharacters() { |
|
796 if (_characters == null) { |
|
797 checkTextState(); |
|
798 } |
|
799 |
|
800 return _characters; |
|
801 } |
|
802 |
|
803 public final int getTextStart() { |
|
804 if (_characters == null) { |
|
805 checkTextState(); |
|
806 } |
|
807 |
|
808 return _charactersOffset; |
|
809 } |
|
810 |
|
811 public final int getTextLength() { |
|
812 if (_characters == null) { |
|
813 checkTextState(); |
|
814 } |
|
815 |
|
816 return _charBufferLength; |
|
817 } |
|
818 |
|
819 public final int getTextCharacters(int sourceStart, char[] target, |
|
820 int targetStart, int length) throws XMLStreamException { |
|
821 if (_characters == null) { |
|
822 checkTextState(); |
|
823 } |
|
824 |
|
825 try { |
|
826 int bytesToCopy = Math.min(_charBufferLength, length); |
|
827 System.arraycopy(_characters, _charactersOffset + sourceStart, |
|
828 target, targetStart, bytesToCopy); |
|
829 return bytesToCopy; |
|
830 } catch (IndexOutOfBoundsException e) { |
|
831 throw new XMLStreamException(e); |
|
832 } |
|
833 } |
|
834 |
|
835 protected final void checkTextState() { |
|
836 if (_algorithmData == null) { |
|
837 throw new IllegalStateException(CommonResourceBundle.getInstance().getString("message.InvalidStateForText")); |
|
838 } |
|
839 |
|
840 try { |
|
841 convertEncodingAlgorithmDataToCharacters(); |
|
842 } catch (Exception e) { |
|
843 throw new IllegalStateException(CommonResourceBundle.getInstance().getString("message.InvalidStateForText")); |
|
844 } |
|
845 } |
|
846 |
|
847 public final String getEncoding() { |
|
848 return _characterEncodingScheme; |
|
849 } |
|
850 |
|
851 public final boolean hasText() { |
|
852 return (_characters != null); |
|
853 } |
|
854 |
|
855 public final Location getLocation() { |
|
856 //location should be created in next() |
|
857 //returns a nil location for now |
|
858 return EventLocation.getNilLocation(); |
|
859 } |
|
860 |
|
861 public final QName getName() { |
|
862 if (_eventType == START_ELEMENT || _eventType == END_ELEMENT) { |
|
863 return _qualifiedName.getQName(); |
|
864 } else { |
|
865 throw new IllegalStateException(CommonResourceBundle.getInstance().getString("message.invalidCallingGetName")); |
|
866 } |
|
867 } |
|
868 |
|
869 public final String getLocalName() { |
|
870 if (_eventType == START_ELEMENT || _eventType == END_ELEMENT) { |
|
871 return _qualifiedName.localName; |
|
872 } else { |
|
873 throw new IllegalStateException(CommonResourceBundle.getInstance().getString("message.invalidCallingGetLocalName")); |
|
874 } |
|
875 } |
|
876 |
|
877 public final boolean hasName() { |
|
878 return (_eventType == START_ELEMENT || _eventType == END_ELEMENT); |
|
879 } |
|
880 |
|
881 public final String getNamespaceURI() { |
|
882 if (_eventType == START_ELEMENT || _eventType == END_ELEMENT) { |
|
883 return _qualifiedName.namespaceName; |
|
884 } else { |
|
885 throw new IllegalStateException(CommonResourceBundle.getInstance().getString("message.invalidCallingGetNamespaceURI")); |
|
886 } |
|
887 } |
|
888 |
|
889 public final String getPrefix() { |
|
890 if (_eventType == START_ELEMENT || _eventType == END_ELEMENT) { |
|
891 return _qualifiedName.prefix; |
|
892 } else { |
|
893 throw new IllegalStateException(CommonResourceBundle.getInstance().getString("message.invalidCallingGetPrefix")); |
|
894 } |
|
895 } |
|
896 |
|
897 public final String getVersion() { |
|
898 return null; |
|
899 } |
|
900 |
|
901 public final boolean isStandalone() { |
|
902 return false; |
|
903 } |
|
904 |
|
905 public final boolean standaloneSet() { |
|
906 return false; |
|
907 } |
|
908 |
|
909 public final String getCharacterEncodingScheme() { |
|
910 return null; |
|
911 } |
|
912 |
|
913 public final String getPITarget() { |
|
914 if (_eventType != PROCESSING_INSTRUCTION) { |
|
915 throw new IllegalStateException(CommonResourceBundle.getInstance().getString("message.invalidCallingGetPITarget")); |
|
916 } |
|
917 |
|
918 return _piTarget; |
|
919 } |
|
920 |
|
921 public final String getPIData() { |
|
922 if (_eventType != PROCESSING_INSTRUCTION) { |
|
923 throw new IllegalStateException(CommonResourceBundle.getInstance().getString("message.invalidCallingGetPIData")); |
|
924 } |
|
925 |
|
926 return _piData; |
|
927 } |
|
928 |
|
929 |
|
930 |
|
931 |
|
932 public final String getNameString() { |
|
933 if (_eventType == START_ELEMENT || _eventType == END_ELEMENT) { |
|
934 return _qualifiedName.getQNameString(); |
|
935 } else { |
|
936 throw new IllegalStateException(CommonResourceBundle.getInstance().getString("message.invalidCallingGetName")); |
|
937 } |
|
938 } |
|
939 |
|
940 public final String getAttributeNameString(int index) { |
|
941 if (_eventType != START_ELEMENT) { |
|
942 throw new IllegalStateException(CommonResourceBundle.getInstance().getString("message.invalidCallingGetAttributeValue")); |
|
943 } |
|
944 return _attributes.getQualifiedName(index).getQNameString(); |
|
945 } |
|
946 |
|
947 |
|
948 public final String getTextAlgorithmURI() { |
|
949 return _algorithmURI; |
|
950 } |
|
951 |
|
952 public final int getTextAlgorithmIndex() { |
|
953 return _algorithmId; |
|
954 } |
|
955 |
|
956 public final boolean hasTextAlgorithmBytes() { |
|
957 return _algorithmData != null; |
|
958 } |
|
959 |
|
960 |
|
961 /** |
|
962 * Returns the byte[], which represents text algorithms. |
|
963 * @deprecated was deprecated due to security reasons. Now the method return cloned byte[]. |
|
964 * |
|
965 * @return |
|
966 */ |
|
967 public final byte[] getTextAlgorithmBytes() { |
|
968 // Do not return the actual _algorithmData due to security reasons |
|
969 // return _algorithmData; |
|
970 if (_algorithmData == null) { |
|
971 return null; |
|
972 } |
|
973 |
|
974 final byte[] algorithmData = new byte[_algorithmData.length]; |
|
975 System.arraycopy(_algorithmData, 0, algorithmData, 0, _algorithmData.length); |
|
976 return algorithmData; |
|
977 } |
|
978 |
|
979 public final byte[] getTextAlgorithmBytesClone() { |
|
980 if (_algorithmData == null) { |
|
981 return null; |
|
982 } |
|
983 |
|
984 byte[] algorithmData = new byte[_algorithmDataLength]; |
|
985 System.arraycopy(_algorithmData, _algorithmDataOffset, algorithmData, 0, _algorithmDataLength); |
|
986 return algorithmData; |
|
987 } |
|
988 |
|
989 public final int getTextAlgorithmStart() { |
|
990 return _algorithmDataOffset; |
|
991 } |
|
992 |
|
993 public final int getTextAlgorithmLength() { |
|
994 return _algorithmDataLength; |
|
995 } |
|
996 |
|
997 public final int getTextAlgorithmBytes(int sourceStart, byte[] target, |
|
998 int targetStart, int length) throws XMLStreamException { |
|
999 try { |
|
1000 System.arraycopy(_algorithmData, sourceStart, target, |
|
1001 targetStart, length); |
|
1002 return length; |
|
1003 } catch (IndexOutOfBoundsException e) { |
|
1004 throw new XMLStreamException(e); |
|
1005 } |
|
1006 } |
|
1007 |
|
1008 // FastInfosetStreamReader impl |
|
1009 |
|
1010 public final int peekNext() throws XMLStreamException { |
|
1011 try { |
|
1012 switch(DecoderStateTables.EII(peek(this))) { |
|
1013 case DecoderStateTables.EII_NO_AIIS_INDEX_SMALL: |
|
1014 case DecoderStateTables.EII_AIIS_INDEX_SMALL: |
|
1015 case DecoderStateTables.EII_INDEX_MEDIUM: |
|
1016 case DecoderStateTables.EII_INDEX_LARGE: |
|
1017 case DecoderStateTables.EII_LITERAL: |
|
1018 case DecoderStateTables.EII_NAMESPACES: |
|
1019 return START_ELEMENT; |
|
1020 case DecoderStateTables.CII_UTF8_SMALL_LENGTH: |
|
1021 case DecoderStateTables.CII_UTF8_MEDIUM_LENGTH: |
|
1022 case DecoderStateTables.CII_UTF8_LARGE_LENGTH: |
|
1023 case DecoderStateTables.CII_UTF16_SMALL_LENGTH: |
|
1024 case DecoderStateTables.CII_UTF16_MEDIUM_LENGTH: |
|
1025 case DecoderStateTables.CII_UTF16_LARGE_LENGTH: |
|
1026 case DecoderStateTables.CII_RA: |
|
1027 case DecoderStateTables.CII_EA: |
|
1028 case DecoderStateTables.CII_INDEX_SMALL: |
|
1029 case DecoderStateTables.CII_INDEX_MEDIUM: |
|
1030 case DecoderStateTables.CII_INDEX_LARGE: |
|
1031 case DecoderStateTables.CII_INDEX_LARGE_LARGE: |
|
1032 return CHARACTERS; |
|
1033 case DecoderStateTables.COMMENT_II: |
|
1034 return COMMENT; |
|
1035 case DecoderStateTables.PROCESSING_INSTRUCTION_II: |
|
1036 return PROCESSING_INSTRUCTION; |
|
1037 case DecoderStateTables.UNEXPANDED_ENTITY_REFERENCE_II: |
|
1038 return ENTITY_REFERENCE; |
|
1039 case DecoderStateTables.TERMINATOR_DOUBLE: |
|
1040 case DecoderStateTables.TERMINATOR_SINGLE: |
|
1041 return (_stackCount != -1) ? END_ELEMENT : END_DOCUMENT; |
|
1042 default: |
|
1043 throw new FastInfosetException( |
|
1044 CommonResourceBundle.getInstance().getString("message.IllegalStateDecodingEII")); |
|
1045 } |
|
1046 } catch (IOException e) { |
|
1047 throw new XMLStreamException(e); |
|
1048 } catch (FastInfosetException e) { |
|
1049 throw new XMLStreamException(e); |
|
1050 } |
|
1051 } |
|
1052 |
|
1053 public void onBeforeOctetBufferOverwrite() { |
|
1054 if (_algorithmData != null) { |
|
1055 _algorithmData = getTextAlgorithmBytesClone(); |
|
1056 _algorithmDataOffset = 0; |
|
1057 _isAlgorithmDataCloned = true; |
|
1058 } |
|
1059 } |
|
1060 |
|
1061 // Faster access methods without checks |
|
1062 |
|
1063 public final int accessNamespaceCount() { |
|
1064 return (_currentNamespaceAIIsEnd > 0) ? (_currentNamespaceAIIsEnd - _currentNamespaceAIIsStart) : 0; |
|
1065 } |
|
1066 |
|
1067 public final String accessLocalName() { |
|
1068 return _qualifiedName.localName; |
|
1069 } |
|
1070 |
|
1071 public final String accessNamespaceURI() { |
|
1072 return _qualifiedName.namespaceName; |
|
1073 } |
|
1074 |
|
1075 public final String accessPrefix() { |
|
1076 return _qualifiedName.prefix; |
|
1077 } |
|
1078 |
|
1079 public final char[] accessTextCharacters() { |
|
1080 if (_characters == null) return null; |
|
1081 |
|
1082 // we return a cloned version of _characters |
|
1083 final char[] clonedCharacters = new char[_characters.length]; |
|
1084 System.arraycopy(_characters, 0, clonedCharacters, 0, _characters.length); |
|
1085 return clonedCharacters; |
|
1086 } |
|
1087 |
|
1088 public final int accessTextStart() { |
|
1089 return _charactersOffset; |
|
1090 } |
|
1091 |
|
1092 public final int accessTextLength() { |
|
1093 return _charBufferLength; |
|
1094 } |
|
1095 |
|
1096 // |
|
1097 |
|
1098 protected final void processDII() throws FastInfosetException, IOException { |
|
1099 final int b = read(); |
|
1100 if (b > 0) { |
|
1101 processDIIOptionalProperties(b); |
|
1102 } |
|
1103 } |
|
1104 |
|
1105 protected final void processDIIOptionalProperties(int b) throws FastInfosetException, IOException { |
|
1106 // Optimize for the most common case |
|
1107 if (b == EncodingConstants.DOCUMENT_INITIAL_VOCABULARY_FLAG) { |
|
1108 decodeInitialVocabulary(); |
|
1109 return; |
|
1110 } |
|
1111 |
|
1112 if ((b & EncodingConstants.DOCUMENT_ADDITIONAL_DATA_FLAG) > 0) { |
|
1113 decodeAdditionalData(); |
|
1114 /* |
|
1115 * TODO |
|
1116 * how to report the additional data? |
|
1117 */ |
|
1118 } |
|
1119 |
|
1120 if ((b & EncodingConstants.DOCUMENT_INITIAL_VOCABULARY_FLAG) > 0) { |
|
1121 decodeInitialVocabulary(); |
|
1122 } |
|
1123 |
|
1124 if ((b & EncodingConstants.DOCUMENT_NOTATIONS_FLAG) > 0) { |
|
1125 decodeNotations(); |
|
1126 /* |
|
1127 try { |
|
1128 _dtdHandler.notationDecl(name, public_identifier, system_identifier); |
|
1129 } catch (SAXException e) { |
|
1130 throw new IOException("NotationsDeclarationII"); |
|
1131 } |
|
1132 */ |
|
1133 } |
|
1134 |
|
1135 if ((b & EncodingConstants.DOCUMENT_UNPARSED_ENTITIES_FLAG) > 0) { |
|
1136 decodeUnparsedEntities(); |
|
1137 /* |
|
1138 try { |
|
1139 _dtdHandler.unparsedEntityDecl(name, public_identifier, system_identifier, notation_name); |
|
1140 } catch (SAXException e) { |
|
1141 throw new IOException("UnparsedEntitiesII"); |
|
1142 } |
|
1143 */ |
|
1144 } |
|
1145 |
|
1146 if ((b & EncodingConstants.DOCUMENT_CHARACTER_ENCODING_SCHEME) > 0) { |
|
1147 _characterEncodingScheme = decodeCharacterEncodingScheme(); |
|
1148 } |
|
1149 |
|
1150 if ((b & EncodingConstants.DOCUMENT_STANDALONE_FLAG) > 0) { |
|
1151 boolean standalone = (read() > 0) ? true : false ; |
|
1152 /* |
|
1153 * TODO |
|
1154 * how to report the standalone flag? |
|
1155 */ |
|
1156 } |
|
1157 |
|
1158 if ((b & EncodingConstants.DOCUMENT_VERSION_FLAG) > 0) { |
|
1159 decodeVersion(); |
|
1160 /* |
|
1161 * TODO |
|
1162 * how to report the standalone flag? |
|
1163 */ |
|
1164 } |
|
1165 } |
|
1166 |
|
1167 |
|
1168 protected final void resizeNamespaceAIIs() { |
|
1169 final String[] namespaceAIIsPrefix = new String[_namespaceAIIsIndex * 2]; |
|
1170 System.arraycopy(_namespaceAIIsPrefix, 0, namespaceAIIsPrefix, 0, _namespaceAIIsIndex); |
|
1171 _namespaceAIIsPrefix = namespaceAIIsPrefix; |
|
1172 |
|
1173 final String[] namespaceAIIsNamespaceName = new String[_namespaceAIIsIndex * 2]; |
|
1174 System.arraycopy(_namespaceAIIsNamespaceName, 0, namespaceAIIsNamespaceName, 0, _namespaceAIIsIndex); |
|
1175 _namespaceAIIsNamespaceName = namespaceAIIsNamespaceName; |
|
1176 |
|
1177 final int[] namespaceAIIsPrefixIndex = new int[_namespaceAIIsIndex * 2]; |
|
1178 System.arraycopy(_namespaceAIIsPrefixIndex, 0, namespaceAIIsPrefixIndex, 0, _namespaceAIIsIndex); |
|
1179 _namespaceAIIsPrefixIndex = namespaceAIIsPrefixIndex; |
|
1180 } |
|
1181 |
|
1182 protected final void processEIIWithNamespaces(boolean hasAttributes) throws FastInfosetException, IOException { |
|
1183 if (++_prefixTable._declarationId == Integer.MAX_VALUE) { |
|
1184 _prefixTable.clearDeclarationIds(); |
|
1185 } |
|
1186 |
|
1187 _currentNamespaceAIIsStart = _namespaceAIIsIndex; |
|
1188 String prefix = "", namespaceName = ""; |
|
1189 int b = read(); |
|
1190 while ((b & EncodingConstants.NAMESPACE_ATTRIBUTE_MASK) == EncodingConstants.NAMESPACE_ATTRIBUTE) { |
|
1191 if (_namespaceAIIsIndex == _namespaceAIIsPrefix.length) { |
|
1192 resizeNamespaceAIIs(); |
|
1193 } |
|
1194 |
|
1195 switch (b & EncodingConstants.NAMESPACE_ATTRIBUTE_PREFIX_NAME_MASK) { |
|
1196 // no prefix, no namespace |
|
1197 // Undeclaration of default namespace |
|
1198 case 0: |
|
1199 prefix = namespaceName = |
|
1200 _namespaceAIIsPrefix[_namespaceAIIsIndex] = |
|
1201 _namespaceAIIsNamespaceName[_namespaceAIIsIndex] = ""; |
|
1202 |
|
1203 _namespaceNameIndex = _prefixIndex = _namespaceAIIsPrefixIndex[_namespaceAIIsIndex++] = -1; |
|
1204 break; |
|
1205 // no prefix, namespace |
|
1206 // Declaration of default namespace |
|
1207 case 1: |
|
1208 prefix = _namespaceAIIsPrefix[_namespaceAIIsIndex] = ""; |
|
1209 namespaceName = _namespaceAIIsNamespaceName[_namespaceAIIsIndex] = |
|
1210 decodeIdentifyingNonEmptyStringOnFirstBitAsNamespaceName(false); |
|
1211 |
|
1212 _prefixIndex = _namespaceAIIsPrefixIndex[_namespaceAIIsIndex++] = -1; |
|
1213 break; |
|
1214 // prefix, no namespace |
|
1215 // Undeclaration of namespace |
|
1216 case 2: |
|
1217 prefix = _namespaceAIIsPrefix[_namespaceAIIsIndex] = |
|
1218 decodeIdentifyingNonEmptyStringOnFirstBitAsPrefix(false); |
|
1219 namespaceName = _namespaceAIIsNamespaceName[_namespaceAIIsIndex] = ""; |
|
1220 |
|
1221 _namespaceNameIndex = -1; |
|
1222 _namespaceAIIsPrefixIndex[_namespaceAIIsIndex++] = _prefixIndex; |
|
1223 break; |
|
1224 // prefix, namespace |
|
1225 // Declaration of prefixed namespace |
|
1226 case 3: |
|
1227 prefix = _namespaceAIIsPrefix[_namespaceAIIsIndex] = |
|
1228 decodeIdentifyingNonEmptyStringOnFirstBitAsPrefix(true); |
|
1229 namespaceName = _namespaceAIIsNamespaceName[_namespaceAIIsIndex] = |
|
1230 decodeIdentifyingNonEmptyStringOnFirstBitAsNamespaceName(true); |
|
1231 |
|
1232 _namespaceAIIsPrefixIndex[_namespaceAIIsIndex++] = _prefixIndex; |
|
1233 break; |
|
1234 } |
|
1235 |
|
1236 // Push namespace declarations onto the stack |
|
1237 _prefixTable.pushScopeWithPrefixEntry(prefix, namespaceName, _prefixIndex, _namespaceNameIndex); |
|
1238 |
|
1239 b = read(); |
|
1240 } |
|
1241 if (b != EncodingConstants.TERMINATOR) { |
|
1242 throw new FastInfosetException(CommonResourceBundle.getInstance().getString("message.EIInamespaceNameNotTerminatedCorrectly")); |
|
1243 } |
|
1244 _currentNamespaceAIIsEnd = _namespaceAIIsIndex; |
|
1245 |
|
1246 b = read(); |
|
1247 switch(DecoderStateTables.EII(b)) { |
|
1248 case DecoderStateTables.EII_NO_AIIS_INDEX_SMALL: |
|
1249 processEII(_elementNameTable._array[b], hasAttributes); |
|
1250 break; |
|
1251 case DecoderStateTables.EII_INDEX_MEDIUM: |
|
1252 processEII(processEIIIndexMedium(b), hasAttributes); |
|
1253 break; |
|
1254 case DecoderStateTables.EII_INDEX_LARGE: |
|
1255 processEII(processEIIIndexLarge(b), hasAttributes); |
|
1256 break; |
|
1257 case DecoderStateTables.EII_LITERAL: |
|
1258 { |
|
1259 final QualifiedName qn = processLiteralQualifiedName( |
|
1260 b & EncodingConstants.LITERAL_QNAME_PREFIX_NAMESPACE_NAME_MASK, |
|
1261 _elementNameTable.getNext()); |
|
1262 _elementNameTable.add(qn); |
|
1263 processEII(qn, hasAttributes); |
|
1264 break; |
|
1265 } |
|
1266 default: |
|
1267 throw new FastInfosetException(CommonResourceBundle.getInstance().getString("message.IllegalStateDecodingEIIAfterAIIs")); |
|
1268 } |
|
1269 } |
|
1270 |
|
1271 protected final void processEII(QualifiedName name, boolean hasAttributes) throws FastInfosetException, IOException { |
|
1272 if (_prefixTable._currentInScope[name.prefixIndex] != name.namespaceNameIndex) { |
|
1273 throw new FastInfosetException(CommonResourceBundle.getInstance().getString("message.qnameOfEIINotInScope")); |
|
1274 } |
|
1275 |
|
1276 _eventType = START_ELEMENT; |
|
1277 _qualifiedName = name; |
|
1278 |
|
1279 if (_clearAttributes) { |
|
1280 _attributes.clear(); |
|
1281 _clearAttributes = false; |
|
1282 } |
|
1283 |
|
1284 if (hasAttributes) { |
|
1285 processAIIs(); |
|
1286 } |
|
1287 |
|
1288 // Push element holder onto the stack |
|
1289 _stackCount++; |
|
1290 if (_stackCount == _qNameStack.length) { |
|
1291 QualifiedName[] qNameStack = new QualifiedName[_qNameStack.length * 2]; |
|
1292 System.arraycopy(_qNameStack, 0, qNameStack, 0, _qNameStack.length); |
|
1293 _qNameStack = qNameStack; |
|
1294 |
|
1295 int[] namespaceAIIsStartStack = new int[_namespaceAIIsStartStack.length * 2]; |
|
1296 System.arraycopy(_namespaceAIIsStartStack, 0, namespaceAIIsStartStack, 0, _namespaceAIIsStartStack.length); |
|
1297 _namespaceAIIsStartStack = namespaceAIIsStartStack; |
|
1298 |
|
1299 int[] namespaceAIIsEndStack = new int[_namespaceAIIsEndStack.length * 2]; |
|
1300 System.arraycopy(_namespaceAIIsEndStack, 0, namespaceAIIsEndStack, 0, _namespaceAIIsEndStack.length); |
|
1301 _namespaceAIIsEndStack = namespaceAIIsEndStack; |
|
1302 } |
|
1303 _qNameStack[_stackCount] = _qualifiedName; |
|
1304 _namespaceAIIsStartStack[_stackCount] = _currentNamespaceAIIsStart; |
|
1305 _namespaceAIIsEndStack[_stackCount] = _currentNamespaceAIIsEnd; |
|
1306 } |
|
1307 |
|
1308 protected final void processAIIs() throws FastInfosetException, IOException { |
|
1309 QualifiedName name; |
|
1310 int b; |
|
1311 String value; |
|
1312 |
|
1313 if (++_duplicateAttributeVerifier._currentIteration == Integer.MAX_VALUE) { |
|
1314 _duplicateAttributeVerifier.clear(); |
|
1315 } |
|
1316 |
|
1317 _clearAttributes = true; |
|
1318 boolean terminate = false; |
|
1319 do { |
|
1320 // AII qualified name |
|
1321 b = read(); |
|
1322 switch (DecoderStateTables.AII(b)) { |
|
1323 case DecoderStateTables.AII_INDEX_SMALL: |
|
1324 name = _attributeNameTable._array[b]; |
|
1325 break; |
|
1326 case DecoderStateTables.AII_INDEX_MEDIUM: |
|
1327 { |
|
1328 final int i = (((b & EncodingConstants.INTEGER_2ND_BIT_MEDIUM_MASK) << 8) | read()) |
|
1329 + EncodingConstants.INTEGER_2ND_BIT_SMALL_LIMIT; |
|
1330 name = _attributeNameTable._array[i]; |
|
1331 break; |
|
1332 } |
|
1333 case DecoderStateTables.AII_INDEX_LARGE: |
|
1334 { |
|
1335 final int i = (((b & EncodingConstants.INTEGER_2ND_BIT_LARGE_MASK) << 16) | (read() << 8) | read()) |
|
1336 + EncodingConstants.INTEGER_2ND_BIT_MEDIUM_LIMIT; |
|
1337 name = _attributeNameTable._array[i]; |
|
1338 break; |
|
1339 } |
|
1340 case DecoderStateTables.AII_LITERAL: |
|
1341 name = processLiteralQualifiedName( |
|
1342 b & EncodingConstants.LITERAL_QNAME_PREFIX_NAMESPACE_NAME_MASK, |
|
1343 _attributeNameTable.getNext()); |
|
1344 name.createAttributeValues(DuplicateAttributeVerifier.MAP_SIZE); |
|
1345 _attributeNameTable.add(name); |
|
1346 break; |
|
1347 case DecoderStateTables.AII_TERMINATOR_DOUBLE: |
|
1348 _internalState = INTERNAL_STATE_START_ELEMENT_TERMINATE; |
|
1349 case DecoderStateTables.AII_TERMINATOR_SINGLE: |
|
1350 terminate = true; |
|
1351 // AIIs have finished break out of loop |
|
1352 continue; |
|
1353 default: |
|
1354 throw new FastInfosetException(CommonResourceBundle.getInstance().getString("message.decodingAIIs")); |
|
1355 } |
|
1356 |
|
1357 // [normalized value] of AII |
|
1358 |
|
1359 if (name.prefixIndex > 0 && _prefixTable._currentInScope[name.prefixIndex] != name.namespaceNameIndex) { |
|
1360 throw new FastInfosetException(CommonResourceBundle.getInstance().getString("message.AIIqNameNotInScope")); |
|
1361 } |
|
1362 |
|
1363 _duplicateAttributeVerifier.checkForDuplicateAttribute(name.attributeHash, name.attributeId); |
|
1364 |
|
1365 b = read(); |
|
1366 switch(DecoderStateTables.NISTRING(b)) { |
|
1367 case DecoderStateTables.NISTRING_UTF8_SMALL_LENGTH: |
|
1368 _octetBufferLength = (b & EncodingConstants.OCTET_STRING_LENGTH_5TH_BIT_SMALL_MASK) + 1; |
|
1369 value = decodeUtf8StringAsString(); |
|
1370 if ((b & EncodingConstants.NISTRING_ADD_TO_TABLE_FLAG) > 0) { |
|
1371 _attributeValueTable.add(value); |
|
1372 } |
|
1373 |
|
1374 _attributes.addAttribute(name, value); |
|
1375 break; |
|
1376 case DecoderStateTables.NISTRING_UTF8_MEDIUM_LENGTH: |
|
1377 _octetBufferLength = read() + EncodingConstants.OCTET_STRING_LENGTH_5TH_BIT_SMALL_LIMIT; |
|
1378 value = decodeUtf8StringAsString(); |
|
1379 if ((b & EncodingConstants.NISTRING_ADD_TO_TABLE_FLAG) > 0) { |
|
1380 _attributeValueTable.add(value); |
|
1381 } |
|
1382 |
|
1383 _attributes.addAttribute(name, value); |
|
1384 break; |
|
1385 case DecoderStateTables.NISTRING_UTF8_LARGE_LENGTH: |
|
1386 _octetBufferLength = ((read() << 24) | |
|
1387 (read() << 16) | |
|
1388 (read() << 8) | |
|
1389 read()) |
|
1390 + EncodingConstants.OCTET_STRING_LENGTH_5TH_BIT_MEDIUM_LIMIT; |
|
1391 value = decodeUtf8StringAsString(); |
|
1392 if ((b & EncodingConstants.NISTRING_ADD_TO_TABLE_FLAG) > 0) { |
|
1393 _attributeValueTable.add(value); |
|
1394 } |
|
1395 |
|
1396 _attributes.addAttribute(name, value); |
|
1397 break; |
|
1398 case DecoderStateTables.NISTRING_UTF16_SMALL_LENGTH: |
|
1399 _octetBufferLength = (b & EncodingConstants.OCTET_STRING_LENGTH_5TH_BIT_SMALL_MASK) + 1; |
|
1400 value = decodeUtf16StringAsString(); |
|
1401 if ((b & EncodingConstants.NISTRING_ADD_TO_TABLE_FLAG) > 0) { |
|
1402 _attributeValueTable.add(value); |
|
1403 } |
|
1404 |
|
1405 _attributes.addAttribute(name, value); |
|
1406 break; |
|
1407 case DecoderStateTables.NISTRING_UTF16_MEDIUM_LENGTH: |
|
1408 _octetBufferLength = read() + EncodingConstants.OCTET_STRING_LENGTH_5TH_BIT_SMALL_LIMIT; |
|
1409 value = decodeUtf16StringAsString(); |
|
1410 if ((b & EncodingConstants.NISTRING_ADD_TO_TABLE_FLAG) > 0) { |
|
1411 _attributeValueTable.add(value); |
|
1412 } |
|
1413 |
|
1414 _attributes.addAttribute(name, value); |
|
1415 break; |
|
1416 case DecoderStateTables.NISTRING_UTF16_LARGE_LENGTH: |
|
1417 _octetBufferLength = ((read() << 24) | |
|
1418 (read() << 16) | |
|
1419 (read() << 8) | |
|
1420 read()) |
|
1421 + EncodingConstants.OCTET_STRING_LENGTH_5TH_BIT_MEDIUM_LIMIT; |
|
1422 value = decodeUtf16StringAsString(); |
|
1423 if ((b & EncodingConstants.NISTRING_ADD_TO_TABLE_FLAG) > 0) { |
|
1424 _attributeValueTable.add(value); |
|
1425 } |
|
1426 |
|
1427 _attributes.addAttribute(name, value); |
|
1428 break; |
|
1429 case DecoderStateTables.NISTRING_RA: |
|
1430 { |
|
1431 final boolean addToTable = (b & EncodingConstants.NISTRING_ADD_TO_TABLE_FLAG) > 0; |
|
1432 // Decode resitricted alphabet integer |
|
1433 _identifier = (b & 0x0F) << 4; |
|
1434 b = read(); |
|
1435 _identifier |= (b & 0xF0) >> 4; |
|
1436 |
|
1437 decodeOctetsOnFifthBitOfNonIdentifyingStringOnFirstBit(b); |
|
1438 |
|
1439 value = decodeRestrictedAlphabetAsString(); |
|
1440 if (addToTable) { |
|
1441 _attributeValueTable.add(value); |
|
1442 } |
|
1443 |
|
1444 _attributes.addAttribute(name, value); |
|
1445 break; |
|
1446 } |
|
1447 case DecoderStateTables.NISTRING_EA: |
|
1448 { |
|
1449 final boolean addToTable = (b & EncodingConstants.NISTRING_ADD_TO_TABLE_FLAG) > 0; |
|
1450 // Decode encoding algorithm integer |
|
1451 _identifier = (b & 0x0F) << 4; |
|
1452 b = read(); |
|
1453 _identifier |= (b & 0xF0) >> 4; |
|
1454 |
|
1455 decodeOctetsOnFifthBitOfNonIdentifyingStringOnFirstBit(b); |
|
1456 processAIIEncodingAlgorithm(name, addToTable); |
|
1457 break; |
|
1458 } |
|
1459 case DecoderStateTables.NISTRING_INDEX_SMALL: |
|
1460 _attributes.addAttribute(name, |
|
1461 _attributeValueTable._array[b & EncodingConstants.INTEGER_2ND_BIT_SMALL_MASK]); |
|
1462 break; |
|
1463 case DecoderStateTables.NISTRING_INDEX_MEDIUM: |
|
1464 { |
|
1465 final int index = (((b & EncodingConstants.INTEGER_2ND_BIT_MEDIUM_MASK) << 8) | read()) |
|
1466 + EncodingConstants.INTEGER_2ND_BIT_SMALL_LIMIT; |
|
1467 |
|
1468 _attributes.addAttribute(name, |
|
1469 _attributeValueTable._array[index]); |
|
1470 break; |
|
1471 } |
|
1472 case DecoderStateTables.NISTRING_INDEX_LARGE: |
|
1473 { |
|
1474 final int index = (((b & EncodingConstants.INTEGER_2ND_BIT_LARGE_MASK) << 16) | (read() << 8) | read()) |
|
1475 + EncodingConstants.INTEGER_2ND_BIT_MEDIUM_LIMIT; |
|
1476 |
|
1477 _attributes.addAttribute(name, |
|
1478 _attributeValueTable._array[index]); |
|
1479 break; |
|
1480 } |
|
1481 case DecoderStateTables.NISTRING_EMPTY: |
|
1482 _attributes.addAttribute(name, ""); |
|
1483 break; |
|
1484 default: |
|
1485 throw new FastInfosetException(CommonResourceBundle.getInstance().getString("message.decodingAIIValue")); |
|
1486 } |
|
1487 |
|
1488 } while (!terminate); |
|
1489 |
|
1490 // Reset duplication attribute verfifier |
|
1491 _duplicateAttributeVerifier._poolCurrent = _duplicateAttributeVerifier._poolHead; |
|
1492 } |
|
1493 |
|
1494 protected final QualifiedName processEIIIndexMedium(int b) throws FastInfosetException, IOException { |
|
1495 final int i = (((b & EncodingConstants.INTEGER_3RD_BIT_MEDIUM_MASK) << 8) | read()) |
|
1496 + EncodingConstants.INTEGER_3RD_BIT_SMALL_LIMIT; |
|
1497 return _elementNameTable._array[i]; |
|
1498 } |
|
1499 |
|
1500 protected final QualifiedName processEIIIndexLarge(int b) throws FastInfosetException, IOException { |
|
1501 int i; |
|
1502 if ((b & EncodingConstants.INTEGER_3RD_BIT_LARGE_LARGE_FLAG) == 0x20) { |
|
1503 // EII large index |
|
1504 i = (((b & EncodingConstants.INTEGER_3RD_BIT_LARGE_MASK) << 16) | (read() << 8) | read()) |
|
1505 + EncodingConstants.INTEGER_3RD_BIT_MEDIUM_LIMIT; |
|
1506 } else { |
|
1507 // EII large large index |
|
1508 i = (((read() & EncodingConstants.INTEGER_3RD_BIT_LARGE_LARGE_MASK) << 16) | (read() << 8) | read()) |
|
1509 + EncodingConstants.INTEGER_3RD_BIT_LARGE_LIMIT; |
|
1510 } |
|
1511 return _elementNameTable._array[i]; |
|
1512 } |
|
1513 |
|
1514 protected final QualifiedName processLiteralQualifiedName(int state, QualifiedName q) |
|
1515 throws FastInfosetException, IOException { |
|
1516 if (q == null) q = new QualifiedName(); |
|
1517 |
|
1518 switch (state) { |
|
1519 // no prefix, no namespace |
|
1520 case 0: |
|
1521 return q.set( |
|
1522 "", |
|
1523 "", |
|
1524 decodeIdentifyingNonEmptyStringOnFirstBit(_v.localName), |
|
1525 "", |
|
1526 0, |
|
1527 -1, |
|
1528 -1, |
|
1529 _identifier); |
|
1530 // no prefix, namespace |
|
1531 case 1: |
|
1532 return q.set( |
|
1533 "", |
|
1534 decodeIdentifyingNonEmptyStringIndexOnFirstBitAsNamespaceName(false), |
|
1535 decodeIdentifyingNonEmptyStringOnFirstBit(_v.localName), |
|
1536 "", |
|
1537 0, |
|
1538 -1, |
|
1539 _namespaceNameIndex, |
|
1540 _identifier); |
|
1541 // prefix, no namespace |
|
1542 case 2: |
|
1543 throw new FastInfosetException(CommonResourceBundle.getInstance().getString("message.qNameMissingNamespaceName")); |
|
1544 // prefix, namespace |
|
1545 case 3: |
|
1546 return q.set( |
|
1547 decodeIdentifyingNonEmptyStringIndexOnFirstBitAsPrefix(true), |
|
1548 decodeIdentifyingNonEmptyStringIndexOnFirstBitAsNamespaceName(true), |
|
1549 decodeIdentifyingNonEmptyStringOnFirstBit(_v.localName), |
|
1550 "", |
|
1551 0, |
|
1552 _prefixIndex, |
|
1553 _namespaceNameIndex, |
|
1554 _identifier); |
|
1555 default: |
|
1556 throw new FastInfosetException(CommonResourceBundle.getInstance().getString("message.decodingEII")); |
|
1557 } |
|
1558 } |
|
1559 |
|
1560 protected final void processCommentII() throws FastInfosetException, IOException { |
|
1561 _eventType = COMMENT; |
|
1562 |
|
1563 switch(decodeNonIdentifyingStringOnFirstBit()) { |
|
1564 case NISTRING_STRING: |
|
1565 if (_addToTable) { |
|
1566 _v.otherString.add(new CharArray(_charBuffer, 0, _charBufferLength, true)); |
|
1567 } |
|
1568 |
|
1569 _characters = _charBuffer; |
|
1570 _charactersOffset = 0; |
|
1571 break; |
|
1572 case NISTRING_ENCODING_ALGORITHM: |
|
1573 throw new FastInfosetException(CommonResourceBundle.getInstance().getString("message.commentIIAlgorithmNotSupported")); |
|
1574 case NISTRING_INDEX: |
|
1575 final CharArray ca = _v.otherString.get(_integer); |
|
1576 |
|
1577 _characters = ca.ch; |
|
1578 _charactersOffset = ca.start; |
|
1579 _charBufferLength = ca.length; |
|
1580 break; |
|
1581 case NISTRING_EMPTY_STRING: |
|
1582 _characters = _charBuffer; |
|
1583 _charactersOffset = 0; |
|
1584 _charBufferLength = 0; |
|
1585 break; |
|
1586 } |
|
1587 } |
|
1588 |
|
1589 protected final void processProcessingII() throws FastInfosetException, IOException { |
|
1590 _eventType = PROCESSING_INSTRUCTION; |
|
1591 |
|
1592 _piTarget = decodeIdentifyingNonEmptyStringOnFirstBit(_v.otherNCName); |
|
1593 |
|
1594 switch(decodeNonIdentifyingStringOnFirstBit()) { |
|
1595 case NISTRING_STRING: |
|
1596 _piData = new String(_charBuffer, 0, _charBufferLength); |
|
1597 if (_addToTable) { |
|
1598 _v.otherString.add(new CharArrayString(_piData)); |
|
1599 } |
|
1600 break; |
|
1601 case NISTRING_ENCODING_ALGORITHM: |
|
1602 throw new FastInfosetException(CommonResourceBundle.getInstance().getString("message.processingIIWithEncodingAlgorithm")); |
|
1603 case NISTRING_INDEX: |
|
1604 _piData = _v.otherString.get(_integer).toString(); |
|
1605 break; |
|
1606 case NISTRING_EMPTY_STRING: |
|
1607 _piData = ""; |
|
1608 break; |
|
1609 } |
|
1610 } |
|
1611 |
|
1612 protected final void processUnexpandedEntityReference(final int b) throws FastInfosetException, IOException { |
|
1613 _eventType = ENTITY_REFERENCE; |
|
1614 |
|
1615 /* |
|
1616 * TODO |
|
1617 * How does StAX report such events? |
|
1618 */ |
|
1619 String entity_reference_name = decodeIdentifyingNonEmptyStringOnFirstBit(_v.otherNCName); |
|
1620 |
|
1621 String system_identifier = ((b & EncodingConstants.UNEXPANDED_ENTITY_SYSTEM_IDENTIFIER_FLAG) > 0) |
|
1622 ? decodeIdentifyingNonEmptyStringOnFirstBit(_v.otherURI) : ""; |
|
1623 String public_identifier = ((b & EncodingConstants.UNEXPANDED_ENTITY_PUBLIC_IDENTIFIER_FLAG) > 0) |
|
1624 ? decodeIdentifyingNonEmptyStringOnFirstBit(_v.otherURI) : ""; |
|
1625 |
|
1626 if (logger.isLoggable(Level.FINEST)) { |
|
1627 logger.log(Level.FINEST, "processUnexpandedEntityReference: entity_reference_name={0} system_identifier={1}public_identifier={2}", |
|
1628 new Object[]{entity_reference_name, system_identifier, public_identifier}); |
|
1629 } |
|
1630 } |
|
1631 |
|
1632 protected final void processCIIEncodingAlgorithm(boolean addToTable) throws FastInfosetException, IOException { |
|
1633 _algorithmData = _octetBuffer; |
|
1634 _algorithmDataOffset = _octetBufferStart; |
|
1635 _algorithmDataLength = _octetBufferLength; |
|
1636 _isAlgorithmDataCloned = false; |
|
1637 |
|
1638 if (_algorithmId >= EncodingConstants.ENCODING_ALGORITHM_APPLICATION_START) { |
|
1639 _algorithmURI = _v.encodingAlgorithm.get(_algorithmId - EncodingConstants.ENCODING_ALGORITHM_APPLICATION_START); |
|
1640 if (_algorithmURI == null) { |
|
1641 throw new EncodingAlgorithmException(CommonResourceBundle.getInstance().getString("message.URINotPresent", new Object[]{Integer.valueOf(_identifier)})); |
|
1642 } |
|
1643 } else if (_algorithmId > EncodingConstants.ENCODING_ALGORITHM_BUILTIN_END) { |
|
1644 // Reserved built-in algorithms for future use |
|
1645 // TODO should use sax property to decide if event will be |
|
1646 // reported, allows for support through handler if required. |
|
1647 throw new EncodingAlgorithmException(CommonResourceBundle.getInstance().getString("message.identifiers10to31Reserved")); |
|
1648 } |
|
1649 |
|
1650 if (addToTable) { |
|
1651 convertEncodingAlgorithmDataToCharacters(); |
|
1652 _characterContentChunkTable.add(_characters, _characters.length); |
|
1653 } |
|
1654 } |
|
1655 |
|
1656 protected final void processAIIEncodingAlgorithm(QualifiedName name, boolean addToTable) throws FastInfosetException, IOException { |
|
1657 EncodingAlgorithm ea = null; |
|
1658 String URI = null; |
|
1659 if (_identifier >= EncodingConstants.ENCODING_ALGORITHM_APPLICATION_START) { |
|
1660 URI = _v.encodingAlgorithm.get(_identifier - EncodingConstants.ENCODING_ALGORITHM_APPLICATION_START); |
|
1661 if (URI == null) { |
|
1662 throw new EncodingAlgorithmException(CommonResourceBundle.getInstance().getString("message.URINotPresent", new Object[]{Integer.valueOf(_identifier)})); |
|
1663 } else if (_registeredEncodingAlgorithms != null) { |
|
1664 ea = (EncodingAlgorithm)_registeredEncodingAlgorithms.get(URI); |
|
1665 } |
|
1666 } else if (_identifier >= EncodingConstants.ENCODING_ALGORITHM_BUILTIN_END) { |
|
1667 if (_identifier == EncodingAlgorithmIndexes.CDATA) { |
|
1668 throw new EncodingAlgorithmException(CommonResourceBundle.getInstance().getString("message.CDATAAlgorithmNotSupported")); |
|
1669 } |
|
1670 |
|
1671 // Reserved built-in algorithms for future use |
|
1672 // TODO should use sax property to decide if event will be |
|
1673 // reported, allows for support through handler if required. |
|
1674 throw new EncodingAlgorithmException(CommonResourceBundle.getInstance().getString("message.identifiers10to31Reserved")); |
|
1675 } else { |
|
1676 ea = BuiltInEncodingAlgorithmFactory.getAlgorithm(_identifier); |
|
1677 } |
|
1678 |
|
1679 Object algorithmData; |
|
1680 |
|
1681 if (ea != null) { |
|
1682 algorithmData = ea.decodeFromBytes(_octetBuffer, _octetBufferStart, |
|
1683 _octetBufferLength); |
|
1684 } else { |
|
1685 final byte[] data = new byte[_octetBufferLength]; |
|
1686 System.arraycopy(_octetBuffer, _octetBufferStart, data, 0, |
|
1687 _octetBufferLength); |
|
1688 algorithmData = data; |
|
1689 } |
|
1690 |
|
1691 _attributes.addAttributeWithAlgorithmData(name, URI, _identifier, |
|
1692 algorithmData); |
|
1693 if (addToTable) { |
|
1694 _attributeValueTable.add(_attributes.getValue(_attributes.getIndex(name.qName))); |
|
1695 } |
|
1696 } |
|
1697 |
|
1698 protected final void convertEncodingAlgorithmDataToCharacters() throws FastInfosetException, IOException { |
|
1699 StringBuffer buffer = new StringBuffer(); |
|
1700 if (_algorithmId == EncodingAlgorithmIndexes.BASE64) { |
|
1701 convertBase64AlorithmDataToCharacters(buffer); |
|
1702 } else if (_algorithmId < EncodingConstants.ENCODING_ALGORITHM_BUILTIN_END) { |
|
1703 Object array = BuiltInEncodingAlgorithmFactory.getAlgorithm(_algorithmId). |
|
1704 decodeFromBytes(_algorithmData, _algorithmDataOffset, _algorithmDataLength); |
|
1705 BuiltInEncodingAlgorithmFactory.getAlgorithm(_algorithmId).convertToCharacters(array, buffer); |
|
1706 } else if (_algorithmId == EncodingAlgorithmIndexes.CDATA) { |
|
1707 _octetBufferOffset -= _octetBufferLength; |
|
1708 decodeUtf8StringIntoCharBuffer(); |
|
1709 |
|
1710 _characters = _charBuffer; |
|
1711 _charactersOffset = 0; |
|
1712 return; |
|
1713 } else if (_algorithmId >= EncodingConstants.ENCODING_ALGORITHM_APPLICATION_START) { |
|
1714 final EncodingAlgorithm ea = (EncodingAlgorithm)_registeredEncodingAlgorithms.get(_algorithmURI); |
|
1715 if (ea != null) { |
|
1716 final Object data = ea.decodeFromBytes(_octetBuffer, _octetBufferStart, _octetBufferLength); |
|
1717 ea.convertToCharacters(data, buffer); |
|
1718 } else { |
|
1719 throw new EncodingAlgorithmException( |
|
1720 CommonResourceBundle.getInstance().getString("message.algorithmDataCannotBeReported")); |
|
1721 } |
|
1722 } |
|
1723 |
|
1724 _characters = new char[buffer.length()]; |
|
1725 buffer.getChars(0, buffer.length(), _characters, 0); |
|
1726 _charactersOffset = 0; |
|
1727 _charBufferLength = _characters.length; |
|
1728 } |
|
1729 |
|
1730 /* If base64 data comes is chunks, bytes, which were cut to align 3, |
|
1731 * from prev. base64 chunk are stored in this buffer */ |
|
1732 private byte[] base64TaleBytes = new byte[3]; |
|
1733 private int base64TaleLength; |
|
1734 /* |
|
1735 * Method converts _algorithmData to base64 encoded String |
|
1736 * Counts with base64 data coming in chunks, aligning input chunks by 3, |
|
1737 * avoiding double cloning, happening after possible peek, peek2 cloning by Base64 algorithm |
|
1738 */ |
|
1739 protected void convertBase64AlorithmDataToCharacters(StringBuffer buffer) throws EncodingAlgorithmException, IOException { |
|
1740 // How much new came data was serialized with prev. tale |
|
1741 int afterTaleOffset = 0; |
|
1742 |
|
1743 if (base64TaleLength > 0) { |
|
1744 // Serialize tale left from prev. chunk |
|
1745 int bytesToCopy = Math.min(3 - base64TaleLength, _algorithmDataLength); |
|
1746 System.arraycopy(_algorithmData, _algorithmDataOffset, base64TaleBytes, base64TaleLength, bytesToCopy); |
|
1747 if (base64TaleLength + bytesToCopy == 3) { |
|
1748 base64DecodeWithCloning(buffer, base64TaleBytes, 0, 3); |
|
1749 } else if (!isBase64Follows()) { |
|
1750 // End of text was read to temp array |
|
1751 base64DecodeWithCloning(buffer, base64TaleBytes, 0, base64TaleLength + bytesToCopy); |
|
1752 return; |
|
1753 } else { |
|
1754 // If the end of chunk fit to tmp array, but next chunk is expected |
|
1755 base64TaleLength += bytesToCopy; |
|
1756 return; |
|
1757 } |
|
1758 |
|
1759 afterTaleOffset = bytesToCopy; |
|
1760 base64TaleLength = 0; |
|
1761 } |
|
1762 |
|
1763 int taleBytesRemaining = isBase64Follows() ? (_algorithmDataLength - afterTaleOffset) % 3 : 0; |
|
1764 |
|
1765 if (_isAlgorithmDataCloned) { |
|
1766 base64DecodeWithoutCloning(buffer, _algorithmData, _algorithmDataOffset + afterTaleOffset, |
|
1767 _algorithmDataLength - afterTaleOffset - taleBytesRemaining); |
|
1768 } else { |
|
1769 base64DecodeWithCloning(buffer, _algorithmData, _algorithmDataOffset + afterTaleOffset, |
|
1770 _algorithmDataLength - afterTaleOffset - taleBytesRemaining); |
|
1771 } |
|
1772 |
|
1773 if (taleBytesRemaining > 0) { |
|
1774 System.arraycopy(_algorithmData, _algorithmDataOffset + _algorithmDataLength - taleBytesRemaining, |
|
1775 base64TaleBytes, 0, taleBytesRemaining); |
|
1776 base64TaleLength = taleBytesRemaining; |
|
1777 } |
|
1778 } |
|
1779 |
|
1780 /* |
|
1781 * Encodes incoming data to Base64 string. |
|
1782 * Method performs additional input data cloning |
|
1783 */ |
|
1784 private void base64DecodeWithCloning(StringBuffer dstBuffer, byte[] data, int offset, int length) throws EncodingAlgorithmException { |
|
1785 Object array = BuiltInEncodingAlgorithmFactory.base64EncodingAlgorithm. |
|
1786 decodeFromBytes(data, offset, length); |
|
1787 BuiltInEncodingAlgorithmFactory.base64EncodingAlgorithm.convertToCharacters(array, dstBuffer); |
|
1788 } |
|
1789 |
|
1790 /* |
|
1791 * Encodes incoming data to Base64 string. |
|
1792 * Avoids input data cloning |
|
1793 */ |
|
1794 private void base64DecodeWithoutCloning(StringBuffer dstBuffer, byte[] data, int offset, int length) throws EncodingAlgorithmException { |
|
1795 BuiltInEncodingAlgorithmFactory.base64EncodingAlgorithm.convertToCharacters(data, offset, length, dstBuffer); |
|
1796 } |
|
1797 |
|
1798 |
|
1799 /* |
|
1800 * Looks ahead in InputStream, whether next data is Base64 chunk |
|
1801 */ |
|
1802 public boolean isBase64Follows() throws IOException { |
|
1803 // Process information item |
|
1804 int b = peek(this); |
|
1805 switch (DecoderStateTables.EII(b)) { |
|
1806 case DecoderStateTables.CII_EA: |
|
1807 int algorithmId = (b & 0x02) << 6; |
|
1808 int b2 = peek2(this); |
|
1809 algorithmId |= (b2 & 0xFC) >> 2; |
|
1810 |
|
1811 return algorithmId == EncodingAlgorithmIndexes.BASE64; |
|
1812 default: |
|
1813 return false; |
|
1814 } |
|
1815 } |
|
1816 |
|
1817 protected class NamespaceContextImpl implements NamespaceContext { |
|
1818 public final String getNamespaceURI(String prefix) { |
|
1819 return _prefixTable.getNamespaceFromPrefix(prefix); |
|
1820 } |
|
1821 |
|
1822 public final String getPrefix(String namespaceURI) { |
|
1823 return _prefixTable.getPrefixFromNamespace(namespaceURI); |
|
1824 } |
|
1825 |
|
1826 public final Iterator getPrefixes(String namespaceURI) { |
|
1827 return _prefixTable.getPrefixesFromNamespace(namespaceURI); |
|
1828 } |
|
1829 } |
|
1830 |
|
1831 public final String getNamespaceDecl(String prefix) { |
|
1832 return _prefixTable.getNamespaceFromPrefix(prefix); |
|
1833 } |
|
1834 |
|
1835 public final String getURI(String prefix) { |
|
1836 return getNamespaceDecl(prefix); |
|
1837 } |
|
1838 |
|
1839 public final Iterator getPrefixes() { |
|
1840 return _prefixTable.getPrefixes(); |
|
1841 } |
|
1842 |
|
1843 public final AttributesHolder getAttributesHolder() { |
|
1844 return _attributes; |
|
1845 } |
|
1846 |
|
1847 public final void setManager(StAXManager manager) { |
|
1848 _manager = manager; |
|
1849 } |
|
1850 |
|
1851 final static String getEventTypeString(int eventType) { |
|
1852 switch (eventType){ |
|
1853 case START_ELEMENT: |
|
1854 return "START_ELEMENT"; |
|
1855 case END_ELEMENT: |
|
1856 return "END_ELEMENT"; |
|
1857 case PROCESSING_INSTRUCTION: |
|
1858 return "PROCESSING_INSTRUCTION"; |
|
1859 case CHARACTERS: |
|
1860 return "CHARACTERS"; |
|
1861 case COMMENT: |
|
1862 return "COMMENT"; |
|
1863 case START_DOCUMENT: |
|
1864 return "START_DOCUMENT"; |
|
1865 case END_DOCUMENT: |
|
1866 return "END_DOCUMENT"; |
|
1867 case ENTITY_REFERENCE: |
|
1868 return "ENTITY_REFERENCE"; |
|
1869 case ATTRIBUTE: |
|
1870 return "ATTRIBUTE"; |
|
1871 case DTD: |
|
1872 return "DTD"; |
|
1873 case CDATA: |
|
1874 return "CDATA"; |
|
1875 } |
|
1876 return "UNKNOWN_EVENT_TYPE"; |
|
1877 } |
|
1878 } |