Author: ggregory Date: Sat Aug 1 04:15:09 2009 New Revision: 799800 URL: http://svn.apache.org/viewvc?rev=799800&view=rev Log: [CODEC-59] Add methods to Base64 which work with String instead of byte[]. Patch applied with one added test code line to keep line code coverage at 100%. Branch coverage up to 92% from 91%.
Modified: commons/proper/codec/trunk/src/java/org/apache/commons/codec/binary/Base64.java commons/proper/codec/trunk/src/java/org/apache/commons/codec/binary/StringUtils.java commons/proper/codec/trunk/src/test/org/apache/commons/codec/binary/Base64Test.java Modified: commons/proper/codec/trunk/src/java/org/apache/commons/codec/binary/Base64.java URL: http://svn.apache.org/viewvc/commons/proper/codec/trunk/src/java/org/apache/commons/codec/binary/Base64.java?rev=799800&r1=799799&r2=799800&view=diff ============================================================================== --- commons/proper/codec/trunk/src/java/org/apache/commons/codec/binary/Base64.java (original) +++ commons/proper/codec/trunk/src/java/org/apache/commons/codec/binary/Base64.java Sat Aug 1 04:15:09 2009 @@ -540,7 +540,7 @@ } byte b = in[inPos++]; if (b == PAD) { - // WE'RE DONE!!!! + // We're done. eof = true; break; } else { @@ -628,19 +628,30 @@ * * @param binaryData * binary data to encode - * @return Base64 characters + * @return byte[] containing Base64 characters in their UTF-8 representation. */ public static byte[] encodeBase64(byte[] binaryData) { return encodeBase64(binaryData, false); } /** + * Encodes binary data using the base64 algorithm into 76 character blocks separated by CRLF. + * + * @param binaryData + * binary data to encode + * @return String containing Base64 characters. + */ + public static String encodeBase64String(byte[] binaryData) { + return StringUtils.newStringUtf8(encodeBase64(binaryData, true)); + } + + /** * Encodes binary data using a URL-safe variation of the base64 algorithm but does not chunk the output. The * url-safe variation emits - and _ instead of + and / characters. * * @param binaryData * binary data to encode - * @return Base64 characters + * @return byte[] containing Base64 characters in their UTF-8 representation. * @since 1.4 */ public static byte[] encodeBase64URLSafe(byte[] binaryData) { @@ -648,6 +659,19 @@ } /** + * Encodes binary data using a URL-safe variation of the base64 algorithm but does not chunk the output. The + * url-safe variation emits - and _ instead of + and / characters. + * + * @param binaryData + * binary data to encode + * @return String containing Base64 characters + * @since 1.4 + */ + public static String encodeBase64URLSafeString(byte[] binaryData) { + return StringUtils.newStringUtf8(encodeBase64(binaryData, false, true)); + } + + /** * Encodes binary data using the base64 algorithm and chunks the encoded output into 76 character blocks * * @param binaryData @@ -660,23 +684,36 @@ /** * Decodes an Object using the base64 algorithm. This method is provided in order to satisfy the requirements of the - * Decoder interface, and will throw a DecoderException if the supplied object is not of type byte[]. + * Decoder interface, and will throw a DecoderException if the supplied object is not of type byte[] or String. * * @param pObject * Object to decode - * @return An object (of type byte[]) containing the binary data which corresponds to the byte[] supplied. + * @return An object (of type byte[]) containing the binary data which corresponds to the byte[] or String supplied. * @throws DecoderException * if the parameter supplied is not of type byte[] */ - public Object decode(Object pObject) throws DecoderException { + public Object decode(Object pObject) throws DecoderException { if (pObject instanceof byte[]) { return decode((byte[]) pObject); + } else if (pObject instanceof String) { + return decode((String) pObject); } else { - throw new DecoderException("Parameter supplied to Base64 decode is not a byte[]"); + throw new DecoderException("Parameter supplied to Base64 decode is not a byte[] or a String"); } } /** + * Decodes a String containing containing characters in the Base64 alphabet. + * + * @param pArray + * A String containing Base64 character data + * @return a byte array containing binary data + */ + public byte[] decode(String pArray) { + return decode(StringUtils.getBytesUtf8(pArray)); + } + + /** * Decodes a byte[] containing containing characters in the Base64 alphabet. * * @param pArray @@ -684,6 +721,7 @@ * @return a byte array containing binary data */ public byte[] decode(byte[] pArray) { + reset(); if (pArray == null || pArray.length == 0) { return pArray; } @@ -771,6 +809,17 @@ } /** + * Decodes a Base64 String into octets + * + * @param base64String + * String containing Base64 data + * @return Array containing decoded data. + */ + public static byte[] decodeBase64(String base64String) { + return new Base64().decode(base64String); + } + + /** * Decodes Base64 data into octets * * @param base64Data @@ -778,8 +827,7 @@ * @return Array containing decoded data. */ public static byte[] decodeBase64(byte[] base64Data) { - Base64 b64 = new Base64(); - return b64.decode(base64Data); + return new Base64().decode(base64Data); } /** @@ -848,6 +896,17 @@ } /** + * Encodes a byte[] containing binary data, into a String containing characters in the Base64 alphabet. + * + * @param pArray + * a byte array containing binary data + * @return A String containing only Base64 character data + */ + public String encodeToString(byte[] pArray) { + return StringUtils.newStringUtf8(encode(pArray)); + } + + /** * Encodes a byte[] containing binary data, into a byte[] containing characters in the Base64 alphabet. * * @param pArray @@ -855,6 +914,10 @@ * @return A byte array containing only Base64 character data */ public byte[] encode(byte[] pArray) { + reset(); + if (pArray == null || pArray.length == 0) { + return pArray; + } long len = getEncodeLength(pArray, lineLength, lineSeparator); byte[] buf = new byte[(int) len]; setInitialBuffer(buf, 0, buf.length); @@ -964,4 +1027,17 @@ System.arraycopy(bigBytes, startSrc, resizedBytes, startDst, len); return resizedBytes; } + + /** + * Resets this Base64 object to its initial newly constructed state. + */ + private void reset() { + buffer = null; + pos = 0; + readPos = 0; + currentLinePos = 0; + modulus = 0; + eof = false; + } + } Modified: commons/proper/codec/trunk/src/java/org/apache/commons/codec/binary/StringUtils.java URL: http://svn.apache.org/viewvc/commons/proper/codec/trunk/src/java/org/apache/commons/codec/binary/StringUtils.java?rev=799800&r1=799799&r2=799800&view=diff ============================================================================== --- commons/proper/codec/trunk/src/java/org/apache/commons/codec/binary/StringUtils.java (original) +++ commons/proper/codec/trunk/src/java/org/apache/commons/codec/binary/StringUtils.java Sat Aug 1 04:15:09 2009 @@ -149,6 +149,9 @@ * @see String#getBytes(String) */ public static byte[] getSupportedBytes(String string, String charsetName) { + if (string == null) { + return null; + } try { return string.getBytes(charsetName); } catch (UnsupportedEncodingException e) { @@ -179,6 +182,9 @@ * @see String#String(byte[], String) */ public static String newString(byte[] bytes, String charsetName) { + if (bytes == null) { + return null; + } try { return new String(bytes, charsetName); } catch (UnsupportedEncodingException e) { Modified: commons/proper/codec/trunk/src/test/org/apache/commons/codec/binary/Base64Test.java URL: http://svn.apache.org/viewvc/commons/proper/codec/trunk/src/test/org/apache/commons/codec/binary/Base64Test.java?rev=799800&r1=799799&r2=799800&view=diff ============================================================================== --- commons/proper/codec/trunk/src/test/org/apache/commons/codec/binary/Base64Test.java (original) +++ commons/proper/codec/trunk/src/test/org/apache/commons/codec/binary/Base64Test.java Sat Aug 1 04:15:09 2009 @@ -60,7 +60,8 @@ public void testBase64() { String content = "Hello World"; String encodedContent; - encodedContent = new String(Base64.encodeBase64(content.getBytes())); + byte[] encodedBytes = Base64.encodeBase64(StringUtils.getBytesUtf8(content)); + encodedContent = StringUtils.newStringUtf8(encodedBytes); assertTrue("encoding hello world", encodedContent.equals("SGVsbG8gV29ybGQ=")); } @@ -288,7 +289,7 @@ empty = new byte[0]; result = Base64.decodeBase64(empty); assertEquals("empty base64 decode", 0, result.length); - assertEquals("empty base64 encode", null, Base64.decodeBase64(null)); + assertEquals("empty base64 encode", null, Base64.decodeBase64((byte[]) null)); } // encode/decode a large random array @@ -423,8 +424,8 @@ Base64 b64 = new Base64(); try { - b64.decode("Yadayadayada"); - fail("decode(Object) didn't throw an exception when passed a String object"); + b64.decode(new Integer(5)); + fail("decode(Object) didn't throw an exception when passed an Integer object"); } catch (DecoderException e) { // ignored } @@ -956,6 +957,45 @@ } } + public void testByteToStringVariations() throws DecoderException { + Base64 base64 = new Base64(0); + byte[] b1 = StringUtils.getBytesUtf8("Hello World"); + byte[] b2 = new byte[0]; + byte[] b3 = null; + byte[] b4 = Hex.decodeHex("2bf7cc2701fe4397b49ebeed5acc7090".toCharArray()); // for url-safe tests + + assertEquals("byteToString Hello World", "SGVsbG8gV29ybGQ=", base64.encodeToString(b1)); + assertEquals("byteToString static Hello World", "SGVsbG8gV29ybGQ=\r\n", Base64.encodeBase64String(b1)); + assertEquals("byteToString \"\"", "", base64.encodeToString(b2)); + assertEquals("byteToString static \"\"", "", Base64.encodeBase64String(b2)); + assertEquals("byteToString null", null, base64.encodeToString(b3)); + assertEquals("byteToString static null", null, Base64.encodeBase64String(b3)); + assertEquals("byteToString UUID", "K/fMJwH+Q5e0nr7tWsxwkA==", base64.encodeToString(b4)); + assertEquals("byteToString static UUID", "K/fMJwH+Q5e0nr7tWsxwkA==\r\n", Base64.encodeBase64String(b4)); + assertEquals("byteToString static-url-safe UUID", "K_fMJwH-Q5e0nr7tWsxwkA", Base64.encodeBase64URLSafeString(b4)); + } + + public void testStringToByteVariations() throws DecoderException { + Base64 base64 = new Base64(); + String s1 = "SGVsbG8gV29ybGQ=\r\n"; + String s2 = ""; + String s3 = null; + String s4a = "K/fMJwH+Q5e0nr7tWsxwkA==\r\n"; + String s4b = "K_fMJwH-Q5e0nr7tWsxwkA"; + byte[] b4 = Hex.decodeHex("2bf7cc2701fe4397b49ebeed5acc7090".toCharArray()); // for url-safe tests + + assertEquals("StringToByte Hello World", "Hello World", StringUtils.newStringUtf8(base64.decode(s1))); + assertEquals("StringToByte Hello World", "Hello World", StringUtils.newStringUtf8((byte[])base64.decode((Object)s1))); + assertEquals("StringToByte static Hello World", "Hello World", StringUtils.newStringUtf8(Base64.decodeBase64(s1))); + assertEquals("StringToByte \"\"", "", StringUtils.newStringUtf8(base64.decode(s2))); + assertEquals("StringToByte static \"\"", "", StringUtils.newStringUtf8(Base64.decodeBase64(s2))); + assertEquals("StringToByte null", null, StringUtils.newStringUtf8(base64.decode(s3))); + assertEquals("StringToByte static null", null, StringUtils.newStringUtf8(Base64.decodeBase64(s3))); + assertTrue("StringToByte UUID", Arrays.equals(b4, base64.decode(s4b))); + assertTrue("StringToByte static UUID", Arrays.equals(b4, Base64.decodeBase64(s4a))); + assertTrue("StringToByte static-url-safe UUID", Arrays.equals(b4, Base64.decodeBase64(s4b))); + } + private String toString(byte[] data) { StringBuffer buf = new StringBuffer(); for (int i = 0; i < data.length; i++) {