You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@commons.apache.org by gg...@apache.org on 2014/02/24 20:38:15 UTC

svn commit: r1571406 - in /commons/proper/codec/trunk/src: changes/ main/java/org/apache/commons/codec/binary/ test/java/org/apache/commons/codec/binary/

Author: ggregory
Date: Mon Feb 24 19:38:15 2014
New Revision: 1571406

URL: http://svn.apache.org/r1571406
Log:
<action dev="ggregory" type="add" issue="CODEC-181" due-to="Ivan Martinez-Ortiz">Make possible to provide padding byte to BaseNCodec in constructor</action>

Modified:
    commons/proper/codec/trunk/src/changes/changes.xml
    commons/proper/codec/trunk/src/main/java/org/apache/commons/codec/binary/Base32.java
    commons/proper/codec/trunk/src/main/java/org/apache/commons/codec/binary/Base64.java
    commons/proper/codec/trunk/src/main/java/org/apache/commons/codec/binary/BaseNCodec.java
    commons/proper/codec/trunk/src/test/java/org/apache/commons/codec/binary/Base32Test.java
    commons/proper/codec/trunk/src/test/java/org/apache/commons/codec/binary/BaseNCodecTest.java

Modified: commons/proper/codec/trunk/src/changes/changes.xml
URL: http://svn.apache.org/viewvc/commons/proper/codec/trunk/src/changes/changes.xml?rev=1571406&r1=1571405&r2=1571406&view=diff
==============================================================================
--- commons/proper/codec/trunk/src/changes/changes.xml (original)
+++ commons/proper/codec/trunk/src/changes/changes.xml Mon Feb 24 19:38:15 2014
@@ -43,6 +43,7 @@ The <action> type attribute can be add,u
   </properties>
   <body>
     <release version="1.10" date="DD Mmmm 2014" description="Feature and fix release."> 
+      <action dev="ggregory" type="add" issue="CODEC-181" due-to="Ivan Martinez-Ortiz">Make possible to provide padding byte to BaseNCodec in constructor</action>   
       <action dev="ggregory" type="fix" issue="CODEC-180" due-to="Ville Skyttä">Fix Javadoc 1.8.0 errors</action>   
       <action dev="ggregory" type="update" issue="CODEC-178">Deprecate Charsets Charset constants in favor of Java 7's java.nio.charset.StandardCharsets</action>   
     </release>

Modified: commons/proper/codec/trunk/src/main/java/org/apache/commons/codec/binary/Base32.java
URL: http://svn.apache.org/viewvc/commons/proper/codec/trunk/src/main/java/org/apache/commons/codec/binary/Base32.java?rev=1571406&r1=1571405&r2=1571406&view=diff
==============================================================================
--- commons/proper/codec/trunk/src/main/java/org/apache/commons/codec/binary/Base32.java (original)
+++ commons/proper/codec/trunk/src/main/java/org/apache/commons/codec/binary/Base32.java Mon Feb 24 19:38:15 2014
@@ -164,10 +164,33 @@ public class Base32 extends BaseNCodec {
      * <p>
      * When encoding the line length is 0 (no chunking).
      * </p>
+     * @param pad byte used as padding byte.
+     */
+    public Base32(final byte pad) {
+        this(false, pad);
+    }
+
+    /**
+     * Creates a Base32 codec used for decoding and encoding.
+     * <p>
+     * When encoding the line length is 0 (no chunking).
+     * </p>
      * @param useHex if {@code true} then use Base32 Hex alphabet
      */
     public Base32(final boolean useHex) {
-        this(0, null, useHex);
+        this(0, null, useHex, PAD_DEFAULT);
+    }
+
+    /**
+     * Creates a Base32 codec used for decoding and encoding.
+     * <p>
+     * When encoding the line length is 0 (no chunking).
+     * </p>
+     * @param useHex if {@code true} then use Base32 Hex alphabet
+     * @param pad byte used as padding byte.
+     */
+    public Base32(final boolean useHex, final byte pad) {
+        this(0, null, useHex, pad);
     }
 
     /**
@@ -204,7 +227,7 @@ public class Base32 extends BaseNCodec {
      *             The provided lineSeparator included some Base32 characters. That's not going to work!
      */
     public Base32(final int lineLength, final byte[] lineSeparator) {
-        this(lineLength, lineSeparator, false);
+        this(lineLength, lineSeparator, false, PAD_DEFAULT);
     }
 
     /**
@@ -229,10 +252,35 @@ public class Base32 extends BaseNCodec {
      *             lineLength &gt; 0 and lineSeparator is null.
      */
     public Base32(final int lineLength, final byte[] lineSeparator, final boolean useHex) {
-        super(BYTES_PER_UNENCODED_BLOCK, BYTES_PER_ENCODED_BLOCK,
-                lineLength,
-                lineSeparator == null ? 0 : lineSeparator.length);
-        if (useHex){
+        this(lineLength, lineSeparator, useHex, PAD_DEFAULT);
+    }
+
+    /**
+     * Creates a Base32 / Base32 Hex codec used for decoding and encoding.
+     * <p>
+     * When encoding the line length and line separator are given in the constructor.
+     * </p>
+     * <p>
+     * Line lengths that aren't multiples of 8 will still essentially end up being multiples of 8 in the encoded data.
+     * </p>
+     *
+     * @param lineLength
+     *            Each line of encoded data will be at most of the given length (rounded down to nearest multiple of
+     *            8). If lineLength &lt;= 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 useHex
+     *            if {@code true}, then use Base32 Hex alphabet, otherwise use Base32 alphabet
+     * @param pad byte used as padding byte.
+     * @throws IllegalArgumentException
+     *             The provided lineSeparator included some Base32 characters. That's not going to work! Or the
+     *             lineLength &gt; 0 and lineSeparator is null.
+     */
+    public Base32(final int lineLength, final byte[] lineSeparator, final boolean useHex, final byte pad) {
+        super(BYTES_PER_UNENCODED_BLOCK, BYTES_PER_ENCODED_BLOCK, lineLength,
+                lineSeparator == null ? 0 : lineSeparator.length, pad);
+        if (useHex) {
             this.encodeTable = HEX_ENCODE_TABLE;
             this.decodeTable = HEX_DECODE_TABLE;
         } else {
@@ -241,7 +289,7 @@ public class Base32 extends BaseNCodec {
         }
         if (lineLength > 0) {
             if (lineSeparator == null) {
-                throw new IllegalArgumentException("lineLength "+lineLength+" > 0, but lineSeparator is null");
+                throw new IllegalArgumentException("lineLength " + lineLength + " > 0, but lineSeparator is null");
             }
             // Must be done after initializing the tables
             if (containsAlphabetOrPad(lineSeparator)) {
@@ -256,6 +304,10 @@ public class Base32 extends BaseNCodec {
             this.lineSeparator = null;
         }
         this.decodeSize = this.encodeSize - 1;
+
+        if (isInAlphabet(pad) || isWhiteSpace(pad)) {
+            throw new IllegalArgumentException("pad must not be in alphabet or whitespace");
+        }
     }
 
     /**
@@ -292,7 +344,7 @@ public class Base32 extends BaseNCodec {
         }
         for (int i = 0; i < inAvail; i++) {
             final byte b = in[inPos++];
-            if (b == PAD) {
+            if (b == pad) {
                 // We're done.
                 context.eof = true;
                 break;
@@ -398,22 +450,22 @@ public class Base32 extends BaseNCodec {
                 case 1 : // Only 1 octet; take top 5 bits then remainder
                     buffer[context.pos++] = encodeTable[(int)(context.lbitWorkArea >> 3) & MASK_5BITS]; // 8-1*5 = 3
                     buffer[context.pos++] = encodeTable[(int)(context.lbitWorkArea << 2) & MASK_5BITS]; // 5-3=2
-                    buffer[context.pos++] = PAD;
-                    buffer[context.pos++] = PAD;
-                    buffer[context.pos++] = PAD;
-                    buffer[context.pos++] = PAD;
-                    buffer[context.pos++] = PAD;
-                    buffer[context.pos++] = PAD;
+                    buffer[context.pos++] = pad;
+                    buffer[context.pos++] = pad;
+                    buffer[context.pos++] = pad;
+                    buffer[context.pos++] = pad;
+                    buffer[context.pos++] = pad;
+                    buffer[context.pos++] = pad;
                     break;
                 case 2 : // 2 octets = 16 bits to use
                     buffer[context.pos++] = encodeTable[(int)(context.lbitWorkArea >> 11) & MASK_5BITS]; // 16-1*5 = 11
                     buffer[context.pos++] = encodeTable[(int)(context.lbitWorkArea >>  6) & MASK_5BITS]; // 16-2*5 = 6
                     buffer[context.pos++] = encodeTable[(int)(context.lbitWorkArea >>  1) & MASK_5BITS]; // 16-3*5 = 1
                     buffer[context.pos++] = encodeTable[(int)(context.lbitWorkArea <<  4) & MASK_5BITS]; // 5-1 = 4
-                    buffer[context.pos++] = PAD;
-                    buffer[context.pos++] = PAD;
-                    buffer[context.pos++] = PAD;
-                    buffer[context.pos++] = PAD;
+                    buffer[context.pos++] = pad;
+                    buffer[context.pos++] = pad;
+                    buffer[context.pos++] = pad;
+                    buffer[context.pos++] = pad;
                     break;
                 case 3 : // 3 octets = 24 bits to use
                     buffer[context.pos++] = encodeTable[(int)(context.lbitWorkArea >> 19) & MASK_5BITS]; // 24-1*5 = 19
@@ -421,9 +473,9 @@ public class Base32 extends BaseNCodec {
                     buffer[context.pos++] = encodeTable[(int)(context.lbitWorkArea >>  9) & MASK_5BITS]; // 24-3*5 = 9
                     buffer[context.pos++] = encodeTable[(int)(context.lbitWorkArea >>  4) & MASK_5BITS]; // 24-4*5 = 4
                     buffer[context.pos++] = encodeTable[(int)(context.lbitWorkArea <<  1) & MASK_5BITS]; // 5-4 = 1
-                    buffer[context.pos++] = PAD;
-                    buffer[context.pos++] = PAD;
-                    buffer[context.pos++] = PAD;
+                    buffer[context.pos++] = pad;
+                    buffer[context.pos++] = pad;
+                    buffer[context.pos++] = pad;
                     break;
                 case 4 : // 4 octets = 32 bits to use
                     buffer[context.pos++] = encodeTable[(int)(context.lbitWorkArea >> 27) & MASK_5BITS]; // 32-1*5 = 27
@@ -433,7 +485,7 @@ public class Base32 extends BaseNCodec {
                     buffer[context.pos++] = encodeTable[(int)(context.lbitWorkArea >>  7) & MASK_5BITS]; // 32-5*5 =  7
                     buffer[context.pos++] = encodeTable[(int)(context.lbitWorkArea >>  2) & MASK_5BITS]; // 32-6*5 =  2
                     buffer[context.pos++] = encodeTable[(int)(context.lbitWorkArea <<  3) & MASK_5BITS]; // 5-2 = 3
-                    buffer[context.pos++] = PAD;
+                    buffer[context.pos++] = pad;
                     break;
                 default:
                     throw new IllegalStateException("Impossible modulus "+context.modulus);

Modified: commons/proper/codec/trunk/src/main/java/org/apache/commons/codec/binary/Base64.java
URL: http://svn.apache.org/viewvc/commons/proper/codec/trunk/src/main/java/org/apache/commons/codec/binary/Base64.java?rev=1571406&r1=1571405&r2=1571406&view=diff
==============================================================================
--- commons/proper/codec/trunk/src/main/java/org/apache/commons/codec/binary/Base64.java (original)
+++ commons/proper/codec/trunk/src/main/java/org/apache/commons/codec/binary/Base64.java Mon Feb 24 19:38:15 2014
@@ -348,8 +348,8 @@ public class Base64 extends BaseNCodec {
                     buffer[context.pos++] = encodeTable[(context.ibitWorkArea << 4) & MASK_6BITS];
                     // URL-SAFE skips the padding to further reduce size.
                     if (encodeTable == STANDARD_ENCODE_TABLE) {
-                        buffer[context.pos++] = PAD;
-                        buffer[context.pos++] = PAD;
+                        buffer[context.pos++] = pad;
+                        buffer[context.pos++] = pad;
                     }
                     break;
 
@@ -359,7 +359,7 @@ public class Base64 extends BaseNCodec {
                     buffer[context.pos++] = encodeTable[(context.ibitWorkArea << 2) & MASK_6BITS];
                     // URL-SAFE skips the padding to further reduce size.
                     if (encodeTable == STANDARD_ENCODE_TABLE) {
-                        buffer[context.pos++] = PAD;
+                        buffer[context.pos++] = pad;
                     }
                     break;
                 default:
@@ -432,7 +432,7 @@ public class Base64 extends BaseNCodec {
         for (int i = 0; i < inAvail; i++) {
             final byte[] buffer = ensureBufferSize(decodeSize, context);
             final byte b = in[inPos++];
-            if (b == PAD) {
+            if (b == pad) {
                 // We're done.
                 context.eof = true;
                 break;

Modified: commons/proper/codec/trunk/src/main/java/org/apache/commons/codec/binary/BaseNCodec.java
URL: http://svn.apache.org/viewvc/commons/proper/codec/trunk/src/main/java/org/apache/commons/codec/binary/BaseNCodec.java?rev=1571406&r1=1571405&r2=1571406&view=diff
==============================================================================
--- commons/proper/codec/trunk/src/main/java/org/apache/commons/codec/binary/BaseNCodec.java (original)
+++ commons/proper/codec/trunk/src/main/java/org/apache/commons/codec/binary/BaseNCodec.java Mon Feb 24 19:38:15 2014
@@ -153,8 +153,14 @@ public abstract class BaseNCodec impleme
      */
     protected static final byte PAD_DEFAULT = '='; // Allow static access to default
 
+    /**
+     * @deprecated Use {@link #pad}. Will be removed in 2.0.
+     */
+    @Deprecated
     protected final byte PAD = PAD_DEFAULT; // instance variable just in case it needs to vary later
 
+    protected final byte pad; // instance variable just in case it needs to vary later
+
     /** Number of bytes in each full block of unencoded data, e.g. 4 for Base64 and 5 for Base32 */
     private final int unencodedBlockSize;
 
@@ -183,11 +189,27 @@ public abstract class BaseNCodec impleme
      */
     protected BaseNCodec(final int unencodedBlockSize, final int encodedBlockSize,
                          final int lineLength, final int chunkSeparatorLength) {
+        this(unencodedBlockSize, encodedBlockSize, lineLength, chunkSeparatorLength, PAD_DEFAULT);
+    }
+
+    /**
+     * Note <code>lineLength</code> is rounded down to the nearest multiple of {@link #encodedBlockSize}
+     * If <code>chunkSeparatorLength</code> 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 &gt; 0, use chunking with a length <code>lineLength</code>
+     * @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) {
         this.unencodedBlockSize = unencodedBlockSize;
         this.encodedBlockSize = encodedBlockSize;
         final boolean useChunking = lineLength > 0 && chunkSeparatorLength > 0;
         this.lineLength = useChunking ? (lineLength / encodedBlockSize) * encodedBlockSize : 0;
         this.chunkSeparatorLength = chunkSeparatorLength;
+
+        this.pad = pad;
     }
 
     /**
@@ -440,7 +462,7 @@ public abstract class BaseNCodec impleme
     public boolean isInAlphabet(final byte[] arrayOctet, final boolean allowWSPad) {
         for (int i = 0; i < arrayOctet.length; i++) {
             if (!isInAlphabet(arrayOctet[i]) &&
-                    (!allowWSPad || (arrayOctet[i] != PAD) && !isWhiteSpace(arrayOctet[i]))) {
+                    (!allowWSPad || (arrayOctet[i] != pad) && !isWhiteSpace(arrayOctet[i]))) {
                 return false;
             }
         }
@@ -474,7 +496,7 @@ public abstract class BaseNCodec impleme
             return false;
         }
         for (final byte element : arrayOctet) {
-            if (PAD == element || isInAlphabet(element)) {
+            if (pad == element || isInAlphabet(element)) {
                 return true;
             }
         }

Modified: commons/proper/codec/trunk/src/test/java/org/apache/commons/codec/binary/Base32Test.java
URL: http://svn.apache.org/viewvc/commons/proper/codec/trunk/src/test/java/org/apache/commons/codec/binary/Base32Test.java?rev=1571406&r1=1571405&r2=1571406&view=diff
==============================================================================
--- commons/proper/codec/trunk/src/test/java/org/apache/commons/codec/binary/Base32Test.java (original)
+++ commons/proper/codec/trunk/src/test/java/org/apache/commons/codec/binary/Base32Test.java Mon Feb 24 19:38:15 2014
@@ -59,6 +59,16 @@ public class Base32Test {
         {"foobar" ,"MZXW6YTBOI======\r\n"},
     };
 
+    private static final String [][] BASE32_PAD_TEST_CASES = { // RFC 4648
+        {""       ,""},
+        {"f"      ,"MY%%%%%%"},
+        {"fo"     ,"MZXQ%%%%"},
+        {"foo"    ,"MZXW6%%%"},
+        {"foob"   ,"MZXW6YQ%"},
+        {"fooba"  ,"MZXW6YTB"},
+        {"foobar" ,"MZXW6YTBOI%%%%%%"},
+    };
+    
     @Test
     public void testBase32Samples() throws Exception {
         final Base32 codec = new Base32();
@@ -132,4 +142,13 @@ public class Base32Test {
             //assertEquals(b[0],codec.decode(b[1]));
         }
     }
+    
+    @Test
+    public void testBase32SamplesNonDefaultPadding() throws Exception {
+        final Base32 codec = new Base32((byte)0x25); // '%' <=> 0x25
+        
+        for (final String[] element : BASE32_PAD_TEST_CASES) {
+                assertEquals(element[1], codec.encodeAsString(element[0].getBytes(Charsets.UTF_8)));
+        }
+    }
 }

Modified: commons/proper/codec/trunk/src/test/java/org/apache/commons/codec/binary/BaseNCodecTest.java
URL: http://svn.apache.org/viewvc/commons/proper/codec/trunk/src/test/java/org/apache/commons/codec/binary/BaseNCodecTest.java?rev=1571406&r1=1571405&r2=1571406&view=diff
==============================================================================
--- commons/proper/codec/trunk/src/test/java/org/apache/commons/codec/binary/BaseNCodecTest.java (original)
+++ commons/proper/codec/trunk/src/test/java/org/apache/commons/codec/binary/BaseNCodecTest.java Mon Feb 24 19:38:15 2014
@@ -21,6 +21,7 @@ package org.apache.commons.codec.binary;
 import static org.junit.Assert.assertFalse;
 import static org.junit.Assert.assertNotNull;
 import static org.junit.Assert.assertTrue;
+import static org.junit.Assert.assertEquals;
 
 import org.junit.Before;
 import org.junit.Test;
@@ -158,11 +159,36 @@ public class BaseNCodecTest {
         assertTrue(codec.containsAlphabetOrPad("OK".getBytes()));
         assertTrue(codec.containsAlphabetOrPad("OK ".getBytes()));
         assertFalse(codec.containsAlphabetOrPad("ok ".getBytes()));
-        assertTrue(codec.containsAlphabetOrPad(new byte[]{codec.PAD}));
+        assertTrue(codec.containsAlphabetOrPad(new byte[]{codec.pad}));
     }
 
 //    @Test
 //    public void testGetEncodedLength() {
 //        fail("Not yet implemented");
 //    }
+    
+    @Test
+    public void testProvidePaddingByte() {
+        // Given
+    	codec = new BaseNCodec(0, 0, 0, 0, (byte)0x25) {
+            @Override
+            protected boolean isInAlphabet(final byte b) {
+                return b=='O' || b == 'K'; // allow OK
+            }
+
+            @Override
+            void encode(final byte[] pArray, final int i, final int length, final Context context) {
+            }
+
+            @Override
+            void decode(final byte[] pArray, final int i, final int length, final Context context) {
+            }
+        };
+        
+        // When
+        byte actualPaddingByte = codec.pad;
+        
+        // Then
+        assertEquals(0x25, actualPaddingByte);
+    }
 }