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