Skip to content

Commit e17d5c5

Browse files
committed
[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%.
git-svn-id: https://svn.apache.org/repos/asf/commons/proper/codec/trunk@799800 13f79535-47bb-0310-9956-ffa450edef68
1 parent 9f24361 commit e17d5c5

3 files changed

Lines changed: 135 additions & 13 deletions

File tree

src/java/org/apache/commons/codec/binary/Base64.java

Lines changed: 85 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -540,7 +540,7 @@ void decode(byte[] in, int inPos, int inAvail) {
540540
}
541541
byte b = in[inPos++];
542542
if (b == PAD) {
543-
// WE'RE DONE!!!!
543+
// We're done.
544544
eof = true;
545545
break;
546546
} else {
@@ -628,25 +628,49 @@ private static boolean containsBase64Byte(byte[] arrayOctet) {
628628
*
629629
* @param binaryData
630630
* binary data to encode
631-
* @return Base64 characters
631+
* @return byte[] containing Base64 characters in their UTF-8 representation.
632632
*/
633633
public static byte[] encodeBase64(byte[] binaryData) {
634634
return encodeBase64(binaryData, false);
635635
}
636636

637+
/**
638+
* Encodes binary data using the base64 algorithm into 76 character blocks separated by CRLF.
639+
*
640+
* @param binaryData
641+
* binary data to encode
642+
* @return String containing Base64 characters.
643+
*/
644+
public static String encodeBase64String(byte[] binaryData) {
645+
return StringUtils.newStringUtf8(encodeBase64(binaryData, true));
646+
}
647+
637648
/**
638649
* Encodes binary data using a URL-safe variation of the base64 algorithm but does not chunk the output. The
639650
* url-safe variation emits - and _ instead of + and / characters.
640651
*
641652
* @param binaryData
642653
* binary data to encode
643-
* @return Base64 characters
654+
* @return byte[] containing Base64 characters in their UTF-8 representation.
644655
* @since 1.4
645656
*/
646657
public static byte[] encodeBase64URLSafe(byte[] binaryData) {
647658
return encodeBase64(binaryData, false, true);
648659
}
649660

661+
/**
662+
* Encodes binary data using a URL-safe variation of the base64 algorithm but does not chunk the output. The
663+
* url-safe variation emits - and _ instead of + and / characters.
664+
*
665+
* @param binaryData
666+
* binary data to encode
667+
* @return String containing Base64 characters
668+
* @since 1.4
669+
*/
670+
public static String encodeBase64URLSafeString(byte[] binaryData) {
671+
return StringUtils.newStringUtf8(encodeBase64(binaryData, false, true));
672+
}
673+
650674
/**
651675
* Encodes binary data using the base64 algorithm and chunks the encoded output into 76 character blocks
652676
*
@@ -660,22 +684,35 @@ public static byte[] encodeBase64Chunked(byte[] binaryData) {
660684

661685
/**
662686
* Decodes an Object using the base64 algorithm. This method is provided in order to satisfy the requirements of the
663-
* Decoder interface, and will throw a DecoderException if the supplied object is not of type byte[].
687+
* Decoder interface, and will throw a DecoderException if the supplied object is not of type byte[] or String.
664688
*
665689
* @param pObject
666690
* Object to decode
667-
* @return An object (of type byte[]) containing the binary data which corresponds to the byte[] supplied.
691+
* @return An object (of type byte[]) containing the binary data which corresponds to the byte[] or String supplied.
668692
* @throws DecoderException
669693
* if the parameter supplied is not of type byte[]
670694
*/
671-
public Object decode(Object pObject) throws DecoderException {
695+
public Object decode(Object pObject) throws DecoderException {
672696
if (pObject instanceof byte[]) {
673697
return decode((byte[]) pObject);
698+
} else if (pObject instanceof String) {
699+
return decode((String) pObject);
674700
} else {
675-
throw new DecoderException("Parameter supplied to Base64 decode is not a byte[]");
701+
throw new DecoderException("Parameter supplied to Base64 decode is not a byte[] or a String");
676702
}
677703
}
678704

705+
/**
706+
* Decodes a String containing containing characters in the Base64 alphabet.
707+
*
708+
* @param pArray
709+
* A String containing Base64 character data
710+
* @return a byte array containing binary data
711+
*/
712+
public byte[] decode(String pArray) {
713+
return decode(StringUtils.getBytesUtf8(pArray));
714+
}
715+
679716
/**
680717
* Decodes a byte[] containing containing characters in the Base64 alphabet.
681718
*
@@ -684,6 +721,7 @@ public Object decode(Object pObject) throws DecoderException {
684721
* @return a byte array containing binary data
685722
*/
686723
public byte[] decode(byte[] pArray) {
724+
reset();
687725
if (pArray == null || pArray.length == 0) {
688726
return pArray;
689727
}
@@ -770,6 +808,17 @@ public static byte[] encodeBase64(byte[] binaryData, boolean isChunked, boolean
770808
return b64.encode(binaryData);
771809
}
772810

811+
/**
812+
* Decodes a Base64 String into octets
813+
*
814+
* @param base64String
815+
* String containing Base64 data
816+
* @return Array containing decoded data.
817+
*/
818+
public static byte[] decodeBase64(String base64String) {
819+
return new Base64().decode(base64String);
820+
}
821+
773822
/**
774823
* Decodes Base64 data into octets
775824
*
@@ -778,8 +827,7 @@ public static byte[] encodeBase64(byte[] binaryData, boolean isChunked, boolean
778827
* @return Array containing decoded data.
779828
*/
780829
public static byte[] decodeBase64(byte[] base64Data) {
781-
Base64 b64 = new Base64();
782-
return b64.decode(base64Data);
830+
return new Base64().decode(base64Data);
783831
}
784832

785833
/**
@@ -847,6 +895,17 @@ public Object encode(Object pObject) throws EncoderException {
847895
return encode((byte[]) pObject);
848896
}
849897

898+
/**
899+
* Encodes a byte[] containing binary data, into a String containing characters in the Base64 alphabet.
900+
*
901+
* @param pArray
902+
* a byte array containing binary data
903+
* @return A String containing only Base64 character data
904+
*/
905+
public String encodeToString(byte[] pArray) {
906+
return StringUtils.newStringUtf8(encode(pArray));
907+
}
908+
850909
/**
851910
* Encodes a byte[] containing binary data, into a byte[] containing characters in the Base64 alphabet.
852911
*
@@ -855,6 +914,10 @@ public Object encode(Object pObject) throws EncoderException {
855914
* @return A byte array containing only Base64 character data
856915
*/
857916
public byte[] encode(byte[] pArray) {
917+
reset();
918+
if (pArray == null || pArray.length == 0) {
919+
return pArray;
920+
}
858921
long len = getEncodeLength(pArray, lineLength, lineSeparator);
859922
byte[] buf = new byte[(int) len];
860923
setInitialBuffer(buf, 0, buf.length);
@@ -964,4 +1027,17 @@ static byte[] toIntegerBytes(BigInteger bigInt) {
9641027
System.arraycopy(bigBytes, startSrc, resizedBytes, startDst, len);
9651028
return resizedBytes;
9661029
}
1030+
1031+
/**
1032+
* Resets this Base64 object to its initial newly constructed state.
1033+
*/
1034+
private void reset() {
1035+
buffer = null;
1036+
pos = 0;
1037+
readPos = 0;
1038+
currentLinePos = 0;
1039+
modulus = 0;
1040+
eof = false;
1041+
}
1042+
9671043
}

src/java/org/apache/commons/codec/binary/StringUtils.java

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -149,6 +149,9 @@ public static byte[] getBytesUtf8(String string) {
149149
* @see String#getBytes(String)
150150
*/
151151
public static byte[] getSupportedBytes(String string, String charsetName) {
152+
if (string == null) {
153+
return null;
154+
}
152155
try {
153156
return string.getBytes(charsetName);
154157
} catch (UnsupportedEncodingException e) {
@@ -179,6 +182,9 @@ private static IllegalStateException newIllegalStateException(String charsetName
179182
* @see String#String(byte[], String)
180183
*/
181184
public static String newString(byte[] bytes, String charsetName) {
185+
if (bytes == null) {
186+
return null;
187+
}
182188
try {
183189
return new String(bytes, charsetName);
184190
} catch (UnsupportedEncodingException e) {

src/test/org/apache/commons/codec/binary/Base64Test.java

Lines changed: 44 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -60,7 +60,8 @@ public Random getRandom() {
6060
public void testBase64() {
6161
String content = "Hello World";
6262
String encodedContent;
63-
encodedContent = new String(Base64.encodeBase64(content.getBytes()));
63+
byte[] encodedBytes = Base64.encodeBase64(StringUtils.getBytesUtf8(content));
64+
encodedContent = StringUtils.newStringUtf8(encodedBytes);
6465
assertTrue("encoding hello world", encodedContent.equals("SGVsbG8gV29ybGQ="));
6566
}
6667

@@ -288,7 +289,7 @@ public void testEmptyBase64() {
288289
empty = new byte[0];
289290
result = Base64.decodeBase64(empty);
290291
assertEquals("empty base64 decode", 0, result.length);
291-
assertEquals("empty base64 encode", null, Base64.decodeBase64(null));
292+
assertEquals("empty base64 encode", null, Base64.decodeBase64((byte[]) null));
292293
}
293294

294295
// encode/decode a large random array
@@ -423,8 +424,8 @@ public void testObjectDecodeWithInvalidParameter() throws Exception {
423424
Base64 b64 = new Base64();
424425

425426
try {
426-
b64.decode("Yadayadayada");
427-
fail("decode(Object) didn't throw an exception when passed a String object");
427+
b64.decode(new Integer(5));
428+
fail("decode(Object) didn't throw an exception when passed an Integer object");
428429
} catch (DecoderException e) {
429430
// ignored
430431
}
@@ -956,6 +957,45 @@ public void testUUID() throws DecoderException {
956957
}
957958
}
958959

960+
public void testByteToStringVariations() throws DecoderException {
961+
Base64 base64 = new Base64(0);
962+
byte[] b1 = StringUtils.getBytesUtf8("Hello World");
963+
byte[] b2 = new byte[0];
964+
byte[] b3 = null;
965+
byte[] b4 = Hex.decodeHex("2bf7cc2701fe4397b49ebeed5acc7090".toCharArray()); // for url-safe tests
966+
967+
assertEquals("byteToString Hello World", "SGVsbG8gV29ybGQ=", base64.encodeToString(b1));
968+
assertEquals("byteToString static Hello World", "SGVsbG8gV29ybGQ=\r\n", Base64.encodeBase64String(b1));
969+
assertEquals("byteToString \"\"", "", base64.encodeToString(b2));
970+
assertEquals("byteToString static \"\"", "", Base64.encodeBase64String(b2));
971+
assertEquals("byteToString null", null, base64.encodeToString(b3));
972+
assertEquals("byteToString static null", null, Base64.encodeBase64String(b3));
973+
assertEquals("byteToString UUID", "K/fMJwH+Q5e0nr7tWsxwkA==", base64.encodeToString(b4));
974+
assertEquals("byteToString static UUID", "K/fMJwH+Q5e0nr7tWsxwkA==\r\n", Base64.encodeBase64String(b4));
975+
assertEquals("byteToString static-url-safe UUID", "K_fMJwH-Q5e0nr7tWsxwkA", Base64.encodeBase64URLSafeString(b4));
976+
}
977+
978+
public void testStringToByteVariations() throws DecoderException {
979+
Base64 base64 = new Base64();
980+
String s1 = "SGVsbG8gV29ybGQ=\r\n";
981+
String s2 = "";
982+
String s3 = null;
983+
String s4a = "K/fMJwH+Q5e0nr7tWsxwkA==\r\n";
984+
String s4b = "K_fMJwH-Q5e0nr7tWsxwkA";
985+
byte[] b4 = Hex.decodeHex("2bf7cc2701fe4397b49ebeed5acc7090".toCharArray()); // for url-safe tests
986+
987+
assertEquals("StringToByte Hello World", "Hello World", StringUtils.newStringUtf8(base64.decode(s1)));
988+
assertEquals("StringToByte Hello World", "Hello World", StringUtils.newStringUtf8((byte[])base64.decode((Object)s1)));
989+
assertEquals("StringToByte static Hello World", "Hello World", StringUtils.newStringUtf8(Base64.decodeBase64(s1)));
990+
assertEquals("StringToByte \"\"", "", StringUtils.newStringUtf8(base64.decode(s2)));
991+
assertEquals("StringToByte static \"\"", "", StringUtils.newStringUtf8(Base64.decodeBase64(s2)));
992+
assertEquals("StringToByte null", null, StringUtils.newStringUtf8(base64.decode(s3)));
993+
assertEquals("StringToByte static null", null, StringUtils.newStringUtf8(Base64.decodeBase64(s3)));
994+
assertTrue("StringToByte UUID", Arrays.equals(b4, base64.decode(s4b)));
995+
assertTrue("StringToByte static UUID", Arrays.equals(b4, Base64.decodeBase64(s4a)));
996+
assertTrue("StringToByte static-url-safe UUID", Arrays.equals(b4, Base64.decodeBase64(s4b)));
997+
}
998+
959999
private String toString(byte[] data) {
9601000
StringBuffer buf = new StringBuffer();
9611001
for (int i = 0; i < data.length; i++) {

0 commit comments

Comments
 (0)