Last active
August 29, 2015 14:10
-
-
Save fupfin/f85822dcf3a64e163442 to your computer and use it in GitHub Desktop.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
package com.fupfin.groovybase64 | |
import java.nio.ByteBuffer | |
class Base64 { | |
static RAW_CHUNK_SIZE = 3 | |
static ENC_CHUNK_SIZE = 4 | |
static encChars = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/".getBytes() | |
static paddingChars = [0x3d, 0x3d, 0x3d, 0x3d] as byte[] // ['=', '=', '=', '='] | |
static decMap = new HashMap() | |
static { | |
for(idx in 0 ..< encChars.length) | |
decMap.put(encChars[idx], idx) | |
} | |
static OutputStream enc(InputStream is, OutputStream os) { | |
def ib = new byte[RAW_CHUNK_SIZE] | |
def ob = new byte[ENC_CHUNK_SIZE] | |
def olen = 0 | |
Arrays.fill(ib, (byte) 0) | |
for(int len=0; (len = is.read(ib, 0, RAW_CHUNK_SIZE)) > 0;) { | |
ob[0] = ib[0] >> 2 | |
ob[1] = (ib[0] & 0x03) << 4 | (ib[1] & 0xf0) >> 4 | |
ob[2] = (ib[1] & 0x0f) << 2 | (ib[2] & 0xc0) >> 6 | |
ob[3] = ib[2] & 0x3f | |
olen = len > 0 ? len + 1 : 0 | |
for (idx in 0 ..< olen) | |
os.write(encChars, ob[idx], 1) | |
Arrays.fill(ib, (byte) 0) | |
} | |
if(olen > 0) os.write(paddingChars, 0, ENC_CHUNK_SIZE - olen) | |
return os | |
} | |
static byte[] enc(byte[] data) { | |
doWithDataArray(data, {is, os -> Base64.enc(is, os)}) | |
} | |
static OutputStream dec(InputStream is, OutputStream os) { | |
def ib = new byte[ENC_CHUNK_SIZE] | |
def ob = new byte[RAW_CHUNK_SIZE] | |
def endOfData = false | |
for(int len=0; (len = is.read(ib, 0, ENC_CHUNK_SIZE)) > 0;) { | |
if(len != ENC_CHUNK_SIZE) | |
throw new IllegalArgumentException("Encoded data should be chunked in 4 bytes.") | |
def rawData = new byte[ENC_CHUNK_SIZE] | |
Arrays.fill(rawData, (byte) 0) | |
def rlen = 0; | |
for(idx in 0 ..< ENC_CHUNK_SIZE) { | |
if(ib[idx] == '=') | |
endOfData = true | |
else { | |
if(endOfData) throw new IllegalArgumentException("Encoded data should not contain the '=' character in the middle of data.") | |
rawData[idx] = decMap[ib[idx]] | |
rlen = idx + 1 | |
} | |
} | |
ob[0] = rawData[0] << 2 | (rawData[1] & 0x30) >> 4 | |
ob[1] = (rawData[1] & 0x0f) << 4 | (rawData[2] & 0xfc) >> 2 | |
ob[2] = (rawData[2] & 0x03) << 6 | rawData[3] | |
os.write(ob, 0, rlen > 0 ? rlen - 1 : 0) | |
Arrays.fill(ib, (byte) 0) | |
} | |
return os | |
} | |
static byte[] dec(byte[] data) { | |
doWithDataArray(data, {is, os -> Base64.dec(is, os)}) | |
} | |
private static byte[] doWithDataArray(byte[] data, func) { | |
def is = new ByteArrayInputStream(data) | |
def os = new ByteArrayOutputStream() | |
func(is,os) | |
os.toByteArray(); | |
} | |
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
package com.fupfin.groovybase64 | |
import spock.lang.Specification | |
class Base64Spec extends Specification { | |
private static final LONG_TEXT = "Man is distinguished, not only by his reason, but by this singular passion from other animals, which is a lust of the mind, that by a perseverance of delight in the continued and indefatigable generation of knowledge, exceeds the short vehemence of any carnal pleasure." | |
private static final LONG_RESULT = "TWFuIGlzIGRpc3Rpbmd1aXNoZWQsIG5vdCBvbmx5IGJ5IGhpcyByZWFzb24sIGJ1dCBieSB0aGlzIHNpbmd1bGFyIHBhc3Npb24gZnJvbSBvdGhlciBhbmltYWxzLCB3aGljaCBpcyBhIGx1c3Qgb2YgdGhlIG1pbmQsIHRoYXQgYnkgYSBwZXJzZXZlcmFuY2Ugb2YgZGVsaWdodCBpbiB0aGUgY29udGludWVkIGFuZCBpbmRlZmF0aWdhYmxlIGdlbmVyYXRpb24gb2Yga25vd2xlZGdlLCBleGNlZWRzIHRoZSBzaG9ydCB2ZWhlbWVuY2Ugb2YgYW55IGNhcm5hbCBwbGVhc3VyZS4=" | |
def "간단한 데이터 스트림 인코딩"() { | |
given: | |
def str = "abc" | |
when: | |
def result = encodeStringWithInputStream(str) | |
then: | |
result == "YWJj".getBytes() | |
} | |
def "패딩 하나"() { | |
given: | |
def str = "ab" | |
when: | |
def result = encodeStringWithInputStream(str) | |
then: | |
result == "YWI=".getBytes() | |
} | |
def "패딩 둘"() { | |
given: | |
def str = "a" | |
when: | |
def result = encodeStringWithInputStream(str) | |
then: | |
result == "YQ==".getBytes() | |
} | |
def "긴 데이터 스트림 인코딩"() { | |
when: | |
def result = encodeStringWithInputStream(LONG_TEXT) | |
then: | |
result == LONG_RESULT.getBytes() | |
} | |
def "긴 문자열 인코딩"() { | |
when: | |
def result = Base64.enc(LONG_TEXT.getBytes()) | |
then: | |
result == LONG_RESULT.getBytes() | |
} | |
def "짧은 데이터 스트림 디코딩" () { | |
given: | |
def is = new ByteArrayInputStream("YWJj".getBytes()) | |
def os = new ByteArrayOutputStream() | |
when: | |
Base64.dec(is, os) | |
then: | |
os.toByteArray() == "abc".getBytes() | |
} | |
def "긴 데이터 스트림 디코딩" () { | |
given: | |
def is = new ByteArrayInputStream(LONG_RESULT.getBytes()) | |
def os = new ByteArrayOutputStream() | |
when: | |
Base64.dec(is, os) | |
then: | |
os.toByteArray() == LONG_TEXT.getBytes() | |
} | |
def "4 바이트로 나뉘지 않는 데이터 스트림 디코딩" () { | |
given: | |
def is = new ByteArrayInputStream("YWJ".getBytes()) | |
def os = new ByteArrayOutputStream() | |
when: | |
Base64.dec(is, os) | |
then: | |
def e = thrown(IllegalArgumentException.class) | |
e.message.contains("4") | |
} | |
def "중간에 = 문자가 있는 데이터 스트림 디코딩" () { | |
given: | |
def is = new ByteArrayInputStream("Y=Jj".getBytes()) | |
def os = new ByteArrayOutputStream() | |
when: | |
Base64.dec(is, os) | |
then: | |
def e = thrown(IllegalArgumentException.class) | |
e.message.contains("=") | |
} | |
def encodeStringWithInputStream(str) { | |
def is = new ByteArrayInputStream(str.getBytes()) | |
def os = new ByteArrayOutputStream() | |
Base64.enc(is, os) | |
os.toByteArray(); | |
} | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment