├── .gitignore ├── README.md ├── base64 ├── pom.xml └── src │ ├── main │ └── java │ │ ├── com │ │ └── joad │ │ │ └── jdz │ │ │ └── base64 │ │ │ ├── Base64Decoder.java │ │ │ ├── Base64Encoder.java │ │ │ ├── Base64Tables.java │ │ │ ├── scalar │ │ │ ├── Base64Scalar.java │ │ │ ├── RFC2045ScalarDecoder.java │ │ │ ├── RFC2045ScalarEncoder.java │ │ │ ├── RFC4648ScalarDecoder.java │ │ │ ├── RFC4648ScalarEncoder.java │ │ │ ├── RFC4648URLScalarDecoder.java │ │ │ ├── RFC4648URLScalarEncoder.java │ │ │ ├── ScalarDecoderVars.java │ │ │ └── ScalarUtils.java │ │ │ └── vector │ │ │ ├── Base64Vector.java │ │ │ ├── RFC2045VectorDecoder.java │ │ │ ├── RFC2045VectorEncoder.java │ │ │ ├── RFC4648URLVectorDecoder.java │ │ │ ├── RFC4648URLVectorEncoder.java │ │ │ ├── RFC4648VectorDecoder.java │ │ │ ├── RFC4648VectorEncoder.java │ │ │ ├── ScalarUtils.java │ │ │ ├── VectorDecoderVars.java │ │ │ ├── VectorEncoderVars.java │ │ │ ├── VectorSpeciesSelection.java │ │ │ └── VectorUtils.java │ │ └── module-info.java │ └── test │ └── java │ └── com │ └── joad │ └── jdz │ └── base64 │ ├── dev │ └── LengthFuzzTest.java │ ├── scalar │ ├── RFC2045FastScalarDecodeTest.java │ ├── RFC2045ScalarDecodeTest.java │ ├── RFC2045ScalarEncodeTest.java │ ├── RFC4648FastScalarDecodeTest.java │ ├── RFC4648ScalarDecodeTest.java │ ├── RFC4648ScalarEncodeTest.java │ ├── RFC4648URLFastScalarDecodeTest.java │ ├── RFC4648URLScalarDecodeTest.java │ └── RFC4648URLScalarEncodeTest.java │ └── vector │ ├── RFC2045FastVectorDecodeTest.java │ ├── RFC2045VectorDecodeTest.java │ ├── RFC2045VectorEncodeTest.java │ ├── RFC4648FastVectorDecodeTest.java │ ├── RFC4648URLFastVectorDecodeTest.java │ ├── RFC4648URLVectorDecodeTest.java │ ├── RFC4648URLVectorEncodeTest.java │ ├── RFC4648VectorDecodeTest.java │ └── RFC4648VectorEncodeTest.java ├── bench ├── pom.xml └── src │ └── main │ └── java │ └── com │ └── joad │ └── jdz │ └── bench │ ├── BenchmarkBase.java │ └── base64 │ ├── Base64DecodeBenchmark.java │ ├── Base64EncodeBenchmark.java │ ├── Base64MimeDecodeBenchmark.java │ └── Base64MimeEncodeBenchmark.java └── pom.xml /.gitignore: -------------------------------------------------------------------------------- 1 | */target 2 | *.flattened-pom.xml 3 | *.jar 4 | .vscode -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | This library contains Base64 encoders and decoders implemented using the incubator Vector API, as well as (slower) scalar implementations. This is the fastest Java-written Base64 library, with both the vector-based and scalar methods outperforming any other Java written library. These methods are faster than intrinsified java.util for RFC2045/MIME encoding/decoding, but slower for RFC4648 (see "java.util Intrinsification" and "Benchmark" sections). Requires Java 16 or higher. 2 | 3 | The encoding and decoding methods used for the Vector implementation, which can be found in VectorUtils.java, were heavily inspired by Wojciech Mula's articles, available here: 4 | 5 | http://0x80.pl/notesen/2016-01-12-sse-base64-encoding.html 6 | 7 | http://0x80.pl/notesen/2016-01-17-sse-base64-decoding.html 8 | 9 | # Usage 10 | As the Vector API is currently an incubator project, you will need to add the flag `--add-modules jdk.incubator.vector` to your java run command in order to use this library's vector methods. 11 | 12 | This library will be hosted on the central Maven repository once the Vector API is officially released. In the meanwhile this may only be used via local installation. 13 | 14 | ## Decoder/Encoder Instantiation 15 | For convenience, statically instantiated encoders/decoders can be accessed via the Base64Vector and Base64Scalar classes. You may also instantiate the indidual encoders/decoders yourself. 16 | 17 | ## Fast vs Normal Decode 18 | The fast decode methods assume that input is valid Base64 encoded according to the relevant spec. The normal decode methods do not, and handle invalid input explicitly. 19 | 20 | For RFC4648 decoding, the normal decode methods will throw an IllegalArgumentException in the case that an invalid byte is detected, with an exception message that includes the position of the first invalid byte. With RFC2045 decoding, the invalid input bytes are simply ignored (as long as total valid input length is divisible by 4). 21 | 22 | Using the fast decoding methods on invalid Base64 input will likely result in either an ArrayOutOfBoundsException due to invalid lookup table indices/invalid encoded input length, or in silently erroneous output. 23 | 24 | ## Vector Sizing 25 | Java should select the optimal vector size thanks to the use of the Vector API's SPECIES_PREFERRED. However, this may not select the optimal vector size on certain systems. 26 | 27 | The automated vector length selection can be overriden with the `jdz.vector.size` system property, which may be set to values 128, 256 or 512, representing the vector bit size. Selecting a value greater than what your CPU supports will make encoding/decoding 100-1000x slower. Experiment with this value if the library appears suspiciously slow. 28 | 29 | # java.util Intrinsification 30 | 31 | The java.util `encode` and `decode` methods rely on the use of an `encodeBlock` and `decodeBlock` method. These methods are both intrinsinc candidates since Java 11 and 16 respectively, meaning that the JVM can replace them with [an extremely fast SIMD method](https://github.com/openjdk/jdk/blob/a59c9b2ac277d6ff6be1700d91ff389f137e61ca/src/hotspot/cpu/x86/stubGenerator_x86_64.cpp#L6063). From my testing, these methods get intrinsifed after around 5000 calls in a JMH benchmark. So how many bytes need to be decoded in order to hit 5000 calls to these methods? 32 | 33 | If you're encoding or decoding according the RFC4648/RFC4648_URL spec, the intrinsic methods get called once for each call to `encode` or `decode`, which obviously allows for the fastest speeds as this minimizes callbacks into Java. Unfortunately, this means that the high level methods must be called ~5000 times before users benefit from intrinsification (*). If you are working with large arrays, this can take a while: 33 seconds of continuous encoding of 10MB arrays were required for the java.util encoding to intrinsify on my M1 mac. Similarly, if your application does not encode/decode 5000+ times in its lifetime, you will never benefit from this. If your application is encoding/decoding base64 sparsely rather than continuously, this might also impede intrinsification. 34 | 35 | The java.util RFC2045 methods are more consistent in their intrinsification and unaffected by input size. The encoding method will encode data in 76 byte blocks, before return to Java to write linebreak characters, while the decoding method will return to Java on each invalid base64 character (which includes linebreak characters every 76 bytes). Although this guarantees faster intrinsification due to the IntrinsicCandidate methods being called at least once per 76 bytes of input, this slows down the methods considerably, allowing the jdz vector implementation to be faster. 36 | 37 | Intrinsification also does not necessarily occur on every system or JVM. For example, the java.util methods were not intrinsified on an AWS m4.large or on my VMWare Ubuntu VM. As a result, jdz methods strongly outperform java.util on any such system, as java.util will be performing scalar encoding/decoding. 38 | 39 | # Benchmarks 40 | Benchmarks were all ran on Java 20 (Temurin), using non byte array allocating methods for all libraries supporting this. These are JMH benchmarks consisting of 3 forks of 5 warmups and 5 iterations. All benchmarks were measured for size of unencoded data, input size for encoding and output size for decoding. 41 | 42 | The overall theme in these benchmarks is that it is hard to predict relative performance of jdz vs java.util across different architectures. If your application is dependent on efficient base64 encoding, make sure to test your system yourself to determine what is fastest. 43 | 44 | jdz scalar methods are generally the best performing scalar methods for both specs and all architectures - however, these were mostly implemented for reference, and are only worth using over the vector/java.util methods if your cpu does not support 128+ bit vector sizes/does not intrinsify java.util. 45 | 46 | As a quick summary, the following table presents the generally fastest library for each spec/method combo. The overall benchmarks assume that java.util is intrinsified - if this is not the case, the jdz vector methods will always be fastest. 47 | 48 | | Spec/Method | Overall Encoding | Overall Fast Decoding | Overall Decoding | Scalar Encoding | Scalar Decoding | Scalar Fast Decoding | 49 | |-------------|----------------------|-----------------------|------------------|-----------------|-----------------|----------------------| 50 | | RFC4648 | java.util | java.util | java.util | jdz scalar | jdz scalar | jdz scalar | 51 | | RFC2045 | jdz vector/java.util | jdz vector | jdz vector | jdz scalar | jdz scalar/java.util | jdz scalar | 52 | 53 | ## Throughput 54 | These benchmarks represent MB/s throughput of encoding/decoding methods given 1MB inputs. java.util scalar throughput was meansured by disabling intrinsification. 55 | 56 | ### RFC4648 57 | #### RFC4648 Encoding 58 | | | java.util scalar | java.util intrinsic | jdz vector | jdz scalar | migBase64 | iharder | Apache Commons | 59 | |---------------------------------|------------------|---------------------|------------|------------|-----------|----------|----------------| 60 | | Apple M1 (128 bits) | 1707MB/s | 16126MB/s | 6277MB/s | 2845MB/s | 1793MB/s | 1560MB/s | 165MB/s | 61 | | Vs Java Scalar | 1.00x | 9.45x | 3.68x | 1.67x | 1.05x | 0.91x | 0.10x | 62 | | vs Java Intrinsic | 0.11x | 1.00x | 0.39x | 0.18x | 0.11x | 0.10x | 0.01x | 63 | | m4.large (256 bits) | 886MB/s | N/A | 1515MB/s | 1171MB/s | 609MB/s | 567MB/s | 133MB/s | 64 | | vs Java Scalar | 1.0x | N/A | 1.70x | 1.32x | 0.69x | 0.64x | 0.15x | 65 | | vs Java Intrinsic | N/A | N/A | N/A | N/A | N/A | N/A | N/A | 66 | | m6i.large | 1441MB/s | 12644MB/s | 10891MB/s | 2018MB/s | 954MB/s | 984MB/s | 178MB/s | 67 | | vs Java Scalar | 1.0x | 8.77x | 7.56x | 1.40x | 0.66x | 0.68x | 0.12x | 68 | | vs Java Intrinsic | 0.11x | 1.0x | 0.86x | 0.16x | 0.06x | 0.08x | 0.01x | 69 | 70 | ### RFC4648 Decoding 71 | | | java.util scalar | java.util intrinsic | jdz vector | jdz vector fast | jdz scalar | jdz scalar fast | migBase64 | migBase64 fast | iharder | Apache Commons | 72 | |---------------------------------|------------------|---------------------|------------|-----------------|------------|-----------------|-----------|----------------|---------|----------------| 73 | | Apple M1 (128 bits) | 1478MB/s | 9149MB/s | 4613MB/s | 6801MB/s | 2503MB/s | 2777MB/s | 637MB/s | 1096MB/s | 323MB/s | 266MB/s | 74 | | Vs Java Scalar | 1.00x | 6.19x | 3.12x | 4.60x | 1.69x | 1.88x | 0.43x | 0.74x | 0.22x | 0.18x | 75 | | vs Java Intrinsic | 0.17x | 1.00x | 0.50x | 0.74x | 0.27x | 0.30x | 0.07x | 0.12x | 0.04x | 0.03x | 76 | | m4.large (256 bits) | 799MB/s | N/A | 1453MB/s | 2434MB/s | 1105MB/s | 1066MB/s | 289MB/s | 479MB/s | 139MB/s | 120MB/s | 77 | | vs Java Scalar | 1.00x | N/A | 1.82x | 0.30x | 1.38x | 1.33x | 0.36x | 0.60x | 0.17x | 0.20x | 78 | | vs Java Intrinsic | N/A | N/A | N/A | N/A | N/A | N/A | N/A | N/A | N/A | N/A | 79 | | m6i.large | 1360MB/s | 14884MB/s | 6585MB/s | 9258MB/s | 1270MB/s | 1351MB/s | 363MB/s | 791MB/s | 218MB/s | 194MB/s | 80 | | vs Java Scalar | 1.00x | 10.20x | 4.85x | 6.80x | 0.93x | 0.99x | 0.26x | 0.58x | 0.16x | 0.14x | 81 | | vs Java Intrinsic | 0.09x | 1.00x | 0.44x | 0.62x | 0.09x | 0.09x | 0.02x | 0.05x | 0.01x | 0.01x | 82 | 83 | ### RFC2045 84 | #### RFC2045 Encoding 85 | | | java.util scalar | java.util intrinsic | jdz vector | jdz scalar | migBase64 | iharder | Apache Commons | 86 | |---------------------------------|------------------|---------------------|------------|------------|-----------|----------|----------------| 87 | | Apple M1 (128 bits) | 1466MB/s | 5721MB/s | 5814MB/s | 2704MB/s | 1572MB/s | 1540MB/s | 171MB/s | 88 | | Vs Java Scalar | 1.0x | 3.90x | 3.97x | 1.84x | 1.07x | 1.05x | 0.12x | 89 | | vs Java Intrinsic | 0.26x | 1.0x | 1.03x | 0.48x | 0.28x | 0.27x | 0.03x | 90 | | m4.large (256 bits) | 686MB/s | N/A | 1192MB/s | 1087MB/s | 464MB/s | 494MB/s | 125MB/s | 91 | | vs Java Scalar | 1.0x | N/A | 1.74x | 1.58x | 0.67x | 0.72x | 0.18x | 92 | | vs Java Intrinsic | N/A | N/A | N/A | N/A | N/A | N/A | N/A | 93 | | m6i.large | 1129MB/s | 3526MB/s | 5722MB/s | 1859MB/s | 861MB/s | 872MB/s | 178MB/s | 94 | | vs Java Scalar | 1.0x | 3.12x | 5.07x | 1.65x | 0.76x | 0.77x | 0.16x | 95 | | vs Java Intrinsic | 0.32x | 1.0x | 1.622x | 0.52x | 0.24x | 0.25 | 0.05x | 96 | 97 | #### RFC2045 Decoding 98 | | | java.util scalar | java.util intrinsic | jdz vector | jdz vector fast | jdz scalar | jdz scalar fast | migBase64 | migBase64 fast | iharder | Apache Commons | 99 | |---------------------------------|------------------|---------------------|------------|-----------------|------------|-----------------|-----------|----------------|---------|----------------| 100 | | Apple M1 (128 bits) | 716MB/s | 919MB/s | 1805MB/s | 6685MB/s | 757MB/s | 2728MB/s | 390MB/s | 928MB/s | 305MB/s | 255MB/s | 101 | | Vs Java Scalar | 1.00x | 1.28x | 2.52x | 9.33x | 1.06x | 3.81x | 0.54x | 1.29x | 0.42x | 0.35x | 102 | | vs Java Intrinsic | 0.78x | 1.00x | 1.96x | 7.27x | 0.82x | 2.97x | 0.42x | 1.01x | 0.33x | 0.28x | 103 | | m4.large (256 bits) | 433MB/s | N/A | 731MB/s | 1809MB/s | 412MB/s | 1157MB/s | 197MB/s | 479MB/s | 138MB/s | 120MB/s | 104 | | vs Java Scalar | 1.00x | N/A | 1.67x | 4.17x | 0.95x | 2.67x | 0.45x | 1.10x | 0.32x | 0.28x | 105 | | vs Java Intrinsic | N/A | N/A | N/A | N/A | N/A | N/A | N/A | N/A | N/A | N/A | 106 | | m6i.large | 652MB/s | 761MB/s | 1729MB/s | 5077MB/s | 583MB/s | 1351/MB/s | 393MB/s | 791MB/s | 218MB/s | 195MB/s | 107 | | vs Java Scalar | 1.00x | 1.17x | 2.65x | 7.79x | 0.89x | 2.07x | 0.60x | 1.21x | 0.33x | 0.30x | 108 | | vs Java Intrinsic | 0.86x | 1.00x | 2.27x | 6.77x | 0.77x | 1.77x | 0.52x | 1.04x | 0.29x | 0.26x | 109 | 110 | ## Vector Sizing 111 | This benchmark measures different vector sizes on a system supporting up to 512 bits (m6i.large). As expected, the largest supported vector size is fastest, and this is naturally the one automatically selected via use of SPECIES_PREFERRED. 112 | 113 | | Method/Vector Size | 128 bits | 256 bits | 512 bits | 114 | |--------------------|----------|----------|-----------| 115 | | RFC4648 encode | 4000MB/s | 6733MB/s | 11157MB/s | 116 | | RFC4648 decode | 2457MB/s | 3945MB/s | 5491MB/s | 117 | | RFC4648 decodeFast | 3517MB/s | 5646MB/s | 9128MB/s | 118 | | RFC2045 encode | 3099MB/s | 4926MB/s | 5724MB/s | 119 | | RFC2045 decode | 1150MB/s | 1482MB/s | 1730MB/s | 120 | | RFC2045 decodeFast | 2965MB/s | 4224MB/s | 6733MB/s | 121 | 122 | ## Unencoded Length Benchmarks 123 | The following benchmarks measure the time per operation to encode/decode a certain unencoded length - lower is better. These were all carried out on an M1 mac using 128 bit vectors. 124 | 125 | ### RFC4648 126 | 127 | #### RFC4648 Encoding 128 | 129 | | Method/Unencoded Length | 10B | 100B | 1KB | 1MB | 10MB | 100MB | 130 | |-------------------|------|------|-------|-------|--------|---------| 131 | | jdz-scalar encode | 11ns | 48ns | 343ns | 346µs | 3486µs | 34.88ms | 132 | | jdz-vector encode | 11ns | 40ns | 195ns | 142µs | 1447µs | 14.31ms | 133 | | java.util encode | 11ns | 15ns | 73ns | 60µs | 5784µs | 57.81ms | 134 | | migBase64 encode | 22ns | 64ns | 562ns | 545µs | 5498µs | 55.12ms | 135 | 136 | #### RFC4648 Decoding 137 | | Method/Unencoded Length | 10B | 100B | 1KB | 1MB | 10MB | 100MB 138 | |-----------------------|------|-------|--------|--------|---------|--------- 139 | | jdz-scalar decode | 11ns | 55ns | 409ns | 405µs | 4079µs | 40.76ms | 140 | | jdz-scalar decodeFast | 11ns | 52ns | 371ns | 364µs | 3673µs | 36.79ms | 141 | | jdz-vector decode | 12ns | 52ns | 299ns | 205µs | 2088µs | 20.90ms | 142 | | jdz-vector decodeFast | 11ns | 43ns | 170ns | 139µs | 1409µs | 14.02ms | 143 | | java.util decode | 14ns | 49ns | 138ns | 109µs | 6727µs | 66.92ms | 144 | | migBase64 decode | 30ns | 157ns | 1472ns | 1554µs | 15673µs | 171.8ms | 145 | | migBase64 decodeFast | 28ns | 104ns | 955ns | 894µs | 9000µs | 98.96ms | 146 | 147 | As only 5 warmups were performed, we can see java.util methods cease to be intrinsified for 10MB+ data (see "java.util Intrinsification"). 148 | 149 | ### RFC2045 (MIME) 150 | 151 | #### RFC2045 Encoding 152 | | Method/Unencoded Length | 10B | 100B | 1KB | 1MB | 10MB | 100MB | 153 | |-------------------|------|------|-------|-------|--------|---------| 154 | | jdz-scalar encode | 10ns | 50ns | 349ns | 358µs | 3799us | 39.80ms | 155 | | jdz-vector encode | 10ns | 38ns | 179ns | 169µs | 1887µs | 20.78ms | 156 | | java.util encode | 12ns | 28ns | 181ns | 171µs | 1767µs | 17.30ms | 157 | | migBase64 encode | 16ns | 72ns | 644ns | 620µs | 6239µs | 62.39ms | 158 | 159 | #### RFC2045 Decoding 160 | | Method/Unencoded Length | 10B | 100B | 1KB | 1MB | 10MB | 100MB | 161 | |-----------------------|-------|-------|---------|--------|---------|-------| 162 | | jdz-scalar decode | 29ns | 247ns | 2.64µs | 1608µs | 16.12ms | 133.60ms | 163 | | jdz-scalar decodeFast | 22ns | 49ns | 376ns | 358µs | 3.569ms | 36.06ms | 164 | | jdz-vector decode | 29ns | 61ns | 575ns | 564µs | 5.698ms | 57.258ms | 165 | | jdz-vector decodeFast | 23ns | 38ns | 167ns | 151µs | 1.528ms | 14.77ms | 166 | | java.util decode | 29ns | 132ns | 1284ns | 1087µs | 10.92ms | 135.35ms | 167 | | migBase64 decode | 408ns | 306ns | 2.89µs | 2383µs | 24.11ms | 286.59ms | 168 | | migBase64 decodeFast | 29ns | 105ns | 987ns | 1052µs | 10.72ms | 125.53ms | 169 | 170 | -------------------------------------------------------------------------------- /base64/pom.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 4.0.0 5 | 6 | com.joad.jdz 7 | jdz-parent 8 | 1.0 9 | ../pom.xml 10 | 11 | 12 | jdz-base64 13 | 14 | jdz base64 15 | 16 | 17 | 18 | junit 19 | junit 20 | ${junit.version} 21 | 22 | 23 | 24 | -------------------------------------------------------------------------------- /base64/src/main/java/com/joad/jdz/base64/Base64Decoder.java: -------------------------------------------------------------------------------- 1 | package com.joad.jdz.base64; 2 | 3 | import java.nio.charset.StandardCharsets; 4 | 5 | public abstract class Base64Decoder { 6 | 7 | /** 8 | * Returns a newly allocated byte[] representing base64 decoded source. 9 | * 10 | * @param src the data to be decoded 11 | * 12 | * @return the decoded data 13 | */ 14 | public byte[] decode(byte[] src) { 15 | int pad = getPadLength(src); 16 | int dl = getDecodedLength(src, pad); 17 | 18 | int sl = src.length - pad; 19 | 20 | byte[] dst = new byte[dl]; 21 | 22 | decode(src, dst, sl, dl); 23 | 24 | return dst; 25 | } 26 | 27 | /** 28 | * Decodes base64 data from src to dst. 29 | * 30 | * @param src the data to be decoded 31 | * @param dst the byte array to write to 32 | * 33 | * @return the decoded data 34 | */ 35 | public int decode(byte[] src, byte[] dst) { 36 | int pad = getPadLength(src); 37 | int dl = getDecodedLength(src, pad); 38 | 39 | int sl = src.length - pad; 40 | 41 | return decode(src, dst, sl, dl); 42 | } 43 | 44 | /** 45 | * Returns a newly allocated byte[] representing base64 decoded source. 46 | * Assumes that input is valid. 47 | * 48 | * @param src the data to be decoded 49 | * 50 | * @return the decoded data 51 | */ 52 | public byte[] decodeFast(byte[] src) { 53 | int pad = getPadLength(src); 54 | int dl = getDecodedLengthFast(src, pad); 55 | 56 | int sl = src.length - pad; 57 | 58 | byte[] dst = new byte[dl]; 59 | 60 | decodeFast(src, dst, sl, dl); 61 | 62 | return dst; 63 | } 64 | 65 | /** 66 | * Decodes base64 data from src to dst. 67 | * Assumes that input is valid. 68 | * 69 | * @param src the data to be decoded 70 | * @param dst the byte array to write to 71 | * 72 | * @return the decoded data 73 | */ 74 | public int decodeFast(byte[] src, byte[] dst) { 75 | int pad = getPadLength(src); 76 | int dl = getDecodedLengthFast(src, pad); 77 | 78 | int sl = src.length - pad; 79 | 80 | return decodeFast(src, dst, sl, dl); 81 | } 82 | 83 | /** 84 | * Calculates decoded length for src 85 | * 86 | * @param src the data to be decoded 87 | * 88 | * @return the decoded length 89 | */ 90 | public int getDecodedLength(byte[] src) { 91 | int pad = getPadLength(src); 92 | 93 | return getDecodedLength(src, pad); 94 | } 95 | 96 | protected abstract int getDecodedLength(byte[] src, int pad); 97 | 98 | /** 99 | * Calculates decoded length for src 100 | * Assumes that input is valid - works for standard and url encoding 101 | * 102 | * @param src the data to be decoded 103 | * 104 | * @return the decoded length 105 | */ 106 | public int getDecodedLengthFast(byte[] src) { 107 | int pad = getPadLength(src); 108 | 109 | return getDecodedLengthFast(src, pad); 110 | } 111 | 112 | protected abstract int getDecodedLengthFast(byte[] src, int pad); 113 | 114 | /** 115 | * Returns a newly allocated byte[] representing base64 decoded source. 116 | * 117 | * @param src the data to be decoded 118 | * 119 | * @return the decoded data 120 | */ 121 | public byte[] decode(String src) { 122 | return decode(src.getBytes(StandardCharsets.ISO_8859_1)); 123 | } 124 | 125 | /** 126 | * Decodes base64 data from src to dst. 127 | * 128 | * @param src the data to be decoded 129 | * @param dst the byte array to write to 130 | * 131 | * @return the decoded data 132 | */ 133 | public int decode(String src, byte[] dst) { 134 | return decode(src.getBytes(StandardCharsets.ISO_8859_1), dst); 135 | } 136 | 137 | private int getPadLength(byte[] src) { 138 | int sl = src.length; 139 | 140 | return sl > 0 && src[sl - 1] == '=' ? (src[sl - 2] == '=' ? 2 : 1) : 0; 141 | } 142 | 143 | protected abstract int decode(byte[] src, byte[] dst, int sl, int dl); 144 | 145 | protected abstract int decodeFast(byte[] src, byte[] dst, int sl, int dl); 146 | } 147 | -------------------------------------------------------------------------------- /base64/src/main/java/com/joad/jdz/base64/Base64Encoder.java: -------------------------------------------------------------------------------- 1 | package com.joad.jdz.base64; 2 | 3 | import java.nio.charset.StandardCharsets; 4 | 5 | public abstract class Base64Encoder { 6 | 7 | /** 8 | * Returns a newly allocated byte[] representing base64 encoded source. 9 | * 10 | * @param src the data to be encoded 11 | * 12 | * @return the base64 encoded data 13 | */ 14 | public byte[] encode(byte[] src) { 15 | int dl = getEncodedLength(src); 16 | 17 | byte[] dst = new byte[dl]; 18 | 19 | encode(src, dst); 20 | 21 | return dst; 22 | } 23 | 24 | /** 25 | * Writes base64 encoded data from src to dst. 26 | * 27 | * @param src the data to be encoded 28 | * @param dst the byte array to write to 29 | * 30 | * @return the length of encoded data 31 | */ 32 | public abstract int encode(byte[] src, byte[] dst); 33 | 34 | /** 35 | * Calculates encoded length for src 36 | * 37 | * @param src the data to be encoded 38 | * 39 | * @return the encoded length 40 | */ 41 | public abstract int getEncodedLength(byte[] src); 42 | 43 | /** 44 | * Returns a newly allocated byte[] representing base64 encoded source. 45 | * 46 | * @param src the data to be encoded 47 | * 48 | * @return the length of encoded data 49 | */ 50 | public byte[] encode(String src) { 51 | return encode(src.getBytes(StandardCharsets.ISO_8859_1)); 52 | } 53 | 54 | /** 55 | * Writes base64 encoded data from src to dst. 56 | * 57 | * @param src the data to be encoded 58 | * @param dst the byte array to write to 59 | * 60 | * @return the base64 encoded data 61 | */ 62 | 63 | public int encode(String src, byte[] dst) { 64 | return encode(src.getBytes(StandardCharsets.ISO_8859_1), dst); 65 | } 66 | } 67 | -------------------------------------------------------------------------------- /base64/src/main/java/com/joad/jdz/base64/Base64Tables.java: -------------------------------------------------------------------------------- 1 | package com.joad.jdz.base64; 2 | 3 | public class Base64Tables { 4 | public static final char[] BASE64 = { 5 | 'A', 'B', 'C', 'D', 'E', 'F', 'G', 'H', 'I', 'J', 'K', 'L', 'M', 6 | 'N', 'O', 'P', 'Q', 'R', 'S', 'T', 'U', 'V', 'W', 'X', 'Y', 'Z', 7 | 'a', 'b', 'c', 'd', 'e', 'f', 'g', 'h', 'i', 'j', 'k', 'l', 'm', 8 | 'n', 'o', 'p', 'q', 'r', 's', 't', 'u', 'v', 'w', 'x', 'y', 'z', 9 | '0', '1', '2', '3', '4', '5', '6', '7', '8', '9', '+', '/' 10 | }; 11 | 12 | public static final char[] BASE64_URL = { 13 | 'A', 'B', 'C', 'D', 'E', 'F', 'G', 'H', 'I', 'J', 'K', 'L', 'M', 14 | 'N', 'O', 'P', 'Q', 'R', 'S', 'T', 'U', 'V', 'W', 'X', 'Y', 'Z', 15 | 'a', 'b', 'c', 'd', 'e', 'f', 'g', 'h', 'i', 'j', 'k', 'l', 'm', 16 | 'n', 'o', 'p', 'q', 'r', 's', 't', 'u', 'v', 'w', 'x', 'y', 'z', 17 | '0', '1', '2', '3', '4', '5', '6', '7', '8', '9', '-', '_' 18 | }; 19 | } 20 | -------------------------------------------------------------------------------- /base64/src/main/java/com/joad/jdz/base64/scalar/Base64Scalar.java: -------------------------------------------------------------------------------- 1 | package com.joad.jdz.base64.scalar; 2 | 3 | import com.joad.jdz.base64.Base64Decoder; 4 | import com.joad.jdz.base64.Base64Encoder; 5 | 6 | public class Base64Scalar { 7 | private static final Base64Encoder RFC4648_ENCODER = new RFC4648ScalarEncoder(); 8 | 9 | private static final Base64Encoder RFC4648URL_ENCODER = new RFC4648URLScalarEncoder(); 10 | 11 | private static final Base64Encoder RFC2045_ENCODER = new RFC2045ScalarEncoder(); 12 | 13 | private static final Base64Decoder RFC4648_DECODER = new RFC4648ScalarDecoder(); 14 | 15 | private static final Base64Decoder RFC4648URL_DECODER = new RFC4648URLScalarDecoder(); 16 | 17 | private static final Base64Decoder RFC2045_DECODER = new RFC2045ScalarDecoder(); 18 | 19 | /** 20 | * Encoder for the RFC4648 Base64 spec 21 | * 22 | * @return An RFC4648 Base64 Encoder 23 | */ 24 | public static Base64Encoder getEncoder() { 25 | return RFC4648_ENCODER; 26 | } 27 | 28 | /** 29 | * Encoder for the RFC4648URL Base64 spec 30 | * 31 | * @return An RFC4648 Base64 Encoder 32 | */ 33 | public static Base64Encoder getUrlEncoder() { 34 | return RFC4648URL_ENCODER; 35 | } 36 | 37 | /** 38 | * Encoder for the RFC2045 Base64 spec 39 | * 40 | * @return An RFC42045 Base64 encoder 41 | */ 42 | public static Base64Encoder getMimeEncoder() { 43 | return RFC2045_ENCODER; 44 | } 45 | 46 | /** 47 | * Decoder for the RFC4648 Base64 spec 48 | * 49 | * @return An RFC4648 Base64 decoder 50 | */ 51 | public static Base64Decoder getDecoder() { 52 | return RFC4648_DECODER; 53 | } 54 | 55 | /** 56 | * Decoder for the RFC4648 URL Base64 spec 57 | * 58 | * @return An RFC4648 URL Base64 decoder 59 | */ 60 | public static Base64Decoder getUrlDecoder() { 61 | return RFC4648URL_DECODER; 62 | } 63 | 64 | /** 65 | * Decoder for the RFC2045 Base64 spec 66 | * 67 | * @return An RFC2045 Base64 fast encoder 68 | */ 69 | public static Base64Decoder getMimeDecoder() { 70 | return RFC2045_DECODER; 71 | } 72 | } 73 | -------------------------------------------------------------------------------- /base64/src/main/java/com/joad/jdz/base64/scalar/RFC2045ScalarDecoder.java: -------------------------------------------------------------------------------- 1 | package com.joad.jdz.base64.scalar; 2 | 3 | import static com.joad.jdz.base64.scalar.ScalarUtils.*; 4 | import static com.joad.jdz.base64.Base64Tables.*; 5 | import static com.joad.jdz.base64.scalar.ScalarDecoderVars.*; 6 | 7 | import java.util.Arrays; 8 | import com.joad.jdz.base64.Base64Decoder; 9 | 10 | public class RFC2045ScalarDecoder extends Base64Decoder { 11 | private static final int[] SIMPLE_LOOKUP = new int[256]; 12 | 13 | static { 14 | Arrays.fill(SIMPLE_LOOKUP, -1); 15 | for (int i = 0; i < 64; i++) 16 | SIMPLE_LOOKUP[BASE64[i]] = i; 17 | } 18 | 19 | @Override 20 | protected int decode(byte[] src, byte[] dst, int sl, int dl) { 21 | int sp = 0; 22 | int dp = 0; 23 | 24 | while (dp < dl - 3) { 25 | int bits = LOOKUP[0][src[sp++]] 26 | | LOOKUP[1][src[sp++]] 27 | | LOOKUP[2][src[sp++]] 28 | | LOOKUP[3][src[sp++]]; 29 | 30 | if (bits > VALID_MAX) { 31 | sp -= 4; 32 | 33 | bits = LOOKUP[0][src[sp++]]; 34 | 35 | if (bits > VALID_MAX) 36 | continue; 37 | 38 | for (int i = 1; i < 4;) { 39 | int b = LOOKUP[i][src[sp++]]; 40 | 41 | if (b < VALID_MAX) { 42 | bits |= b; 43 | i++; 44 | } 45 | } 46 | } 47 | 48 | INT_LE.set(dst, dp, bits); 49 | 50 | dp += 3; 51 | } 52 | 53 | int remaining = dl - dp; 54 | 55 | return switch (remaining) { 56 | case 3 -> decodeLastThreeDestBytesMime(src, dst, LOOKUP, sp, dp); 57 | case 2 -> decodeLastTwoDestBytesMime(src, dst, LOOKUP, sp, dp); 58 | case 1 -> decodeLastDestByteMime(src, dst, LOOKUP, sp, dp); 59 | default -> dp; 60 | }; 61 | } 62 | 63 | @Override 64 | protected int decodeFast(byte[] src, byte[] dst, int sl, int dl) { 65 | int sp = 0; 66 | int dp = 0; 67 | 68 | for (; dp < dl - 57; sp += 78, dp += 57) { 69 | decodeEightBytes(src, dst, LOOKUP, sp, dp); 70 | decodeEightBytes(src, dst, LOOKUP, sp + 8, dp + 6); 71 | decodeEightBytes(src, dst, LOOKUP, sp + 16, dp + 12); 72 | decodeEightBytes(src, dst, LOOKUP, sp + 24, dp + 18); 73 | decodeEightBytes(src, dst, LOOKUP, sp + 32, dp + 24); 74 | decodeEightBytes(src, dst, LOOKUP, sp + 40, dp + 30); 75 | decodeEightBytes(src, dst, LOOKUP, sp + 48, dp + 36); 76 | decodeEightBytes(src, dst, LOOKUP, sp + 56, dp + 42); 77 | decodeEightBytes(src, dst, LOOKUP, sp + 64, dp + 48); 78 | decodeFourBytes(src, dst, LOOKUP, sp + 72, dp + 54); 79 | } 80 | 81 | for (; sp < sl - 4; sp += 4, dp += 3) { 82 | decodeFourBytes(src, dst, LOOKUP, sp, dp); 83 | } 84 | 85 | int remaining = sl - sp; 86 | 87 | return switch (remaining) { 88 | case 4 -> decodeLastFourBytes(src, dst, LOOKUP, sp, dp); 89 | case 3 -> decodeLastThreeBytes(src, dst, LOOKUP, sp, dp); 90 | case 2 -> decodeLastTwoBytes(src, dst, LOOKUP, sp, dp); 91 | default -> dp; 92 | }; 93 | } 94 | 95 | @Override 96 | protected int getDecodedLength(byte[] src, int pad) { 97 | int sl = src.length; 98 | 99 | int invalid = 0; 100 | 101 | for (int sp = 0; sp < sl - pad; sp++) { 102 | if (SIMPLE_LOOKUP[src[sp]] < 0) 103 | invalid++; 104 | } 105 | 106 | int vsl = sl - invalid; 107 | 108 | if ((vsl & MOD4) != 0) 109 | throw new IllegalArgumentException("Number of valid input bytes not divisible by 4"); 110 | 111 | return vsl / 4 * 3 - pad; 112 | } 113 | 114 | @Override 115 | protected int getDecodedLengthFast(byte[] src, int pad) { 116 | int sl = src.length; 117 | 118 | int vsl = sl - (sl/78) * 2; 119 | 120 | if ((vsl & MOD4) != 0) 121 | throw new IllegalArgumentException("Number of valid input bytes not divisible by 4"); 122 | 123 | return vsl / 4 * 3 - pad; 124 | } 125 | } 126 | -------------------------------------------------------------------------------- /base64/src/main/java/com/joad/jdz/base64/scalar/RFC2045ScalarEncoder.java: -------------------------------------------------------------------------------- 1 | package com.joad.jdz.base64.scalar; 2 | 3 | import static com.joad.jdz.base64.Base64Tables.*; 4 | import static com.joad.jdz.base64.scalar.ScalarUtils.*; 5 | 6 | import com.joad.jdz.base64.Base64Encoder; 7 | 8 | public class RFC2045ScalarEncoder extends Base64Encoder { 9 | 10 | @Override 11 | public int encode(byte[] src, byte[] dst) { 12 | int sl = src.length; 13 | 14 | int sp = 0; 15 | int dp = 0; 16 | 17 | for (int ldp = 76; ldp < dst.length; ldp += 78) { 18 | dst[ldp] = '\r'; 19 | dst[ldp+1] = '\n'; 20 | } 21 | 22 | for (; sp < src.length - 57; sp += 57, dp += 78) { 23 | encodeSixBytes(src, dst, BASE64, sp, dp); 24 | encodeSixBytes(src, dst, BASE64, sp + 6, dp + 8); 25 | encodeSixBytes(src, dst, BASE64, sp + 12, dp + 16); 26 | encodeSixBytes(src, dst, BASE64, sp + 18, dp + 24); 27 | encodeSixBytes(src, dst, BASE64, sp + 24, dp + 32); 28 | encodeSixBytes(src, dst, BASE64, sp + 30, dp + 40); 29 | encodeSixBytes(src, dst, BASE64, sp + 36, dp + 48); 30 | encodeSixBytes(src, dst, BASE64, sp + 42, dp + 56); 31 | encodeSixBytes(src, dst, BASE64, sp + 48, dp + 64); 32 | encodeThreeBytes(src, dst, BASE64, sp + 54, dp + 72); 33 | } 34 | 35 | for (; sp < src.length - 3; sp += 3, dp += 4) { 36 | encodeThreeBytes(src, dst, BASE64, sp, dp); 37 | } 38 | 39 | int remaining = sl - sp; 40 | 41 | return switch (remaining) { 42 | case 3 -> encodeLastThreeBytes(src, dst, BASE64, sp, dp); 43 | case 2 -> encodeLastTwoBytes(src, dst, BASE64, sp, dp); 44 | case 1 -> encodeLastByte(src, dst, BASE64, sp, dp); 45 | default -> dp; 46 | }; 47 | } 48 | 49 | @Override 50 | public int getEncodedLength(byte[] src) { 51 | int rawLen = Math.multiplyExact(4, (Math.addExact(src.length, 2) / 3)); 52 | 53 | return rawLen + ((rawLen - 1)/76) * 2; 54 | } 55 | } -------------------------------------------------------------------------------- /base64/src/main/java/com/joad/jdz/base64/scalar/RFC4648ScalarDecoder.java: -------------------------------------------------------------------------------- 1 | package com.joad.jdz.base64.scalar; 2 | 3 | import static com.joad.jdz.base64.scalar.ScalarDecoderVars.*; 4 | import static com.joad.jdz.base64.scalar.ScalarUtils.*; 5 | 6 | import com.joad.jdz.base64.Base64Decoder; 7 | 8 | public class RFC4648ScalarDecoder extends Base64Decoder { 9 | 10 | @Override 11 | protected int decode(byte[] src, byte[] dst, int sl, int dl) { 12 | int sp = 0; 13 | int dp = 0; 14 | 15 | for (; dp < dl - 57; sp += 76, dp += 57) { 16 | decodeEightBytesValidating(src, dst, LOOKUP, sp, dp); 17 | decodeEightBytesValidating(src, dst, LOOKUP, sp + 8, dp + 6); 18 | decodeEightBytesValidating(src, dst, LOOKUP, sp + 16, dp + 12); 19 | decodeEightBytesValidating(src, dst, LOOKUP, sp + 24, dp + 18); 20 | decodeEightBytesValidating(src, dst, LOOKUP, sp + 32, dp + 24); 21 | decodeEightBytesValidating(src, dst, LOOKUP, sp + 40, dp + 30); 22 | decodeEightBytesValidating(src, dst, LOOKUP, sp + 48, dp + 36); 23 | decodeEightBytesValidating(src, dst, LOOKUP, sp + 56, dp + 42); 24 | decodeEightBytesValidating(src, dst, LOOKUP, sp + 64, dp + 48); 25 | decodeFourBytesValidating(src, dst, LOOKUP, sp + 72, dp + 54); 26 | } 27 | 28 | for (; sp < sl - 4; sp += 4, dp += 3) { 29 | decodeFourBytesValidating(src, dst, LOOKUP, sp, dp); 30 | } 31 | 32 | int remaining = sl - sp; 33 | 34 | return switch (remaining) { 35 | case 4 -> decodeLastFourBytesValidating(src, dst, LOOKUP, sp, dp); 36 | case 3 -> decodeLastThreeBytesValidating(src, dst, LOOKUP, sp, dp); 37 | case 2 -> decodeLastTwoBytesValidating(src, dst, LOOKUP, sp, dp); 38 | default -> dp; 39 | }; 40 | } 41 | 42 | @Override 43 | protected int decodeFast(byte[] src, byte[] dst, int sl, int dl) { 44 | int sp = 0; 45 | int dp = 0; 46 | 47 | for (; dp < dl - 57; sp += 76, dp += 57) { 48 | decodeEightBytes(src, dst, LOOKUP, sp, dp); 49 | decodeEightBytes(src, dst, LOOKUP, sp + 8, dp + 6); 50 | decodeEightBytes(src, dst, LOOKUP, sp + 16, dp + 12); 51 | decodeEightBytes(src, dst, LOOKUP, sp + 24, dp + 18); 52 | decodeEightBytes(src, dst, LOOKUP, sp + 32, dp + 24); 53 | decodeEightBytes(src, dst, LOOKUP, sp + 40, dp + 30); 54 | decodeEightBytes(src, dst, LOOKUP, sp + 48, dp + 36); 55 | decodeEightBytes(src, dst, LOOKUP, sp + 56, dp + 42); 56 | decodeEightBytes(src, dst, LOOKUP, sp + 64, dp + 48); 57 | decodeFourBytes(src, dst, LOOKUP, sp + 72, dp + 54); 58 | } 59 | 60 | for (; sp < sl - 4; sp += 4, dp += 3) { 61 | decodeFourBytes(src, dst, LOOKUP, sp, dp); 62 | } 63 | 64 | int remaining = sl - sp; 65 | 66 | return switch (remaining) { 67 | case 4 -> decodeLastFourBytes(src, dst, LOOKUP, sp, dp); 68 | case 3 -> decodeLastThreeBytes(src, dst, LOOKUP, sp, dp); 69 | case 2 -> decodeLastTwoBytes(src, dst, LOOKUP, sp, dp); 70 | default -> dp; 71 | }; 72 | } 73 | 74 | @Override 75 | protected int getDecodedLength(byte[] src, int pad) { 76 | int sl = src.length; 77 | 78 | if ((sl & MOD4) != 0) 79 | throw new IllegalArgumentException("Number of input bytes not divisible by 4"); 80 | 81 | return sl/4 * 3 - pad; 82 | } 83 | 84 | @Override 85 | protected int getDecodedLengthFast(byte[] src, int pad) { 86 | return getDecodedLength(src, pad); 87 | } 88 | } 89 | -------------------------------------------------------------------------------- /base64/src/main/java/com/joad/jdz/base64/scalar/RFC4648ScalarEncoder.java: -------------------------------------------------------------------------------- 1 | package com.joad.jdz.base64.scalar; 2 | 3 | import static com.joad.jdz.base64.scalar.ScalarUtils.*; 4 | import static com.joad.jdz.base64.Base64Tables.*; 5 | 6 | import com.joad.jdz.base64.Base64Encoder; 7 | 8 | public class RFC4648ScalarEncoder extends Base64Encoder { 9 | 10 | @Override 11 | public int encode(final byte[] src, final byte[] dst) { 12 | int sl = src.length; 13 | 14 | int sp = 0; 15 | int dp = 0; 16 | 17 | for (; sp < src.length - 57; sp += 57, dp += 76) { 18 | encodeSixBytes(src, dst, BASE64, sp, dp); 19 | encodeSixBytes(src, dst, BASE64, sp + 6, dp + 8); 20 | encodeSixBytes(src, dst, BASE64, sp + 12, dp + 16); 21 | encodeSixBytes(src, dst, BASE64, sp + 18, dp + 24); 22 | encodeSixBytes(src, dst, BASE64, sp + 24, dp + 32); 23 | encodeSixBytes(src, dst, BASE64, sp + 30, dp + 40); 24 | encodeSixBytes(src, dst, BASE64, sp + 36, dp + 48); 25 | encodeSixBytes(src, dst, BASE64, sp + 42, dp + 56); 26 | encodeSixBytes(src, dst, BASE64, sp + 48, dp + 64); 27 | encodeThreeBytes(src, dst, BASE64, sp + 54, dp + 72); 28 | } 29 | 30 | for (; sp < src.length - 3; sp += 3, dp += 4) { 31 | encodeThreeBytes(src, dst, BASE64, sp, dp); 32 | } 33 | 34 | int remaining = sl - sp; 35 | 36 | return switch (remaining) { 37 | case 3 -> encodeLastThreeBytes(src, dst, BASE64, sp, dp); 38 | case 2 -> encodeLastTwoBytes(src, dst, BASE64, sp, dp); 39 | case 1 -> encodeLastByte(src, dst, BASE64, sp, dp); 40 | default -> dp; 41 | }; 42 | } 43 | 44 | @Override 45 | public int getEncodedLength(final byte[] src) { 46 | return Math.multiplyExact(4, (Math.addExact(src.length, 2) / 3)); 47 | } 48 | } -------------------------------------------------------------------------------- /base64/src/main/java/com/joad/jdz/base64/scalar/RFC4648URLScalarDecoder.java: -------------------------------------------------------------------------------- 1 | package com.joad.jdz.base64.scalar; 2 | 3 | import static com.joad.jdz.base64.scalar.ScalarDecoderVars.*; 4 | import static com.joad.jdz.base64.scalar.ScalarUtils.*; 5 | 6 | import com.joad.jdz.base64.Base64Decoder; 7 | 8 | public class RFC4648URLScalarDecoder extends Base64Decoder { 9 | 10 | @Override 11 | protected int decode(byte[] src, byte[] dst, int sl, int dl) { 12 | int sp = 0; 13 | int dp = 0; 14 | 15 | for (; dp < dl - 57; sp += 76, dp += 57) { 16 | decodeEightBytesValidating(src, dst, LOOKUP_URL, sp, dp); 17 | decodeEightBytesValidating(src, dst, LOOKUP_URL, sp + 8, dp + 6); 18 | decodeEightBytesValidating(src, dst, LOOKUP_URL, sp + 16, dp + 12); 19 | decodeEightBytesValidating(src, dst, LOOKUP_URL, sp + 24, dp + 18); 20 | decodeEightBytesValidating(src, dst, LOOKUP_URL, sp + 32, dp + 24); 21 | decodeEightBytesValidating(src, dst, LOOKUP_URL, sp + 40, dp + 30); 22 | decodeEightBytesValidating(src, dst, LOOKUP_URL, sp + 48, dp + 36); 23 | decodeEightBytesValidating(src, dst, LOOKUP_URL, sp + 56, dp + 42); 24 | decodeEightBytesValidating(src, dst, LOOKUP_URL, sp + 64, dp + 48); 25 | decodeFourBytesValidating(src, dst, LOOKUP_URL, sp + 72, dp + 54); 26 | } 27 | 28 | for (; sp < sl - 4; sp += 4, dp += 3) { 29 | decodeFourBytesValidating(src, dst, LOOKUP_URL, sp, dp); 30 | } 31 | 32 | int remaining = sl - sp; 33 | 34 | return switch (remaining) { 35 | case 4 -> decodeLastFourBytesValidating(src, dst, LOOKUP_URL, sp, dp); 36 | case 3 -> decodeLastThreeBytesValidating(src, dst, LOOKUP_URL, sp, dp); 37 | case 2 -> decodeLastTwoBytesValidating(src, dst, LOOKUP_URL, sp, dp); 38 | default -> dp; 39 | }; 40 | } 41 | 42 | @Override 43 | protected int decodeFast(byte[] src, byte[] dst, int sl, int dl) { 44 | int sp = 0; 45 | int dp = 0; 46 | 47 | for (; dp < dl - 57; sp += 76, dp += 57) { 48 | decodeEightBytes(src, dst, LOOKUP_URL, sp, dp); 49 | decodeEightBytes(src, dst, LOOKUP_URL, sp + 8, dp + 6); 50 | decodeEightBytes(src, dst, LOOKUP_URL, sp + 16, dp + 12); 51 | decodeEightBytes(src, dst, LOOKUP_URL, sp + 24, dp + 18); 52 | decodeEightBytes(src, dst, LOOKUP_URL, sp + 32, dp + 24); 53 | decodeEightBytes(src, dst, LOOKUP_URL, sp + 40, dp + 30); 54 | decodeEightBytes(src, dst, LOOKUP_URL, sp + 48, dp + 36); 55 | decodeEightBytes(src, dst, LOOKUP_URL, sp + 56, dp + 42); 56 | decodeEightBytes(src, dst, LOOKUP_URL, sp + 64, dp + 48); 57 | decodeFourBytes(src, dst, LOOKUP_URL, sp + 72, dp + 54); 58 | } 59 | 60 | for (; sp < sl - 4; sp += 4, dp += 3) { 61 | decodeFourBytes(src, dst, LOOKUP_URL, sp, dp); 62 | } 63 | 64 | int remaining = sl - sp; 65 | 66 | return switch (remaining) { 67 | case 4 -> decodeLastFourBytes(src, dst, LOOKUP_URL, sp, dp); 68 | case 3 -> decodeLastThreeBytes(src, dst, LOOKUP_URL, sp, dp); 69 | case 2 -> decodeLastTwoBytes(src, dst, LOOKUP_URL, sp, dp); 70 | default -> dp; 71 | }; 72 | } 73 | 74 | @Override 75 | protected int getDecodedLength(byte[] src, int pad) { 76 | int sl = src.length; 77 | 78 | if ((sl & MOD4) != 0) 79 | throw new IllegalArgumentException("Number of input bytes not divisible by 4"); 80 | 81 | return sl/4 * 3 - pad; 82 | } 83 | 84 | @Override 85 | protected int getDecodedLengthFast(byte[] src, int pad) { 86 | return getDecodedLength(src, pad); 87 | } 88 | } 89 | -------------------------------------------------------------------------------- /base64/src/main/java/com/joad/jdz/base64/scalar/RFC4648URLScalarEncoder.java: -------------------------------------------------------------------------------- 1 | package com.joad.jdz.base64.scalar; 2 | 3 | import static com.joad.jdz.base64.scalar.ScalarUtils.*; 4 | import static com.joad.jdz.base64.Base64Tables.*; 5 | 6 | import com.joad.jdz.base64.Base64Encoder; 7 | 8 | public class RFC4648URLScalarEncoder extends Base64Encoder { 9 | 10 | @Override 11 | public int encode(final byte[] src, final byte[] dst) { 12 | int sl = src.length; 13 | 14 | int sp = 0; 15 | int dp = 0; 16 | 17 | for (; sp < src.length - 57; sp += 57, dp += 76) { 18 | encodeSixBytes(src, dst, BASE64_URL, sp, dp); 19 | encodeSixBytes(src, dst, BASE64_URL, sp + 6, dp + 8); 20 | encodeSixBytes(src, dst, BASE64_URL, sp + 12, dp + 16); 21 | encodeSixBytes(src, dst, BASE64_URL, sp + 18, dp + 24); 22 | encodeSixBytes(src, dst, BASE64_URL, sp + 24, dp + 32); 23 | encodeSixBytes(src, dst, BASE64_URL, sp + 30, dp + 40); 24 | encodeSixBytes(src, dst, BASE64_URL, sp + 36, dp + 48); 25 | encodeSixBytes(src, dst, BASE64_URL, sp + 42, dp + 56); 26 | encodeSixBytes(src, dst, BASE64_URL, sp + 48, dp + 64); 27 | encodeThreeBytes(src, dst, BASE64_URL, sp + 54, dp + 72); 28 | } 29 | 30 | for (; sp < src.length - 3; sp += 3, dp += 4) { 31 | encodeThreeBytes(src, dst, BASE64_URL, sp, dp); 32 | } 33 | 34 | int remaining = sl - sp; 35 | 36 | return switch (remaining) { 37 | case 3 -> encodeLastThreeBytes(src, dst, BASE64_URL, sp, dp); 38 | case 2 -> encodeLastTwoBytes(src, dst, BASE64_URL, sp, dp); 39 | case 1 -> encodeLastByte(src, dst, BASE64_URL, sp, dp); 40 | default -> dp; 41 | }; 42 | } 43 | 44 | @Override 45 | public int getEncodedLength(final byte[] src) { 46 | return Math.multiplyExact(4, (Math.addExact(src.length, 2) / 3)); 47 | } 48 | } -------------------------------------------------------------------------------- /base64/src/main/java/com/joad/jdz/base64/scalar/ScalarDecoderVars.java: -------------------------------------------------------------------------------- 1 | package com.joad.jdz.base64.scalar; 2 | 3 | import static com.joad.jdz.base64.Base64Tables.*; 4 | 5 | import java.lang.invoke.MethodHandles; 6 | import java.lang.invoke.VarHandle; 7 | import java.nio.ByteOrder; 8 | import java.util.Arrays; 9 | 10 | class ScalarDecoderVars { 11 | static final int[][] LOOKUP = new int[4][256]; 12 | 13 | static final int[][] LOOKUP_URL = new int[4][256]; 14 | 15 | final static VarHandle INT_LE = 16 | MethodHandles.byteArrayViewVarHandle(int[].class, ByteOrder.LITTLE_ENDIAN); 17 | 18 | static { 19 | for (int i = 0; i < 4; i++) { 20 | Arrays.fill(LOOKUP[i], 1 << (24 + 3 - i)); 21 | Arrays.fill(LOOKUP_URL[i], 1 << (24 + 3 - i)); 22 | } 23 | 24 | for (int i = 0; i < 64; i++) { 25 | LOOKUP[0][BASE64[i]] = i << 2; 26 | LOOKUP[1][BASE64[i]] = (i >> 4) | ((i & 0x0f) << 12); 27 | LOOKUP[2][BASE64[i]] = ((i & 0x3) << 22) | ((i & 0x3c) << 6); 28 | LOOKUP[3][BASE64[i]] = i << 16; 29 | 30 | LOOKUP_URL[0][BASE64_URL[i]] = i << 2; 31 | LOOKUP_URL[1][BASE64_URL[i]] = (i >> 4) | ((i & 0x0f) << 12); 32 | LOOKUP_URL[2][BASE64_URL[i]] = ((i & 0x3) << 22) | ((i & 0x3c) << 6); 33 | LOOKUP_URL[3][BASE64_URL[i]] = i << 16; 34 | } 35 | } 36 | 37 | static final int VALID_MAX = (1 << 24) - 1; 38 | 39 | static final int MOD4 = 3; 40 | } -------------------------------------------------------------------------------- /base64/src/main/java/com/joad/jdz/base64/scalar/ScalarUtils.java: -------------------------------------------------------------------------------- 1 | package com.joad.jdz.base64.scalar; 2 | 3 | import static com.joad.jdz.base64.scalar.ScalarDecoderVars.*; 4 | 5 | import java.lang.invoke.MethodHandles; 6 | import java.lang.invoke.VarHandle; 7 | import java.nio.ByteOrder; 8 | 9 | class ScalarUtils { 10 | private final static VarHandle LONG_BE = 11 | MethodHandles.byteArrayViewVarHandle(long[].class, ByteOrder.BIG_ENDIAN); 12 | 13 | private final static VarHandle LONG_LE = 14 | MethodHandles.byteArrayViewVarHandle(long[].class, ByteOrder.LITTLE_ENDIAN); 15 | 16 | private final static VarHandle INT_BE = 17 | MethodHandles.byteArrayViewVarHandle(int[].class, ByteOrder.BIG_ENDIAN); 18 | 19 | private final static VarHandle INT_LE = 20 | MethodHandles.byteArrayViewVarHandle(int[].class, ByteOrder.LITTLE_ENDIAN); 21 | 22 | static void encodeSixBytes(byte[] src, byte[] dst, char[] lookup, int sp, int dp) { 23 | long bits = (long) LONG_BE.get(src, sp); 24 | 25 | dst[dp++] = (byte) lookup[(int) (bits >>> 58) & 0x3f]; 26 | dst[dp++] = (byte) lookup[(int) (bits >>> 52) & 0x3f]; 27 | dst[dp++] = (byte) lookup[(int) (bits >>> 46) & 0x3f]; 28 | dst[dp++] = (byte) lookup[(int) (bits >>> 40) & 0x3f]; 29 | dst[dp++] = (byte) lookup[(int) (bits >>> 34) & 0x3f]; 30 | dst[dp++] = (byte) lookup[(int) (bits >>> 28) & 0x3f]; 31 | dst[dp++] = (byte) lookup[(int) (bits >>> 22) & 0x3f]; 32 | dst[dp] = (byte) lookup[(int) (bits >>> 16) & 0x3f]; 33 | } 34 | 35 | static void encodeThreeBytes(byte[] src, byte[] dst, char[] lookup, int sp, int dp) { 36 | int bits = (int) INT_BE.get(src, sp); 37 | 38 | dst[dp++] = (byte) lookup[(bits >>> 26) & 0x3f]; 39 | dst[dp++] = (byte) lookup[(bits >>> 20) & 0x3f]; 40 | dst[dp++] = (byte) lookup[(bits >>> 14) & 0x3f]; 41 | dst[dp] = (byte) lookup[(bits >>> 8) & 0x3f]; 42 | } 43 | 44 | static void decodeFourBytes(byte[] src, byte[] dst, int[][] lookup, int sp, int dp) { 45 | int bits = lookup[0][src[sp++]] 46 | | lookup[1][src[sp++]] 47 | | lookup[2][src[sp++]] 48 | | lookup[3][src[sp]]; 49 | 50 | INT_LE.set(dst, dp, bits); 51 | } 52 | 53 | static void decodeFourBytesValidating(byte[] src, byte[] dst, int[][] lookup, int sp, int dp) { 54 | int osp = sp; 55 | 56 | int bits = lookup[0][src[sp++]] 57 | | lookup[1][src[sp++]] 58 | | lookup[2][src[sp++]] 59 | | lookup[3][src[sp]]; 60 | 61 | assertValidBase64(src, bits, osp); 62 | 63 | INT_LE.set(dst, dp, bits); 64 | } 65 | 66 | static void decodeEightBytes(byte[] src, byte[] dst, int[][] lookup, int sp, int dp) { 67 | long bits1 = lookup[0][src[sp++]] 68 | | lookup[1][src[sp++]] 69 | | lookup[2][src[sp++]] 70 | | lookup[3][src[sp++]]; 71 | 72 | long bits2 = lookup[0][src[sp++]] 73 | | lookup[1][src[sp++]] 74 | | lookup[2][src[sp++]] 75 | | lookup[3][src[sp]]; 76 | 77 | long bits = bits1 | (bits2 << 24); 78 | 79 | LONG_LE.set(dst, dp, bits); 80 | } 81 | 82 | static void decodeEightBytesValidating(byte[] src, byte[] dst, int[][] lookup, int sp, int dp) { 83 | int osp = sp; 84 | 85 | long bits1 = lookup[0][src[sp++]] 86 | | lookup[1][src[sp++]] 87 | | lookup[2][src[sp++]] 88 | | lookup[3][src[sp++]]; 89 | 90 | long bits2 = lookup[0][src[sp++]] 91 | | lookup[1][src[sp++]] 92 | | lookup[2][src[sp++]] 93 | | lookup[3][src[sp]]; 94 | 95 | assertValidBase64(src, (int) bits1, osp); 96 | assertValidBase64(src, (int) bits2, osp); 97 | 98 | long bits = bits1 | (bits2 << 24); 99 | 100 | LONG_LE.set(dst, dp, bits); 101 | } 102 | 103 | static int encodeLastByte(byte[] src, byte[] dst, char[] lookup, int sp, int dp) { 104 | int b0 = src[sp] & 0xff; 105 | 106 | dst[dp++] = (byte) lookup[b0 >> 2]; 107 | dst[dp++] = (byte) lookup[(b0 << 4) & 0x3f]; 108 | dst[dp++] = '='; 109 | dst[dp++] = '='; 110 | 111 | return dp; 112 | } 113 | 114 | static int encodeLastTwoBytes(byte[] src, byte[] dst, char[] lookup, int sp, int dp) { 115 | int b0 = src[sp++] & 0xff; 116 | int b1 = src[sp] & 0xff; 117 | 118 | dst[dp++] = (byte) lookup[b0 >> 2]; 119 | dst[dp++] = (byte) lookup[(b0 << 4) & 0x3f | (b1 >> 4)]; 120 | dst[dp++] = (byte) lookup[(b1 << 2) & 0x3f]; 121 | dst[dp++] = '='; 122 | 123 | return dp; 124 | } 125 | 126 | static int encodeLastThreeBytes(byte[] src, byte[] dst, char[] lookup, int sp, int dp) { 127 | int b0 = src[sp++] & 0xff; 128 | int b1 = src[sp++] & 0xff; 129 | int b2 = src[sp] & 0xff; 130 | 131 | dst[dp++] = (byte) lookup[b0 >> 2]; 132 | dst[dp++] = (byte) lookup[(b0 << 4) & 0x3f | (b1 >> 4)]; 133 | dst[dp++] = (byte) lookup[(b1 << 2) & 0x3f | (b2 >> 6)]; 134 | dst[dp++] = (byte) lookup[b2 & 0x3f]; 135 | 136 | return dp; 137 | } 138 | 139 | static int decodeLastFourBytes(byte[] src, byte[] dst, int[][] lookup, int sp, int dp) { 140 | int bits = lookup[0][src[sp++]] 141 | | lookup[1][src[sp++]] 142 | | lookup[2][src[sp++]] 143 | | lookup[3][src[sp]]; 144 | 145 | dst[dp++] = (byte) bits; 146 | dst[dp++] = (byte) (bits >> 8); 147 | dst[dp++] = (byte) (bits >> 16); 148 | 149 | return dp; 150 | } 151 | 152 | static int decodeLastThreeBytes(byte[] src, byte[] dst, int[][] lookup, int sp, int dp) { 153 | int bits = lookup[0][src[sp++]] 154 | | lookup[1][src[sp++]] 155 | | lookup[2][src[sp++]]; 156 | 157 | dst[dp++] = (byte) bits; 158 | dst[dp++] = (byte) (bits >> 8); 159 | 160 | return dp; 161 | } 162 | 163 | static int decodeLastTwoBytes(byte[] src, byte[] dst, int[][] lookup, int sp, int dp) { 164 | int bits = lookup[0][src[sp++]] 165 | | lookup[1][src[sp++]]; 166 | 167 | dst[dp++] = (byte) bits; 168 | 169 | return dp; 170 | } 171 | 172 | static int decodeLastFourBytesValidating(byte[] src, byte[] dst, int[][] lookup, int sp, int dp) { 173 | int osp = sp; 174 | 175 | int bits = lookup[0][src[sp++]] 176 | | lookup[1][src[sp++]] 177 | | lookup[2][src[sp++]] 178 | | lookup[3][src[sp]]; 179 | 180 | assertValidBase64(src, bits, osp); 181 | 182 | dst[dp++] = (byte) bits; 183 | dst[dp++] = (byte) (bits >> 8); 184 | dst[dp++] = (byte) (bits >> 16); 185 | 186 | return dp; 187 | } 188 | 189 | static int decodeLastThreeBytesValidating(byte[] src, byte[] dst, int[][] lookup, int sp, int dp) { 190 | int osp = sp; 191 | 192 | int bits = lookup[0][src[sp++]] 193 | | lookup[1][src[sp++]] 194 | | lookup[2][src[sp]]; 195 | 196 | assertValidBase64(src, bits, osp); 197 | 198 | dst[dp++] = (byte) bits; 199 | dst[dp++] = (byte) (bits >> 8); 200 | 201 | return dp; 202 | } 203 | 204 | static int decodeLastTwoBytesValidating(byte[] src, byte[] dst, int[][] lookup, int sp, int dp) { 205 | int osp = sp; 206 | 207 | int bits = lookup[0][src[sp++]] 208 | | lookup[1][src[sp]]; 209 | 210 | assertValidBase64(src, bits, osp); 211 | 212 | dst[dp++] = (byte) bits; 213 | 214 | return dp; 215 | } 216 | 217 | static int decodeLastThreeDestBytesMime(byte[] src, byte[] dst, int[][] lookup, int sp, int dp) { 218 | int bits = 0; 219 | for (int i = 0; i < 4;) { 220 | int b = lookup[i][src[sp++]]; 221 | 222 | if (b <= VALID_MAX) { 223 | bits |= b; 224 | i++; 225 | } 226 | } 227 | 228 | dst[dp++] = (byte) bits; 229 | dst[dp++] = (byte) (bits >> 8); 230 | dst[dp++] = (byte) (bits >> 16); 231 | 232 | return dp; 233 | } 234 | 235 | static int decodeLastTwoDestBytesMime(byte[] src, byte[] dst, int[][] lookup, int sp, int dp) { 236 | int bits = 0; 237 | for (int i = 0; i < 3;) { 238 | int b = lookup[i][src[sp++]]; 239 | 240 | if (b <= VALID_MAX) { 241 | bits |= b; 242 | i++; 243 | } 244 | } 245 | 246 | dst[dp++] = (byte) bits; 247 | dst[dp++] = (byte) (bits >> 8); 248 | 249 | return dp; 250 | } 251 | 252 | static int decodeLastDestByteMime(byte[] src, byte[] dst, int[][] lookup, int sp, int dp) { 253 | int bits = 0; 254 | for (int i = 0; i < 2;) { 255 | int b = lookup[i][src[sp++]]; 256 | 257 | if (b <= VALID_MAX) { 258 | bits |= b; 259 | i++; 260 | } 261 | } 262 | 263 | dst[dp++] = (byte) bits; 264 | 265 | return dp; 266 | } 267 | 268 | private static void assertValidBase64(byte[] src, int bits, int sp) { 269 | if (bits > VALID_MAX) { 270 | int ip = sp + Integer.numberOfLeadingZeros(bits) - 4; 271 | 272 | throw new IllegalArgumentException("Illegal base64 character " + Integer.toString(src[ip], 16) + " at position " + ip); 273 | } 274 | } 275 | } 276 | -------------------------------------------------------------------------------- /base64/src/main/java/com/joad/jdz/base64/vector/Base64Vector.java: -------------------------------------------------------------------------------- 1 | package com.joad.jdz.base64.vector; 2 | 3 | import com.joad.jdz.base64.Base64Decoder; 4 | import com.joad.jdz.base64.Base64Encoder; 5 | 6 | public class Base64Vector { 7 | private static final Base64Encoder RFC4648_ENCODER = new RFC4648VectorEncoder(); 8 | 9 | private static final Base64Encoder RFC4648URL_ENCODER = new RFC4648URLVectorEncoder(); 10 | 11 | private static final Base64Encoder RFC2045_ENCODER = new RFC2045VectorEncoder(); 12 | 13 | private static final Base64Decoder RFC4648_DECODER = new RFC4648VectorDecoder(); 14 | 15 | private static final Base64Decoder RFC4648URL_DECODER = new RFC4648URLVectorDecoder(); 16 | 17 | private static final Base64Decoder RFC2045_DECODER = new RFC2045VectorDecoder(); 18 | 19 | /** 20 | * Encoder for the RFC4648 Base64 spec 21 | * 22 | * @return An RFC4648 Base64 Encoder 23 | */ 24 | public static Base64Encoder getEncoder() { 25 | return RFC4648_ENCODER; 26 | } 27 | 28 | /** 29 | * Encoder for the RFC4648URL Base64 spec 30 | * 31 | * @return An RFC4648 Base64 Encoder 32 | */ 33 | public static Base64Encoder getUrlEncoder() { 34 | return RFC4648URL_ENCODER; 35 | } 36 | 37 | /** 38 | * Encoder for the RFC2045 Base64 spec 39 | * 40 | * @return An RFC42045 Base64 encoder 41 | */ 42 | public static Base64Encoder getMimeEncoder() { 43 | return RFC2045_ENCODER; 44 | } 45 | 46 | /** 47 | * Decoder for the RFC4648 Base64 spec 48 | * 49 | * @return An RFC4648 Base64 decoder 50 | */ 51 | public static Base64Decoder getDecoder() { 52 | return RFC4648_DECODER; 53 | } 54 | 55 | /** 56 | * Decoder for the RFC4648 URL Base64 spec 57 | * 58 | * @return An RFC4648 URL Base64 decoder 59 | */ 60 | public static Base64Decoder getUrlDecoder() { 61 | return RFC4648URL_DECODER; 62 | } 63 | 64 | /** 65 | * Decoder for the RFC2045 Base64 spec 66 | * 67 | * @return An RFC2045 Base64 fast encoder 68 | */ 69 | public static Base64Decoder getMimeDecoder() { 70 | return RFC2045_DECODER; 71 | } 72 | } 73 | -------------------------------------------------------------------------------- /base64/src/main/java/com/joad/jdz/base64/vector/RFC2045VectorDecoder.java: -------------------------------------------------------------------------------- 1 | package com.joad.jdz.base64.vector; 2 | 3 | import static com.joad.jdz.base64.Base64Tables.*; 4 | import static com.joad.jdz.base64.vector.ScalarUtils.*; 5 | import static com.joad.jdz.base64.vector.VectorUtils.*; 6 | import static com.joad.jdz.base64.vector.VectorDecoderVars.*; 7 | 8 | import java.util.Arrays; 9 | import com.joad.jdz.base64.Base64Decoder; 10 | 11 | public class RFC2045VectorDecoder extends Base64Decoder { 12 | private static final int[] SIMPLE_LOOKUP = new int[256]; 13 | 14 | static { 15 | Arrays.fill(SIMPLE_LOOKUP, -1); 16 | for (int i = 0; i < 64; i++) 17 | SIMPLE_LOOKUP[BASE64[i]] = i; 18 | } 19 | 20 | private static final int NUM_ITERS = 64 / SPECIES_LENGTH + 1; 21 | 22 | @Override 23 | protected int decode(byte[] src, byte[] dst, int sl, int dl) { 24 | int sp = 0; 25 | int dp = 0; 26 | 27 | while (dp < dl - SPECIES_LENGTH) { 28 | int invalid = decodeBytesVectorizedMime(src, dst, SHIFT, SLASH_BYTE, SLASH_SWAP, sp, dp); 29 | 30 | if (invalid != SPECIES_LENGTH) { 31 | int spInc = invalid - (invalid & MOD4); 32 | 33 | sp += spInc; 34 | dp += spInc / 4 * 3; 35 | 36 | int bits = 0; 37 | 38 | for (int i = 0; i < 4;) { 39 | int b = LOOKUP[i][src[sp++]]; 40 | 41 | if (b <= VALID_MAX) { 42 | bits |= b; 43 | i++; 44 | } 45 | } 46 | 47 | INT_LE.set(dst, dp, bits); 48 | 49 | dp += 3; 50 | } 51 | else { 52 | dp += DP_INC; 53 | sp += SP_INC; 54 | } 55 | } 56 | 57 | while (dp < dl - 3) { 58 | int bits = 0; 59 | for (int i = 0; i < 4;) { 60 | int b = LOOKUP[i][src[sp++]]; 61 | 62 | if (b <= VALID_MAX) { 63 | bits |= b; 64 | i++; 65 | } 66 | } 67 | 68 | INT_LE.set(dst, dp, bits); 69 | 70 | dp += 3; 71 | } 72 | 73 | int remaining = dl - dp; 74 | 75 | return switch (remaining) { 76 | case 3 -> decodeLastThreeDestBytesMime(src, dst, LOOKUP, sp, dp); 77 | case 2 -> decodeLastTwoDestBytesMime(src, dst, LOOKUP, sp, dp); 78 | case 1 -> decodeLastDestByteMime(src, dst, LOOKUP, sp, dp); 79 | default -> dp; 80 | }; 81 | } 82 | 83 | @Override 84 | protected int decodeFast(byte[] src, byte[] dst, int sl, int dl) { 85 | int sp = 0; 86 | int dp = 0; 87 | 88 | int end = dl - (NUM_ITERS - 1) * DP_INC - SPECIES_LENGTH; 89 | 90 | for (; dp < end; sp += 78, dp += 57) { 91 | for (int i = 0; i < NUM_ITERS; i++) 92 | decodeBytesVectorized(src, dst, SHIFT, SLASH_BYTE, SLASH_SWAP, sp + SP_INC * i, dp + DP_INC * i); 93 | } 94 | 95 | for (; dp < dl - 57; sp += 78, dp += 57) { 96 | decodeEightBytes(src, dst, LOOKUP, sp, dp); 97 | decodeEightBytes(src, dst, LOOKUP, sp + 8, dp + 6); 98 | decodeEightBytes(src, dst, LOOKUP, sp + 16, dp + 12); 99 | decodeEightBytes(src, dst, LOOKUP, sp + 24, dp + 18); 100 | decodeEightBytes(src, dst, LOOKUP, sp + 32, dp + 24); 101 | decodeEightBytes(src, dst, LOOKUP, sp + 40, dp + 30); 102 | decodeEightBytes(src, dst, LOOKUP, sp + 48, dp + 36); 103 | decodeEightBytes(src, dst, LOOKUP, sp + 56, dp + 42); 104 | decodeEightBytes(src, dst, LOOKUP, sp + 64, dp + 48); 105 | decodeFourBytes(src, dst, LOOKUP, sp + 72, dp + 54); 106 | } 107 | 108 | for (; sp < sl - 4; sp += 4, dp += 3) { 109 | decodeFourBytes(src, dst, LOOKUP, sp, dp); 110 | } 111 | 112 | int remaining = sl - sp; 113 | return switch (remaining) { 114 | case 4 -> decodeLastFourBytes(src, dst, LOOKUP, sp, dp); 115 | case 3 -> decodeLastThreeBytes(src, dst, LOOKUP, sp, dp); 116 | case 2 -> decodeLastTwoBytes(src, dst, LOOKUP, sp, dp); 117 | default -> dp; 118 | }; 119 | } 120 | 121 | @Override 122 | protected int getDecodedLength(byte[] src, int pad) { 123 | int sl = src.length; 124 | 125 | int invalid = 0; 126 | 127 | int sp = 0; 128 | for (; sp < sl - SPECIES_LENGTH; sp += SPECIES_LENGTH) { 129 | invalid += countInvalidBytesVectorized(src, sp); 130 | } 131 | 132 | while (sp < sl - pad) { 133 | if (SIMPLE_LOOKUP[src[sp++]] < 0) 134 | invalid++; 135 | } 136 | 137 | int vsl = sl - invalid; 138 | 139 | if ((vsl & MOD4) != 0) 140 | throw new IllegalArgumentException("Number of valid input bytes not divisible by 4"); 141 | 142 | return vsl / 4 * 3 - pad; 143 | } 144 | 145 | @Override 146 | protected int getDecodedLengthFast(byte[] src, int pad) { 147 | int sl = src.length; 148 | 149 | int vsl = sl - (sl/78) * 2; 150 | 151 | if ((vsl & MOD4) != 0) 152 | throw new IllegalArgumentException("Number of valid input bytes not divisible by 4"); 153 | 154 | return vsl / 4 * 3 - pad; 155 | } 156 | } 157 | -------------------------------------------------------------------------------- /base64/src/main/java/com/joad/jdz/base64/vector/RFC2045VectorEncoder.java: -------------------------------------------------------------------------------- 1 | package com.joad.jdz.base64.vector; 2 | 3 | import static com.joad.jdz.base64.Base64Tables.*; 4 | import static com.joad.jdz.base64.vector.ScalarUtils.*; 5 | import static com.joad.jdz.base64.vector.VectorUtils.*; 6 | import static com.joad.jdz.base64.vector.VectorEncoderVars.*; 7 | 8 | import com.joad.jdz.base64.Base64Encoder; 9 | 10 | public class RFC2045VectorEncoder extends Base64Encoder { 11 | private static final int NUM_ITERS_64 = 64 / SPECIES_LENGTH; 12 | 13 | private static final int NUM_ITERS_OVERFLOW = NUM_ITERS_64 + 1; 14 | 15 | @Override 16 | public int encode(byte[] src, byte[] dst) { 17 | int sl = src.length; 18 | int dl = dst.length; 19 | int dp = 0; 20 | int sp = 0; 21 | 22 | for (; sp < sl - SPECIES_LENGTH * NUM_ITERS_OVERFLOW; sp += 57, dp += 78) { 23 | for (int i = 0; i < NUM_ITERS_OVERFLOW; i++) 24 | encodeBytesVectorized(src, dst, SHIFT, sp + SP_INC * i, dp + DP_INC * i); 25 | } 26 | 27 | for (; sp < sl - 57; sp += 57, dp += 78) { 28 | encodeSixBytes(src, dst, BASE64, sp, dp); 29 | encodeSixBytes(src, dst, BASE64, sp + 6, dp + 8); 30 | encodeSixBytes(src, dst, BASE64, sp + 12, dp + 16); 31 | encodeSixBytes(src, dst, BASE64, sp + 18, dp + 24); 32 | encodeSixBytes(src, dst, BASE64, sp + 24, dp + 32); 33 | encodeSixBytes(src, dst, BASE64, sp + 30, dp + 40); 34 | encodeSixBytes(src, dst, BASE64, sp + 36, dp + 48); 35 | encodeSixBytes(src, dst, BASE64, sp + 42, dp + 56); 36 | encodeSixBytes(src, dst, BASE64, sp + 48, dp + 64); 37 | encodeThreeBytes(src, dst, BASE64, sp + 54, dp + 72); 38 | } 39 | 40 | 41 | for (; sp < sl - 3; sp += 3, dp += 4) { 42 | encodeThreeBytes(src, dst, BASE64, sp, dp); 43 | } 44 | 45 | for (int ldp = 76; ldp < dl; ldp += 78) { 46 | dst[ldp] = '\r'; 47 | dst[ldp+1] = '\n'; 48 | } 49 | 50 | int remaining = sl - sp; 51 | 52 | return switch (remaining) { 53 | case 3 -> encodeLastThreeBytes(src, dst, BASE64, sp, dp); 54 | case 2 -> encodeLastTwoBytes(src, dst, BASE64, sp, dp); 55 | case 1 -> encodeLastByte(src, dst, BASE64, sp, dp); 56 | default -> dp; 57 | }; 58 | } 59 | 60 | @Override 61 | public int getEncodedLength(byte[] src) { 62 | int rawLen = Math.multiplyExact(4, (Math.addExact(src.length, 2) / 3)); 63 | 64 | return rawLen + ((rawLen - 1)/76) * 2; 65 | } 66 | } -------------------------------------------------------------------------------- /base64/src/main/java/com/joad/jdz/base64/vector/RFC4648URLVectorDecoder.java: -------------------------------------------------------------------------------- 1 | package com.joad.jdz.base64.vector; 2 | 3 | import static com.joad.jdz.base64.vector.ScalarUtils.*; 4 | import static com.joad.jdz.base64.vector.VectorUtils.*; 5 | import static com.joad.jdz.base64.vector.VectorDecoderVars.*; 6 | 7 | import com.joad.jdz.base64.Base64Decoder; 8 | 9 | public class RFC4648URLVectorDecoder extends Base64Decoder { 10 | 11 | @Override 12 | protected int decode(byte[] src, byte[] dst, int sl, int dl) { 13 | int sp = 0; 14 | int dp = 0; 15 | 16 | for (; dp < dl - SPECIES_LENGTH; sp += SP_INC, dp += DP_INC) { 17 | decodeBytesVectorizedValidating(src, dst, SHIFT_URL, MASK_URL, UNDERSCORE_BYTE, UNDERSCORE_SWAP, sp, dp); 18 | } 19 | 20 | for (; sp < sl - 4; sp += 4, dp += 3) { 21 | decodeFourBytesValidating(src, dst, LOOKUP_URL, sp, dp); 22 | } 23 | 24 | int remaining = sl - sp; 25 | 26 | return switch (remaining) { 27 | case 4 -> decodeLastFourBytesValidating(src, dst, LOOKUP_URL, sp, dp); 28 | case 3 -> decodeLastThreeBytesValidating(src, dst, LOOKUP_URL, sp, dp); 29 | case 2 -> decodeLastTwoBytesValidating(src, dst, LOOKUP_URL, sp, dp); 30 | default -> dp; 31 | }; 32 | } 33 | 34 | @Override 35 | protected int decodeFast(byte[] src, byte[] dst, int sl, int dl) { 36 | int sp = 0; 37 | int dp = 0; 38 | 39 | for (; dp < dl - SPECIES_LENGTH; sp += SP_INC, dp += DP_INC) { 40 | decodeBytesVectorized(src, dst, SHIFT_URL, UNDERSCORE_BYTE, UNDERSCORE_SWAP, sp, dp); 41 | } 42 | 43 | for (; sp < sl - 4; sp += 4, dp += 3) { 44 | decodeFourBytes(src, dst, LOOKUP_URL, sp, dp); 45 | } 46 | 47 | int remaining = sl - sp; 48 | 49 | return switch (remaining) { 50 | case 4 -> decodeLastFourBytes(src, dst, LOOKUP_URL, sp, dp); 51 | case 3 -> decodeLastThreeBytes(src, dst, LOOKUP_URL, sp, dp); 52 | case 2 -> decodeLastTwoBytes(src, dst, LOOKUP_URL, sp, dp); 53 | default -> dp; 54 | }; 55 | } 56 | 57 | @Override 58 | protected int getDecodedLength(byte[] src, int pad) { 59 | int sl = src.length; 60 | 61 | if ((sl & MOD4) != 0) 62 | throw new IllegalArgumentException("Number of input bytes not divisible by 4"); 63 | 64 | return sl / 4 * 3 - pad; 65 | } 66 | 67 | @Override 68 | protected int getDecodedLengthFast(byte[] src, int pad) { 69 | return getDecodedLength(src, pad); 70 | } 71 | } -------------------------------------------------------------------------------- /base64/src/main/java/com/joad/jdz/base64/vector/RFC4648URLVectorEncoder.java: -------------------------------------------------------------------------------- 1 | package com.joad.jdz.base64.vector; 2 | 3 | import static com.joad.jdz.base64.Base64Tables.*; 4 | import static com.joad.jdz.base64.vector.ScalarUtils.*; 5 | import static com.joad.jdz.base64.vector.VectorUtils.*; 6 | import static com.joad.jdz.base64.vector.VectorEncoderVars.*; 7 | 8 | import com.joad.jdz.base64.Base64Encoder; 9 | 10 | public class RFC4648URLVectorEncoder extends Base64Encoder { 11 | 12 | @Override 13 | public int encode(byte[] src, byte[] dst) { 14 | int sl = src.length; 15 | int dp = 0; 16 | int sp = 0; 17 | 18 | for (; sp < sl - SPECIES_LENGTH; sp += SP_INC, dp += DP_INC) { 19 | encodeBytesVectorized(src, dst, SHIFT_URL, sp, dp); 20 | } 21 | 22 | for (; sp < src.length - 3; sp += 3, dp += 4) { 23 | encodeThreeBytes(src, dst, BASE64_URL, sp, dp); 24 | } 25 | 26 | int remaining = sl - sp; 27 | 28 | return switch (remaining) { 29 | case 3 -> encodeLastThreeBytes(src, dst, BASE64_URL, sp, dp); 30 | case 2 -> encodeLastTwoBytes(src, dst, BASE64_URL, sp, dp); 31 | case 1 -> encodeLastByte(src, dst, BASE64_URL, sp, dp); 32 | default -> dp; 33 | }; 34 | } 35 | 36 | @Override 37 | public int getEncodedLength(byte[] src) { 38 | return Math.multiplyExact(4, (Math.addExact(src.length, 2) / 3)); 39 | } 40 | } 41 | -------------------------------------------------------------------------------- /base64/src/main/java/com/joad/jdz/base64/vector/RFC4648VectorDecoder.java: -------------------------------------------------------------------------------- 1 | package com.joad.jdz.base64.vector; 2 | 3 | import static com.joad.jdz.base64.vector.ScalarUtils.*; 4 | import static com.joad.jdz.base64.vector.VectorUtils.*; 5 | import static com.joad.jdz.base64.vector.VectorDecoderVars.*; 6 | 7 | import com.joad.jdz.base64.Base64Decoder; 8 | 9 | public class RFC4648VectorDecoder extends Base64Decoder { 10 | 11 | @Override 12 | protected int decode(byte[] src, byte[] dst, int sl, int dl) { 13 | int sp = 0; 14 | int dp = 0; 15 | 16 | for (; dp < dl - SPECIES_LENGTH; sp += SP_INC, dp += DP_INC) { 17 | decodeBytesVectorizedValidating(src, dst, SHIFT, MASK, SLASH_BYTE, SLASH_SWAP, sp, dp); 18 | } 19 | 20 | for (; sp < sl - 4; sp += 4, dp += 3) { 21 | decodeFourBytesValidating(src, dst, LOOKUP, sp, dp); 22 | } 23 | 24 | int remaining = sl - sp; 25 | 26 | return switch (remaining) { 27 | case 4 -> decodeLastFourBytesValidating(src, dst, LOOKUP, sp, dp); 28 | case 3 -> decodeLastThreeBytesValidating(src, dst, LOOKUP, sp, dp); 29 | case 2 -> decodeLastTwoBytesValidating(src, dst, LOOKUP, sp, dp); 30 | default -> dp; 31 | }; 32 | } 33 | 34 | @Override 35 | protected int decodeFast(byte[] src, byte[] dst, int sl, int dl) { 36 | int sp = 0; 37 | int dp = 0; 38 | 39 | for (; dp < dl - SPECIES_LENGTH; sp += SP_INC, dp += DP_INC) { 40 | decodeBytesVectorized(src, dst, SHIFT, SLASH_BYTE, SLASH_SWAP, sp, dp); 41 | } 42 | 43 | for (; sp < sl - 4; sp += 4, dp += 3) { 44 | decodeFourBytes(src, dst, LOOKUP, sp, dp); 45 | } 46 | 47 | int remaining = sl - sp; 48 | 49 | return switch (remaining) { 50 | case 4 -> decodeLastFourBytes(src, dst, LOOKUP, sp, dp); 51 | case 3 -> decodeLastThreeBytes(src, dst, LOOKUP, sp, dp); 52 | case 2 -> decodeLastTwoBytes(src, dst, LOOKUP, sp, dp); 53 | default -> dp; 54 | }; 55 | } 56 | 57 | @Override 58 | protected int getDecodedLength(byte[] src, int pad) { 59 | int sl = src.length; 60 | 61 | if ((sl & MOD4) != 0) 62 | throw new IllegalArgumentException("Number of input bytes not divisible by 4"); 63 | 64 | return sl / 4 * 3 - pad; 65 | } 66 | 67 | @Override 68 | protected int getDecodedLengthFast(byte[] src, int pad) { 69 | return getDecodedLength(src, pad); 70 | } 71 | } -------------------------------------------------------------------------------- /base64/src/main/java/com/joad/jdz/base64/vector/RFC4648VectorEncoder.java: -------------------------------------------------------------------------------- 1 | package com.joad.jdz.base64.vector; 2 | 3 | import static com.joad.jdz.base64.Base64Tables.*; 4 | import static com.joad.jdz.base64.vector.ScalarUtils.*; 5 | import static com.joad.jdz.base64.vector.VectorUtils.*; 6 | import static com.joad.jdz.base64.vector.VectorEncoderVars.*; 7 | 8 | import com.joad.jdz.base64.Base64Encoder; 9 | 10 | public class RFC4648VectorEncoder extends Base64Encoder { 11 | 12 | @Override 13 | public int encode(byte[] src, byte[] dst) { 14 | int sl = src.length; 15 | int dp = 0; 16 | int sp = 0; 17 | 18 | for (; sp < sl - SPECIES_LENGTH; sp += SP_INC, dp += DP_INC) { 19 | encodeBytesVectorized(src, dst, SHIFT, sp, dp); 20 | } 21 | 22 | for (; sp < src.length - 3; sp += 3, dp += 4) { 23 | encodeThreeBytes(src, dst, BASE64, sp, dp); 24 | } 25 | 26 | int remaining = sl - sp; 27 | 28 | return switch (remaining) { 29 | case 3 -> encodeLastThreeBytes(src, dst, BASE64, sp, dp); 30 | case 2 -> encodeLastTwoBytes(src, dst, BASE64, sp, dp); 31 | case 1 -> encodeLastByte(src, dst, BASE64, sp, dp); 32 | default -> dp; 33 | }; 34 | } 35 | 36 | @Override 37 | public int getEncodedLength(byte[] src) { 38 | return Math.multiplyExact(4, (Math.addExact(src.length, 2) / 3)); 39 | } 40 | } 41 | -------------------------------------------------------------------------------- /base64/src/main/java/com/joad/jdz/base64/vector/ScalarUtils.java: -------------------------------------------------------------------------------- 1 | package com.joad.jdz.base64.vector; 2 | 3 | import static com.joad.jdz.base64.vector.VectorDecoderVars.*; 4 | 5 | import java.lang.invoke.MethodHandles; 6 | import java.lang.invoke.VarHandle; 7 | import java.nio.ByteOrder; 8 | 9 | class ScalarUtils { 10 | private final static VarHandle LONG_BE = 11 | MethodHandles.byteArrayViewVarHandle(long[].class, ByteOrder.BIG_ENDIAN); 12 | 13 | private final static VarHandle LONG_LE = 14 | MethodHandles.byteArrayViewVarHandle(long[].class, ByteOrder.LITTLE_ENDIAN); 15 | 16 | private final static VarHandle INT_BE = 17 | MethodHandles.byteArrayViewVarHandle(int[].class, ByteOrder.BIG_ENDIAN); 18 | 19 | private final static VarHandle INT_LE = 20 | MethodHandles.byteArrayViewVarHandle(int[].class, ByteOrder.LITTLE_ENDIAN); 21 | 22 | static void encodeSixBytes(byte[] src, byte[] dst, char[] lookup, int sp, int dp) { 23 | long bits = (long) LONG_BE.get(src, sp); 24 | 25 | dst[dp++] = (byte) lookup[(int) (bits >>> 58) & 0x3f]; 26 | dst[dp++] = (byte) lookup[(int) (bits >>> 52) & 0x3f]; 27 | dst[dp++] = (byte) lookup[(int) (bits >>> 46) & 0x3f]; 28 | dst[dp++] = (byte) lookup[(int) (bits >>> 40) & 0x3f]; 29 | dst[dp++] = (byte) lookup[(int) (bits >>> 34) & 0x3f]; 30 | dst[dp++] = (byte) lookup[(int) (bits >>> 28) & 0x3f]; 31 | dst[dp++] = (byte) lookup[(int) (bits >>> 22) & 0x3f]; 32 | dst[dp] = (byte) lookup[(int) (bits >>> 16) & 0x3f]; 33 | } 34 | 35 | static void encodeThreeBytes(byte[] src, byte[] dst, char[] lookup, int sp, int dp) { 36 | int bits = (int) INT_BE.get(src, sp); 37 | 38 | dst[dp++] = (byte) lookup[(bits >>> 26) & 0x3f]; 39 | dst[dp++] = (byte) lookup[(bits >>> 20) & 0x3f]; 40 | dst[dp++] = (byte) lookup[(bits >>> 14) & 0x3f]; 41 | dst[dp] = (byte) lookup[(bits >>> 8) & 0x3f]; 42 | } 43 | 44 | static void decodeFourBytes(byte[] src, byte[] dst, int[][] lookup, int sp, int dp) { 45 | int bits = lookup[0][src[sp++]] 46 | | lookup[1][src[sp++]] 47 | | lookup[2][src[sp++]] 48 | | lookup[3][src[sp]]; 49 | 50 | INT_LE.set(dst, dp, bits); 51 | } 52 | 53 | static void decodeFourBytesValidating(byte[] src, byte[] dst, int[][] lookup, int sp, int dp) { 54 | int osp = sp; 55 | 56 | int bits = lookup[0][src[sp++]] 57 | | lookup[1][src[sp++]] 58 | | lookup[2][src[sp++]] 59 | | lookup[3][src[sp]]; 60 | 61 | assertValidBase64(src, bits, osp); 62 | 63 | INT_LE.set(dst, dp, bits); 64 | } 65 | 66 | static void decodeEightBytes(byte[] src, byte[] dst, int[][] lookup, int sp, int dp) { 67 | long bits1 = lookup[0][src[sp++]] 68 | | lookup[1][src[sp++]] 69 | | lookup[2][src[sp++]] 70 | | lookup[3][src[sp++]]; 71 | 72 | long bits2 = lookup[0][src[sp++]] 73 | | lookup[1][src[sp++]] 74 | | lookup[2][src[sp++]] 75 | | lookup[3][src[sp]]; 76 | 77 | long bits = bits1 | (bits2 << 24); 78 | 79 | LONG_LE.set(dst, dp, bits); 80 | } 81 | 82 | static void decodeEightBytesValidating(byte[] src, byte[] dst, int[][] lookup, int sp, int dp) { 83 | int osp = sp; 84 | 85 | long bits1 = lookup[0][src[sp++]] 86 | | lookup[1][src[sp++]] 87 | | lookup[2][src[sp++]] 88 | | lookup[3][src[sp++]]; 89 | 90 | long bits2 = lookup[0][src[sp++]] 91 | | lookup[1][src[sp++]] 92 | | lookup[2][src[sp++]] 93 | | lookup[3][src[sp]]; 94 | 95 | assertValidBase64(src, (int) bits1, osp); 96 | assertValidBase64(src, (int) bits2, osp); 97 | 98 | long bits = bits1 | (bits2 << 24); 99 | 100 | LONG_LE.set(dst, dp, bits); 101 | } 102 | 103 | static int encodeLastByte(byte[] src, byte[] dst, char[] lookup, int sp, int dp) { 104 | int b0 = src[sp] & 0xff; 105 | 106 | dst[dp++] = (byte) lookup[b0 >> 2]; 107 | dst[dp++] = (byte) lookup[(b0 << 4) & 0x3f]; 108 | dst[dp++] = '='; 109 | dst[dp++] = '='; 110 | 111 | return dp; 112 | } 113 | 114 | static int encodeLastTwoBytes(byte[] src, byte[] dst, char[] lookup, int sp, int dp) { 115 | int b0 = src[sp++] & 0xff; 116 | int b1 = src[sp] & 0xff; 117 | 118 | dst[dp++] = (byte) lookup[b0 >> 2]; 119 | dst[dp++] = (byte) lookup[(b0 << 4) & 0x3f | (b1 >> 4)]; 120 | dst[dp++] = (byte) lookup[(b1 << 2) & 0x3f]; 121 | dst[dp++] = '='; 122 | 123 | return dp; 124 | } 125 | 126 | static int encodeLastThreeBytes(byte[] src, byte[] dst, char[] lookup, int sp, int dp) { 127 | int b0 = src[sp++] & 0xff; 128 | int b1 = src[sp++] & 0xff; 129 | int b2 = src[sp] & 0xff; 130 | 131 | dst[dp++] = (byte) lookup[b0 >> 2]; 132 | dst[dp++] = (byte) lookup[(b0 << 4) & 0x3f | (b1 >> 4)]; 133 | dst[dp++] = (byte) lookup[(b1 << 2) & 0x3f | (b2 >> 6)]; 134 | dst[dp++] = (byte) lookup[b2 & 0x3f]; 135 | 136 | return dp; 137 | } 138 | 139 | static int decodeLastFourBytes(byte[] src, byte[] dst, int[][] lookup, int sp, int dp) { 140 | int bits = lookup[0][src[sp++]] 141 | | lookup[1][src[sp++]] 142 | | lookup[2][src[sp++]] 143 | | lookup[3][src[sp]]; 144 | 145 | dst[dp++] = (byte) bits; 146 | dst[dp++] = (byte) (bits >> 8); 147 | dst[dp++] = (byte) (bits >> 16); 148 | 149 | return dp; 150 | } 151 | 152 | static int decodeLastThreeBytes(byte[] src, byte[] dst, int[][] lookup, int sp, int dp) { 153 | int bits = lookup[0][src[sp++]] 154 | | lookup[1][src[sp++]] 155 | | lookup[2][src[sp]]; 156 | 157 | dst[dp++] = (byte) bits; 158 | dst[dp++] = (byte) (bits >> 8); 159 | 160 | return dp; 161 | } 162 | 163 | static int decodeLastTwoBytes(byte[] src, byte[] dst, int[][] lookup, int sp, int dp) { 164 | int bits = lookup[0][src[sp++]] 165 | | lookup[1][src[sp]]; 166 | 167 | dst[dp++] = (byte) bits; 168 | 169 | return dp; 170 | } 171 | 172 | static int decodeLastFourBytesValidating(byte[] src, byte[] dst, int[][] lookup, int sp, int dp) { 173 | int osp = sp; 174 | 175 | int bits = lookup[0][src[sp++]] 176 | | lookup[1][src[sp++]] 177 | | lookup[2][src[sp++]] 178 | | lookup[3][src[sp]]; 179 | 180 | assertValidBase64(src, bits, osp); 181 | 182 | dst[dp++] = (byte) bits; 183 | dst[dp++] = (byte) (bits >> 8); 184 | dst[dp++] = (byte) (bits >> 16); 185 | 186 | return dp; 187 | } 188 | 189 | static int decodeLastThreeBytesValidating(byte[] src, byte[] dst, int[][] lookup, int sp, int dp) { 190 | int osp = sp; 191 | 192 | int bits = lookup[0][src[sp++]] 193 | | lookup[1][src[sp++]] 194 | | lookup[2][src[sp]]; 195 | 196 | assertValidBase64(src, bits, osp); 197 | 198 | dst[dp++] = (byte) bits; 199 | dst[dp++] = (byte) (bits >> 8); 200 | 201 | return dp; 202 | } 203 | 204 | static int decodeLastTwoBytesValidating(byte[] src, byte[] dst, int[][] lookup, int sp, int dp) { 205 | int osp = sp; 206 | 207 | int bits = lookup[0][src[sp++]] 208 | | lookup[1][src[sp]]; 209 | 210 | assertValidBase64(src, bits, osp); 211 | 212 | dst[dp++] = (byte) bits; 213 | 214 | return dp; 215 | } 216 | 217 | static int decodeLastThreeDestBytesMime(byte[] src, byte[] dst, int[][] lookup, int sp, int dp) { 218 | int bits = 0; 219 | for (int i = 0; i < 4;) { 220 | int b = lookup[i][src[sp++]]; 221 | 222 | if (b <= VALID_MAX) { 223 | bits |= b; 224 | i++; 225 | } 226 | } 227 | 228 | dst[dp++] = (byte) bits; 229 | dst[dp++] = (byte) (bits >> 8); 230 | dst[dp++] = (byte) (bits >> 16); 231 | 232 | return dp; 233 | } 234 | 235 | static int decodeLastTwoDestBytesMime(byte[] src, byte[] dst, int[][] lookup, int sp, int dp) { 236 | int bits = 0; 237 | for (int i = 0; i < 3;) { 238 | int b = lookup[i][src[sp++]]; 239 | 240 | if (b <= VALID_MAX) { 241 | bits |= b; 242 | i++; 243 | } 244 | } 245 | 246 | dst[dp++] = (byte) bits; 247 | dst[dp++] = (byte) (bits >> 8); 248 | 249 | return dp; 250 | } 251 | 252 | static int decodeLastDestByteMime(byte[] src, byte[] dst, int[][] lookup, int sp, int dp) { 253 | int bits = 0; 254 | for (int i = 0; i < 2;) { 255 | int b = lookup[i][src[sp++]]; 256 | 257 | if (b <= VALID_MAX) { 258 | bits |= b; 259 | i++; 260 | } 261 | } 262 | 263 | dst[dp++] = (byte) bits; 264 | 265 | return dp; 266 | } 267 | 268 | private static void assertValidBase64(byte[] src, int bits, int sp) { 269 | if (bits > VALID_MAX) { 270 | int ip = sp + Integer.numberOfLeadingZeros(bits) - 4; 271 | 272 | throw new IllegalArgumentException("Illegal base64 character " + Integer.toString(src[ip], 16) + " at position " + ip); 273 | } 274 | } 275 | } 276 | -------------------------------------------------------------------------------- /base64/src/main/java/com/joad/jdz/base64/vector/VectorDecoderVars.java: -------------------------------------------------------------------------------- 1 | package com.joad.jdz.base64.vector; 2 | 3 | import static com.joad.jdz.base64.Base64Tables.*; 4 | import static com.joad.jdz.base64.vector.VectorSpeciesSelection.*; 5 | 6 | import java.lang.invoke.MethodHandles; 7 | import java.lang.invoke.VarHandle; 8 | import java.nio.ByteOrder; 9 | import java.util.Arrays; 10 | import jdk.incubator.vector.ByteVector; 11 | 12 | class VectorDecoderVars { 13 | static final ByteVector SHIFT = ByteVector.fromArray(BYTE_SPECIES, new byte[] { 14 | 0, 0, 19, 4, -65, -65, -71, -71, 0, 0, 0, 0, 0, 0, 0, 0, 15 | 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 16 | 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 17 | 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}, 18 | 0); 19 | 20 | static final ByteVector SHIFT_URL = ByteVector.fromArray(BYTE_SPECIES, new byte[] { 21 | 0, 0, 17, 4, -65, -65, -71, -71, 0, 0, 0, 0, 0, 0, 0, 0, 22 | 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 23 | 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 24 | 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}, 25 | 0); 26 | 27 | 28 | static final ByteVector MASK = ByteVector.fromArray(BYTE_SPECIES, new byte[] { 29 | (byte) 0b10101000, 30 | (byte) 0b11111000, (byte) 0b11111000, (byte) 0b11111000, (byte) 0b11111000, 31 | (byte) 0b11111000, (byte) 0b11111000, (byte) 0b11111000, (byte) 0b11111000, 32 | (byte) 0b11111000, 33 | (byte) 0b11110000, 34 | (byte) 0b01010100, 35 | (byte) 0b01010000, (byte) 0b01010000, (byte) 0b01010000, 36 | (byte) 0b01010100, 37 | 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 38 | 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 39 | 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 40 | }, 0); 41 | 42 | static final ByteVector MASK_URL = ByteVector.fromArray(BYTE_SPECIES, new byte[] { 43 | (byte) 0b10101000, 44 | (byte) 0b11111000, (byte) 0b11111000, (byte) 0b11111000, (byte) 0b11111000, 45 | (byte) 0b11111000, (byte) 0b11111000, (byte) 0b11111000, (byte) 0b11111000, 46 | (byte) 0b11111000, 47 | (byte) 0b11110000, 48 | (byte) 0b01010000, 49 | (byte) 0b01010000, (byte) 0b01010100, (byte) 0b01010000, 50 | (byte) 0b01110000, 51 | 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 52 | 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 53 | 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 54 | }, 0); 55 | 56 | static final int[][] LOOKUP = new int[4][256]; 57 | 58 | static final int[][] LOOKUP_URL = new int[4][256]; 59 | 60 | final static VarHandle INT_LE = 61 | MethodHandles.byteArrayViewVarHandle(int[].class, ByteOrder.LITTLE_ENDIAN); 62 | 63 | static { 64 | for (int i = 0; i < 4; i++) { 65 | Arrays.fill(LOOKUP[i], 1 << (24 + 3 - i)); 66 | Arrays.fill(LOOKUP_URL[i], 1 << (24 + 3 - i)); 67 | } 68 | 69 | for (int i = 0; i < 64; i++) { 70 | LOOKUP[0][BASE64[i]] = i << 2; 71 | LOOKUP[1][BASE64[i]] = (i >> 4) | ((i & 0x0f) << 12); 72 | LOOKUP[2][BASE64[i]] = ((i & 0x3) << 22) | ((i & 0x3c) << 6); 73 | LOOKUP[3][BASE64[i]] = i << 16; 74 | 75 | LOOKUP_URL[0][BASE64_URL[i]] = i << 2; 76 | LOOKUP_URL[1][BASE64_URL[i]] = (i >> 4) | ((i & 0x0f) << 12); 77 | LOOKUP_URL[2][BASE64_URL[i]] = ((i & 0x3) << 22) | ((i & 0x3c) << 6); 78 | LOOKUP_URL[3][BASE64_URL[i]] = i << 16; 79 | } 80 | } 81 | 82 | static final int SPECIES_LENGTH = BYTE_SPECIES.length(); 83 | 84 | static final int SP_INC = SPECIES_LENGTH; 85 | 86 | static final int DP_INC = SP_INC / 4 * 3; 87 | 88 | static final byte SLASH_BYTE = (byte) '/'; 89 | 90 | static final byte SLASH_SWAP = (byte) 16; 91 | 92 | static final byte UNDERSCORE_BYTE = (byte) '_'; 93 | 94 | static final byte UNDERSCORE_SWAP = (byte) -32; 95 | 96 | static final int VALID_MAX = (1 << 24) - 1; 97 | 98 | static final int MOD4 = 3; 99 | } 100 | -------------------------------------------------------------------------------- /base64/src/main/java/com/joad/jdz/base64/vector/VectorEncoderVars.java: -------------------------------------------------------------------------------- 1 | package com.joad.jdz.base64.vector; 2 | 3 | import static com.joad.jdz.base64.vector.VectorSpeciesSelection.*; 4 | 5 | import jdk.incubator.vector.ByteVector; 6 | 7 | class VectorEncoderVars { 8 | static final ByteVector SHIFT = ByteVector.fromArray(BYTE_SPECIES, 9 | new byte[] {'A', '0' - 52, '0' - 52, '0' - 52, '0' - 52, '0' - 52, 10 | '0' - 52, '0' - 52, '0' - 52, '0' - 52, '0' - 52, '+' - 62, 11 | '/' - 63, 'a' - 26, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 12 | 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 13 | 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}, 0); 14 | 15 | static final ByteVector SHIFT_URL = ByteVector.fromArray(BYTE_SPECIES, 16 | new byte[] {'A', '0' - 52, '0' - 52, '0' - 52, '0' - 52, '0' - 52, 17 | '0' - 52, '0' - 52, '0' - 52, '0' - 52, '0' - 52, '-' - 62, 18 | '_' - 63, 'a' - 26, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 19 | 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 20 | 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}, 0); 21 | 22 | static final int SPECIES_LENGTH = BYTE_SPECIES.length(); 23 | 24 | static final int DP_INC = SPECIES_LENGTH; 25 | 26 | static final int SP_INC = DP_INC / 4 * 3; 27 | } 28 | -------------------------------------------------------------------------------- /base64/src/main/java/com/joad/jdz/base64/vector/VectorSpeciesSelection.java: -------------------------------------------------------------------------------- 1 | package com.joad.jdz.base64.vector; 2 | 3 | import java.util.HashMap; 4 | import java.util.Map; 5 | import jdk.incubator.vector.ByteVector; 6 | import jdk.incubator.vector.IntVector; 7 | import jdk.incubator.vector.VectorSpecies; 8 | 9 | class VectorSpeciesSelection { 10 | static final VectorSpecies BYTE_SPECIES; 11 | 12 | static final VectorSpecies INT_SPECIES; 13 | 14 | static { 15 | Map> BYTE_SPECIES_MAP = new HashMap<>(); 16 | 17 | Map> INT_SPECIES_MAP = new HashMap<>(); 18 | 19 | BYTE_SPECIES_MAP.put("128", ByteVector.SPECIES_128); 20 | BYTE_SPECIES_MAP.put("256", ByteVector.SPECIES_256); 21 | BYTE_SPECIES_MAP.put("512", ByteVector.SPECIES_512); 22 | 23 | INT_SPECIES_MAP.put("128", IntVector.SPECIES_128); 24 | INT_SPECIES_MAP.put("256", IntVector.SPECIES_256); 25 | INT_SPECIES_MAP.put("512", IntVector.SPECIES_512); 26 | 27 | String speciesLength = System.getProperty("jdz.vector.size"); 28 | 29 | if (speciesLength != null) { 30 | if (!BYTE_SPECIES_MAP.containsKey(speciesLength)) 31 | throw new ExceptionInInitializerError(speciesLength + " is not a valid vector size - please pick one of 128, 256 or 512"); 32 | 33 | BYTE_SPECIES = BYTE_SPECIES_MAP.get(speciesLength); 34 | 35 | INT_SPECIES = INT_SPECIES_MAP.get(speciesLength); 36 | } 37 | else { 38 | if (ByteVector.SPECIES_PREFERRED.equals(ByteVector.SPECIES_64)) { 39 | throw new ExceptionInInitializerError("Vectorized base64 encoding/decoding requires 128 or greater bit vector support - system preferred is 64."); 40 | } 41 | 42 | BYTE_SPECIES = ByteVector.SPECIES_PREFERRED; 43 | 44 | INT_SPECIES = IntVector.SPECIES_PREFERRED; 45 | } 46 | } 47 | } 48 | -------------------------------------------------------------------------------- /base64/src/main/java/com/joad/jdz/base64/vector/VectorUtils.java: -------------------------------------------------------------------------------- 1 | package com.joad.jdz.base64.vector; 2 | 3 | import static com.joad.jdz.base64.vector.VectorSpeciesSelection.*; 4 | import static com.joad.jdz.base64.vector.VectorDecoderVars.*; 5 | 6 | import jdk.incubator.vector.ByteVector; 7 | import jdk.incubator.vector.IntVector; 8 | import jdk.incubator.vector.ShortVector; 9 | import jdk.incubator.vector.VectorMask; 10 | import jdk.incubator.vector.VectorOperators; 11 | import jdk.incubator.vector.VectorShuffle; 12 | 13 | /* 14 | * The methods in this class are heavily inspired by the following articles by Wojciech Mula: 15 | * 16 | * http://0x80.pl/notesen/2016-01-12-sse-base64-encoding.html 17 | * http://0x80.pl/notesen/2016-01-17-sse-base64-decoding.html 18 | */ 19 | public class VectorUtils { 20 | private static final VectorShuffle ENC_SHUFFLE = VectorShuffle.fromArray(BYTE_SPECIES, new int[] 21 | {1, 0, 2, 1, 4, 3, 5, 4, 7, 6, 8, 7, 10, 9, 11, 10, 13, 12, 14, 13, 22 | 16, 15, 17, 16, 19, 18, 20, 19, 22, 21, 23, 22, 25, 24, 26, 25, 23 | 28, 27, 29, 28, 31, 30, 32, 31, 34, 33, 35, 34, 37, 36, 38, 37, 24 | 40, 39, 41, 40, 43, 42, 44, 43, 46, 45, 47, 46, 49, 48, 50, 49}, 25 | 0); 26 | 27 | private static final ShortVector AC_MASK = IntVector.broadcast(INT_SPECIES, 0x0fc0fc00).reinterpretAsShorts(); 28 | 29 | private static final ShortVector AC_SHIFT = IntVector.broadcast(INT_SPECIES, 0x0006000a).reinterpretAsShorts(); 30 | 31 | private static final ShortVector BD_MASK = IntVector.broadcast(INT_SPECIES, 0x003f03f0).reinterpretAsShorts(); 32 | 33 | private static final ShortVector BD_SHIFT = IntVector.broadcast(INT_SPECIES, 0x00080004).reinterpretAsShorts(); 34 | 35 | private static final VectorShuffle DEC_PACK = switch (BYTE_SPECIES.length()) { 36 | case 16 -> VectorShuffle.fromArray(BYTE_SPECIES, new int[] { 37 | 2, 1, 0, 6, 5, 4, 10, 9, 8, 14, 13, 12, 0, 0, 0, 0 38 | }, 0); 39 | 40 | case 32 -> VectorShuffle.fromArray(BYTE_SPECIES, new int[] { 41 | 2, 1, 0, 6, 5, 4, 10, 9, 8, 14, 13, 12, 18, 17, 16, 42 | 22, 21, 20, 26, 25, 24, 30, 29, 28, 43 | 0, 0, 0, 0, 0, 0, 0, 0 44 | }, 0); 45 | 46 | case 64 -> VectorShuffle.fromArray(BYTE_SPECIES, new int[] { 47 | 2, 1, 0, 6, 5, 4, 10, 9, 8, 14, 13, 12, 18, 17, 16, 48 | 22, 21, 20, 26, 25, 24, 30, 29, 28, 34, 33, 32, 38, 37, 36, 49 | 42, 41, 40, 46, 45, 44, 50, 49, 48, 54, 53, 52, 58, 57, 56, 50 | 62, 61, 60, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 51 | }, 0); 52 | 53 | default -> throw new ExceptionInInitializerError("Byte species length unsupported"); 54 | }; 55 | 56 | private static final ByteVector BIT_POS_LUT = ByteVector.fromArray(BYTE_SPECIES, new byte[] { 57 | 0x01, 0x02, 0x04, 0x08, 0x10, 0x20, 0x40, (byte) 0x80, 0, 0, 0, 0, 0, 0, 0, 0, 58 | 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 59 | 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 60 | 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 61 | }, 0); 62 | 63 | static void encodeBytesVectorized(byte[] src, byte[] dst, ByteVector shiftLookup, int sp, int dp) { 64 | ByteVector input = ByteVector.fromArray(BYTE_SPECIES, src, sp); 65 | ByteVector shuffled = input.rearrange(ENC_SHUFFLE); 66 | ShortVector shortShuf = shuffled.reinterpretAsShorts(); 67 | 68 | ShortVector ac = shortShuf.and(AC_MASK); 69 | ShortVector bd = shortShuf.and(BD_MASK); 70 | 71 | ShortVector acShifted = ac.lanewise(VectorOperators.LSHR, AC_SHIFT); 72 | ShortVector bdShifted = bd.lanewise(VectorOperators.LSHL, BD_SHIFT); 73 | 74 | ByteVector noLookupRes = bdShifted.or(acShifted).reinterpretAsBytes(); 75 | 76 | VectorMask lt26 = noLookupRes.lt((byte) 26); 77 | VectorMask lt52 = noLookupRes.lt((byte) 52); 78 | VectorMask thirteens = lt52.andNot(lt26); 79 | 80 | ByteVector subbed = noLookupRes.sub((byte) 51) 81 | .lanewise(VectorOperators.AND, 0x00, lt52) 82 | .blend((byte) 13, thirteens); 83 | 84 | ByteVector shifts = subbed.selectFrom(shiftLookup); 85 | 86 | ByteVector res = noLookupRes.add(shifts); 87 | 88 | res.intoArray(dst, dp); 89 | } 90 | 91 | static void decodeBytesVectorized(byte[] src, byte[] dst, ByteVector shiftLookup, byte swapKey, byte swapVal, int sp, int dp) { 92 | ByteVector input = ByteVector.fromArray(BYTE_SPECIES, src, sp); 93 | 94 | ByteVector higherNibble = input.lanewise(VectorOperators.LSHR, 4); 95 | 96 | ByteVector sh = higherNibble.selectFrom(shiftLookup); 97 | VectorMask eqSwap = input.eq(swapKey); 98 | ByteVector shift = sh.blend(swapVal, eqSwap); 99 | 100 | IntVector shifted = input.add(shift).reinterpretAsInts(); 101 | 102 | IntVector ca = shifted.and(0x003f003f); 103 | IntVector db = shifted.and(0x3f003f00); 104 | 105 | IntVector t0 = db.lanewise(VectorOperators.LSHR, 8).or(ca.lanewise(VectorOperators.LSHL, 6)); 106 | IntVector t1 = t0.lanewise(VectorOperators.LSHR, 16).or(t0.lanewise(VectorOperators.LSHL, 12)); 107 | 108 | ByteVector res = t1.reinterpretAsBytes().rearrange(DEC_PACK); 109 | 110 | res.intoArray(dst, dp); 111 | } 112 | 113 | static void decodeBytesVectorizedValidating(byte[] src, byte[] dst, ByteVector shiftLookup, ByteVector mask, byte swapKey, byte swapVal, int sp, int dp) { 114 | ByteVector input = ByteVector.fromArray(BYTE_SPECIES, src, sp); 115 | 116 | ByteVector higherNibble = input.lanewise(VectorOperators.LSHR, 4); 117 | ByteVector lowerNibble = input.and((byte) 0x0f); 118 | 119 | ByteVector sh = higherNibble.selectFrom(shiftLookup); 120 | VectorMask eqSwap = input.eq(swapKey); 121 | ByteVector shift = sh.blend(swapVal, eqSwap); 122 | 123 | ByteVector masked = lowerNibble.selectFrom(mask); 124 | ByteVector bit = higherNibble.selectFrom(BIT_POS_LUT); 125 | ByteVector maskedAndBit = masked.and(bit); 126 | 127 | boolean invalid = maskedAndBit.eq((byte) 0).anyTrue(); 128 | 129 | if (invalid) { 130 | int ip = sp + maskedAndBit.eq((byte) 0).firstTrue(); 131 | 132 | throw new IllegalArgumentException("Illegal base64 character " + Integer.toString(src[ip], 16) + " at position " + ip); 133 | } 134 | 135 | IntVector shifted = input.add(shift).reinterpretAsInts(); 136 | 137 | IntVector ca = shifted.and(0x003f003f); 138 | IntVector db = shifted.and(0x3f003f00); 139 | 140 | IntVector t0 = db.lanewise(VectorOperators.LSHR, 8).or(ca.lanewise(VectorOperators.LSHL, 6)); 141 | IntVector t1 = t0.lanewise(VectorOperators.LSHR, 16).or(t0.lanewise(VectorOperators.LSHL, 12)); 142 | 143 | ByteVector res = t1.reinterpretAsBytes().rearrange(DEC_PACK); 144 | 145 | res.intoArray(dst, dp); 146 | } 147 | 148 | static int decodeBytesVectorizedMime(byte[] src, byte[] dst, ByteVector shiftLookup, byte swapKey, byte swapVal, int sp, int dp) { 149 | ByteVector input = ByteVector.fromArray(BYTE_SPECIES, src, sp); 150 | 151 | ByteVector higherNibble = input.lanewise(VectorOperators.LSHR, 4); 152 | ByteVector lowerNibble = input.and((byte) 0x0f); 153 | 154 | ByteVector sh = higherNibble.selectFrom(shiftLookup); 155 | VectorMask eqSwap = input.eq(swapKey); 156 | ByteVector shift = sh.blend(swapVal, eqSwap); 157 | 158 | ByteVector masked = lowerNibble.selectFrom(MASK); 159 | ByteVector bit = higherNibble.selectFrom(BIT_POS_LUT); 160 | ByteVector maskedAndBit = masked.and(bit); 161 | 162 | int firstInvalid = maskedAndBit.eq((byte) 0).firstTrue(); 163 | 164 | IntVector shifted = input.add(shift).reinterpretAsInts(); 165 | 166 | IntVector ca = shifted.and(0x003f003f); 167 | IntVector db = shifted.and(0x3f003f00); 168 | 169 | IntVector t0 = db.lanewise(VectorOperators.LSHR, 8).or(ca.lanewise(VectorOperators.LSHL, 6)); 170 | IntVector t1 = t0.lanewise(VectorOperators.LSHR, 16).or(t0.lanewise(VectorOperators.LSHL, 12)); 171 | 172 | ByteVector res = t1.reinterpretAsBytes().rearrange(DEC_PACK); 173 | 174 | res.intoArray(dst, dp); 175 | 176 | return firstInvalid; 177 | } 178 | 179 | static int countInvalidBytesVectorized(byte[] src, int sp) { 180 | ByteVector input = ByteVector.fromArray(BYTE_SPECIES, src, sp); 181 | 182 | ByteVector higherNibble = input.lanewise(VectorOperators.LSHR, 4); 183 | ByteVector lowerNibble = input.and((byte) 0x0f); 184 | 185 | ByteVector masked = lowerNibble.selectFrom(MASK); 186 | ByteVector bit = higherNibble.selectFrom(BIT_POS_LUT); 187 | ByteVector maskedAndBit = masked.and(bit); 188 | 189 | int invalid = maskedAndBit.eq((byte) 0).trueCount(); 190 | 191 | return invalid; 192 | } 193 | } 194 | -------------------------------------------------------------------------------- /base64/src/main/java/module-info.java: -------------------------------------------------------------------------------- 1 | module com.joad.jdz.base64 { 2 | requires jdk.incubator.vector; 3 | exports com.joad.jdz.base64; 4 | } -------------------------------------------------------------------------------- /base64/src/test/java/com/joad/jdz/base64/dev/LengthFuzzTest.java: -------------------------------------------------------------------------------- 1 | package com.joad.jdz.base64.dev; 2 | 3 | import static org.junit.Assert.*; 4 | 5 | import java.util.Random; 6 | import org.junit.Test; 7 | 8 | public class LengthFuzzTest { 9 | @Test 10 | public void lengthFuzz() { 11 | // for (int i = 0; i < 1000; i++) { 12 | for (int i = 0; i < 100; i++) { 13 | byte[] randomData = new byte[i]; 14 | 15 | //System.out.println(i); 16 | new Random().nextBytes(randomData); 17 | 18 | // try{ 19 | byte[] randomDataEnc = java.util.Base64.getEncoder().encode(randomData); 20 | byte[] randomDataEncUrl = java.util.Base64.getUrlEncoder().encode(randomData); 21 | byte[] randomDataEncMime = java.util.Base64.getMimeEncoder().encode(randomData); 22 | 23 | String javaResEnc = new String(randomDataEnc); 24 | String javaResUrlEnc = new String(randomDataEncUrl); 25 | String javaResMimeEnc = new String(randomDataEncMime); 26 | 27 | String javaResDec = new String(java.util.Base64.getDecoder().decode(randomDataEnc)); 28 | String javaResUrlDec = new String(java.util.Base64.getUrlDecoder().decode(randomDataEncUrl)); 29 | String javaResMimeDec = new String(java.util.Base64.getMimeDecoder().decode(randomDataEncMime)); 30 | 31 | String jdzResScalarEnc = new String(com.joad.jdz.base64.scalar.Base64Scalar.getEncoder().encode(randomData)); 32 | String jdzResScalarUrlEnc = new String(com.joad.jdz.base64.scalar.Base64Scalar.getUrlEncoder().encode(randomData)); 33 | String jdzResScalarMimeEnc = new String(com.joad.jdz.base64.scalar.Base64Scalar.getMimeEncoder().encode(randomData)); 34 | 35 | String jdzResVectorEnc = new String(com.joad.jdz.base64.vector.Base64Vector.getEncoder().encode(randomData)); 36 | String jdzResVectorUrlEnc = new String(com.joad.jdz.base64.vector.Base64Vector.getUrlEncoder().encode(randomData)); 37 | String jdzResVectorMimeEnc = new String(com.joad.jdz.base64.vector.Base64Vector.getMimeEncoder().encode(randomData)); 38 | 39 | String jdzResScalarDec = new String(com.joad.jdz.base64.scalar.Base64Scalar.getDecoder().decode(randomDataEnc)); 40 | String jdzResScalarUrlDec = new String(com.joad.jdz.base64.scalar.Base64Scalar.getUrlDecoder().decode(randomDataEncUrl)); 41 | String jdzResScalarMimeDec = new String(com.joad.jdz.base64.scalar.Base64Scalar.getMimeDecoder().decode(randomDataEncMime)); 42 | String jdzResScalarFastMimeDec = new String(com.joad.jdz.base64.scalar.Base64Scalar.getMimeDecoder().decodeFast(randomDataEncMime)); 43 | 44 | String jdzResVectorDec = new String(com.joad.jdz.base64.vector.Base64Vector.getDecoder().decode(randomDataEnc)); 45 | String jdzResVectorUrlDec = new String(com.joad.jdz.base64.vector.Base64Vector.getUrlDecoder().decode(randomDataEncUrl)); 46 | String jdzResVectorMimeDec = new String(com.joad.jdz.base64.vector.Base64Vector.getMimeDecoder().decode(randomDataEncMime)); 47 | String jdzResVectorFastMimeDec = new String(com.joad.jdz.base64.vector.Base64Vector.getMimeDecoder().decodeFast(randomDataEncMime)); 48 | 49 | assertEquals("scalarEnc", javaResEnc, jdzResScalarEnc); 50 | assertEquals("scalarUrlEnc", javaResUrlEnc, jdzResScalarUrlEnc); 51 | assertEquals("scalarMimeEnc", javaResMimeEnc, jdzResScalarMimeEnc); 52 | 53 | assertEquals("vectorEnc", javaResEnc, jdzResVectorEnc); 54 | assertEquals("vectorUrlEnc", javaResUrlEnc, jdzResVectorUrlEnc); 55 | assertEquals("vectorMimeEnc", javaResMimeEnc, jdzResVectorMimeEnc); 56 | 57 | assertEquals("scalarDec", javaResDec, jdzResScalarDec); 58 | assertEquals("scalarUrlDec", javaResUrlDec, jdzResScalarUrlDec); 59 | assertEquals("scalarMimeDec", javaResMimeDec, jdzResScalarMimeDec); 60 | assertEquals("scalarFastMimeDec", javaResMimeDec, jdzResScalarFastMimeDec); 61 | 62 | assertEquals("vectorDec", javaResDec, jdzResVectorDec); 63 | assertEquals("vectorUrlDec", javaResUrlDec, jdzResVectorUrlDec); 64 | assertEquals("vectorMimeDec", javaResMimeDec, jdzResVectorMimeDec); 65 | assertEquals("vectorFastMimeDec", javaResMimeDec, jdzResVectorFastMimeDec); 66 | // } catch (Exception e) {e.printStackTrace(); System.exit(0);} 67 | } 68 | } 69 | } 70 | -------------------------------------------------------------------------------- /base64/src/test/java/com/joad/jdz/base64/scalar/RFC2045FastScalarDecodeTest.java: -------------------------------------------------------------------------------- 1 | package com.joad.jdz.base64.scalar; 2 | 3 | import static org.junit.Assert.*; 4 | 5 | import java.util.Random; 6 | import org.junit.Test; 7 | 8 | public class RFC2045FastScalarDecodeTest { 9 | /* 10 | * RFC2045 test vectors 11 | */ 12 | private static final byte[] emptyVector = "".getBytes(); 13 | private static final byte[] fVector = "Zg==".getBytes(); 14 | private static final byte[] foVector = "Zm8=".getBytes(); 15 | private static final byte[] fooVector = "Zm9v".getBytes(); 16 | private static final byte[] foobVector = "Zm9vYg==".getBytes(); 17 | private static final byte[] foobaVector = "Zm9vYmE=".getBytes(); 18 | private static final byte[] foobarVector = "Zm9vYmFy".getBytes(); 19 | 20 | /* 21 | * Random data fuzz 22 | */ 23 | private static final byte[] randomDataZeroMod = new byte[1000]; 24 | private static final byte[] randomDataOneMod = new byte[1001]; 25 | private static final byte[] randomDataTwoMod = new byte[1002]; 26 | private static final byte[] randomDataThreeMod = new byte[1003]; 27 | private static final byte[] randomDataSixtyOne = new byte[61]; 28 | 29 | static { 30 | new Random().nextBytes(randomDataZeroMod); 31 | new Random().nextBytes(randomDataOneMod); 32 | new Random().nextBytes(randomDataTwoMod); 33 | new Random().nextBytes(randomDataThreeMod); 34 | new Random().nextBytes(randomDataSixtyOne); 35 | } 36 | 37 | private static final byte[] base64RandomDataZeroMod = java.util.Base64.getMimeEncoder().encode(randomDataZeroMod); 38 | private static final byte[] base64RandomDataOneMod = java.util.Base64.getMimeEncoder().encode(randomDataOneMod); 39 | private static final byte[] base64RandomDataTwoMod = java.util.Base64.getMimeEncoder().encode(randomDataTwoMod); 40 | private static final byte[] base64RandomDataThreeMod = java.util.Base64.getMimeEncoder().encode(randomDataThreeMod); 41 | private static final byte[] base64RandomDataSixtyOne = java.util.Base64.getMimeEncoder().encode(randomDataSixtyOne); 42 | 43 | @Test 44 | public void RFC2045DecodeEmptyVector() { 45 | String jdzRes = new String(com.joad.jdz.base64.scalar.Base64Scalar.getMimeDecoder().decodeFast(emptyVector)); 46 | 47 | assertEquals("", jdzRes); 48 | } 49 | 50 | @Test 51 | public void RFC2045DecodefVector() { 52 | String jdzRes = new String(com.joad.jdz.base64.scalar.Base64Scalar.getMimeDecoder().decodeFast(fVector)); 53 | 54 | assertEquals("f", jdzRes); 55 | } 56 | 57 | @Test 58 | public void RFC2045DecodefoVector() { 59 | String jdzRes = new String(com.joad.jdz.base64.scalar.Base64Scalar.getMimeDecoder().decodeFast(foVector)); 60 | 61 | assertEquals("fo", jdzRes); 62 | } 63 | 64 | @Test 65 | public void RFC2045DecodefooVector() { 66 | String jdzRes = new String(com.joad.jdz.base64.scalar.Base64Scalar.getMimeDecoder().decodeFast(fooVector)); 67 | 68 | assertEquals("foo", jdzRes); 69 | } 70 | 71 | @Test 72 | public void RFC2045DecodefoobVector() { 73 | String jdzRes = new String(com.joad.jdz.base64.scalar.Base64Scalar.getMimeDecoder().decodeFast(foobVector)); 74 | 75 | assertEquals("foob", jdzRes); 76 | } 77 | 78 | @Test 79 | public void RFC2045DecodefoobaVector() { 80 | String jdzRes = new String(com.joad.jdz.base64.scalar.Base64Scalar.getMimeDecoder().decodeFast(foobaVector)); 81 | 82 | assertEquals("fooba", jdzRes); 83 | } 84 | 85 | @Test 86 | public void RFC2045DecodefoobarVector() { 87 | String jdzRes = new String(com.joad.jdz.base64.scalar.Base64Scalar.getMimeDecoder().decodeFast(foobarVector)); 88 | 89 | assertEquals("foobar", jdzRes); 90 | } 91 | 92 | @Test 93 | public void RFC2045DecodeZeroMod() { 94 | String javaRes = new String(java.util.Base64.getMimeDecoder().decode(base64RandomDataZeroMod)); 95 | String jdzRes = new String(com.joad.jdz.base64.scalar.Base64Scalar.getMimeDecoder().decodeFast(base64RandomDataZeroMod)); 96 | 97 | assertEquals(javaRes, jdzRes); 98 | } 99 | 100 | @Test 101 | public void RFC2045DecodeOneMod() { 102 | String javaRes = new String(java.util.Base64.getMimeDecoder().decode(base64RandomDataOneMod)); 103 | String jdzRes = new String(com.joad.jdz.base64.scalar.Base64Scalar.getMimeDecoder().decodeFast(base64RandomDataOneMod)); 104 | 105 | assertEquals(javaRes, jdzRes); 106 | } 107 | 108 | @Test 109 | public void RFC2045DecodeTwoMod() { 110 | String javaRes = new String(java.util.Base64.getMimeDecoder().decode(base64RandomDataTwoMod)); 111 | String jdzRes = new String(com.joad.jdz.base64.scalar.Base64Scalar.getMimeDecoder().decodeFast(base64RandomDataTwoMod)); 112 | 113 | assertEquals(javaRes, jdzRes); 114 | } 115 | 116 | @Test 117 | public void RFC2045DecodeThreeMod() { 118 | String javaRes = new String(java.util.Base64.getMimeDecoder().decode(base64RandomDataThreeMod)); 119 | String jdzRes = new String(com.joad.jdz.base64.scalar.Base64Scalar.getMimeDecoder().decodeFast(base64RandomDataThreeMod)); 120 | 121 | assertEquals(javaRes, jdzRes); 122 | } 123 | 124 | @Test 125 | public void RFC2045DecodeSixtyOne() { 126 | String javaRes = new String(java.util.Base64.getMimeDecoder().decode(base64RandomDataSixtyOne)); 127 | String jdzRes = new String(com.joad.jdz.base64.scalar.Base64Scalar.getMimeDecoder().decodeFast(base64RandomDataSixtyOne)); 128 | 129 | assertEquals(javaRes, jdzRes); 130 | } 131 | } 132 | -------------------------------------------------------------------------------- /base64/src/test/java/com/joad/jdz/base64/scalar/RFC2045ScalarDecodeTest.java: -------------------------------------------------------------------------------- 1 | package com.joad.jdz.base64.scalar; 2 | 3 | import static org.junit.Assert.*; 4 | 5 | import java.util.Random; 6 | import org.junit.Test; 7 | 8 | public class RFC2045ScalarDecodeTest { 9 | /* 10 | * RFC2045 test vectors 11 | */ 12 | private static final byte[] emptyVector = "".getBytes(); 13 | private static final byte[] fVector = "Zg==".getBytes(); 14 | private static final byte[] foVector = "Zm8=".getBytes(); 15 | private static final byte[] fooVector = "Zm9v".getBytes(); 16 | private static final byte[] foobVector = "Zm9vYg==".getBytes(); 17 | private static final byte[] foobaVector = "Zm9vYmE=".getBytes(); 18 | private static final byte[] foobarVector = "Zm9vYmFy".getBytes(); 19 | 20 | /* 21 | * Random data fuzz 22 | */ 23 | private static final byte[] randomDataZeroMod = new byte[1000]; 24 | private static final byte[] randomDataOneMod = new byte[1001]; 25 | private static final byte[] randomDataTwoMod = new byte[1002]; 26 | private static final byte[] randomDataThreeMod = new byte[1003]; 27 | private static final byte[] randomDataSixtyOne = new byte[61]; 28 | 29 | static { 30 | new Random().nextBytes(randomDataZeroMod); 31 | new Random().nextBytes(randomDataOneMod); 32 | new Random().nextBytes(randomDataTwoMod); 33 | new Random().nextBytes(randomDataThreeMod); 34 | new Random().nextBytes(randomDataSixtyOne); 35 | } 36 | 37 | private static final byte[] base64RandomDataZeroMod = java.util.Base64.getMimeEncoder().encode(randomDataZeroMod); 38 | private static final byte[] base64RandomDataOneMod = java.util.Base64.getMimeEncoder().encode(randomDataOneMod); 39 | private static final byte[] base64RandomDataTwoMod = java.util.Base64.getMimeEncoder().encode(randomDataTwoMod); 40 | private static final byte[] base64RandomDataThreeMod = java.util.Base64.getMimeEncoder().encode(randomDataThreeMod); 41 | private static final byte[] base64RandomDataSixtyOne = java.util.Base64.getMimeEncoder().encode(randomDataSixtyOne); 42 | 43 | @Test 44 | public void RFC2045DecodeEmptyVector() { 45 | String jdzRes = new String(com.joad.jdz.base64.scalar.Base64Scalar.getMimeDecoder().decode(emptyVector)); 46 | 47 | assertEquals("", jdzRes); 48 | } 49 | 50 | @Test 51 | public void RFC2045DecodefVector() { 52 | String jdzRes = new String(com.joad.jdz.base64.scalar.Base64Scalar.getMimeDecoder().decode(fVector)); 53 | 54 | assertEquals("f", jdzRes); 55 | } 56 | 57 | @Test 58 | public void RFC2045DecodefoVector() { 59 | String jdzRes = new String(com.joad.jdz.base64.scalar.Base64Scalar.getMimeDecoder().decode(foVector)); 60 | 61 | assertEquals("fo", jdzRes); 62 | } 63 | 64 | @Test 65 | public void RFC2045DecodefooVector() { 66 | String jdzRes = new String(com.joad.jdz.base64.scalar.Base64Scalar.getMimeDecoder().decode(fooVector)); 67 | 68 | assertEquals("foo", jdzRes); 69 | } 70 | 71 | @Test 72 | public void RFC2045DecodefoobVector() { 73 | String jdzRes = new String(com.joad.jdz.base64.scalar.Base64Scalar.getMimeDecoder().decode(foobVector)); 74 | 75 | assertEquals("foob", jdzRes); 76 | } 77 | 78 | @Test 79 | public void RFC2045DecodefoobaVector() { 80 | String jdzRes = new String(com.joad.jdz.base64.scalar.Base64Scalar.getMimeDecoder().decode(foobaVector)); 81 | 82 | assertEquals("fooba", jdzRes); 83 | } 84 | 85 | @Test 86 | public void RFC2045DecodefoobarVector() { 87 | String jdzRes = new String(com.joad.jdz.base64.scalar.Base64Scalar.getMimeDecoder().decode(foobarVector)); 88 | 89 | assertEquals("foobar", jdzRes); 90 | } 91 | 92 | @Test 93 | public void RFC2045DecodeZeroMod() { 94 | String javaRes = new String(java.util.Base64.getMimeDecoder().decode(base64RandomDataZeroMod)); 95 | String jdzRes = new String(com.joad.jdz.base64.scalar.Base64Scalar.getMimeDecoder().decode(base64RandomDataZeroMod)); 96 | 97 | assertEquals(javaRes, jdzRes); 98 | } 99 | 100 | @Test 101 | public void RFC2045DecodeOneMod() { 102 | String javaRes = new String(java.util.Base64.getMimeDecoder().decode(base64RandomDataOneMod)); 103 | String jdzRes = new String(com.joad.jdz.base64.scalar.Base64Scalar.getMimeDecoder().decode(base64RandomDataOneMod)); 104 | 105 | assertEquals(javaRes, jdzRes); 106 | } 107 | 108 | @Test 109 | public void RFC2045DecodeTwoMod() { 110 | String javaRes = new String(java.util.Base64.getMimeDecoder().decode(base64RandomDataTwoMod)); 111 | String jdzRes = new String(com.joad.jdz.base64.scalar.Base64Scalar.getMimeDecoder().decode(base64RandomDataTwoMod)); 112 | 113 | assertEquals(javaRes, jdzRes); 114 | } 115 | 116 | @Test 117 | public void RFC2045DecodeThreeMod() { 118 | String javaRes = new String(java.util.Base64.getMimeDecoder().decode(base64RandomDataThreeMod)); 119 | String jdzRes = new String(com.joad.jdz.base64.scalar.Base64Scalar.getMimeDecoder().decode(base64RandomDataThreeMod)); 120 | 121 | assertEquals(javaRes, jdzRes); 122 | } 123 | 124 | @Test 125 | public void RFC2045DecodeSixtyOne() { 126 | String javaRes = new String(java.util.Base64.getMimeDecoder().decode(base64RandomDataSixtyOne)); 127 | String jdzRes = new String(com.joad.jdz.base64.scalar.Base64Scalar.getMimeDecoder().decode(base64RandomDataSixtyOne)); 128 | 129 | assertEquals(javaRes, jdzRes); 130 | } 131 | } 132 | -------------------------------------------------------------------------------- /base64/src/test/java/com/joad/jdz/base64/scalar/RFC2045ScalarEncodeTest.java: -------------------------------------------------------------------------------- 1 | package com.joad.jdz.base64.scalar; 2 | 3 | import static org.junit.Assert.*; 4 | 5 | import java.util.Random; 6 | import org.junit.Test; 7 | 8 | public class RFC2045ScalarEncodeTest { 9 | /* 10 | * RFC2045 test vectors 11 | */ 12 | private static final byte[] emptyVector = "".getBytes(); 13 | private static final byte[] fVector = "f".getBytes(); 14 | private static final byte[] foVector = "fo".getBytes(); 15 | private static final byte[] fooVector = "foo".getBytes(); 16 | private static final byte[] foobVector = "foob".getBytes(); 17 | private static final byte[] foobaVector = "fooba".getBytes(); 18 | private static final byte[] foobarVector = "foobar".getBytes(); 19 | 20 | /* 21 | * Random data fuzz 22 | */ 23 | private static final byte[] randomDataZeroMod = new byte[1000]; 24 | private static final byte[] randomDataOneMod = new byte[1001]; 25 | private static final byte[] randomDataTwoMod = new byte[1002]; 26 | private static final byte[] randomDataThreeMod = new byte[1003]; 27 | private static final byte[] randomDataSeventySix = new byte[55]; 28 | 29 | static { 30 | new Random().nextBytes(randomDataZeroMod); 31 | new Random().nextBytes(randomDataOneMod); 32 | new Random().nextBytes(randomDataTwoMod); 33 | new Random().nextBytes(randomDataThreeMod); 34 | new Random().nextBytes(randomDataSeventySix); 35 | } 36 | 37 | @Test 38 | public void RFC2045EncodeEmptyVector() { 39 | String jdzRes = new String(com.joad.jdz.base64.scalar.Base64Scalar.getMimeEncoder().encode(emptyVector)); 40 | 41 | assertEquals("", jdzRes); 42 | } 43 | 44 | @Test 45 | public void RFC2045EncodefVector() { 46 | String jdzRes = new String(com.joad.jdz.base64.scalar.Base64Scalar.getMimeEncoder().encode(fVector)); 47 | 48 | assertEquals("Zg==", jdzRes); 49 | } 50 | 51 | @Test 52 | public void RFC2045EncodefoVector() { 53 | String jdzRes = new String(com.joad.jdz.base64.scalar.Base64Scalar.getMimeEncoder().encode(foVector)); 54 | 55 | assertEquals("Zm8=", jdzRes); 56 | } 57 | 58 | @Test 59 | public void RFC2045EncodefooVector() { 60 | String jdzRes = new String(com.joad.jdz.base64.scalar.Base64Scalar.getMimeEncoder().encode(fooVector)); 61 | 62 | assertEquals("Zm9v", jdzRes); 63 | } 64 | 65 | @Test 66 | public void RFC2045EncodefoobVector() { 67 | String jdzRes = new String(com.joad.jdz.base64.scalar.Base64Scalar.getMimeEncoder().encode(foobVector)); 68 | 69 | assertEquals("Zm9vYg==", jdzRes); 70 | } 71 | 72 | @Test 73 | public void RFC2045EncodefoobaVector() { 74 | String jdzRes = new String(com.joad.jdz.base64.scalar.Base64Scalar.getMimeEncoder().encode(foobaVector)); 75 | 76 | assertEquals("Zm9vYmE=", jdzRes); 77 | } 78 | 79 | @Test 80 | public void RFC2045EncodefoobarVector() { 81 | String jdzRes = new String(com.joad.jdz.base64.scalar.Base64Scalar.getMimeEncoder().encode(foobarVector)); 82 | 83 | assertEquals("Zm9vYmFy", jdzRes); 84 | } 85 | @Test 86 | public void RFC2045EncodeZeroMod() { 87 | String javaRes = new String(java.util.Base64.getMimeEncoder().encode(randomDataZeroMod)); 88 | String joadRes = new String(com.joad.jdz.base64.scalar.Base64Scalar.getMimeEncoder().encode(randomDataZeroMod)); 89 | 90 | assertEquals(javaRes, joadRes); 91 | } 92 | 93 | @Test 94 | public void RFC2045EncodeOneMod() { 95 | String javaRes = new String(java.util.Base64.getMimeEncoder().encode(randomDataOneMod)); 96 | String joadRes = new String(com.joad.jdz.base64.scalar.Base64Scalar.getMimeEncoder().encode(randomDataOneMod)); 97 | 98 | assertEquals(javaRes, joadRes); 99 | } 100 | 101 | @Test 102 | public void RFC2045EncodeTwoMod() { 103 | String javaRes = new String(java.util.Base64.getMimeEncoder().encode(randomDataTwoMod)); 104 | String joadRes = new String(com.joad.jdz.base64.scalar.Base64Scalar.getMimeEncoder().encode(randomDataTwoMod)); 105 | 106 | assertEquals(javaRes, joadRes); 107 | } 108 | 109 | @Test 110 | public void RFC2045EncodeThreeMod() { 111 | String javaRes = new String(java.util.Base64.getMimeEncoder().encode(randomDataThreeMod)); 112 | String joadRes = new String(com.joad.jdz.base64.scalar.Base64Scalar.getMimeEncoder().encode(randomDataThreeMod)); 113 | 114 | assertEquals(javaRes, joadRes); 115 | } 116 | 117 | @Test 118 | public void RFC2045EncodeSeventySix() { 119 | String javaRes = new String(java.util.Base64.getMimeEncoder().encode(randomDataSeventySix)); 120 | String joadRes = new String(com.joad.jdz.base64.scalar.Base64Scalar.getMimeEncoder().encode(randomDataSeventySix)); 121 | 122 | assertEquals(javaRes, joadRes); 123 | } 124 | } -------------------------------------------------------------------------------- /base64/src/test/java/com/joad/jdz/base64/scalar/RFC4648FastScalarDecodeTest.java: -------------------------------------------------------------------------------- 1 | package com.joad.jdz.base64.scalar; 2 | 3 | import static org.junit.Assert.*; 4 | 5 | import java.util.Random; 6 | import org.junit.Test; 7 | 8 | public class RFC4648FastScalarDecodeTest { 9 | /* 10 | * RFC4648 test vectors 11 | */ 12 | private static final byte[] emptyVector = "".getBytes(); 13 | private static final byte[] fVector = "Zg==".getBytes(); 14 | private static final byte[] foVector = "Zm8=".getBytes(); 15 | private static final byte[] fooVector = "Zm9v".getBytes(); 16 | private static final byte[] foobVector = "Zm9vYg==".getBytes(); 17 | private static final byte[] foobaVector = "Zm9vYmE=".getBytes(); 18 | private static final byte[] foobarVector = "Zm9vYmFy".getBytes(); 19 | 20 | /* 21 | * Random data fuzz 22 | */ 23 | private static final byte[] randomDataZeroMod = new byte[1000]; 24 | private static final byte[] randomDataOneMod = new byte[1001]; 25 | private static final byte[] randomDataTwoMod = new byte[1002]; 26 | private static final byte[] randomDataThreeMod = new byte[1003]; 27 | 28 | static { 29 | new Random().nextBytes(randomDataZeroMod); 30 | new Random().nextBytes(randomDataOneMod); 31 | new Random().nextBytes(randomDataTwoMod); 32 | new Random().nextBytes(randomDataThreeMod); 33 | } 34 | 35 | private static final byte[] base64RandomDataZeroMod = java.util.Base64.getEncoder().encode(randomDataZeroMod); 36 | private static final byte[] base64RandomDataOneMod = java.util.Base64.getEncoder().encode(randomDataOneMod); 37 | private static final byte[] base64RandomDataTwoMod = java.util.Base64.getEncoder().encode(randomDataTwoMod); 38 | private static final byte[] base64RandomDataThreeMod = java.util.Base64.getEncoder().encode(randomDataThreeMod); 39 | 40 | @Test 41 | public void RFC4648DecodeEmptyVector() { 42 | String jdzRes = new String(com.joad.jdz.base64.scalar.Base64Scalar.getDecoder().decodeFast(emptyVector)); 43 | 44 | assertEquals("", jdzRes); 45 | } 46 | 47 | @Test 48 | public void RFC4648DecodefVector() { 49 | String jdzRes = new String(com.joad.jdz.base64.scalar.Base64Scalar.getDecoder().decodeFast(fVector)); 50 | 51 | assertEquals("f", jdzRes); 52 | } 53 | 54 | @Test 55 | public void RFC4648DecodefoVector() { 56 | String jdzRes = new String(com.joad.jdz.base64.scalar.Base64Scalar.getDecoder().decodeFast(foVector)); 57 | 58 | assertEquals("fo", jdzRes); 59 | } 60 | 61 | @Test 62 | public void RFC4648DecodefooVector() { 63 | String jdzRes = new String(com.joad.jdz.base64.scalar.Base64Scalar.getDecoder().decodeFast(fooVector)); 64 | 65 | assertEquals("foo", jdzRes); 66 | } 67 | 68 | @Test 69 | public void RFC4648DecodefoobVector() { 70 | String jdzRes = new String(com.joad.jdz.base64.scalar.Base64Scalar.getDecoder().decodeFast(foobVector)); 71 | 72 | assertEquals("foob", jdzRes); 73 | } 74 | 75 | @Test 76 | public void RFC4648DecodefoobaVector() { 77 | String jdzRes = new String(com.joad.jdz.base64.scalar.Base64Scalar.getDecoder().decodeFast(foobaVector)); 78 | 79 | assertEquals("fooba", jdzRes); 80 | } 81 | 82 | @Test 83 | public void RFC4648DecodefoobarVector() { 84 | String jdzRes = new String(com.joad.jdz.base64.scalar.Base64Scalar.getDecoder().decodeFast(foobarVector)); 85 | 86 | assertEquals("foobar", jdzRes); 87 | } 88 | 89 | @Test 90 | public void RFC4648DecodeZeroMod() { 91 | String javaRes = new String(java.util.Base64.getDecoder().decode(base64RandomDataZeroMod)); 92 | String jdzRes = new String(com.joad.jdz.base64.scalar.Base64Scalar.getDecoder().decodeFast(base64RandomDataZeroMod)); 93 | 94 | assertEquals(javaRes, jdzRes); 95 | } 96 | 97 | @Test 98 | public void RFC4648DecodeOneMod() { 99 | String javaRes = new String(java.util.Base64.getDecoder().decode(base64RandomDataOneMod)); 100 | String jdzRes = new String(com.joad.jdz.base64.scalar.Base64Scalar.getDecoder().decodeFast(base64RandomDataOneMod)); 101 | 102 | assertEquals(javaRes, jdzRes); 103 | } 104 | 105 | @Test 106 | public void RFC4648DecodeTwoMod() { 107 | String javaRes = new String(java.util.Base64.getDecoder().decode(base64RandomDataTwoMod)); 108 | String jdzRes = new String(com.joad.jdz.base64.scalar.Base64Scalar.getDecoder().decodeFast(base64RandomDataTwoMod)); 109 | 110 | assertEquals(javaRes, jdzRes); 111 | } 112 | 113 | @Test 114 | public void RFC4648DecodeThreeMod() { 115 | String javaRes = new String(java.util.Base64.getDecoder().decode(base64RandomDataThreeMod)); 116 | String jdzRes = new String(com.joad.jdz.base64.scalar.Base64Scalar.getDecoder().decodeFast(base64RandomDataThreeMod)); 117 | 118 | assertEquals(javaRes, jdzRes); 119 | } 120 | } 121 | -------------------------------------------------------------------------------- /base64/src/test/java/com/joad/jdz/base64/scalar/RFC4648ScalarDecodeTest.java: -------------------------------------------------------------------------------- 1 | package com.joad.jdz.base64.scalar; 2 | 3 | import static org.junit.Assert.*; 4 | 5 | import java.util.Random; 6 | import org.junit.Test; 7 | 8 | public class RFC4648ScalarDecodeTest { 9 | /* 10 | * RFC4648 test vectors 11 | */ 12 | private static final byte[] emptyVector = "".getBytes(); 13 | private static final byte[] fVector = "Zg==".getBytes(); 14 | private static final byte[] foVector = "Zm8=".getBytes(); 15 | private static final byte[] fooVector = "Zm9v".getBytes(); 16 | private static final byte[] foobVector = "Zm9vYg==".getBytes(); 17 | private static final byte[] foobaVector = "Zm9vYmE=".getBytes(); 18 | private static final byte[] foobarVector = "Zm9vYmFy".getBytes(); 19 | 20 | /* 21 | * Random data fuzz 22 | */ 23 | private static final byte[] randomDataZeroMod = new byte[1000]; 24 | private static final byte[] randomDataOneMod = new byte[1001]; 25 | private static final byte[] randomDataTwoMod = new byte[1002]; 26 | private static final byte[] randomDataThreeMod = new byte[1003]; 27 | 28 | static { 29 | new Random().nextBytes(randomDataZeroMod); 30 | new Random().nextBytes(randomDataOneMod); 31 | new Random().nextBytes(randomDataTwoMod); 32 | new Random().nextBytes(randomDataThreeMod); 33 | } 34 | 35 | private static final byte[] base64RandomDataZeroMod = java.util.Base64.getEncoder().encode(randomDataZeroMod); 36 | private static final byte[] base64RandomDataOneMod = java.util.Base64.getEncoder().encode(randomDataOneMod); 37 | private static final byte[] base64RandomDataTwoMod = java.util.Base64.getEncoder().encode(randomDataTwoMod); 38 | private static final byte[] base64RandomDataThreeMod = java.util.Base64.getEncoder().encode(randomDataThreeMod); 39 | private static final byte[] base64InvalidData = java.util.Base64.getEncoder().encode(randomDataZeroMod); 40 | 41 | @Test 42 | public void RFC4648DecodeEmptyVector() { 43 | String jdzRes = new String(com.joad.jdz.base64.scalar.Base64Scalar.getDecoder().decode(emptyVector)); 44 | 45 | assertEquals("", jdzRes); 46 | } 47 | 48 | @Test 49 | public void RFC4648DecodefVector() { 50 | String jdzRes = new String(com.joad.jdz.base64.scalar.Base64Scalar.getDecoder().decode(fVector)); 51 | 52 | assertEquals("f", jdzRes); 53 | } 54 | 55 | @Test 56 | public void RFC4648DecodefoVector() { 57 | String jdzRes = new String(com.joad.jdz.base64.scalar.Base64Scalar.getDecoder().decode(foVector)); 58 | 59 | assertEquals("fo", jdzRes); 60 | } 61 | 62 | @Test 63 | public void RFC4648DecodefooVector() { 64 | String jdzRes = new String(com.joad.jdz.base64.scalar.Base64Scalar.getDecoder().decode(fooVector)); 65 | 66 | assertEquals("foo", jdzRes); 67 | } 68 | 69 | @Test 70 | public void RFC4648DecodefoobVector() { 71 | String jdzRes = new String(com.joad.jdz.base64.scalar.Base64Scalar.getDecoder().decode(foobVector)); 72 | 73 | assertEquals("foob", jdzRes); 74 | } 75 | 76 | @Test 77 | public void RFC4648DecodefoobaVector() { 78 | String jdzRes = new String(com.joad.jdz.base64.scalar.Base64Scalar.getDecoder().decode(foobaVector)); 79 | 80 | assertEquals("fooba", jdzRes); 81 | } 82 | 83 | @Test 84 | public void RFC4648DecodefoobarVector() { 85 | String jdzRes = new String(com.joad.jdz.base64.scalar.Base64Scalar.getDecoder().decode(foobarVector)); 86 | 87 | assertEquals("foobar", jdzRes); 88 | } 89 | 90 | @Test 91 | public void RFC4648DecodeZeroMod() { 92 | String javaRes = new String(java.util.Base64.getDecoder().decode(base64RandomDataZeroMod)); 93 | String jdzRes = new String(com.joad.jdz.base64.scalar.Base64Scalar.getDecoder().decode(base64RandomDataZeroMod)); 94 | 95 | assertEquals(javaRes, jdzRes); 96 | } 97 | 98 | @Test 99 | public void RFC4648DecodeOneMod() { 100 | String javaRes = new String(java.util.Base64.getDecoder().decode(base64RandomDataOneMod)); 101 | String jdzRes = new String(com.joad.jdz.base64.scalar.Base64Scalar.getDecoder().decode(base64RandomDataOneMod)); 102 | 103 | assertEquals(javaRes, jdzRes); 104 | } 105 | 106 | @Test 107 | public void RFC4648DecodeTwoMod() { 108 | String javaRes = new String(java.util.Base64.getDecoder().decode(base64RandomDataTwoMod)); 109 | String jdzRes = new String(com.joad.jdz.base64.scalar.Base64Scalar.getDecoder().decode(base64RandomDataTwoMod)); 110 | 111 | assertEquals(javaRes, jdzRes); 112 | } 113 | 114 | @Test 115 | public void RFC4648DecodeThreeMod() { 116 | String javaRes = new String(java.util.Base64.getDecoder().decode(base64RandomDataThreeMod)); 117 | String jdzRes = new String(com.joad.jdz.base64.scalar.Base64Scalar.getDecoder().decode(base64RandomDataThreeMod)); 118 | 119 | assertEquals(javaRes, jdzRes); 120 | } 121 | 122 | @Test 123 | public void RFC4648InvalidInputDecode() { 124 | base64InvalidData[100] = (byte) '$'; 125 | base64InvalidData[101] = (byte) '$'; 126 | base64InvalidData[102] = (byte) '$'; 127 | base64InvalidData[103] = (byte) '$'; 128 | 129 | String exception = "No exception"; 130 | 131 | try { 132 | com.joad.jdz.base64.scalar.Base64Scalar.getDecoder().decode(base64InvalidData); 133 | } 134 | catch (Exception e) { 135 | exception = e.getMessage(); 136 | } 137 | 138 | assertEquals("Illegal base64 character 24 at position 100", exception); 139 | } 140 | } 141 | -------------------------------------------------------------------------------- /base64/src/test/java/com/joad/jdz/base64/scalar/RFC4648ScalarEncodeTest.java: -------------------------------------------------------------------------------- 1 | package com.joad.jdz.base64.scalar; 2 | 3 | import static org.junit.Assert.*; 4 | 5 | import java.util.Random; 6 | import org.junit.Test; 7 | 8 | public class RFC4648ScalarEncodeTest { 9 | /* 10 | * RFC4648 test vectors 11 | */ 12 | private static final byte[] emptyVector = "".getBytes(); 13 | private static final byte[] fVector = "f".getBytes(); 14 | private static final byte[] foVector = "fo".getBytes(); 15 | private static final byte[] fooVector = "foo".getBytes(); 16 | private static final byte[] foobVector = "foob".getBytes(); 17 | private static final byte[] foobaVector = "fooba".getBytes(); 18 | private static final byte[] foobarVector = "foobar".getBytes(); 19 | 20 | /* 21 | * Random data fuzz 22 | */ 23 | private static final byte[] randomDataZeroMod = new byte[1000]; 24 | private static final byte[] randomDataOneMod = new byte[1001]; 25 | private static final byte[] randomDataTwoMod = new byte[1002]; 26 | private static final byte[] randomDataThreeMod = new byte[1003]; 27 | 28 | static { 29 | new Random().nextBytes(randomDataZeroMod); 30 | new Random().nextBytes(randomDataOneMod); 31 | new Random().nextBytes(randomDataTwoMod); 32 | new Random().nextBytes(randomDataThreeMod); 33 | } 34 | 35 | @Test 36 | public void RFC4648EncodeEmptyVector() { 37 | String jdzRes = new String(com.joad.jdz.base64.scalar.Base64Scalar.getEncoder().encode(emptyVector)); 38 | 39 | assertEquals("", jdzRes); 40 | } 41 | 42 | @Test 43 | public void RFC4648EncodefVector() { 44 | String jdzRes = new String(com.joad.jdz.base64.scalar.Base64Scalar.getEncoder().encode(fVector)); 45 | 46 | assertEquals("Zg==", jdzRes); 47 | } 48 | 49 | @Test 50 | public void RFC4648EncodefoVector() { 51 | String jdzRes = new String(com.joad.jdz.base64.scalar.Base64Scalar.getEncoder().encode(foVector)); 52 | 53 | assertEquals("Zm8=", jdzRes); 54 | } 55 | 56 | @Test 57 | public void RFC4648EncodefooVector() { 58 | String jdzRes = new String(com.joad.jdz.base64.scalar.Base64Scalar.getEncoder().encode(fooVector)); 59 | 60 | assertEquals("Zm9v", jdzRes); 61 | } 62 | 63 | @Test 64 | public void RFC4648EncodefoobVector() { 65 | String jdzRes = new String(com.joad.jdz.base64.scalar.Base64Scalar.getEncoder().encode(foobVector)); 66 | 67 | assertEquals("Zm9vYg==", jdzRes); 68 | } 69 | 70 | @Test 71 | public void RFC4648EncodefoobaVector() { 72 | String jdzRes = new String(com.joad.jdz.base64.scalar.Base64Scalar.getEncoder().encode(foobaVector)); 73 | 74 | assertEquals("Zm9vYmE=", jdzRes); 75 | } 76 | 77 | @Test 78 | public void RFC4648EncodefoobarVector() { 79 | String jdzRes = new String(com.joad.jdz.base64.scalar.Base64Scalar.getEncoder().encode(foobarVector)); 80 | 81 | assertEquals("Zm9vYmFy", jdzRes); 82 | } 83 | @Test 84 | public void RFC4648EncodeZeroMod() { 85 | String javaRes = new String(java.util.Base64.getEncoder().encode(randomDataZeroMod)); 86 | String joadRes = new String(com.joad.jdz.base64.scalar.Base64Scalar.getEncoder().encode(randomDataZeroMod)); 87 | 88 | assertEquals(javaRes, joadRes); 89 | } 90 | 91 | @Test 92 | public void RFC4648EncodeOneMod() { 93 | String javaRes = new String(java.util.Base64.getEncoder().encode(randomDataOneMod)); 94 | String joadRes = new String(com.joad.jdz.base64.scalar.Base64Scalar.getEncoder().encode(randomDataOneMod)); 95 | 96 | assertEquals(javaRes, joadRes); 97 | } 98 | 99 | @Test 100 | public void RFC4648EncodeTwoMod() { 101 | String javaRes = new String(java.util.Base64.getEncoder().encode(randomDataTwoMod)); 102 | String joadRes = new String(com.joad.jdz.base64.scalar.Base64Scalar.getEncoder().encode(randomDataTwoMod)); 103 | 104 | assertEquals(javaRes, joadRes); 105 | } 106 | 107 | @Test 108 | public void RFC4648EncodeThreeMod() { 109 | String javaRes = new String(java.util.Base64.getEncoder().encode(randomDataThreeMod)); 110 | String joadRes = new String(com.joad.jdz.base64.scalar.Base64Scalar.getEncoder().encode(randomDataThreeMod)); 111 | 112 | assertEquals(javaRes, joadRes); 113 | } 114 | } -------------------------------------------------------------------------------- /base64/src/test/java/com/joad/jdz/base64/scalar/RFC4648URLFastScalarDecodeTest.java: -------------------------------------------------------------------------------- 1 | package com.joad.jdz.base64.scalar; 2 | 3 | import static org.junit.Assert.*; 4 | 5 | import java.util.Random; 6 | import org.junit.Test; 7 | 8 | public class RFC4648URLFastScalarDecodeTest { 9 | /* 10 | * RFC4648 test vectors 11 | */ 12 | private static final byte[] emptyVector = "".getBytes(); 13 | private static final byte[] fVector = "Zg==".getBytes(); 14 | private static final byte[] foVector = "Zm8=".getBytes(); 15 | private static final byte[] fooVector = "Zm9v".getBytes(); 16 | private static final byte[] foobVector = "Zm9vYg==".getBytes(); 17 | private static final byte[] foobaVector = "Zm9vYmE=".getBytes(); 18 | private static final byte[] foobarVector = "Zm9vYmFy".getBytes(); 19 | 20 | /* 21 | * Random data fuzz 22 | */ 23 | private static final byte[] randomDataZeroMod = new byte[1000]; 24 | private static final byte[] randomDataOneMod = new byte[1001]; 25 | private static final byte[] randomDataTwoMod = new byte[1002]; 26 | private static final byte[] randomDataThreeMod = new byte[1003]; 27 | 28 | 29 | static { 30 | new Random().nextBytes(randomDataZeroMod); 31 | new Random().nextBytes(randomDataOneMod); 32 | new Random().nextBytes(randomDataTwoMod); 33 | new Random().nextBytes(randomDataThreeMod); 34 | } 35 | 36 | private static final byte[] base64RandomDataZeroMod = java.util.Base64.getUrlEncoder().encode(randomDataZeroMod); 37 | private static final byte[] base64RandomDataOneMod = java.util.Base64.getUrlEncoder().encode(randomDataOneMod); 38 | private static final byte[] base64RandomDataTwoMod = java.util.Base64.getUrlEncoder().encode(randomDataTwoMod); 39 | private static final byte[] base64RandomDataThreeMod = java.util.Base64.getUrlEncoder().encode(randomDataThreeMod); 40 | 41 | @Test 42 | public void RFC4648URLDecodeEmptyVector() { 43 | String jdzRes = new String(com.joad.jdz.base64.scalar.Base64Scalar.getUrlDecoder().decodeFast(emptyVector)); 44 | 45 | assertEquals("", jdzRes); 46 | } 47 | 48 | @Test 49 | public void RFC4648URLDecodefVector() { 50 | String jdzRes = new String(com.joad.jdz.base64.scalar.Base64Scalar.getUrlDecoder().decodeFast(fVector)); 51 | 52 | assertEquals("f", jdzRes); 53 | } 54 | 55 | @Test 56 | public void RFC4648URLDecodefoVector() { 57 | String jdzRes = new String(com.joad.jdz.base64.scalar.Base64Scalar.getUrlDecoder().decodeFast(foVector)); 58 | 59 | assertEquals("fo", jdzRes); 60 | } 61 | 62 | @Test 63 | public void RFC4648URLDecodefooVector() { 64 | String jdzRes = new String(com.joad.jdz.base64.scalar.Base64Scalar.getUrlDecoder().decodeFast(fooVector)); 65 | 66 | assertEquals("foo", jdzRes); 67 | } 68 | 69 | @Test 70 | public void RFC4648URLDecodefoobVector() { 71 | String jdzRes = new String(com.joad.jdz.base64.scalar.Base64Scalar.getUrlDecoder().decodeFast(foobVector)); 72 | 73 | assertEquals("foob", jdzRes); 74 | } 75 | 76 | @Test 77 | public void RFC4648URLDecodefoobaVector() { 78 | String jdzRes = new String(com.joad.jdz.base64.scalar.Base64Scalar.getUrlDecoder().decodeFast(foobaVector)); 79 | 80 | assertEquals("fooba", jdzRes); 81 | } 82 | 83 | @Test 84 | public void RFC4648URLDecodefoobarVector() { 85 | String jdzRes = new String(com.joad.jdz.base64.scalar.Base64Scalar.getUrlDecoder().decodeFast(foobarVector)); 86 | 87 | assertEquals("foobar", jdzRes); 88 | } 89 | 90 | @Test 91 | public void RFC4648URLDecodeZeroMod() { 92 | String javaRes = new String(java.util.Base64.getUrlDecoder().decode(base64RandomDataZeroMod)); 93 | String jdzRes = new String(com.joad.jdz.base64.scalar.Base64Scalar.getUrlDecoder().decodeFast(base64RandomDataZeroMod)); 94 | 95 | assertEquals(javaRes, jdzRes); 96 | } 97 | 98 | @Test 99 | public void RFC4648URLDecodeOneMod() { 100 | String javaRes = new String(java.util.Base64.getUrlDecoder().decode(base64RandomDataOneMod)); 101 | String jdzRes = new String(com.joad.jdz.base64.scalar.Base64Scalar.getUrlDecoder().decodeFast(base64RandomDataOneMod)); 102 | 103 | assertEquals(javaRes, jdzRes); 104 | } 105 | 106 | @Test 107 | public void RFC4648URLDecodeTwoMod() { 108 | String javaRes = new String(java.util.Base64.getUrlDecoder().decode(base64RandomDataTwoMod)); 109 | String jdzRes = new String(com.joad.jdz.base64.scalar.Base64Scalar.getUrlDecoder().decodeFast(base64RandomDataTwoMod)); 110 | 111 | assertEquals(javaRes, jdzRes); 112 | } 113 | 114 | @Test 115 | public void RFC4648URLDecodeThreeMod() { 116 | String javaRes = new String(java.util.Base64.getUrlDecoder().decode(base64RandomDataThreeMod)); 117 | String jdzRes = new String(com.joad.jdz.base64.scalar.Base64Scalar.getUrlDecoder().decodeFast(base64RandomDataThreeMod)); 118 | 119 | assertEquals(javaRes, jdzRes); 120 | } 121 | } 122 | -------------------------------------------------------------------------------- /base64/src/test/java/com/joad/jdz/base64/scalar/RFC4648URLScalarDecodeTest.java: -------------------------------------------------------------------------------- 1 | package com.joad.jdz.base64.scalar; 2 | 3 | import static org.junit.Assert.*; 4 | 5 | import java.util.Random; 6 | import org.junit.Test; 7 | 8 | public class RFC4648URLScalarDecodeTest { 9 | /* 10 | * RFC4648 test vectors 11 | */ 12 | private static final byte[] emptyVector = "".getBytes(); 13 | private static final byte[] fVector = "Zg==".getBytes(); 14 | private static final byte[] foVector = "Zm8=".getBytes(); 15 | private static final byte[] fooVector = "Zm9v".getBytes(); 16 | private static final byte[] foobVector = "Zm9vYg==".getBytes(); 17 | private static final byte[] foobaVector = "Zm9vYmE=".getBytes(); 18 | private static final byte[] foobarVector = "Zm9vYmFy".getBytes(); 19 | 20 | /* 21 | * Random data fuzz 22 | */ 23 | private static final byte[] randomDataZeroMod = new byte[1000]; 24 | private static final byte[] randomDataOneMod = new byte[1001]; 25 | private static final byte[] randomDataTwoMod = new byte[1002]; 26 | private static final byte[] randomDataThreeMod = new byte[1003]; 27 | 28 | 29 | static { 30 | new Random().nextBytes(randomDataZeroMod); 31 | new Random().nextBytes(randomDataOneMod); 32 | new Random().nextBytes(randomDataTwoMod); 33 | new Random().nextBytes(randomDataThreeMod); 34 | } 35 | 36 | private static final byte[] base64RandomDataZeroMod = java.util.Base64.getUrlEncoder().encode(randomDataZeroMod); 37 | private static final byte[] base64RandomDataOneMod = java.util.Base64.getUrlEncoder().encode(randomDataOneMod); 38 | private static final byte[] base64RandomDataTwoMod = java.util.Base64.getUrlEncoder().encode(randomDataTwoMod); 39 | private static final byte[] base64RandomDataThreeMod = java.util.Base64.getUrlEncoder().encode(randomDataThreeMod); 40 | private static final byte[] base64InvalidData = java.util.Base64.getUrlEncoder().encode(randomDataZeroMod); 41 | 42 | @Test 43 | public void RFC4648URLDecodeEmptyVector() { 44 | String jdzRes = new String(com.joad.jdz.base64.scalar.Base64Scalar.getUrlDecoder().decode(emptyVector)); 45 | 46 | assertEquals("", jdzRes); 47 | } 48 | 49 | @Test 50 | public void RFC4648URLDecodefVector() { 51 | String jdzRes = new String(com.joad.jdz.base64.scalar.Base64Scalar.getUrlDecoder().decode(fVector)); 52 | 53 | assertEquals("f", jdzRes); 54 | } 55 | 56 | @Test 57 | public void RFC4648URLDecodefoVector() { 58 | String jdzRes = new String(com.joad.jdz.base64.scalar.Base64Scalar.getUrlDecoder().decode(foVector)); 59 | 60 | assertEquals("fo", jdzRes); 61 | } 62 | 63 | @Test 64 | public void RFC4648URLDecodefooVector() { 65 | String jdzRes = new String(com.joad.jdz.base64.scalar.Base64Scalar.getUrlDecoder().decode(fooVector)); 66 | 67 | assertEquals("foo", jdzRes); 68 | } 69 | 70 | @Test 71 | public void RFC4648URLDecodefoobVector() { 72 | String jdzRes = new String(com.joad.jdz.base64.scalar.Base64Scalar.getUrlDecoder().decode(foobVector)); 73 | 74 | assertEquals("foob", jdzRes); 75 | } 76 | 77 | @Test 78 | public void RFC4648URLDecodefoobaVector() { 79 | String jdzRes = new String(com.joad.jdz.base64.scalar.Base64Scalar.getUrlDecoder().decode(foobaVector)); 80 | 81 | assertEquals("fooba", jdzRes); 82 | } 83 | 84 | @Test 85 | public void RFC4648URLDecodefoobarVector() { 86 | String jdzRes = new String(com.joad.jdz.base64.scalar.Base64Scalar.getUrlDecoder().decode(foobarVector)); 87 | 88 | assertEquals("foobar", jdzRes); 89 | } 90 | 91 | @Test 92 | public void RFC4648URLDecodeZeroMod() { 93 | String javaRes = new String(java.util.Base64.getUrlDecoder().decode(base64RandomDataZeroMod)); 94 | String jdzRes = new String(com.joad.jdz.base64.scalar.Base64Scalar.getUrlDecoder().decode(base64RandomDataZeroMod)); 95 | 96 | assertEquals(javaRes, jdzRes); 97 | } 98 | 99 | @Test 100 | public void RFC4648URLDecodeOneMod() { 101 | String javaRes = new String(java.util.Base64.getUrlDecoder().decode(base64RandomDataOneMod)); 102 | String jdzRes = new String(com.joad.jdz.base64.scalar.Base64Scalar.getUrlDecoder().decode(base64RandomDataOneMod)); 103 | 104 | assertEquals(javaRes, jdzRes); 105 | } 106 | 107 | @Test 108 | public void RFC4648URLDecodeTwoMod() { 109 | String javaRes = new String(java.util.Base64.getUrlDecoder().decode(base64RandomDataTwoMod)); 110 | String jdzRes = new String(com.joad.jdz.base64.scalar.Base64Scalar.getUrlDecoder().decode(base64RandomDataTwoMod)); 111 | 112 | assertEquals(javaRes, jdzRes); 113 | } 114 | 115 | @Test 116 | public void RFC4648URLDecodeThreeMod() { 117 | String javaRes = new String(java.util.Base64.getUrlDecoder().decode(base64RandomDataThreeMod)); 118 | String jdzRes = new String(com.joad.jdz.base64.scalar.Base64Scalar.getUrlDecoder().decode(base64RandomDataThreeMod)); 119 | 120 | assertEquals(javaRes, jdzRes); 121 | } 122 | 123 | @Test 124 | public void RFC4648URLInvalidInputDecode() { 125 | base64InvalidData[100] = (byte) '$'; 126 | base64InvalidData[101] = (byte) '$'; 127 | base64InvalidData[102] = (byte) '$'; 128 | base64InvalidData[103] = (byte) '$'; 129 | 130 | String exception = "No exception"; 131 | 132 | try { 133 | com.joad.jdz.base64.scalar.Base64Scalar.getUrlDecoder().decode(base64InvalidData); 134 | } 135 | catch (Exception e) { 136 | exception = e.getMessage(); 137 | } 138 | 139 | assertEquals("Illegal base64 character 24 at position 100", exception); 140 | } 141 | } 142 | -------------------------------------------------------------------------------- /base64/src/test/java/com/joad/jdz/base64/scalar/RFC4648URLScalarEncodeTest.java: -------------------------------------------------------------------------------- 1 | package com.joad.jdz.base64.scalar; 2 | 3 | import static org.junit.Assert.*; 4 | 5 | import java.util.Random; 6 | import org.junit.Test; 7 | 8 | public class RFC4648URLScalarEncodeTest { 9 | /* 10 | * RFC4648 test vectors 11 | */ 12 | private static final byte[] emptyVector = "".getBytes(); 13 | private static final byte[] fVector = "f".getBytes(); 14 | private static final byte[] foVector = "fo".getBytes(); 15 | private static final byte[] fooVector = "foo".getBytes(); 16 | private static final byte[] foobVector = "foob".getBytes(); 17 | private static final byte[] foobaVector = "fooba".getBytes(); 18 | private static final byte[] foobarVector = "foobar".getBytes(); 19 | 20 | /* 21 | * Random data fuzz 22 | */ 23 | private static final byte[] randomDataZeroMod = new byte[1000]; 24 | private static final byte[] randomDataOneMod = new byte[1001]; 25 | private static final byte[] randomDataTwoMod = new byte[1002]; 26 | private static final byte[] randomDataThreeMod = new byte[1003]; 27 | 28 | static { 29 | new Random().nextBytes(randomDataZeroMod); 30 | new Random().nextBytes(randomDataOneMod); 31 | new Random().nextBytes(randomDataTwoMod); 32 | new Random().nextBytes(randomDataThreeMod); 33 | } 34 | 35 | @Test 36 | public void RFC4648URLEncodeEmptyVector() { 37 | String jdzRes = new String(com.joad.jdz.base64.scalar.Base64Scalar.getUrlEncoder().encode(emptyVector)); 38 | 39 | assertEquals("", jdzRes); 40 | } 41 | 42 | @Test 43 | public void RFC4648URLEncodefVector() { 44 | String jdzRes = new String(com.joad.jdz.base64.scalar.Base64Scalar.getUrlEncoder().encode(fVector)); 45 | 46 | assertEquals("Zg==", jdzRes); 47 | } 48 | 49 | @Test 50 | public void RFC4648URLEncodefoVector() { 51 | String jdzRes = new String(com.joad.jdz.base64.scalar.Base64Scalar.getUrlEncoder().encode(foVector)); 52 | 53 | assertEquals("Zm8=", jdzRes); 54 | } 55 | 56 | @Test 57 | public void RFC4648URLEncodefooVector() { 58 | String jdzRes = new String(com.joad.jdz.base64.scalar.Base64Scalar.getUrlEncoder().encode(fooVector)); 59 | 60 | assertEquals("Zm9v", jdzRes); 61 | } 62 | 63 | @Test 64 | public void RFC4648URLEncodefoobVector() { 65 | String jdzRes = new String(com.joad.jdz.base64.scalar.Base64Scalar.getUrlEncoder().encode(foobVector)); 66 | 67 | assertEquals("Zm9vYg==", jdzRes); 68 | } 69 | 70 | @Test 71 | public void RFC4648URLEncodefoobaVector() { 72 | String jdzRes = new String(com.joad.jdz.base64.scalar.Base64Scalar.getUrlEncoder().encode(foobaVector)); 73 | 74 | assertEquals("Zm9vYmE=", jdzRes); 75 | } 76 | 77 | @Test 78 | public void RFC4648URLEncodefoobarVector() { 79 | String jdzRes = new String(com.joad.jdz.base64.scalar.Base64Scalar.getUrlEncoder().encode(foobarVector)); 80 | 81 | assertEquals("Zm9vYmFy", jdzRes); 82 | } 83 | @Test 84 | public void RFC4648URLEncodeZeroMod() { 85 | String javaRes = new String(java.util.Base64.getUrlEncoder().encode(randomDataZeroMod)); 86 | String joadRes = new String(com.joad.jdz.base64.scalar.Base64Scalar.getUrlEncoder().encode(randomDataZeroMod)); 87 | 88 | assertEquals(javaRes, joadRes); 89 | } 90 | 91 | @Test 92 | public void RFC4648URLEncodeOneMod() { 93 | String javaRes = new String(java.util.Base64.getUrlEncoder().encode(randomDataOneMod)); 94 | String joadRes = new String(com.joad.jdz.base64.scalar.Base64Scalar.getUrlEncoder().encode(randomDataOneMod)); 95 | 96 | assertEquals(javaRes, joadRes); 97 | } 98 | 99 | @Test 100 | public void RFC4648URLEncodeTwoMod() { 101 | String javaRes = new String(java.util.Base64.getUrlEncoder().encode(randomDataTwoMod)); 102 | String joadRes = new String(com.joad.jdz.base64.scalar.Base64Scalar.getUrlEncoder().encode(randomDataTwoMod)); 103 | 104 | assertEquals(javaRes, joadRes); 105 | } 106 | 107 | @Test 108 | public void RFC4648URLEncodeThreeMod() { 109 | String javaRes = new String(java.util.Base64.getUrlEncoder().encode(randomDataThreeMod)); 110 | String joadRes = new String(com.joad.jdz.base64.scalar.Base64Scalar.getUrlEncoder().encode(randomDataThreeMod)); 111 | 112 | assertEquals(javaRes, joadRes); 113 | } 114 | } -------------------------------------------------------------------------------- /base64/src/test/java/com/joad/jdz/base64/vector/RFC2045FastVectorDecodeTest.java: -------------------------------------------------------------------------------- 1 | package com.joad.jdz.base64.vector; 2 | 3 | import static org.junit.Assert.*; 4 | 5 | import java.util.Random; 6 | import org.junit.Test; 7 | 8 | public class RFC2045FastVectorDecodeTest { 9 | /* 10 | * RFC2045Fast test vectors 11 | */ 12 | private static final byte[] emptyVector = "".getBytes(); 13 | private static final byte[] fVector = "Zg==".getBytes(); 14 | private static final byte[] foVector = "Zm8=".getBytes(); 15 | private static final byte[] fooVector = "Zm9v".getBytes(); 16 | private static final byte[] foobVector = "Zm9vYg==".getBytes(); 17 | private static final byte[] foobaVector = "Zm9vYmE=".getBytes(); 18 | private static final byte[] foobarVector = "Zm9vYmFy".getBytes(); 19 | 20 | /* 21 | * Random data fuzz 22 | */ 23 | private static final byte[] randomDataZeroMod = new byte[1000]; 24 | private static final byte[] randomDataOneMod = new byte[1001]; 25 | private static final byte[] randomDataTwoMod = new byte[1002]; 26 | private static final byte[] randomDataThreeMod = new byte[1003]; 27 | private static final byte[] randomDataSixtyOne = new byte[61]; 28 | 29 | static { 30 | new Random().nextBytes(randomDataZeroMod); 31 | new Random().nextBytes(randomDataOneMod); 32 | new Random().nextBytes(randomDataTwoMod); 33 | new Random().nextBytes(randomDataThreeMod); 34 | new Random().nextBytes(randomDataSixtyOne); 35 | } 36 | 37 | private static final byte[] base64RandomDataZeroMod = java.util.Base64.getMimeEncoder().encode(randomDataZeroMod); 38 | private static final byte[] base64RandomDataOneMod = java.util.Base64.getMimeEncoder().encode(randomDataOneMod); 39 | private static final byte[] base64RandomDataTwoMod = java.util.Base64.getMimeEncoder().encode(randomDataTwoMod); 40 | private static final byte[] base64RandomDataThreeMod = java.util.Base64.getMimeEncoder().encode(randomDataThreeMod); 41 | private static final byte[] base64RandomDataSixtyOne = java.util.Base64.getMimeEncoder().encode(randomDataSixtyOne); 42 | 43 | @Test 44 | public void RFC2045FastDecodeEmptyVector() { 45 | String jdzRes = new String(com.joad.jdz.base64.vector.Base64Vector.getMimeDecoder().decodeFast(emptyVector)); 46 | 47 | assertEquals("", jdzRes); 48 | } 49 | 50 | @Test 51 | public void RFC2045FastDecodefVector() { 52 | String jdzRes = new String(com.joad.jdz.base64.vector.Base64Vector.getMimeDecoder().decodeFast(fVector)); 53 | 54 | assertEquals("f", jdzRes); 55 | } 56 | 57 | @Test 58 | public void RFC2045FastDecodefoVector() { 59 | String jdzRes = new String(com.joad.jdz.base64.vector.Base64Vector.getMimeDecoder().decodeFast(foVector)); 60 | 61 | assertEquals("fo", jdzRes); 62 | } 63 | 64 | @Test 65 | public void RFC2045FastDecodefooVector() { 66 | String jdzRes = new String(com.joad.jdz.base64.vector.Base64Vector.getMimeDecoder().decodeFast(fooVector)); 67 | 68 | assertEquals("foo", jdzRes); 69 | } 70 | 71 | @Test 72 | public void RFC2045FastDecodefoobVector() { 73 | String jdzRes = new String(com.joad.jdz.base64.vector.Base64Vector.getMimeDecoder().decodeFast(foobVector)); 74 | 75 | assertEquals("foob", jdzRes); 76 | } 77 | 78 | @Test 79 | public void RFC2045FastDecodefoobaVector() { 80 | String jdzRes = new String(com.joad.jdz.base64.vector.Base64Vector.getMimeDecoder().decodeFast(foobaVector)); 81 | 82 | assertEquals("fooba", jdzRes); 83 | } 84 | 85 | @Test 86 | public void RFC2045FastDecodefoobarVector() { 87 | String jdzRes = new String(com.joad.jdz.base64.vector.Base64Vector.getMimeDecoder().decodeFast(foobarVector)); 88 | 89 | assertEquals("foobar", jdzRes); 90 | } 91 | 92 | @Test 93 | public void RFC2045FastDecodeZeroMod() { 94 | String javaRes = new String(java.util.Base64.getMimeDecoder().decode(base64RandomDataZeroMod)); 95 | String jdzRes = new String(com.joad.jdz.base64.vector.Base64Vector.getMimeDecoder().decodeFast(base64RandomDataZeroMod)); 96 | 97 | assertEquals(javaRes, jdzRes); 98 | } 99 | 100 | @Test 101 | public void RFC2045FastDecodeOneMod() { 102 | String javaRes = new String(java.util.Base64.getMimeDecoder().decode(base64RandomDataOneMod)); 103 | String jdzRes = new String(com.joad.jdz.base64.vector.Base64Vector.getMimeDecoder().decodeFast(base64RandomDataOneMod)); 104 | 105 | assertEquals(javaRes, jdzRes); 106 | } 107 | 108 | @Test 109 | public void RFC2045FastDecodeTwoMod() { 110 | String javaRes = new String(java.util.Base64.getMimeDecoder().decode(base64RandomDataTwoMod)); 111 | String jdzRes = new String(com.joad.jdz.base64.vector.Base64Vector.getMimeDecoder().decodeFast(base64RandomDataTwoMod)); 112 | 113 | assertEquals(javaRes, jdzRes); 114 | } 115 | 116 | @Test 117 | public void RFC2045FastDecodeThreeMod() { 118 | String javaRes = new String(java.util.Base64.getMimeDecoder().decode(base64RandomDataThreeMod)); 119 | String jdzRes = new String(com.joad.jdz.base64.vector.Base64Vector.getMimeDecoder().decodeFast(base64RandomDataThreeMod)); 120 | 121 | assertEquals(javaRes, jdzRes); 122 | } 123 | 124 | @Test 125 | public void RFC2045DecodeSixtyOne() { 126 | String javaRes = new String(java.util.Base64.getMimeDecoder().decode(base64RandomDataSixtyOne)); 127 | String jdzRes = new String(com.joad.jdz.base64.vector.Base64Vector.getMimeDecoder().decodeFast(base64RandomDataSixtyOne)); 128 | 129 | assertEquals(javaRes, jdzRes); 130 | } 131 | } -------------------------------------------------------------------------------- /base64/src/test/java/com/joad/jdz/base64/vector/RFC2045VectorDecodeTest.java: -------------------------------------------------------------------------------- 1 | package com.joad.jdz.base64.vector; 2 | 3 | import static org.junit.Assert.*; 4 | 5 | import java.util.Random; 6 | import org.junit.Test; 7 | 8 | public class RFC2045VectorDecodeTest { 9 | /* 10 | * RFC2045 test vectors 11 | */ 12 | private static final byte[] emptyVector = "".getBytes(); 13 | private static final byte[] fVector = "Zg==".getBytes(); 14 | private static final byte[] foVector = "Zm8=".getBytes(); 15 | private static final byte[] fooVector = "Zm9v".getBytes(); 16 | private static final byte[] foobVector = "Zm9vYg==".getBytes(); 17 | private static final byte[] foobaVector = "Zm9vYmE=".getBytes(); 18 | private static final byte[] foobarVector = "Zm9vYmFy".getBytes(); 19 | 20 | /* 21 | * Random data fuzz 22 | */ 23 | private static final byte[] randomDataZeroMod = new byte[1000]; 24 | private static final byte[] randomDataOneMod = new byte[1001]; 25 | private static final byte[] randomDataTwoMod = new byte[1002]; 26 | private static final byte[] randomDataThreeMod = new byte[1003]; 27 | private static final byte[] randomDataSixtyOne = new byte[61]; 28 | 29 | static { 30 | new Random().nextBytes(randomDataZeroMod); 31 | new Random().nextBytes(randomDataOneMod); 32 | new Random().nextBytes(randomDataTwoMod); 33 | new Random().nextBytes(randomDataThreeMod); 34 | new Random().nextBytes(randomDataSixtyOne); 35 | } 36 | 37 | private static final byte[] base64RandomDataZeroMod = java.util.Base64.getMimeEncoder().encode(randomDataZeroMod); 38 | private static final byte[] base64RandomDataOneMod = java.util.Base64.getMimeEncoder().encode(randomDataOneMod); 39 | private static final byte[] base64RandomDataTwoMod = java.util.Base64.getMimeEncoder().encode(randomDataTwoMod); 40 | private static final byte[] base64RandomDataThreeMod = java.util.Base64.getMimeEncoder().encode(randomDataThreeMod); 41 | private static final byte[] base64RandomDataSixtyOne = java.util.Base64.getMimeEncoder().encode(randomDataSixtyOne); 42 | private static final byte[] base64InvalidData = java.util.Base64.getMimeEncoder().encode(randomDataZeroMod); 43 | 44 | @Test 45 | public void RFC2045DecodeEmptyVector() { 46 | String jdzRes = new String(com.joad.jdz.base64.vector.Base64Vector.getMimeDecoder().decode(emptyVector)); 47 | 48 | assertEquals("", jdzRes); 49 | } 50 | 51 | @Test 52 | public void RFC2045DecodefVector() { 53 | String jdzRes = new String(com.joad.jdz.base64.vector.Base64Vector.getMimeDecoder().decode(fVector)); 54 | 55 | assertEquals("f", jdzRes); 56 | } 57 | 58 | @Test 59 | public void RFC2045DecodefoVector() { 60 | String jdzRes = new String(com.joad.jdz.base64.vector.Base64Vector.getMimeDecoder().decode(foVector)); 61 | 62 | assertEquals("fo", jdzRes); 63 | } 64 | 65 | @Test 66 | public void RFC2045DecodefooVector() { 67 | String jdzRes = new String(com.joad.jdz.base64.vector.Base64Vector.getMimeDecoder().decode(fooVector)); 68 | 69 | assertEquals("foo", jdzRes); 70 | } 71 | 72 | @Test 73 | public void RFC2045DecodefoobVector() { 74 | String jdzRes = new String(com.joad.jdz.base64.vector.Base64Vector.getMimeDecoder().decode(foobVector)); 75 | 76 | assertEquals("foob", jdzRes); 77 | } 78 | 79 | @Test 80 | public void RFC2045DecodefoobaVector() { 81 | String jdzRes = new String(com.joad.jdz.base64.vector.Base64Vector.getMimeDecoder().decode(foobaVector)); 82 | 83 | assertEquals("fooba", jdzRes); 84 | } 85 | 86 | @Test 87 | public void RFC2045DecodefoobarVector() { 88 | String jdzRes = new String(com.joad.jdz.base64.vector.Base64Vector.getMimeDecoder().decode(foobarVector)); 89 | 90 | assertEquals("foobar", jdzRes); 91 | } 92 | 93 | @Test 94 | public void RFC2045DecodeZeroMod() { 95 | String javaRes = new String(java.util.Base64.getMimeDecoder().decode(base64RandomDataZeroMod)); 96 | String jdzRes = new String(com.joad.jdz.base64.vector.Base64Vector.getMimeDecoder().decode(base64RandomDataZeroMod)); 97 | 98 | assertEquals(javaRes, jdzRes); 99 | } 100 | 101 | @Test 102 | public void RFC2045DecodeOneMod() { 103 | String javaRes = new String(java.util.Base64.getMimeDecoder().decode(base64RandomDataOneMod)); 104 | String jdzRes = new String(com.joad.jdz.base64.vector.Base64Vector.getMimeDecoder().decode(base64RandomDataOneMod)); 105 | 106 | assertEquals(javaRes, jdzRes); 107 | } 108 | 109 | @Test 110 | public void RFC2045DecodeTwoMod() { 111 | String javaRes = new String(java.util.Base64.getMimeDecoder().decode(base64RandomDataTwoMod)); 112 | String jdzRes = new String(com.joad.jdz.base64.vector.Base64Vector.getMimeDecoder().decode(base64RandomDataTwoMod)); 113 | 114 | assertEquals(javaRes, jdzRes); 115 | } 116 | 117 | @Test 118 | public void RFC2045DecodeThreeMod() { 119 | String javaRes = new String(java.util.Base64.getMimeDecoder().decode(base64RandomDataThreeMod)); 120 | String jdzRes = new String(com.joad.jdz.base64.vector.Base64Vector.getMimeDecoder().decode(base64RandomDataThreeMod)); 121 | 122 | assertEquals(javaRes, jdzRes); 123 | } 124 | 125 | @Test 126 | public void RFC2045DecodeSixtyOne() { 127 | String javaRes = new String(java.util.Base64.getMimeDecoder().decode(base64RandomDataSixtyOne)); 128 | String jdzRes = new String(com.joad.jdz.base64.vector.Base64Vector.getMimeDecoder().decode(base64RandomDataSixtyOne)); 129 | 130 | assertEquals(javaRes, jdzRes); 131 | } 132 | 133 | @Test 134 | public void RFC2045InvalidInputDecode() { 135 | base64InvalidData[100] = (byte) '$'; 136 | base64InvalidData[101] = (byte) '$'; 137 | base64InvalidData[102] = (byte) '$'; 138 | base64InvalidData[103] = (byte) '$'; 139 | 140 | String javaRes = new String(java.util.Base64.getMimeDecoder().decode(base64InvalidData)); 141 | String jdzRes = new String(com.joad.jdz.base64.vector.Base64Vector.getMimeDecoder().decode(base64InvalidData)); 142 | 143 | assertEquals(javaRes, jdzRes); 144 | } 145 | } -------------------------------------------------------------------------------- /base64/src/test/java/com/joad/jdz/base64/vector/RFC2045VectorEncodeTest.java: -------------------------------------------------------------------------------- 1 | package com.joad.jdz.base64.vector; 2 | 3 | import static org.junit.Assert.*; 4 | 5 | import java.util.Random; 6 | import org.junit.Test; 7 | 8 | public class RFC2045VectorEncodeTest { 9 | /* 10 | * RFC2045 test vectors 11 | */ 12 | private static final byte[] emptyVector = "".getBytes(); 13 | private static final byte[] fVector = "f".getBytes(); 14 | private static final byte[] foVector = "fo".getBytes(); 15 | private static final byte[] fooVector = "foo".getBytes(); 16 | private static final byte[] foobVector = "foob".getBytes(); 17 | private static final byte[] foobaVector = "fooba".getBytes(); 18 | private static final byte[] foobarVector = "foobar".getBytes(); 19 | 20 | /* 21 | * Random data fuzz 22 | */ 23 | private static final byte[] randomDataZeroMod = new byte[1000]; 24 | private static final byte[] randomDataOneMod = new byte[1001]; 25 | private static final byte[] randomDataTwoMod = new byte[1002]; 26 | private static final byte[] randomDataThreeMod = new byte[1003]; 27 | private static final byte[] randomDataSeventySix = new byte[55]; 28 | 29 | static { 30 | new Random().nextBytes(randomDataZeroMod); 31 | new Random().nextBytes(randomDataOneMod); 32 | new Random().nextBytes(randomDataTwoMod); 33 | new Random().nextBytes(randomDataThreeMod); 34 | new Random().nextBytes(randomDataSeventySix); 35 | } 36 | 37 | @Test 38 | public void RFC2045EncodeEmptyVector() { 39 | String jdzRes = new String(com.joad.jdz.base64.vector.Base64Vector.getMimeEncoder().encode(emptyVector)); 40 | 41 | assertEquals("", jdzRes); 42 | } 43 | 44 | @Test 45 | public void RFC2045EncodefVector() { 46 | String jdzRes = new String(com.joad.jdz.base64.vector.Base64Vector.getMimeEncoder().encode(fVector)); 47 | 48 | assertEquals("Zg==", jdzRes); 49 | } 50 | 51 | @Test 52 | public void RFC2045EncodefoVector() { 53 | String jdzRes = new String(com.joad.jdz.base64.vector.Base64Vector.getMimeEncoder().encode(foVector)); 54 | 55 | assertEquals("Zm8=", jdzRes); 56 | } 57 | 58 | @Test 59 | public void RFC2045EncodefooVector() { 60 | String jdzRes = new String(com.joad.jdz.base64.vector.Base64Vector.getMimeEncoder().encode(fooVector)); 61 | 62 | assertEquals("Zm9v", jdzRes); 63 | } 64 | 65 | @Test 66 | public void RFC2045EncodefoobVector() { 67 | String jdzRes = new String(com.joad.jdz.base64.vector.Base64Vector.getMimeEncoder().encode(foobVector)); 68 | 69 | assertEquals("Zm9vYg==", jdzRes); 70 | } 71 | 72 | @Test 73 | public void RFC2045EncodefoobaVector() { 74 | String jdzRes = new String(com.joad.jdz.base64.vector.Base64Vector.getMimeEncoder().encode(foobaVector)); 75 | 76 | assertEquals("Zm9vYmE=", jdzRes); 77 | } 78 | 79 | @Test 80 | public void RFC2045EncodefoobarVector() { 81 | String jdzRes = new String(com.joad.jdz.base64.vector.Base64Vector.getMimeEncoder().encode(foobarVector)); 82 | 83 | assertEquals("Zm9vYmFy", jdzRes); 84 | } 85 | @Test 86 | public void RFC2045EncodeZeroMod() { 87 | String javaRes = new String(java.util.Base64.getMimeEncoder().encode(randomDataZeroMod)); 88 | String joadRes = new String(com.joad.jdz.base64.vector.Base64Vector.getMimeEncoder().encode(randomDataZeroMod)); 89 | 90 | assertEquals(javaRes, joadRes); 91 | } 92 | 93 | @Test 94 | public void RFC2045EncodeOneMod() { 95 | String javaRes = new String(java.util.Base64.getMimeEncoder().encode(randomDataOneMod)); 96 | String joadRes = new String(com.joad.jdz.base64.vector.Base64Vector.getMimeEncoder().encode(randomDataOneMod)); 97 | 98 | assertEquals(javaRes, joadRes); 99 | } 100 | 101 | @Test 102 | public void RFC2045EncodeTwoMod() { 103 | String javaRes = new String(java.util.Base64.getMimeEncoder().encode(randomDataTwoMod)); 104 | String joadRes = new String(com.joad.jdz.base64.vector.Base64Vector.getMimeEncoder().encode(randomDataTwoMod)); 105 | 106 | assertEquals(javaRes, joadRes); 107 | } 108 | 109 | @Test 110 | public void RFC2045EncodeThreeMod() { 111 | String javaRes = new String(java.util.Base64.getMimeEncoder().encode(randomDataThreeMod)); 112 | String joadRes = new String(com.joad.jdz.base64.vector.Base64Vector.getMimeEncoder().encode(randomDataThreeMod)); 113 | 114 | assertEquals(javaRes, joadRes); 115 | } 116 | 117 | @Test 118 | public void RFC2045EncodeSeventySix() { 119 | String javaRes = new String(java.util.Base64.getMimeEncoder().encode(randomDataSeventySix)); 120 | String joadRes = new String(com.joad.jdz.base64.vector.Base64Vector.getMimeEncoder().encode(randomDataSeventySix)); 121 | 122 | assertEquals(javaRes, joadRes); 123 | } 124 | } -------------------------------------------------------------------------------- /base64/src/test/java/com/joad/jdz/base64/vector/RFC4648FastVectorDecodeTest.java: -------------------------------------------------------------------------------- 1 | package com.joad.jdz.base64.vector; 2 | 3 | import static org.junit.Assert.*; 4 | 5 | import java.util.Random; 6 | import org.junit.Test; 7 | 8 | public class RFC4648FastVectorDecodeTest { 9 | /* 10 | * RFC4648 test vectors 11 | */ 12 | private static final byte[] emptyVector = "".getBytes(); 13 | private static final byte[] fVector = "Zg==".getBytes(); 14 | private static final byte[] foVector = "Zm8=".getBytes(); 15 | private static final byte[] fooVector = "Zm9v".getBytes(); 16 | private static final byte[] foobVector = "Zm9vYg==".getBytes(); 17 | private static final byte[] foobaVector = "Zm9vYmE=".getBytes(); 18 | private static final byte[] foobarVector = "Zm9vYmFy".getBytes(); 19 | 20 | /* 21 | * Random data fuzz 22 | */ 23 | private static final byte[] randomDataZeroMod = new byte[1000]; 24 | private static final byte[] randomDataOneMod = new byte[1001]; 25 | private static final byte[] randomDataTwoMod = new byte[1002]; 26 | private static final byte[] randomDataThreeMod = new byte[1003]; 27 | 28 | static { 29 | new Random().nextBytes(randomDataZeroMod); 30 | new Random().nextBytes(randomDataOneMod); 31 | new Random().nextBytes(randomDataTwoMod); 32 | new Random().nextBytes(randomDataThreeMod); 33 | } 34 | 35 | private static final byte[] base64RandomDataZeroMod = java.util.Base64.getEncoder().encode(randomDataZeroMod); 36 | private static final byte[] base64RandomDataOneMod = java.util.Base64.getEncoder().encode(randomDataOneMod); 37 | private static final byte[] base64RandomDataTwoMod = java.util.Base64.getEncoder().encode(randomDataTwoMod); 38 | private static final byte[] base64RandomDataThreeMod = java.util.Base64.getEncoder().encode(randomDataThreeMod); 39 | 40 | @Test 41 | public void RFC4648DecodeEmptyVector() { 42 | String jdzRes = new String(com.joad.jdz.base64.vector.Base64Vector.getDecoder().decodeFast(emptyVector)); 43 | 44 | assertEquals("", jdzRes); 45 | } 46 | 47 | @Test 48 | public void RFC4648DecodefVector() { 49 | String jdzRes = new String(com.joad.jdz.base64.vector.Base64Vector.getDecoder().decodeFast(fVector)); 50 | 51 | assertEquals("f", jdzRes); 52 | } 53 | 54 | @Test 55 | public void RFC4648DecodefoVector() { 56 | String jdzRes = new String(com.joad.jdz.base64.vector.Base64Vector.getDecoder().decodeFast(foVector)); 57 | 58 | assertEquals("fo", jdzRes); 59 | } 60 | 61 | @Test 62 | public void RFC4648DecodefooVector() { 63 | String jdzRes = new String(com.joad.jdz.base64.vector.Base64Vector.getDecoder().decodeFast(fooVector)); 64 | 65 | assertEquals("foo", jdzRes); 66 | } 67 | 68 | @Test 69 | public void RFC4648DecodefoobVector() { 70 | String jdzRes = new String(com.joad.jdz.base64.vector.Base64Vector.getDecoder().decodeFast(foobVector)); 71 | 72 | assertEquals("foob", jdzRes); 73 | } 74 | 75 | @Test 76 | public void RFC4648DecodefoobaVector() { 77 | String jdzRes = new String(com.joad.jdz.base64.vector.Base64Vector.getDecoder().decodeFast(foobaVector)); 78 | 79 | assertEquals("fooba", jdzRes); 80 | } 81 | 82 | @Test 83 | public void RFC4648DecodefoobarVector() { 84 | String jdzRes = new String(com.joad.jdz.base64.vector.Base64Vector.getDecoder().decodeFast(foobarVector)); 85 | 86 | assertEquals("foobar", jdzRes); 87 | } 88 | 89 | @Test 90 | public void RFC4648DecodeZeroMod() { 91 | String javaRes = new String(java.util.Base64.getDecoder().decode(base64RandomDataZeroMod)); 92 | String jdzRes = new String(com.joad.jdz.base64.vector.Base64Vector.getDecoder().decodeFast(base64RandomDataZeroMod)); 93 | 94 | assertEquals(javaRes, jdzRes); 95 | } 96 | 97 | @Test 98 | public void RFC4648DecodeOneMod() { 99 | String javaRes = new String(java.util.Base64.getDecoder().decode(base64RandomDataOneMod)); 100 | String jdzRes = new String(com.joad.jdz.base64.vector.Base64Vector.getDecoder().decodeFast(base64RandomDataOneMod)); 101 | 102 | assertEquals(javaRes, jdzRes); 103 | } 104 | 105 | @Test 106 | public void RFC4648DecodeTwoMod() { 107 | String javaRes = new String(java.util.Base64.getDecoder().decode(base64RandomDataTwoMod)); 108 | String jdzRes = new String(com.joad.jdz.base64.vector.Base64Vector.getDecoder().decodeFast(base64RandomDataTwoMod)); 109 | 110 | assertEquals(javaRes, jdzRes); 111 | } 112 | 113 | @Test 114 | public void RFC4648DecodeThreeMod() { 115 | String javaRes = new String(java.util.Base64.getDecoder().decode(base64RandomDataThreeMod)); 116 | String jdzRes = new String(com.joad.jdz.base64.vector.Base64Vector.getDecoder().decodeFast(base64RandomDataThreeMod)); 117 | 118 | assertEquals(javaRes, jdzRes); 119 | } 120 | } 121 | -------------------------------------------------------------------------------- /base64/src/test/java/com/joad/jdz/base64/vector/RFC4648URLFastVectorDecodeTest.java: -------------------------------------------------------------------------------- 1 | package com.joad.jdz.base64.vector; 2 | 3 | import static org.junit.Assert.*; 4 | 5 | import java.util.Random; 6 | import org.junit.Test; 7 | 8 | public class RFC4648URLFastVectorDecodeTest { 9 | /* 10 | * RFC4648 test vectors 11 | */ 12 | private static final byte[] emptyVector = "".getBytes(); 13 | private static final byte[] fVector = "Zg==".getBytes(); 14 | private static final byte[] foVector = "Zm8=".getBytes(); 15 | private static final byte[] fooVector = "Zm9v".getBytes(); 16 | private static final byte[] foobVector = "Zm9vYg==".getBytes(); 17 | private static final byte[] foobaVector = "Zm9vYmE=".getBytes(); 18 | private static final byte[] foobarVector = "Zm9vYmFy".getBytes(); 19 | 20 | /* 21 | * Random data fuzz 22 | */ 23 | private static final byte[] randomDataZeroMod = new byte[1000]; 24 | private static final byte[] randomDataOneMod = new byte[1001]; 25 | private static final byte[] randomDataTwoMod = new byte[1002]; 26 | private static final byte[] randomDataThreeMod = new byte[1003]; 27 | 28 | static { 29 | new Random().nextBytes(randomDataZeroMod); 30 | new Random().nextBytes(randomDataOneMod); 31 | new Random().nextBytes(randomDataTwoMod); 32 | new Random().nextBytes(randomDataThreeMod); 33 | } 34 | 35 | private static final byte[] base64RandomDataZeroMod = java.util.Base64.getUrlEncoder().encode(randomDataZeroMod); 36 | private static final byte[] base64RandomDataOneMod = java.util.Base64.getUrlEncoder().encode(randomDataOneMod); 37 | private static final byte[] base64RandomDataTwoMod = java.util.Base64.getUrlEncoder().encode(randomDataTwoMod); 38 | private static final byte[] base64RandomDataThreeMod = java.util.Base64.getUrlEncoder().encode(randomDataThreeMod); 39 | 40 | @Test 41 | public void RFC4648DecodeEmptyVector() { 42 | String jdzRes = new String(com.joad.jdz.base64.vector.Base64Vector.getUrlDecoder().decodeFast(emptyVector)); 43 | 44 | assertEquals("", jdzRes); 45 | } 46 | 47 | @Test 48 | public void RFC4648DecodefVector() { 49 | String jdzRes = new String(com.joad.jdz.base64.vector.Base64Vector.getUrlDecoder().decodeFast(fVector)); 50 | 51 | assertEquals("f", jdzRes); 52 | } 53 | 54 | @Test 55 | public void RFC4648DecodefoVector() { 56 | String jdzRes = new String(com.joad.jdz.base64.vector.Base64Vector.getUrlDecoder().decodeFast(foVector)); 57 | 58 | assertEquals("fo", jdzRes); 59 | } 60 | 61 | @Test 62 | public void RFC4648DecodefooVector() { 63 | String jdzRes = new String(com.joad.jdz.base64.vector.Base64Vector.getUrlDecoder().decodeFast(fooVector)); 64 | 65 | assertEquals("foo", jdzRes); 66 | } 67 | 68 | @Test 69 | public void RFC4648DecodefoobVector() { 70 | String jdzRes = new String(com.joad.jdz.base64.vector.Base64Vector.getUrlDecoder().decodeFast(foobVector)); 71 | 72 | assertEquals("foob", jdzRes); 73 | } 74 | 75 | @Test 76 | public void RFC4648DecodefoobaVector() { 77 | String jdzRes = new String(com.joad.jdz.base64.vector.Base64Vector.getUrlDecoder().decodeFast(foobaVector)); 78 | 79 | assertEquals("fooba", jdzRes); 80 | } 81 | 82 | @Test 83 | public void RFC4648DecodefoobarVector() { 84 | String jdzRes = new String(com.joad.jdz.base64.vector.Base64Vector.getUrlDecoder().decodeFast(foobarVector)); 85 | 86 | assertEquals("foobar", jdzRes); 87 | } 88 | 89 | @Test 90 | public void RFC4648DecodeZeroMod() { 91 | String javaRes = new String(java.util.Base64.getUrlDecoder().decode(base64RandomDataZeroMod)); 92 | String jdzRes = new String(com.joad.jdz.base64.vector.Base64Vector.getUrlDecoder().decodeFast(base64RandomDataZeroMod)); 93 | 94 | assertEquals(javaRes, jdzRes); 95 | } 96 | 97 | @Test 98 | public void RFC4648DecodeOneMod() { 99 | String javaRes = new String(java.util.Base64.getUrlDecoder().decode(base64RandomDataOneMod)); 100 | String jdzRes = new String(com.joad.jdz.base64.vector.Base64Vector.getUrlDecoder().decodeFast(base64RandomDataOneMod)); 101 | 102 | assertEquals(javaRes, jdzRes); 103 | } 104 | 105 | @Test 106 | public void RFC4648DecodeTwoMod() { 107 | String javaRes = new String(java.util.Base64.getUrlDecoder().decode(base64RandomDataTwoMod)); 108 | String jdzRes = new String(com.joad.jdz.base64.vector.Base64Vector.getUrlDecoder().decodeFast(base64RandomDataTwoMod)); 109 | 110 | assertEquals(javaRes, jdzRes); 111 | } 112 | 113 | @Test 114 | public void RFC4648DecodeThreeMod() { 115 | String javaRes = new String(java.util.Base64.getUrlDecoder().decode(base64RandomDataThreeMod)); 116 | String jdzRes = new String(com.joad.jdz.base64.vector.Base64Vector.getUrlDecoder().decodeFast(base64RandomDataThreeMod)); 117 | 118 | assertEquals(javaRes, jdzRes); 119 | } 120 | } 121 | -------------------------------------------------------------------------------- /base64/src/test/java/com/joad/jdz/base64/vector/RFC4648URLVectorDecodeTest.java: -------------------------------------------------------------------------------- 1 | package com.joad.jdz.base64.vector; 2 | 3 | import static org.junit.Assert.*; 4 | 5 | import java.util.Random; 6 | import org.junit.Test; 7 | 8 | public class RFC4648URLVectorDecodeTest { 9 | /* 10 | * RFC4648 test vectors 11 | */ 12 | private static final byte[] emptyVector = "".getBytes(); 13 | private static final byte[] fVector = "Zg==".getBytes(); 14 | private static final byte[] foVector = "Zm8=".getBytes(); 15 | private static final byte[] fooVector = "Zm9v".getBytes(); 16 | private static final byte[] foobVector = "Zm9vYg==".getBytes(); 17 | private static final byte[] foobaVector = "Zm9vYmE=".getBytes(); 18 | private static final byte[] foobarVector = "Zm9vYmFy".getBytes(); 19 | 20 | /* 21 | * Random data fuzz 22 | */ 23 | private static final byte[] randomDataZeroMod = new byte[1000]; 24 | private static final byte[] randomDataOneMod = new byte[1001]; 25 | private static final byte[] randomDataTwoMod = new byte[1002]; 26 | private static final byte[] randomDataThreeMod = new byte[1003]; 27 | 28 | static { 29 | new Random().nextBytes(randomDataZeroMod); 30 | new Random().nextBytes(randomDataOneMod); 31 | new Random().nextBytes(randomDataTwoMod); 32 | new Random().nextBytes(randomDataThreeMod); 33 | } 34 | 35 | private static final byte[] base64RandomDataZeroMod = java.util.Base64.getUrlEncoder().encode(randomDataZeroMod); 36 | private static final byte[] base64RandomDataOneMod = java.util.Base64.getUrlEncoder().encode(randomDataOneMod); 37 | private static final byte[] base64RandomDataTwoMod = java.util.Base64.getUrlEncoder().encode(randomDataTwoMod); 38 | private static final byte[] base64RandomDataThreeMod = java.util.Base64.getUrlEncoder().encode(randomDataThreeMod); 39 | private static final byte[] base64InvalidData = java.util.Base64.getUrlEncoder().encode(randomDataZeroMod); 40 | 41 | @Test 42 | public void RFC4648URLDecodeEmptyVector() { 43 | String jdzRes = new String(com.joad.jdz.base64.vector.Base64Vector.getUrlDecoder().decode(emptyVector)); 44 | 45 | assertEquals("", jdzRes); 46 | } 47 | 48 | @Test 49 | public void RFC4648URLDecodefVector() { 50 | String jdzRes = new String(com.joad.jdz.base64.vector.Base64Vector.getUrlDecoder().decode(fVector)); 51 | 52 | assertEquals("f", jdzRes); 53 | } 54 | 55 | @Test 56 | public void RFC4648URLDecodefoVector() { 57 | String jdzRes = new String(com.joad.jdz.base64.vector.Base64Vector.getUrlDecoder().decode(foVector)); 58 | 59 | assertEquals("fo", jdzRes); 60 | } 61 | 62 | @Test 63 | public void RFC4648URLDecodefooVector() { 64 | String jdzRes = new String(com.joad.jdz.base64.vector.Base64Vector.getUrlDecoder().decode(fooVector)); 65 | 66 | assertEquals("foo", jdzRes); 67 | } 68 | 69 | @Test 70 | public void RFC4648URLDecodefoobVector() { 71 | String jdzRes = new String(com.joad.jdz.base64.vector.Base64Vector.getUrlDecoder().decode(foobVector)); 72 | 73 | assertEquals("foob", jdzRes); 74 | } 75 | 76 | @Test 77 | public void RFC4648URLDecodefoobaVector() { 78 | String jdzRes = new String(com.joad.jdz.base64.vector.Base64Vector.getUrlDecoder().decode(foobaVector)); 79 | 80 | assertEquals("fooba", jdzRes); 81 | } 82 | 83 | @Test 84 | public void RFC4648URLDecodefoobarVector() { 85 | String jdzRes = new String(com.joad.jdz.base64.vector.Base64Vector.getUrlDecoder().decode(foobarVector)); 86 | 87 | assertEquals("foobar", jdzRes); 88 | } 89 | 90 | @Test 91 | public void RFC4648URLDecodeZeroMod() { 92 | String javaRes = new String(java.util.Base64.getUrlDecoder().decode(base64RandomDataZeroMod)); 93 | String jdzRes = new String(com.joad.jdz.base64.vector.Base64Vector.getUrlDecoder().decode(base64RandomDataZeroMod)); 94 | 95 | assertEquals(javaRes, jdzRes); 96 | } 97 | 98 | @Test 99 | public void RFC4648URLDecodeOneMod() { 100 | String javaRes = new String(java.util.Base64.getUrlDecoder().decode(base64RandomDataOneMod)); 101 | String jdzRes = new String(com.joad.jdz.base64.vector.Base64Vector.getUrlDecoder().decode(base64RandomDataOneMod)); 102 | 103 | assertEquals(javaRes, jdzRes); 104 | } 105 | 106 | @Test 107 | public void RFC4648URLDecodeTwoMod() { 108 | String javaRes = new String(java.util.Base64.getUrlDecoder().decode(base64RandomDataTwoMod)); 109 | String jdzRes = new String(com.joad.jdz.base64.vector.Base64Vector.getUrlDecoder().decode(base64RandomDataTwoMod)); 110 | 111 | assertEquals(javaRes, jdzRes); 112 | } 113 | 114 | @Test 115 | public void RFC4648URLDecodeThreeMod() { 116 | String javaRes = new String(java.util.Base64.getUrlDecoder().decode(base64RandomDataThreeMod)); 117 | String jdzRes = new String(com.joad.jdz.base64.vector.Base64Vector.getUrlDecoder().decode(base64RandomDataThreeMod)); 118 | 119 | assertEquals(javaRes, jdzRes); 120 | } 121 | 122 | @Test 123 | public void RFC4648URLInvalidInputDecode() { 124 | base64InvalidData[100] = (byte) '$'; 125 | base64InvalidData[101] = (byte) '$'; 126 | base64InvalidData[102] = (byte) '$'; 127 | base64InvalidData[103] = (byte) '$'; 128 | 129 | String exception = "No exception"; 130 | 131 | try { 132 | com.joad.jdz.base64.vector.Base64Vector.getUrlDecoder().decode(base64InvalidData); 133 | } 134 | catch (Exception e) { 135 | exception = e.getMessage(); 136 | } 137 | 138 | assertEquals("Illegal base64 character 24 at position 100", exception); 139 | } 140 | } 141 | -------------------------------------------------------------------------------- /base64/src/test/java/com/joad/jdz/base64/vector/RFC4648URLVectorEncodeTest.java: -------------------------------------------------------------------------------- 1 | package com.joad.jdz.base64.vector; 2 | 3 | import static org.junit.Assert.*; 4 | 5 | import java.util.Random; 6 | import org.junit.Test; 7 | 8 | public class RFC4648URLVectorEncodeTest { 9 | /* 10 | * RFC4648 test vectors 11 | */ 12 | private static final byte[] emptyVector = "".getBytes(); 13 | private static final byte[] fVector = "f".getBytes(); 14 | private static final byte[] foVector = "fo".getBytes(); 15 | private static final byte[] fooVector = "foo".getBytes(); 16 | private static final byte[] foobVector = "foob".getBytes(); 17 | private static final byte[] foobaVector = "fooba".getBytes(); 18 | private static final byte[] foobarVector = "foobar".getBytes(); 19 | 20 | /* 21 | * Random data fuzz 22 | */ 23 | private static final byte[] randomDataZeroMod = new byte[1000]; 24 | private static final byte[] randomDataOneMod = new byte[1001]; 25 | private static final byte[] randomDataTwoMod = new byte[1002]; 26 | private static final byte[] randomDataThreeMod = new byte[1003]; 27 | 28 | static { 29 | new Random().nextBytes(randomDataZeroMod); 30 | new Random().nextBytes(randomDataOneMod); 31 | new Random().nextBytes(randomDataTwoMod); 32 | new Random().nextBytes(randomDataThreeMod); 33 | } 34 | 35 | @Test 36 | public void RFC4648EncodeEmptyVector() { 37 | String jdzRes = new String(com.joad.jdz.base64.vector.Base64Vector.getUrlEncoder().encode(emptyVector)); 38 | 39 | assertEquals("", jdzRes); 40 | } 41 | 42 | @Test 43 | public void RFC4648EncodefVector() { 44 | String jdzRes = new String(com.joad.jdz.base64.vector.Base64Vector.getUrlEncoder().encode(fVector)); 45 | 46 | assertEquals("Zg==", jdzRes); 47 | } 48 | 49 | @Test 50 | public void RFC4648EncodefoVector() { 51 | String jdzRes = new String(com.joad.jdz.base64.vector.Base64Vector.getUrlEncoder().encode(foVector)); 52 | 53 | assertEquals("Zm8=", jdzRes); 54 | } 55 | 56 | @Test 57 | public void RFC4648EncodefooVector() { 58 | String jdzRes = new String(com.joad.jdz.base64.vector.Base64Vector.getUrlEncoder().encode(fooVector)); 59 | 60 | assertEquals("Zm9v", jdzRes); 61 | } 62 | 63 | @Test 64 | public void RFC4648EncodefoobVector() { 65 | String jdzRes = new String(com.joad.jdz.base64.vector.Base64Vector.getUrlEncoder().encode(foobVector)); 66 | 67 | assertEquals("Zm9vYg==", jdzRes); 68 | } 69 | 70 | @Test 71 | public void RFC4648EncodefoobaVector() { 72 | String jdzRes = new String(com.joad.jdz.base64.vector.Base64Vector.getUrlEncoder().encode(foobaVector)); 73 | 74 | assertEquals("Zm9vYmE=", jdzRes); 75 | } 76 | 77 | @Test 78 | public void RFC4648EncodefoobarVector() { 79 | String jdzRes = new String(com.joad.jdz.base64.vector.Base64Vector.getUrlEncoder().encode(foobarVector)); 80 | 81 | assertEquals("Zm9vYmFy", jdzRes); 82 | } 83 | @Test 84 | public void RFC4648EncodeZeroMod() { 85 | String javaRes = new String(java.util.Base64.getUrlEncoder().encode(randomDataZeroMod)); 86 | String joadRes = new String(com.joad.jdz.base64.vector.Base64Vector.getUrlEncoder().encode(randomDataZeroMod)); 87 | 88 | assertEquals(javaRes, joadRes); 89 | } 90 | 91 | @Test 92 | public void RFC4648EncodeOneMod() { 93 | String javaRes = new String(java.util.Base64.getUrlEncoder().encode(randomDataOneMod)); 94 | String joadRes = new String(com.joad.jdz.base64.vector.Base64Vector.getUrlEncoder().encode(randomDataOneMod)); 95 | 96 | assertEquals(javaRes, joadRes); 97 | } 98 | 99 | @Test 100 | public void RFC4648EncodeTwoMod() { 101 | String javaRes = new String(java.util.Base64.getUrlEncoder().encode(randomDataTwoMod)); 102 | String joadRes = new String(com.joad.jdz.base64.vector.Base64Vector.getUrlEncoder().encode(randomDataTwoMod)); 103 | 104 | assertEquals(javaRes, joadRes); 105 | } 106 | 107 | @Test 108 | public void RFC4648EncodeThreeMod() { 109 | String javaRes = new String(java.util.Base64.getUrlEncoder().encode(randomDataThreeMod)); 110 | String joadRes = new String(com.joad.jdz.base64.vector.Base64Vector.getUrlEncoder().encode(randomDataThreeMod)); 111 | 112 | assertEquals(javaRes, joadRes); 113 | } 114 | } -------------------------------------------------------------------------------- /base64/src/test/java/com/joad/jdz/base64/vector/RFC4648VectorDecodeTest.java: -------------------------------------------------------------------------------- 1 | package com.joad.jdz.base64.vector; 2 | 3 | import static org.junit.Assert.*; 4 | 5 | import java.util.Random; 6 | import org.junit.Test; 7 | 8 | public class RFC4648VectorDecodeTest { 9 | /* 10 | * RFC4648 test vectors 11 | */ 12 | private static final byte[] emptyVector = "".getBytes(); 13 | private static final byte[] fVector = "Zg==".getBytes(); 14 | private static final byte[] foVector = "Zm8=".getBytes(); 15 | private static final byte[] fooVector = "Zm9v".getBytes(); 16 | private static final byte[] foobVector = "Zm9vYg==".getBytes(); 17 | private static final byte[] foobaVector = "Zm9vYmE=".getBytes(); 18 | private static final byte[] foobarVector = "Zm9vYmFy".getBytes(); 19 | 20 | /* 21 | * Random data fuzz 22 | */ 23 | private static final byte[] randomDataZeroMod = new byte[1000]; 24 | private static final byte[] randomDataOneMod = new byte[1001]; 25 | private static final byte[] randomDataTwoMod = new byte[1002]; 26 | private static final byte[] randomDataThreeMod = new byte[1003]; 27 | 28 | static { 29 | new Random().nextBytes(randomDataZeroMod); 30 | new Random().nextBytes(randomDataOneMod); 31 | new Random().nextBytes(randomDataTwoMod); 32 | new Random().nextBytes(randomDataThreeMod); 33 | } 34 | 35 | private static final byte[] base64RandomDataZeroMod = java.util.Base64.getEncoder().encode(randomDataZeroMod); 36 | private static final byte[] base64RandomDataOneMod = java.util.Base64.getEncoder().encode(randomDataOneMod); 37 | private static final byte[] base64RandomDataTwoMod = java.util.Base64.getEncoder().encode(randomDataTwoMod); 38 | private static final byte[] base64RandomDataThreeMod = java.util.Base64.getEncoder().encode(randomDataThreeMod); 39 | private static final byte[] base64InvalidData = java.util.Base64.getEncoder().encode(randomDataZeroMod); 40 | 41 | @Test 42 | public void RFC4648DecodeEmptyVector() { 43 | String jdzRes = new String(com.joad.jdz.base64.vector.Base64Vector.getDecoder().decode(emptyVector)); 44 | 45 | assertEquals("", jdzRes); 46 | } 47 | 48 | @Test 49 | public void RFC4648DecodefVector() { 50 | String jdzRes = new String(com.joad.jdz.base64.vector.Base64Vector.getDecoder().decode(fVector)); 51 | 52 | assertEquals("f", jdzRes); 53 | } 54 | 55 | @Test 56 | public void RFC4648DecodefoVector() { 57 | String jdzRes = new String(com.joad.jdz.base64.vector.Base64Vector.getDecoder().decode(foVector)); 58 | 59 | assertEquals("fo", jdzRes); 60 | } 61 | 62 | @Test 63 | public void RFC4648DecodefooVector() { 64 | String jdzRes = new String(com.joad.jdz.base64.vector.Base64Vector.getDecoder().decode(fooVector)); 65 | 66 | assertEquals("foo", jdzRes); 67 | } 68 | 69 | @Test 70 | public void RFC4648DecodefoobVector() { 71 | String jdzRes = new String(com.joad.jdz.base64.vector.Base64Vector.getDecoder().decode(foobVector)); 72 | 73 | assertEquals("foob", jdzRes); 74 | } 75 | 76 | @Test 77 | public void RFC4648DecodefoobaVector() { 78 | String jdzRes = new String(com.joad.jdz.base64.vector.Base64Vector.getDecoder().decode(foobaVector)); 79 | 80 | assertEquals("fooba", jdzRes); 81 | } 82 | 83 | @Test 84 | public void RFC4648DecodefoobarVector() { 85 | String jdzRes = new String(com.joad.jdz.base64.vector.Base64Vector.getDecoder().decode(foobarVector)); 86 | 87 | assertEquals("foobar", jdzRes); 88 | } 89 | 90 | @Test 91 | public void RFC4648DecodeZeroMod() { 92 | String javaRes = new String(java.util.Base64.getDecoder().decode(base64RandomDataZeroMod)); 93 | String jdzRes = new String(com.joad.jdz.base64.vector.Base64Vector.getDecoder().decode(base64RandomDataZeroMod)); 94 | 95 | assertEquals(javaRes, jdzRes); 96 | } 97 | 98 | @Test 99 | public void RFC4648DecodeOneMod() { 100 | String javaRes = new String(java.util.Base64.getDecoder().decode(base64RandomDataOneMod)); 101 | String jdzRes = new String(com.joad.jdz.base64.vector.Base64Vector.getDecoder().decode(base64RandomDataOneMod)); 102 | 103 | assertEquals(javaRes, jdzRes); 104 | } 105 | 106 | @Test 107 | public void RFC4648DecodeTwoMod() { 108 | String javaRes = new String(java.util.Base64.getDecoder().decode(base64RandomDataTwoMod)); 109 | String jdzRes = new String(com.joad.jdz.base64.vector.Base64Vector.getDecoder().decode(base64RandomDataTwoMod)); 110 | 111 | assertEquals(javaRes, jdzRes); 112 | } 113 | 114 | @Test 115 | public void RFC4648DecodeThreeMod() { 116 | String javaRes = new String(java.util.Base64.getDecoder().decode(base64RandomDataThreeMod)); 117 | String jdzRes = new String(com.joad.jdz.base64.vector.Base64Vector.getDecoder().decode(base64RandomDataThreeMod)); 118 | 119 | assertEquals(javaRes, jdzRes); 120 | } 121 | 122 | @Test 123 | public void RFC4648InvalidInputDecode() { 124 | base64InvalidData[100] = (byte) '$'; 125 | base64InvalidData[101] = (byte) '$'; 126 | base64InvalidData[102] = (byte) '$'; 127 | base64InvalidData[103] = (byte) '$'; 128 | 129 | String exception = "No exception"; 130 | 131 | try { 132 | com.joad.jdz.base64.vector.Base64Vector.getDecoder().decode(base64InvalidData); 133 | } 134 | catch (Exception e) { 135 | exception = e.getMessage(); 136 | } 137 | 138 | assertEquals("Illegal base64 character 24 at position 100", exception); 139 | } 140 | } -------------------------------------------------------------------------------- /base64/src/test/java/com/joad/jdz/base64/vector/RFC4648VectorEncodeTest.java: -------------------------------------------------------------------------------- 1 | package com.joad.jdz.base64.vector; 2 | 3 | import static org.junit.Assert.*; 4 | 5 | import java.util.Random; 6 | import org.junit.Test; 7 | 8 | public class RFC4648VectorEncodeTest { 9 | /* 10 | * RFC4648 test vectors 11 | */ 12 | private static final byte[] emptyVector = "".getBytes(); 13 | private static final byte[] fVector = "f".getBytes(); 14 | private static final byte[] foVector = "fo".getBytes(); 15 | private static final byte[] fooVector = "foo".getBytes(); 16 | private static final byte[] foobVector = "foob".getBytes(); 17 | private static final byte[] foobaVector = "fooba".getBytes(); 18 | private static final byte[] foobarVector = "foobar".getBytes(); 19 | 20 | /* 21 | * Random data fuzz 22 | */ 23 | private static final byte[] randomDataZeroMod = new byte[1000]; 24 | private static final byte[] randomDataOneMod = new byte[1001]; 25 | private static final byte[] randomDataTwoMod = new byte[1002]; 26 | private static final byte[] randomDataThreeMod = new byte[1003]; 27 | 28 | static { 29 | new Random().nextBytes(randomDataZeroMod); 30 | new Random().nextBytes(randomDataOneMod); 31 | new Random().nextBytes(randomDataTwoMod); 32 | new Random().nextBytes(randomDataThreeMod); 33 | } 34 | 35 | @Test 36 | public void RFC4648EncodeEmptyVector() { 37 | String jdzRes = new String(com.joad.jdz.base64.vector.Base64Vector.getEncoder().encode(emptyVector)); 38 | 39 | assertEquals("", jdzRes); 40 | } 41 | 42 | @Test 43 | public void RFC4648EncodefVector() { 44 | String jdzRes = new String(com.joad.jdz.base64.vector.Base64Vector.getEncoder().encode(fVector)); 45 | 46 | assertEquals("Zg==", jdzRes); 47 | } 48 | 49 | @Test 50 | public void RFC4648EncodefoVector() { 51 | String jdzRes = new String(com.joad.jdz.base64.vector.Base64Vector.getEncoder().encode(foVector)); 52 | 53 | assertEquals("Zm8=", jdzRes); 54 | } 55 | 56 | @Test 57 | public void RFC4648EncodefooVector() { 58 | String jdzRes = new String(com.joad.jdz.base64.vector.Base64Vector.getEncoder().encode(fooVector)); 59 | 60 | assertEquals("Zm9v", jdzRes); 61 | } 62 | 63 | @Test 64 | public void RFC4648EncodefoobVector() { 65 | String jdzRes = new String(com.joad.jdz.base64.vector.Base64Vector.getEncoder().encode(foobVector)); 66 | 67 | assertEquals("Zm9vYg==", jdzRes); 68 | } 69 | 70 | @Test 71 | public void RFC4648EncodefoobaVector() { 72 | String jdzRes = new String(com.joad.jdz.base64.vector.Base64Vector.getEncoder().encode(foobaVector)); 73 | 74 | assertEquals("Zm9vYmE=", jdzRes); 75 | } 76 | 77 | @Test 78 | public void RFC4648EncodefoobarVector() { 79 | String jdzRes = new String(com.joad.jdz.base64.vector.Base64Vector.getEncoder().encode(foobarVector)); 80 | 81 | assertEquals("Zm9vYmFy", jdzRes); 82 | } 83 | @Test 84 | public void RFC4648EncodeZeroMod() { 85 | String javaRes = new String(java.util.Base64.getEncoder().encode(randomDataZeroMod)); 86 | String joadRes = new String(com.joad.jdz.base64.vector.Base64Vector.getEncoder().encode(randomDataZeroMod)); 87 | 88 | assertEquals(javaRes, joadRes); 89 | } 90 | 91 | @Test 92 | public void RFC4648EncodeOneMod() { 93 | String javaRes = new String(java.util.Base64.getEncoder().encode(randomDataOneMod)); 94 | String joadRes = new String(com.joad.jdz.base64.vector.Base64Vector.getEncoder().encode(randomDataOneMod)); 95 | 96 | assertEquals(javaRes, joadRes); 97 | } 98 | 99 | @Test 100 | public void RFC4648EncodeTwoMod() { 101 | String javaRes = new String(java.util.Base64.getEncoder().encode(randomDataTwoMod)); 102 | String joadRes = new String(com.joad.jdz.base64.vector.Base64Vector.getEncoder().encode(randomDataTwoMod)); 103 | 104 | assertEquals(javaRes, joadRes); 105 | } 106 | 107 | @Test 108 | public void RFC4648EncodeThreeMod() { 109 | String javaRes = new String(java.util.Base64.getEncoder().encode(randomDataThreeMod)); 110 | String joadRes = new String(com.joad.jdz.base64.vector.Base64Vector.getEncoder().encode(randomDataThreeMod)); 111 | 112 | assertEquals(javaRes, joadRes); 113 | } 114 | } -------------------------------------------------------------------------------- /bench/pom.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4.0.0 4 | 5 | com.joad.jdz 6 | jdz-parent 7 | 1.0 8 | ../pom.xml 9 | 10 | 11 | jdz-base64-bench 12 | 13 | Base64 Performance Benchmarks 14 | 15 | 16 | 17 | com.joad.jdz 18 | jdz-base64 19 | 1.0 20 | 21 | 22 | org.openjdk.jmh 23 | jmh-core 24 | ${jmh.version} 25 | 26 | 27 | org.openjdk.jmh 28 | jmh-generator-annprocess 29 | ${jmh.version} 30 | 31 | 32 | com.brsanthu 33 | migbase64 34 | 2.2 35 | 36 | 37 | net.iharder 38 | base64 39 | 2.3.9 40 | 41 | 42 | commons-codec 43 | commons-codec 44 | 1.16.0 45 | 46 | 47 | 48 | 49 | 50 | 51 | org.apache.maven.plugins 52 | maven-shade-plugin 53 | 54 | false 55 | jdz-bench.jar 56 | 57 | 59 | 60 | org.openjdk.jmh.Main 61 | true 62 | 63 | 64 | 65 | 66 | 67 | 68 | 69 | 70 | -------------------------------------------------------------------------------- /bench/src/main/java/com/joad/jdz/bench/BenchmarkBase.java: -------------------------------------------------------------------------------- 1 | package com.joad.jdz.bench; 2 | 3 | import java.util.concurrent.TimeUnit; 4 | import org.openjdk.jmh.annotations.BenchmarkMode; 5 | import org.openjdk.jmh.annotations.Fork; 6 | import org.openjdk.jmh.annotations.Measurement; 7 | import org.openjdk.jmh.annotations.OutputTimeUnit; 8 | import org.openjdk.jmh.annotations.State; 9 | import org.openjdk.jmh.annotations.Warmup; 10 | import org.openjdk.jmh.annotations.Scope; 11 | import org.openjdk.jmh.annotations.Mode; 12 | 13 | @Warmup(iterations = 5, time = 1, timeUnit = TimeUnit.SECONDS) 14 | @Measurement(iterations = 5, time = 1, timeUnit = TimeUnit.SECONDS) 15 | @Fork(value = 3, jvmArgsAppend = {"--add-modules", "jdk.incubator.vector"}) 16 | @State(Scope.Benchmark) 17 | @OutputTimeUnit(TimeUnit.SECONDS) 18 | @BenchmarkMode(Mode.Throughput) 19 | public abstract class BenchmarkBase { 20 | protected static final int ARR_LEN = 1000000; 21 | } -------------------------------------------------------------------------------- /bench/src/main/java/com/joad/jdz/bench/base64/Base64DecodeBenchmark.java: -------------------------------------------------------------------------------- 1 | package com.joad.jdz.bench.base64; 2 | 3 | import java.io.IOException; 4 | import java.util.Random; 5 | import org.openjdk.jmh.annotations.Benchmark; 6 | import com.joad.jdz.bench.BenchmarkBase; 7 | 8 | public class Base64DecodeBenchmark extends BenchmarkBase { 9 | private static final byte[] randomDataDec = new byte[ARR_LEN]; 10 | 11 | static { 12 | new Random().nextBytes(randomDataDec); 13 | } 14 | 15 | private static final byte[] randomData = java.util.Base64.getEncoder().encode(randomDataDec); 16 | 17 | private static final byte[] dst = new byte[com.joad.jdz.base64.scalar.Base64Scalar.getDecoder().getDecodedLength(randomData)]; 18 | 19 | @Benchmark 20 | public byte[] jdzBase64ScalarDecode() { 21 | return com.joad.jdz.base64.scalar.Base64Scalar.getDecoder().decode(randomData); 22 | } 23 | 24 | @Benchmark 25 | public byte[] jdzBase64ScalarDecodeReuse() { 26 | com.joad.jdz.base64.scalar.Base64Scalar.getDecoder().decode(randomData, dst); 27 | 28 | return dst; 29 | } 30 | 31 | @Benchmark 32 | public byte[] jdzBase64VectorDecode() { 33 | return com.joad.jdz.base64.vector.Base64Vector.getDecoder().decode(randomData); 34 | } 35 | 36 | @Benchmark 37 | public byte[] jdzBase64VectorDecodeReuse() { 38 | com.joad.jdz.base64.vector.Base64Vector.getDecoder().decode(randomData, dst); 39 | 40 | return dst; 41 | } 42 | 43 | @Benchmark 44 | public byte[] jdzBase64ScalarDecodeFast() { 45 | return com.joad.jdz.base64.scalar.Base64Scalar.getDecoder().decodeFast(randomData); 46 | } 47 | 48 | @Benchmark 49 | public byte[] jdzBase64ScalarDecodeReuseFast() { 50 | com.joad.jdz.base64.scalar.Base64Scalar.getDecoder().decodeFast(randomData, dst); 51 | 52 | return dst; 53 | } 54 | 55 | @Benchmark 56 | public byte[] jdzBase64VectorDecodeFast() { 57 | return com.joad.jdz.base64.vector.Base64Vector.getDecoder().decodeFast(randomData); 58 | } 59 | 60 | @Benchmark 61 | public byte[] jdzBase64VectorDecodeReuseFast() { 62 | com.joad.jdz.base64.vector.Base64Vector.getDecoder().decodeFast(randomData, dst); 63 | 64 | return dst; 65 | } 66 | 67 | @Benchmark 68 | public byte[] javaUtilBase64Decode() { 69 | return java.util.Base64.getDecoder().decode(randomData); 70 | } 71 | 72 | @Benchmark 73 | public byte[] javaUtilBase64DecodeReuse() { 74 | java.util.Base64.getDecoder().decode(randomData, dst); 75 | 76 | return dst; 77 | } 78 | 79 | @Benchmark 80 | public byte[] migBase64Decode() { 81 | return com.migcomponents.migbase64.Base64.decode(randomData); 82 | } 83 | 84 | @Benchmark 85 | public byte[] migBase64DecodeFast() { 86 | return com.migcomponents.migbase64.Base64.decodeFast(randomData); 87 | } 88 | 89 | @Benchmark 90 | public byte[] iharderBase64Decode() throws IOException { 91 | return net.iharder.Base64.decode(randomData, 0, randomData.length, 0); 92 | } 93 | 94 | @Benchmark 95 | public byte[] apacheBase64Decode() { 96 | return org.apache.commons.codec.binary.Base64.decodeBase64(randomData); 97 | } 98 | } 99 | -------------------------------------------------------------------------------- /bench/src/main/java/com/joad/jdz/bench/base64/Base64EncodeBenchmark.java: -------------------------------------------------------------------------------- 1 | package com.joad.jdz.bench.base64; 2 | 3 | import java.util.Random; 4 | import org.openjdk.jmh.annotations.Benchmark; 5 | import com.joad.jdz.bench.BenchmarkBase; 6 | import com.migcomponents.migbase64.Base64; 7 | 8 | public class Base64EncodeBenchmark extends BenchmarkBase { 9 | private static final byte[] randomData = new byte[ARR_LEN]; 10 | 11 | private static final int dl = Math.multiplyExact(4, (Math.addExact(randomData.length, 2) / 3)); 12 | 13 | private static final byte[] dst = new byte[dl]; 14 | 15 | static { 16 | new Random().nextBytes(randomData); 17 | } 18 | 19 | @Benchmark 20 | public byte[] jdzBase64VectorEncode() { 21 | return com.joad.jdz.base64.vector.Base64Vector.getEncoder().encode(randomData); 22 | } 23 | 24 | @Benchmark 25 | public byte[] jdzBase64VectorEncodeReuse() { 26 | com.joad.jdz.base64.vector.Base64Vector.getEncoder().encode(randomData, dst); 27 | 28 | return dst; 29 | } 30 | 31 | @Benchmark 32 | public byte[] jdzBase64ScalarEncode() { 33 | return com.joad.jdz.base64.scalar.Base64Scalar.getEncoder().encode(randomData); 34 | } 35 | 36 | @Benchmark 37 | public byte[] jdzBase64ScalarEncodeReuse() { 38 | com.joad.jdz.base64.scalar.Base64Scalar.getEncoder().encode(randomData, dst); 39 | 40 | return dst; 41 | } 42 | 43 | @Benchmark 44 | public byte[] javaUtilBase64Encode() { 45 | return java.util.Base64.getEncoder().encode(randomData); 46 | } 47 | 48 | @Benchmark 49 | public byte[] javaUtilBase64EncodeReuse() { 50 | java.util.Base64.getEncoder().encode(randomData, dst); 51 | 52 | return dst; 53 | } 54 | 55 | @Benchmark 56 | public byte[] migBase64Encode() { 57 | return Base64.encodeToByte(randomData, false); 58 | } 59 | 60 | @Benchmark 61 | public byte[] iharderBase64Encode() { 62 | return net.iharder.Base64.encodeBytesToBytes(randomData); 63 | } 64 | 65 | @Benchmark 66 | public byte[] apacheBase64Encode() { 67 | return org.apache.commons.codec.binary.Base64.encodeBase64(randomData); 68 | } 69 | } -------------------------------------------------------------------------------- /bench/src/main/java/com/joad/jdz/bench/base64/Base64MimeDecodeBenchmark.java: -------------------------------------------------------------------------------- 1 | package com.joad.jdz.bench.base64; 2 | 3 | import java.io.IOException; 4 | import java.util.Random; 5 | import org.openjdk.jmh.annotations.Benchmark; 6 | import com.joad.jdz.bench.BenchmarkBase; 7 | 8 | public class Base64MimeDecodeBenchmark extends BenchmarkBase { 9 | private static final byte[] randomDataDec = new byte[ARR_LEN]; 10 | 11 | static { 12 | new Random().nextBytes(randomDataDec); 13 | } 14 | 15 | private static final byte[] randomData = java.util.Base64.getMimeEncoder().encode(randomDataDec); 16 | 17 | private static final byte[] dst = new byte[com.joad.jdz.base64.scalar.Base64Scalar.getMimeDecoder().getDecodedLengthFast(randomData)]; 18 | 19 | @Benchmark 20 | public byte[] jdzBase64FastMimeScalarDecode() { 21 | return com.joad.jdz.base64.scalar.Base64Scalar.getMimeDecoder().decodeFast(randomData); 22 | } 23 | 24 | @Benchmark 25 | public byte[] jdzBase64FastMimeScalarDecodeReuse() { 26 | com.joad.jdz.base64.scalar.Base64Scalar.getMimeDecoder().decodeFast(randomData, dst); 27 | 28 | return dst; 29 | } 30 | 31 | @Benchmark 32 | public byte[] jdzBase64FastMimeVectorDecode() { 33 | return com.joad.jdz.base64.vector.Base64Vector.getMimeDecoder().decodeFast(randomData); 34 | } 35 | 36 | @Benchmark 37 | public byte[] jdzBase64FastMimeVectorDecodeReuse() { 38 | com.joad.jdz.base64.vector.Base64Vector.getMimeDecoder().decodeFast(randomData, dst); 39 | 40 | return dst; 41 | } 42 | 43 | @Benchmark 44 | public byte[] jdzBase64MimeScalarDecode() { 45 | return com.joad.jdz.base64.scalar.Base64Scalar.getMimeDecoder().decode(randomData); 46 | } 47 | 48 | @Benchmark 49 | public byte[] jdzBase64MimeScalarDecodeReuse() { 50 | com.joad.jdz.base64.scalar.Base64Scalar.getMimeDecoder().decode(randomData, dst); 51 | 52 | return dst; 53 | } 54 | 55 | @Benchmark 56 | public byte[] jdzBase64MimeVectorDecode() { 57 | return com.joad.jdz.base64.vector.Base64Vector.getMimeDecoder().decode(randomData); 58 | } 59 | 60 | @Benchmark 61 | public byte[] jdzBase64MimeVectorDecodeReuse() { 62 | com.joad.jdz.base64.vector.Base64Vector.getMimeDecoder().decode(randomData, dst); 63 | 64 | return dst; 65 | } 66 | 67 | @Benchmark 68 | public byte[] javaUtilBase64MimeDecode() { 69 | return java.util.Base64.getMimeDecoder().decode(randomData); 70 | } 71 | 72 | @Benchmark 73 | public byte[] javaUtilBase64MimeDecodeReuse() { 74 | java.util.Base64.getMimeDecoder().decode(randomData, dst); 75 | 76 | return dst; 77 | } 78 | 79 | @Benchmark 80 | public byte[] migBase64MimeDecode() { 81 | return com.migcomponents.migbase64.Base64.decode(randomData); 82 | } 83 | 84 | @Benchmark 85 | public byte[] migBase64MimeDecodeFast() { 86 | return com.migcomponents.migbase64.Base64.decodeFast(randomData); 87 | } 88 | 89 | @Benchmark 90 | public byte[] iharderBase64MimeDecode() throws IOException { 91 | return net.iharder.Base64.decode(randomData, 0, randomData.length, 8); 92 | } 93 | 94 | @Benchmark 95 | public byte[] apacheBase64MimeDecode() { 96 | return org.apache.commons.codec.binary.Base64.decodeBase64(randomData); 97 | } 98 | } 99 | -------------------------------------------------------------------------------- /bench/src/main/java/com/joad/jdz/bench/base64/Base64MimeEncodeBenchmark.java: -------------------------------------------------------------------------------- 1 | package com.joad.jdz.bench.base64; 2 | 3 | import java.io.IOException; 4 | import java.util.Random; 5 | import org.openjdk.jmh.annotations.Benchmark; 6 | import com.joad.jdz.bench.BenchmarkBase; 7 | import com.migcomponents.migbase64.Base64; 8 | 9 | public class Base64MimeEncodeBenchmark extends BenchmarkBase { 10 | private static final byte[] randomData = new byte[ARR_LEN]; 11 | 12 | private static final int dl = com.joad.jdz.base64.scalar.Base64Scalar.getMimeEncoder().getEncodedLength(randomData); 13 | 14 | private static final byte[] dst = new byte[dl]; 15 | 16 | static { 17 | new Random().nextBytes(randomData); 18 | } 19 | 20 | @Benchmark 21 | public byte[] jdzBase64MimeVectorEncode() { 22 | return com.joad.jdz.base64.vector.Base64Vector.getMimeEncoder().encode(randomData); 23 | } 24 | 25 | @Benchmark 26 | public byte[] jdzBase64MimeVectorEncodeReuse() { 27 | com.joad.jdz.base64.vector.Base64Vector.getMimeEncoder().encode(randomData, dst); 28 | 29 | return dst; 30 | } 31 | 32 | @Benchmark 33 | public byte[] jdzBase64MimeScalarEncode() { 34 | return com.joad.jdz.base64.scalar.Base64Scalar.getMimeEncoder().encode(randomData); 35 | } 36 | 37 | @Benchmark 38 | public byte[] jdzBase64MimeScalarEncodeReuse() { 39 | com.joad.jdz.base64.scalar.Base64Scalar.getMimeEncoder().encode(randomData, dst); 40 | 41 | return dst; 42 | } 43 | 44 | @Benchmark 45 | public byte[] javaUtilBase64MimeEncode() { 46 | return java.util.Base64.getMimeEncoder().encode(randomData); 47 | } 48 | 49 | @Benchmark 50 | public byte[] javaUtilBase64MimeEncodeReuse() { 51 | java.util.Base64.getMimeEncoder().encode(randomData, dst); 52 | 53 | return dst; 54 | } 55 | 56 | @Benchmark 57 | public byte[] migBase64MimeEncode() { 58 | return Base64.encodeToByte(randomData, true); 59 | } 60 | 61 | @Benchmark 62 | public byte[] iharderBase64MimeEncode() throws IOException { 63 | return net.iharder.Base64.encodeBytesToBytes(randomData, 0, randomData.length, 8); 64 | } 65 | 66 | @Benchmark 67 | public byte[] apacheBase64MimeEncode() { 68 | return org.apache.commons.codec.binary.Base64.encodeBase64Chunked(randomData); 69 | } 70 | } 71 | -------------------------------------------------------------------------------- /pom.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4.0.0 4 | 5 | com.joad.jdz 6 | jdz-parent 7 | 1.0 8 | pom 9 | 10 | jdz 11 | 12 | 13 | UTF-8 14 | 16 15 | 1.21 16 | 4.12 17 | 18 | 19 | 20 | base64 21 | bench 22 | 23 | 24 | 25 | 26 | 27 | 28 | org.codehaus.mojo 29 | build-helper-maven-plugin 30 | 3.0.0 31 | 32 | 33 | org.apache.maven.plugins 34 | maven-compiler-plugin 35 | 3.10.1 36 | 37 | 38 | org.apache.maven.plugins 39 | maven-dependency-plugin 40 | 3.1.0 41 | 42 | 43 | org.apache.maven.plugins 44 | maven-jar-plugin 45 | 3.2.0 46 | 47 | 48 | org.apache.maven.plugins 49 | maven-javadoc-plugin 50 | 3.1.0 51 | 52 | 53 | org.codehaus.mojo 54 | flatten-maven-plugin 55 | 1.5.0 56 | 57 | 58 | org.apache.maven.plugins 59 | maven-shade-plugin 60 | 3.4.1 61 | 62 | 63 | package 64 | 65 | shade 66 | 67 | 68 | 69 | 70 | *:* 71 | 72 | META-INF/*.SF 73 | META-INF/*.DSA 74 | META-INF/*.RSA 75 | META-INF/versions/11/module-info.class 76 | 77 | 78 | 79 | 80 | 81 | 82 | 83 | 84 | org.apache.maven.plugins 85 | maven-surefire-plugin 86 | 3.0.0 87 | 88 | 89 | 90 | 91 | 92 | org.apache.maven.plugins 93 | maven-compiler-plugin 94 | 95 | ${java.version} 96 | 97 | -Xlint:all 98 | --add-modules=jdk.incubator.vector 99 | 100 | 101 | 102 | 103 | org.apache.maven.plugins 104 | maven-surefire-plugin 105 | 106 | 107 | --add-modules=jdk.incubator.vector 108 | 109 | 110 | 111 | 112 | org.codehaus.mojo 113 | flatten-maven-plugin 114 | 115 | 116 | 117 | flatten 118 | process-resources 119 | 120 | flatten 121 | 122 | 123 | 124 | 125 | flatten.clean 126 | clean 127 | 128 | clean 129 | 130 | 131 | 132 | 133 | 134 | 135 | 136 | --------------------------------------------------------------------------------