src/share/jaxws_classes/com/sun/xml/internal/fastinfoset/Encoder.java

Thu, 12 Oct 2017 19:44:07 +0800

author
aoqi
date
Thu, 12 Oct 2017 19:44:07 +0800
changeset 760
e530533619ec
parent 0
373ffda63c9a
permissions
-rw-r--r--

merge

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

mercurial