Skip to content

Instantly share code, notes, and snippets.

@fupfin
Last active August 29, 2015 14:10
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save fupfin/f85822dcf3a64e163442 to your computer and use it in GitHub Desktop.
Save fupfin/f85822dcf3a64e163442 to your computer and use it in GitHub Desktop.
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();
}
}
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