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