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 |