1 /* 2 * Licensed to the Apache Software Foundation (ASF) under one or more 3 * contributor license agreements. See the NOTICE file distributed with 4 * this work for additional information regarding copyright ownership. 5 * The ASF licenses this file to You under the Apache License, Version 2.0 6 * (the "License"); you may not use this file except in compliance with 7 * the License. You may obtain a copy of the License at 8 * 9 * http://www.apache.org/licenses/LICENSE-2.0 10 * 11 * Unless required by applicable law or agreed to in writing, software 12 * distributed under the License is distributed on an "AS IS" BASIS, 13 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 14 * See the License for the specific language governing permissions and 15 * limitations under the License. 16 */ 17 18 package org.apache.commons.codec.binary; 19 20 import java.util.Arrays; 21 import java.util.Objects; 22 23 import org.apache.commons.codec.BinaryDecoder; 24 import org.apache.commons.codec.BinaryEncoder; 25 import org.apache.commons.codec.CodecPolicy; 26 import org.apache.commons.codec.DecoderException; 27 import org.apache.commons.codec.EncoderException; 28 29 /** 30 * Abstract superclass for Base-N encoders and decoders. 31 * 32 * <p> 33 * This class is thread-safe. 34 * </p> 35 * <p> 36 * You can set the decoding behavior when the input bytes contain leftover trailing bits that cannot be created by a 37 * valid encoding. These can be bits that are unused from the final character or entire characters. The default mode is 38 * lenient decoding. 39 * </p> 40 * <ul> 41 * <li>Lenient: Any trailing bits are composed into 8-bit bytes where possible. The remainder are discarded. 42 * <li>Strict: The decoding will raise an {@link IllegalArgumentException} if trailing bits are not part of a valid 43 * encoding. Any unused bits from the final character must be zero. Impossible counts of entire final characters are not 44 * allowed. 45 * </ul> 46 * <p> 47 * When strict decoding is enabled it is expected that the decoded bytes will be re-encoded to a byte array that matches 48 * the original, i.e. no changes occur on the final character. This requires that the input bytes use the same padding 49 * and alphabet as the encoder. 50 * </p> 51 */ 52 public abstract class BaseNCodec implements BinaryEncoder, BinaryDecoder { 53 54 /** 55 * Holds thread context so classes can be thread-safe. 56 * 57 * This class is not itself thread-safe; each thread must allocate its own copy. 58 * 59 * @since 1.7 60 */ 61 static class Context { 62 63 /** 64 * Placeholder for the bytes we're dealing with for our based logic. 65 * Bitwise operations store and extract the encoding or decoding from this variable. 66 */ 67 int ibitWorkArea; 68 69 /** 70 * Placeholder for the bytes we're dealing with for our based logic. 71 * Bitwise operations store and extract the encoding or decoding from this variable. 72 */ 73 long lbitWorkArea; 74 75 /** 76 * Buffer for streaming. 77 */ 78 byte[] buffer; 79 80 /** 81 * Position where next character should be written in the buffer. 82 */ 83 int pos; 84 85 /** 86 * Position where next character should be read from the buffer. 87 */ 88 int readPos; 89 90 /** 91 * Boolean flag to indicate the EOF has been reached. Once EOF has been reached, this object becomes useless, 92 * and must be thrown away. 93 */ 94 boolean eof; 95 96 /** 97 * Variable tracks how many characters have been written to the current line. Only used when encoding. We use 98 * it to make sure each encoded line never goes beyond lineLength (if lineLength > 0). 99 */ 100 int currentLinePos; 101 102 /** 103 * Writes to the buffer only occur after every 3/5 reads when encoding, and every 4/8 reads when decoding. This 104 * variable helps track that. 105 */ 106 int modulus; 107 108 /** 109 * Returns a String useful for debugging (especially within a debugger.) 110 * 111 * @return a String useful for debugging. 112 */ 113 @SuppressWarnings("boxing") // OK to ignore boxing here 114 @Override 115 public String toString() { 116 return String.format("%s[buffer=%s, currentLinePos=%s, eof=%s, ibitWorkArea=%s, lbitWorkArea=%s, " + 117 "modulus=%s, pos=%s, readPos=%s]", this.getClass().getSimpleName(), Arrays.toString(buffer), 118 currentLinePos, eof, ibitWorkArea, lbitWorkArea, modulus, pos, readPos); 119 } 120 } 121 122 /** 123 * EOF 124 * 125 * @since 1.7 126 */ 127 static final int EOF = -1; 128 129 /** 130 * MIME chunk size per RFC 2045 section 6.8. 131 * 132 * <p> 133 * The {@value} character limit does not count the trailing CRLF, but counts all other characters, including any 134 * equal signs. 135 * </p> 136 * 137 * @see <a href="http://www.ietf.org/rfc/rfc2045.txt">RFC 2045 section 6.8</a> 138 */ 139 public static final int MIME_CHUNK_SIZE = 76; 140 141 /** 142 * PEM chunk size per RFC 1421 section 4.3.2.4. 143 * 144 * <p> 145 * The {@value} character limit does not count the trailing CRLF, but counts all other characters, including any 146 * equal signs. 147 * </p> 148 * 149 * @see <a href="https://tools.ietf.org/html/rfc1421">RFC 1421 section 4.3.2.4</a> 150 */ 151 public static final int PEM_CHUNK_SIZE = 64; 152 153 private static final int DEFAULT_BUFFER_RESIZE_FACTOR = 2; 154 155 /** 156 * Defines the default buffer size - currently {@value} 157 * - must be large enough for at least one encoded block+separator 158 */ 159 private static final int DEFAULT_BUFFER_SIZE = 8192; 160 161 /** 162 * The maximum size buffer to allocate. 163 * 164 * <p>This is set to the same size used in the JDK {@link java.util.ArrayList}:</p> 165 * <blockquote> 166 * Some VMs reserve some header words in an array. 167 * Attempts to allocate larger arrays may result in 168 * OutOfMemoryError: Requested array size exceeds VM limit. 169 * </blockquote> 170 */ 171 private static final int MAX_BUFFER_SIZE = Integer.MAX_VALUE - 8; 172 173 /** Mask used to extract 8 bits, used in decoding bytes */ 174 protected static final int MASK_8BITS = 0xff; 175 176 /** 177 * Byte used to pad output. 178 */ 179 protected static final byte PAD_DEFAULT = '='; // Allow static access to default 180 181 /** 182 * The default decoding policy. 183 * @since 1.15 184 */ 185 protected static final CodecPolicy DECODING_POLICY_DEFAULT = CodecPolicy.LENIENT; 186 187 /** 188 * Chunk separator per RFC 2045 section 2.1. 189 * 190 * @see <a href="http://www.ietf.org/rfc/rfc2045.txt">RFC 2045 section 2.1</a> 191 */ 192 static final byte[] CHUNK_SEPARATOR = {'\r', '\n'}; 193 194 /** 195 * Create a positive capacity at least as large the minimum required capacity. 196 * If the minimum capacity is negative then this throws an OutOfMemoryError as no array 197 * can be allocated. 198 * 199 * @param minCapacity the minimum capacity 200 * @return the capacity 201 * @throws OutOfMemoryError if the {@code minCapacity} is negative 202 */ 203 private static int createPositiveCapacity(final int minCapacity) { 204 if (minCapacity < 0) { 205 // overflow 206 throw new OutOfMemoryError("Unable to allocate array size: " + (minCapacity & 0xffffffffL)); 207 } 208 // This is called when we require buffer expansion to a very big array. 209 // Use the conservative maximum buffer size if possible, otherwise the biggest required. 210 // 211 // Note: In this situation JDK 1.8 java.util.ArrayList returns Integer.MAX_VALUE. 212 // This excludes some VMs that can exceed MAX_BUFFER_SIZE but not allocate a full 213 // Integer.MAX_VALUE length array. 214 // The result is that we may have to allocate an array of this size more than once if 215 // the capacity must be expanded again. 216 return Math.max(minCapacity, MAX_BUFFER_SIZE); 217 } 218 219 /** 220 * Gets a copy of the chunk separator per RFC 2045 section 2.1. 221 * 222 * @return the chunk separator 223 * @see <a href="http://www.ietf.org/rfc/rfc2045.txt">RFC 2045 section 2.1</a> 224 * @since 1.15 225 */ 226 public static byte[] getChunkSeparator() { 227 return CHUNK_SEPARATOR.clone(); 228 } 229 230 /** 231 * Checks if a byte value is whitespace or not. 232 * @param byteToCheck 233 * the byte to check 234 * @return true if byte is whitespace, false otherwise 235 * @see Character#isWhitespace(int) 236 * @deprecated Use {@link Character#isWhitespace(int)}. 237 */ 238 @Deprecated 239 protected static boolean isWhiteSpace(final byte byteToCheck) { 240 return Character.isWhitespace(byteToCheck); 241 } 242 243 /** 244 * Increases our buffer by the {@link #DEFAULT_BUFFER_RESIZE_FACTOR}. 245 * @param context the context to be used 246 * @param minCapacity the minimum required capacity 247 * @return the resized byte[] buffer 248 * @throws OutOfMemoryError if the {@code minCapacity} is negative 249 */ 250 private static byte[] resizeBuffer(final Context context, final int minCapacity) { 251 // Overflow-conscious code treats the min and new capacity as unsigned. 252 final int oldCapacity = context.buffer.length; 253 int newCapacity = oldCapacity * DEFAULT_BUFFER_RESIZE_FACTOR; 254 if (Integer.compareUnsigned(newCapacity, minCapacity) < 0) { 255 newCapacity = minCapacity; 256 } 257 if (Integer.compareUnsigned(newCapacity, MAX_BUFFER_SIZE) > 0) { 258 newCapacity = createPositiveCapacity(minCapacity); 259 } 260 261 final byte[] b = Arrays.copyOf(context.buffer, newCapacity); 262 context.buffer = b; 263 return b; 264 } 265 266 /** 267 * @deprecated Use {@link #pad}. Will be removed in 2.0. 268 */ 269 @Deprecated 270 protected final byte PAD = PAD_DEFAULT; // instance variable just in case it needs to vary later 271 272 /** Pad byte. Instance variable just in case it needs to vary later. */ 273 protected final byte pad; 274 275 /** Number of bytes in each full block of unencoded data, e.g. 4 for Base64 and 5 for Base32 */ 276 private final int unencodedBlockSize; 277 278 /** Number of bytes in each full block of encoded data, e.g. 3 for Base64 and 8 for Base32 */ 279 private final int encodedBlockSize; 280 281 /** 282 * Chunksize for encoding. Not used when decoding. 283 * A value of zero or less implies no chunking of the encoded data. 284 * Rounded down to the nearest multiple of encodedBlockSize. 285 */ 286 protected final int lineLength; 287 288 /** 289 * Size of chunk separator. Not used unless {@link #lineLength} > 0. 290 */ 291 private final int chunkSeparatorLength; 292 293 /** 294 * Defines the decoding behavior when the input bytes contain leftover trailing bits that 295 * cannot be created by a valid encoding. These can be bits that are unused from the final 296 * character or entire characters. The default mode is lenient decoding. Set this to 297 * {@code true} to enable strict decoding. 298 * <ul> 299 * <li>Lenient: Any trailing bits are composed into 8-bit bytes where possible. 300 * The remainder are discarded. 301 * <li>Strict: The decoding will raise an {@link IllegalArgumentException} if trailing bits 302 * are not part of a valid encoding. Any unused bits from the final character must 303 * be zero. Impossible counts of entire final characters are not allowed. 304 * </ul> 305 * <p> 306 * When strict decoding is enabled it is expected that the decoded bytes will be re-encoded 307 * to a byte array that matches the original, i.e. no changes occur on the final 308 * character. This requires that the input bytes use the same padding and alphabet 309 * as the encoder. 310 * </p> 311 */ 312 private final CodecPolicy decodingPolicy; 313 314 /** 315 * Note {@code lineLength} is rounded down to the nearest multiple of the encoded block size. 316 * If {@code chunkSeparatorLength} is zero, then chunking is disabled. 317 * 318 * @param unencodedBlockSize the size of an unencoded block (e.g. Base64 = 3) 319 * @param encodedBlockSize the size of an encoded block (e.g. Base64 = 4) 320 * @param lineLength if > 0, use chunking with a length {@code lineLength} 321 * @param chunkSeparatorLength the chunk separator length, if relevant 322 */ 323 protected BaseNCodec(final int unencodedBlockSize, final int encodedBlockSize, 324 final int lineLength, final int chunkSeparatorLength) { 325 this(unencodedBlockSize, encodedBlockSize, lineLength, chunkSeparatorLength, PAD_DEFAULT); 326 } 327 328 /** 329 * Note {@code lineLength} is rounded down to the nearest multiple of the encoded block size. 330 * If {@code chunkSeparatorLength} is zero, then chunking is disabled. 331 * 332 * @param unencodedBlockSize the size of an unencoded block (e.g. Base64 = 3) 333 * @param encodedBlockSize the size of an encoded block (e.g. Base64 = 4) 334 * @param lineLength if > 0, use chunking with a length {@code lineLength} 335 * @param chunkSeparatorLength the chunk separator length, if relevant 336 * @param pad byte used as padding byte. 337 */ 338 protected BaseNCodec(final int unencodedBlockSize, final int encodedBlockSize, 339 final int lineLength, final int chunkSeparatorLength, final byte pad) { 340 this(unencodedBlockSize, encodedBlockSize, lineLength, chunkSeparatorLength, pad, DECODING_POLICY_DEFAULT); 341 } 342 343 /** 344 * Note {@code lineLength} is rounded down to the nearest multiple of the encoded block size. 345 * If {@code chunkSeparatorLength} is zero, then chunking is disabled. 346 * 347 * @param unencodedBlockSize the size of an unencoded block (e.g. Base64 = 3) 348 * @param encodedBlockSize the size of an encoded block (e.g. Base64 = 4) 349 * @param lineLength if > 0, use chunking with a length {@code lineLength} 350 * @param chunkSeparatorLength the chunk separator length, if relevant 351 * @param pad byte used as padding byte. 352 * @param decodingPolicy Decoding policy. 353 * @since 1.15 354 */ 355 protected BaseNCodec(final int unencodedBlockSize, final int encodedBlockSize, 356 final int lineLength, final int chunkSeparatorLength, final byte pad, 357 final CodecPolicy decodingPolicy) { 358 this.unencodedBlockSize = unencodedBlockSize; 359 this.encodedBlockSize = encodedBlockSize; 360 final boolean useChunking = lineLength > 0 && chunkSeparatorLength > 0; 361 this.lineLength = useChunking ? lineLength / encodedBlockSize * encodedBlockSize : 0; 362 this.chunkSeparatorLength = chunkSeparatorLength; 363 this.pad = pad; 364 this.decodingPolicy = Objects.requireNonNull(decodingPolicy, "codecPolicy"); 365 } 366 367 /** 368 * Returns the amount of buffered data available for reading. 369 * 370 * @param context the context to be used 371 * @return The amount of buffered data available for reading. 372 */ 373 int available(final Context context) { // package protected for access from I/O streams 374 return hasData(context) ? context.pos - context.readPos : 0; 375 } 376 377 /** 378 * Tests a given byte array to see if it contains any characters within the alphabet or PAD. 379 * 380 * Intended for use in checking line-ending arrays 381 * 382 * @param arrayOctet 383 * byte array to test 384 * @return {@code true} if any byte is a valid character in the alphabet or PAD; {@code false} otherwise 385 */ 386 protected boolean containsAlphabetOrPad(final byte[] arrayOctet) { 387 if (arrayOctet == null) { 388 return false; 389 } 390 for (final byte element : arrayOctet) { 391 if (pad == element || isInAlphabet(element)) { 392 return true; 393 } 394 } 395 return false; 396 } 397 398 /** 399 * Decodes a byte[] containing characters in the Base-N alphabet. 400 * 401 * @param pArray 402 * A byte array containing Base-N character data 403 * @return a byte array containing binary data 404 */ 405 @Override 406 public byte[] decode(final byte[] pArray) { 407 if (BinaryCodec.isEmpty(pArray)) { 408 return pArray; 409 } 410 final Context context = new Context(); 411 decode(pArray, 0, pArray.length, context); 412 decode(pArray, 0, EOF, context); // Notify decoder of EOF. 413 final byte[] result = new byte[context.pos]; 414 readResults(result, 0, result.length, context); 415 return result; 416 } 417 418 // package protected for access from I/O streams 419 abstract void decode(byte[] pArray, int i, int length, Context context); 420 421 /** 422 * Decodes an Object using the Base-N algorithm. This method is provided in order to satisfy the requirements of 423 * the Decoder interface, and will throw a DecoderException if the supplied object is not of type byte[] or String. 424 * 425 * @param obj 426 * Object to decode 427 * @return An object (of type byte[]) containing the binary data which corresponds to the byte[] or String 428 * supplied. 429 * @throws DecoderException 430 * if the parameter supplied is not of type byte[] 431 */ 432 @Override 433 public Object decode(final Object obj) throws DecoderException { 434 if (obj instanceof byte[]) { 435 return decode((byte[]) obj); 436 } 437 if (obj instanceof String) { 438 return decode((String) obj); 439 } 440 throw new DecoderException("Parameter supplied to Base-N decode is not a byte[] or a String"); 441 } 442 443 /** 444 * Decodes a String containing characters in the Base-N alphabet. 445 * 446 * @param pArray 447 * A String containing Base-N character data 448 * @return a byte array containing binary data 449 */ 450 public byte[] decode(final String pArray) { 451 return decode(StringUtils.getBytesUtf8(pArray)); 452 } 453 454 /** 455 * Encodes a byte[] containing binary data, into a byte[] containing characters in the alphabet. 456 * 457 * @param pArray 458 * a byte array containing binary data 459 * @return A byte array containing only the base N alphabetic character data 460 */ 461 @Override 462 public byte[] encode(final byte[] pArray) { 463 if (BinaryCodec.isEmpty(pArray)) { 464 return pArray; 465 } 466 return encode(pArray, 0, pArray.length); 467 } 468 469 /** 470 * Encodes a byte[] containing binary data, into a byte[] containing 471 * characters in the alphabet. 472 * 473 * @param pArray 474 * a byte array containing binary data 475 * @param offset 476 * initial offset of the subarray. 477 * @param length 478 * length of the subarray. 479 * @return A byte array containing only the base N alphabetic character data 480 * @since 1.11 481 */ 482 public byte[] encode(final byte[] pArray, final int offset, final int length) { 483 if (BinaryCodec.isEmpty(pArray)) { 484 return pArray; 485 } 486 final Context context = new Context(); 487 encode(pArray, offset, length, context); 488 encode(pArray, offset, EOF, context); // Notify encoder of EOF. 489 final byte[] buf = new byte[context.pos - context.readPos]; 490 readResults(buf, 0, buf.length, context); 491 return buf; 492 } 493 494 // package protected for access from I/O streams 495 abstract void encode(byte[] pArray, int i, int length, Context context); 496 497 /** 498 * Encodes an Object using the Base-N algorithm. This method is provided in order to satisfy the requirements of 499 * the Encoder interface, and will throw an EncoderException if the supplied object is not of type byte[]. 500 * 501 * @param obj 502 * Object to encode 503 * @return An object (of type byte[]) containing the Base-N encoded data which corresponds to the byte[] supplied. 504 * @throws EncoderException 505 * if the parameter supplied is not of type byte[] 506 */ 507 @Override 508 public Object encode(final Object obj) throws EncoderException { 509 if (!(obj instanceof byte[])) { 510 throw new EncoderException("Parameter supplied to Base-N encode is not a byte[]"); 511 } 512 return encode((byte[]) obj); 513 } 514 515 /** 516 * Encodes a byte[] containing binary data, into a String containing characters in the appropriate alphabet. 517 * Uses UTF8 encoding. 518 * 519 * @param pArray a byte array containing binary data 520 * @return String containing only character data in the appropriate alphabet. 521 * @since 1.5 522 * This is a duplicate of {@link #encodeToString(byte[])}; it was merged during refactoring. 523 */ 524 public String encodeAsString(final byte[] pArray){ 525 return StringUtils.newStringUtf8(encode(pArray)); 526 } 527 528 /** 529 * Encodes a byte[] containing binary data, into a String containing characters in the Base-N alphabet. 530 * Uses UTF8 encoding. 531 * 532 * @param pArray 533 * a byte array containing binary data 534 * @return A String containing only Base-N character data 535 */ 536 public String encodeToString(final byte[] pArray) { 537 return StringUtils.newStringUtf8(encode(pArray)); 538 } 539 540 /** 541 * Ensure that the buffer has room for {@code size} bytes 542 * 543 * @param size minimum spare space required 544 * @param context the context to be used 545 * @return the buffer 546 */ 547 protected byte[] ensureBufferSize(final int size, final Context context){ 548 if (context.buffer == null) { 549 context.buffer = new byte[Math.max(size, getDefaultBufferSize())]; 550 context.pos = 0; 551 context.readPos = 0; 552 553 // Overflow-conscious: 554 // x + y > z == x + y - z > 0 555 } else if (context.pos + size - context.buffer.length > 0) { 556 return resizeBuffer(context, context.pos + size); 557 } 558 return context.buffer; 559 } 560 561 /** 562 * Returns the decoding behavior policy. 563 * 564 * <p> 565 * The default is lenient. If the decoding policy is strict, then decoding will raise an 566 * {@link IllegalArgumentException} if trailing bits are not part of a valid encoding. Decoding will compose 567 * trailing bits into 8-bit bytes and discard the remainder. 568 * </p> 569 * 570 * @return true if using strict decoding 571 * @since 1.15 572 */ 573 public CodecPolicy getCodecPolicy() { 574 return decodingPolicy; 575 } 576 577 /** 578 * Gets the default buffer size. Can be overridden. 579 * 580 * @return the default buffer size. 581 */ 582 protected int getDefaultBufferSize() { 583 return DEFAULT_BUFFER_SIZE; 584 } 585 586 /** 587 * Calculates the amount of space needed to encode the supplied array. 588 * 589 * @param pArray byte[] array which will later be encoded 590 * 591 * @return amount of space needed to encode the supplied array. 592 * Returns a long since a max-len array will require > Integer.MAX_VALUE 593 */ 594 public long getEncodedLength(final byte[] pArray) { 595 // Calculate non-chunked size - rounded up to allow for padding 596 // cast to long is needed to avoid possibility of overflow 597 long len = (pArray.length + unencodedBlockSize-1) / unencodedBlockSize * (long) encodedBlockSize; 598 if (lineLength > 0) { // We're using chunking 599 // Round up to nearest multiple 600 len += (len + lineLength-1) / lineLength * chunkSeparatorLength; 601 } 602 return len; 603 } 604 605 /** 606 * Returns true if this object has buffered data for reading. 607 * 608 * @param context the context to be used 609 * @return true if there is data still available for reading. 610 */ 611 boolean hasData(final Context context) { // package protected for access from I/O streams 612 return context.pos > context.readPos; 613 } 614 615 /** 616 * Returns whether or not the {@code octet} is in the current alphabet. 617 * Does not allow whitespace or pad. 618 * 619 * @param value The value to test 620 * 621 * @return {@code true} if the value is defined in the current alphabet, {@code false} otherwise. 622 */ 623 protected abstract boolean isInAlphabet(byte value); 624 625 /** 626 * Tests a given byte array to see if it contains only valid characters within the alphabet. 627 * The method optionally treats whitespace and pad as valid. 628 * 629 * @param arrayOctet byte array to test 630 * @param allowWSPad if {@code true}, then whitespace and PAD are also allowed 631 * 632 * @return {@code true} if all bytes are valid characters in the alphabet or if the byte array is empty; 633 * {@code false}, otherwise 634 */ 635 public boolean isInAlphabet(final byte[] arrayOctet, final boolean allowWSPad) { 636 for (final byte octet : arrayOctet) { 637 if (!isInAlphabet(octet) && 638 (!allowWSPad || octet != pad && !Character.isWhitespace(octet))) { 639 return false; 640 } 641 } 642 return true; 643 } 644 645 /** 646 * Tests a given String to see if it contains only valid characters within the alphabet. 647 * The method treats whitespace and PAD as valid. 648 * 649 * @param basen String to test 650 * @return {@code true} if all characters in the String are valid characters in the alphabet or if 651 * the String is empty; {@code false}, otherwise 652 * @see #isInAlphabet(byte[], boolean) 653 */ 654 public boolean isInAlphabet(final String basen) { 655 return isInAlphabet(StringUtils.getBytesUtf8(basen), true); 656 } 657 658 /** 659 * Returns true if decoding behavior is strict. Decoding will raise an {@link IllegalArgumentException} if trailing 660 * bits are not part of a valid encoding. 661 * 662 * <p> 663 * The default is false for lenient decoding. Decoding will compose trailing bits into 8-bit bytes and discard the 664 * remainder. 665 * </p> 666 * 667 * @return true if using strict decoding 668 * @since 1.15 669 */ 670 public boolean isStrictDecoding() { 671 return decodingPolicy == CodecPolicy.STRICT; 672 } 673 674 /** 675 * Extracts buffered data into the provided byte[] array, starting at position bPos, up to a maximum of bAvail 676 * bytes. Returns how many bytes were actually extracted. 677 * <p> 678 * Package private for access from I/O streams. 679 * </p> 680 * 681 * @param b 682 * byte[] array to extract the buffered data into. 683 * @param bPos 684 * position in byte[] array to start extraction at. 685 * @param bAvail 686 * amount of bytes we're allowed to extract. We may extract fewer (if fewer are available). 687 * @param context 688 * the context to be used 689 * @return The number of bytes successfully extracted into the provided byte[] array. 690 */ 691 int readResults(final byte[] b, final int bPos, final int bAvail, final Context context) { 692 if (hasData(context)) { 693 final int len = Math.min(available(context), bAvail); 694 System.arraycopy(context.buffer, context.readPos, b, bPos, len); 695 context.readPos += len; 696 if (!hasData(context)) { 697 // All data read. 698 // Reset position markers but do not set buffer to null to allow its reuse. 699 // hasData(context) will still return false, and this method will return 0 until 700 // more data is available, or -1 if EOF. 701 context.pos = context.readPos = 0; 702 } 703 return len; 704 } 705 return context.eof ? EOF : 0; 706 } 707 }