diff --git a/.github/workflows/codeql-analysis.yml b/.github/workflows/codeql-analysis.yml index c50eccfd28..5f3a488e4f 100644 --- a/.github/workflows/codeql-analysis.yml +++ b/.github/workflows/codeql-analysis.yml @@ -45,10 +45,10 @@ jobs: steps: - name: Checkout repository - uses: actions/checkout@b4ffde65f46336ab88eb53be808477a3936bae11 # 4.1.1 + uses: actions/checkout@1d96c772d19495a3b5c517cd2bc0cb401ea0529f # 4.1.3 with: persist-credentials: false - - uses: actions/cache@13aacd865c20de90d75de3b17ebe84f7a17d57d2 # v4.0.0 + - uses: actions/cache@0c45773b623bea8c8e75f6c82b208c3cf94ea4f9 # v4.0.2 with: path: ~/.m2/repository key: ${{ runner.os }}-maven-${{ hashFiles('**/pom.xml') }} @@ -57,7 +57,7 @@ jobs: # Initializes the CodeQL tools for scanning. - name: Initialize CodeQL - uses: github/codeql-action/init@b7bf0a3ed3ecfa44160715d7c442788f65f0f923 # 3.23.2 + uses: github/codeql-action/init@c7f9125735019aa87cfc361530512d50ea439c71 # 3.25.1 with: languages: ${{ matrix.language }} # If you wish to specify custom queries, you can do so here or in a config file. @@ -68,7 +68,7 @@ jobs: # Autobuild attempts to build any compiled languages (C/C++, C#, or Java). # If this step fails, then you should remove it and run the build manually (see below) - name: Autobuild - uses: github/codeql-action/autobuild@b7bf0a3ed3ecfa44160715d7c442788f65f0f923 # 3.23.2 + uses: github/codeql-action/autobuild@c7f9125735019aa87cfc361530512d50ea439c71 # 3.25.1 # ℹ️ Command-line programs to run using the OS shell. # 📚 https://git.io/JvXDl @@ -82,4 +82,4 @@ jobs: # make release - name: Perform CodeQL Analysis - uses: github/codeql-action/analyze@b7bf0a3ed3ecfa44160715d7c442788f65f0f923 # 3.23.2 + uses: github/codeql-action/analyze@c7f9125735019aa87cfc361530512d50ea439c71 # 3.25.1 diff --git a/.github/workflows/coverage.yml b/.github/workflows/coverage.yml index ec4859063d..1f3beb86ce 100644 --- a/.github/workflows/coverage.yml +++ b/.github/workflows/coverage.yml @@ -29,17 +29,17 @@ jobs: java: [ 8 ] steps: - - uses: actions/checkout@b4ffde65f46336ab88eb53be808477a3936bae11 # 4.1.1 + - uses: actions/checkout@1d96c772d19495a3b5c517cd2bc0cb401ea0529f # 4.1.3 with: persist-credentials: false - - uses: actions/cache@13aacd865c20de90d75de3b17ebe84f7a17d57d2 # v4.0.0 + - uses: actions/cache@0c45773b623bea8c8e75f6c82b208c3cf94ea4f9 # v4.0.2 with: path: ~/.m2/repository key: ${{ runner.os }}-maven-${{ hashFiles('**/pom.xml') }} restore-keys: | ${{ runner.os }}-maven- - name: Set up JDK ${{ matrix.java }} - uses: actions/setup-java@387ac29b308b003ca37ba93a6cab5eb57c8f5f93 # v4.0.0 + uses: actions/setup-java@99b8673ff64fbf99d8d325f52d9a5bdedb8483e9 # v4.2.1 with: distribution: 'temurin' java-version: ${{ matrix.java }} @@ -47,6 +47,6 @@ jobs: run: mvn --show-version --batch-mode --no-transfer-progress test jacoco:report - name: Upload coverage to Codecov - uses: codecov/codecov-action@e0b68c6749509c5f83f984dd99a76a1c1a231044 # v4.0.1 + uses: codecov/codecov-action@84508663e988701840491b86de86b666e8a86bed # v4.3.0 with: files: ./target/site/jacoco/jacoco.xml diff --git a/.github/workflows/maven.yml b/.github/workflows/maven.yml index 3a9d0e5b36..3b5054ac74 100644 --- a/.github/workflows/maven.yml +++ b/.github/workflows/maven.yml @@ -34,17 +34,17 @@ jobs: experimental: true steps: - - uses: actions/checkout@b4ffde65f46336ab88eb53be808477a3936bae11 # 4.1.1 + - uses: actions/checkout@1d96c772d19495a3b5c517cd2bc0cb401ea0529f # 4.1.3 with: persist-credentials: false - - uses: actions/cache@13aacd865c20de90d75de3b17ebe84f7a17d57d2 # v4.0.0 + - uses: actions/cache@0c45773b623bea8c8e75f6c82b208c3cf94ea4f9 # v4.0.2 with: path: ~/.m2/repository key: ${{ runner.os }}-maven-${{ hashFiles('**/pom.xml') }} restore-keys: | ${{ runner.os }}-maven- - name: Set up JDK ${{ matrix.java }} - uses: actions/setup-java@387ac29b308b003ca37ba93a6cab5eb57c8f5f93 # v4.0.0 + uses: actions/setup-java@99b8673ff64fbf99d8d325f52d9a5bdedb8483e9 # v4.2.1 with: distribution: 'temurin' java-version: ${{ matrix.java }} diff --git a/.github/workflows/scorecards-analysis.yml b/.github/workflows/scorecards-analysis.yml index 31f9d421c8..c22ee1c0e1 100644 --- a/.github/workflows/scorecards-analysis.yml +++ b/.github/workflows/scorecards-analysis.yml @@ -40,7 +40,7 @@ jobs: steps: - name: "Checkout code" - uses: actions/checkout@b4ffde65f46336ab88eb53be808477a3936bae11 # 4.1.1 + uses: actions/checkout@1d96c772d19495a3b5c517cd2bc0cb401ea0529f # 4.1.3 with: persist-credentials: false @@ -57,13 +57,13 @@ jobs: publish_results: true - name: "Upload artifact" - uses: actions/upload-artifact@26f96dfa697d77e81fd5907df203aa23a56210a8 # v4.3.0 + uses: actions/upload-artifact@1746f4ab65b179e0ea60a494b83293b640dd5bba # v4.3.2 with: name: SARIF file path: results.sarif retention-days: 5 - name: "Upload to code-scanning" - uses: github/codeql-action/upload-sarif@b7bf0a3ed3ecfa44160715d7c442788f65f0f923 # 3.23.2 + uses: github/codeql-action/upload-sarif@c7f9125735019aa87cfc361530512d50ea439c71 # 3.25.1 with: sarif_file: results.sarif diff --git a/README.md b/README.md index 66cda56ccc..6ad95c8878 100644 --- a/README.md +++ b/README.md @@ -46,7 +46,7 @@ Apache Commons Codec [![Java CI](https://github.com/apache/commons-codec/actions/workflows/maven.yml/badge.svg)](https://github.com/apache/commons-codec/actions/workflows/maven.yml) [![Coverage Status](https://codecov.io/gh/apache/commons-codec/branch/master/graph/badge.svg)](https://app.codecov.io/gh/apache/commons-codec) [![Maven Central](https://maven-badges.herokuapp.com/maven-central/commons-codec/commons-codec/badge.svg?gav=true)](https://maven-badges.herokuapp.com/maven-central/commons-codec/commons-codec/?gav=true) -[![Javadocs](https://javadoc.io/badge/commons-codec/commons-codec/1.16.1.svg)](https://javadoc.io/doc/commons-codec/commons-codec/1.16.1) +[![Javadocs](https://javadoc.io/badge/commons-codec/commons-codec/1.17.0.svg)](https://javadoc.io/doc/commons-codec/commons-codec/1.17.0) [![CodeQL](https://github.com/apache/commons-codec/actions/workflows/codeql-analysis.yml/badge.svg)](https://github.com/apache/commons-codec/actions/workflows/codeql-analysis.yml) [![OpenSSF Scorecard](https://api.securityscorecards.dev/projects/github.com/apache/commons-codec/badge)](https://api.securityscorecards.dev/projects/github.com/apache/commons-codec) @@ -72,7 +72,7 @@ Alternatively, you can pull it from the central Maven repositories: commons-codec commons-codec - 1.16.1 + 1.17.0 ``` diff --git a/RELEASE-NOTES.txt b/RELEASE-NOTES.txt index 6137cdb113..ee1f2a3c34 100644 --- a/RELEASE-NOTES.txt +++ b/RELEASE-NOTES.txt @@ -1,5 +1,5 @@ -Apache Commons Codec 1.16.1 -RELEASE NOTES +Apache Commons Codec 1.17.0 RELEASE NOTES +----------------------------------------- The Apache Commons Codec component contains encoder and decoders for various formats such as Base16, Base32, Base64, digest, and Hexadecimal. In addition to these @@ -8,36 +8,88 @@ collection of phonetic encoding utilities. Feature and fix release. Requires a minimum of Java 8. -Changes in this version include: -New features: -o Add Maven property project.build.outputTimestamp for build reproducibility. Thanks to Gary Gregory. - -Fixed Bugs: -o CODEC-295: Test clean ups. Thanks to Gary Gregory. -o [StepSecurity] ci: Harden GitHub Actions #187. Thanks to step-security-bot, Gary Gregory. -o CODEC-295: Correct error in Base64 Javadoc #188. Thanks to Evan Saulpaugh. -o CODEC-295: Add minimum Java version in changes.xml #186. Thanks to Olivier Jaquemet, Gary Gregory. -o CODEC-310: Documentation update for the org.apache.commons.codec.digest.* package #208. Thanks to Yakov Shafranovich. -o Precompile regular expression in UnixCrypt.crypt(byte[], String). Thanks to Gary Gregory. -o CODEC-315: Fix possible IndexOutOfBoundException in PhoneticEngine.encode method #223. Thanks to Arthur Chan, Gary Gregory. -o CODEC-313: Fix possible ArrayIndexOutOfBoundsException in QuotedPrintableCodec.encodeQuotedPrintable() method #221. Thanks to Arthur Chan, Gary Gregory. -o CODEC-312: Fix possible StringIndexOutOfBoundException in MatchRatingApproachEncoder.encode() method #220. Thanks to Arthur Chan, Gary Gregory. -o CODEC-311: Fix possible ArrayIndexOutOfBoundException in RefinedSoundex.getMappingCode() #219. Thanks to Arthur Chan, Gary Gregory. -o CODEC-314: Fix possible IndexOutOfBoundsException in PercentCodec.insertAlwaysEncodeChars() method #222. Thanks to Arthur Chan, Gary Gregory. -o Deprecate UnixCrypt 0-argument constructor. Thanks to Gary Gregory. -o Deprecate Md5Crypt 0-argument constructor. Thanks to Gary Gregory. -o Deprecate Crypt 0-argument constructor. Thanks to Gary Gregory. -o Deprecate StringUtils 0-argument constructor. Thanks to Gary Gregory. -o Deprecate Resources 0-argument constructor. Thanks to Gary Gregory. -o Deprecate Charsets 0-argument constructor. Thanks to Gary Gregory. -o Deprecate CharEncoding 0-argument constructor. Thanks to Gary Gregory. -o Add missing version for animal-sniffer-maven-plugin. Thanks to Gary Gregory. - -Changes: -o Bump commons-parent from 58 to 66. Thanks to Dependabot, Gary Gregory. -o Bump commons-lang3 from 3.12.0 to 3.14.0. Thanks to Gary Gregory. -o Bump commons-io from 2.13.0 to 2.15.1. Thanks to Gary Gregory. +New features +------------ + +* Add override org.apache.commons.codec.language.bm.Rule.PhonemeExpr.size(). Thanks to Gary Gregory. +* Add support for Base64 custom alphabets #266. Thanks to Chris Kocel, Gary Gregory. +* Add Base64.Builder (allows custom alphabets). Thanks to Gary Gregory. +* Add Base32.Builder (allows custom alphabets). Thanks to Gary Gregory. +* Add Base64 support for a custom padding byte (like Base32). Thanks to Gary Gregory. + +Fixed Bugs +---------- + +* CODEC-320: Wrong output of DoubleMetaphone in 1.16.1. Thanks to Martin Frydl, Gary Gregory. +* Optimize memory allocation in PhoneticEngine. Thanks to Gary Gregory. +* BCodec and QCodec encode() methods throw UnsupportedCharsetException instead of EncoderException. Thanks to Gary Gregory. +* Set Javadoc link to latest Java API LTS version. Thanks to Gary Gregory. +* Base32 constructor fails-fast with a NullPointerException if the custom alphabet array is null. Thanks to Gary Gregory. +* Base32 constructor makes a defensive copy of the line separator array. Thanks to Gary Gregory. +* Base64 constructor makes a defensive copy of the line separator array. Thanks to Gary Gregory. +* Base64 constructor makes a defensive copy of a custom alphabet array. Thanks to Gary Gregory. + +Changes +------- + +* Bump org.apache.commons:commons-parent from 66 to 69 #250, #261. Thanks to Dependabot, Gary Gregory. +* Bump commons-io:commons-io from 2.15.1 to 2.16.1 #258, #265. Thanks to Dependabot, Gary Gregory. + + +For complete information on Apache Commons Codec, including instructions on how to submit bug reports, +patches, or suggestions for improvement, see the Apache Commons Codec website: + +https://commons.apache.org/proper/commons-codec/ + +Download page: https://commons.apache.org/proper/commons-codec/download_codec.cgi + +--------------------------------------------------------------------------------- + +Apache Commons Codec 1.16.1 RELEASE NOTES +----------------------------------------- + +The Apache Commons Codec component contains encoder and decoders for +various formats such as Base16, Base32, Base64, digest, and Hexadecimal. In addition to these +widely used encoders and decoders, the codec package also maintains a +collection of phonetic encoding utilities. + +Feature and fix release. Requires a minimum of Java 8. + +New features +------------ + +* Add Maven property project.build.outputTimestamp for build reproducibility. Thanks to Gary Gregory. + +Fixed Bugs +---------- + +* CODEC-295: Test clean ups. Thanks to Gary Gregory. +* [StepSecurity] ci: Harden GitHub Actions #187. Thanks to step-security-bot, Gary Gregory. +* CODEC-295: Correct error in Base64 Javadoc #188. Thanks to Evan Saulpaugh. +* CODEC-295: Add minimum Java version in changes.xml #186. Thanks to Olivier Jaquemet, Gary Gregory. +* CODEC-310: Documentation update for the org.apache.commons.codec.digest.* package #208. Thanks to Yakov Shafranovich. +* Precompile regular expression in UnixCrypt.crypt(byte[], String). Thanks to Gary Gregory. +* CODEC-315: Fix possible IndexOutOfBoundException in PhoneticEngine.encode method #223. Thanks to Arthur Chan, Gary Gregory. +* CODEC-313: Fix possible ArrayIndexOutOfBoundsException in QuotedPrintableCodec.encodeQuotedPrintable() method #221. Thanks to Arthur Chan, Gary Gregory. +* CODEC-312: Fix possible StringIndexOutOfBoundException in MatchRatingApproachEncoder.encode() method #220. Thanks to Arthur Chan, Gary Gregory. +* CODEC-311: Fix possible ArrayIndexOutOfBoundException in RefinedSoundex.getMappingCode() #219. Thanks to Arthur Chan, Gary Gregory. +* CODEC-314: Fix possible IndexOutOfBoundsException in PercentCodec.insertAlwaysEncodeChars() method #222. Thanks to Arthur Chan, Gary Gregory. +* Deprecate UnixCrypt 0-argument constructor. Thanks to Gary Gregory. +* Deprecate Md5Crypt 0-argument constructor. Thanks to Gary Gregory. +* Deprecate Crypt 0-argument constructor. Thanks to Gary Gregory. +* Deprecate StringUtils 0-argument constructor. Thanks to Gary Gregory. +* Deprecate Resources 0-argument constructor. Thanks to Gary Gregory. +* Deprecate Charsets 0-argument constructor. Thanks to Gary Gregory. +* Deprecate CharEncoding 0-argument constructor. Thanks to Gary Gregory. +* Add missing version for animal-sniffer-maven-plugin. Thanks to Gary Gregory. + +Changes +------- + +* Bump commons-parent from 58 to 66. Thanks to Dependabot, Gary Gregory. +* Bump commons-lang3 from 3.12.0 to 3.14.0. Thanks to Gary Gregory. +* Bump commons-io from 2.13.0 to 2.15.1. Thanks to Gary Gregory. For complete information on Apache Commons Codec, including instructions on how to submit bug reports, @@ -60,42 +112,48 @@ Feature and fix release. Changes in this version include: -New features: -o CODEC-296: Add support for Blake3 family of hashes. Thanks to Matt Sicker. -o Add github/codeql-action. - -Fixed Bugs: -o CODEC-295: Minor improvements #67. Thanks to Arturo Bernal. -o Remove duplicated words from Javadocs. Thanks to James Gan. -o CODEC-301: Simplify assertion #84. Thanks to Alexander Pinske, Alex Herbert. -o CODEC-300: Simplify assertion #84. Thanks to Arturo Bernal. -o CODEC-298: Use Standard Charset object #82. Thanks to Arturo Bernal. -o Use String.contains() functions #125. Thanks to Arturo Bernal. -o Avoid use toString() or substring() in favor of a simplified expression #126. Thanks to Arturo Bernal. -o CODEC-305: Fix byte-skipping in Base16 decoding #135. Thanks to Florian. -o Fix several typos, improve writing in some javadocs #139. Thanks to Marc Wrobel. -o BaseNCodecOutputStream.eof() should not throw IOException. Thanks to Gary Gregory. -o Javadoc improvements and cleanups. Thanks to Gary Gregory. -o Deprecate BaseNCodec.isWhiteSpace(byte) and use Character.isWhitespace(int). Thanks to Gary Gregory. - -Changes: -o Bump actions/cache from v2 to v3.0.10 #75, #99, #119, #138, #149, #152. Thanks to Dependabot, Gary Gregory. -o Bump actions/setup-java from v1.4.1 to 3.5.1 #60, #62, #121. Thanks to Dependabot, Gary Gregory. -o Bump actions/checkout from 2.3.2 to 3.1.0 #65, #98, #114, #153. Thanks to Dependabot, Gary Gregory. -o Bump commons-parent from 52 to 58, #147, #165, #170. Thanks to Dependabot, Gary Gregory. -o CODEC-285: Bump junit from 4.13.1 to 5.9.1 #76, #39, #140, #148. Thanks to Dependabot, John Patrick. -o Bump Java 7 to 8. Thanks to Gary Gregory. -o Bump japicmp-maven-plugin from 0.14.3 to 0.17.1. Thanks to Gary Gregory. -o Bump jacoco-maven-plugin from 0.8.5 to 0.8.8 (Fixes Java 15 builds). Thanks to Gary Gregory. -o Bump maven-surefire-plugin from 2.22.2 to 3.0.0-M7 #122, #134. Thanks to Gary Gregory. -o Bump maven-javadoc-plugin from 3.2.0 to 3.4.1. Thanks to Gary Gregory. -o Bump animal-sniffer-maven-plugin from 1.19 to 1.22. Thanks to Gary Gregory. -o Bump maven-pmd-plugin from 3.13.0 to 3.19.0, #133, #142, #145. Thanks to Gary Gregory, Dependabot. -o Bump pmd from 6.47.0 to 6.52.0. Thanks to Gary Gregory. -o Bump maven-checkstyle-plugin from 2.17 to 3.2.0 #143. Thanks to Gary Gregory. -o Bump checkstyle from 8.45.1 to 9.3 #97, #100, #101, #103. Thanks to Dependabot. -o Bump taglist-maven-plugin from 2.4 to 3.0.0 #102. Thanks to Dependabot. -o Bump jacoco-maven-plugin from 0.8.7 to 0.8.8. Thanks to Gary Gregory. +New features +------------ + +* CODEC-296: Add support for Blake3 family of hashes. Thanks to Matt Sicker. +* Add github/codeql-action. + +Fixed Bugs +---------- + +* CODEC-295: Minor improvements #67. Thanks to Arturo Bernal. +* Remove duplicated words from Javadocs. Thanks to James Gan. +* CODEC-301: Simplify assertion #84. Thanks to Alexander Pinske, Alex Herbert. +* CODEC-300: Simplify assertion #84. Thanks to Arturo Bernal. +* CODEC-298: Use Standard Charset object #82. Thanks to Arturo Bernal. +* Use String.contains() functions #125. Thanks to Arturo Bernal. +* Avoid use toString() or substring() in favor of a simplified expression #126. Thanks to Arturo Bernal. +* CODEC-305: Fix byte-skipping in Base16 decoding #135. Thanks to Florian. +* Fix several typos, improve writing in some javadocs #139. Thanks to Marc Wrobel. +* BaseNCodecOutputStream.eof() should not throw IOException. Thanks to Gary Gregory. +* Javadoc improvements and cleanups. Thanks to Gary Gregory. +* Deprecate BaseNCodec.isWhiteSpace(byte) and use Character.isWhitespace(int). Thanks to Gary Gregory. + +Changes +------- + +* Bump actions/cache from v2 to v3.0.10 #75, #99, #119, #138, #149, #152. Thanks to Dependabot, Gary Gregory. +* Bump actions/setup-java from v1.4.1 to 3.5.1 #60, #62, #121. Thanks to Dependabot, Gary Gregory. +* Bump actions/checkout from 2.3.2 to 3.1.0 #65, #98, #114, #153. Thanks to Dependabot, Gary Gregory. +* Bump commons-parent from 52 to 58, #147, #165, #170. Thanks to Dependabot, Gary Gregory. +* CODEC-285: Bump junit from 4.13.1 to 5.9.1 #76, #39, #140, #148. Thanks to Dependabot, John Patrick. +* Bump Java 7 to 8. Thanks to Gary Gregory. +* Bump japicmp-maven-plugin from 0.14.3 to 0.17.1. Thanks to Gary Gregory. +* Bump jacoco-maven-plugin from 0.8.5 to 0.8.8 (Fixes Java 15 builds). Thanks to Gary Gregory. +* Bump maven-surefire-plugin from 2.22.2 to 3.0.0-M7 #122, #134. Thanks to Gary Gregory. +* Bump maven-javadoc-plugin from 3.2.0 to 3.4.1. Thanks to Gary Gregory. +* Bump animal-sniffer-maven-plugin from 1.19 to 1.22. Thanks to Gary Gregory. +* Bump maven-pmd-plugin from 3.13.0 to 3.19.0, #133, #142, #145. Thanks to Gary Gregory, Dependabot. +* Bump pmd from 6.47.0 to 6.52.0. Thanks to Gary Gregory. +* Bump maven-checkstyle-plugin from 2.17 to 3.2.0 #143. Thanks to Gary Gregory. +* Bump checkstyle from 8.45.1 to 9.3 #97, #100, #101, #103. Thanks to Dependabot. +* Bump taglist-maven-plugin from 2.4 to 3.0.0 #102. Thanks to Dependabot. +* Bump jacoco-maven-plugin from 0.8.7 to 0.8.8. Thanks to Gary Gregory. For complete information on Apache Commons Codec, including instructions on how to submit bug reports, @@ -104,3 +162,5 @@ patches, or suggestions for improvement, see the Apache Commons Codec website: https://commons.apache.org/proper/commons-codec/ Download page: https://commons.apache.org/proper/commons-codec/download_codec.cgi + +--------------------------------------------------------------------------------- diff --git a/pom.xml b/pom.xml index 19002c2af2..9a407f652b 100644 --- a/pom.xml +++ b/pom.xml @@ -24,11 +24,11 @@ limitations under the License. org.apache.commons commons-parent - 66 + 69 commons-codec commons-codec - 1.16.1 + 1.17.0 Apache Commons Codec 2002 @@ -55,179 +55,6 @@ limitations under the License. ${commons.deployment.protocol}://people.apache.org/www/commons.apache.org/commons-${commons.componentid}/ - - - Henri Yandell - bayard - bayard@apache.org - - - Tim OBrien - tobrien - tobrien@apache.org - -6 - - - Scott Sanders - sanders - sanders@totalsync.com - - - Rodney Waldhoff - rwaldhoff - rwaldhoff@apache.org - - - Daniel Rall - dlr - dlr@finemaltcoding.com - - - Jon S. Stevens - jon - jon@collab.net - - - ggregory - Gary Gregory - ggregory at apache.org - https://www.garygregory.com - The Apache Software Foundation - https://www.apache.org/ - - PMC Member - - America/New_York - - https://people.apache.org/~ggregory/img/garydgregory80.png - - - - David Graham - dgraham - dgraham@apache.org - - - Julius Davies - julius - julius@apache.org - http://juliusdavies.ca/ - -8 - - - Thomas Neidhart - tn - tn@apache.org - - - Rob Tompkins - chtompki - chtompki@apache.org - - - Matt Sicker - mattsicker - mattsicker@apache.org - https://musigma.blog/ - - - - - Christopher O'Brien - siege@preoccupied.net - - hex - md5 - architecture - - - - Martin Redington - - Representing xml-rpc - - - - Jeffery Dever - - Representing http-client - - - - Steve Zimmermann - steve.zimmermann@heii.com - - Documentation - - - - Benjamin Walstrum - ben@walstrum.com - - - Oleg Kalnichevski - oleg@ural.ru - - Representing http-client - - - - Dave Dribin - apache@dave.dribin.org - - DigestUtil - - - - Alex Karasulu - aok123 at bellsouth.net - - Submitted Binary class and test - - - - Matthew Inger - mattinger at yahoo.com - - Submitted DIFFERENCE algorithm for Soundex and RefinedSoundex - - - - Jochen Wiedmann - jochen@apache.org - - Base64 code [CODEC-69] - - - - Sebastian Bazley - sebb@apache.org - - Streaming Base64 - - - - Matthew Pocock - turingatemyhamster@gmail.com - - Beider-Morse phonetic matching - - - - Colm Rice - colm_rice at hotmail dot com - - Submitted Match Rating Approach (MRA) phonetic encoder and tests [CODEC-161] - - - - Adam Retter - Evolved Binary - - Base16 Input and Output Streams - - - org.apache.commons @@ -238,7 +65,7 @@ limitations under the License. commons-io commons-io - 2.15.1 + 2.16.1 test @@ -273,13 +100,23 @@ limitations under the License. ${basedir}/src/conf/checkstyle.xml false - 1.16.1 - 1.16.0 - 1.16.2 + 1.17.0 + 1.16.1 + 1.17.1 RC1 true scm:svn:https://dist.apache.org/repos/dist/dev/commons/${commons.componentid} - 2024-02-04T15:10:25Z + 2024-04-20T18:05:56Z + 0.8.12 + ${commons.javadoc21.java.link} + + true + 0.92 + 0.91 + 0.87 + 0.86 + 0.89 + 0.84 clean verify apache-rat:check japicmp:cmp checkstyle:check javadoc:javadoc @@ -443,4 +280,213 @@ limitations under the License. + + + + java-8 + + 8 + + + + true + 0.96 + 0.97 + 0.88 + 0.92 + 0.88 + 0.94 + + + + + java-9-up + + [9,) + + + + true + 0.96 + 0.97 + 0.93 + 0.92 + 0.90 + 0.95 + + + + + + Henri Yandell + bayard + bayard@apache.org + + + Tim OBrien + tobrien + tobrien@apache.org + -6 + + + Scott Sanders + sanders + sanders@totalsync.com + + + Rodney Waldhoff + rwaldhoff + rwaldhoff@apache.org + + + Daniel Rall + dlr + dlr@finemaltcoding.com + + + Jon S. Stevens + jon + jon@collab.net + + + ggregory + Gary Gregory + ggregory at apache.org + https://www.garygregory.com + The Apache Software Foundation + https://www.apache.org/ + + PMC Member + + America/New_York + + https://people.apache.org/~ggregory/img/garydgregory80.png + + + + David Graham + dgraham + dgraham@apache.org + + + Julius Davies + julius + julius@apache.org + http://juliusdavies.ca/ + -8 + + + Thomas Neidhart + tn + tn@apache.org + + + Rob Tompkins + chtompki + chtompki@apache.org + + + Matt Sicker + mattsicker + mattsicker@apache.org + https://musigma.blog/ + + + + + Christopher O'Brien + siege@preoccupied.net + + hex + md5 + architecture + + + + Martin Redington + + Representing xml-rpc + + + + Jeffery Dever + + Representing http-client + + + + Steve Zimmermann + steve.zimmermann@heii.com + + Documentation + + + + Benjamin Walstrum + ben@walstrum.com + + + Oleg Kalnichevski + oleg@ural.ru + + Representing http-client + + + + Dave Dribin + apache@dave.dribin.org + + DigestUtil + + + + Alex Karasulu + aok123 at bellsouth.net + + Submitted Binary class and test + + + + Matthew Inger + mattinger at yahoo.com + + Submitted DIFFERENCE algorithm for Soundex and RefinedSoundex + + + + Jochen Wiedmann + jochen@apache.org + + Base64 code [CODEC-69] + + + + Sebastian Bazley + sebb@apache.org + + Streaming Base64 + + + + Matthew Pocock + turingatemyhamster@gmail.com + + Beider-Morse phonetic matching + + + + Colm Rice + colm_rice at hotmail dot com + + Submitted Match Rating Approach (MRA) phonetic encoder and tests [CODEC-161] + + + + Adam Retter + Evolved Binary + + Base16 Input and Output Streams + + + diff --git a/src/changes/changes.xml b/src/changes/changes.xml index 513fe6fa24..a8a65fdc09 100644 --- a/src/changes/changes.xml +++ b/src/changes/changes.xml @@ -43,6 +43,26 @@ The type attribute can be add,update,fix,remove. Apache Commons Developers + + + Wrong output of DoubleMetaphone in 1.16.1. + Optimize memory allocation in PhoneticEngine. + BCodec and QCodec encode() methods throw UnsupportedCharsetException instead of EncoderException. + Set Javadoc link to latest Java API LTS version. + Base32 constructor fails-fast with a NullPointerException if the custom alphabet array is null. + Base32 constructor makes a defensive copy of the line separator array. + Base64 constructor makes a defensive copy of the line separator array. + Base64 constructor makes a defensive copy of a custom alphabet array. + + Add override org.apache.commons.codec.language.bm.Rule.PhonemeExpr.size(). + Add support for Base64 custom alphabets #266. + Add Base64.Builder (allows custom alphabets). + Add Base32.Builder (allows custom alphabets). + Add Base64 support for a custom padding byte (like Base32). + + Bump org.apache.commons:commons-parent from 66 to 69 #250, #261. + Bump commons-io:commons-io from 2.15.1 to 2.16.1 #258, #265. + Add Maven property project.build.outputTimestamp for build reproducibility. diff --git a/src/changes/release-notes.vm b/src/changes/release-notes.vm index cce5c5a738..92fe6ee805 100644 --- a/src/changes/release-notes.vm +++ b/src/changes/release-notes.vm @@ -14,8 +14,8 @@ ## KIND, either express or implied. See the License for the ## specific language governing permissions and limitations ## under the License. -${project.name} ${version} -RELEASE NOTES +${project.name} ${version} RELEASE NOTES +----------------------------------------- $introduction.replaceAll("(? + diff --git a/src/main/java/org/apache/commons/codec/binary/Base16.java b/src/main/java/org/apache/commons/codec/binary/Base16.java index 492d1d3802..2968944215 100644 --- a/src/main/java/org/apache/commons/codec/binary/Base16.java +++ b/src/main/java/org/apache/commons/codec/binary/Base16.java @@ -17,6 +17,8 @@ package org.apache.commons.codec.binary; +import java.util.Objects; + import org.apache.commons.codec.CodecPolicy; /** @@ -66,12 +68,7 @@ public class Base16 extends BaseNCodec { * This array is a lookup table that translates 4-bit positive integer index values into their "Base16 Alphabet" equivalents as specified in Table 5 of RFC * 4648. */ - // @formatter:off - private static final byte[] UPPER_CASE_ENCODE_TABLE = { - '0', '1', '2', '3', '4', '5', '6', '7', '8', '9', - 'A', 'B', 'C', 'D', 'E', 'F' - }; - // @formatter:on + private static final byte[] UPPER_CASE_ENCODE_TABLE = { '0', '1', '2', '3', '4', '5', '6', '7', '8', '9', 'A', 'B', 'C', 'D', 'E', 'F' }; /** * This array is a lookup table that translates Unicode characters drawn from the a lower-case "Base16 Alphabet" into their 4-bit positive integer @@ -93,12 +90,7 @@ public class Base16 extends BaseNCodec { /** * This array is a lookup table that translates 4-bit positive integer index values into their "Base16 Alphabet" lower-case equivalents. */ - // @formatter:off - private static final byte[] LOWER_CASE_ENCODE_TABLE = { - '0', '1', '2', '3', '4', '5', '6', '7', '8', '9', - 'a', 'b', 'c', 'd', 'e', 'f' - }; - // @formatter:on + private static final byte[] LOWER_CASE_ENCODE_TABLE = { '0', '1', '2', '3', '4', '5', '6', '7', '8', '9', 'a', 'b', 'c', 'd', 'e', 'f' }; /** Mask used to extract 4 bits, used when decoding character. */ private static final int MASK_4BITS = 0x0f; @@ -114,14 +106,14 @@ public class Base16 extends BaseNCodec { private final byte[] encodeTable; /** - * Creates a Base16 codec used for decoding and encoding. + * Constructs a Base16 codec used for decoding and encoding. */ public Base16() { this(false); } /** - * Creates a Base16 codec used for decoding and encoding. + * Constructs a Base16 codec used for decoding and encoding. * * @param lowerCase if {@code true} then use a lower-case Base16 alphabet. */ @@ -130,20 +122,27 @@ public Base16(final boolean lowerCase) { } /** - * Creates a Base16 codec used for decoding and encoding. + * Constructs a Base16 codec used for decoding and encoding. * * @param lowerCase if {@code true} then use a lower-case Base16 alphabet. + * @param encodeTable the encode table. * @param decodingPolicy Decoding policy. */ - public Base16(final boolean lowerCase, final CodecPolicy decodingPolicy) { + private Base16(final boolean lowerCase, final byte[] encodeTable, final CodecPolicy decodingPolicy) { super(BYTES_PER_UNENCODED_BLOCK, BYTES_PER_ENCODED_BLOCK, 0, 0, PAD_DEFAULT, decodingPolicy); - if (lowerCase) { - this.encodeTable = LOWER_CASE_ENCODE_TABLE; - this.decodeTable = LOWER_CASE_DECODE_TABLE; - } else { - this.encodeTable = UPPER_CASE_ENCODE_TABLE; - this.decodeTable = UPPER_CASE_DECODE_TABLE; - } + Objects.requireNonNull(encodeTable, "encodeTable"); + this.encodeTable = encodeTable; + this.decodeTable = encodeTable == LOWER_CASE_ENCODE_TABLE ? LOWER_CASE_DECODE_TABLE : UPPER_CASE_DECODE_TABLE; + } + + /** + * Constructs a Base16 codec used for decoding and encoding. + * + * @param lowerCase if {@code true} then use a lower-case Base16 alphabet. + * @param decodingPolicy Decoding policy. + */ + public Base16(final boolean lowerCase, final CodecPolicy decodingPolicy) { + this(lowerCase, lowerCase ? LOWER_CASE_ENCODE_TABLE : UPPER_CASE_ENCODE_TABLE, decodingPolicy); } @Override @@ -155,42 +154,33 @@ void decode(final byte[] data, int offset, final int length, final Context conte } return; } - final int dataLen = Math.min(data.length - offset, length); final int availableChars = (context.ibitWorkArea != 0 ? 1 : 0) + dataLen; - // small optimization to short-cut the rest of this method when it is fed byte-by-byte if (availableChars == 1 && availableChars == dataLen) { // store 1/2 byte for next invocation of decode, we offset by +1 as empty-value is 0 context.ibitWorkArea = decodeOctet(data[offset]) + 1; return; } - // we must have an even number of chars to decode final int charsToProcess = availableChars % BYTES_PER_ENCODED_BLOCK == 0 ? availableChars : availableChars - 1; final int end = offset + dataLen; - final byte[] buffer = ensureBufferSize(charsToProcess / BYTES_PER_ENCODED_BLOCK, context); - int result; if (dataLen < availableChars) { // we have 1/2 byte from previous invocation to decode result = context.ibitWorkArea - 1 << BITS_PER_ENCODED_BYTE; result |= decodeOctet(data[offset++]); - buffer[context.pos++] = (byte) result; - // reset to empty-value for next invocation! context.ibitWorkArea = 0; } - final int loopEnd = end - 1; while (offset < loopEnd) { result = decodeOctet(data[offset++]) << BITS_PER_ENCODED_BYTE; result |= decodeOctet(data[offset++]); buffer[context.pos++] = (byte) result; } - // we have one char of a hex-pair left over if (offset < end) { // store 1/2 byte for next invocation of decode, we offset by +1 as empty-value is 0 @@ -203,11 +193,9 @@ private int decodeOctet(final byte octet) { if ((octet & 0xff) < decodeTable.length) { decoded = decodeTable[octet]; } - if (decoded == -1) { throw new IllegalArgumentException("Invalid octet in encoded value: " + (int) octet); } - return decoded; } @@ -216,19 +204,15 @@ void encode(final byte[] data, final int offset, final int length, final Context if (context.eof) { return; } - if (length < 0) { context.eof = true; return; } - final int size = length * BYTES_PER_ENCODED_BLOCK; if (size < 0) { throw new IllegalArgumentException("Input length exceeds maximum size for encoded data: " + length); } - final byte[] buffer = ensureBufferSize(size, context); - final int end = offset + length; for (int i = offset; i < end; i++) { final int value = data[i]; diff --git a/src/main/java/org/apache/commons/codec/binary/Base16InputStream.java b/src/main/java/org/apache/commons/codec/binary/Base16InputStream.java index de580a1503..5c0448271a 100644 --- a/src/main/java/org/apache/commons/codec/binary/Base16InputStream.java +++ b/src/main/java/org/apache/commons/codec/binary/Base16InputStream.java @@ -33,7 +33,7 @@ public class Base16InputStream extends BaseNCodecInputStream { /** - * Creates a Base16InputStream such that all data read is Base16-decoded from the original provided InputStream. + * Constructs a Base16InputStream such that all data read is Base16-decoded from the original provided InputStream. * * @param inputStream InputStream to wrap. */ @@ -42,7 +42,7 @@ public Base16InputStream(final InputStream inputStream) { } /** - * Creates a Base16InputStream such that all data read is either Base16-encoded or Base16-decoded from the original + * Constructs a Base16InputStream such that all data read is either Base16-encoded or Base16-decoded from the original * provided InputStream. * * @param inputStream InputStream to wrap. @@ -53,7 +53,7 @@ public Base16InputStream(final InputStream inputStream, final boolean doEncode) } /** - * Creates a Base16InputStream such that all data read is either Base16-encoded or Base16-decoded from the original + * Constructs a Base16InputStream such that all data read is either Base16-encoded or Base16-decoded from the original * provided InputStream. * * @param inputStream InputStream to wrap. @@ -66,7 +66,7 @@ public Base16InputStream(final InputStream inputStream, final boolean doEncode, } /** - * Creates a Base16InputStream such that all data read is either Base16-encoded or Base16-decoded from the original + * Constructs a Base16InputStream such that all data read is either Base16-encoded or Base16-decoded from the original * provided InputStream. * * @param inputStream InputStream to wrap. diff --git a/src/main/java/org/apache/commons/codec/binary/Base16OutputStream.java b/src/main/java/org/apache/commons/codec/binary/Base16OutputStream.java index 18e28764e4..7e653a372d 100644 --- a/src/main/java/org/apache/commons/codec/binary/Base16OutputStream.java +++ b/src/main/java/org/apache/commons/codec/binary/Base16OutputStream.java @@ -33,7 +33,7 @@ public class Base16OutputStream extends BaseNCodecOutputStream { /** - * Creates a Base16OutputStream such that all data written is Hex-encoded to the original provided OutputStream. + * Constructs a Base16OutputStream such that all data written is Hex-encoded to the original provided OutputStream. * * @param outputStream OutputStream to wrap. */ @@ -42,7 +42,7 @@ public Base16OutputStream(final OutputStream outputStream) { } /** - * Creates a Base16OutputStream such that all data written is either Hex-encoded or Hex-decoded to the + * Constructs a Base16OutputStream such that all data written is either Hex-encoded or Hex-decoded to the * original provided OutputStream. * * @param outputStream OutputStream to wrap. @@ -53,7 +53,7 @@ public Base16OutputStream(final OutputStream outputStream, final boolean doEncod } /** - * Creates a Base16OutputStream such that all data written is either Hex-encoded or Hex-decoded to the + * Constructs a Base16OutputStream such that all data written is either Hex-encoded or Hex-decoded to the * original provided OutputStream. * * @param outputStream OutputStream to wrap. @@ -65,7 +65,7 @@ public Base16OutputStream(final OutputStream outputStream, final boolean doEncod } /** - * Creates a Base16OutputStream such that all data written is either Hex-encoded or Hex-decoded to the + * Constructs a Base16OutputStream such that all data written is either Hex-encoded or Hex-decoded to the * original provided OutputStream. * * @param outputStream OutputStream to wrap. diff --git a/src/main/java/org/apache/commons/codec/binary/Base32.java b/src/main/java/org/apache/commons/codec/binary/Base32.java index 9c3ac7ee32..06ecec4736 100644 --- a/src/main/java/org/apache/commons/codec/binary/Base32.java +++ b/src/main/java/org/apache/commons/codec/binary/Base32.java @@ -17,6 +17,8 @@ package org.apache.commons.codec.binary; +import java.util.Objects; + import org.apache.commons.codec.CodecPolicy; /** @@ -36,21 +38,53 @@ *

* This class is thread-safe. *

+ *

+ * You can configure instances with the {@link Builder}. + *

+ *
+ * Base32 base32 = Base32.builder()
+ *   .setDecodingPolicy(DecodingPolicy.LENIENT) // default is lenient
+ *   .setEncodeTable(customEncodeTable)
+ *   .setLineLength(0)                          // default is none
+ *   .setLineSeparator('\r', '\n')              // default is CR LF
+ *   .setPadding('=')                           // default is =
+ *   .get()
+ * 
* * @see RFC 4648 - * * @since 1.5 */ public class Base32 extends BaseNCodec { + /** + * Builds {@link Base32} instances. + * + * @since 1.17.0 + */ + public static class Builder extends AbstractBuilder { + + /** + * Constructs a new instance. + */ + public Builder() { + super(ENCODE_TABLE); + } + + @Override + public Base32 get() { + return new Base32(getLineLength(), getLineSeparator(), getEncodeTable(), getPadding(), getDecodingPolicy()); + } + + } + /** * BASE32 characters are 5 bits in length. They are formed by taking a block of five octets to form a 40-bit string, which is converted into eight BASE32 * characters. */ private static final int BITS_PER_ENCODED_BYTE = 5; + private static final int BYTES_PER_ENCODED_BLOCK = 8; private static final int BYTES_PER_UNENCODED_BLOCK = 5; - /** * This array is a lookup table that translates Unicode characters drawn from the "Base32 Alphabet" (as specified in Table 3 of RFC 4648) into their 5-bit * positive integer equivalents. Characters that are not in the Base32 alphabet but fall within the bounds of the array are translated to -1. @@ -128,16 +162,20 @@ public class Base32 extends BaseNCodec { /** Mask used to extract 1 bits, used when decoding final trailing character. */ private static final long MASK_1BITS = 0x01L; + /** + * Creates a new Builder. + * + * @return a new Builder. + * @since 1.17.0 + */ + public static Builder builder() { + return new Builder(); + } + // The static final fields above are used for the original static byte[] methods on Base32. // The private member fields below are used with the new streaming approach, which requires // some state be preserved between calls of encode() and decode(). - /** - * Convenience variable to help us determine when our buffer is going to run out of room and needs resizing. {@code decodeSize = {@link - * #BYTES_PER_ENCODED_BLOCK} - 1 + lineSeparator.length;} - */ - private final int decodeSize; - /** * Decode table to use. */ @@ -160,7 +198,7 @@ public class Base32 extends BaseNCodec { private final byte[] lineSeparator; /** - * Creates a Base32 codec used for decoding and encoding. + * Constructs a Base32 codec used for decoding and encoding. *

* When encoding the line length is 0 (no chunking). *

@@ -170,7 +208,7 @@ public Base32() { } /** - * Creates a Base32 codec used for decoding and encoding. + * Constructs a Base32 codec used for decoding and encoding. *

* When encoding the line length is 0 (no chunking). *

@@ -182,7 +220,7 @@ public Base32(final boolean useHex) { } /** - * Creates a Base32 codec used for decoding and encoding. + * Constructs a Base32 codec used for decoding and encoding. *

* When encoding the line length is 0 (no chunking). *

@@ -195,7 +233,7 @@ public Base32(final boolean useHex, final byte padding) { } /** - * Creates a Base32 codec used for decoding and encoding. + * Constructs a Base32 codec used for decoding and encoding. *

* When encoding the line length is 0 (no chunking). *

@@ -207,7 +245,7 @@ public Base32(final byte pad) { } /** - * Creates a Base32 codec used for decoding and encoding. + * Constructs a Base32 codec used for decoding and encoding. *

* When encoding the line length is given in the constructor, the line separator is CRLF. *

@@ -220,7 +258,7 @@ public Base32(final int lineLength) { } /** - * Creates a Base32 codec used for decoding and encoding. + * Constructs a Base32 codec used for decoding and encoding. *

* When encoding the line length and line separator are given in the constructor. *

@@ -238,7 +276,7 @@ public Base32(final int lineLength, final byte[] lineSeparator) { } /** - * Creates a Base32 / Base32 Hex codec used for decoding and encoding. + * Constructs a Base32 / Base32 Hex codec used for decoding and encoding. *

* When encoding the line length and line separator are given in the constructor. *

@@ -257,7 +295,7 @@ public Base32(final int lineLength, final byte[] lineSeparator, final boolean us } /** - * Creates a Base32 / Base32 Hex codec used for decoding and encoding. + * Constructs a Base32 / Base32 Hex codec used for decoding and encoding. *

* When encoding the line length and line separator are given in the constructor. *

@@ -269,7 +307,7 @@ public Base32(final int lineLength, final byte[] lineSeparator, final boolean us * then the output will not be divided into lines (chunks). Ignored when decoding. * @param lineSeparator Each line of encoded data will end with this sequence of bytes. * @param useHex if {@code true}, then use Base32 Hex alphabet, otherwise use Base32 alphabet - * @param padding byte used as padding byte. + * @param padding padding byte. * @throws IllegalArgumentException Thrown when the {@code lineSeparator} contains Base32 characters. Or the lineLength > 0 and lineSeparator is null. */ public Base32(final int lineLength, final byte[] lineSeparator, final boolean useHex, final byte padding) { @@ -277,7 +315,7 @@ public Base32(final int lineLength, final byte[] lineSeparator, final boolean us } /** - * Creates a Base32 / Base32 Hex codec used for decoding and encoding. + * Constructs a Base32 / Base32 Hex codec used for decoding and encoding. *

* When encoding the line length and line separator are given in the constructor. *

@@ -289,37 +327,53 @@ public Base32(final int lineLength, final byte[] lineSeparator, final boolean us * then the output will not be divided into lines (chunks). Ignored when decoding. * @param lineSeparator Each line of encoded data will end with this sequence of bytes. * @param useHex if {@code true}, then use Base32 Hex alphabet, otherwise use Base32 alphabet - * @param padding byte used as padding byte. + * @param padding padding byte. * @param decodingPolicy The decoding policy. * @throws IllegalArgumentException Thrown when the {@code lineSeparator} contains Base32 characters. Or the lineLength > 0 and lineSeparator is null. * @since 1.15 */ public Base32(final int lineLength, final byte[] lineSeparator, final boolean useHex, final byte padding, final CodecPolicy decodingPolicy) { - super(BYTES_PER_UNENCODED_BLOCK, BYTES_PER_ENCODED_BLOCK, lineLength, lineSeparator == null ? 0 : lineSeparator.length, padding, decodingPolicy); - if (useHex) { - this.encodeTable = HEX_ENCODE_TABLE; - this.decodeTable = HEX_DECODE_TABLE; - } else { - this.encodeTable = ENCODE_TABLE; - this.decodeTable = DECODE_TABLE; - } + this(lineLength, lineSeparator, useHex ? HEX_ENCODE_TABLE : ENCODE_TABLE, padding, decodingPolicy); + } + + /** + * Constructs a Base32 / Base32 Hex codec used for decoding and encoding. + *

+ * When encoding the line length and line separator are given in the constructor. + *

+ *

+ * Line lengths that aren't multiples of 8 will still essentially end up being multiples of 8 in the encoded data. + *

+ * + * @param lineLength Each line of encoded data will be at most of the given length (rounded down to the nearest multiple of 8). If lineLength <= 0, + * then the output will not be divided into lines (chunks). Ignored when decoding. + * @param lineSeparator Each line of encoded data will end with this sequence of bytes. + * @param encodeTable A Base32 alphabet. + * @param padding padding byte. + * @param decodingPolicy The decoding policy. + * @throws IllegalArgumentException Thrown when the {@code lineSeparator} contains Base32 characters. Or the lineLength > 0 and lineSeparator is null. + */ + private Base32(final int lineLength, final byte[] lineSeparator, final byte[] encodeTable, final byte padding, final CodecPolicy decodingPolicy) { + super(BYTES_PER_UNENCODED_BLOCK, BYTES_PER_ENCODED_BLOCK, lineLength, toLength(lineSeparator), padding, decodingPolicy); + Objects.requireNonNull(encodeTable, "encodeTable"); + this.encodeTable = encodeTable; + this.decodeTable = encodeTable == HEX_ENCODE_TABLE ? HEX_DECODE_TABLE : DECODE_TABLE; if (lineLength > 0) { if (lineSeparator == null) { throw new IllegalArgumentException("lineLength " + lineLength + " > 0, but lineSeparator is null"); } + final byte[] lineSeparatorCopy = lineSeparator.clone(); // Must be done after initializing the tables - if (containsAlphabetOrPad(lineSeparator)) { - final String sep = StringUtils.newStringUtf8(lineSeparator); + if (containsAlphabetOrPad(lineSeparatorCopy)) { + final String sep = StringUtils.newStringUtf8(lineSeparatorCopy); throw new IllegalArgumentException("lineSeparator must not contain Base32 characters: [" + sep + "]"); } - this.encodeSize = BYTES_PER_ENCODED_BLOCK + lineSeparator.length; - this.lineSeparator = lineSeparator.clone(); + this.encodeSize = BYTES_PER_ENCODED_BLOCK + lineSeparatorCopy.length; + this.lineSeparator = lineSeparatorCopy; } else { this.encodeSize = BYTES_PER_ENCODED_BLOCK; this.lineSeparator = null; } - this.decodeSize = this.encodeSize - 1; - if (isInAlphabet(padding) || Character.isWhitespace(padding)) { throw new IllegalArgumentException("pad must not be in alphabet or whitespace"); } @@ -347,13 +401,13 @@ public Base32(final int lineLength, final byte[] lineSeparator, final boolean us @Override void decode(final byte[] input, int inPos, final int inAvail, final Context context) { // package protected for access from I/O streams - if (context.eof) { return; } if (inAvail < 0) { context.eof = true; } + final int decodeSize = this.encodeSize - 1; for (int i = 0; i < inAvail; i++) { final byte b = input[inPos++]; if (b == pad) { @@ -378,13 +432,11 @@ void decode(final byte[] input, int inPos, final int inAvail, final Context cont } } } - // Two forms of EOF as far as Base32 decoder is concerned: actual // EOF (-1) and first time '=' character is encountered in stream. // This approach makes the '=' padding characters completely optional. if (context.eof && context.modulus > 0) { // if modulus == 0, nothing to do final byte[] buffer = ensureBufferSize(decodeSize, context); - // We ignore partial bytes, i.e. only multiples of 8 count. // Any combination not part of a valid encoding is either partially decoded // or will raise an exception. Possible trailing characters are 2, 4, 5, 7. @@ -454,7 +506,6 @@ void decode(final byte[] input, int inPos, final int inAvail, final Context cont @Override void encode(final byte[] input, int inPos, final int inAvail, final Context context) { // package protected for access from I/O streams - if (context.eof) { return; } @@ -548,6 +599,15 @@ void encode(final byte[] input, int inPos, final int inAvail, final Context cont } } + /** + * Gets the line separator (for testing only). + * + * @return the line separator. + */ + byte[] getLineSeparator() { + return lineSeparator; + } + /** * Returns whether or not the {@code octet} is in the Base32 alphabet. * diff --git a/src/main/java/org/apache/commons/codec/binary/Base32InputStream.java b/src/main/java/org/apache/commons/codec/binary/Base32InputStream.java index 82091760ab..51adce23db 100644 --- a/src/main/java/org/apache/commons/codec/binary/Base32InputStream.java +++ b/src/main/java/org/apache/commons/codec/binary/Base32InputStream.java @@ -55,7 +55,7 @@ public class Base32InputStream extends BaseNCodecInputStream { /** - * Creates a Base32InputStream such that all data read is Base32-decoded from the original provided InputStream. + * Constructs a Base32InputStream such that all data read is Base32-decoded from the original provided InputStream. * * @param inputStream * InputStream to wrap. @@ -65,7 +65,7 @@ public Base32InputStream(final InputStream inputStream) { } /** - * Creates a Base32InputStream such that all data read is either Base32-encoded or Base32-decoded from the original + * Constructs a Base32InputStream such that all data read is either Base32-encoded or Base32-decoded from the original * provided InputStream. * * @param inputStream @@ -78,7 +78,7 @@ public Base32InputStream(final InputStream inputStream, final boolean doEncode) } /** - * Creates a Base32InputStream such that all data read is either Base32-encoded or Base32-decoded from the original + * Constructs a Base32InputStream such that all data read is either Base32-encoded or Base32-decoded from the original * provided InputStream. * * @param inputStream @@ -98,7 +98,7 @@ public Base32InputStream(final InputStream inputStream, final boolean doEncode, } /** - * Creates a Base32InputStream such that all data read is either Base32-encoded or Base32-decoded from the original + * Constructs a Base32InputStream such that all data read is either Base32-encoded or Base32-decoded from the original * provided InputStream. * * @param inputStream diff --git a/src/main/java/org/apache/commons/codec/binary/Base32OutputStream.java b/src/main/java/org/apache/commons/codec/binary/Base32OutputStream.java index c0bc740c6e..5977ae9d81 100644 --- a/src/main/java/org/apache/commons/codec/binary/Base32OutputStream.java +++ b/src/main/java/org/apache/commons/codec/binary/Base32OutputStream.java @@ -59,7 +59,7 @@ public class Base32OutputStream extends BaseNCodecOutputStream { /** - * Creates a Base32OutputStream such that all data written is Base32-encoded to the original provided OutputStream. + * Constructs a Base32OutputStream such that all data written is Base32-encoded to the original provided OutputStream. * * @param outputStream * OutputStream to wrap. @@ -69,7 +69,7 @@ public Base32OutputStream(final OutputStream outputStream) { } /** - * Creates a Base32OutputStream such that all data written is either Base32-encoded or Base32-decoded to the + * Constructs a Base32OutputStream such that all data written is either Base32-encoded or Base32-decoded to the * original provided OutputStream. * * @param outputStream @@ -82,7 +82,7 @@ public Base32OutputStream(final OutputStream outputStream, final boolean doEncod } /** - * Creates a Base32OutputStream such that all data written is either Base32-encoded or Base32-decoded to the + * Constructs a Base32OutputStream such that all data written is either Base32-encoded or Base32-decoded to the * original provided OutputStream. * * @param outputStream @@ -102,7 +102,7 @@ public Base32OutputStream(final OutputStream outputStream, final boolean doEncod } /** - * Creates a Base32OutputStream such that all data written is either Base32-encoded or Base32-decoded to the + * Constructs a Base32OutputStream such that all data written is either Base32-encoded or Base32-decoded to the * original provided OutputStream. * * @param outputStream diff --git a/src/main/java/org/apache/commons/codec/binary/Base64.java b/src/main/java/org/apache/commons/codec/binary/Base64.java index 61e411ae7e..443ccc6612 100644 --- a/src/main/java/org/apache/commons/codec/binary/Base64.java +++ b/src/main/java/org/apache/commons/codec/binary/Base64.java @@ -18,6 +18,7 @@ package org.apache.commons.codec.binary; import java.math.BigInteger; +import java.util.Arrays; import java.util.Objects; import org.apache.commons.codec.CodecPolicy; @@ -49,12 +50,56 @@ *

* This class is thread-safe. *

+ *

+ * You can configure instances with the {@link Builder}. + *

+ *
+ * Base64 base64 = Base64.builder()
+ *   .setDecodingPolicy(DecodingPolicy.LENIENT) // default is lenient, null resets to default
+ *   .setEncodeTable(customEncodeTable)         // default is built in, null resets to default
+ *   .setLineLength(0)                          // default is none
+ *   .setLineSeparator('\r', '\n')              // default is CR LF, null resets to default
+ *   .setPadding('=')                           // default is =
+ *   .setUrlSafe(false)                         // default is false
+ *   .get()
+ * 
* * @see RFC 2045 * @since 1.0 */ public class Base64 extends BaseNCodec { + /** + * Builds {@link Base64} instances. + * + * @since 1.17.0 + */ + public static class Builder extends AbstractBuilder { + + /** + * Constructs a new instance. + */ + public Builder() { + super(STANDARD_ENCODE_TABLE); + } + + @Override + public Base64 get() { + return new Base64(getLineLength(), getLineSeparator(), getPadding(), getEncodeTable(), getDecodingPolicy()); + } + + /** + * Sets the URL-safe encoding policy. + * + * @param urlSafe URL-safe encoding policy, null resets to the default. + * @return this. + */ + public Builder setUrlSafe(final boolean urlSafe) { + return setEncodeTable(toUrlSafeEncodeTable(urlSafe)); + } + + } + /** * BASE64 characters are 6 bits in length. * They are formed by taking a block of 3 octets to form a 24-bit string, @@ -63,6 +108,8 @@ public class Base64 extends BaseNCodec { private static final int BITS_PER_ENCODED_BYTE = 6; private static final int BYTES_PER_UNENCODED_BLOCK = 3; private static final int BYTES_PER_ENCODED_BLOCK = 4; + private static final int ALPHABET_LENGTH = 64; + private static final int DECODING_TABLE_LENGTH = 256; /** * This array is a lookup table that translates 6-bit positive integer index values into their "Base64 Alphabet" @@ -118,20 +165,31 @@ public class Base64 extends BaseNCodec { 41, 42, 43, 44, 45, 46, 47, 48, 49, 50, 51 // 70-7a p-z }; - // The static final fields above are used for the original static byte[] methods on Base64. - // The private member fields below are used with the new streaming approach, which requires - // some state be preserved between calls of encode() and decode(). - /** * Base64 uses 6-bit fields. */ /** Mask used to extract 6 bits, used when encoding */ private static final int MASK_6BITS = 0x3f; + + // The static final fields above are used for the original static byte[] methods on Base64. + // The private member fields below are used with the new streaming approach, which requires + // some state be preserved between calls of encode() and decode(). + /** Mask used to extract 4 bits, used when decoding final trailing character. */ private static final int MASK_4BITS = 0xf; /** Mask used to extract 2 bits, used when decoding final trailing character. */ private static final int MASK_2BITS = 0x3; + /** + * Creates a new Builder. + * + * @return a new Builder. + * @since 1.17.0 + */ + public static Builder builder() { + return new Builder(); + } + /** * Decodes Base64 data into octets. *

@@ -241,7 +299,6 @@ public static byte[] encodeBase64(final byte[] binaryData, final boolean isChunk if (BinaryCodec.isEmpty(binaryData)) { return binaryData; } - // Create this so can use the super-class method // Also ensures that the same roundings are performed by the ctor and the code final Base64 b64 = isChunked ? new Base64(urlSafe) : new Base64(0, CHUNK_SEPARATOR, urlSafe); @@ -252,7 +309,6 @@ public static byte[] encodeBase64(final byte[] binaryData, final boolean isChunk ") than the specified maximum size of " + maxResultSize); } - return b64.encode(binaryData); } @@ -414,26 +470,27 @@ static byte[] toIntegerBytes(final BigInteger bigInt) { return resizedBytes; } + private static byte[] toUrlSafeEncodeTable(final boolean urlSafe) { + return urlSafe ? URL_SAFE_ENCODE_TABLE : STANDARD_ENCODE_TABLE; + } + /** - * Encode table to use: either STANDARD or URL_SAFE. Note: the DECODE_TABLE above remains static because it is able + * Encode table to use: either STANDARD or URL_SAFE or custom. + * Note: the DECODE_TABLE above remains static because it is able * to decode both STANDARD and URL_SAFE streams, but the encodeTable must be a member variable so we can switch * between the two modes. */ private final byte[] encodeTable; - /** Only one decode table currently; keep for consistency with Base32 code. */ - private final byte[] decodeTable = DECODE_TABLE; - /** - * Line separator for encoding. Not used when decoding. Only used if lineLength > 0. + * Decode table to use. */ - private final byte[] lineSeparator; + private final byte[] decodeTable; /** - * Convenience variable to help us determine when our buffer is going to run out of room and needs resizing. - * {@code decodeSize = 3 + lineSeparator.length;} + * Line separator for encoding. Not used when decoding. Only used if lineLength > 0. */ - private final int decodeSize; + private final byte[] lineSeparator; /** * Convenience variable to help us determine when our buffer is going to run out of room and needs resizing. @@ -441,12 +498,13 @@ static byte[] toIntegerBytes(final BigInteger bigInt) { */ private final int encodeSize; + private final boolean isUrlSafe; + /** - * Creates a Base64 codec used for decoding (all modes) and encoding in URL-unsafe mode. + * Constructs a Base64 codec used for decoding (all modes) and encoding in URL-unsafe mode. *

* When encoding the line length is 0 (no chunking), and the encoding table is STANDARD_ENCODE_TABLE. *

- * *

* When decoding all variants are supported. *

@@ -456,11 +514,10 @@ public Base64() { } /** - * Creates a Base64 codec used for decoding (all modes) and encoding in the given URL-safe mode. + * Constructs a Base64 codec used for decoding (all modes) and encoding in the given URL-safe mode. *

* When encoding the line length is 76, the line separator is CRLF, and the encoding table is STANDARD_ENCODE_TABLE. *

- * *

* When decoding all variants are supported. *

@@ -474,8 +531,9 @@ public Base64(final boolean urlSafe) { this(MIME_CHUNK_SIZE, CHUNK_SEPARATOR, urlSafe); } + /** - * Creates a Base64 codec used for decoding (all modes) and encoding in URL-unsafe mode. + * Constructs a Base64 codec used for decoding (all modes) and encoding in URL-unsafe mode. *

* When encoding the line length is given in the constructor, the line separator is CRLF, and the encoding table is * STANDARD_ENCODE_TABLE. @@ -498,7 +556,7 @@ public Base64(final int lineLength) { } /** - * Creates a Base64 codec used for decoding (all modes) and encoding in URL-unsafe mode. + * Constructs a Base64 codec used for decoding (all modes) and encoding in URL-unsafe mode. *

* When encoding the line length and line separator are given in the constructor, and the encoding table is * STANDARD_ENCODE_TABLE. @@ -525,7 +583,7 @@ public Base64(final int lineLength, final byte[] lineSeparator) { } /** - * Creates a Base64 codec used for decoding (all modes) and encoding in URL-unsafe mode. + * Constructs a Base64 codec used for decoding (all modes) and encoding in URL-unsafe mode. *

* When encoding the line length and line separator are given in the constructor, and the encoding table is * STANDARD_ENCODE_TABLE. @@ -552,11 +610,11 @@ public Base64(final int lineLength, final byte[] lineSeparator) { * @since 1.4 */ public Base64(final int lineLength, final byte[] lineSeparator, final boolean urlSafe) { - this(lineLength, lineSeparator, urlSafe, DECODING_POLICY_DEFAULT); + this(lineLength, lineSeparator, PAD_DEFAULT, toUrlSafeEncodeTable(urlSafe), DECODING_POLICY_DEFAULT); } /** - * Creates a Base64 codec used for decoding (all modes) and encoding in URL-unsafe mode. + * Constructs a Base64 codec used for decoding (all modes) and encoding in URL-unsafe mode. *

* When encoding the line length and line separator are given in the constructor, and the encoding table is * STANDARD_ENCODE_TABLE. @@ -583,23 +641,56 @@ public Base64(final int lineLength, final byte[] lineSeparator, final boolean ur * Thrown when the {@code lineSeparator} contains Base64 characters. * @since 1.15 */ - public Base64(final int lineLength, final byte[] lineSeparator, final boolean urlSafe, - final CodecPolicy decodingPolicy) { - super(BYTES_PER_UNENCODED_BLOCK, BYTES_PER_ENCODED_BLOCK, - lineLength, - lineSeparator == null ? 0 : lineSeparator.length, - PAD_DEFAULT, - decodingPolicy); + public Base64(final int lineLength, final byte[] lineSeparator, final boolean urlSafe, final CodecPolicy decodingPolicy) { + this(lineLength, lineSeparator, PAD_DEFAULT, toUrlSafeEncodeTable(urlSafe), decodingPolicy); + } + + /** + * Constructs a Base64 codec used for decoding (all modes) and encoding in URL-unsafe mode. + *

+ * When encoding the line length and line separator are given in the constructor, and the encoding table is STANDARD_ENCODE_TABLE. + *

+ *

+ * Line lengths that aren't multiples of 4 will still essentially end up being multiples of 4 in the encoded data. + *

+ *

+ * When decoding all variants are supported. + *

+ * + * @param lineLength Each line of encoded data will be at most of the given length (rounded down to the nearest multiple of 4). If lineLength <= 0, + * then the output will not be divided into lines (chunks). Ignored when decoding. + * @param lineSeparator Each line of encoded data will end with this sequence of bytes; the constructor makes a defensive copy. May be null. + * @param padding padding byte. + * @param encodeTable The manual encodeTable - a byte array of 64 chars. + * @param decodingPolicy The decoding policy. + * @throws IllegalArgumentException Thrown when the {@code lineSeparator} contains Base64 characters. + */ + private Base64(final int lineLength, final byte[] lineSeparator, final byte padding, final byte[] encodeTable, final CodecPolicy decodingPolicy) { + super(BYTES_PER_UNENCODED_BLOCK, BYTES_PER_ENCODED_BLOCK, lineLength, toLength(lineSeparator), padding, decodingPolicy); + Objects.requireNonNull(encodeTable, "encodeTable"); + if (encodeTable.length != ALPHABET_LENGTH) { + throw new IllegalArgumentException("encodeTable must have exactly 64 entries."); + } + this.isUrlSafe = encodeTable == URL_SAFE_ENCODE_TABLE; + if (encodeTable == STANDARD_ENCODE_TABLE || this.isUrlSafe) { + decodeTable = DECODE_TABLE; + // No need of a defensive copy of an internal table. + this.encodeTable = encodeTable; + } else { + this.encodeTable = encodeTable.clone(); + this.decodeTable = calculateDecodeTable(this.encodeTable); + } // TODO could be simplified if there is no requirement to reject invalid line sep when length <=0 // @see test case Base64Test.testConstructors() if (lineSeparator != null) { - if (containsAlphabetOrPad(lineSeparator)) { - final String sep = StringUtils.newStringUtf8(lineSeparator); + final byte[] lineSeparatorCopy = lineSeparator.clone(); + if (containsAlphabetOrPad(lineSeparatorCopy)) { + final String sep = StringUtils.newStringUtf8(lineSeparatorCopy); throw new IllegalArgumentException("lineSeparator must not contain base64 characters: [" + sep + "]"); } - if (lineLength > 0){ // null line-sep forces no chunking rather than throwing IAE - this.encodeSize = BYTES_PER_ENCODED_BLOCK + lineSeparator.length; - this.lineSeparator = lineSeparator.clone(); + if (lineLength > 0) { // null line-sep forces no chunking rather than throwing IAE + this.encodeSize = BYTES_PER_ENCODED_BLOCK + lineSeparatorCopy.length; + this.lineSeparator = lineSeparatorCopy; } else { this.encodeSize = BYTES_PER_ENCODED_BLOCK; this.lineSeparator = null; @@ -608,11 +699,22 @@ public Base64(final int lineLength, final byte[] lineSeparator, final boolean ur this.encodeSize = BYTES_PER_ENCODED_BLOCK; this.lineSeparator = null; } - this.decodeSize = this.encodeSize - 1; - this.encodeTable = urlSafe ? URL_SAFE_ENCODE_TABLE : STANDARD_ENCODE_TABLE; } - // Implementation of the Encoder Interface + /** + * Calculates a decode table for a given encode table. + * + * @param encodeTable that is used to determine decode lookup table + * @return decodeTable + */ + private byte[] calculateDecodeTable(final byte[] encodeTable) { + final byte[] decodeTable = new byte[DECODING_TABLE_LENGTH]; + Arrays.fill(decodeTable, (byte) -1); + for (int i = 0; i < encodeTable.length; i++) { + decodeTable[encodeTable[i]] = (byte) i; + } + return decodeTable; + } /** *

@@ -647,6 +749,7 @@ void decode(final byte[] input, int inPos, final int inAvail, final Context cont if (inAvail < 0) { context.eof = true; } + final int decodeSize = this.encodeSize - 1; for (int i = 0; i < inAvail; i++) { final byte[] buffer = ensureBufferSize(decodeSize, context); final byte b = input[inPos++]; @@ -655,10 +758,10 @@ void decode(final byte[] input, int inPos, final int inAvail, final Context cont context.eof = true; break; } - if (b >= 0 && b < DECODE_TABLE.length) { - final int result = DECODE_TABLE[b]; + if (b >= 0 && b < decodeTable.length) { + final int result = decodeTable[b]; if (result >= 0) { - context.modulus = (context.modulus+1) % BYTES_PER_ENCODED_BLOCK; + context.modulus = (context.modulus + 1) % BYTES_PER_ENCODED_BLOCK; context.ibitWorkArea = (context.ibitWorkArea << BITS_PER_ENCODED_BYTE) + result; if (context.modulus == 0) { buffer[context.pos++] = (byte) (context.ibitWorkArea >> 16 & MASK_8BITS); @@ -770,12 +873,12 @@ void encode(final byte[] in, int inPos, final int inAvail, final Context context } else { for (int i = 0; i < inAvail; i++) { final byte[] buffer = ensureBufferSize(encodeSize, context); - context.modulus = (context.modulus+1) % BYTES_PER_UNENCODED_BLOCK; + context.modulus = (context.modulus + 1) % BYTES_PER_UNENCODED_BLOCK; int b = in[inPos++]; if (b < 0) { b += 256; } - context.ibitWorkArea = (context.ibitWorkArea << 8) + b; // BITS_PER_BYTE + context.ibitWorkArea = (context.ibitWorkArea << 8) + b; // BITS_PER_BYTE if (0 == context.modulus) { // 3 bytes = 24 bits = 4 * 6 bits to extract buffer[context.pos++] = encodeTable[context.ibitWorkArea >> 18 & MASK_6BITS]; buffer[context.pos++] = encodeTable[context.ibitWorkArea >> 12 & MASK_6BITS]; @@ -792,6 +895,15 @@ void encode(final byte[] in, int inPos, final int inAvail, final Context context } } + /** + * Gets the line separator (for testing only). + * + * @return the line separator. + */ + byte[] getLineSeparator() { + return lineSeparator; + } + /** * Returns whether or not the {@code octet} is in the Base64 alphabet. * @@ -805,13 +917,13 @@ protected boolean isInAlphabet(final byte octet) { } /** - * Returns our current encode mode. True if we're URL-SAFE, false otherwise. + * Returns our current encode mode. True if we're URL-safe, false otherwise. * - * @return true if we're in URL-SAFE mode, false otherwise. + * @return true if we're in URL-safe mode, false otherwise. * @since 1.4 */ public boolean isUrlSafe() { - return this.encodeTable == URL_SAFE_ENCODE_TABLE; + return isUrlSafe; } /** diff --git a/src/main/java/org/apache/commons/codec/binary/Base64InputStream.java b/src/main/java/org/apache/commons/codec/binary/Base64InputStream.java index 6a96217bf9..45ce8b41c0 100644 --- a/src/main/java/org/apache/commons/codec/binary/Base64InputStream.java +++ b/src/main/java/org/apache/commons/codec/binary/Base64InputStream.java @@ -59,7 +59,7 @@ public class Base64InputStream extends BaseNCodecInputStream { /** - * Creates a Base64InputStream such that all data read is Base64-decoded from the original provided InputStream. + * Constructs a Base64InputStream such that all data read is Base64-decoded from the original provided InputStream. * * @param inputStream * InputStream to wrap. @@ -69,7 +69,7 @@ public Base64InputStream(final InputStream inputStream) { } /** - * Creates a Base64InputStream such that all data read is either Base64-encoded or Base64-decoded from the original + * Constructs a Base64InputStream such that all data read is either Base64-encoded or Base64-decoded from the original * provided InputStream. * * @param inputStream @@ -82,7 +82,7 @@ public Base64InputStream(final InputStream inputStream, final boolean doEncode) } /** - * Creates a Base64InputStream such that all data read is either Base64-encoded or Base64-decoded from the original + * Constructs a Base64InputStream such that all data read is either Base64-encoded or Base64-decoded from the original * provided InputStream. * * @param inputStream @@ -102,7 +102,7 @@ public Base64InputStream(final InputStream inputStream, final boolean doEncode, } /** - * Creates a Base64InputStream such that all data read is either Base64-encoded or Base64-decoded from the original + * Constructs a Base64InputStream such that all data read is either Base64-encoded or Base64-decoded from the original * provided InputStream. * * @param inputStream diff --git a/src/main/java/org/apache/commons/codec/binary/Base64OutputStream.java b/src/main/java/org/apache/commons/codec/binary/Base64OutputStream.java index 492610dae9..43b87da5ca 100644 --- a/src/main/java/org/apache/commons/codec/binary/Base64OutputStream.java +++ b/src/main/java/org/apache/commons/codec/binary/Base64OutputStream.java @@ -63,7 +63,7 @@ public class Base64OutputStream extends BaseNCodecOutputStream { /** - * Creates a Base64OutputStream such that all data written is Base64-encoded to the original provided OutputStream. + * Constructs a Base64OutputStream such that all data written is Base64-encoded to the original provided OutputStream. * * @param outputStream * OutputStream to wrap. @@ -73,7 +73,7 @@ public Base64OutputStream(final OutputStream outputStream) { } /** - * Creates a Base64OutputStream such that all data written is either Base64-encoded or Base64-decoded to the + * Constructs a Base64OutputStream such that all data written is either Base64-encoded or Base64-decoded to the * original provided OutputStream. * * @param outputStream @@ -86,7 +86,7 @@ public Base64OutputStream(final OutputStream outputStream, final boolean doEncod } /** - * Creates a Base64OutputStream such that all data written is either Base64-encoded or Base64-decoded to the + * Constructs a Base64OutputStream such that all data written is either Base64-encoded or Base64-decoded to the * original provided OutputStream. * * @param outputStream @@ -106,7 +106,7 @@ public Base64OutputStream(final OutputStream outputStream, final boolean doEncod } /** - * Creates a Base64OutputStream such that all data written is either Base64-encoded or Base64-decoded to the + * Constructs a Base64OutputStream such that all data written is either Base64-encoded or Base64-decoded to the * original provided OutputStream. * * @param outputStream diff --git a/src/main/java/org/apache/commons/codec/binary/BaseNCodec.java b/src/main/java/org/apache/commons/codec/binary/BaseNCodec.java index 56870c66e4..c598abc3d1 100644 --- a/src/main/java/org/apache/commons/codec/binary/BaseNCodec.java +++ b/src/main/java/org/apache/commons/codec/binary/BaseNCodec.java @@ -19,6 +19,7 @@ import java.util.Arrays; import java.util.Objects; +import java.util.function.Supplier; import org.apache.commons.codec.BinaryDecoder; import org.apache.commons.codec.BinaryEncoder; @@ -51,12 +52,114 @@ */ public abstract class BaseNCodec implements BinaryEncoder, BinaryDecoder { + /** + * Builds {@link Base64} instances. + * + * @param the codec type to build. + * @param the codec builder subtype. + * @since 1.17.0 + */ + public abstract static class AbstractBuilder> implements Supplier { + + private CodecPolicy decodingPolicy = DECODING_POLICY_DEFAULT; + private int lineLength; + private byte[] lineSeparator = CHUNK_SEPARATOR; + private final byte[] defaultEncodeTable; + private byte[] encodeTable; + /** Padding byte. */ + private byte padding = PAD_DEFAULT; + + AbstractBuilder(final byte[] defaultEncodeTable) { + this.defaultEncodeTable = defaultEncodeTable; + this.encodeTable = defaultEncodeTable; + } + + @SuppressWarnings("unchecked") + B asThis() { + return (B) this; + } + + CodecPolicy getDecodingPolicy() { + return decodingPolicy; + } + + byte[] getEncodeTable() { + return encodeTable; + } + + int getLineLength() { + return lineLength; + } + + byte[] getLineSeparator() { + return lineSeparator; + } + + byte getPadding() { + return padding; + } + + /** + * Sets the decoding policy. + * + * @param decodingPolicy the decoding policy, null resets to the default. + * @return this. + */ + public B setDecodingPolicy(final CodecPolicy decodingPolicy) { + this.decodingPolicy = decodingPolicy != null ? decodingPolicy : DECODING_POLICY_DEFAULT; + return asThis(); + } + + /** + * Sets the encode table. + * + * @param encodeTable the encode table, null resets to the default. + * @return this. + */ + public B setEncodeTable(final byte... encodeTable) { + this.encodeTable = encodeTable != null ? encodeTable : defaultEncodeTable; + return asThis(); + } + + /** + * Sets the line length. + * + * @param lineLength the line length, less than 0 resets to the default. + * @return this. + */ + public B setLineLength(final int lineLength) { + this.lineLength = Math.max(0, lineLength); + return asThis(); + } + + /** + * Sets the line separator. + * + * @param lineSeparator the line separator, null resets to the default. + * @return this. + */ + public B setLineSeparator(final byte... lineSeparator) { + this.lineSeparator = lineSeparator != null ? lineSeparator : CHUNK_SEPARATOR; + return asThis(); + } + + /** + * Sets the padding byte. + * + * @param padding the padding byte. + * @return this. + */ + public B setPadding(final byte padding) { + this.padding = padding; + return asThis(); + } + + } + /** * Holds thread context so classes can be thread-safe. * * This class is not itself thread-safe; each thread must allocate its own copy. - * - * @since 1.7 */ static class Context { @@ -110,7 +213,6 @@ static class Context { * * @return a String useful for debugging. */ - @SuppressWarnings("boxing") // OK to ignore boxing here @Override public String toString() { return String.format("%s[buffer=%s, currentLinePos=%s, eof=%s, ibitWorkArea=%s, lbitWorkArea=%s, " + @@ -257,12 +359,21 @@ private static byte[] resizeBuffer(final Context context, final int minCapacity) if (Integer.compareUnsigned(newCapacity, MAX_BUFFER_SIZE) > 0) { newCapacity = createPositiveCapacity(minCapacity); } - final byte[] b = Arrays.copyOf(context.buffer, newCapacity); context.buffer = b; return b; } + /** + * Gets the array length or 0 if null. + * + * @param array the array or null. + * @return the array length or 0 if null. + */ + static int toLength(final byte[] array) { + return array == null ? 0 : array.length; + } + /** * @deprecated Use {@link #pad}. Will be removed in 2.0. */ @@ -312,22 +423,27 @@ private static byte[] resizeBuffer(final Context context, final int minCapacity) private final CodecPolicy decodingPolicy; /** + * Constructs a new instance. + *

* Note {@code lineLength} is rounded down to the nearest multiple of the encoded block size. * If {@code chunkSeparatorLength} is zero, then chunking is disabled. + *

* * @param unencodedBlockSize the size of an unencoded block (e.g. Base64 = 3) * @param encodedBlockSize the size of an encoded block (e.g. Base64 = 4) * @param lineLength if > 0, use chunking with a length {@code lineLength} * @param chunkSeparatorLength the chunk separator length, if relevant */ - protected BaseNCodec(final int unencodedBlockSize, final int encodedBlockSize, - final int lineLength, final int chunkSeparatorLength) { + protected BaseNCodec(final int unencodedBlockSize, final int encodedBlockSize, final int lineLength, final int chunkSeparatorLength) { this(unencodedBlockSize, encodedBlockSize, lineLength, chunkSeparatorLength, PAD_DEFAULT); } /** + * Constructs a new instance. + *

* Note {@code lineLength} is rounded down to the nearest multiple of the encoded block size. * If {@code chunkSeparatorLength} is zero, then chunking is disabled. + *

* * @param unencodedBlockSize the size of an unencoded block (e.g. Base64 = 3) * @param encodedBlockSize the size of an encoded block (e.g. Base64 = 4) @@ -335,14 +451,16 @@ protected BaseNCodec(final int unencodedBlockSize, final int encodedBlockSize, * @param chunkSeparatorLength the chunk separator length, if relevant * @param pad byte used as padding byte. */ - protected BaseNCodec(final int unencodedBlockSize, final int encodedBlockSize, - final int lineLength, final int chunkSeparatorLength, final byte pad) { + protected BaseNCodec(final int unencodedBlockSize, final int encodedBlockSize, final int lineLength, final int chunkSeparatorLength, final byte pad) { this(unencodedBlockSize, encodedBlockSize, lineLength, chunkSeparatorLength, pad, DECODING_POLICY_DEFAULT); } /** + * Constructs a new instance. + *

* Note {@code lineLength} is rounded down to the nearest multiple of the encoded block size. * If {@code chunkSeparatorLength} is zero, then chunking is disabled. + *

* * @param unencodedBlockSize the size of an unencoded block (e.g. Base64 = 3) * @param encodedBlockSize the size of an encoded block (e.g. Base64 = 4) @@ -352,9 +470,8 @@ protected BaseNCodec(final int unencodedBlockSize, final int encodedBlockSize, * @param decodingPolicy Decoding policy. * @since 1.15 */ - protected BaseNCodec(final int unencodedBlockSize, final int encodedBlockSize, - final int lineLength, final int chunkSeparatorLength, final byte pad, - final CodecPolicy decodingPolicy) { + protected BaseNCodec(final int unencodedBlockSize, final int encodedBlockSize, final int lineLength, final int chunkSeparatorLength, final byte pad, + final CodecPolicy decodingPolicy) { this.unencodedBlockSize = unencodedBlockSize; this.encodedBlockSize = encodedBlockSize; final boolean useChunking = lineLength > 0 && chunkSeparatorLength > 0; @@ -384,12 +501,11 @@ int available(final Context context) { // package protected for access from I/O * @return {@code true} if any byte is a valid character in the alphabet or PAD; {@code false} otherwise */ protected boolean containsAlphabetOrPad(final byte[] arrayOctet) { - if (arrayOctet == null) { - return false; - } - for (final byte element : arrayOctet) { - if (pad == element || isInAlphabet(element)) { - return true; + if (arrayOctet != null) { + for (final byte element : arrayOctet) { + if (pad == element || isInAlphabet(element)) { + return true; + } } } return false; @@ -515,13 +631,15 @@ public Object encode(final Object obj) throws EncoderException { /** * Encodes a byte[] containing binary data, into a String containing characters in the appropriate alphabet. * Uses UTF8 encoding. + *

+ * This is a duplicate of {@link #encodeToString(byte[])}; it was merged during refactoring. + *

* * @param pArray a byte array containing binary data * @return String containing only character data in the appropriate alphabet. * @since 1.5 - * This is a duplicate of {@link #encodeToString(byte[])}; it was merged during refactoring. */ - public String encodeAsString(final byte[] pArray){ + public String encodeAsString(final byte[] pArray) { return StringUtils.newStringUtf8(encode(pArray)); } @@ -544,14 +662,13 @@ public String encodeToString(final byte[] pArray) { * @param context the context to be used * @return the buffer */ - protected byte[] ensureBufferSize(final int size, final Context context){ + protected byte[] ensureBufferSize(final int size, final Context context) { if (context.buffer == null) { context.buffer = new byte[Math.max(size, getDefaultBufferSize())]; context.pos = 0; context.readPos = 0; - // Overflow-conscious: - // x + y > z == x + y - z > 0 + // x + y > z == x + y - z > 0 } else if (context.pos + size - context.buffer.length > 0) { return resizeBuffer(context, context.pos + size); } @@ -594,10 +711,10 @@ protected int getDefaultBufferSize() { public long getEncodedLength(final byte[] pArray) { // Calculate non-chunked size - rounded up to allow for padding // cast to long is needed to avoid possibility of overflow - long len = (pArray.length + unencodedBlockSize-1) / unencodedBlockSize * (long) encodedBlockSize; + long len = (pArray.length + unencodedBlockSize - 1) / unencodedBlockSize * (long) encodedBlockSize; if (lineLength > 0) { // We're using chunking // Round up to nearest multiple - len += (len + lineLength-1) / lineLength * chunkSeparatorLength; + len += (len + lineLength - 1) / lineLength * chunkSeparatorLength; } return len; } @@ -634,8 +751,7 @@ boolean hasData(final Context context) { // package protected for access from I */ public boolean isInAlphabet(final byte[] arrayOctet, final boolean allowWSPad) { for (final byte octet : arrayOctet) { - if (!isInAlphabet(octet) && - (!allowWSPad || octet != pad && !Character.isWhitespace(octet))) { + if (!isInAlphabet(octet) && (!allowWSPad || octet != pad && !Character.isWhitespace(octet))) { return false; } } diff --git a/src/main/java/org/apache/commons/codec/binary/BaseNCodecInputStream.java b/src/main/java/org/apache/commons/codec/binary/BaseNCodecInputStream.java index ac1471836e..1a4c72c4ef 100644 --- a/src/main/java/org/apache/commons/codec/binary/BaseNCodecInputStream.java +++ b/src/main/java/org/apache/commons/codec/binary/BaseNCodecInputStream.java @@ -44,7 +44,7 @@ public class BaseNCodecInputStream extends FilterInputStream { private final Context context = new Context(); /** - * Create an instance. + * Constructs a new instance. * * @param inputStream the input stream * @param baseNCodec the codec @@ -70,7 +70,6 @@ public int available() throws IOException { // as long as we have not reached EOF, indicate that there is more // data available. As we do not know for sure how much data is left, // just return 1 as a safe guess. - return context.eof ? 0 : 1; } @@ -209,6 +208,7 @@ public int read(final byte[] array, final int offset, final int len) throws IOEx * Repositions this stream to the position at the time the mark method was last called on this input stream. *

* The {@link #reset} method of {@link BaseNCodecInputStream} does nothing except throw an {@link IOException}. + *

* * @throws IOException if this method is invoked * @since 1.7 @@ -229,11 +229,9 @@ public long skip(final long n) throws IOException { if (n < 0) { throw new IllegalArgumentException("Negative skip length: " + n); } - // skip in chunks of 512 bytes final byte[] b = new byte[512]; long todo = n; - while (todo > 0) { int len = (int) Math.min(b.length, todo); len = this.read(b, 0, len); @@ -242,7 +240,6 @@ public long skip(final long n) throws IOException { } todo -= len; } - return n - todo; } } diff --git a/src/main/java/org/apache/commons/codec/binary/BaseNCodecOutputStream.java b/src/main/java/org/apache/commons/codec/binary/BaseNCodecOutputStream.java index b3f141ab46..1964759384 100644 --- a/src/main/java/org/apache/commons/codec/binary/BaseNCodecOutputStream.java +++ b/src/main/java/org/apache/commons/codec/binary/BaseNCodecOutputStream.java @@ -48,6 +48,8 @@ public class BaseNCodecOutputStream extends FilterOutputStream { private final Context context = new Context(); /** + * Constructs a new instance. + * * TODO should this be protected? * * @param outputStream the underlying output or null. diff --git a/src/main/java/org/apache/commons/codec/binary/CharSequenceUtils.java b/src/main/java/org/apache/commons/codec/binary/CharSequenceUtils.java index 43e99fb39f..1868b0b2e6 100644 --- a/src/main/java/org/apache/commons/codec/binary/CharSequenceUtils.java +++ b/src/main/java/org/apache/commons/codec/binary/CharSequenceUtils.java @@ -59,26 +59,21 @@ static boolean regionMatches(final CharSequence cs, final boolean ignoreCase, fi int index1 = thisStart; int index2 = start; int tmpLen = length; - while (tmpLen-- > 0) { final char c1 = cs.charAt(index1++); final char c2 = substring.charAt(index2++); - if (c1 == c2) { continue; } - if (!ignoreCase) { return false; } - // The same check as in String.regionMatches(): if (Character.toUpperCase(c1) != Character.toUpperCase(c2) && Character.toLowerCase(c1) != Character.toLowerCase(c2)) { return false; } } - return true; } } diff --git a/src/main/java/org/apache/commons/codec/binary/Hex.java b/src/main/java/org/apache/commons/codec/binary/Hex.java index 6dfc28ee8a..dc6d0806b6 100644 --- a/src/main/java/org/apache/commons/codec/binary/Hex.java +++ b/src/main/java/org/apache/commons/codec/binary/Hex.java @@ -54,14 +54,12 @@ public class Hex implements BinaryEncoder, BinaryDecoder { /** * Used to build output as hex. */ - private static final char[] DIGITS_LOWER = { '0', '1', '2', '3', '4', '5', '6', '7', '8', '9', 'a', 'b', 'c', 'd', - 'e', 'f' }; + private static final char[] DIGITS_LOWER = { '0', '1', '2', '3', '4', '5', '6', '7', '8', '9', 'a', 'b', 'c', 'd', 'e', 'f' }; /** * Used to build output as hex. */ - private static final char[] DIGITS_UPPER = { '0', '1', '2', '3', '4', '5', '6', '7', '8', '9', 'A', 'B', 'C', 'D', - 'E', 'F' }; + private static final char[] DIGITS_UPPER = { '0', '1', '2', '3', '4', '5', '6', '7', '8', '9', 'A', 'B', 'C', 'D', 'E', 'F' }; /** * Converts an array of characters representing hexadecimal values into an array of bytes of those same values. The @@ -92,16 +90,13 @@ public static byte[] decodeHex(final char[] data) throws DecoderException { */ public static int decodeHex(final char[] data, final byte[] out, final int outOffset) throws DecoderException { final int len = data.length; - if ((len & 0x01) != 0) { throw new DecoderException("Odd number of characters."); } - final int outLen = len >> 1; if (out.length - outOffset < outLen) { throw new DecoderException("Output array is not large enough to accommodate decoded data."); } - // two characters form the hex value. for (int i = outOffset, j = 0; j < len; i++) { int f = toDigit(data[j], j) << 4; @@ -110,7 +105,6 @@ public static int decodeHex(final char[] data, final byte[] out, final int outOf j++; out[i] = (byte) (f & 0xFF); } - return outLen; } @@ -151,7 +145,7 @@ public static char[] encodeHex(final byte[] data) { * @since 1.4 */ public static char[] encodeHex(final byte[] data, final boolean toLowerCase) { - return encodeHex(data, toLowerCase ? DIGITS_LOWER : DIGITS_UPPER); + return encodeHex(data, toAlphabet(toLowerCase)); } /** @@ -167,9 +161,7 @@ public static char[] encodeHex(final byte[] data, final boolean toLowerCase) { */ protected static char[] encodeHex(final byte[] data, final char[] toDigits) { final int dataLength = data.length; - final char[] out = new char[dataLength << 1]; - encodeHex(data, 0, dataLength, toDigits, out, 0); - return out; + return encodeHex(data, 0, dataLength, toDigits, new char[dataLength << 1], 0); } /** @@ -183,11 +175,8 @@ protected static char[] encodeHex(final byte[] data, final char[] toDigits) { * upper- or lower-case hex. * @since 1.15 */ - public static char[] encodeHex(final byte[] data, final int dataOffset, final int dataLen, - final boolean toLowerCase) { - final char[] out = new char[dataLen << 1]; - encodeHex(data, dataOffset, dataLen, toLowerCase ? DIGITS_LOWER : DIGITS_UPPER, out, 0); - return out; + public static char[] encodeHex(final byte[] data, final int dataOffset, final int dataLen, final boolean toLowerCase) { + return encodeHex(data, dataOffset, dataLen, toAlphabet(toLowerCase), new char[dataLen << 1], 0); } /** @@ -201,9 +190,8 @@ public static char[] encodeHex(final byte[] data, final int dataOffset, final in * @param outOffset the position within {@code out} at which to start writing the encoded characters. * @since 1.15 */ - public static void encodeHex(final byte[] data, final int dataOffset, final int dataLen, - final boolean toLowerCase, final char[] out, final int outOffset) { - encodeHex(data, dataOffset, dataLen, toLowerCase ? DIGITS_LOWER : DIGITS_UPPER, out, outOffset); + public static void encodeHex(final byte[] data, final int dataOffset, final int dataLen, final boolean toLowerCase, final char[] out, final int outOffset) { + encodeHex(data, dataOffset, dataLen, toAlphabet(toLowerCase), out, outOffset); } /** @@ -215,14 +203,15 @@ public static void encodeHex(final byte[] data, final int dataOffset, final int * @param toDigits the output alphabet (must contain at least 16 chars) * @param out a char[] which will hold the resultant appropriate characters from the alphabet. * @param outOffset the position within {@code out} at which to start writing the encoded characters. + * @return the given {@code out}. */ - private static void encodeHex(final byte[] data, final int dataOffset, final int dataLen, final char[] toDigits, - final char[] out, final int outOffset) { + private static char[] encodeHex(final byte[] data, final int dataOffset, final int dataLen, final char[] toDigits, final char[] out, final int outOffset) { // two characters form the hex value. for (int i = dataOffset, j = outOffset; i < dataOffset + dataLen; i++) { out[j++] = toDigits[(0xF0 & data[i]) >>> 4]; out[j++] = toDigits[0x0F & data[i]]; } + return out; } /** @@ -255,7 +244,7 @@ public static char[] encodeHex(final ByteBuffer data) { * @since 1.11 */ public static char[] encodeHex(final ByteBuffer data, final boolean toLowerCase) { - return encodeHex(data, toLowerCase ? DIGITS_LOWER : DIGITS_UPPER); + return encodeHex(data, toAlphabet(toLowerCase)); } /** @@ -332,6 +321,16 @@ public static String encodeHexString(final ByteBuffer data, final boolean toLowe return new String(encodeHex(data, toLowerCase)); } + /** + * Converts a boolean to an alphabet. + * + * @param toLowerCase true for lowercase, false for uppercase. + * @return an alphabet. + */ + private static char[] toAlphabet(final boolean toLowerCase) { + return toLowerCase ? DIGITS_LOWER : DIGITS_UPPER; + } + /** * Convert the byte buffer to a byte array. All bytes identified by * {@link ByteBuffer#remaining()} will be used. diff --git a/src/main/java/org/apache/commons/codec/cli/Digest.java b/src/main/java/org/apache/commons/codec/cli/Digest.java index e111c35340..20b3684a34 100644 --- a/src/main/java/org/apache/commons/codec/cli/Digest.java +++ b/src/main/java/org/apache/commons/codec/cli/Digest.java @@ -22,6 +22,7 @@ import java.security.MessageDigest; import java.util.Arrays; import java.util.Locale; +import java.util.Objects; import org.apache.commons.codec.binary.Hex; import org.apache.commons.codec.digest.DigestUtils; @@ -52,26 +53,24 @@ public class Digest { public static void main(final String[] args) throws IOException { new Digest(args).run(); } + private final String algorithm; private final String[] args; - private final String[] inputs; private Digest(final String[] args) { - if (args == null) { - throw new IllegalArgumentException("args"); - } + Objects.requireNonNull(args); final int argsLength = args.length; if (argsLength == 0) { throw new IllegalArgumentException( String.format("Usage: java %s [algorithm] [FILE|DIRECTORY|string] ...", Digest.class.getName())); } this.args = args; - algorithm = args[0]; + this.algorithm = args[0]; if (argsLength <= 1) { - inputs = null; + this.inputs = null; } else { - inputs = Arrays.copyOfRange(args, 1, argsLength); + this.inputs = Arrays.copyOfRange(args, 1, argsLength); } } diff --git a/src/main/java/org/apache/commons/codec/digest/B64.java b/src/main/java/org/apache/commons/codec/digest/B64.java index a0973f5bdf..5627570d62 100644 --- a/src/main/java/org/apache/commons/codec/digest/B64.java +++ b/src/main/java/org/apache/commons/codec/digest/B64.java @@ -66,18 +66,18 @@ static void b64from24bit(final byte b2, final byte b1, final byte b0, final int } } - /** - * Generates a string of random chars from the B64T set. - *

- * The salt is generated with {@link SecureRandom}. - *

- * - * @param num Number of chars to generate. - * @return a random salt {@link String}. - */ - static String getRandomSalt(final int num) { - return getRandomSalt(num, new SecureRandom()); - } + /** + * Generates a string of random chars from the B64T set. + *

+ * The salt is generated with {@link SecureRandom}. + *

+ * + * @param num Number of chars to generate. + * @return a random salt {@link String}. + */ + static String getRandomSalt(final int num) { + return getRandomSalt(num, new SecureRandom()); + } /** * Generates a string of random chars from the B64T set. diff --git a/src/main/java/org/apache/commons/codec/digest/Blake3.java b/src/main/java/org/apache/commons/codec/digest/Blake3.java index dcbc6ea8b4..ba6cceedf4 100644 --- a/src/main/java/org/apache/commons/codec/digest/Blake3.java +++ b/src/main/java/org/apache/commons/codec/digest/Blake3.java @@ -76,6 +76,7 @@ public final class Blake3 { private static final class ChunkState { + private int[] chainingValue; private final long chunkCounter; private final int flags; @@ -209,20 +210,20 @@ private void reset() { state = new ChunkState(key, 0, flags); } } + /** * Represents the state just prior to either producing an eight word chaining value or any number of output bytes * when the ROOT flag is set. */ private static final class Output { + private final int[] inputChainingValue; private final int[] blockWords; private final long counter; private final int blockLength; private final int flags; - private Output( - final int[] inputChainingValue, final int[] blockWords, final long counter, final int blockLength, - final int flags) { + private Output(final int[] inputChainingValue, final int[] blockWords, final long counter, final int blockLength, final int flags) { this.inputChainingValue = inputChainingValue; this.blockWords = blockWords; this.counter = counter; @@ -231,8 +232,7 @@ private Output( } private int[] chainingValue() { - return Arrays - .copyOf(compress(inputChainingValue, blockWords, blockLength, counter, flags), CHAINING_VALUE_INTS); + return Arrays.copyOf(compress(inputChainingValue, blockWords, blockLength, counter, flags), CHAINING_VALUE_INTS); } private void rootOutputBytes(final byte[] out, int offset, int length) { @@ -240,8 +240,7 @@ private void rootOutputBytes(final byte[] out, int offset, int length) { while (length > 0) { int chunkLength = Math.min(OUT_LEN * 2, length); length -= chunkLength; - final int[] words = - compress(inputChainingValue, blockWords, blockLength, outputBlockCounter++, flags | ROOT); + final int[] words = compress(inputChainingValue, blockWords, blockLength, outputBlockCounter++, flags | ROOT); int wordCounter = 0; while (chunkLength > 0) { final int wordLength = Math.min(Integer.BYTES, chunkLength); @@ -252,35 +251,33 @@ private void rootOutputBytes(final byte[] out, int offset, int length) { } } } + private static final int BLOCK_LEN = 64; private static final int BLOCK_INTS = BLOCK_LEN / Integer.BYTES; private static final int KEY_LEN = 32; private static final int KEY_INTS = KEY_LEN / Integer.BYTES; - private static final int OUT_LEN = 32; - private static final int CHUNK_LEN = 1024; private static final int CHAINING_VALUE_INTS = 8; + /** * Standard hash key used for plain hashes; same initialization vector as Blake2s. */ - private static final int[] IV = - { 0x6A09E667, 0xBB67AE85, 0x3C6EF372, 0xA54FF53A, 0x510E527F, 0x9B05688C, 0x1F83D9AB, 0x5BE0CD19 }; + private static final int[] IV = { 0x6A09E667, 0xBB67AE85, 0x3C6EF372, 0xA54FF53A, 0x510E527F, 0x9B05688C, 0x1F83D9AB, 0x5BE0CD19 }; + // domain flags private static final int CHUNK_START = 1; private static final int CHUNK_END = 1 << 1; private static final int PARENT = 1 << 2; private static final int ROOT = 1 << 3; - private static final int KEYED_HASH = 1 << 4; - private static final int DERIVE_KEY_CONTEXT = 1 << 5; - private static final int DERIVE_KEY_MATERIAL = 1 << 6; /** * Pre-permuted for all 7 rounds; the second row (2,6,3,...) indicates the base permutation. */ + // @formatter:off private static final byte[][] MSG_SCHEDULE = { { 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15 }, { 2, 6, 3, 10, 7, 0, 4, 13, 1, 11, 12, 5, 9, 14, 15, 8 }, @@ -290,6 +287,7 @@ private void rootOutputBytes(final byte[] out, int offset, int length) { { 9, 14, 11, 5, 8, 12, 15, 1, 13, 3, 0, 10, 2, 6, 4, 7 }, { 11, 15, 5, 0, 1, 9, 8, 6, 14, 10, 2, 12, 3, 4, 7, 13 } }; + // @formatter:on private static void checkBufferArgs(final byte[] buffer, final int offset, final int length) { Objects.requireNonNull(buffer); @@ -301,14 +299,11 @@ private static void checkBufferArgs(final byte[] buffer, final int offset, final } final int bufferLength = buffer.length; if (offset > bufferLength - length) { - throw new IndexOutOfBoundsException( - "Offset " + offset + " and length " + length + " out of bounds with buffer length " + bufferLength); + throw new IndexOutOfBoundsException("Offset " + offset + " and length " + length + " out of bounds with buffer length " + bufferLength); } } - private static int[] compress( - final int[] chainingValue, final int[] blockWords, final int blockLength, final long counter, - final int flags) { + private static int[] compress(final int[] chainingValue, final int[] blockWords, final int blockLength, final long counter, final int flags) { final int[] state = Arrays.copyOf(chainingValue, BLOCK_INTS); System.arraycopy(IV, 0, state, 8, 4); state[12] = (int) counter; @@ -329,8 +324,7 @@ private static int[] compress( /** * The mixing function, G, which mixes either a column or a diagonal. */ - private static void g( - final int[] state, final int a, final int b, final int c, final int d, final int mx, final int my) { + private static void g(final int[] state, final int a, final int b, final int c, final int d, final int mx, final int my) { state[a] += state[b] + mx; state[d] = Integer.rotateRight(state[d] ^ state[a], 16); state[c] += state[d]; @@ -414,13 +408,11 @@ private static void packInt(final int value, final byte[] dst, final int off, fi } } - private static int[] parentChainingValue( - final int[] leftChildCV, final int[] rightChildCV, final int[] key, final int flags) { + private static int[] parentChainingValue(final int[] leftChildCV, final int[] rightChildCV, final int[] key, final int flags) { return parentOutput(leftChildCV, rightChildCV, key, flags).chainingValue(); } - private static Output parentOutput( - final int[] leftChildCV, final int[] rightChildCV, final int[] key, final int flags) { + private static Output parentOutput(final int[] leftChildCV, final int[] rightChildCV, final int[] key, final int flags) { final int[] blockWords = Arrays.copyOf(leftChildCV, BLOCK_INTS); System.arraycopy(rightChildCV, 0, blockWords, 8, CHAINING_VALUE_INTS); return new Output(key.clone(), blockWords, 0, BLOCK_LEN, flags | PARENT); diff --git a/src/main/java/org/apache/commons/codec/digest/HmacUtils.java b/src/main/java/org/apache/commons/codec/digest/HmacUtils.java index 1f298349d9..38cb141011 100644 --- a/src/main/java/org/apache/commons/codec/digest/HmacUtils.java +++ b/src/main/java/org/apache/commons/codec/digest/HmacUtils.java @@ -196,11 +196,9 @@ public static Mac getInitializedMac(final HmacAlgorithms algorithm, final byte[] * when a {@link NoSuchAlgorithmException} is caught or key is null or key is invalid. */ public static Mac getInitializedMac(final String algorithm, final byte[] key) { - if (key == null) { throw new IllegalArgumentException("Null key"); } - try { final SecretKeySpec keySpec = new SecretKeySpec(key, algorithm); final Mac mac = Mac.getInstance(algorithm); diff --git a/src/main/java/org/apache/commons/codec/digest/PureJavaCrc32.java b/src/main/java/org/apache/commons/codec/digest/PureJavaCrc32.java index c0845e64aa..5cb3a48830 100644 --- a/src/main/java/org/apache/commons/codec/digest/PureJavaCrc32.java +++ b/src/main/java/org/apache/commons/codec/digest/PureJavaCrc32.java @@ -49,6 +49,7 @@ public class PureJavaCrc32 implements Checksum { * CRC-32 lookup tables generated by the polynomial 0xEDB88320. * See also TestPureJavaCrc32.Table. */ + // @formatter:off private static final int[] T = { /* T8_0 */ 0x00000000, 0x77073096, 0xEE0E612C, 0x990951BA, @@ -571,74 +572,75 @@ public class PureJavaCrc32 implements Checksum { 0x2C8E0FFF, 0xE0240F61, 0x6EAB0882, 0xA201081C, 0xA8C40105, 0x646E019B, 0xEAE10678, 0x264B06E6 }; + // @formatter:on - /** The current CRC value, bit-flipped */ - private int crc; + /** The current CRC value, bit-flipped */ + private int crc; - /** Create a new PureJavaCrc32 object. */ - public PureJavaCrc32() { - resetCrc(); - } + /** Create a new PureJavaCrc32 object. */ + public PureJavaCrc32() { + resetCrc(); + } + + @Override + public long getValue() { + return ~crc & 0xffffffffL; + } + + @Override + public void reset() { + resetCrc(); + } - @Override - public long getValue() { - return ~crc & 0xffffffffL; - } + // called by ctor, so must not be overrideable + private void resetCrc() { + crc = 0xffffffff; + } - @Override - public void reset() { - resetCrc(); - } + @Override + public void update(final byte[] b, final int offset, final int len) { + int localCrc = crc; - // called by ctor, so must not be overrideable - private void resetCrc() { - crc = 0xffffffff; - } + final int remainder = len & 0x7; + int i = offset; + for (final int end = offset + len - remainder; i < end; i += 8) { + final int x = localCrc ^ + (b[i] << 24 >>> 24) + (b[i + 1] << 24 >>> 16) + + (b[i + 2] << 24 >>> 8) + (b[i + 3] << 24); - @Override - public void update(final byte[] b, final int offset, final int len) { - int localCrc = crc; + localCrc = T[(x << 24 >>> 24) + 0x700] ^ T[(x << 16 >>> 24) + 0x600] ^ + T[(x << 8 >>> 24) + 0x500] ^ T[ (x >>> 24) + 0x400] ^ + T[(b[i + 4] << 24 >>> 24) + 0x300] ^ T[(b[i + 5] << 24 >>> 24) + 0x200] ^ + T[(b[i + 6] << 24 >>> 24) + 0x100] ^ T[b[i + 7] << 24 >>> 24]; + } - final int remainder = len & 0x7; - int i = offset; - for (final int end = offset + len - remainder; i < end; i += 8) { - final int x = localCrc ^ - (b[i] << 24 >>> 24) + (b[i + 1] << 24 >>> 16) + - (b[i + 2] << 24 >>> 8) + (b[i + 3] << 24); + /* loop unroll - duff's device style */ + switch (remainder) { + case 7: + localCrc = localCrc >>> 8 ^ T[(localCrc ^ b[i++]) << 24 >>> 24]; + case 6: + localCrc = localCrc >>> 8 ^ T[(localCrc ^ b[i++]) << 24 >>> 24]; + case 5: + localCrc = localCrc >>> 8 ^ T[(localCrc ^ b[i++]) << 24 >>> 24]; + case 4: + localCrc = localCrc >>> 8 ^ T[(localCrc ^ b[i++]) << 24 >>> 24]; + case 3: + localCrc = localCrc >>> 8 ^ T[(localCrc ^ b[i++]) << 24 >>> 24]; + case 2: + localCrc = localCrc >>> 8 ^ T[(localCrc ^ b[i++]) << 24 >>> 24]; + case 1: + localCrc = localCrc >>> 8 ^ T[(localCrc ^ b[i++]) << 24 >>> 24]; + default: + /* nothing */ + } - localCrc = T[(x << 24 >>> 24) + 0x700] ^ T[(x << 16 >>> 24) + 0x600] ^ - T[(x << 8 >>> 24) + 0x500] ^ T[ (x >>> 24) + 0x400] ^ - T[(b[i + 4] << 24 >>> 24) + 0x300] ^ T[(b[i + 5] << 24 >>> 24) + 0x200] ^ - T[(b[i + 6] << 24 >>> 24) + 0x100] ^ T[b[i + 7] << 24 >>> 24]; + // Publish crc out to object + crc = localCrc; } - /* loop unroll - duff's device style */ - switch (remainder) { - case 7: - localCrc = localCrc >>> 8 ^ T[(localCrc ^ b[i++]) << 24 >>> 24]; - case 6: - localCrc = localCrc >>> 8 ^ T[(localCrc ^ b[i++]) << 24 >>> 24]; - case 5: - localCrc = localCrc >>> 8 ^ T[(localCrc ^ b[i++]) << 24 >>> 24]; - case 4: - localCrc = localCrc >>> 8 ^ T[(localCrc ^ b[i++]) << 24 >>> 24]; - case 3: - localCrc = localCrc >>> 8 ^ T[(localCrc ^ b[i++]) << 24 >>> 24]; - case 2: - localCrc = localCrc >>> 8 ^ T[(localCrc ^ b[i++]) << 24 >>> 24]; - case 1: - localCrc = localCrc >>> 8 ^ T[(localCrc ^ b[i++]) << 24 >>> 24]; - default: - /* nothing */ + @Override + final public void update(final int b) { + crc = crc >>> 8 ^ T[(crc ^ b) << 24 >>> 24]; } - // Publish crc out to object - crc = localCrc; - } - - @Override - final public void update(final int b) { - crc = crc >>> 8 ^ T[(crc ^ b) << 24 >>> 24]; - } - } diff --git a/src/main/java/org/apache/commons/codec/digest/Sha2Crypt.java b/src/main/java/org/apache/commons/codec/digest/Sha2Crypt.java index 0df7e11659..e20a3a2ce7 100644 --- a/src/main/java/org/apache/commons/codec/digest/Sha2Crypt.java +++ b/src/main/java/org/apache/commons/codec/digest/Sha2Crypt.java @@ -26,7 +26,7 @@ import java.util.regex.Pattern; /** - * SHA2-based Unix crypt implementation. + * SHA2-based UNIX crypt implementation. *

* Based on the C implementation released into the Public Domain by Ulrich Drepper <drepper@redhat.com> * http://www.akkadia.org/drepper/SHA-crypt.txt diff --git a/src/main/java/org/apache/commons/codec/digest/UnixCrypt.java b/src/main/java/org/apache/commons/codec/digest/UnixCrypt.java index dc77091ad8..eecbb89885 100644 --- a/src/main/java/org/apache/commons/codec/digest/UnixCrypt.java +++ b/src/main/java/org/apache/commons/codec/digest/UnixCrypt.java @@ -22,7 +22,7 @@ import java.util.regex.Pattern; /** - * Unix crypt(3) algorithm implementation. + * UNIX crypt(3) algorithm implementation. *

* This class only implements the traditional 56 bit DES based algorithm. Please use DigestUtils.crypt() for a method * that distinguishes between all the algorithms supported in the current glibc's crypt(). diff --git a/src/main/java/org/apache/commons/codec/language/DoubleMetaphone.java b/src/main/java/org/apache/commons/codec/language/DoubleMetaphone.java index 18c3c8f286..4dd8fd3376 100644 --- a/src/main/java/org/apache/commons/codec/language/DoubleMetaphone.java +++ b/src/main/java/org/apache/commons/codec/language/DoubleMetaphone.java @@ -31,8 +31,8 @@ * of the value between threads, and must not invoke {@link #setMaxCodeLen(int)} after initial setup. *

* - * @see Original Article - * @see https://en.wikipedia.org/wiki/Metaphone + * @see Dr. Dobbs Original Article + * @see Wikipedia Metaphone */ public class DoubleMetaphone implements StringEncoder { @@ -617,6 +617,7 @@ private int handleG(final String value, final DoubleMetaphoneResult result, int private int handleGH(final String value, final DoubleMetaphoneResult result, int index) { if (index > 0 && !isVowel(charAt(value, index - 1))) { result.append('K'); + index += 2; } else if (index == 0) { if (charAt(value, index + 2) == 'I') { result.append('J'); diff --git a/src/main/java/org/apache/commons/codec/language/bm/Lang.java b/src/main/java/org/apache/commons/codec/language/bm/Lang.java index 734f668d27..cd5e6f5c4a 100644 --- a/src/main/java/org/apache/commons/codec/language/bm/Lang.java +++ b/src/main/java/org/apache/commons/codec/language/bm/Lang.java @@ -211,9 +211,8 @@ public String guessLanguage(final String text) { */ public Languages.LanguageSet guessLanguages(final String input) { final String text = input.toLowerCase(Locale.ENGLISH); - final Set langs = new HashSet<>(this.languages.getLanguages()); - this.rules.forEach(rule -> { + rules.forEach(rule -> { if (rule.matches(text)) { if (rule.acceptOnMatch) { langs.retainAll(rule.languages); @@ -222,7 +221,6 @@ public Languages.LanguageSet guessLanguages(final String input) { } } }); - final Languages.LanguageSet ls = Languages.LanguageSet.from(langs); return ls.equals(Languages.NO_LANGUAGES) ? Languages.ANY_LANGUAGE : ls; } diff --git a/src/main/java/org/apache/commons/codec/language/bm/PhoneticEngine.java b/src/main/java/org/apache/commons/codec/language/bm/PhoneticEngine.java index b98893cf5d..84fbe35158 100644 --- a/src/main/java/org/apache/commons/codec/language/bm/PhoneticEngine.java +++ b/src/main/java/org/apache/commons/codec/language/bm/PhoneticEngine.java @@ -106,9 +106,8 @@ public void append(final CharSequence str) { * @param maxPhonemes the maximum number of phonemes to build up */ public void apply(final Rule.PhonemeExpr phonemeExpr, final int maxPhonemes) { - final Set newPhonemes = new LinkedHashSet<>(maxPhonemes); - - EXPR: for (final Rule.Phoneme left : this.phonemes) { + final Set newPhonemes = new LinkedHashSet<>(Math.min(phonemes.size() * phonemeExpr.size(), maxPhonemes)); + EXPR: for (final Rule.Phoneme left : phonemes) { for (final Rule.Phoneme right : phonemeExpr.getPhonemes()) { final LanguageSet languages = left.getLanguages().restrictTo(right.getLanguages()); if (!languages.isEmpty()) { @@ -122,9 +121,8 @@ public void apply(final Rule.PhonemeExpr phonemeExpr, final int maxPhonemes) { } } } - - this.phonemes.clear(); - this.phonemes.addAll(newPhonemes); + phonemes.clear(); + phonemes.addAll(newPhonemes); } /** @@ -133,7 +131,7 @@ public void apply(final Rule.PhonemeExpr phonemeExpr, final int maxPhonemes) { * @return the phoneme set */ public Set getPhonemes() { - return this.phonemes; + return phonemes; } /** @@ -155,22 +153,24 @@ public String makeString() { * processed already), and {@code found} indicates if a matching rule was found or not. In the case where a * matching rule was found, {@code phonemeBuilder} is replaced with a new builder containing the phonemes * updated by the matching rule. - * + *

* Although this class is not thread-safe (it has mutable unprotected fields), it is not shared between threads * as it is constructed as needed by the calling methods. + *

+ * * @since 1.6 */ private static final class RulesApplication { + private final Map> finalRules; private final CharSequence input; - private final PhonemeBuilder phonemeBuilder; private int i; private final int maxPhonemes; private boolean found; - public RulesApplication(final Map> finalRules, final CharSequence input, - final PhonemeBuilder phonemeBuilder, final int i, final int maxPhonemes) { + public RulesApplication(final Map> finalRules, final CharSequence input, final PhonemeBuilder phonemeBuilder, final int i, + final int maxPhonemes) { Objects.requireNonNull(finalRules, "finalRules"); this.finalRules = finalRules; this.phonemeBuilder = phonemeBuilder; @@ -180,11 +180,11 @@ public RulesApplication(final Map> finalRules, final CharSequ } public int getI() { - return this.i; + return i; } public PhonemeBuilder getPhonemeBuilder() { - return this.phonemeBuilder; + return phonemeBuilder; } /** @@ -195,31 +195,31 @@ public PhonemeBuilder getPhonemeBuilder() { * @return {@code this} */ public RulesApplication invoke() { - this.found = false; + found = false; int patternLength = 1; - final List rules = this.finalRules.get(input.subSequence(i, i+patternLength)); + final List rules = finalRules.get(input.subSequence(i, i + patternLength)); if (rules != null) { for (final Rule rule : rules) { final String pattern = rule.getPattern(); patternLength = pattern.length(); - if (rule.patternAndContextMatches(this.input, this.i)) { - this.phonemeBuilder.apply(rule.getPhoneme(), maxPhonemes); - this.found = true; + if (rule.patternAndContextMatches(input, i)) { + phonemeBuilder.apply(rule.getPhoneme(), maxPhonemes); + found = true; break; } } } - if (!this.found) { + if (!found) { patternLength = 1; } - this.i += patternLength; + i += patternLength; return this; } public boolean isFound() { - return this.found; + return found; } } @@ -269,11 +269,11 @@ private static String join(final List strings, final String sep) { * the type of names it will use * @param ruleType * the type of rules it will apply - * @param concat + * @param concatenate * if it will concatenate multiple encodings */ - public PhoneticEngine(final NameType nameType, final RuleType ruleType, final boolean concat) { - this(nameType, ruleType, concat, DEFAULT_MAX_PHONEMES); + public PhoneticEngine(final NameType nameType, final RuleType ruleType, final boolean concatenate) { + this(nameType, ruleType, concatenate, DEFAULT_MAX_PHONEMES); } /** @@ -283,20 +283,19 @@ public PhoneticEngine(final NameType nameType, final RuleType ruleType, final bo * the type of names it will use * @param ruleType * the type of rules it will apply - * @param concat + * @param concatenate * if it will concatenate multiple encodings * @param maxPhonemes * the maximum number of phonemes that will be handled * @since 1.7 */ - public PhoneticEngine(final NameType nameType, final RuleType ruleType, final boolean concat, - final int maxPhonemes) { + public PhoneticEngine(final NameType nameType, final RuleType ruleType, final boolean concatenate, final int maxPhonemes) { if (ruleType == RuleType.RULES) { throw new IllegalArgumentException("ruleType must not be " + RuleType.RULES); } this.nameType = nameType; this.ruleType = ruleType; - this.concat = concat; + this.concat = concatenate; this.lang = Lang.instance(nameType); this.maxPhonemes = maxPhonemes; } diff --git a/src/main/java/org/apache/commons/codec/language/bm/Rule.java b/src/main/java/org/apache/commons/codec/language/bm/Rule.java index 641719e74f..728e4bd07b 100644 --- a/src/main/java/org/apache/commons/codec/language/bm/Rule.java +++ b/src/main/java/org/apache/commons/codec/language/bm/Rule.java @@ -166,6 +166,11 @@ public Phoneme mergeWithLanguage(final LanguageSet lang) { return new Phoneme(this.phonemeText.toString(), this.languages.merge(lang)); } + @Override + public int size() { + return 1; + } + @Override public String toString() { return phonemeText.toString() + "[" + languages + "]"; @@ -174,19 +179,35 @@ public String toString() { public interface PhonemeExpr { Iterable getPhonemes(); + + /** + * Gets the expression size in phonemes. + * + * @return the expression size in phonemes. + * @since 1.17.0 + */ + default int size() { + // All implementations are int-bound. + return (int) Math.min(getPhonemes().spliterator().getExactSizeIfKnown(), Integer.MAX_VALUE); + } } public static final class PhonemeList implements PhonemeExpr { - private final List phonemes; + private final List phonemeList; public PhonemeList(final List phonemes) { - this.phonemes = phonemes; + this.phonemeList = phonemes; } @Override public List getPhonemes() { - return this.phonemes; + return phonemeList; + } + + @Override + public int size() { + return phonemeList.size(); } } diff --git a/src/main/java/org/apache/commons/codec/net/BCodec.java b/src/main/java/org/apache/commons/codec/net/BCodec.java index 481cd1e0de..fae4520e03 100644 --- a/src/main/java/org/apache/commons/codec/net/BCodec.java +++ b/src/main/java/org/apache/commons/codec/net/BCodec.java @@ -20,6 +20,7 @@ import java.io.UnsupportedEncodingException; import java.nio.charset.Charset; import java.nio.charset.StandardCharsets; +import java.nio.charset.UnsupportedCharsetException; import org.apache.commons.codec.CodecPolicy; import org.apache.commons.codec.DecoderException; @@ -53,11 +54,6 @@ public class BCodec extends RFC1522Codec implements StringEncoder, StringDecoder */ private static final CodecPolicy DECODING_POLICY_DEFAULT = CodecPolicy.LENIENT; - /** - * The default Charset used for string decoding and encoding. - */ - private final Charset charset; - /** * If true then decoding should throw an exception for impossible combinations of bits at the * end of the byte input. The default is to decode as much of them as possible. @@ -95,7 +91,7 @@ public BCodec(final Charset charset) { * @since 1.15 */ public BCodec(final Charset charset, final CodecPolicy decodingPolicy) { - this.charset = charset; + super(charset); this.decodingPolicy = decodingPolicy; } @@ -132,9 +128,7 @@ public Object decode(final Object value) throws DecoderException { if (value instanceof String) { return decode((String) value); } - throw new DecoderException("Objects of type " + - value.getClass().getName() + - " cannot be decoded using BCodec"); + throw new DecoderException("Objects of type " + value.getClass().getName() + " cannot be decoded using BCodec"); } /** @@ -149,11 +143,8 @@ public Object decode(final Object value) throws DecoderException { */ @Override public String decode(final String value) throws DecoderException { - if (value == null) { - return null; - } try { - return this.decodeText(value); + return decodeText(value); } catch (final UnsupportedEncodingException | IllegalArgumentException e) { throw new DecoderException(e.getMessage(), e); } @@ -192,9 +183,7 @@ public Object encode(final Object value) throws EncoderException { if (value instanceof String) { return encode((String) value); } - throw new EncoderException("Objects of type " + - value.getClass().getName() + - " cannot be encoded using BCodec"); + throw new EncoderException("Objects of type " + value.getClass().getName() + " cannot be encoded using BCodec"); } /** @@ -208,10 +197,7 @@ public Object encode(final Object value) throws EncoderException { */ @Override public String encode(final String strSource) throws EncoderException { - if (strSource == null) { - return null; - } - return encode(strSource, this.getCharset()); + return encode(strSource, getCharset()); } /** @@ -227,9 +213,6 @@ public String encode(final String strSource) throws EncoderException { * @since 1.7 */ public String encode(final String strSource, final Charset sourceCharset) throws EncoderException { - if (strSource == null) { - return null; - } return encodeText(strSource, sourceCharset); } @@ -245,35 +228,13 @@ public String encode(final String strSource, final Charset sourceCharset) throws * thrown if a failure condition is encountered during the encoding process. */ public String encode(final String strSource, final String sourceCharset) throws EncoderException { - if (strSource == null) { - return null; - } try { - return this.encodeText(strSource, sourceCharset); - } catch (final UnsupportedEncodingException e) { + return encodeText(strSource, sourceCharset); + } catch (final UnsupportedCharsetException e) { throw new EncoderException(e.getMessage(), e); } } - /** - * Gets the default Charset name used for string decoding and encoding. - * - * @return the default Charset name - * @since 1.7 - */ - public Charset getCharset() { - return this.charset; - } - - /** - * Gets the default Charset name used for string decoding and encoding. - * - * @return the default Charset name - */ - public String getDefaultCharset() { - return this.charset.name(); - } - @Override protected String getEncoding() { return "B"; diff --git a/src/main/java/org/apache/commons/codec/net/PercentCodec.java b/src/main/java/org/apache/commons/codec/net/PercentCodec.java index df623df198..ee87cf97b6 100644 --- a/src/main/java/org/apache/commons/codec/net/PercentCodec.java +++ b/src/main/java/org/apache/commons/codec/net/PercentCodec.java @@ -42,7 +42,6 @@ public class PercentCodec implements BinaryEncoder, BinaryDecoder { /** * The escape character used by the Percent-Encoding in order to introduce an encoded character. */ - private static final byte ESCAPE_CHAR = '%'; /** @@ -97,7 +96,7 @@ private boolean containsSpace(final byte[] bytes) { } /** - * Decode bytes encoded with Percent-Encoding based on RFC 3986. The reverse process is performed in order to + * Decodes bytes encoded with Percent-Encoding based on RFC 3986. The reverse process is performed in order to * decode the encoded characters to Unicode. */ @Override @@ -105,7 +104,6 @@ public byte[] decode(final byte[] bytes) throws DecoderException { if (bytes == null) { return null; } - final ByteBuffer buffer = ByteBuffer.allocate(expectedDecodingBytes(bytes)); for (int i = 0; i < bytes.length; i++) { final byte b = bytes[i]; @@ -175,7 +173,6 @@ public byte[] encode(final byte[] bytes) throws EncoderException { if (bytes == null) { return null; } - final int expectedEncodingBytes = expectedEncodingBytes(bytes); final boolean willEncode = expectedEncodingBytes != bytes.length; if (willEncode || plusForSpace && containsSpace(bytes)) { @@ -204,9 +201,9 @@ public Object encode(final Object obj) throws EncoderException { private int expectedDecodingBytes(final byte[] bytes) { int byteCount = 0; - for (int i = 0; i < bytes.length; ) { + for (int i = 0; i < bytes.length;) { final byte b = bytes[i]; - i += b == ESCAPE_CHAR ? 3: 1; + i += b == ESCAPE_CHAR ? 3 : 1; byteCount++; } return byteCount; @@ -215,7 +212,7 @@ private int expectedDecodingBytes(final byte[] bytes) { private int expectedEncodingBytes(final byte[] bytes) { int byteCount = 0; for (final byte b : bytes) { - byteCount += canEncode(b) ? 3: 1; + byteCount += canEncode(b) ? 3 : 1; } return byteCount; } @@ -244,7 +241,7 @@ private void insertAlwaysEncodeChar(final byte b) { } /** - * Adds the byte array into a BitSet for faster lookup + * Inserts the byte array into a BitSet for faster lookup. * * @param alwaysEncodeCharsArray */ diff --git a/src/main/java/org/apache/commons/codec/net/QCodec.java b/src/main/java/org/apache/commons/codec/net/QCodec.java index 4618a7e31a..3dad9bdefc 100644 --- a/src/main/java/org/apache/commons/codec/net/QCodec.java +++ b/src/main/java/org/apache/commons/codec/net/QCodec.java @@ -20,6 +20,7 @@ import java.io.UnsupportedEncodingException; import java.nio.charset.Charset; import java.nio.charset.StandardCharsets; +import java.nio.charset.UnsupportedCharsetException; import java.util.BitSet; import org.apache.commons.codec.DecoderException; @@ -103,11 +104,6 @@ public class QCodec extends RFC1522Codec implements StringEncoder, StringDecoder private static final byte UNDERSCORE = 95; - /** - * The default Charset used for string decoding and encoding. - */ - private final Charset charset; - private boolean encodeBlanks; /** @@ -127,7 +123,7 @@ public QCodec() { * @since 1.7 */ public QCodec(final Charset charset) { - this.charset = charset; + super(charset); } /** @@ -163,9 +159,7 @@ public Object decode(final Object obj) throws DecoderException { if (obj instanceof String) { return decode((String) obj); } - throw new DecoderException("Objects of type " + - obj.getClass().getName() + - " cannot be decoded using Q codec"); + throw new DecoderException("Objects of type " + obj.getClass().getName() + " cannot be decoded using Q codec"); } /** @@ -180,9 +174,6 @@ public Object decode(final Object obj) throws DecoderException { */ @Override public String decode(final String str) throws DecoderException { - if (str == null) { - return null; - } try { return decodeText(str); } catch (final UnsupportedEncodingException e) { @@ -250,9 +241,7 @@ public Object encode(final Object obj) throws EncoderException { if (obj instanceof String) { return encode((String) obj); } - throw new EncoderException("Objects of type " + - obj.getClass().getName() + - " cannot be encoded using Q codec"); + throw new EncoderException("Objects of type " + obj.getClass().getName() + " cannot be encoded using Q codec"); } /** @@ -266,9 +255,6 @@ public Object encode(final Object obj) throws EncoderException { */ @Override public String encode(final String sourceStr) throws EncoderException { - if (sourceStr == null) { - return null; - } return encode(sourceStr, getCharset()); } @@ -285,9 +271,6 @@ public String encode(final String sourceStr) throws EncoderException { * @since 1.7 */ public String encode(final String sourceStr, final Charset sourceCharset) throws EncoderException { - if (sourceStr == null) { - return null; - } return encodeText(sourceStr, sourceCharset); } @@ -303,35 +286,13 @@ public String encode(final String sourceStr, final Charset sourceCharset) throws * thrown if a failure condition is encountered during the encoding process. */ public String encode(final String sourceStr, final String sourceCharset) throws EncoderException { - if (sourceStr == null) { - return null; - } try { return encodeText(sourceStr, sourceCharset); - } catch (final UnsupportedEncodingException e) { + } catch (final UnsupportedCharsetException e) { throw new EncoderException(e.getMessage(), e); } } - /** - * Gets the default Charset name used for string decoding and encoding. - * - * @return the default Charset name - * @since 1.7 - */ - public Charset getCharset() { - return this.charset; - } - - /** - * Gets the default Charset name used for string decoding and encoding. - * - * @return the default Charset name - */ - public String getDefaultCharset() { - return this.charset.name(); - } - @Override protected String getEncoding() { return "Q"; diff --git a/src/main/java/org/apache/commons/codec/net/QuotedPrintableCodec.java b/src/main/java/org/apache/commons/codec/net/QuotedPrintableCodec.java index 03fbc13f62..6dd8007723 100644 --- a/src/main/java/org/apache/commons/codec/net/QuotedPrintableCodec.java +++ b/src/main/java/org/apache/commons/codec/net/QuotedPrintableCodec.java @@ -149,7 +149,7 @@ public static final byte[] decodeQuotedPrintable(final byte[] bytes) throws Deco } /** - * Write a byte to the buffer. + * Encodes a byte in the buffer. * * @param b * byte to write @@ -159,8 +159,7 @@ public static final byte[] decodeQuotedPrintable(final byte[] bytes) throws Deco * the buffer to write to * @return the number of bytes that have been written to the buffer */ - private static int encodeByte(final int b, final boolean encode, - final ByteArrayOutputStream buffer) { + private static int encodeByte(final int b, final boolean encode, final ByteArrayOutputStream buffer) { if (encode) { return encodeQuotedPrintable(b, buffer); } @@ -388,8 +387,7 @@ public QuotedPrintableCodec(final Charset charset, final boolean strict) { * * @since 1.7 throws UnsupportedCharsetException if the named Charset is unavailable */ - public QuotedPrintableCodec(final String charsetName) - throws IllegalCharsetNameException, IllegalArgumentException, UnsupportedCharsetException { + public QuotedPrintableCodec(final String charsetName) throws IllegalCharsetNameException, IllegalArgumentException, UnsupportedCharsetException { this(Charset.forName(charsetName), false); } @@ -434,9 +432,7 @@ public Object decode(final Object obj) throws DecoderException { if (obj instanceof String) { return decode((String) obj); } - throw new DecoderException("Objects of type " + - obj.getClass().getName() + - " cannot be quoted-printable decoded"); + throw new DecoderException("Objects of type " + obj.getClass().getName() + " cannot be quoted-printable decoded"); } /** @@ -489,8 +485,7 @@ public String decode(final String sourceStr, final Charset sourceCharset) throws * @throws UnsupportedEncodingException * Thrown if Charset is not supported */ - public String decode(final String sourceStr, final String sourceCharset) - throws DecoderException, UnsupportedEncodingException { + public String decode(final String sourceStr, final String sourceCharset) throws DecoderException, UnsupportedEncodingException { if (sourceStr == null) { return null; } @@ -535,9 +530,7 @@ public Object encode(final Object obj) throws EncoderException { if (obj instanceof String) { return encode((String) obj); } - throw new EncoderException("Objects of type " + - obj.getClass().getName() + - " cannot be quoted-printable encoded"); + throw new EncoderException("Objects of type " + obj.getClass().getName() + " cannot be quoted-printable encoded"); } /** @@ -558,7 +551,7 @@ public Object encode(final Object obj) throws EncoderException { */ @Override public String encode(final String sourceStr) throws EncoderException { - return this.encode(sourceStr, getCharset()); + return encode(sourceStr, getCharset()); } /** diff --git a/src/main/java/org/apache/commons/codec/net/RFC1522Codec.java b/src/main/java/org/apache/commons/codec/net/RFC1522Codec.java index c71304a1c7..39064c52a6 100644 --- a/src/main/java/org/apache/commons/codec/net/RFC1522Codec.java +++ b/src/main/java/org/apache/commons/codec/net/RFC1522Codec.java @@ -19,6 +19,8 @@ import java.io.UnsupportedEncodingException; import java.nio.charset.Charset; +import java.nio.charset.UnsupportedCharsetException; +import java.util.Objects; import org.apache.commons.codec.DecoderException; import org.apache.commons.codec.EncoderException; @@ -37,7 +39,6 @@ * * @see MIME (Multipurpose Internet Mail Extensions) Part Two: * Message Header Extensions for Non-ASCII Text - * * @since 1.3 */ abstract class RFC1522Codec { @@ -51,6 +52,15 @@ abstract class RFC1522Codec { /** Postfix. */ protected static final String PREFIX = "=?"; + /** + * The default Charset used for string decoding and encoding. + */ + protected final Charset charset; + + RFC1522Codec(final Charset charset) { + this.charset = Objects.requireNonNull(charset, "charset"); + } + /** * Applies an RFC 1522 compliant decoding scheme to the given string of text. *

@@ -66,8 +76,7 @@ abstract class RFC1522Codec { * @throws UnsupportedEncodingException * thrown if charset specified in the "encoded-word" header is not supported */ - protected String decodeText(final String text) - throws DecoderException, UnsupportedEncodingException { + protected String decodeText(final String text) throws DecoderException, UnsupportedEncodingException { if (text == null) { return null; } @@ -167,22 +176,41 @@ protected String encodeText(final String text, final Charset charset) throws Enc * @return RFC 1522 compliant "encoded-word" * @throws EncoderException * thrown if there is an error condition during the Encoding process. - * @throws UnsupportedEncodingException + * @throws UnsupportedCharsetException * if charset is not available * @see Charset */ - protected String encodeText(final String text, final String charsetName) - throws EncoderException, UnsupportedEncodingException { + protected String encodeText(final String text, final String charsetName) throws EncoderException { if (text == null) { + // Don't attempt charsetName conversion. return null; } - return this.encodeText(text, Charset.forName(charsetName)); + return encodeText(text, Charset.forName(charsetName)); + } + + /** + * Gets the default Charset name used for string decoding and encoding. + * + * @return the default Charset name + * @since 1.7 + */ + public Charset getCharset() { + return charset; + } + + /** + * Gets the default Charset name used for string decoding and encoding. + * + * @return the default Charset name + */ + public String getDefaultCharset() { + return charset.name(); } /** * Returns the codec name (referred to as encoding in the RFC 1522). * - * @return name of the codec + * @return name of the codec. */ protected abstract String getEncoding(); } diff --git a/src/site/xdoc/download_codec.xml b/src/site/xdoc/download_codec.xml index 2b5813df7d..21317e594b 100644 --- a/src/site/xdoc/download_codec.xml +++ b/src/site/xdoc/download_codec.xml @@ -113,32 +113,32 @@ limitations under the License.

-
+
- - - + + + - - - + + +
commons-codec-1.16.1-bin.tar.gzsha512pgpcommons-codec-1.17.0-bin.tar.gzsha512pgp
commons-codec-1.16.1-bin.zipsha512pgpcommons-codec-1.17.0-bin.zipsha512pgp
- - - + + + - - - + + +
commons-codec-1.16.1-src.tar.gzsha512pgpcommons-codec-1.17.0-src.tar.gzsha512pgp
commons-codec-1.16.1-src.zipsha512pgpcommons-codec-1.17.0-src.zipsha512pgp
diff --git a/src/test/java/org/apache/commons/codec/binary/Base32InputStreamTest.java b/src/test/java/org/apache/commons/codec/binary/Base32InputStreamTest.java index 81e17d24a8..2c6c4c4446 100644 --- a/src/test/java/org/apache/commons/codec/binary/Base32InputStreamTest.java +++ b/src/test/java/org/apache/commons/codec/binary/Base32InputStreamTest.java @@ -248,33 +248,28 @@ public void testBase32InputStreamByteByByte() throws Exception { * Usually signifies a bug in the Base32 commons-codec implementation. */ private void testByChunk(final byte[] encoded, final byte[] decoded, final int chunkSize, final byte[] separator) throws Exception { - // Start with encode. - InputStream in; - - in = new Base32InputStream(new ByteArrayInputStream(decoded), true, chunkSize, separator); - byte[] output = BaseNTestData.streamToBytes(in); - - assertEquals(-1, in.read(), "EOF"); - assertEquals(-1, in.read(), "Still EOF"); - assertArrayEquals(encoded, output, "Streaming base32 encode"); - + try (InputStream in = new Base32InputStream(new ByteArrayInputStream(decoded), true, chunkSize, separator)) { + final byte[] output = BaseNTestData.streamToBytes(in); + assertEquals(-1, in.read(), "EOF"); + assertEquals(-1, in.read(), "Still EOF"); + assertArrayEquals(encoded, output, "Streaming base32 encode"); + } // Now let's try to decode. - in = new Base32InputStream(new ByteArrayInputStream(encoded)); - output = BaseNTestData.streamToBytes(in); - - assertEquals(-1, in.read(), "EOF"); - assertEquals(-1, in.read(), "Still EOF"); - assertArrayEquals(decoded, output, "Streaming base32 decode"); + try (InputStream in = new Base32InputStream(new ByteArrayInputStream(encoded))) { + final byte[] output = BaseNTestData.streamToBytes(in); + assertEquals(-1, in.read(), "EOF"); + assertEquals(-1, in.read(), "Still EOF"); + assertArrayEquals(decoded, output, "Streaming base32 decode"); + } // I always wanted to do this! (wrap encoder with decoder etc.). - in = new ByteArrayInputStream(decoded); + InputStream in = new ByteArrayInputStream(decoded); for (int i = 0; i < 10; i++) { in = new Base32InputStream(in, true, chunkSize, separator); in = new Base32InputStream(in, false); } - output = BaseNTestData.streamToBytes(in); - + final byte[] output = BaseNTestData.streamToBytes(in); assertEquals(-1, in.read(), "EOF"); assertEquals(-1, in.read(), "Still EOF"); assertArrayEquals(decoded, output, "Streaming base32 wrap-wrap-wrap!"); diff --git a/src/test/java/org/apache/commons/codec/binary/Base32Test.java b/src/test/java/org/apache/commons/codec/binary/Base32Test.java index de2cd67e14..0414914496 100644 --- a/src/test/java/org/apache/commons/codec/binary/Base32Test.java +++ b/src/test/java/org/apache/commons/codec/binary/Base32Test.java @@ -355,6 +355,41 @@ public void testBase32SamplesNonDefaultPadding() throws Exception { } } + @Test + public void testBuilderCodecPolicy() { + assertEquals(CodecPolicy.LENIENT, Base32.builder().get().getCodecPolicy()); + assertEquals(CodecPolicy.LENIENT, Base32.builder().setDecodingPolicy(CodecPolicy.LENIENT).get().getCodecPolicy()); + assertEquals(CodecPolicy.STRICT, Base32.builder().setDecodingPolicy(CodecPolicy.STRICT).get().getCodecPolicy()); + assertEquals(CodecPolicy.LENIENT, Base32.builder().setDecodingPolicy(CodecPolicy.STRICT).setDecodingPolicy(null).get().getCodecPolicy()); + assertEquals(CodecPolicy.LENIENT, Base32.builder().setDecodingPolicy(null).get().getCodecPolicy()); + } + + @Test + public void testBuilderLineAttributes() { + assertNull(Base32.builder().get().getLineSeparator()); + assertNull(Base32.builder().setLineSeparator(BaseNCodec.CHUNK_SEPARATOR).get().getLineSeparator()); + assertArrayEquals(BaseNCodec.CHUNK_SEPARATOR, Base32.builder().setLineLength(4).setLineSeparator(BaseNCodec.CHUNK_SEPARATOR).get().getLineSeparator()); + assertArrayEquals(BaseNCodec.CHUNK_SEPARATOR, Base32.builder().setLineLength(4).setLineSeparator(null).get().getLineSeparator()); + assertArrayEquals(BaseNCodec.CHUNK_SEPARATOR, Base32.builder().setLineLength(10).setLineSeparator(null).get().getLineSeparator()); + assertNull(Base32.builder().setLineLength(-1).setLineSeparator(null).get().getLineSeparator()); + assertNull(Base32.builder().setLineLength(0).setLineSeparator(null).get().getLineSeparator()); + assertArrayEquals(new byte[] { 1 }, Base32.builder().setLineLength(4).setLineSeparator((byte) 1).get().getLineSeparator()); + assertEquals("MZXXQ===", Base32.builder().setLineLength(4).get().encodeToString("fox".getBytes(CHARSET_UTF8))); + } + + @Test + public void testBuilderPadingByte() { + assertNull(Base32.builder().get().getLineSeparator()); + assertNull(Base32.builder().setLineSeparator(BaseNCodec.CHUNK_SEPARATOR).get().getLineSeparator()); + assertArrayEquals(BaseNCodec.CHUNK_SEPARATOR, Base32.builder().setLineLength(4).setLineSeparator(BaseNCodec.CHUNK_SEPARATOR).get().getLineSeparator()); + assertArrayEquals(BaseNCodec.CHUNK_SEPARATOR, Base32.builder().setLineLength(4).setLineSeparator(null).get().getLineSeparator()); + assertArrayEquals(BaseNCodec.CHUNK_SEPARATOR, Base32.builder().setLineLength(10).setLineSeparator(null).get().getLineSeparator()); + assertNull(Base32.builder().setLineLength(-1).setLineSeparator(null).get().getLineSeparator()); + assertNull(Base32.builder().setLineLength(0).setLineSeparator(null).get().getLineSeparator()); + assertArrayEquals(new byte[] { 1 }, Base32.builder().setLineLength(4).setLineSeparator((byte) 1).get().getLineSeparator()); + assertEquals("MZXXQ___", Base32.builder().setLineLength(4).setPadding((byte) '_').get().encodeToString("fox".getBytes(CHARSET_UTF8))); + } + @Test public void testCodec200() { final Base32 codec = new Base32(true, (byte) 'W'); // should be allowed diff --git a/src/test/java/org/apache/commons/codec/binary/Base64Test.java b/src/test/java/org/apache/commons/codec/binary/Base64Test.java index 7919ea8859..e96e9fa790 100644 --- a/src/test/java/org/apache/commons/codec/binary/Base64Test.java +++ b/src/test/java/org/apache/commons/codec/binary/Base64Test.java @@ -46,6 +46,10 @@ */ public class Base64Test { + private static final String FOX_BASE64 = "VGhlIH@$#$@%F1aWN@#@#@@rIGJyb3duIGZve\n\r\t%#%#%#%CBqd##$#$W1wZWQgb3ZlciB0aGUgbGF6eSBkb2dzLg=="; + + private static final String FOX_TEXT = "The quick brown fox jumped over the lazy dogs."; + private static final Charset CHARSET_UTF8 = StandardCharsets.UTF_8; /** @@ -216,6 +220,50 @@ private void testBase64InBuffer(final int startPasSize, final int endPadSize) { assertEquals("SGVsbG8gV29ybGQ=", encodedContent, "encoding hello world"); } + @Test + public void testBuilderCodecPolicy() { + assertEquals(CodecPolicy.LENIENT, Base64.builder().get().getCodecPolicy()); + assertEquals(CodecPolicy.LENIENT, Base64.builder().setDecodingPolicy(CodecPolicy.LENIENT).get().getCodecPolicy()); + assertEquals(CodecPolicy.STRICT, Base64.builder().setDecodingPolicy(CodecPolicy.STRICT).get().getCodecPolicy()); + assertEquals(CodecPolicy.LENIENT, Base64.builder().setDecodingPolicy(CodecPolicy.STRICT).setDecodingPolicy(null).get().getCodecPolicy()); + assertEquals(CodecPolicy.LENIENT, Base64.builder().setDecodingPolicy(null).get().getCodecPolicy()); + } + + @Test + public void testBuilderLineAttributes() { + assertNull(Base64.builder().get().getLineSeparator()); + assertNull(Base64.builder().setLineSeparator(BaseNCodec.CHUNK_SEPARATOR).get().getLineSeparator()); + assertArrayEquals(BaseNCodec.CHUNK_SEPARATOR, Base64.builder().setLineLength(4).setLineSeparator(BaseNCodec.CHUNK_SEPARATOR).get().getLineSeparator()); + assertArrayEquals(BaseNCodec.CHUNK_SEPARATOR, Base64.builder().setLineLength(4).setLineSeparator(null).get().getLineSeparator()); + assertArrayEquals(BaseNCodec.CHUNK_SEPARATOR, Base64.builder().setLineLength(10).setLineSeparator(null).get().getLineSeparator()); + assertNull(Base64.builder().setLineLength(-1).setLineSeparator(null).get().getLineSeparator()); + assertNull(Base64.builder().setLineLength(0).setLineSeparator(null).get().getLineSeparator()); + assertArrayEquals(new byte[] { 1 }, Base64.builder().setLineLength(4).setLineSeparator((byte) 1).get().getLineSeparator()); + assertEquals("Zm94\r\n", Base64.builder().setLineLength(4).get().encodeToString("fox".getBytes(CHARSET_UTF8))); + } + + @Test + public void testBuilderPadingByte() { + assertNull(Base64.builder().get().getLineSeparator()); + assertNull(Base64.builder().setLineSeparator(BaseNCodec.CHUNK_SEPARATOR).get().getLineSeparator()); + assertArrayEquals(BaseNCodec.CHUNK_SEPARATOR, Base64.builder().setLineLength(4).setLineSeparator(BaseNCodec.CHUNK_SEPARATOR).get().getLineSeparator()); + assertArrayEquals(BaseNCodec.CHUNK_SEPARATOR, Base64.builder().setLineLength(4).setLineSeparator(null).get().getLineSeparator()); + assertArrayEquals(BaseNCodec.CHUNK_SEPARATOR, Base64.builder().setLineLength(10).setLineSeparator(null).get().getLineSeparator()); + assertNull(Base64.builder().setLineLength(-1).setLineSeparator(null).get().getLineSeparator()); + assertNull(Base64.builder().setLineLength(0).setLineSeparator(null).get().getLineSeparator()); + assertArrayEquals(new byte[] { 1 }, Base64.builder().setLineLength(4).setLineSeparator((byte) 1).get().getLineSeparator()); + assertEquals("VGhlIGJyb3duIGZveA==", Base64.builder().get().encodeToString("The brown fox".getBytes(CHARSET_UTF8))); + assertEquals("VGhlIGJyb3duIGZveA__", Base64.builder().setPadding((byte) '_').get().encodeToString("The brown fox".getBytes(CHARSET_UTF8))); + } + + @Test + public void testBuilderUrlSafe() { + assertFalse(Base64.builder().get().isUrlSafe()); + assertFalse(Base64.builder().setUrlSafe(false).get().isUrlSafe()); + assertFalse(Base64.builder().setUrlSafe(true).setUrlSafe(false).get().isUrlSafe()); + assertTrue(Base64.builder().setUrlSafe(false).setUrlSafe(true).get().isUrlSafe()); + } + @Test public void testByteToStringVariations() throws DecoderException { final Base64 base64 = new Base64(0); @@ -257,6 +305,14 @@ public void testCodec112() { // size calculation assumes always chunked // TODO Assert?? } + /** + * Tests CODEC-263. + */ + public void testCodec263() { + Base64.decodeBase64("publishMessage"); + assertTrue(Base64.isBase64("publishMessage")); + } + /** * Test for CODEC-265: Encode a 1GiB file. * @@ -415,6 +471,55 @@ public void testConstructors() { assertNotNull(base64); } + @Test + public void testCustomEncodingAlphabet() { + // created a duplicate of STANDARD_ENCODE_TABLE and replaced two chars with + // custom values not already present in table + // A => . B => - + // @formatter:off + final byte[] encodeTable = { + '.', '-', 'C', 'D', 'E', 'F', 'G', 'H', 'I', 'J', 'K', 'L', 'M', + 'N', 'O', 'P', 'Q', 'R', 'S', 'T', 'U', 'V', 'W', 'X', 'Y', 'Z', + 'a', 'b', 'c', 'd', 'e', 'f', 'g', 'h', 'i', 'j', 'k', 'l', 'm', + 'n', 'o', 'p', 'q', 'r', 's', 't', 'u', 'v', 'w', 'x', 'y', 'z', + '0', '1', '2', '3', '4', '5', '6', '7', '8', '9', '+', '/' + }; + // @formatter:on + + // two instances: one with default table and one with adjusted encoding table + final Base64 b64 = new Base64(); + final Base64 b64customEncoding = Base64.builder().setEncodeTable(encodeTable).get(); + + final String content = "! Hello World - this §$%"; + + final byte[] encodedBytes = b64.encode(StringUtils.getBytesUtf8(content)); + final String encodedContent = StringUtils.newStringUtf8(encodedBytes); + + final byte[] encodedBytesCustom = b64customEncoding.encode(StringUtils.getBytesUtf8(content)); + final String encodedContentCustom = StringUtils.newStringUtf8(encodedBytesCustom); + + assertTrue(encodedContent.contains("A") && encodedContent.contains("B"), + "testing precondition not met - ecodedContent should contain parts of modified table"); + + assertEquals(encodedContent.replace('A', '.').replace('B', '-') // replace alphabet adjustments + .replace("=", "") // remove padding (not default alphabet) + , encodedContentCustom); + + // try decode encoded content + final byte[] decode = b64customEncoding.decode(encodedBytesCustom); + final String decodeString = StringUtils.newStringUtf8(decode); + + assertEquals(content, decodeString); + } + + @Test + public void testCustomEncodingAlphabet_illegal() { + final byte[] encodeTable = { + '.', '-', 'C', 'D', 'E', 'F', 'G', 'H', 'I', 'J', 'K', 'L', 'M' + }; + assertThrows(IllegalArgumentException.class, () -> Base64.builder().setEncodeTable(encodeTable).get()); + } + private void testDecodeEncode(final String encodedText) { final String decodedText = StringUtils.newStringUsAscii(Base64.decodeBase64(encodedText)); final String encodedText2 = Base64.encodeBase64String(StringUtils.getBytesUtf8(decodedText)); @@ -583,10 +688,7 @@ public void testHugeLineSeparator() { @Test public void testIgnoringNonBase64InDecode() throws Exception { - assertEquals("The quick brown fox jumped over the lazy dogs.", - new String(Base64.decodeBase64( - "VGhlIH@$#$@%F1aWN@#@#@@rIGJyb3duIGZve\n\r\t%#%#%#%CBqd##$#$W1wZWQgb3ZlciB0aGUgbGF6eSBkb2dzLg==" - .getBytes(CHARSET_UTF8)))); + assertEquals(FOX_TEXT, new String(Base64.decodeBase64(FOX_BASE64.getBytes(CHARSET_UTF8)))); } @Test @@ -643,7 +745,7 @@ public void testIsUrlSafe() { @Test public void testKnownDecodings() { - assertEquals("The quick brown fox jumped over the lazy dogs.", new String(Base64.decodeBase64( + assertEquals(FOX_TEXT, new String(Base64.decodeBase64( "VGhlIHF1aWNrIGJyb3duIGZveCBqdW1wZWQgb3ZlciB0aGUgbGF6eSBkb2dzLg==".getBytes(CHARSET_UTF8)))); assertEquals("It was the best of times, it was the worst of times.", new String(Base64.decodeBase64( "SXQgd2FzIHRoZSBiZXN0IG9mIHRpbWVzLCBpdCB3YXMgdGhlIHdvcnN0IG9mIHRpbWVzLg==".getBytes(CHARSET_UTF8)))); @@ -659,7 +761,7 @@ public void testKnownDecodings() { @Test public void testKnownEncodings() { assertEquals("VGhlIHF1aWNrIGJyb3duIGZveCBqdW1wZWQgb3ZlciB0aGUgbGF6eSBkb2dzLg==", new String( - Base64.encodeBase64("The quick brown fox jumped over the lazy dogs.".getBytes(CHARSET_UTF8)))); + Base64.encodeBase64(FOX_TEXT.getBytes(CHARSET_UTF8)))); assertEquals( "YmxhaCBibGFoIGJsYWggYmxhaCBibGFoIGJsYWggYmxhaCBibGFoIGJsYWggYmxhaCBibGFoIGJs\r\nYWggYmxhaCBibGFoIGJsYWggYmxhaCBibGFoIGJsYWggYmxhaCBibGFoIGJsYWggYmxhaCBibGFo\r\nIGJsYWggYmxhaCBibGFoIGJsYWggYmxhaCBibGFoIGJsYWggYmxhaCBibGFoIGJsYWggYmxhaCBi\r\nbGFoIGJsYWg=\r\n", new String(Base64.encodeBase64Chunked( diff --git a/src/test/java/org/apache/commons/codec/binary/BaseNCodecTest.java b/src/test/java/org/apache/commons/codec/binary/BaseNCodecTest.java index 887d0127fc..dbe9391630 100644 --- a/src/test/java/org/apache/commons/codec/binary/BaseNCodecTest.java +++ b/src/test/java/org/apache/commons/codec/binary/BaseNCodecTest.java @@ -137,8 +137,9 @@ static long getPresumableFreeMemory() { return Runtime.getRuntime().maxMemory() - allocatedMemory; } -BaseNCodec codec; -@BeforeEach + BaseNCodec codec; + @BeforeEach + public void setUp() { codec = new BaseNCodec(0, 0, 0, 0) { @Override @@ -151,7 +152,7 @@ void encode(final byte[] pArray, final int i, final int length, final Context co @Override protected boolean isInAlphabet(final byte b) { - return b=='O' || b == 'K'; // allow OK + return b == 'O' || b == 'K'; // allow OK } }; } diff --git a/src/test/java/org/apache/commons/codec/binary/CharSequenceUtilsTest.java b/src/test/java/org/apache/commons/codec/binary/CharSequenceUtilsTest.java index d1e580faa6..93d3aba466 100644 --- a/src/test/java/org/apache/commons/codec/binary/CharSequenceUtilsTest.java +++ b/src/test/java/org/apache/commons/codec/binary/CharSequenceUtilsTest.java @@ -58,7 +58,8 @@ void run(final TestData data, final String id) { // Note: The commented out tests fail due to the CharSequenceUtils method // being based on Lang 3.3.2 and the tests are from 3.11. - static class TestData{ + static class TestData { + final String source; final boolean ignoreCase; final int toffset; @@ -67,8 +68,9 @@ static class TestData{ final int len; final boolean expected; final Class throwable; - TestData(final String source, final boolean ignoreCase, final int toffset, - final String other, final int ooffset, final int len, final boolean expected) { + + TestData(final String source, final boolean ignoreCase, final int toffset, final String other, final int ooffset, final int len, + final boolean expected) { this.source = source; this.ignoreCase = ignoreCase; this.toffset = toffset; @@ -78,8 +80,9 @@ static class TestData{ this.expected = expected; this.throwable = null; } - TestData(final String source, final boolean ignoreCase, final int toffset, - final String other, final int ooffset, final int len, final Class throwable) { + + TestData(final String source, final boolean ignoreCase, final int toffset, final String other, final int ooffset, final int len, + final Class throwable) { this.source = source; this.ignoreCase = ignoreCase; this.toffset = toffset; @@ -89,11 +92,12 @@ static class TestData{ this.expected = false; this.throwable = throwable; } + @Override public String toString() { final StringBuilder sb = new StringBuilder(); sb.append(source).append("[").append(toffset).append("]"); - sb.append(ignoreCase? " caseblind ":" samecase "); + sb.append(ignoreCase ? " caseblind " : " samecase "); sb.append(other).append("[").append(ooffset).append("]"); sb.append(" ").append(len).append(" => "); if (throwable != null) { diff --git a/src/test/java/org/apache/commons/codec/binary/HexTest.java b/src/test/java/org/apache/commons/codec/binary/HexTest.java index d41d57a2d3..8857b267c0 100644 --- a/src/test/java/org/apache/commons/codec/binary/HexTest.java +++ b/src/test/java/org/apache/commons/codec/binary/HexTest.java @@ -198,7 +198,7 @@ public void testCustomCharsetBadName() { @Test public void testCustomCharsetToString() { - assertTrue(new Hex().toString().indexOf(Hex.DEFAULT_CHARSET_NAME) >= 0); + assertTrue(new Hex().toString().contains(Hex.DEFAULT_CHARSET_NAME)); } @Test diff --git a/src/test/java/org/apache/commons/codec/cli/DigestTest.java b/src/test/java/org/apache/commons/codec/cli/DigestTest.java index c00cba7bdd..a45fba6443 100644 --- a/src/test/java/org/apache/commons/codec/cli/DigestTest.java +++ b/src/test/java/org/apache/commons/codec/cli/DigestTest.java @@ -38,6 +38,6 @@ public void testEmptyArguments() { */ @Test public void testNullArguments() { - assertThrows(IllegalArgumentException.class, () -> Digest.main(null)); + assertThrows(NullPointerException.class, () -> Digest.main(null)); } } diff --git a/src/test/java/org/apache/commons/codec/digest/DigestUtilsTest.java b/src/test/java/org/apache/commons/codec/digest/DigestUtilsTest.java index 7b5baf9d21..6958d44274 100644 --- a/src/test/java/org/apache/commons/codec/digest/DigestUtilsTest.java +++ b/src/test/java/org/apache/commons/codec/digest/DigestUtilsTest.java @@ -50,7 +50,7 @@ import org.junit.jupiter.api.Test; /** - * Tests DigestUtils methods. + * Tests {@link DigestUtils}. */ public class DigestUtilsTest { @@ -154,17 +154,13 @@ public void testMd2Hex() throws IOException { assertEquals("4e8ddff3650292ab5a4108c3aa47940b", DigestUtils.md2Hex("abcdefghijklmnopqrstuvwxyz")); - assertEquals( - "da33def2a42df13975352846c30338cd", - DigestUtils.md2Hex("ABCDEFGHIJKLMNOPQRSTUVWXYZ" + "abcdefghijklmnopqrstuvwxyz" + "0123456789")); + assertEquals("da33def2a42df13975352846c30338cd", DigestUtils.md2Hex("ABCDEFGHIJKLMNOPQRSTUVWXYZ" + "abcdefghijklmnopqrstuvwxyz" + "0123456789")); - assertEquals( - "d5976f79d83d3a0dc9806c3c66f3efd8", - DigestUtils.md2Hex("1234567890123456789012345678901234567890" + "1234567890123456789012345678901234567890")); + assertEquals("d5976f79d83d3a0dc9806c3c66f3efd8", + DigestUtils.md2Hex("1234567890123456789012345678901234567890" + "1234567890123456789012345678901234567890")); - assertEquals(DigestUtils.md2Hex(testData), - DigestUtils.md2Hex(new ByteArrayInputStream(testData))); -} + assertEquals(DigestUtils.md2Hex(testData), DigestUtils.md2Hex(new ByteArrayInputStream(testData))); + } /** * An MD2 hash converted to hexadecimal should always be 32 characters. @@ -207,16 +203,12 @@ public void testMd5Hex() throws IOException { assertEquals("c3fcd3d76192e4007dfb496cca67e13b", DigestUtils.md5Hex("abcdefghijklmnopqrstuvwxyz")); - assertEquals( - "d174ab98d277d9f5a5611c2c9f419d9f", - DigestUtils.md5Hex("ABCDEFGHIJKLMNOPQRSTUVWXYZ" + "abcdefghijklmnopqrstuvwxyz" + "0123456789")); + assertEquals("d174ab98d277d9f5a5611c2c9f419d9f", DigestUtils.md5Hex("ABCDEFGHIJKLMNOPQRSTUVWXYZ" + "abcdefghijklmnopqrstuvwxyz" + "0123456789")); - assertEquals( - "57edf4a22be3c955ac49da2e2107b67a", - DigestUtils.md5Hex("1234567890123456789012345678901234567890" + "1234567890123456789012345678901234567890")); + assertEquals("57edf4a22be3c955ac49da2e2107b67a", + DigestUtils.md5Hex("1234567890123456789012345678901234567890" + "1234567890123456789012345678901234567890")); - assertEquals(DigestUtils.md5Hex(testData), - DigestUtils.md5Hex(new ByteArrayInputStream(testData))); + assertEquals(DigestUtils.md5Hex(testData), DigestUtils.md5Hex(new ByteArrayInputStream(testData))); } /** @@ -254,15 +246,12 @@ public void testSha1Hex() throws IOException { assertEquals("a9993e364706816aba3e25717850c26c9cd0d89d", DigestUtils.sha1Hex(getBytesUtf8("abc"))); - assertEquals( - "84983e441c3bd26ebaae4aa1f95129e5e54670f1", - DigestUtils.sha1Hex("abcdbcdecdefdefgefghfghighij" + "hijkijkljklmklmnlmnomnopnopq")); - assertEquals(DigestUtils.sha1Hex(testData), - DigestUtils.sha1Hex(new ByteArrayInputStream(testData))); + assertEquals("84983e441c3bd26ebaae4aa1f95129e5e54670f1", DigestUtils.sha1Hex("abcdbcdecdefdefgefghfghighij" + "hijkijkljklmklmnlmnomnopnopq")); + assertEquals(DigestUtils.sha1Hex(testData), DigestUtils.sha1Hex(new ByteArrayInputStream(testData))); } @Test - public void testSha1UpdateWithByteArray(){ + public void testSha1UpdateWithByteArray() { final String d1 = "C'est un homme qui rentre dans un café, et plouf"; final String d2 = "C'est un homme, c'est qu'une tête, on lui offre un cadeau: 'oh... encore un chapeau!'"; @@ -280,7 +269,7 @@ public void testSha1UpdateWithByteArray(){ } @Test - public void testSha1UpdateWithByteBuffer(){ + public void testSha1UpdateWithByteBuffer() { final String d1 = "C'est un homme qui rentre dans un café, et plouf"; final String d2 = "C'est un homme, c'est qu'une tête, on lui offre un cadeau: 'oh... encore un chapeau!'"; @@ -298,7 +287,7 @@ public void testSha1UpdateWithByteBuffer(){ } @Test - public void testSha1UpdateWithString(){ + public void testSha1UpdateWithString() { final String d1 = "C'est un homme qui rentre dans un café, et plouf"; final String d2 = "C'est un homme, c'est qu'une tête, on lui offre un cadeau: 'oh... encore un chapeau!'"; @@ -341,8 +330,7 @@ public void testSha224_PathAsHex() throws IOException { @Test public void testSha224_StringAsHex() { assumeJava8(); - assertEquals("d14a028c2a3a2bc9476102bb288234c415a2b01f828ea62ac5b3e42f", - new DigestUtils(MessageDigestAlgorithms.SHA_224).digestAsHex(EMPTY_STRING)); + assertEquals("d14a028c2a3a2bc9476102bb288234c415a2b01f828ea62ac5b3e42f", new DigestUtils(MessageDigestAlgorithms.SHA_224).digestAsHex(EMPTY_STRING)); assertEquals("730e109bd7a8a32b1cb9d9a09aa2325d2430587ddbc0c38bad911525", new DigestUtils(MessageDigestAlgorithms.SHA_224).digestAsHex("The quick brown fox jumps over the lazy dog")); @@ -351,22 +339,18 @@ public void testSha224_StringAsHex() { @Test public void testSha256() throws IOException { - // Examples from FIPS 180-2 - assertEquals("ba7816bf8f01cfea414140de5dae2223b00361a396177a9cb410ff61f20015ad", - DigestUtils.sha256Hex("abc")); - assertEquals("ba7816bf8f01cfea414140de5dae2223b00361a396177a9cb410ff61f20015ad", - DigestUtils.sha256Hex(getBytesUtf8("abc"))); - assertEquals("248d6a61d20638b8e5c026930c3e6039a33ce45964ff2167f6ecedd419db06c1", - DigestUtils.sha256Hex("abcdbcdecdefdefgefghfghighijhijkijkljklmklmnlmnomnopnopq")); + // Examples from FIPS 180-2 + assertEquals("ba7816bf8f01cfea414140de5dae2223b00361a396177a9cb410ff61f20015ad", DigestUtils.sha256Hex("abc")); + assertEquals("ba7816bf8f01cfea414140de5dae2223b00361a396177a9cb410ff61f20015ad", DigestUtils.sha256Hex(getBytesUtf8("abc"))); + assertEquals("248d6a61d20638b8e5c026930c3e6039a33ce45964ff2167f6ecedd419db06c1", + DigestUtils.sha256Hex("abcdbcdecdefdefgefghfghighijhijkijkljklmklmnlmnomnopnopq")); - assertEquals(DigestUtils.sha256Hex(testData), - DigestUtils.sha256Hex(new ByteArrayInputStream(testData))); + assertEquals(DigestUtils.sha256Hex(testData), DigestUtils.sha256Hex(new ByteArrayInputStream(testData))); } @Test public void testSha256HexInputStream() throws IOException { - assertEquals(DigestUtils.sha256Hex(testData), - DigestUtils.sha256Hex(new ByteArrayInputStream(testData))); + assertEquals(DigestUtils.sha256Hex(testData), DigestUtils.sha256Hex(new ByteArrayInputStream(testData))); } @Test @@ -375,16 +359,13 @@ public void testSha3_224() { // Examples from https://csrc.nist.gov/projects/cryptographic-standards-and-guidelines/example-values // // https://csrc.nist.gov/CSRC/media/Projects/Cryptographic-Standards-and-Guidelines/documents/examples/SHA3-224_Msg0.pdf - assertEquals( - "6b4e03423667dbb73b6e15454f0eb1abd4597f9a1b078e3f5b5a6bc7", - DigestUtils.sha3_224Hex(EMPTY_STRING)); + assertEquals("6b4e03423667dbb73b6e15454f0eb1abd4597f9a1b078e3f5b5a6bc7", DigestUtils.sha3_224Hex(EMPTY_STRING)); } @Test public void testSha3_224HexInputStream() throws IOException { assumeJava9(); - assertEquals(DigestUtils.sha3_224Hex(testData), - DigestUtils.sha3_224Hex(new ByteArrayInputStream(testData))); + assertEquals(DigestUtils.sha3_224Hex(testData), DigestUtils.sha3_224Hex(new ByteArrayInputStream(testData))); } @Test @@ -393,16 +374,13 @@ public void testSha3_256() { // Examples from https://csrc.nist.gov/projects/cryptographic-standards-and-guidelines/example-values // // https://csrc.nist.gov/CSRC/media/Projects/Cryptographic-Standards-and-Guidelines/documents/examples/SHA3-256_Msg0.pdf - assertEquals( - "a7ffc6f8bf1ed76651c14756a061d662f580ff4de43b49fa82d80a4b80f8434a", - DigestUtils.sha3_256Hex(EMPTY_STRING)); + assertEquals("a7ffc6f8bf1ed76651c14756a061d662f580ff4de43b49fa82d80a4b80f8434a", DigestUtils.sha3_256Hex(EMPTY_STRING)); } @Test public void testSha3_256HexInputStream() throws IOException { assumeJava9(); - assertEquals(DigestUtils.sha3_256Hex(testData), - DigestUtils.sha3_256Hex(new ByteArrayInputStream(testData))); + assertEquals(DigestUtils.sha3_256Hex(testData), DigestUtils.sha3_256Hex(new ByteArrayInputStream(testData))); } @Test @@ -411,16 +389,13 @@ public void testSha3_384() { // Examples from https://csrc.nist.gov/projects/cryptographic-standards-and-guidelines/example-values // // https://csrc.nist.gov/CSRC/media/Projects/Cryptographic-Standards-and-Guidelines/documents/examples/SHA3-384_Msg0.pdf - assertEquals( - "0c63a75b845e4f7d01107d852e4c2485c51a50aaaa94fc61995e71bbee983a2ac3713831264adb47fb6bd1e058d5f004", - DigestUtils.sha3_384Hex(EMPTY_STRING)); + assertEquals("0c63a75b845e4f7d01107d852e4c2485c51a50aaaa94fc61995e71bbee983a2ac3713831264adb47fb6bd1e058d5f004", DigestUtils.sha3_384Hex(EMPTY_STRING)); } @Test public void testSha3_384HexInputStream() throws IOException { assumeJava9(); - assertEquals(DigestUtils.sha3_384Hex(testData), - DigestUtils.sha3_384Hex(new ByteArrayInputStream(testData))); + assertEquals(DigestUtils.sha3_384Hex(testData), DigestUtils.sha3_384Hex(new ByteArrayInputStream(testData))); } @Test @@ -429,54 +404,41 @@ public void testSha3_512() { // Examples from https://csrc.nist.gov/projects/cryptographic-standards-and-guidelines/example-values // // https://csrc.nist.gov/CSRC/media/Projects/Cryptographic-Standards-and-Guidelines/documents/examples/SHA3-512_Msg0.pdf - assertEquals( - "a69f73cca23a9ac5c8b567dc185a756e97c982164fe25859e0d1dcc1475c80a615b2123af1f5f94c11e3e9402c3ac558f500199d95b6d3e301758586281dcd26", + assertEquals("a69f73cca23a9ac5c8b567dc185a756e97c982164fe25859e0d1dcc1475c80a615b2123af1f5f94c11e3e9402c3ac558f500199d95b6d3e301758586281dcd26", DigestUtils.sha3_512Hex(EMPTY_STRING)); } @Test public void testSha3_512HexInputStream() throws IOException { assumeJava9(); - assertEquals(DigestUtils.sha3_512Hex(testData), - DigestUtils.sha3_512Hex(new ByteArrayInputStream(testData))); + assertEquals(DigestUtils.sha3_512Hex(testData), DigestUtils.sha3_512Hex(new ByteArrayInputStream(testData))); } @Test public void testSha384() throws IOException { - // Examples from FIPS 180-2 - assertEquals("cb00753f45a35e8bb5a03d699ac65007272c32ab0eded1631a8b605a43ff5bed" + - "8086072ba1e7cc2358baeca134c825a7", - DigestUtils.sha384Hex("abc")); - assertEquals("cb00753f45a35e8bb5a03d699ac65007272c32ab0eded1631a8b605a43ff5bed" + - "8086072ba1e7cc2358baeca134c825a7", - DigestUtils.sha384Hex(getBytesUtf8("abc"))); - assertEquals("09330c33f71147e83d192fc782cd1b4753111b173b3b05d22fa08086e3b0f712" + - "fcc7c71a557e2db966c3e9fa91746039", - DigestUtils.sha384Hex("abcdefghbcdefghicdefghijdefghijkefghijklfghijklmghijklmn" + - "hijklmnoijklmnopjklmnopqklmnopqrlmnopqrsmnopqrstnopqrstu")); - assertEquals(DigestUtils.sha384Hex(testData), - DigestUtils.sha384Hex(new ByteArrayInputStream(testData))); + // Examples from FIPS 180-2 + assertEquals("cb00753f45a35e8bb5a03d699ac65007272c32ab0eded1631a8b605a43ff5bed" + "8086072ba1e7cc2358baeca134c825a7", DigestUtils.sha384Hex("abc")); + assertEquals("cb00753f45a35e8bb5a03d699ac65007272c32ab0eded1631a8b605a43ff5bed" + "8086072ba1e7cc2358baeca134c825a7", + DigestUtils.sha384Hex(getBytesUtf8("abc"))); + assertEquals("09330c33f71147e83d192fc782cd1b4753111b173b3b05d22fa08086e3b0f712" + "fcc7c71a557e2db966c3e9fa91746039", + DigestUtils.sha384Hex("abcdefghbcdefghicdefghijdefghijkefghijklfghijklmghijklmn" + "hijklmnoijklmnopjklmnopqklmnopqrlmnopqrsmnopqrstnopqrstu")); + assertEquals(DigestUtils.sha384Hex(testData), DigestUtils.sha384Hex(new ByteArrayInputStream(testData))); } @Test public void testSha384HexInputStream() throws IOException { - assertEquals(DigestUtils.sha384Hex(testData), - DigestUtils.sha384Hex(new ByteArrayInputStream(testData))); + assertEquals(DigestUtils.sha384Hex(testData), DigestUtils.sha384Hex(new ByteArrayInputStream(testData))); } @Test public void testSha512() { - // Examples from FIPS 180-2 - assertEquals("ddaf35a193617abacc417349ae20413112e6fa4e89a97ea20a9eeee64b55d39a" + - "2192992a274fc1a836ba3c23a3feebbd454d4423643ce80e2a9ac94fa54ca49f", - DigestUtils.sha512Hex("abc")); - assertEquals("ddaf35a193617abacc417349ae20413112e6fa4e89a97ea20a9eeee64b55d39a" + - "2192992a274fc1a836ba3c23a3feebbd454d4423643ce80e2a9ac94fa54ca49f", - DigestUtils.sha512Hex(getBytesUtf8("abc"))); - assertEquals("8e959b75dae313da8cf4f72814fc143f8f7779c6eb9f7fa17299aeadb6889018" + - "501d289e4900f7e4331b99dec4b5433ac7d329eeb6dd26545e96e55b874be909", - DigestUtils.sha512Hex("abcdefghbcdefghicdefghijdefghijkefghijklfghijklmghijklmn" + - "hijklmnoijklmnopjklmnopqklmnopqrlmnopqrsmnopqrstnopqrstu")); + // Examples from FIPS 180-2 + assertEquals("ddaf35a193617abacc417349ae20413112e6fa4e89a97ea20a9eeee64b55d39a" + "2192992a274fc1a836ba3c23a3feebbd454d4423643ce80e2a9ac94fa54ca49f", + DigestUtils.sha512Hex("abc")); + assertEquals("ddaf35a193617abacc417349ae20413112e6fa4e89a97ea20a9eeee64b55d39a" + "2192992a274fc1a836ba3c23a3feebbd454d4423643ce80e2a9ac94fa54ca49f", + DigestUtils.sha512Hex(getBytesUtf8("abc"))); + assertEquals("8e959b75dae313da8cf4f72814fc143f8f7779c6eb9f7fa17299aeadb6889018" + "501d289e4900f7e4331b99dec4b5433ac7d329eeb6dd26545e96e55b874be909", + DigestUtils.sha512Hex("abcdefghbcdefghicdefghijdefghijkefghijklfghijklmghijklmn" + "hijklmnoijklmnopjklmnopqklmnopqrlmnopqrsmnopqrstnopqrstu")); } @Test @@ -498,8 +460,7 @@ public void testSha512_224() throws Exception { assertEquals(resultString, DigestUtils.sha512_224Hex(stringInput)); // Example 2 assertEquals("23FEC5BB94D60B23308192640B0C453335D664734FE40E7268674AF9".toLowerCase(Locale.ROOT), - DigestUtils.sha512_224Hex( - "abcdefghbcdefghicdefghijdefghijkefghijklfghijklmghijklmnhijklmnoijklmnopjklmnopqklmnopqrlmnopqrsmnopqrstnopqrstu")); + DigestUtils.sha512_224Hex("abcdefghbcdefghicdefghijdefghijkefghijklfghijklmghijklmnhijklmnoijklmnopjklmnopqklmnopqrlmnopqrsmnopqrstnopqrstu")); } @Test @@ -509,8 +470,7 @@ public void testSha512_256() throws Exception { // https://csrc.nist.gov/CSRC/media/Projects/Cryptographic-Standards-and-Guidelines/documents/examples/SHA512_256.pdf final String stringInput = "abc"; final byte[] bytesInput = getBytesUtf8(stringInput); - final String resultString = "53048E2681941EF99B2E29B76B4C7DABE4C2D0C634FC6D46E0E2F13107E7AF23" - .toLowerCase(Locale.ROOT); + final String resultString = "53048E2681941EF99B2E29B76B4C7DABE4C2D0C634FC6D46E0E2F13107E7AF23".toLowerCase(Locale.ROOT); final byte[] resultBytes = Hex.decodeHex(resultString); // assertArrayEquals(resultBytes, DigestUtils.sha512_256(bytesInput)); @@ -522,14 +482,12 @@ public void testSha512_256() throws Exception { assertEquals(resultString, DigestUtils.sha512_256Hex(stringInput)); // Example 2 assertEquals("3928E184FB8690F840DA3988121D31BE65CB9D3EF83EE6146FEAC861E19B563A".toLowerCase(Locale.ROOT), - DigestUtils.sha512_256Hex( - "abcdefghbcdefghicdefghijdefghijkefghijklfghijklmghijklmnhijklmnoijklmnopjklmnopqklmnopqrlmnopqrsmnopqrstnopqrstu")); + DigestUtils.sha512_256Hex("abcdefghbcdefghicdefghijdefghijkefghijklfghijklmghijklmnhijklmnoijklmnopjklmnopqklmnopqrlmnopqrsmnopqrstnopqrstu")); } @Test public void testSha512HexInputStream() throws IOException { - assertEquals(DigestUtils.sha512Hex(testData), - DigestUtils.sha512Hex(new ByteArrayInputStream(testData))); + assertEquals(DigestUtils.sha512Hex(testData), DigestUtils.sha512Hex(new ByteArrayInputStream(testData))); } @SuppressWarnings("deprecation") // deliberate tests of deprecated code @@ -540,16 +498,13 @@ public void testShaHex() throws IOException { assertEquals("a9993e364706816aba3e25717850c26c9cd0d89d", DigestUtils.shaHex(getBytesUtf8("abc"))); - assertEquals( - "84983e441c3bd26ebaae4aa1f95129e5e54670f1", - DigestUtils.shaHex("abcdbcdecdefdefgefghfghighij" + "hijkijkljklmklmnlmnomnopnopq")); - assertEquals(DigestUtils.shaHex(testData), - DigestUtils.shaHex(new ByteArrayInputStream(testData))); + assertEquals("84983e441c3bd26ebaae4aa1f95129e5e54670f1", DigestUtils.shaHex("abcdbcdecdefdefgefghfghighij" + "hijkijkljklmklmnlmnomnopnopq")); + assertEquals(DigestUtils.shaHex(testData), DigestUtils.shaHex(new ByteArrayInputStream(testData))); } @SuppressWarnings("deprecation") // deliberate tests of deprecated code @Test - public void testShaUpdateWithByteArray(){ + public void testShaUpdateWithByteArray() { final String d1 = "C'est un homme qui rentre dans un café, et plouf"; final String d2 = "C'est un homme, c'est qu'une tête, on lui offre un cadeau: 'oh... encore un chapeau!'"; @@ -568,7 +523,7 @@ public void testShaUpdateWithByteArray(){ @SuppressWarnings("deprecation") // deliberate tests of deprecated code @Test - public void testShaUpdateWithString(){ + public void testShaUpdateWithString() { final String d1 = "C'est un homme qui rentre dans un café, et plouf"; final String d2 = "C'est un homme, c'est qu'une tête, on lui offre un cadeau: 'oh... encore un chapeau!'"; diff --git a/src/test/java/org/apache/commons/codec/digest/HmacUtilsTest.java b/src/test/java/org/apache/commons/codec/digest/HmacUtilsTest.java index b0e4ad1c9e..70d926427a 100644 --- a/src/test/java/org/apache/commons/codec/digest/HmacUtilsTest.java +++ b/src/test/java/org/apache/commons/codec/digest/HmacUtilsTest.java @@ -31,7 +31,7 @@ import org.junit.jupiter.api.Test; /** - * Tests HmacUtils methods. + * Tests {@link HmacUtils}. */ public class HmacUtilsTest { diff --git a/src/test/java/org/apache/commons/codec/digest/PureJavaCrc32CTest.java b/src/test/java/org/apache/commons/codec/digest/PureJavaCrc32CTest.java index a250e1798c..ee6f2c0434 100644 --- a/src/test/java/org/apache/commons/codec/digest/PureJavaCrc32CTest.java +++ b/src/test/java/org/apache/commons/codec/digest/PureJavaCrc32CTest.java @@ -23,7 +23,7 @@ import org.junit.jupiter.api.Test; /** - * Test class for PureJavaCrc32C. Test data was derived from https://tools.ietf.org/html/rfc3720#appendix-B.4 + * Tests {@link PureJavaCrc32C}. Test data was derived from https://tools.ietf.org/html/rfc3720#appendix-B.4 */ public class PureJavaCrc32CTest { diff --git a/src/test/java/org/apache/commons/codec/language/DoubleMetaphoneTest.java b/src/test/java/org/apache/commons/codec/language/DoubleMetaphoneTest.java index ab75fd04e6..0efcfb85b8 100644 --- a/src/test/java/org/apache/commons/codec/language/DoubleMetaphoneTest.java +++ b/src/test/java/org/apache/commons/codec/language/DoubleMetaphoneTest.java @@ -1061,14 +1061,19 @@ public void testCCedilla() { } @Test - public void testCodec184() throws Throwable { + public void testCodec184() { assertTrue(new DoubleMetaphone().isDoubleMetaphoneEqual("", "", false)); assertTrue(new DoubleMetaphone().isDoubleMetaphoneEqual("", "", true)); assertFalse(new DoubleMetaphone().isDoubleMetaphoneEqual("aa", "", false)); assertFalse(new DoubleMetaphone().isDoubleMetaphoneEqual("aa", "", true)); assertFalse(new DoubleMetaphone().isDoubleMetaphoneEqual("", "aa", false)); assertFalse(new DoubleMetaphone().isDoubleMetaphoneEqual("", "aa", true)); - } + } + + @Test + public void testCodec320() { + assertTrue(new DoubleMetaphone().isDoubleMetaphoneEqual("ANGHELINA", "ANKL", false)); + } @Test public void testDoubleMetaphone() { diff --git a/src/test/java/org/apache/commons/codec/language/MatchRatingApproachEncoderTest.java b/src/test/java/org/apache/commons/codec/language/MatchRatingApproachEncoderTest.java index c54a10a56e..cf8c6e2441 100644 --- a/src/test/java/org/apache/commons/codec/language/MatchRatingApproachEncoderTest.java +++ b/src/test/java/org/apache/commons/codec/language/MatchRatingApproachEncoderTest.java @@ -47,8 +47,7 @@ public final void testAccentRemoval_AllLower_SuccessfullyRemoved() { @Test public final void testAccentRemoval_ComprehensiveAccentMix_AllSuccessfullyRemoved() { - assertEquals("E,E,E,E,U,U,I,I,A,A,O,e,e,e,e,u,u,i,i,a,a,o,c", - this.getStringEncoder().removeAccents("È,É,Ê,Ë,Û,Ù,Ï,Î,À,Â,Ô,è,é,ê,ë,û,ù,ï,î,à,â,ô,ç")); + assertEquals("E,E,E,E,U,U,I,I,A,A,O,e,e,e,e,u,u,i,i,a,a,o,c", this.getStringEncoder().removeAccents("È,É,Ê,Ë,Û,Ù,Ï,Î,À,Â,Ô,è,é,ê,ë,û,ù,ï,î,à,â,ô,ç")); } @Test @@ -357,12 +356,12 @@ public final void testGetMinRating_1_Returns5_Successfully() { } @Test - public final void testgetMinRating_10_Returns3_Successfully(){ + public final void testgetMinRating_10_Returns3_Successfully() { assertEquals(3, this.getStringEncoder().getMinRating(10)); } @Test - public final void testgetMinRating_11_Returns_3_Successfully(){ + public final void testgetMinRating_11_Returns_3_Successfully() { assertEquals(3, this.getStringEncoder().getMinRating(11)); } @@ -377,17 +376,17 @@ public final void testGetMinRating_2_Returns5_Successfully() { } @Test - public final void testgetMinRating_5_Returns4_Successfully(){ + public final void testgetMinRating_5_Returns4_Successfully() { assertEquals(4, this.getStringEncoder().getMinRating(5)); } @Test - public final void testgetMinRating_5_Returns4_Successfully2(){ + public final void testgetMinRating_5_Returns4_Successfully2() { assertEquals(4, this.getStringEncoder().getMinRating(5)); } @Test - public final void testgetMinRating_6_Returns4_Successfully(){ + public final void testgetMinRating_6_Returns4_Successfully() { assertEquals(4, this.getStringEncoder().getMinRating(6)); } @@ -399,12 +398,12 @@ public final void testGetMinRating_7_Return4_Successfully() { // ***** Begin Region - Test Get Encoding - Surnames @Test - public final void testgetMinRating_7_Returns4_Successfully(){ + public final void testgetMinRating_7_Returns4_Successfully() { assertEquals(4, this.getStringEncoder().getMinRating(7)); } @Test - public final void testgetMinRating_8_Returns3_Successfully(){ + public final void testgetMinRating_8_Returns3_Successfully() { assertEquals(3, this.getStringEncoder().getMinRating(8)); } diff --git a/src/test/java/org/apache/commons/codec/language/bm/PhoneticEngineTest.java b/src/test/java/org/apache/commons/codec/language/bm/PhoneticEngineTest.java index b7f92b1595..7c949f17c1 100644 --- a/src/test/java/org/apache/commons/codec/language/bm/PhoneticEngineTest.java +++ b/src/test/java/org/apache/commons/codec/language/bm/PhoneticEngineTest.java @@ -34,25 +34,31 @@ public class PhoneticEngineTest { private static final Integer TEN = Integer.valueOf(10); public static Stream data() { + // @formatter:off return Stream.of( - Arguments.of("Renault", "rinD|rinDlt|rina|rinalt|rino|rinolt|rinu|rinult", NameType.GENERIC, RuleType.APPROX, Boolean.TRUE, TEN), - Arguments.of("Renault", "rYnDlt|rYnalt|rYnult|rinDlt|rinalt|rinolt|rinult", NameType.ASHKENAZI, RuleType.APPROX, Boolean.TRUE, TEN), - Arguments.of("Renault", "rinDlt", NameType.ASHKENAZI, RuleType.APPROX, Boolean.TRUE, Integer.valueOf(1)), - Arguments.of("Renault", "rinDlt", NameType.SEPHARDIC, RuleType.APPROX, Boolean.TRUE, TEN), - Arguments.of("SntJohn-Smith", "sntjonsmit", NameType.GENERIC, RuleType.EXACT, Boolean.TRUE, TEN), - Arguments.of("d'ortley", "(ortlaj|ortlej)-(dortlaj|dortlej)", NameType.GENERIC, RuleType.EXACT, Boolean.TRUE, TEN), - Arguments.of("van helsing", "(elSink|elsink|helSink|helsink|helzink|xelsink)-(banhelsink|fanhelsink|fanhelzink|vanhelsink|vanhelzink|vanjelsink)", NameType.GENERIC, RuleType.EXACT, Boolean.FALSE, TEN), - Arguments.of("Judenburg", "iudnbYrk|iudnbirk|iudnburk|xudnbirk|xudnburk|zudnbirk|zudnburk", NameType.GENERIC, RuleType.APPROX, Boolean.TRUE, TEN) + Arguments.of("Renault", "rinD|rinDlt|rina|rinalt|rino|rinolt|rinu|rinult", NameType.GENERIC, RuleType.APPROX, Boolean.TRUE, TEN), + Arguments.of("Renault", "rYnDlt|rYnalt|rYnult|rinDlt|rinalt|rinolt|rinult", NameType.ASHKENAZI, RuleType.APPROX, Boolean.TRUE, TEN), + Arguments.of("Renault", "rinDlt", NameType.ASHKENAZI, RuleType.APPROX, Boolean.TRUE, Integer.valueOf(1)), + Arguments.of("Renault", "rinDlt", NameType.SEPHARDIC, RuleType.APPROX, Boolean.TRUE, TEN), + Arguments.of("SntJohn-Smith", "sntjonsmit", NameType.GENERIC, RuleType.EXACT, Boolean.TRUE, TEN), + Arguments.of("d'ortley", "(ortlaj|ortlej)-(dortlaj|dortlej)", NameType.GENERIC, RuleType.EXACT, Boolean.TRUE, TEN), + Arguments.of("van helsing", "(elSink|elsink|helSink|helsink|helzink|xelsink)-(banhelsink|fanhelsink|fanhelzink|vanhelsink|vanhelzink|vanjelsink)", NameType.GENERIC, RuleType.EXACT, Boolean.FALSE, TEN), + Arguments.of("Judenburg", "iudnbYrk|iudnbirk|iudnburk|xudnbirk|xudnburk|zudnbirk|zudnburk", NameType.GENERIC, RuleType.APPROX, Boolean.TRUE, TEN), + Arguments.of("Judenburg", "iudnbYrk|iudnbirk|iudnburk|xudnbirk|xudnburk|zudnbirk|zudnburk", NameType.GENERIC, RuleType.APPROX, Boolean.TRUE, Integer.MAX_VALUE) ); + // @formatter:on } public static Stream invalidData() { + // @formatter:off return Stream.of( - Arguments.of("bar", "bar|bor|var|vor", NameType.ASHKENAZI, RuleType.APPROX, Boolean.FALSE, TEN), - Arguments.of("al", "|al", NameType.SEPHARDIC, RuleType.APPROX, Boolean.FALSE, TEN), - Arguments.of("da", "da|di", NameType.GENERIC, RuleType.EXACT, Boolean.FALSE, TEN), - Arguments.of("'''", "", NameType.SEPHARDIC, RuleType.APPROX, Boolean.FALSE, TEN) + Arguments.of("bar", "bar|bor|var|vor", NameType.ASHKENAZI, RuleType.APPROX, Boolean.FALSE, TEN), + Arguments.of("al", "|al", NameType.SEPHARDIC, RuleType.APPROX, Boolean.FALSE, TEN), + Arguments.of("da", "da|di", NameType.GENERIC, RuleType.EXACT, Boolean.FALSE, TEN), + Arguments.of("'''", "", NameType.SEPHARDIC, RuleType.APPROX, Boolean.FALSE, TEN), + Arguments.of("'''", "", NameType.SEPHARDIC, RuleType.APPROX, Boolean.FALSE, Integer.MAX_VALUE) ); + // @formatter:on } // TODO Identify if there is a need to an assertTimeout(Duration.ofMillis(10000L) in some point, since this method was marked as @Test(timeout = 10000L) diff --git a/src/test/java/org/apache/commons/codec/net/PercentCodecTest.java b/src/test/java/org/apache/commons/codec/net/PercentCodecTest.java index a537efba5f..0424fd86d7 100644 --- a/src/test/java/org/apache/commons/codec/net/PercentCodecTest.java +++ b/src/test/java/org/apache/commons/codec/net/PercentCodecTest.java @@ -74,10 +74,9 @@ public void testDecodeInvalidEncodedResultDecoding() throws Exception { final PercentCodec percentCodec = new PercentCodec(); final byte[] encoded = percentCodec.encode(inputS.getBytes(StandardCharsets.UTF_8)); try { - percentCodec.decode(Arrays.copyOf(encoded, encoded.length-1)); //exclude one byte + percentCodec.decode(Arrays.copyOf(encoded, encoded.length - 1)); // exclude one byte } catch (final Exception e) { - assertTrue(DecoderException.class.isInstance(e) && - ArrayIndexOutOfBoundsException.class.isInstance(e.getCause())); + assertTrue(DecoderException.class.isInstance(e) && ArrayIndexOutOfBoundsException.class.isInstance(e.getCause())); } } diff --git a/src/test/java/org/apache/commons/codec/net/RFC1522CodecTest.java b/src/test/java/org/apache/commons/codec/net/RFC1522CodecTest.java index b115600039..9e566a814d 100644 --- a/src/test/java/org/apache/commons/codec/net/RFC1522CodecTest.java +++ b/src/test/java/org/apache/commons/codec/net/RFC1522CodecTest.java @@ -20,6 +20,8 @@ import static org.junit.jupiter.api.Assertions.assertNull; import static org.junit.jupiter.api.Assertions.assertThrows; +import java.nio.charset.StandardCharsets; + import org.apache.commons.codec.CharEncoding; import org.apache.commons.codec.DecoderException; import org.junit.jupiter.api.Test; @@ -31,6 +33,10 @@ public class RFC1522CodecTest { static class RFC1522TestCodec extends RFC1522Codec { + RFC1522TestCodec() { + super(StandardCharsets.UTF_8); + } + @Override protected byte[] doDecoding(final byte[] bytes) { return bytes; diff --git a/src/test/java/org/apache/commons/codec/net/CustomRFC1522Codec.java b/src/test/java/org/apache/commons/codec/net/RFC1522OverrideTestCodec.java similarity index 89% rename from src/test/java/org/apache/commons/codec/net/CustomRFC1522Codec.java rename to src/test/java/org/apache/commons/codec/net/RFC1522OverrideTestCodec.java index 90b2de31ca..c643d9da8b 100644 --- a/src/test/java/org/apache/commons/codec/net/CustomRFC1522Codec.java +++ b/src/test/java/org/apache/commons/codec/net/RFC1522OverrideTestCodec.java @@ -19,6 +19,7 @@ import java.io.UnsupportedEncodingException; import java.nio.charset.Charset; +import java.nio.charset.StandardCharsets; import org.apache.commons.codec.DecoderException; import org.apache.commons.codec.EncoderException; @@ -26,7 +27,11 @@ /** * Tests overriding the package private RFC1522Codec. */ -public class CustomRFC1522Codec extends RFC1522Codec { +class RFC1522OverrideTestCodec extends RFC1522Codec { + + RFC1522OverrideTestCodec() { + super(StandardCharsets.UTF_8); + } @Override protected String decodeText(final String text) throws DecoderException, UnsupportedEncodingException { @@ -49,7 +54,7 @@ protected String encodeText(final String text, final Charset charset) throws Enc } @Override - protected String encodeText(final String text, final String charsetName) throws EncoderException, UnsupportedEncodingException { + protected String encodeText(final String text, final String charsetName) throws EncoderException { return super.encodeText(text, charsetName); }