Tue, 06 Mar 2012 16:09:35 -0800
7150322: Stop using drop source bundles in jaxws
Reviewed-by: darcy, ohrstrom
1 /*
2 * Copyright (c) 2004, 2011, 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 */
28 package com.sun.xml.internal.fastinfoset;
30 import com.sun.xml.internal.fastinfoset.algorithm.BuiltInEncodingAlgorithmFactory;
31 import com.sun.xml.internal.fastinfoset.org.apache.xerces.util.XMLChar;
32 import com.sun.xml.internal.fastinfoset.util.CharArrayIntMap;
33 import com.sun.xml.internal.fastinfoset.util.KeyIntMap;
34 import com.sun.xml.internal.fastinfoset.util.LocalNameQualifiedNamesMap;
35 import com.sun.xml.internal.fastinfoset.util.StringIntMap;
36 import com.sun.xml.internal.fastinfoset.vocab.SerializerVocabulary;
37 import java.io.IOException;
38 import java.io.OutputStream;
39 import java.util.HashMap;
40 import java.util.Map;
41 import com.sun.xml.internal.org.jvnet.fastinfoset.EncodingAlgorithm;
42 import com.sun.xml.internal.org.jvnet.fastinfoset.EncodingAlgorithmException;
43 import com.sun.xml.internal.org.jvnet.fastinfoset.EncodingAlgorithmIndexes;
44 import com.sun.xml.internal.org.jvnet.fastinfoset.ExternalVocabulary;
45 import com.sun.xml.internal.org.jvnet.fastinfoset.FastInfosetException;
46 import com.sun.xml.internal.org.jvnet.fastinfoset.FastInfosetSerializer;
47 import com.sun.xml.internal.org.jvnet.fastinfoset.RestrictedAlphabet;
48 import com.sun.xml.internal.org.jvnet.fastinfoset.VocabularyApplicationData;
49 import org.xml.sax.helpers.DefaultHandler;
51 /**
52 * Abstract encoder for developing concrete encoders.
53 *
54 * Concrete implementations extending Encoder will utilize methods on Encoder
55 * to encode XML infoset according to the Fast Infoset standard. It is the
56 * responsibility of the concrete implementation to ensure that methods are
57 * invoked in the correct order to produce a valid fast infoset document.
58 *
59 * <p>
60 * This class extends org.sax.xml.DefaultHandler so that concrete SAX
61 * implementations can be used with javax.xml.parsers.SAXParser and the parse
62 * methods that take org.sax.xml.DefaultHandler as a parameter.
63 *
64 * <p>
65 * Buffering of octets that are written to an {@link java.io.OutputStream} is
66 * supported in a similar manner to a {@link java.io.BufferedOutputStream}.
67 * Combining buffering with encoding enables better performance.
68 *
69 * <p>
70 * More than one fast infoset document may be encoded to the
71 * {@link java.io.OutputStream}.
72 *
73 */
74 public abstract class Encoder extends DefaultHandler implements FastInfosetSerializer {
76 /**
77 * Character encoding scheme system property for the encoding
78 * of content and attribute values.
79 */
80 public static final String CHARACTER_ENCODING_SCHEME_SYSTEM_PROPERTY =
81 "com.sun.xml.internal.fastinfoset.serializer.character-encoding-scheme";
83 /**
84 * Default character encoding scheme system property for the encoding
85 * of content and attribute values.
86 */
87 protected static final String _characterEncodingSchemeSystemDefault = getDefaultEncodingScheme();
89 private static String getDefaultEncodingScheme() {
90 String p = System.getProperty(CHARACTER_ENCODING_SCHEME_SYSTEM_PROPERTY,
91 UTF_8);
92 if (p.equals(UTF_16BE)) {
93 return UTF_16BE;
94 } else {
95 return UTF_8;
96 }
97 }
99 private static int[] NUMERIC_CHARACTERS_TABLE;
101 private static int[] DATE_TIME_CHARACTERS_TABLE;
103 static {
104 NUMERIC_CHARACTERS_TABLE = new int[maxCharacter(RestrictedAlphabet.NUMERIC_CHARACTERS) + 1];
105 DATE_TIME_CHARACTERS_TABLE = new int[maxCharacter(RestrictedAlphabet.DATE_TIME_CHARACTERS) + 1];
107 for (int i = 0; i < NUMERIC_CHARACTERS_TABLE.length ; i++) {
108 NUMERIC_CHARACTERS_TABLE[i] = -1;
109 }
110 for (int i = 0; i < DATE_TIME_CHARACTERS_TABLE.length ; i++) {
111 DATE_TIME_CHARACTERS_TABLE[i] = -1;
112 }
114 for (int i = 0; i < RestrictedAlphabet.NUMERIC_CHARACTERS.length() ; i++) {
115 NUMERIC_CHARACTERS_TABLE[RestrictedAlphabet.NUMERIC_CHARACTERS.charAt(i)] = i;
116 }
117 for (int i = 0; i < RestrictedAlphabet.DATE_TIME_CHARACTERS.length() ; i++) {
118 DATE_TIME_CHARACTERS_TABLE[RestrictedAlphabet.DATE_TIME_CHARACTERS.charAt(i)] = i;
119 }
120 }
122 private static int maxCharacter(String alphabet) {
123 int c = 0;
124 for (int i = 0; i < alphabet.length() ; i++) {
125 if (c < alphabet.charAt(i)) {
126 c = alphabet.charAt(i);
127 }
128 }
130 return c;
131 }
133 /**
134 * True if DTD and internal subset shall be ignored.
135 */
136 private boolean _ignoreDTD;
138 /**
139 * True if comments shall be ignored.
140 */
141 private boolean _ignoreComments;
143 /**
144 * True if procesing instructions shall be ignored.
145 */
146 private boolean _ignoreProcessingInstructions;
148 /**
149 * True if white space characters for text content shall be ignored.
150 */
151 private boolean _ignoreWhiteSpaceTextContent;
153 /**
154 * True, if the local name string is used as the key to find the
155 * associated set of qualified names.
156 * <p>
157 * False, if the <prefix>:<local name> string is used as the key
158 * to find the associated set of qualified names.
159 */
160 private boolean _useLocalNameAsKeyForQualifiedNameLookup;
162 /**
163 * True if strings for text content and attribute values will be
164 * UTF-8 encoded otherwise they will be UTF-16 encoded.
165 */
166 private boolean _encodingStringsAsUtf8 = true;
168 /**
169 * Encoding constant generated from the string encoding.
170 */
171 private int _nonIdentifyingStringOnThirdBitCES;
173 /**
174 * Encoding constant generated from the string encoding.
175 */
176 private int _nonIdentifyingStringOnFirstBitCES;
178 /**
179 * The map of URIs to algorithms.
180 */
181 private Map _registeredEncodingAlgorithms = new HashMap();
183 /**
184 * The vocabulary that is used by the encoder
185 */
186 protected SerializerVocabulary _v;
188 /**
189 * The vocabulary application data that is used by the encoder
190 */
191 protected VocabularyApplicationData _vData;
193 /**
194 * True if the vocubulary is internal to the encoder
195 */
196 private boolean _vIsInternal;
198 /**
199 * True if terminatation of an information item is required
200 */
201 protected boolean _terminate = false;
203 /**
204 * The current octet that is to be written.
205 */
206 protected int _b;
208 /**
209 * The {@link java.io.OutputStream} that the encoded XML infoset (the
210 * fast infoset document) is written to.
211 */
212 protected OutputStream _s;
214 /**
215 * The internal buffer of characters used for the UTF-8 or UTF-16 encoding
216 * of characters.
217 */
218 protected char[] _charBuffer = new char[512];
220 /**
221 * The internal buffer of bytes.
222 */
223 protected byte[] _octetBuffer = new byte[1024];
225 /**
226 * The current position in the internal buffer.
227 */
228 protected int _octetBufferIndex;
230 /**
231 * The current mark in the internal buffer.
232 *
233 * <p>
234 * If the value of the mark is < 0 then the mark is not set.
235 */
236 protected int _markIndex = -1;
238 /**
239 * The minimum size of [normalized value] of Attribute Information
240 * Items that will be indexed.
241 */
242 protected int minAttributeValueSize = FastInfosetSerializer.MIN_ATTRIBUTE_VALUE_SIZE;
244 /**
245 * The maximum size of [normalized value] of Attribute Information
246 * Items that will be indexed.
247 */
248 protected int maxAttributeValueSize = FastInfosetSerializer.MAX_ATTRIBUTE_VALUE_SIZE;
250 /**
251 * The limit on the size of indexed Map for attribute values
252 * Limit is measured in characters number
253 */
254 protected int attributeValueMapTotalCharactersConstraint = FastInfosetSerializer.ATTRIBUTE_VALUE_MAP_MEMORY_CONSTRAINT / 2;
256 /**
257 * The minimum size of character content chunks
258 * of Character Information Items or Comment Information Items that
259 * will be indexed.
260 */
261 protected int minCharacterContentChunkSize = FastInfosetSerializer.MIN_CHARACTER_CONTENT_CHUNK_SIZE;
263 /**
264 * The maximum size of character content chunks
265 * of Character Information Items or Comment Information Items that
266 * will be indexed.
267 */
268 protected int maxCharacterContentChunkSize = FastInfosetSerializer.MAX_CHARACTER_CONTENT_CHUNK_SIZE;
270 /**
271 * The limit on the size of indexed Map for character content chunks
272 * Limit is measured in characters number
273 */
274 protected int characterContentChunkMapTotalCharactersConstraint = FastInfosetSerializer.CHARACTER_CONTENT_CHUNK_MAP_MEMORY_CONSTRAINT / 2;
276 /**
277 * Default constructor for the Encoder.
278 */
279 protected Encoder() {
280 setCharacterEncodingScheme(_characterEncodingSchemeSystemDefault);
281 }
283 protected Encoder(boolean useLocalNameAsKeyForQualifiedNameLookup) {
284 setCharacterEncodingScheme(_characterEncodingSchemeSystemDefault);
285 _useLocalNameAsKeyForQualifiedNameLookup = useLocalNameAsKeyForQualifiedNameLookup;
286 }
289 // FastInfosetSerializer interface
291 /**
292 * {@inheritDoc}
293 */
294 public final void setIgnoreDTD(boolean ignoreDTD) {
295 _ignoreDTD = ignoreDTD;
296 }
298 /**
299 * {@inheritDoc}
300 */
301 public final boolean getIgnoreDTD() {
302 return _ignoreDTD;
303 }
305 /**
306 * {@inheritDoc}
307 */
308 public final void setIgnoreComments(boolean ignoreComments) {
309 _ignoreComments = ignoreComments;
310 }
312 /**
313 * {@inheritDoc}
314 */
315 public final boolean getIgnoreComments() {
316 return _ignoreComments;
317 }
319 /**
320 * {@inheritDoc}
321 */
322 public final void setIgnoreProcesingInstructions(boolean
323 ignoreProcesingInstructions) {
324 _ignoreProcessingInstructions = ignoreProcesingInstructions;
325 }
327 /**
328 * {@inheritDoc}
329 */
330 public final boolean getIgnoreProcesingInstructions() {
331 return _ignoreProcessingInstructions;
332 }
334 /**
335 * {@inheritDoc}
336 */
337 public final void setIgnoreWhiteSpaceTextContent(boolean ignoreWhiteSpaceTextContent) {
338 _ignoreWhiteSpaceTextContent = ignoreWhiteSpaceTextContent;
339 }
341 /**
342 * {@inheritDoc}
343 */
344 public final boolean getIgnoreWhiteSpaceTextContent() {
345 return _ignoreWhiteSpaceTextContent;
346 }
348 /**
349 * {@inheritDoc}
350 */
351 public void setCharacterEncodingScheme(String characterEncodingScheme) {
352 if (characterEncodingScheme.equals(UTF_16BE)) {
353 _encodingStringsAsUtf8 = false;
354 _nonIdentifyingStringOnThirdBitCES = EncodingConstants.CHARACTER_CHUNK | EncodingConstants.CHARACTER_CHUNK_UTF_16_FLAG;
355 _nonIdentifyingStringOnFirstBitCES = EncodingConstants.NISTRING_UTF_16_FLAG;
356 } else {
357 _encodingStringsAsUtf8 = true;
358 _nonIdentifyingStringOnThirdBitCES = EncodingConstants.CHARACTER_CHUNK;
359 _nonIdentifyingStringOnFirstBitCES = 0;
360 }
361 }
363 /**
364 * {@inheritDoc}
365 */
366 public String getCharacterEncodingScheme() {
367 return (_encodingStringsAsUtf8) ? UTF_8 : UTF_16BE;
368 }
370 /**
371 * {@inheritDoc}
372 */
373 public void setRegisteredEncodingAlgorithms(Map algorithms) {
374 _registeredEncodingAlgorithms = algorithms;
375 if (_registeredEncodingAlgorithms == null) {
376 _registeredEncodingAlgorithms = new HashMap();
377 }
378 }
380 /**
381 * {@inheritDoc}
382 */
383 public Map getRegisteredEncodingAlgorithms() {
384 return _registeredEncodingAlgorithms;
385 }
387 /**
388 * {@inheritDoc}
389 */
390 public int getMinCharacterContentChunkSize() {
391 return minCharacterContentChunkSize;
392 }
394 /**
395 * {@inheritDoc}
396 */
397 public void setMinCharacterContentChunkSize(int size) {
398 if (size < 0 ) {
399 size = 0;
400 }
402 minCharacterContentChunkSize = size;
403 }
405 /**
406 * {@inheritDoc}
407 */
408 public int getMaxCharacterContentChunkSize() {
409 return maxCharacterContentChunkSize;
410 }
412 /**
413 * {@inheritDoc}
414 */
415 public void setMaxCharacterContentChunkSize(int size) {
416 if (size < 0 ) {
417 size = 0;
418 }
420 maxCharacterContentChunkSize = size;
421 }
423 /**
424 * {@inheritDoc}
425 */
426 public int getCharacterContentChunkMapMemoryLimit() {
427 return characterContentChunkMapTotalCharactersConstraint * 2;
428 }
430 /**
431 * {@inheritDoc}
432 */
433 public void setCharacterContentChunkMapMemoryLimit(int size) {
434 if (size < 0 ) {
435 size = 0;
436 }
438 characterContentChunkMapTotalCharactersConstraint = size / 2;
439 }
441 /**
442 * Checks whether character content chunk (its length) matches length limit
443 *
444 * @param length the length of character content chunk is checking to be added to Map.
445 * @return whether character content chunk length matches limit
446 */
447 public boolean isCharacterContentChunkLengthMatchesLimit(int length) {
448 return length >= minCharacterContentChunkSize &&
449 length < maxCharacterContentChunkSize;
450 }
452 /**
453 * Checks whether character content table has enough memory to
454 * store character content chunk with the given length
455 *
456 * @param length the length of character content chunk is checking to be added to Map.
457 * @param map the custom CharArrayIntMap, which memory limits will be checked.
458 * @return whether character content map has enough memory
459 */
460 public boolean canAddCharacterContentToTable(int length, CharArrayIntMap map) {
461 return map.getTotalCharacterCount() + length <
462 characterContentChunkMapTotalCharactersConstraint;
463 }
465 /**
466 * {@inheritDoc}
467 */
468 public int getMinAttributeValueSize() {
469 return minAttributeValueSize;
470 }
472 /**
473 * {@inheritDoc}
474 */
475 public void setMinAttributeValueSize(int size) {
476 if (size < 0 ) {
477 size = 0;
478 }
480 minAttributeValueSize = size;
481 }
483 /**
484 * {@inheritDoc}
485 */
486 public int getMaxAttributeValueSize() {
487 return maxAttributeValueSize;
488 }
490 /**
491 * {@inheritDoc}
492 */
493 public void setMaxAttributeValueSize(int size) {
494 if (size < 0 ) {
495 size = 0;
496 }
498 maxAttributeValueSize = size;
499 }
501 /**
502 * {@inheritDoc}
503 */
504 public void setAttributeValueMapMemoryLimit(int size) {
505 if (size < 0 ) {
506 size = 0;
507 }
509 attributeValueMapTotalCharactersConstraint = size / 2;
511 }
513 /**
514 * {@inheritDoc}
515 */
516 public int getAttributeValueMapMemoryLimit() {
517 return attributeValueMapTotalCharactersConstraint * 2;
518 }
520 /**
521 * Checks whether attribute value (its length) matches length limit
522 *
523 * @param length the length of attribute
524 * @return whether attribute value matches limit
525 */
526 public boolean isAttributeValueLengthMatchesLimit(int length) {
527 return length >= minAttributeValueSize &&
528 length < maxAttributeValueSize;
529 }
531 /**
532 * Checks whether attribute table has enough memory to
533 * store attribute value with the given length
534 *
535 * @param length the length of attribute value is checking to be added to Map.
536 * @return whether attribute map has enough memory
537 */
538 public boolean canAddAttributeToTable(int length) {
539 return _v.attributeValue.getTotalCharacterCount() + length <
540 attributeValueMapTotalCharactersConstraint;
541 }
543 /**
544 * {@inheritDoc}
545 */
546 public void setExternalVocabulary(ExternalVocabulary v) {
547 // Create internal serializer vocabulary
548 _v = new SerializerVocabulary();
549 // Set the external vocabulary
550 SerializerVocabulary ev = new SerializerVocabulary(v.vocabulary,
551 _useLocalNameAsKeyForQualifiedNameLookup);
552 _v.setExternalVocabulary(v.URI,
553 ev, false);
555 _vIsInternal = true;
556 }
558 /**
559 * {@inheritDoc}
560 */
561 public void setVocabularyApplicationData(VocabularyApplicationData data) {
562 _vData = data;
563 }
565 /**
566 * {@inheritDoc}
567 */
568 public VocabularyApplicationData getVocabularyApplicationData() {
569 return _vData;
570 }
572 // End of FastInfosetSerializer interface
574 /**
575 * Reset the encoder for reuse encoding another XML infoset.
576 */
577 public void reset() {
578 _terminate = false;
579 }
581 /**
582 * Set the OutputStream to encode the XML infoset to a
583 * fast infoset document.
584 *
585 * @param s the OutputStream where the fast infoset document is written to.
586 */
587 public void setOutputStream(OutputStream s) {
588 _octetBufferIndex = 0;
589 _markIndex = -1;
590 _s = s;
591 }
593 /**
594 * Set the SerializerVocabulary to be used for encoding.
595 *
596 * @param vocabulary the vocabulary to be used for encoding.
597 */
598 public void setVocabulary(SerializerVocabulary vocabulary) {
599 _v = vocabulary;
600 _vIsInternal = false;
601 }
603 /**
604 * Encode the header of a fast infoset document.
605 *
606 * @param encodeXmlDecl true if the XML declaration should be encoded.
607 */
608 protected final void encodeHeader(boolean encodeXmlDecl) throws IOException {
609 if (encodeXmlDecl) {
610 _s.write(EncodingConstants.XML_DECLARATION_VALUES[0]);
611 }
612 _s.write(EncodingConstants.BINARY_HEADER);
613 }
615 /**
616 * Encode the initial vocabulary of a fast infoset document.
617 *
618 */
619 protected final void encodeInitialVocabulary() throws IOException {
620 if (_v == null) {
621 _v = new SerializerVocabulary();
622 _vIsInternal = true;
623 } else if (_vIsInternal) {
624 _v.clear();
625 if (_vData != null)
626 _vData.clear();
627 }
629 if (!_v.hasInitialVocabulary() && !_v.hasExternalVocabulary()) {
630 write(0);
631 } else if (_v.hasInitialVocabulary()) {
632 _b = EncodingConstants.DOCUMENT_INITIAL_VOCABULARY_FLAG;
633 write(_b);
635 SerializerVocabulary initialVocabulary = _v.getReadOnlyVocabulary();
637 // TODO check for contents of vocabulary to assign bits
638 if (initialVocabulary.hasExternalVocabulary()) {
639 _b = EncodingConstants.INITIAL_VOCABULARY_EXTERNAL_VOCABULARY_FLAG;
640 write(_b);
641 write(0);
642 }
644 if (initialVocabulary.hasExternalVocabulary()) {
645 encodeNonEmptyOctetStringOnSecondBit(_v.getExternalVocabularyURI());
646 }
648 // TODO check for contents of vocabulary to encode values
649 } else if (_v.hasExternalVocabulary()) {
650 _b = EncodingConstants.DOCUMENT_INITIAL_VOCABULARY_FLAG;
651 write(_b);
653 _b = EncodingConstants.INITIAL_VOCABULARY_EXTERNAL_VOCABULARY_FLAG;
654 write(_b);
655 write(0);
657 encodeNonEmptyOctetStringOnSecondBit(_v.getExternalVocabularyURI());
658 }
659 }
661 /**
662 * Encode the termination of the Document Information Item.
663 *
664 */
665 protected final void encodeDocumentTermination() throws IOException {
666 encodeElementTermination();
667 encodeTermination();
668 _flush();
669 _s.flush();
670 }
672 /**
673 * Encode the termination of an Element Information Item.
674 *
675 */
676 protected final void encodeElementTermination() throws IOException {
677 _terminate = true;
678 switch (_b) {
679 case EncodingConstants.TERMINATOR:
680 _b = EncodingConstants.DOUBLE_TERMINATOR;
681 break;
682 case EncodingConstants.DOUBLE_TERMINATOR:
683 write(EncodingConstants.DOUBLE_TERMINATOR);
684 default:
685 _b = EncodingConstants.TERMINATOR;
686 }
687 }
689 /**
690 * Encode a termination if required.
691 *
692 */
693 protected final void encodeTermination() throws IOException {
694 if (_terminate) {
695 write(_b);
696 _b = 0;
697 _terminate = false;
698 }
699 }
701 /**
702 * Encode a Attribute Information Item that is a namespace declaration.
703 *
704 * @param prefix the prefix of the namespace declaration,
705 * if "" then there is no prefix for the namespace declaration.
706 * @param uri the URI of the namespace declaration,
707 * if "" then there is no URI for the namespace declaration.
708 */
709 protected final void encodeNamespaceAttribute(String prefix, String uri) throws IOException {
710 _b = EncodingConstants.NAMESPACE_ATTRIBUTE;
711 if (prefix.length() > 0) {
712 _b |= EncodingConstants.NAMESPACE_ATTRIBUTE_PREFIX_FLAG;
713 }
714 if (uri.length() > 0) {
715 _b |= EncodingConstants.NAMESPACE_ATTRIBUTE_NAME_FLAG;
716 }
718 // NOTE a prefix with out a namespace name is an undeclaration
719 // of the namespace bound to the prefix
720 // TODO needs to investigate how the startPrefixMapping works in
721 // relation to undeclaration
723 write(_b);
725 if (prefix.length() > 0) {
726 encodeIdentifyingNonEmptyStringOnFirstBit(prefix, _v.prefix);
727 }
728 if (uri.length() > 0) {
729 encodeIdentifyingNonEmptyStringOnFirstBit(uri, _v.namespaceName);
730 }
731 }
733 /**
734 * Encode a chunk of Character Information Items.
735 *
736 * @param ch the array of characters.
737 * @param offset the offset into the array of characters.
738 * @param length the length of characters.
739 * @throws ArrayIndexOutOfBoundsException.
740 */
741 protected final void encodeCharacters(char[] ch, int offset, int length) throws IOException {
742 final boolean addToTable = isCharacterContentChunkLengthMatchesLimit(length);
743 encodeNonIdentifyingStringOnThirdBit(ch, offset, length, _v.characterContentChunk, addToTable, true);
744 }
746 /**
747 * Encode a chunk of Character Information Items.
748 *
749 * If the array of characters is to be indexed (as determined by
750 * {@link Encoder#characterContentChunkSizeContraint}) then the array is not cloned
751 * when adding the array to the vocabulary.
752 *
753 * @param ch the array of characters.
754 * @param offset the offset into the array of characters.
755 * @param length the length of characters.
756 * @throws ArrayIndexOutOfBoundsException.
757 */
758 protected final void encodeCharactersNoClone(char[] ch, int offset, int length) throws IOException {
759 final boolean addToTable = isCharacterContentChunkLengthMatchesLimit(length);
760 encodeNonIdentifyingStringOnThirdBit(ch, offset, length, _v.characterContentChunk, addToTable, false);
761 }
763 /**
764 * Encode a chunk of Character Information Items using a numeric
765 * alphabet that results in the encoding of a character in 4 bits
766 * (or two characters per octet).
767 *
768 * @param id the restricted alphabet identifier.
769 * @param table the table mapping characters to 4 bit values.
770 * @param ch the array of characters.
771 * @param offset the offset into the array of characters.
772 * @param length the length of characters.
773 * @param addToTable if characters should be added to table.
774 * @throws ArrayIndexOutOfBoundsException.
775 */
776 protected final void encodeNumericFourBitCharacters(char[] ch, int offset, int length,
777 boolean addToTable) throws FastInfosetException, IOException {
778 encodeFourBitCharacters(RestrictedAlphabet.NUMERIC_CHARACTERS_INDEX,
779 NUMERIC_CHARACTERS_TABLE, ch, offset, length, addToTable);
780 }
782 /**
783 * Encode a chunk of Character Information Items using a date-time
784 * alphabet that results in the encoding of a character in 4 bits
785 * (or two characters per octet).
786 *
787 * @param id the restricted alphabet identifier.
788 * @param table the table mapping characters to 4 bit values.
789 * @param ch the array of characters.
790 * @param offset the offset into the array of characters.
791 * @param length the length of characters.
792 * @param addToTable if characters should be added to table.
793 * @throws ArrayIndexOutOfBoundsException.
794 */
795 protected final void encodeDateTimeFourBitCharacters(char[] ch, int offset, int length,
796 boolean addToTable) throws FastInfosetException, IOException {
797 encodeFourBitCharacters(RestrictedAlphabet.DATE_TIME_CHARACTERS_INDEX,
798 DATE_TIME_CHARACTERS_TABLE, ch, offset, length, addToTable);
799 }
801 /**
802 * Encode a chunk of Character Information Items using a restricted
803 * alphabet that results in the encoding of a character in 4 bits
804 * (or two characters per octet).
805 *
806 * @param id the restricted alphabet identifier.
807 * @param table the table mapping characters to 4 bit values.
808 * @param ch the array of characters.
809 * @param offset the offset into the array of characters.
810 * @param length the length of characters.
811 * @param addToTable if characters should be added to table.
812 * @throws ArrayIndexOutOfBoundsException.
813 */
814 protected final void encodeFourBitCharacters(int id, int[] table, char[] ch, int offset, int length,
815 boolean addToTable) throws FastInfosetException, IOException {
816 if (addToTable) {
817 // if char array could be added to table
818 boolean canAddCharacterContentToTable =
819 canAddCharacterContentToTable(length, _v.characterContentChunk);
821 // obtain/get index
822 int index = canAddCharacterContentToTable ?
823 _v.characterContentChunk.obtainIndex(ch, offset, length, true) :
824 _v.characterContentChunk.get(ch, offset, length);
826 if (index != KeyIntMap.NOT_PRESENT) {
827 // if char array is in table
828 _b = EncodingConstants.CHARACTER_CHUNK | 0x20;
829 encodeNonZeroIntegerOnFourthBit(index);
830 return;
831 } else if (canAddCharacterContentToTable) {
832 // if char array is not in table, but could be added
833 _b = EncodingConstants.CHARACTER_CHUNK | EncodingConstants.CHARACTER_CHUNK_RESTRICTED_ALPHABET_FLAG | EncodingConstants.CHARACTER_CHUNK_ADD_TO_TABLE_FLAG;
834 } else {
835 // if char array is not in table and could not be added
836 _b = EncodingConstants.CHARACTER_CHUNK | EncodingConstants.CHARACTER_CHUNK_RESTRICTED_ALPHABET_FLAG;
837 }
838 } else {
839 _b = EncodingConstants.CHARACTER_CHUNK | EncodingConstants.CHARACTER_CHUNK_RESTRICTED_ALPHABET_FLAG;
840 }
842 write (_b);
844 // Encode bottom 6 bits of enoding algorithm id
845 _b = id << 2;
847 encodeNonEmptyFourBitCharacterStringOnSeventhBit(table, ch, offset, length);
848 }
850 /**
851 * Encode a chunk of Character Information Items using a restricted
852 * alphabet table.
853 *
854 * @param alphabet the alphabet defining the mapping between characters and
855 * integer values.
856 * @param ch the array of characters.
857 * @param offset the offset into the array of characters.
858 * @param length the length of characters.
859 * @param addToTable if characters should be added to table
860 * @throws ArrayIndexOutOfBoundsException.
861 * @throws FastInfosetException if the alphabet is not present in the
862 * vocabulary.
863 */
864 protected final void encodeAlphabetCharacters(String alphabet, char[] ch, int offset, int length,
865 boolean addToTable) throws FastInfosetException, IOException {
866 if (addToTable) {
867 // if char array could be added to table
868 boolean canAddCharacterContentToTable =
869 canAddCharacterContentToTable(length, _v.characterContentChunk);
871 // obtain/get index
872 int index = canAddCharacterContentToTable ?
873 _v.characterContentChunk.obtainIndex(ch, offset, length, true) :
874 _v.characterContentChunk.get(ch, offset, length);
876 if (index != KeyIntMap.NOT_PRESENT) {
877 // if char array is in table
878 _b = EncodingConstants.CHARACTER_CHUNK | 0x20;
879 encodeNonZeroIntegerOnFourthBit(index);
880 return;
881 } else if (canAddCharacterContentToTable) {
882 // if char array is not in table, but could be added
883 _b = EncodingConstants.CHARACTER_CHUNK | EncodingConstants.CHARACTER_CHUNK_RESTRICTED_ALPHABET_FLAG | EncodingConstants.CHARACTER_CHUNK_ADD_TO_TABLE_FLAG;
884 } else {
885 // if char array is not in table and could not be added
886 _b = EncodingConstants.CHARACTER_CHUNK | EncodingConstants.CHARACTER_CHUNK_RESTRICTED_ALPHABET_FLAG;
887 }
888 } else {
889 _b = EncodingConstants.CHARACTER_CHUNK | EncodingConstants.CHARACTER_CHUNK_RESTRICTED_ALPHABET_FLAG;
890 }
892 int id = _v.restrictedAlphabet.get(alphabet);
893 if (id == KeyIntMap.NOT_PRESENT) {
894 throw new FastInfosetException(CommonResourceBundle.getInstance().getString("message.restrictedAlphabetNotPresent"));
895 }
896 id += EncodingConstants.RESTRICTED_ALPHABET_APPLICATION_START;
898 _b |= (id & 0xC0) >> 6;
899 write(_b);
901 // Encode bottom 6 bits of enoding algorithm id
902 _b = (id & 0x3F) << 2;
904 encodeNonEmptyNBitCharacterStringOnSeventhBit(alphabet, ch, offset, length);
905 }
907 /**
908 * Encode a Processing Instruction Information Item.
909 *
910 * @param target the target of the processing instruction.
911 * @param data the data of the processing instruction.
912 */
913 protected final void encodeProcessingInstruction(String target, String data) throws IOException {
914 write(EncodingConstants.PROCESSING_INSTRUCTION);
916 // Target
917 encodeIdentifyingNonEmptyStringOnFirstBit(target, _v.otherNCName);
919 // Data
920 boolean addToTable = isCharacterContentChunkLengthMatchesLimit(data.length());
921 encodeNonIdentifyingStringOnFirstBit(data, _v.otherString, addToTable);
922 }
924 /**
925 * Encode a Document Type Declaration.
926 *
927 * @param systemId the system identifier of the external subset.
928 * @param publicId the public identifier of the external subset.
929 */
930 protected final void encodeDocumentTypeDeclaration(String systemId, String publicId) throws IOException {
931 _b = EncodingConstants.DOCUMENT_TYPE_DECLARATION;
932 if (systemId != null && systemId.length() > 0) {
933 _b |= EncodingConstants.DOCUMENT_TYPE_SYSTEM_IDENTIFIER_FLAG;
934 }
935 if (publicId != null && publicId.length() > 0) {
936 _b |= EncodingConstants.DOCUMENT_TYPE_PUBLIC_IDENTIFIER_FLAG;
937 }
938 write(_b);
940 if (systemId != null && systemId.length() > 0) {
941 encodeIdentifyingNonEmptyStringOnFirstBit(systemId, _v.otherURI);
942 }
943 if (publicId != null && publicId.length() > 0) {
944 encodeIdentifyingNonEmptyStringOnFirstBit(publicId, _v.otherURI);
945 }
946 }
948 /**
949 * Encode a Comment Information Item.
950 *
951 * @param ch the array of characters that is as comment.
952 * @param offset the offset into the array of characters.
953 * @param length the length of characters.
954 * @throws ArrayIndexOutOfBoundsException.
955 */
956 protected final void encodeComment(char[] ch, int offset, int length) throws IOException {
957 write(EncodingConstants.COMMENT);
959 boolean addToTable = isCharacterContentChunkLengthMatchesLimit(length);
960 encodeNonIdentifyingStringOnFirstBit(ch, offset, length, _v.otherString, addToTable, true);
961 }
963 /**
964 * Encode a Comment Information Item.
965 *
966 * If the array of characters that is a comment is to be indexed (as
967 * determined by {@link Encoder#characterContentChunkSizeContraint}) then
968 * the array is not cloned when adding the array to the vocabulary.
969 *
970 * @param ch the array of characters.
971 * @param offset the offset into the array of characters.
972 * @param length the length of characters.
973 * @throws ArrayIndexOutOfBoundsException.
974 */
975 protected final void encodeCommentNoClone(char[] ch, int offset, int length) throws IOException {
976 write(EncodingConstants.COMMENT);
978 boolean addToTable = isCharacterContentChunkLengthMatchesLimit(length);
979 encodeNonIdentifyingStringOnFirstBit(ch, offset, length, _v.otherString, addToTable, false);
980 }
982 /**
983 * Encode a qualified name of an Element Informaiton Item on the third bit
984 * of an octet.
985 * Implementation of clause C.18 of ITU-T Rec. X.891 | ISO/IEC 24824-1.
986 *
987 * <p>
988 * The index of the qualified name will be encoded if the name is present
989 * in the vocabulary otherwise the qualified name will be encoded literally
990 * (see {@link #encodeLiteralElementQualifiedNameOnThirdBit}).
991 *
992 * @param namespaceURI the namespace URI of the qualified name.
993 * @param prefix the prefix of the qualified name.
994 * @param localName the local name of the qualified name.
995 */
996 protected final void encodeElementQualifiedNameOnThirdBit(String namespaceURI, String prefix, String localName) throws IOException {
997 LocalNameQualifiedNamesMap.Entry entry = _v.elementName.obtainEntry(localName);
998 if (entry._valueIndex > 0) {
999 QualifiedName[] names = entry._value;
1000 for (int i = 0; i < entry._valueIndex; i++) {
1001 if ((prefix == names[i].prefix || prefix.equals(names[i].prefix))
1002 && (namespaceURI == names[i].namespaceName || namespaceURI.equals(names[i].namespaceName))) {
1003 encodeNonZeroIntegerOnThirdBit(names[i].index);
1004 return;
1005 }
1006 }
1007 }
1009 encodeLiteralElementQualifiedNameOnThirdBit(namespaceURI, prefix,
1010 localName, entry);
1011 }
1013 /**
1014 * Encode a literal qualified name of an Element Informaiton Item on the
1015 * third bit of an octet.
1016 * Implementation of clause C.18 of ITU-T Rec. X.891 | ISO/IEC 24824-1.
1017 *
1018 * @param namespaceURI the namespace URI of the qualified name.
1019 * @param prefix the prefix of the qualified name.
1020 * @param localName the local name of the qualified name.
1021 */
1022 protected final void encodeLiteralElementQualifiedNameOnThirdBit(String namespaceURI, String prefix, String localName,
1023 LocalNameQualifiedNamesMap.Entry entry) throws IOException {
1024 QualifiedName name = new QualifiedName(prefix, namespaceURI, localName, "", _v.elementName.getNextIndex());
1025 entry.addQualifiedName(name);
1027 int namespaceURIIndex = KeyIntMap.NOT_PRESENT;
1028 int prefixIndex = KeyIntMap.NOT_PRESENT;
1029 if (namespaceURI.length() > 0) {
1030 namespaceURIIndex = _v.namespaceName.get(namespaceURI);
1031 if (namespaceURIIndex == KeyIntMap.NOT_PRESENT) {
1032 throw new IOException(CommonResourceBundle.getInstance().getString("message.namespaceURINotIndexed", new Object[]{namespaceURI}));
1033 }
1035 if (prefix.length() > 0) {
1036 prefixIndex = _v.prefix.get(prefix);
1037 if (prefixIndex == KeyIntMap.NOT_PRESENT) {
1038 throw new IOException(CommonResourceBundle.getInstance().getString("message.prefixNotIndexed", new Object[]{prefix}));
1039 }
1040 }
1041 }
1043 int localNameIndex = _v.localName.obtainIndex(localName);
1045 _b |= EncodingConstants.ELEMENT_LITERAL_QNAME_FLAG;
1046 if (namespaceURIIndex >= 0) {
1047 _b |= EncodingConstants.LITERAL_QNAME_NAMESPACE_NAME_FLAG;
1048 if (prefixIndex >= 0) {
1049 _b |= EncodingConstants.LITERAL_QNAME_PREFIX_FLAG;
1050 }
1051 }
1052 write(_b);
1054 if (namespaceURIIndex >= 0) {
1055 if (prefixIndex >= 0) {
1056 encodeNonZeroIntegerOnSecondBitFirstBitOne(prefixIndex);
1057 }
1058 encodeNonZeroIntegerOnSecondBitFirstBitOne(namespaceURIIndex);
1059 }
1061 if (localNameIndex >= 0) {
1062 encodeNonZeroIntegerOnSecondBitFirstBitOne(localNameIndex);
1063 } else {
1064 encodeNonEmptyOctetStringOnSecondBit(localName);
1065 }
1066 }
1068 /**
1069 * Encode a qualified name of an Attribute Informaiton Item on the third bit
1070 * of an octet.
1071 * Implementation of clause C.17 of ITU-T Rec. X.891 | ISO/IEC 24824-1.
1072 *
1073 * <p>
1074 * The index of the qualified name will be encoded if the name is present
1075 * in the vocabulary otherwise the qualified name will be encoded literally
1076 * (see {@link #encodeLiteralAttributeQualifiedNameOnSecondBit}).
1077 *
1078 * @param namespaceURI the namespace URI of the qualified name.
1079 * @param prefix the prefix of the qualified name.
1080 * @param localName the local name of the qualified name.
1081 */
1082 protected final void encodeAttributeQualifiedNameOnSecondBit(String namespaceURI, String prefix, String localName) throws IOException {
1083 LocalNameQualifiedNamesMap.Entry entry = _v.attributeName.obtainEntry(localName);
1084 if (entry._valueIndex > 0) {
1085 QualifiedName[] names = entry._value;
1086 for (int i = 0; i < entry._valueIndex; i++) {
1087 if ((prefix == names[i].prefix || prefix.equals(names[i].prefix))
1088 && (namespaceURI == names[i].namespaceName || namespaceURI.equals(names[i].namespaceName))) {
1089 encodeNonZeroIntegerOnSecondBitFirstBitZero(names[i].index);
1090 return;
1091 }
1092 }
1093 }
1095 encodeLiteralAttributeQualifiedNameOnSecondBit(namespaceURI, prefix,
1096 localName, entry);
1097 }
1099 /**
1100 * Encode a literal qualified name of an Attribute Informaiton Item on the
1101 * third bit of an octet.
1102 * Implementation of clause C.17 of ITU-T Rec. X.891 | ISO/IEC 24824-1.
1103 *
1104 * @param namespaceURI the namespace URI of the qualified name.
1105 * @param prefix the prefix of the qualified name.
1106 * @param localName the local name of the qualified name.
1107 */
1108 protected final boolean encodeLiteralAttributeQualifiedNameOnSecondBit(String namespaceURI, String prefix, String localName,
1109 LocalNameQualifiedNamesMap.Entry entry) throws IOException {
1110 int namespaceURIIndex = KeyIntMap.NOT_PRESENT;
1111 int prefixIndex = KeyIntMap.NOT_PRESENT;
1112 if (namespaceURI.length() > 0) {
1113 namespaceURIIndex = _v.namespaceName.get(namespaceURI);
1114 if (namespaceURIIndex == KeyIntMap.NOT_PRESENT) {
1115 if (namespaceURI == EncodingConstants.XMLNS_NAMESPACE_NAME ||
1116 namespaceURI.equals(EncodingConstants.XMLNS_NAMESPACE_NAME)) {
1117 return false;
1118 } else {
1119 throw new IOException(CommonResourceBundle.getInstance().getString("message.namespaceURINotIndexed", new Object[]{namespaceURI}));
1120 }
1121 }
1123 if (prefix.length() > 0) {
1124 prefixIndex = _v.prefix.get(prefix);
1125 if (prefixIndex == KeyIntMap.NOT_PRESENT) {
1126 throw new IOException(CommonResourceBundle.getInstance().getString("message.prefixNotIndexed", new Object[]{prefix}));
1127 }
1128 }
1129 }
1131 int localNameIndex = _v.localName.obtainIndex(localName);
1133 QualifiedName name = new QualifiedName(prefix, namespaceURI, localName, "", _v.attributeName.getNextIndex());
1134 entry.addQualifiedName(name);
1136 _b = EncodingConstants.ATTRIBUTE_LITERAL_QNAME_FLAG;
1137 if (namespaceURI.length() > 0) {
1138 _b |= EncodingConstants.LITERAL_QNAME_NAMESPACE_NAME_FLAG;
1139 if (prefix.length() > 0) {
1140 _b |= EncodingConstants.LITERAL_QNAME_PREFIX_FLAG;
1141 }
1142 }
1144 write(_b);
1146 if (namespaceURIIndex >= 0) {
1147 if (prefixIndex >= 0) {
1148 encodeNonZeroIntegerOnSecondBitFirstBitOne(prefixIndex);
1149 }
1150 encodeNonZeroIntegerOnSecondBitFirstBitOne(namespaceURIIndex);
1151 } else if (namespaceURI != "") {
1152 // XML prefix and namespace name
1153 encodeNonEmptyOctetStringOnSecondBit("xml");
1154 encodeNonEmptyOctetStringOnSecondBit("http://www.w3.org/XML/1998/namespace");
1155 }
1157 if (localNameIndex >= 0) {
1158 encodeNonZeroIntegerOnSecondBitFirstBitOne(localNameIndex);
1159 } else {
1160 encodeNonEmptyOctetStringOnSecondBit(localName);
1161 }
1163 return true;
1164 }
1166 /**
1167 * Encode a non identifying string on the first bit of an octet.
1168 * Implementation of clause C.14 of ITU-T Rec. X.891 | ISO/IEC 24824-1.
1169 *
1170 * @param s the string to encode
1171 * @param map the vocabulary table of strings to indexes.
1172 * @param addToTable true if the string could be added to the vocabulary
1173 * table (if table has enough memory)
1174 * @param mustBeAddedToTable true if the string must be added to the vocabulary
1175 * table (if not already present in the table).
1176 */
1177 protected final void encodeNonIdentifyingStringOnFirstBit(String s, StringIntMap map,
1178 boolean addToTable, boolean mustBeAddedToTable) throws IOException {
1179 if (s == null || s.length() == 0) {
1180 // C.26 an index (first bit '1') with seven '1' bits for an empty string
1181 write(0xFF);
1182 } else {
1183 if (addToTable || mustBeAddedToTable) {
1184 // if attribute value could be added to table
1185 boolean canAddAttributeToTable = mustBeAddedToTable ||
1186 canAddAttributeToTable(s.length());
1188 // obtain/get index
1189 int index = canAddAttributeToTable ?
1190 map.obtainIndex(s) :
1191 map.get(s);
1193 if (index != KeyIntMap.NOT_PRESENT) {
1194 // if attribute value is in table
1195 encodeNonZeroIntegerOnSecondBitFirstBitOne(index);
1196 } else if (canAddAttributeToTable) {
1197 // if attribute value is not in table, but could be added
1198 _b = EncodingConstants.NISTRING_ADD_TO_TABLE_FLAG |
1199 _nonIdentifyingStringOnFirstBitCES;
1200 encodeNonEmptyCharacterStringOnFifthBit(s);
1201 } else {
1202 // if attribute value is not in table and could not be added
1203 _b = _nonIdentifyingStringOnFirstBitCES;
1204 encodeNonEmptyCharacterStringOnFifthBit(s);
1205 }
1206 } else {
1207 _b = _nonIdentifyingStringOnFirstBitCES;
1208 encodeNonEmptyCharacterStringOnFifthBit(s);
1209 }
1210 }
1211 }
1213 /**
1214 * Encode a non identifying string on the first bit of an octet.
1215 * Implementation of clause C.14 of ITU-T Rec. X.891 | ISO/IEC 24824-1.
1216 *
1217 * @param s the string to encode
1218 * @param map the vocabulary table of character arrays to indexes.
1219 * @param addToTable true if the string should be added to the vocabulary
1220 * table (if not already present in the table).
1221 */
1222 protected final void encodeNonIdentifyingStringOnFirstBit(String s, CharArrayIntMap map, boolean addToTable) throws IOException {
1223 if (s == null || s.length() == 0) {
1224 // C.26 an index (first bit '1') with seven '1' bits for an empty string
1225 write(0xFF);
1226 } else {
1227 if (addToTable) {
1228 final char[] ch = s.toCharArray();
1229 final int length = s.length();
1231 // if char array could be added to table
1232 boolean canAddCharacterContentToTable =
1233 canAddCharacterContentToTable(length, map);
1235 // obtain/get index
1236 int index = canAddCharacterContentToTable ?
1237 map.obtainIndex(ch, 0, length, false) :
1238 map.get(ch, 0, length);
1240 if (index != KeyIntMap.NOT_PRESENT) {
1241 // if char array is in table
1242 encodeNonZeroIntegerOnSecondBitFirstBitOne(index);
1243 } else if (canAddCharacterContentToTable) {
1244 // if char array is not in table, but could be added
1245 _b = EncodingConstants.NISTRING_ADD_TO_TABLE_FLAG |
1246 _nonIdentifyingStringOnFirstBitCES;
1247 encodeNonEmptyCharacterStringOnFifthBit(ch, 0, length);
1248 } else {
1249 // if char array is not in table and could not be added
1250 _b = _nonIdentifyingStringOnFirstBitCES;
1251 encodeNonEmptyCharacterStringOnFifthBit(s);
1252 }
1253 } else {
1254 _b = _nonIdentifyingStringOnFirstBitCES;
1255 encodeNonEmptyCharacterStringOnFifthBit(s);
1256 }
1257 }
1258 }
1260 /**
1261 * Encode a non identifying string on the first bit of an octet.
1262 * Implementation of clause C.14 of ITU-T Rec. X.891 | ISO/IEC 24824-1.
1263 *
1264 * @param ch the array of characters.
1265 * @param offset the offset into the array of characters.
1266 * @param length the length of characters.
1267 * @param map the vocabulary table of character arrays to indexes.
1268 * @param addToTable true if the string should be added to the vocabulary
1269 * table (if not already present in the table).
1270 * @param clone true if the array of characters should be cloned if added
1271 * to the vocabulary table.
1272 */
1273 protected final void encodeNonIdentifyingStringOnFirstBit(char[] ch, int offset, int length, CharArrayIntMap map,
1274 boolean addToTable, boolean clone) throws IOException {
1275 if (length == 0) {
1276 // C.26 an index (first bit '1') with seven '1' bits for an empty string
1277 write(0xFF);
1278 } else {
1279 if (addToTable) {
1280 // if char array could be added to table
1281 boolean canAddCharacterContentToTable =
1282 canAddCharacterContentToTable(length, map);
1284 // obtain/get index
1285 int index = canAddCharacterContentToTable ?
1286 map.obtainIndex(ch, offset, length, clone) :
1287 map.get(ch, offset, length);
1289 if (index != KeyIntMap.NOT_PRESENT) {
1290 // if char array is in table
1291 encodeNonZeroIntegerOnSecondBitFirstBitOne(index);
1292 } else if (canAddCharacterContentToTable) {
1293 // if char array is not in table, but could be added
1294 _b = EncodingConstants.NISTRING_ADD_TO_TABLE_FLAG |
1295 _nonIdentifyingStringOnFirstBitCES;
1296 encodeNonEmptyCharacterStringOnFifthBit(ch, offset, length);
1297 } else {
1298 // if char array is not in table and could not be added
1299 _b = _nonIdentifyingStringOnFirstBitCES;
1300 encodeNonEmptyCharacterStringOnFifthBit(ch, offset, length);
1301 }
1302 } else {
1303 _b = _nonIdentifyingStringOnFirstBitCES;
1304 encodeNonEmptyCharacterStringOnFifthBit(ch, offset, length);
1305 }
1306 }
1307 }
1309 protected final void encodeNumericNonIdentifyingStringOnFirstBit(
1310 String s, boolean addToTable, boolean mustBeAddedToTable)
1311 throws IOException, FastInfosetException {
1312 encodeNonIdentifyingStringOnFirstBit(
1313 RestrictedAlphabet.NUMERIC_CHARACTERS_INDEX,
1314 NUMERIC_CHARACTERS_TABLE, s, addToTable,
1315 mustBeAddedToTable);
1316 }
1318 protected final void encodeDateTimeNonIdentifyingStringOnFirstBit(
1319 String s, boolean addToTable, boolean mustBeAddedToTable)
1320 throws IOException, FastInfosetException {
1321 encodeNonIdentifyingStringOnFirstBit(
1322 RestrictedAlphabet.DATE_TIME_CHARACTERS_INDEX,
1323 DATE_TIME_CHARACTERS_TABLE, s, addToTable,
1324 mustBeAddedToTable);
1325 }
1327 protected final void encodeNonIdentifyingStringOnFirstBit(int id, int[] table,
1328 String s, boolean addToTable, boolean mustBeAddedToTable)
1329 throws IOException, FastInfosetException {
1330 if (s == null || s.length() == 0) {
1331 // C.26 an index (first bit '1') with seven '1' bits for an empty string
1332 write(0xFF);
1333 return;
1334 }
1336 if (addToTable || mustBeAddedToTable) {
1337 // if attribute value could be added to table
1338 boolean canAddAttributeToTable = mustBeAddedToTable ||
1339 canAddAttributeToTable(s.length());
1341 // obtain/get index
1342 int index = canAddAttributeToTable ?
1343 _v.attributeValue.obtainIndex(s) :
1344 _v.attributeValue.get(s);
1346 if (index != KeyIntMap.NOT_PRESENT) {
1347 // if attribute value is in table
1348 encodeNonZeroIntegerOnSecondBitFirstBitOne(index);
1349 return;
1350 } else if (canAddAttributeToTable) {
1351 // if attribute value is not in table, but could be added
1352 _b = EncodingConstants.NISTRING_RESTRICTED_ALPHABET_FLAG |
1353 EncodingConstants.NISTRING_ADD_TO_TABLE_FLAG;
1354 } else {
1355 // if attribute value is not in table and could not be added
1356 _b = EncodingConstants.NISTRING_RESTRICTED_ALPHABET_FLAG;
1357 }
1358 } else {
1359 _b = EncodingConstants.NISTRING_RESTRICTED_ALPHABET_FLAG;
1360 }
1362 // Encode identification and top four bits of alphabet id
1363 write (_b | ((id & 0xF0) >> 4));
1364 // Encode bottom 4 bits of alphabet id
1365 _b = (id & 0x0F) << 4;
1367 final int length = s.length();
1368 final int octetPairLength = length / 2;
1369 final int octetSingleLength = length % 2;
1370 encodeNonZeroOctetStringLengthOnFifthBit(octetPairLength + octetSingleLength);
1371 encodeNonEmptyFourBitCharacterString(table, s.toCharArray(), 0, octetPairLength, octetSingleLength);
1372 }
1374 /**
1375 * Encode a non identifying string on the first bit of an octet as binary
1376 * data using an encoding algorithm.
1377 * Implementation of clause C.14 of ITU-T Rec. X.891 | ISO/IEC 24824-1.
1378 *
1379 * @param URI the encoding algorithm URI. If the URI == null then the
1380 * encoding algorithm identifier takes precendence.
1381 * @param id the encoding algorithm identifier.
1382 * @param data the data to be encoded using an encoding algorithm.
1383 * @throws EncodingAlgorithmException if the encoding algorithm URI is not
1384 * present in the vocabulary, or the encoding algorithm identifier
1385 * is not with the required range.
1386 */
1387 protected final void encodeNonIdentifyingStringOnFirstBit(String URI, int id, Object data) throws FastInfosetException, IOException {
1388 if (URI != null) {
1389 id = _v.encodingAlgorithm.get(URI);
1390 if (id == KeyIntMap.NOT_PRESENT) {
1391 throw new EncodingAlgorithmException(CommonResourceBundle.getInstance().getString("message.EncodingAlgorithmURI", new Object[]{URI}));
1392 }
1393 id += EncodingConstants.ENCODING_ALGORITHM_APPLICATION_START;
1395 EncodingAlgorithm ea = (EncodingAlgorithm)_registeredEncodingAlgorithms.get(URI);
1396 if (ea != null) {
1397 encodeAIIObjectAlgorithmData(id, data, ea);
1398 } else {
1399 if (data instanceof byte[]) {
1400 byte[] d = (byte[])data;
1401 encodeAIIOctetAlgorithmData(id, d, 0, d.length);
1402 } else {
1403 throw new EncodingAlgorithmException(CommonResourceBundle.getInstance().getString("message.nullEncodingAlgorithmURI"));
1404 }
1405 }
1406 } else if (id <= EncodingConstants.ENCODING_ALGORITHM_BUILTIN_END) {
1407 int length = 0;
1408 switch(id) {
1409 case EncodingAlgorithmIndexes.HEXADECIMAL:
1410 case EncodingAlgorithmIndexes.BASE64:
1411 length = ((byte[])data).length;
1412 break;
1413 case EncodingAlgorithmIndexes.SHORT:
1414 length = ((short[])data).length;
1415 break;
1416 case EncodingAlgorithmIndexes.INT:
1417 length = ((int[])data).length;
1418 break;
1419 case EncodingAlgorithmIndexes.LONG:
1420 case EncodingAlgorithmIndexes.UUID:
1421 length = ((long[])data).length;
1422 break;
1423 case EncodingAlgorithmIndexes.BOOLEAN:
1424 length = ((boolean[])data).length;
1425 break;
1426 case EncodingAlgorithmIndexes.FLOAT:
1427 length = ((float[])data).length;
1428 break;
1429 case EncodingAlgorithmIndexes.DOUBLE:
1430 length = ((double[])data).length;
1431 break;
1432 case EncodingAlgorithmIndexes.CDATA:
1433 throw new UnsupportedOperationException(CommonResourceBundle.getInstance().getString("message.CDATA"));
1434 default:
1435 throw new EncodingAlgorithmException(CommonResourceBundle.getInstance().getString("message.UnsupportedBuiltInAlgorithm", new Object[]{Integer.valueOf(id)}));
1436 }
1437 encodeAIIBuiltInAlgorithmData(id, data, 0, length);
1438 } else if (id >= EncodingConstants.ENCODING_ALGORITHM_APPLICATION_START) {
1439 if (data instanceof byte[]) {
1440 byte[] d = (byte[])data;
1441 encodeAIIOctetAlgorithmData(id, d, 0, d.length);
1442 } else {
1443 throw new EncodingAlgorithmException(CommonResourceBundle.getInstance().getString("message.nullEncodingAlgorithmURI"));
1444 }
1445 } else {
1446 throw new EncodingAlgorithmException(CommonResourceBundle.getInstance().getString("message.identifiers10to31Reserved"));
1447 }
1448 }
1450 /**
1451 * Encode the [normalized value] of an Attribute Information Item using
1452 * using an encoding algorithm.
1453 * Implementation of clause C.14 of ITU-T Rec. X.891 | ISO/IEC 24824-1.
1454 *
1455 * @param id the encoding algorithm identifier.
1456 * @param d the data, as an array of bytes, to be encoded.
1457 * @param offset the offset into the array of bytes.
1458 * @param length the length of bytes.
1459 */
1460 protected final void encodeAIIOctetAlgorithmData(int id, byte[] d, int offset, int length) throws IOException {
1461 // Encode identification and top four bits of encoding algorithm id
1462 write (EncodingConstants.NISTRING_ENCODING_ALGORITHM_FLAG |
1463 ((id & 0xF0) >> 4));
1465 // Encode bottom 4 bits of enoding algorithm id
1466 _b = (id & 0x0F) << 4;
1468 // Encode the length
1469 encodeNonZeroOctetStringLengthOnFifthBit(length);
1471 write(d, offset, length);
1472 }
1474 /**
1475 * Encode the [normalized value] of an Attribute Information Item using
1476 * using an encoding algorithm.
1477 * Implementation of clause C.14 of ITU-T Rec. X.891 | ISO/IEC 24824-1.
1478 *
1479 * @param id the encoding algorithm identifier.
1480 * @param data the data to be encoded using an encoding algorithm.
1481 * @param ea the encoding algorithm to use to encode the data into an
1482 * array of bytes.
1483 */
1484 protected final void encodeAIIObjectAlgorithmData(int id, Object data, EncodingAlgorithm ea) throws FastInfosetException, IOException {
1485 // Encode identification and top four bits of encoding algorithm id
1486 write (EncodingConstants.NISTRING_ENCODING_ALGORITHM_FLAG |
1487 ((id & 0xF0) >> 4));
1489 // Encode bottom 4 bits of enoding algorithm id
1490 _b = (id & 0x0F) << 4;
1492 _encodingBufferOutputStream.reset();
1493 ea.encodeToOutputStream(data, _encodingBufferOutputStream);
1494 encodeNonZeroOctetStringLengthOnFifthBit(_encodingBufferIndex);
1495 write(_encodingBuffer, _encodingBufferIndex);
1496 }
1498 /**
1499 * Encode the [normalized value] of an Attribute Information Item using
1500 * using a built in encoding algorithm.
1501 * Implementation of clause C.14 of ITU-T Rec. X.891 | ISO/IEC 24824-1.
1502 *
1503 * @param id the built in encoding algorithm identifier.
1504 * @param data the data to be encoded using an encoding algorithm. The data
1505 * represents an array of items specified by the encoding algorithm
1506 * identifier
1507 * @param offset the offset into the array of bytes.
1508 * @param length the length of bytes.
1509 */
1510 protected final void encodeAIIBuiltInAlgorithmData(int id, Object data, int offset, int length) throws IOException {
1511 // Encode identification and top four bits of encoding algorithm id
1512 write (EncodingConstants.NISTRING_ENCODING_ALGORITHM_FLAG |
1513 ((id & 0xF0) >> 4));
1515 // Encode bottom 4 bits of enoding algorithm id
1516 _b = (id & 0x0F) << 4;
1518 final int octetLength = BuiltInEncodingAlgorithmFactory.getAlgorithm(id).
1519 getOctetLengthFromPrimitiveLength(length);
1521 encodeNonZeroOctetStringLengthOnFifthBit(octetLength);
1523 ensureSize(octetLength);
1524 BuiltInEncodingAlgorithmFactory.getAlgorithm(id).
1525 encodeToBytes(data, offset, length, _octetBuffer, _octetBufferIndex);
1526 _octetBufferIndex += octetLength;
1527 }
1529 /**
1530 * Encode a non identifying string on the third bit of an octet.
1531 * Implementation of clause C.15 of ITU-T Rec. X.891 | ISO/IEC 24824-1.
1532 *
1533 * @param ch the array of characters.
1534 * @param offset the offset into the array of characters.
1535 * @param length the length of characters.
1536 * @param map the vocabulary table of character arrays to indexes.
1537 * @param addToTable true if the array of characters should be added to the vocabulary
1538 * table (if not already present in the table).
1539 * @param clone true if the array of characters should be cloned if added
1540 * to the vocabulary table.
1541 */
1542 protected final void encodeNonIdentifyingStringOnThirdBit(char[] ch, int offset, int length,
1543 CharArrayIntMap map, boolean addToTable, boolean clone) throws IOException {
1544 // length cannot be zero since sequence of CIIs has to be > 0
1546 if (addToTable) {
1547 // if char array could be added to table
1548 boolean canAddCharacterContentToTable =
1549 canAddCharacterContentToTable(length, map);
1551 // obtain/get index
1552 int index = canAddCharacterContentToTable ?
1553 map.obtainIndex(ch, offset, length, clone) :
1554 map.get(ch, offset, length);
1556 if (index != KeyIntMap.NOT_PRESENT) {
1557 // if char array is in table
1558 _b = EncodingConstants.CHARACTER_CHUNK | 0x20;
1559 encodeNonZeroIntegerOnFourthBit(index);
1560 } else if (canAddCharacterContentToTable) {
1561 // if char array is not in table, but could be added
1562 _b = EncodingConstants.CHARACTER_CHUNK_ADD_TO_TABLE_FLAG |
1563 _nonIdentifyingStringOnThirdBitCES;
1564 encodeNonEmptyCharacterStringOnSeventhBit(ch, offset, length);
1565 } else {
1566 // if char array is not in table and could not be added
1567 _b = _nonIdentifyingStringOnThirdBitCES;
1568 encodeNonEmptyCharacterStringOnSeventhBit(ch, offset, length);
1569 }
1570 } else {
1571 // char array will not be added to map
1572 _b = _nonIdentifyingStringOnThirdBitCES;
1573 encodeNonEmptyCharacterStringOnSeventhBit(ch, offset, length);
1574 }
1575 }
1577 /**
1578 * Encode a non identifying string on the third bit of an octet as binary
1579 * data using an encoding algorithm.
1580 * Implementation of clause C.15 of ITU-T Rec. X.891 | ISO/IEC 24824-1.
1581 *
1582 * @param URI the encoding algorithm URI. If the URI == null then the
1583 * encoding algorithm identifier takes precendence.
1584 * @param id the encoding algorithm identifier.
1585 * @param data the data to be encoded using an encoding algorithm.
1586 * @throws EncodingAlgorithmException if the encoding algorithm URI is not
1587 * present in the vocabulary, or the encoding algorithm identifier
1588 * is not with the required range.
1589 */
1590 protected final void encodeNonIdentifyingStringOnThirdBit(String URI, int id, Object data) throws FastInfosetException, IOException {
1591 if (URI != null) {
1592 id = _v.encodingAlgorithm.get(URI);
1593 if (id == KeyIntMap.NOT_PRESENT) {
1594 throw new EncodingAlgorithmException(CommonResourceBundle.getInstance().getString("message.EncodingAlgorithmURI", new Object[]{URI}));
1595 }
1596 id += EncodingConstants.ENCODING_ALGORITHM_APPLICATION_START;
1598 EncodingAlgorithm ea = (EncodingAlgorithm)_registeredEncodingAlgorithms.get(URI);
1599 if (ea != null) {
1600 encodeCIIObjectAlgorithmData(id, data, ea);
1601 } else {
1602 if (data instanceof byte[]) {
1603 byte[] d = (byte[])data;
1604 encodeCIIOctetAlgorithmData(id, d, 0, d.length);
1605 } else {
1606 throw new EncodingAlgorithmException(CommonResourceBundle.getInstance().getString("message.nullEncodingAlgorithmURI"));
1607 }
1608 }
1609 } else if (id <= EncodingConstants.ENCODING_ALGORITHM_BUILTIN_END) {
1610 int length = 0;
1611 switch(id) {
1612 case EncodingAlgorithmIndexes.HEXADECIMAL:
1613 case EncodingAlgorithmIndexes.BASE64:
1614 length = ((byte[])data).length;
1615 break;
1616 case EncodingAlgorithmIndexes.SHORT:
1617 length = ((short[])data).length;
1618 break;
1619 case EncodingAlgorithmIndexes.INT:
1620 length = ((int[])data).length;
1621 break;
1622 case EncodingAlgorithmIndexes.LONG:
1623 case EncodingAlgorithmIndexes.UUID:
1624 length = ((long[])data).length;
1625 break;
1626 case EncodingAlgorithmIndexes.BOOLEAN:
1627 length = ((boolean[])data).length;
1628 break;
1629 case EncodingAlgorithmIndexes.FLOAT:
1630 length = ((float[])data).length;
1631 break;
1632 case EncodingAlgorithmIndexes.DOUBLE:
1633 length = ((double[])data).length;
1634 break;
1635 case EncodingAlgorithmIndexes.CDATA:
1636 throw new UnsupportedOperationException(CommonResourceBundle.getInstance().getString("message.CDATA"));
1637 default:
1638 throw new EncodingAlgorithmException(CommonResourceBundle.getInstance().getString("message.UnsupportedBuiltInAlgorithm", new Object[]{Integer.valueOf(id)}));
1639 }
1640 encodeCIIBuiltInAlgorithmData(id, data, 0, length);
1641 } else if (id >= EncodingConstants.ENCODING_ALGORITHM_APPLICATION_START) {
1642 if (data instanceof byte[]) {
1643 byte[] d = (byte[])data;
1644 encodeCIIOctetAlgorithmData(id, d, 0, d.length);
1645 } else {
1646 throw new EncodingAlgorithmException(CommonResourceBundle.getInstance().getString("message.nullEncodingAlgorithmURI"));
1647 }
1648 } else {
1649 throw new EncodingAlgorithmException(CommonResourceBundle.getInstance().getString("message.identifiers10to31Reserved"));
1650 }
1651 }
1653 /**
1654 * Encode a non identifying string on the third bit of an octet as binary
1655 * data using an encoding algorithm.
1656 * Implementation of clause C.15 of ITU-T Rec. X.891 | ISO/IEC 24824-1.
1657 *
1658 * @param URI the encoding algorithm URI. If the URI == null then the
1659 * encoding algorithm identifier takes precendence.
1660 * @param id the encoding algorithm identifier.
1661 * @param d the data, as an array of bytes, to be encoded.
1662 * @param offset the offset into the array of bytes.
1663 * @param length the length of bytes.
1664 * @throws EncodingAlgorithmException if the encoding algorithm URI is not
1665 * present in the vocabulary.
1666 */
1667 protected final void encodeNonIdentifyingStringOnThirdBit(String URI, int id, byte[] d, int offset, int length) throws FastInfosetException, IOException {
1668 if (URI != null) {
1669 id = _v.encodingAlgorithm.get(URI);
1670 if (id == KeyIntMap.NOT_PRESENT) {
1671 throw new EncodingAlgorithmException(CommonResourceBundle.getInstance().getString("message.EncodingAlgorithmURI", new Object[]{URI}));
1672 }
1673 id += EncodingConstants.ENCODING_ALGORITHM_APPLICATION_START;
1674 }
1676 encodeCIIOctetAlgorithmData(id, d, offset, length);
1677 }
1679 /**
1680 * Encode a chunk of Character Information Items using
1681 * using an encoding algorithm.
1682 * Implementation of clause C.15 of ITU-T Rec. X.891 | ISO/IEC 24824-1.
1683 *
1684 * @param id the encoding algorithm identifier.
1685 * @param d the data, as an array of bytes, to be encoded.
1686 * @param offset the offset into the array of bytes.
1687 * @param length the length of bytes.
1688 */
1689 protected final void encodeCIIOctetAlgorithmData(int id, byte[] d, int offset, int length) throws IOException {
1690 // Encode identification and top two bits of encoding algorithm id
1691 write (EncodingConstants.CHARACTER_CHUNK | EncodingConstants.CHARACTER_CHUNK_ENCODING_ALGORITHM_FLAG |
1692 ((id & 0xC0) >> 6));
1694 // Encode bottom 6 bits of enoding algorithm id
1695 _b = (id & 0x3F) << 2;
1697 // Encode the length
1698 encodeNonZeroOctetStringLengthOnSenventhBit(length);
1700 write(d, offset, length);
1701 }
1703 /**
1704 * Encode a chunk of Character Information Items using
1705 * using an encoding algorithm.
1706 * Implementation of clause C.15 of ITU-T Rec. X.891 | ISO/IEC 24824-1.
1707 *
1708 * @param id the encoding algorithm identifier.
1709 * @param data the data to be encoded using an encoding algorithm.
1710 * @param ea the encoding algorithm to use to encode the data into an
1711 * array of bytes.
1712 */
1713 protected final void encodeCIIObjectAlgorithmData(int id, Object data, EncodingAlgorithm ea) throws FastInfosetException, IOException {
1714 // Encode identification and top two bits of encoding algorithm id
1715 write (EncodingConstants.CHARACTER_CHUNK | EncodingConstants.CHARACTER_CHUNK_ENCODING_ALGORITHM_FLAG |
1716 ((id & 0xC0) >> 6));
1718 // Encode bottom 6 bits of enoding algorithm id
1719 _b = (id & 0x3F) << 2;
1721 _encodingBufferOutputStream.reset();
1722 ea.encodeToOutputStream(data, _encodingBufferOutputStream);
1723 encodeNonZeroOctetStringLengthOnSenventhBit(_encodingBufferIndex);
1724 write(_encodingBuffer, _encodingBufferIndex);
1725 }
1727 /**
1728 * Encode a chunk of Character Information Items using
1729 * using an encoding algorithm.
1730 * Implementation of clause C.15 of ITU-T Rec. X.891 | ISO/IEC 24824-1.
1731 *
1732 * @param id the built in encoding algorithm identifier.
1733 * @param data the data to be encoded using an encoding algorithm. The data
1734 * represents an array of items specified by the encoding algorithm
1735 * identifier
1736 * @param offset the offset into the array of bytes.
1737 * @param length the length of bytes.
1738 */
1739 protected final void encodeCIIBuiltInAlgorithmData(int id, Object data, int offset, int length) throws FastInfosetException, IOException {
1740 // Encode identification and top two bits of encoding algorithm id
1741 write (EncodingConstants.CHARACTER_CHUNK | EncodingConstants.CHARACTER_CHUNK_ENCODING_ALGORITHM_FLAG |
1742 ((id & 0xC0) >> 6));
1744 // Encode bottom 6 bits of enoding algorithm id
1745 _b = (id & 0x3F) << 2;
1747 final int octetLength = BuiltInEncodingAlgorithmFactory.getAlgorithm(id).
1748 getOctetLengthFromPrimitiveLength(length);
1750 encodeNonZeroOctetStringLengthOnSenventhBit(octetLength);
1752 ensureSize(octetLength);
1753 BuiltInEncodingAlgorithmFactory.getAlgorithm(id).
1754 encodeToBytes(data, offset, length, _octetBuffer, _octetBufferIndex);
1755 _octetBufferIndex += octetLength;
1756 }
1758 /**
1759 * Encode a chunk of Character Information Items using
1760 * using the CDATA built in encoding algorithm.
1761 * Implementation of clause C.15 of ITU-T Rec. X.891 | ISO/IEC 24824-1.
1762 *
1763 * @param ch the array of characters.
1764 * @param offset the offset into the array of characters.
1765 * @param length the length of characters.
1766 */
1767 protected final void encodeCIIBuiltInAlgorithmDataAsCDATA(char[] ch, int offset, int length) throws FastInfosetException, IOException {
1768 // Encode identification and top two bits of encoding algorithm id
1769 write (EncodingConstants.CHARACTER_CHUNK | EncodingConstants.CHARACTER_CHUNK_ENCODING_ALGORITHM_FLAG);
1771 // Encode bottom 6 bits of enoding algorithm id
1772 _b = EncodingAlgorithmIndexes.CDATA << 2;
1775 length = encodeUTF8String(ch, offset, length);
1776 encodeNonZeroOctetStringLengthOnSenventhBit(length);
1777 write(_encodingBuffer, length);
1778 }
1780 /**
1781 * Encode a non empty identifying string on the first bit of an octet.
1782 * Implementation of clause C.13 of ITU-T Rec. X.891 | ISO/IEC 24824-1.
1783 *
1784 * @param s the identifying string.
1785 * @param map the vocabulary table to use to determin the index of the
1786 * identifying string
1787 */
1788 protected final void encodeIdentifyingNonEmptyStringOnFirstBit(String s, StringIntMap map) throws IOException {
1789 int index = map.obtainIndex(s);
1790 if (index == KeyIntMap.NOT_PRESENT) {
1791 // _b = 0;
1792 encodeNonEmptyOctetStringOnSecondBit(s);
1793 } else {
1794 // _b = 0x80;
1795 encodeNonZeroIntegerOnSecondBitFirstBitOne(index);
1796 }
1797 }
1799 /**
1800 * Encode a non empty string on the second bit of an octet using the UTF-8
1801 * encoding.
1802 * Implementation of clause C.22 of ITU-T Rec. X.891 | ISO/IEC 24824-1.
1803 *
1804 * @param s the string.
1805 */
1806 protected final void encodeNonEmptyOctetStringOnSecondBit(String s) throws IOException {
1807 final int length = encodeUTF8String(s);
1808 encodeNonZeroOctetStringLengthOnSecondBit(length);
1809 write(_encodingBuffer, length);
1810 }
1812 /**
1813 * Encode the length of a UTF-8 encoded string on the second bit of an octet.
1814 * Implementation of clause C.22 of ITU-T Rec. X.891 | ISO/IEC 24824-1.
1815 *
1816 * @param length the length to encode.
1817 */
1818 protected final void encodeNonZeroOctetStringLengthOnSecondBit(int length) throws IOException {
1819 if (length < EncodingConstants.OCTET_STRING_LENGTH_2ND_BIT_SMALL_LIMIT) {
1820 // [1, 64]
1821 write(length - 1);
1822 } else if (length < EncodingConstants.OCTET_STRING_LENGTH_2ND_BIT_MEDIUM_LIMIT) {
1823 // [65, 320]
1824 write(EncodingConstants.OCTET_STRING_LENGTH_2ND_BIT_MEDIUM_FLAG); // 010 00000
1825 write(length - EncodingConstants.OCTET_STRING_LENGTH_2ND_BIT_SMALL_LIMIT);
1826 } else {
1827 // [321, 4294967296]
1828 write(EncodingConstants.OCTET_STRING_LENGTH_2ND_BIT_LARGE_FLAG); // 0110 0000
1829 length -= EncodingConstants.OCTET_STRING_LENGTH_2ND_BIT_MEDIUM_LIMIT;
1830 write(length >>> 24);
1831 write((length >> 16) & 0xFF);
1832 write((length >> 8) & 0xFF);
1833 write(length & 0xFF);
1834 }
1835 }
1837 /**
1838 * Encode a non empty string on the fifth bit of an octet using the UTF-8
1839 * or UTF-16 encoding.
1840 * Implementation of clause C.23 of ITU-T Rec. X.891 | ISO/IEC 24824-1.
1841 *
1842 * @param s the string.
1843 */
1844 protected final void encodeNonEmptyCharacterStringOnFifthBit(String s) throws IOException {
1845 final int length = (_encodingStringsAsUtf8) ? encodeUTF8String(s) : encodeUtf16String(s);
1846 encodeNonZeroOctetStringLengthOnFifthBit(length);
1847 write(_encodingBuffer, length);
1848 }
1850 /**
1851 * Encode a non empty string on the fifth bit of an octet using the UTF-8
1852 * or UTF-16 encoding.
1853 * Implementation of clause C.23 of ITU-T Rec. X.891 | ISO/IEC 24824-1.
1854 *
1855 * @param ch the array of characters.
1856 * @param offset the offset into the array of characters.
1857 * @param length the length of characters.
1858 */
1859 protected final void encodeNonEmptyCharacterStringOnFifthBit(char[] ch, int offset, int length) throws IOException {
1860 length = (_encodingStringsAsUtf8) ? encodeUTF8String(ch, offset, length) : encodeUtf16String(ch, offset, length);
1861 encodeNonZeroOctetStringLengthOnFifthBit(length);
1862 write(_encodingBuffer, length);
1863 }
1865 /**
1866 * Encode the length of a UTF-8 or UTF-16 encoded string on the fifth bit
1867 * of an octet.
1868 * Implementation of clause C.23 of ITU-T Rec. X.891 | ISO/IEC 24824-1.
1869 *
1870 * @param length the length to encode.
1871 */
1872 protected final void encodeNonZeroOctetStringLengthOnFifthBit(int length) throws IOException {
1873 if (length < EncodingConstants.OCTET_STRING_LENGTH_5TH_BIT_SMALL_LIMIT) {
1874 // [1, 8]
1875 write(_b | (length - 1));
1876 } else if (length < EncodingConstants.OCTET_STRING_LENGTH_5TH_BIT_MEDIUM_LIMIT) {
1877 // [9, 264]
1878 write(_b | EncodingConstants.OCTET_STRING_LENGTH_5TH_BIT_MEDIUM_FLAG); // 000010 00
1879 write(length - EncodingConstants.OCTET_STRING_LENGTH_5TH_BIT_SMALL_LIMIT);
1880 } else {
1881 // [265, 4294967296]
1882 write(_b | EncodingConstants.OCTET_STRING_LENGTH_5TH_BIT_LARGE_FLAG); // 000011 00
1883 length -= EncodingConstants.OCTET_STRING_LENGTH_5TH_BIT_MEDIUM_LIMIT;
1884 write(length >>> 24);
1885 write((length >> 16) & 0xFF);
1886 write((length >> 8) & 0xFF);
1887 write(length & 0xFF);
1888 }
1889 }
1891 /**
1892 * Encode a non empty string on the seventh bit of an octet using the UTF-8
1893 * or UTF-16 encoding.
1894 * Implementation of clause C.24 of ITU-T Rec. X.891 | ISO/IEC 24824-1.
1895 *
1896 * @param ch the array of characters.
1897 * @param offset the offset into the array of characters.
1898 * @param length the length of characters.
1899 */
1900 protected final void encodeNonEmptyCharacterStringOnSeventhBit(char[] ch, int offset, int length) throws IOException {
1901 length = (_encodingStringsAsUtf8) ? encodeUTF8String(ch, offset, length) : encodeUtf16String(ch, offset, length);
1902 encodeNonZeroOctetStringLengthOnSenventhBit(length);
1903 write(_encodingBuffer, length);
1904 }
1906 /**
1907 * Encode a non empty string on the seventh bit of an octet using a restricted
1908 * alphabet that results in the encoding of a character in 4 bits
1909 * (or two characters per octet).
1910 * Implementation of clause C.24 of ITU-T Rec. X.891 | ISO/IEC 24824-1.
1911 *
1912 * @param table the table mapping characters to 4 bit values.
1913 * @param ch the array of characters.
1914 * @param offset the offset into the array of characters.
1915 * @param length the length of characters.
1916 */
1917 protected final void encodeNonEmptyFourBitCharacterStringOnSeventhBit(int[] table, char[] ch, int offset, int length) throws FastInfosetException, IOException {
1918 final int octetPairLength = length / 2;
1919 final int octetSingleLength = length % 2;
1921 // Encode the length
1922 encodeNonZeroOctetStringLengthOnSenventhBit(octetPairLength + octetSingleLength);
1923 encodeNonEmptyFourBitCharacterString(table, ch, offset, octetPairLength, octetSingleLength);
1924 }
1926 protected final void encodeNonEmptyFourBitCharacterString(int[] table, char[] ch, int offset,
1927 int octetPairLength, int octetSingleLength) throws FastInfosetException, IOException {
1928 ensureSize(octetPairLength + octetSingleLength);
1929 // Encode all pairs
1930 int v = 0;
1931 for (int i = 0; i < octetPairLength; i++) {
1932 v = (table[ch[offset++]] << 4) | table[ch[offset++]];
1933 if (v < 0) {
1934 throw new FastInfosetException(CommonResourceBundle.getInstance().getString("message.characterOutofAlphabetRange"));
1935 }
1936 _octetBuffer[_octetBufferIndex++] = (byte)v;
1937 }
1938 // Encode single character at end with termination bits
1939 if (octetSingleLength == 1) {
1940 v = (table[ch[offset]] << 4) | 0x0F;
1941 if (v < 0) {
1942 throw new FastInfosetException(CommonResourceBundle.getInstance().getString("message.characterOutofAlphabetRange"));
1943 }
1944 _octetBuffer[_octetBufferIndex++] = (byte)v;
1945 }
1946 }
1948 /**
1949 * Encode a non empty string on the seventh bit of an octet using a restricted
1950 * alphabet table.
1951 * Implementation of clause C.24 of ITU-T Rec. X.891 | ISO/IEC 24824-1.
1952 *
1953 * @param alphabet the alphabet defining the mapping between characters and
1954 * integer values.
1955 * @param ch the array of characters.
1956 * @param offset the offset into the array of characters.
1957 * @param length the length of characters.
1958 */
1959 protected final void encodeNonEmptyNBitCharacterStringOnSeventhBit(String alphabet, char[] ch, int offset, int length) throws FastInfosetException, IOException {
1960 int bitsPerCharacter = 1;
1961 while ((1 << bitsPerCharacter) <= alphabet.length()) {
1962 bitsPerCharacter++;
1963 }
1965 final int bits = length * bitsPerCharacter;
1966 final int octets = bits / 8;
1967 final int bitsOfLastOctet = bits % 8;
1968 final int totalOctets = octets + ((bitsOfLastOctet > 0) ? 1 : 0);
1970 // Encode the length
1971 encodeNonZeroOctetStringLengthOnSenventhBit(totalOctets);
1973 resetBits();
1974 ensureSize(totalOctets);
1975 int v = 0;
1976 for (int i = 0; i < length; i++) {
1977 final char c = ch[offset + i];
1978 // This is grotesquely slow, need to use hash table of character to int value
1979 for (v = 0; v < alphabet.length(); v++) {
1980 if (c == alphabet.charAt(v)) {
1981 break;
1982 }
1983 }
1984 if (v == alphabet.length()) {
1985 throw new FastInfosetException(CommonResourceBundle.getInstance().getString("message.characterOutofAlphabetRange"));
1986 }
1987 writeBits(bitsPerCharacter, v);
1988 }
1990 if (bitsOfLastOctet > 0) {
1991 _b |= (1 << (8 - bitsOfLastOctet)) - 1;
1992 write(_b);
1993 }
1994 }
1996 private int _bitsLeftInOctet;
1998 private final void resetBits() {
1999 _bitsLeftInOctet = 8;
2000 _b = 0;
2001 }
2003 private final void writeBits(int bits, int v) throws IOException {
2004 while (bits > 0) {
2005 final int bit = (v & (1 << --bits)) > 0 ? 1 : 0;
2006 _b |= bit << (--_bitsLeftInOctet);
2007 if (_bitsLeftInOctet == 0) {
2008 write(_b);
2009 _bitsLeftInOctet = 8;
2010 _b = 0;
2011 }
2012 }
2013 }
2015 /**
2016 * Encode the length of a encoded string on the seventh bit
2017 * of an octet.
2018 * Implementation of clause C.24 of ITU-T Rec. X.891 | ISO/IEC 24824-1.
2019 *
2020 * @param length the length to encode.
2021 */
2022 protected final void encodeNonZeroOctetStringLengthOnSenventhBit(int length) throws IOException {
2023 if (length < EncodingConstants.OCTET_STRING_LENGTH_7TH_BIT_SMALL_LIMIT) {
2024 // [1, 2]
2025 write(_b | (length - 1));
2026 } else if (length < EncodingConstants.OCTET_STRING_LENGTH_7TH_BIT_MEDIUM_LIMIT) {
2027 // [3, 258]
2028 write(_b | EncodingConstants.OCTET_STRING_LENGTH_7TH_BIT_MEDIUM_FLAG); // 00000010
2029 write(length - EncodingConstants.OCTET_STRING_LENGTH_7TH_BIT_SMALL_LIMIT);
2030 } else {
2031 // [259, 4294967296]
2032 write(_b | EncodingConstants.OCTET_STRING_LENGTH_7TH_BIT_LARGE_FLAG); // 00000011
2033 length -= EncodingConstants.OCTET_STRING_LENGTH_7TH_BIT_MEDIUM_LIMIT;
2034 write(length >>> 24);
2035 write((length >> 16) & 0xFF);
2036 write((length >> 8) & 0xFF);
2037 write(length & 0xFF);
2038 }
2039 }
2041 /**
2042 * Encode a non zero integer on the second bit of an octet, setting
2043 * the first bit to 1.
2044 * Implementation of clause C.24 of ITU-T Rec. X.891 | ISO/IEC 24824-1.
2045 *
2046 * <p>
2047 * The first bit of the first octet is set, as specified in clause C.13 of
2048 * ITU-T Rec. X.891 | ISO/IEC 24824-1
2049 *
2050 * @param i The integer to encode, which is a member of the interval
2051 * [0, 1048575]. In the specification the interval is [1, 1048576]
2052 *
2053 */
2054 protected final void encodeNonZeroIntegerOnSecondBitFirstBitOne(int i) throws IOException {
2055 if (i < EncodingConstants.INTEGER_2ND_BIT_SMALL_LIMIT) {
2056 // [1, 64] ( [0, 63] ) 6 bits
2057 write(0x80 | i);
2058 } else if (i < EncodingConstants.INTEGER_2ND_BIT_MEDIUM_LIMIT) {
2059 // [65, 8256] ( [64, 8255] ) 13 bits
2060 i -= EncodingConstants.INTEGER_2ND_BIT_SMALL_LIMIT;
2061 _b = (0x80 | EncodingConstants.INTEGER_2ND_BIT_MEDIUM_FLAG) | (i >> 8); // 010 00000
2062 // _b = 0xC0 | (i >> 8); // 010 00000
2063 write(_b);
2064 write(i & 0xFF);
2065 } else if (i < EncodingConstants.INTEGER_2ND_BIT_LARGE_LIMIT) {
2066 // [8257, 1048576] ( [8256, 1048575] ) 20 bits
2067 i -= EncodingConstants.INTEGER_2ND_BIT_MEDIUM_LIMIT;
2068 _b = (0x80 | EncodingConstants.INTEGER_2ND_BIT_LARGE_FLAG) | (i >> 16); // 0110 0000
2069 // _b = 0xE0 | (i >> 16); // 0110 0000
2070 write(_b);
2071 write((i >> 8) & 0xFF);
2072 write(i & 0xFF);
2073 } else {
2074 throw new IOException(
2075 CommonResourceBundle.getInstance().getString("message.integerMaxSize",
2076 new Object[]{Integer.valueOf(EncodingConstants.INTEGER_2ND_BIT_LARGE_LIMIT)}));
2077 }
2078 }
2080 /**
2081 * Encode a non zero integer on the second bit of an octet, setting
2082 * the first bit to 0.
2083 * Implementation of clause C.25 of ITU-T Rec. X.891 | ISO/IEC 24824-1.
2084 *
2085 * <p>
2086 * The first bit of the first octet is set, as specified in clause C.13 of
2087 * ITU-T Rec. X.891 | ISO/IEC 24824-1
2088 *
2089 * @param i The integer to encode, which is a member of the interval
2090 * [0, 1048575]. In the specification the interval is [1, 1048576]
2091 *
2092 */
2093 protected final void encodeNonZeroIntegerOnSecondBitFirstBitZero(int i) throws IOException {
2094 if (i < EncodingConstants.INTEGER_2ND_BIT_SMALL_LIMIT) {
2095 // [1, 64] ( [0, 63] ) 6 bits
2096 write(i);
2097 } else if (i < EncodingConstants.INTEGER_2ND_BIT_MEDIUM_LIMIT) {
2098 // [65, 8256] ( [64, 8255] ) 13 bits
2099 i -= EncodingConstants.INTEGER_2ND_BIT_SMALL_LIMIT;
2100 _b = EncodingConstants.INTEGER_2ND_BIT_MEDIUM_FLAG | (i >> 8); // 010 00000
2101 write(_b);
2102 write(i & 0xFF);
2103 } else {
2104 // [8257, 1048576] ( [8256, 1048575] ) 20 bits
2105 i -= EncodingConstants.INTEGER_2ND_BIT_MEDIUM_LIMIT;
2106 _b = EncodingConstants.INTEGER_2ND_BIT_LARGE_FLAG | (i >> 16); // 0110 0000
2107 write(_b);
2108 write((i >> 8) & 0xFF);
2109 write(i & 0xFF);
2110 }
2111 }
2113 /**
2114 * Encode a non zero integer on the third bit of an octet.
2115 * Implementation of clause C.27 of ITU-T Rec. X.891 | ISO/IEC 24824-1.
2116 *
2117 * @param i The integer to encode, which is a member of the interval
2118 * [0, 1048575]. In the specification the interval is [1, 1048576]
2119 *
2120 */
2121 protected final void encodeNonZeroIntegerOnThirdBit(int i) throws IOException {
2122 if (i < EncodingConstants.INTEGER_3RD_BIT_SMALL_LIMIT) {
2123 // [1, 32] ( [0, 31] ) 5 bits
2124 write(_b | i);
2125 } else if (i < EncodingConstants.INTEGER_3RD_BIT_MEDIUM_LIMIT) {
2126 // [33, 2080] ( [32, 2079] ) 11 bits
2127 i -= EncodingConstants.INTEGER_3RD_BIT_SMALL_LIMIT;
2128 _b |= EncodingConstants.INTEGER_3RD_BIT_MEDIUM_FLAG | (i >> 8); // 00100 000
2129 write(_b);
2130 write(i & 0xFF);
2131 } else if (i < EncodingConstants.INTEGER_3RD_BIT_LARGE_LIMIT) {
2132 // [2081, 526368] ( [2080, 526367] ) 19 bits
2133 i -= EncodingConstants.INTEGER_3RD_BIT_MEDIUM_LIMIT;
2134 _b |= EncodingConstants.INTEGER_3RD_BIT_LARGE_FLAG | (i >> 16); // 00101 000
2135 write(_b);
2136 write((i >> 8) & 0xFF);
2137 write(i & 0xFF);
2138 } else {
2139 // [526369, 1048576] ( [526368, 1048575] ) 20 bits
2140 i -= EncodingConstants.INTEGER_3RD_BIT_LARGE_LIMIT;
2141 _b |= EncodingConstants.INTEGER_3RD_BIT_LARGE_LARGE_FLAG; // 00110 000
2142 write(_b);
2143 write(i >> 16);
2144 write((i >> 8) & 0xFF);
2145 write(i & 0xFF);
2146 }
2147 }
2149 /**
2150 * Encode a non zero integer on the fourth bit of an octet.
2151 * Implementation of clause C.28 of ITU-T Rec. X.891 | ISO/IEC 24824-1.
2152 *
2153 * @param i The integer to encode, which is a member of the interval
2154 * [0, 1048575]. In the specification the interval is [1, 1048576]
2155 *
2156 */
2157 protected final void encodeNonZeroIntegerOnFourthBit(int i) throws IOException {
2158 if (i < EncodingConstants.INTEGER_4TH_BIT_SMALL_LIMIT) {
2159 // [1, 16] ( [0, 15] ) 4 bits
2160 write(_b | i);
2161 } else if (i < EncodingConstants.INTEGER_4TH_BIT_MEDIUM_LIMIT) {
2162 // [17, 1040] ( [16, 1039] ) 10 bits
2163 i -= EncodingConstants.INTEGER_4TH_BIT_SMALL_LIMIT;
2164 _b |= EncodingConstants.INTEGER_4TH_BIT_MEDIUM_FLAG | (i >> 8); // 000 100 00
2165 write(_b);
2166 write(i & 0xFF);
2167 } else if (i < EncodingConstants.INTEGER_4TH_BIT_LARGE_LIMIT) {
2168 // [1041, 263184] ( [1040, 263183] ) 18 bits
2169 i -= EncodingConstants.INTEGER_4TH_BIT_MEDIUM_LIMIT;
2170 _b |= EncodingConstants.INTEGER_4TH_BIT_LARGE_FLAG | (i >> 16); // 000 101 00
2171 write(_b);
2172 write((i >> 8) & 0xFF);
2173 write(i & 0xFF);
2174 } else {
2175 // [263185, 1048576] ( [263184, 1048575] ) 20 bits
2176 i -= EncodingConstants.INTEGER_4TH_BIT_LARGE_LIMIT;
2177 _b |= EncodingConstants.INTEGER_4TH_BIT_LARGE_LARGE_FLAG; // 000 110 00
2178 write(_b);
2179 write(i >> 16);
2180 write((i >> 8) & 0xFF);
2181 write(i & 0xFF);
2182 }
2183 }
2185 /**
2186 * Encode a non empty string using the UTF-8 encoding.
2187 *
2188 * @param b the current octet that is being written.
2189 * @param s the string to be UTF-8 encoded.
2190 * @param constants the array of constants to use when encoding to determin
2191 * how the length of the UTF-8 encoded string is encoded.
2192 */
2193 protected final void encodeNonEmptyUTF8StringAsOctetString(int b, String s, int[] constants) throws IOException {
2194 final char[] ch = s.toCharArray();
2195 encodeNonEmptyUTF8StringAsOctetString(b, ch, 0, ch.length, constants);
2196 }
2198 /**
2199 * Encode a non empty string using the UTF-8 encoding.
2200 *
2201 * @param b the current octet that is being written.
2202 * @param ch the array of characters.
2203 * @param offset the offset into the array of characters.
2204 * @param length the length of characters.
2205 * how the length of the UTF-8 encoded string is encoded.
2206 * @param constants the array of constants to use when encoding to determin
2207 * how the length of the UTF-8 encoded string is encoded.
2208 */
2209 protected final void encodeNonEmptyUTF8StringAsOctetString(int b, char ch[], int offset, int length, int[] constants) throws IOException {
2210 length = encodeUTF8String(ch, offset, length);
2211 encodeNonZeroOctetStringLength(b, length, constants);
2212 write(_encodingBuffer, length);
2213 }
2215 /**
2216 * Encode the length of non empty UTF-8 encoded string.
2217 *
2218 * @param b the current octet that is being written.
2219 * @param length the length of the UTF-8 encoded string.
2220 * how the length of the UTF-8 encoded string is encoded.
2221 * @param constants the array of constants to use when encoding to determin
2222 * how the length of the UTF-8 encoded string is encoded.
2223 */
2224 protected final void encodeNonZeroOctetStringLength(int b, int length, int[] constants) throws IOException {
2225 if (length < constants[EncodingConstants.OCTET_STRING_LENGTH_SMALL_LIMIT]) {
2226 write(b | (length - 1));
2227 } else if (length < constants[EncodingConstants.OCTET_STRING_LENGTH_MEDIUM_LIMIT]) {
2228 write(b | constants[EncodingConstants.OCTET_STRING_LENGTH_MEDIUM_FLAG]);
2229 write(length - constants[EncodingConstants.OCTET_STRING_LENGTH_SMALL_LIMIT]);
2230 } else {
2231 write(b | constants[EncodingConstants.OCTET_STRING_LENGTH_LARGE_FLAG]);
2232 length -= constants[EncodingConstants.OCTET_STRING_LENGTH_MEDIUM_LIMIT];
2233 write(length >>> 24);
2234 write((length >> 16) & 0xFF);
2235 write((length >> 8) & 0xFF);
2236 write(length & 0xFF);
2237 }
2238 }
2240 /**
2241 * Encode a non zero integer.
2242 *
2243 * @param b the current octet that is being written.
2244 * @param i the non zero integer.
2245 * @param constants the array of constants to use when encoding to determin
2246 * how the non zero integer is encoded.
2247 */
2248 protected final void encodeNonZeroInteger(int b, int i, int[] constants) throws IOException {
2249 if (i < constants[EncodingConstants.INTEGER_SMALL_LIMIT]) {
2250 write(b | i);
2251 } else if (i < constants[EncodingConstants.INTEGER_MEDIUM_LIMIT]) {
2252 i -= constants[EncodingConstants.INTEGER_SMALL_LIMIT];
2253 write(b | constants[EncodingConstants.INTEGER_MEDIUM_FLAG] | (i >> 8));
2254 write(i & 0xFF);
2255 } else if (i < constants[EncodingConstants.INTEGER_LARGE_LIMIT]) {
2256 i -= constants[EncodingConstants.INTEGER_MEDIUM_LIMIT];
2257 write(b | constants[EncodingConstants.INTEGER_LARGE_FLAG] | (i >> 16));
2258 write((i >> 8) & 0xFF);
2259 write(i & 0xFF);
2260 } else if (i < EncodingConstants.INTEGER_MAXIMUM_SIZE) {
2261 i -= constants[EncodingConstants.INTEGER_LARGE_LIMIT];
2262 write(b | constants[EncodingConstants.INTEGER_LARGE_LARGE_FLAG]);
2263 write(i >> 16);
2264 write((i >> 8) & 0xFF);
2265 write(i & 0xFF);
2266 } else {
2267 throw new IOException(CommonResourceBundle.getInstance().getString("message.integerMaxSize", new Object[]{Integer.valueOf(EncodingConstants.INTEGER_MAXIMUM_SIZE)}));
2268 }
2269 }
2271 /**
2272 * Mark the current position in the buffered stream.
2273 */
2274 protected final void mark() {
2275 _markIndex = _octetBufferIndex;
2276 }
2278 /**
2279 * Reset the marked position in the buffered stream.
2280 */
2281 protected final void resetMark() {
2282 _markIndex = -1;
2283 }
2285 /**
2286 * @return true if the mark has been set, otherwise false if the mark
2287 * has not been set.
2288 */
2289 protected final boolean hasMark() {
2290 return _markIndex != -1;
2291 }
2293 /**
2294 * Write a byte to the buffered stream.
2295 */
2296 protected final void write(int i) throws IOException {
2297 if (_octetBufferIndex < _octetBuffer.length) {
2298 _octetBuffer[_octetBufferIndex++] = (byte)i;
2299 } else {
2300 if (_markIndex == -1) {
2301 _s.write(_octetBuffer);
2302 _octetBufferIndex = 1;
2303 _octetBuffer[0] = (byte)i;
2304 } else {
2305 resize(_octetBuffer.length * 3 / 2);
2306 _octetBuffer[_octetBufferIndex++] = (byte)i;
2307 }
2308 }
2309 }
2311 /**
2312 * Write an array of bytes to the buffered stream.
2313 *
2314 * @param b the array of bytes.
2315 * @param length the length of bytes.
2316 */
2317 protected final void write(byte[] b, int length) throws IOException {
2318 write(b, 0, length);
2319 }
2321 /**
2322 * Write an array of bytes to the buffered stream.
2323 *
2324 * @param b the array of bytes.
2325 * @param offset the offset into the array of bytes.
2326 * @param length the length of bytes.
2327 */
2328 protected final void write(byte[] b, int offset, int length) throws IOException {
2329 if ((_octetBufferIndex + length) < _octetBuffer.length) {
2330 System.arraycopy(b, offset, _octetBuffer, _octetBufferIndex, length);
2331 _octetBufferIndex += length;
2332 } else {
2333 if (_markIndex == -1) {
2334 _s.write(_octetBuffer, 0, _octetBufferIndex);
2335 _s.write(b, offset, length);
2336 _octetBufferIndex = 0;
2337 } else {
2338 resize((_octetBuffer.length + length) * 3 / 2 + 1);
2339 System.arraycopy(b, offset, _octetBuffer, _octetBufferIndex, length);
2340 _octetBufferIndex += length;
2341 }
2342 }
2343 }
2345 private void ensureSize(int length) {
2346 if ((_octetBufferIndex + length) > _octetBuffer.length) {
2347 resize((_octetBufferIndex + length) * 3 / 2 + 1);
2348 }
2349 }
2351 private void resize(int length) {
2352 byte[] b = new byte[length];
2353 System.arraycopy(_octetBuffer, 0, b, 0, _octetBufferIndex);
2354 _octetBuffer = b;
2355 }
2357 private void _flush() throws IOException {
2358 if (_octetBufferIndex > 0) {
2359 _s.write(_octetBuffer, 0, _octetBufferIndex);
2360 _octetBufferIndex = 0;
2361 }
2362 }
2365 private EncodingBufferOutputStream _encodingBufferOutputStream = new EncodingBufferOutputStream();
2367 private byte[] _encodingBuffer = new byte[512];
2369 private int _encodingBufferIndex;
2371 private class EncodingBufferOutputStream extends OutputStream {
2373 public void write(int b) throws IOException {
2374 if (_encodingBufferIndex < _encodingBuffer.length) {
2375 _encodingBuffer[_encodingBufferIndex++] = (byte)b;
2376 } else {
2377 byte newbuf[] = new byte[Math.max(_encodingBuffer.length << 1, _encodingBufferIndex)];
2378 System.arraycopy(_encodingBuffer, 0, newbuf, 0, _encodingBufferIndex);
2379 _encodingBuffer = newbuf;
2381 _encodingBuffer[_encodingBufferIndex++] = (byte)b;
2382 }
2383 }
2385 public void write(byte b[], int off, int len) throws IOException {
2386 if ((off < 0) || (off > b.length) || (len < 0) ||
2387 ((off + len) > b.length) || ((off + len) < 0)) {
2388 throw new IndexOutOfBoundsException();
2389 } else if (len == 0) {
2390 return;
2391 }
2392 final int newoffset = _encodingBufferIndex + len;
2393 if (newoffset > _encodingBuffer.length) {
2394 byte newbuf[] = new byte[Math.max(_encodingBuffer.length << 1, newoffset)];
2395 System.arraycopy(_encodingBuffer, 0, newbuf, 0, _encodingBufferIndex);
2396 _encodingBuffer = newbuf;
2397 }
2398 System.arraycopy(b, off, _encodingBuffer, _encodingBufferIndex, len);
2399 _encodingBufferIndex = newoffset;
2400 }
2402 public int getLength() {
2403 return _encodingBufferIndex;
2404 }
2406 public void reset() {
2407 _encodingBufferIndex = 0;
2408 }
2409 }
2411 /**
2412 * Encode a string using the UTF-8 encoding.
2413 *
2414 * @param s the string to encode.
2415 */
2416 protected final int encodeUTF8String(String s) throws IOException {
2417 final int length = s.length();
2418 if (length < _charBuffer.length) {
2419 s.getChars(0, length, _charBuffer, 0);
2420 return encodeUTF8String(_charBuffer, 0, length);
2421 } else {
2422 char[] ch = s.toCharArray();
2423 return encodeUTF8String(ch, 0, length);
2424 }
2425 }
2427 private void ensureEncodingBufferSizeForUtf8String(int length) {
2428 final int newLength = 4 * length;
2429 if (_encodingBuffer.length < newLength) {
2430 _encodingBuffer = new byte[newLength];
2431 }
2432 }
2434 /**
2435 * Encode a string using the UTF-8 encoding.
2436 *
2437 * @param ch the array of characters.
2438 * @param offset the offset into the array of characters.
2439 * @param length the length of characters.
2440 */
2441 protected final int encodeUTF8String(char[] ch, int offset, int length) throws IOException {
2442 int bpos = 0;
2444 // Make sure buffer is large enough
2445 ensureEncodingBufferSizeForUtf8String(length);
2447 final int end = offset + length;
2448 int c;
2449 while (end != offset) {
2450 c = ch[offset++];
2451 if (c < 0x80) {
2452 // 1 byte, 7 bits
2453 _encodingBuffer[bpos++] = (byte) c;
2454 } else if (c < 0x800) {
2455 // 2 bytes, 11 bits
2456 _encodingBuffer[bpos++] =
2457 (byte) (0xC0 | (c >> 6)); // first 5
2458 _encodingBuffer[bpos++] =
2459 (byte) (0x80 | (c & 0x3F)); // second 6
2460 } else if (c <= '\uFFFF') {
2461 if (!XMLChar.isHighSurrogate(c) && !XMLChar.isLowSurrogate(c)) {
2462 // 3 bytes, 16 bits
2463 _encodingBuffer[bpos++] =
2464 (byte) (0xE0 | (c >> 12)); // first 4
2465 _encodingBuffer[bpos++] =
2466 (byte) (0x80 | ((c >> 6) & 0x3F)); // second 6
2467 _encodingBuffer[bpos++] =
2468 (byte) (0x80 | (c & 0x3F)); // third 6
2469 } else {
2470 // 4 bytes, high and low surrogate
2471 encodeCharacterAsUtf8FourByte(c, ch, offset, end, bpos);
2472 bpos += 4;
2473 offset++;
2474 }
2475 }
2476 }
2478 return bpos;
2479 }
2481 private void encodeCharacterAsUtf8FourByte(int c, char[] ch, int chpos, int chend, int bpos) throws IOException {
2482 if (chpos == chend) {
2483 throw new IOException("");
2484 }
2486 final char d = ch[chpos];
2487 if (!XMLChar.isLowSurrogate(d)) {
2488 throw new IOException("");
2489 }
2491 final int uc = (((c & 0x3ff) << 10) | (d & 0x3ff)) + 0x10000;
2492 if (uc < 0 || uc >= 0x200000) {
2493 throw new IOException("");
2494 }
2496 _encodingBuffer[bpos++] = (byte)(0xF0 | ((uc >> 18)));
2497 _encodingBuffer[bpos++] = (byte)(0x80 | ((uc >> 12) & 0x3F));
2498 _encodingBuffer[bpos++] = (byte)(0x80 | ((uc >> 6) & 0x3F));
2499 _encodingBuffer[bpos++] = (byte)(0x80 | (uc & 0x3F));
2500 }
2502 /**
2503 * Encode a string using the UTF-16 encoding.
2504 *
2505 * @param s the string to encode.
2506 */
2507 protected final int encodeUtf16String(String s) throws IOException {
2508 final int length = s.length();
2509 if (length < _charBuffer.length) {
2510 s.getChars(0, length, _charBuffer, 0);
2511 return encodeUtf16String(_charBuffer, 0, length);
2512 } else {
2513 char[] ch = s.toCharArray();
2514 return encodeUtf16String(ch, 0, length);
2515 }
2516 }
2518 private void ensureEncodingBufferSizeForUtf16String(int length) {
2519 final int newLength = 2 * length;
2520 if (_encodingBuffer.length < newLength) {
2521 _encodingBuffer = new byte[newLength];
2522 }
2523 }
2525 /**
2526 * Encode a string using the UTF-16 encoding.
2527 *
2528 * @param ch the array of characters.
2529 * @param offset the offset into the array of characters.
2530 * @param length the length of characters.
2531 */
2532 protected final int encodeUtf16String(char[] ch, int offset, int length) throws IOException {
2533 int byteLength = 0;
2535 // Make sure buffer is large enough
2536 ensureEncodingBufferSizeForUtf16String(length);
2538 final int n = offset + length;
2539 for (int i = offset; i < n; i++) {
2540 final int c = (int) ch[i];
2541 _encodingBuffer[byteLength++] = (byte)(c >> 8);
2542 _encodingBuffer[byteLength++] = (byte)(c & 0xFF);
2543 }
2545 return byteLength;
2546 }
2548 /**
2549 * Obtain the prefix from a qualified name.
2550 *
2551 * @param qName the qualified name
2552 * @return the prefix, or "" if there is no prefix.
2553 */
2554 public static String getPrefixFromQualifiedName(String qName) {
2555 int i = qName.indexOf(':');
2556 String prefix = "";
2557 if (i != -1) {
2558 prefix = qName.substring(0, i);
2559 }
2560 return prefix;
2561 }
2563 /**
2564 * Check if character array contains characters that are all white space.
2565 *
2566 * @param ch the character array
2567 * @param start the starting character index into the array to check from
2568 * @param length the number of characters to check
2569 * @return true if all characters are white space, false otherwise
2570 */
2571 public static boolean isWhiteSpace(final char[] ch, int start, final int length) {
2572 if (!XMLChar.isSpace(ch[start])) return false;
2574 final int end = start + length;
2575 while(++start < end && XMLChar.isSpace(ch[start]));
2577 return start == end;
2578 }
2580 /**
2581 * Check if a String contains characters that are all white space.
2582 *
2583 * @param s the string
2584 * @return true if all characters are white space, false otherwise
2585 */
2586 public static boolean isWhiteSpace(String s) {
2587 if (!XMLChar.isSpace(s.charAt(0))) return false;
2589 final int end = s.length();
2590 int start = 1;
2591 while(start < end && XMLChar.isSpace(s.charAt(start++)));
2592 return start == end;
2593 }
2594 }