This is an automated email from the ASF dual-hosted git repository.

garydgregory pushed a commit to branch master
in repository https://gitbox.apache.org/repos/asf/commons-codec.git

commit 8c0303cece155da873ee15a4133dca00ddd1dd52
Author: Gary Gregory <[email protected]>
AuthorDate: Fri Sep 18 05:48:16 2026 -0700

    Fix Base58 encoded-length calculation and line-length validation
    
    Calculate the exact encoded length within the configured encode limit.
    Reject unsupported positive line lengths with IllegalArgumentException.
    Add regression tests and update documentation.
---
 src/changes/changes.xml                            |  1 +
 .../org/apache/commons/codec/binary/Base58.java    | 38 +++++++++++++++++++++-
 .../apache/commons/codec/binary/Base58Test.java    | 36 ++++++++++++++++++++
 3 files changed, 74 insertions(+), 1 deletion(-)

diff --git a/src/changes/changes.xml b/src/changes/changes.xml
index 8299dffd..25e3558f 100644
--- a/src/changes/changes.xml
+++ b/src/changes/changes.xml
@@ -57,6 +57,7 @@ The <action> type attribute can be add,update,fix,remove.
       <action type="fix" dev="ggregory" due-to="Gary Gregory">Base32 and 
Base64 STRICT decoding now require the encoder's canonical alphabet, padding, 
and line separators, and validate streams through EOF. Use LENIENT to retain 
permissive decoding.</action>
       <action type="fix" dev="ggregory" due-to="Gary Gregory">Limit Base58 
decoding to 8192 encoded bytes by default, checking cumulative stream input 
before buffering. Use Base58.Builder.setMaxDecodeLength(int) for larger trusted 
input. Encoding defaults to a configurable 8192-byte binary input limit through 
Base58.Builder.setMaxEncodeLength(int).</action>
       <action type="fix" dev="ggregory" due-to="Gary Gregory">Grow Base58 
accumulation buffers geometrically within the configured input limits and 
validate actual accumulated length.</action>
+      <action type="fix" dev="ggregory" due-to="Gary Gregory">Implement Base58 
encoded-length calculation and explicitly reject unsupported line 
chunking.</action>
       <!-- ADD -->
       <action type="add" dev="ggregory" due-to="Gary Gregory">Add and use 
PhoneticEngine.Builder and deprecate old constructors.</action>
       <action type="add" dev="ggregory" due-to="Gary Gregory">Add 
BeiderMorseEncoder.Builder and deprecate old constructor.</action>
diff --git a/src/main/java/org/apache/commons/codec/binary/Base58.java 
b/src/main/java/org/apache/commons/codec/binary/Base58.java
index e6b2cb0a..0076517e 100644
--- a/src/main/java/org/apache/commons/codec/binary/Base58.java
+++ b/src/main/java/org/apache/commons/codec/binary/Base58.java
@@ -104,6 +104,25 @@ public class Base58 extends BaseNCodec {
             return super.setEncodeTable(encodeTable);
         }
 
+        /**
+         * Sets the line length to zero.
+         * <p>
+         * Base58 does not support line chunking. Zero or a negative value 
selects unchunked output.
+         * </p>
+         *
+         * @param lineLength The line length; must not be positive.
+         * @return {@code this} instance.
+         * @throws IllegalArgumentException if lineLength is positive.
+         * @since 1.23.0
+         */
+        @Override
+        public Builder setLineLength(final int lineLength) {
+            if (lineLength > 0) {
+                throw new IllegalArgumentException("Base58 does not support 
line chunking.");
+            }
+            return super.setLineLength(lineLength);
+        }
+
         /**
          * Sets the maximum number of encoded bytes accepted by a single 
decode operation.
          * <p>
@@ -207,7 +226,7 @@ public class Base58 extends BaseNCodec {
      *
      * <pre>
      * Base58 base58 = Base58.builder()
-     *   .setEncode(true)
+     *   .setMaxEncodeLength(4096)
      *   .get()
      * </pre>
      *
@@ -458,6 +477,23 @@ public class Base58 extends BaseNCodec {
         code(array, offset, length, context, maxEncodeLength, "encode", 
this::convertToBase58);
     }
 
+    /**
+     * Gets the number of Base58 characters needed to encode the supplied 
array.
+     * <p>
+     * The length depends on the input bytes, including leading zeros. This 
method observes the configured maximum encode length.
+     * </p>
+     *
+     * @param array The binary input to encode.
+     * @return The number of Base58 characters that encoding the array 
produces.
+     * @throws IllegalArgumentException if the input exceeds the configured 
maximum encode length.
+     * @since 1.23.0
+     */
+    @Override
+    public long getEncodedLength(final byte[] array) {
+        checkLength(array.length, 0, maxEncodeLength, "encode");
+        return getStringBuilder(array).length();
+    }
+
     /**
      * Builds the Base58 string representation of the given binary data.
      * <p>
diff --git a/src/test/java/org/apache/commons/codec/binary/Base58Test.java 
b/src/test/java/org/apache/commons/codec/binary/Base58Test.java
index 5d7b3f6c..5ae27d94 100644
--- a/src/test/java/org/apache/commons/codec/binary/Base58Test.java
+++ b/src/test/java/org/apache/commons/codec/binary/Base58Test.java
@@ -204,6 +204,31 @@ public class Base58Test {
         }
     }
 
+    @Test
+    void testEncodedLength() {
+        final Base58 codec = new Base58();
+        assertEquals(0, codec.getEncodedLength(new byte[0]));
+        assertEquals(1, codec.getEncodedLength(new byte[] { 0 }));
+        assertEquals(3, codec.getEncodedLength(new byte[] { 0, 0, 0 }));
+        assertEquals(1, codec.getEncodedLength(new byte[] { 57 }));
+        assertEquals(2, codec.getEncodedLength(new byte[] { 58 }));
+        assertEquals(3, codec.getEncodedLength(new byte[] { 0, 58 }));
+        final Random random = new Random(58);
+        for (int length = 1; length <= 256; length++) {
+            final byte[] input = new byte[length];
+            random.nextBytes(input);
+            assertEquals(codec.encode(input).length, 
codec.getEncodedLength(input));
+        }
+    }
+
+    @Test
+    void testEncodedLengthLimit() {
+        final Base58 codec = Base58.builder().setMaxEncodeLength(10).get();
+        assertEquals(10, codec.getEncodedLength(new byte[10]));
+        assertThrows(IllegalArgumentException.class, () -> 
codec.getEncodedLength(new byte[11]));
+        assertEquals(11, 
Base58.builder().setMaxEncodeLength(11).get().getEncodedLength(new byte[11]));
+    }
+
     @Test
     void testHexEncoding() {
         final String hexString = "48656c6c6f20576f726c6421";
@@ -330,6 +355,17 @@ public class Base58Test {
         assertArrayEquals(input, decoded, "Decoded should match original 
including leading zeros");
     }
 
+    @Test
+    void testLineLength() {
+        assertThrows(IllegalArgumentException.class, () -> 
Base58.builder().setLineLength(76));
+        assertThrows(IllegalArgumentException.class, () -> 
Base58.builder().setLineSeparator(new byte[0]).setLineLength(1));
+        for (final int length : new int[] { 0, -1 }) {
+            final Base58 codec = Base58.builder().setLineLength(length).get();
+            assertArrayEquals(new byte[] { '2', '1' }, codec.encode(new byte[] 
{ 58 }));
+            assertEquals(2, codec.getEncodedLength(new byte[] { 58 }));
+        }
+    }
+
     @Test
     void testObjectDecodeWithInvalidParameter() {
         assertThrows(DecoderException.class, () -> new 
Base58().decode(Integer.valueOf(5)));

Reply via email to