001: /*
002: * Fast Infoset ver. 0.1 software ("Software")
003: *
004: * Copyright, 2004-2005 Sun Microsystems, Inc. All Rights Reserved.
005: *
006: * Software is licensed under the Apache License, Version 2.0 (the "License");
007: * you may not use this file except in compliance with the License. You may
008: * obtain a copy of the License at:
009: *
010: * http://www.apache.org/licenses/LICENSE-2.0
011: *
012: * Unless required by applicable law or agreed to in writing, software
013: * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
014: * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
015: * License for the specific language governing permissions and limitations.
016: *
017: * Sun supports and benefits from the global community of open source
018: * developers, and thanks the community for its important contributions and
019: * open standards-based technology, which Sun has adopted into many of its
020: * products.
021: *
022: * Please note that portions of Software may be provided with notices and
023: * open source licenses from such communities and third parties that govern the
024: * use of those portions, and any licenses granted hereunder do not alter any
025: * rights and obligations you may have under such open source licenses,
026: * however, the disclaimer of warranty and limitation of liability provisions
027: * in this License will apply to all Software in this distribution.
028: *
029: * You acknowledge that the Software is not designed, licensed or intended
030: * for use in the design, construction, operation or maintenance of any nuclear
031: * facility.
032: *
033: * Apache License
034: * Version 2.0, January 2004
035: * http://www.apache.org/licenses/
036: *
037: */
038:
039: package com.sun.xml.fastinfoset.stax;
040:
041: import com.sun.xml.fastinfoset.Encoder;
042: import com.sun.xml.fastinfoset.EncodingConstants;
043: import com.sun.xml.fastinfoset.util.NamespaceContextImplementation;
044: import java.io.IOException;
045: import java.io.OutputStream;
046: import java.util.EmptyStackException;
047: import javax.xml.namespace.NamespaceContext;
048: import javax.xml.stream.XMLStreamException;
049: import javax.xml.stream.XMLStreamWriter;
050: import org.jvnet.fastinfoset.EncodingAlgorithmIndexes;
051: import com.sun.xml.fastinfoset.CommonResourceBundle;
052: import com.sun.xml.fastinfoset.QualifiedName;
053: import com.sun.xml.fastinfoset.util.LocalNameQualifiedNamesMap;
054: import org.jvnet.fastinfoset.stax.LowLevelFastInfosetStreamWriter;
055:
056: /**
057: * The Fast Infoset StAX serializer.
058: * <p>
059: * Instantiate this serializer to serialize a fast infoset document in accordance
060: * with the StAX API.
061: *
062: * <p>
063: * More than one fast infoset document may be encoded to the
064: * {@link java.io.OutputStream}.
065: */
066: public class StAXDocumentSerializer extends Encoder implements
067: XMLStreamWriter, LowLevelFastInfosetStreamWriter {
068: protected StAXManager _manager;
069:
070: protected String _encoding;
071: /**
072: * Local name of current element.
073: */
074: protected String _currentLocalName;
075:
076: /**
077: * Namespace of current element.
078: */
079: protected String _currentUri;
080:
081: /**
082: * Prefix of current element.
083: */
084: protected String _currentPrefix;
085:
086: /**
087: * This flag indicates when there is a pending start element event.
088: */
089: protected boolean _inStartElement = false;
090:
091: /**
092: * This flag indicates if the current element is empty.
093: */
094: protected boolean _isEmptyElement = false;
095:
096: /**
097: * List of attributes qnames and values defined in the current element.
098: */
099: protected String[] _attributesArray = new String[4 * 16];
100: protected int _attributesArrayIndex = 0;
101:
102: protected boolean[] _nsSupportContextStack = new boolean[32];
103: protected int _stackCount = -1;
104:
105: /**
106: * Mapping between uris and prefixes.
107: */
108: protected NamespaceContextImplementation _nsContext = new NamespaceContextImplementation();
109:
110: /**
111: * List of namespaces defined in the current element.
112: */
113: protected String[] _namespacesArray = new String[2 * 8];
114: protected int _namespacesArrayIndex = 0;
115:
116: public StAXDocumentSerializer() {
117: super (true);
118: _manager = new StAXManager(StAXManager.CONTEXT_WRITER);
119: }
120:
121: public StAXDocumentSerializer(OutputStream outputStream) {
122: super (true);
123: setOutputStream(outputStream);
124: _manager = new StAXManager(StAXManager.CONTEXT_WRITER);
125: }
126:
127: public StAXDocumentSerializer(OutputStream outputStream,
128: StAXManager manager) {
129: super (true);
130: setOutputStream(outputStream);
131: _manager = manager;
132: }
133:
134: public void reset() {
135: super .reset();
136:
137: _attributesArrayIndex = 0;
138: _namespacesArrayIndex = 0;
139:
140: _nsContext.reset();
141: _stackCount = -1;
142:
143: _currentUri = _currentPrefix = null;
144: _currentLocalName = null;
145:
146: _inStartElement = _isEmptyElement = false;
147: }
148:
149: // -- XMLStreamWriter Interface -------------------------------------------
150:
151: public void writeStartDocument() throws XMLStreamException {
152: writeStartDocument("finf", "1.0");
153: }
154:
155: public void writeStartDocument(String version)
156: throws XMLStreamException {
157: writeStartDocument("finf", version);
158: }
159:
160: public void writeStartDocument(String encoding, String version)
161: throws XMLStreamException {
162: reset();
163:
164: try {
165: encodeHeader(false);
166: encodeInitialVocabulary();
167: } catch (IOException e) {
168: throw new XMLStreamException(e);
169: }
170: }
171:
172: public void writeEndDocument() throws XMLStreamException {
173: try {
174:
175: // terminate all elements not terminated
176: // by writeEndElement
177: for (; _stackCount >= 0; _stackCount--) {
178: writeEndElement();
179: }
180:
181: encodeDocumentTermination();
182: } catch (IOException e) {
183: throw new XMLStreamException(e);
184: }
185: }
186:
187: public void close() throws XMLStreamException {
188: reset();
189: }
190:
191: public void flush() throws XMLStreamException {
192: try {
193: _s.flush();
194: } catch (IOException e) {
195: throw new XMLStreamException(e);
196: }
197: }
198:
199: public void writeStartElement(String localName)
200: throws XMLStreamException {
201: // TODO is it necessary for FI to obtain the default namespace in scope?
202: writeStartElement("", localName, "");
203: }
204:
205: public void writeStartElement(String namespaceURI, String localName)
206: throws XMLStreamException {
207: writeStartElement(getPrefix(namespaceURI), localName,
208: namespaceURI);
209: }
210:
211: public void writeStartElement(String prefix, String localName,
212: String namespaceURI) throws XMLStreamException {
213: encodeTerminationAndCurrentElement(false);
214:
215: _inStartElement = true;
216: _isEmptyElement = false;
217:
218: _currentLocalName = localName;
219: _currentPrefix = prefix;
220: _currentUri = namespaceURI;
221:
222: _stackCount++;
223: if (_stackCount == _nsSupportContextStack.length) {
224: boolean[] nsSupportContextStack = new boolean[_stackCount * 2];
225: System.arraycopy(_nsSupportContextStack, 0,
226: nsSupportContextStack, 0,
227: _nsSupportContextStack.length);
228: _nsSupportContextStack = nsSupportContextStack;
229: }
230:
231: _nsSupportContextStack[_stackCount] = false;
232: }
233:
234: public void writeEmptyElement(String localName)
235: throws XMLStreamException {
236: writeEmptyElement("", localName, "");
237: }
238:
239: public void writeEmptyElement(String namespaceURI, String localName)
240: throws XMLStreamException {
241: writeEmptyElement(getPrefix(namespaceURI), localName,
242: namespaceURI);
243: }
244:
245: public void writeEmptyElement(String prefix, String localName,
246: String namespaceURI) throws XMLStreamException {
247: encodeTerminationAndCurrentElement(false);
248:
249: _isEmptyElement = _inStartElement = true;
250:
251: _currentLocalName = localName;
252: _currentPrefix = prefix;
253: _currentUri = namespaceURI;
254:
255: _stackCount++;
256: if (_stackCount == _nsSupportContextStack.length) {
257: boolean[] nsSupportContextStack = new boolean[_stackCount * 2];
258: System.arraycopy(_nsSupportContextStack, 0,
259: nsSupportContextStack, 0,
260: _nsSupportContextStack.length);
261: _nsSupportContextStack = nsSupportContextStack;
262: }
263:
264: _nsSupportContextStack[_stackCount] = false;
265: }
266:
267: public void writeEndElement() throws XMLStreamException {
268: if (_inStartElement) {
269: encodeTerminationAndCurrentElement(false);
270: }
271:
272: try {
273: encodeElementTermination();
274: if (_nsSupportContextStack[_stackCount--] == true) {
275: _nsContext.popContext();
276: }
277: } catch (IOException e) {
278: throw new XMLStreamException(e);
279: } catch (EmptyStackException e) {
280: throw new XMLStreamException(e);
281: }
282: }
283:
284: public void writeAttribute(String localName, String value)
285: throws XMLStreamException {
286: writeAttribute("", "", localName, value);
287: }
288:
289: public void writeAttribute(String namespaceURI, String localName,
290: String value) throws XMLStreamException {
291: String prefix = "";
292:
293: // Find prefix for attribute, ignoring default namespace
294: if (namespaceURI.length() > 0) {
295: prefix = _nsContext.getNonDefaultPrefix(namespaceURI);
296:
297: // Undeclared prefix or ignorable default ns?
298: if (prefix == null || prefix.length() == 0) {
299: // Workaround for BUG in SAX NamespaceSupport helper
300: // which incorrectly defines namespace declaration URI
301: if (namespaceURI == EncodingConstants.XMLNS_NAMESPACE_NAME
302: || namespaceURI
303: .equals(EncodingConstants.XMLNS_NAMESPACE_NAME)) {
304: // TODO
305: // Need to check carefully the rule for the writing of
306: // namespaces in StAX. Is it safe to ignore such
307: // attributes, as declarations will be made using the
308: // writeNamespace method
309: return;
310: }
311: throw new XMLStreamException(CommonResourceBundle
312: .getInstance().getString("message.URIUnbound",
313: new Object[] { namespaceURI }));
314: }
315: }
316: writeAttribute(prefix, namespaceURI, localName, value);
317: }
318:
319: public void writeAttribute(String prefix, String namespaceURI,
320: String localName, String value) throws XMLStreamException {
321: if (!_inStartElement) {
322: throw new IllegalStateException(CommonResourceBundle
323: .getInstance().getString(
324: "message.attributeWritingNotAllowed"));
325: }
326:
327: // TODO
328: // Need to check carefully the rule for the writing of
329: // namespaces in StAX. Is it safe to ignore such
330: // attributes, as declarations will be made using the
331: // writeNamespace method
332: if (namespaceURI == EncodingConstants.XMLNS_NAMESPACE_NAME
333: || namespaceURI
334: .equals(EncodingConstants.XMLNS_NAMESPACE_NAME)) {
335: return;
336: }
337:
338: if (_attributesArrayIndex == _attributesArray.length) {
339: final String[] attributesArray = new String[_attributesArrayIndex * 2];
340: System.arraycopy(_attributesArray, 0, attributesArray, 0,
341: _attributesArrayIndex);
342: _attributesArray = attributesArray;
343: }
344:
345: _attributesArray[_attributesArrayIndex++] = namespaceURI;
346: _attributesArray[_attributesArrayIndex++] = prefix;
347: _attributesArray[_attributesArrayIndex++] = localName;
348: _attributesArray[_attributesArrayIndex++] = value;
349: }
350:
351: public void writeNamespace(String prefix, String namespaceURI)
352: throws XMLStreamException {
353: if (prefix == null
354: || prefix.length() == 0
355: || prefix
356: .equals(EncodingConstants.XMLNS_NAMESPACE_PREFIX)) {
357: writeDefaultNamespace(namespaceURI);
358: } else {
359: if (!_inStartElement) {
360: throw new IllegalStateException(CommonResourceBundle
361: .getInstance().getString(
362: "message.attributeWritingNotAllowed"));
363: }
364:
365: if (_namespacesArrayIndex == _namespacesArray.length) {
366: final String[] namespacesArray = new String[_namespacesArrayIndex * 2];
367: System.arraycopy(_namespacesArray, 0, namespacesArray,
368: 0, _namespacesArrayIndex);
369: _namespacesArray = namespacesArray;
370: }
371:
372: _namespacesArray[_namespacesArrayIndex++] = prefix;
373: _namespacesArray[_namespacesArrayIndex++] = namespaceURI;
374: setPrefix(prefix, namespaceURI);
375: }
376: }
377:
378: public void writeDefaultNamespace(String namespaceURI)
379: throws XMLStreamException {
380: if (!_inStartElement) {
381: throw new IllegalStateException(CommonResourceBundle
382: .getInstance().getString(
383: "message.attributeWritingNotAllowed"));
384: }
385:
386: if (_namespacesArrayIndex == _namespacesArray.length) {
387: final String[] namespacesArray = new String[_namespacesArrayIndex * 2];
388: System.arraycopy(_namespacesArray, 0, namespacesArray, 0,
389: _namespacesArrayIndex);
390: _namespacesArray = namespacesArray;
391: }
392:
393: _namespacesArray[_namespacesArrayIndex++] = "";
394: _namespacesArray[_namespacesArrayIndex++] = namespaceURI;
395: setPrefix("", namespaceURI);
396: }
397:
398: public void writeComment(String data) throws XMLStreamException {
399: try {
400: if (getIgnoreComments())
401: return;
402:
403: encodeTerminationAndCurrentElement(true);
404:
405: // TODO: avoid array copy here
406: encodeComment(data.toCharArray(), 0, data.length());
407: } catch (IOException e) {
408: throw new XMLStreamException(e);
409: }
410: }
411:
412: public void writeProcessingInstruction(String target)
413: throws XMLStreamException {
414: writeProcessingInstruction(target, "");
415: }
416:
417: public void writeProcessingInstruction(String target, String data)
418: throws XMLStreamException {
419: try {
420: if (getIgnoreProcesingInstructions())
421: return;
422:
423: encodeTerminationAndCurrentElement(true);
424:
425: encodeProcessingInstruction(target, data);
426: } catch (IOException e) {
427: throw new XMLStreamException(e);
428: }
429: }
430:
431: public void writeCData(String data) throws XMLStreamException {
432: throw new UnsupportedOperationException(CommonResourceBundle
433: .getInstance().getString("message.notImplemented"));
434: }
435:
436: public void writeDTD(String dtd) throws XMLStreamException {
437: throw new UnsupportedOperationException(CommonResourceBundle
438: .getInstance().getString("message.notImplemented"));
439: }
440:
441: public void writeEntityRef(String name) throws XMLStreamException {
442: throw new UnsupportedOperationException(CommonResourceBundle
443: .getInstance().getString("message.notImplemented"));
444: }
445:
446: public void writeCharacters(String text) throws XMLStreamException {
447: try {
448: final int length = text.length();
449: if (length == 0) {
450: return;
451: } else if (length < _charBuffer.length) {
452: if (getIgnoreWhiteSpaceTextContent()
453: && isWhiteSpace(text))
454: return;
455:
456: // Warning: this method must be called before any state
457: // is modified, such as the _charBuffer contents,
458: // so the characters of text cannot be copied to _charBuffer
459: // before this call
460: encodeTerminationAndCurrentElement(true);
461:
462: text.getChars(0, length, _charBuffer, 0);
463: encodeCharacters(_charBuffer, 0, length);
464: } else {
465: final char ch[] = text.toCharArray();
466: if (getIgnoreWhiteSpaceTextContent()
467: && isWhiteSpace(ch, 0, length))
468: return;
469:
470: encodeTerminationAndCurrentElement(true);
471:
472: encodeCharactersNoClone(ch, 0, length);
473: }
474: } catch (IOException e) {
475: throw new XMLStreamException(e);
476: }
477: }
478:
479: public void writeCharacters(char[] text, int start, int len)
480: throws XMLStreamException {
481: try {
482: if (len <= 0) {
483: return;
484: }
485:
486: if (getIgnoreWhiteSpaceTextContent()
487: && isWhiteSpace(text, start, len))
488: return;
489:
490: encodeTerminationAndCurrentElement(true);
491:
492: encodeCharacters(text, start, len);
493: } catch (IOException e) {
494: throw new XMLStreamException(e);
495: }
496: }
497:
498: public String getPrefix(String uri) throws XMLStreamException {
499: return _nsContext.getPrefix(uri);
500: }
501:
502: public void setPrefix(String prefix, String uri)
503: throws XMLStreamException {
504: if (_stackCount > -1
505: && _nsSupportContextStack[_stackCount] == false) {
506: _nsSupportContextStack[_stackCount] = true;
507: _nsContext.pushContext();
508: }
509:
510: _nsContext.declarePrefix(prefix, uri);
511: }
512:
513: public void setDefaultNamespace(String uri)
514: throws XMLStreamException {
515: setPrefix("", uri);
516: }
517:
518: /**
519: * Sets the current namespace context for prefix and uri bindings.
520: * This context becomes the root namespace context for writing and
521: * will replace the current root namespace context. Subsequent calls
522: * to setPrefix and setDefaultNamespace will bind namespaces using
523: * the context passed to the method as the root context for resolving
524: * namespaces. This method may only be called once at the start of
525: * the document. It does not cause the namespaces to be declared.
526: * If a namespace URI to prefix mapping is found in the namespace
527: * context it is treated as declared and the prefix may be used
528: * by the StreamWriter.
529: * @param context the namespace context to use for this writer, may not be null
530: * @throws XMLStreamException
531: */
532: public void setNamespaceContext(NamespaceContext context)
533: throws XMLStreamException {
534: throw new UnsupportedOperationException("setNamespaceContext");
535: }
536:
537: public NamespaceContext getNamespaceContext() {
538: return _nsContext;
539: }
540:
541: public Object getProperty(java.lang.String name)
542: throws IllegalArgumentException {
543: if (_manager != null) {
544: return _manager.getProperty(name);
545: }
546: return null;
547: }
548:
549: public void setManager(StAXManager manager) {
550: _manager = manager;
551: }
552:
553: public void setEncoding(String encoding) {
554: _encoding = encoding;
555: }
556:
557: public void writeOctets(byte[] b, int start, int len)
558: throws XMLStreamException {
559: try {
560: if (len == 0) {
561: return;
562: }
563:
564: encodeTerminationAndCurrentElement(true);
565:
566: encodeCIIOctetAlgorithmData(
567: EncodingAlgorithmIndexes.BASE64, b, start, len);
568: } catch (IOException e) {
569: throw new XMLStreamException(e);
570: }
571: }
572:
573: protected void encodeTerminationAndCurrentElement(
574: boolean terminateAfter) throws XMLStreamException {
575: try {
576: encodeTermination();
577:
578: if (_inStartElement) {
579:
580: _b = EncodingConstants.ELEMENT;
581: if (_attributesArrayIndex > 0) {
582: _b |= EncodingConstants.ELEMENT_ATTRIBUTE_FLAG;
583: }
584:
585: // Encode namespace decls associated with this element
586: if (_namespacesArrayIndex > 0) {
587: write(_b
588: | EncodingConstants.ELEMENT_NAMESPACES_FLAG);
589: for (int i = 0; i < _namespacesArrayIndex;) {
590: encodeNamespaceAttribute(_namespacesArray[i++],
591: _namespacesArray[i++]);
592: }
593: _namespacesArrayIndex = 0;
594:
595: write(EncodingConstants.TERMINATOR);
596:
597: _b = 0;
598: }
599:
600: // If element's prefix is empty - apply default scope namespace
601: if (_currentPrefix.length() == 0
602: && _currentUri.length() == 0) {
603: _currentUri = _nsContext.getNamespaceURI("");
604: }
605:
606: encodeElementQualifiedNameOnThirdBit(_currentUri,
607: _currentPrefix, _currentLocalName);
608:
609: for (int i = 0; i < _attributesArrayIndex;) {
610: encodeAttributeQualifiedNameOnSecondBit(
611: _attributesArray[i++],
612: _attributesArray[i++],
613: _attributesArray[i++]);
614:
615: final String value = _attributesArray[i];
616: _attributesArray[i++] = null;
617: final boolean addToTable = isAttributeValueLengthMatchesLimit(value
618: .length());
619: encodeNonIdentifyingStringOnFirstBit(value,
620: _v.attributeValue, addToTable);
621:
622: _b = EncodingConstants.TERMINATOR;
623: _terminate = true;
624: }
625: _attributesArrayIndex = 0;
626: _inStartElement = false;
627:
628: if (_isEmptyElement) {
629: encodeElementTermination();
630: if (_nsSupportContextStack[_stackCount--] == true) {
631: _nsContext.popContext();
632: }
633:
634: _isEmptyElement = false;
635: }
636:
637: if (terminateAfter) {
638: encodeTermination();
639: }
640: }
641: } catch (IOException e) {
642: throw new XMLStreamException(e);
643: }
644: }
645:
646: // LowLevelFastInfosetSerializer
647:
648: public final void initiateLowLevelWriting()
649: throws XMLStreamException {
650: encodeTerminationAndCurrentElement(false);
651: }
652:
653: public final int getNextElementIndex() {
654: return _v.elementName.getNextIndex();
655: }
656:
657: public final int getNextAttributeIndex() {
658: return _v.attributeName.getNextIndex();
659: }
660:
661: public final int getLocalNameIndex() {
662: return _v.localName.getIndex();
663: }
664:
665: public final int getNextLocalNameIndex() {
666: return _v.localName.getNextIndex();
667: }
668:
669: public final void writeLowLevelTerminationAndMark()
670: throws IOException {
671: encodeTermination();
672: mark();
673: }
674:
675: public final void writeLowLevelStartElementIndexed(int type,
676: int index) throws IOException {
677: _b = type;
678: encodeNonZeroIntegerOnThirdBit(index);
679: }
680:
681: public final boolean writeLowLevelStartElement(int type,
682: String prefix, String localName, String namespaceURI)
683: throws IOException {
684: final boolean isIndexed = encodeElement(type, namespaceURI,
685: prefix, localName);
686:
687: if (!isIndexed)
688: encodeLiteral(type
689: | EncodingConstants.ELEMENT_LITERAL_QNAME_FLAG,
690: namespaceURI, prefix, localName);
691:
692: return isIndexed;
693: }
694:
695: public final void writeLowLevelStartNamespaces() throws IOException {
696: write(EncodingConstants.ELEMENT
697: | EncodingConstants.ELEMENT_NAMESPACES_FLAG);
698: }
699:
700: public final void writeLowLevelNamespace(String prefix,
701: String namespaceName) throws IOException {
702: encodeNamespaceAttribute(prefix, namespaceName);
703: }
704:
705: public final void writeLowLevelEndNamespaces() throws IOException {
706: write(EncodingConstants.TERMINATOR);
707: }
708:
709: public final void writeLowLevelStartAttributes() throws IOException {
710: if (hasMark()) {
711: _octetBuffer[_markIndex] |= EncodingConstants.ELEMENT_ATTRIBUTE_FLAG;
712: resetMark();
713: }
714: }
715:
716: public final void writeLowLevelAttributeIndexed(int index)
717: throws IOException {
718: encodeNonZeroIntegerOnSecondBitFirstBitZero(index);
719: }
720:
721: public final boolean writeLowLevelAttribute(String prefix,
722: String namespaceURI, String localName) throws IOException {
723: final boolean isIndexed = encodeAttribute(namespaceURI, prefix,
724: localName);
725:
726: if (!isIndexed)
727: encodeLiteral(
728: EncodingConstants.ATTRIBUTE_LITERAL_QNAME_FLAG,
729: namespaceURI, prefix, localName);
730:
731: return isIndexed;
732: }
733:
734: public final void writeLowLevelAttributeValue(String value)
735: throws IOException {
736: final boolean addToTable = isAttributeValueLengthMatchesLimit(value
737: .length());
738: encodeNonIdentifyingStringOnFirstBit(value, _v.attributeValue,
739: addToTable);
740: }
741:
742: public final void writeLowLevelStartNameLiteral(int type,
743: String prefix, byte[] utf8LocalName, String namespaceURI)
744: throws IOException {
745: encodeLiteralHeader(type, namespaceURI, prefix);
746: encodeNonZeroOctetStringLengthOnSecondBit(utf8LocalName.length);
747: write(utf8LocalName, 0, utf8LocalName.length);
748: }
749:
750: public final void writeLowLevelStartNameLiteral(int type,
751: String prefix, int localNameIndex, String namespaceURI)
752: throws IOException {
753: encodeLiteralHeader(type, namespaceURI, prefix);
754: encodeNonZeroIntegerOnSecondBitFirstBitOne(localNameIndex);
755: }
756:
757: public final void writeLowLevelEndStartElement() throws IOException {
758: if (hasMark()) {
759: resetMark();
760: } else {
761: // Terminate the attributes
762: _b = EncodingConstants.TERMINATOR;
763: _terminate = true;
764: }
765: }
766:
767: public final void writeLowLevelEndElement() throws IOException {
768: encodeElementTermination();
769: }
770:
771: public final void writeLowLevelText(char[] text, int length)
772: throws IOException {
773: if (length == 0)
774: return;
775:
776: encodeTermination();
777:
778: encodeCharacters(text, 0, length);
779: }
780:
781: public final void writeLowLevelText(String text) throws IOException {
782: final int length = text.length();
783: if (length == 0)
784: return;
785:
786: encodeTermination();
787:
788: if (length < _charBuffer.length) {
789: text.getChars(0, length, _charBuffer, 0);
790: encodeCharacters(_charBuffer, 0, length);
791: } else {
792: final char ch[] = text.toCharArray();
793: encodeCharactersNoClone(ch, 0, length);
794: }
795: }
796:
797: public final void writeLowLevelOctets(byte[] octets, int length)
798: throws IOException {
799: if (length == 0)
800: return;
801:
802: encodeTermination();
803:
804: encodeCIIOctetAlgorithmData(EncodingAlgorithmIndexes.BASE64,
805: octets, 0, length);
806: }
807:
808: private boolean encodeElement(int type, String namespaceURI,
809: String prefix, String localName) throws IOException {
810: final LocalNameQualifiedNamesMap.Entry entry = _v.elementName
811: .obtainEntry(localName);
812: for (int i = 0; i < entry._valueIndex; i++) {
813: final QualifiedName name = entry._value[i];
814: if ((prefix == name.prefix || prefix.equals(name.prefix))
815: && (namespaceURI == name.namespaceName || namespaceURI
816: .equals(name.namespaceName))) {
817: _b = type;
818: encodeNonZeroIntegerOnThirdBit(name.index);
819: return true;
820: }
821: }
822:
823: entry.addQualifiedName(new QualifiedName(prefix, namespaceURI,
824: localName, "", _v.elementName.getNextIndex()));
825: return false;
826: }
827:
828: private boolean encodeAttribute(String namespaceURI, String prefix,
829: String localName) throws IOException {
830: final LocalNameQualifiedNamesMap.Entry entry = _v.attributeName
831: .obtainEntry(localName);
832: for (int i = 0; i < entry._valueIndex; i++) {
833: final QualifiedName name = entry._value[i];
834: if ((prefix == name.prefix || prefix.equals(name.prefix))
835: && (namespaceURI == name.namespaceName || namespaceURI
836: .equals(name.namespaceName))) {
837: encodeNonZeroIntegerOnSecondBitFirstBitZero(name.index);
838: return true;
839: }
840: }
841:
842: entry.addQualifiedName(new QualifiedName(prefix, namespaceURI,
843: localName, "", _v.attributeName.getNextIndex()));
844: return false;
845: }
846:
847: private void encodeLiteralHeader(int type, String namespaceURI,
848: String prefix) throws IOException {
849: if (namespaceURI != "") {
850: type |= EncodingConstants.LITERAL_QNAME_NAMESPACE_NAME_FLAG;
851: if (prefix != "")
852: type |= EncodingConstants.LITERAL_QNAME_PREFIX_FLAG;
853:
854: write(type);
855: if (prefix != "")
856: encodeNonZeroIntegerOnSecondBitFirstBitOne(_v.prefix
857: .get(prefix));
858: encodeNonZeroIntegerOnSecondBitFirstBitOne(_v.namespaceName
859: .get(namespaceURI));
860: } else
861: write(type);
862: }
863:
864: private void encodeLiteral(int type, String namespaceURI,
865: String prefix, String localName) throws IOException {
866: encodeLiteralHeader(type, namespaceURI, prefix);
867:
868: final int localNameIndex = _v.localName.obtainIndex(localName);
869: if (localNameIndex == -1) {
870: encodeNonEmptyOctetStringOnSecondBit(localName);
871: } else
872: encodeNonZeroIntegerOnSecondBitFirstBitOne(localNameIndex);
873: }
874: }
|