diff --git a/src/main/java/com/annimon/ownlang/modules/base64/base64.java b/src/main/java/com/annimon/ownlang/modules/base64/base64.java new file mode 100644 index 0000000..328ffa9 --- /dev/null +++ b/src/main/java/com/annimon/ownlang/modules/base64/base64.java @@ -0,0 +1,74 @@ +package com.annimon.ownlang.modules.base64; + +import com.annimon.ownlang.lib.*; +import com.annimon.ownlang.modules.Module; +import java.io.UnsupportedEncodingException; +import java.util.Base64; + +public class base64 implements Module { + + private static final int TYPE_URL_SAFE = 8; + + public static void initConstants() { + Variables.define("BASE64_URL_SAFE", NumberValue.of(TYPE_URL_SAFE)); + } + + @Override + public void init() { + initConstants(); + Functions.set("base64encode", this::base64encode); + Functions.set("base64decode", this::base64decode); + Functions.set("base64encodeToString", this::base64encodeToString); + } + + private Value base64encode(Value... args) { + Arguments.checkOrOr(1, 2, args.length); + return ArrayValue.of(getEncoder(args).encode(getInputToEncode(args))); + } + + private Value base64encodeToString(Value... args) { + Arguments.checkOrOr(1, 2, args.length); + return new StringValue(getEncoder(args).encodeToString(getInputToEncode(args))); + } + + private Value base64decode(Value... args) { + Arguments.checkOrOr(1, 2, args.length); + final Base64.Decoder decoder = getDecoder(args); + final byte[] result; + if (args[0].type() == Types.ARRAY) { + result = decoder.decode(ValueUtils.toByteArray((ArrayValue) args[0])); + } else { + result = decoder.decode(args[0].asString()); + } + return ArrayValue.of(result); + } + + + private byte[] getInputToEncode(Value[] args) { + byte[] input; + if (args[0].type() == Types.ARRAY) { + input = ValueUtils.toByteArray((ArrayValue) args[0]); + } else { + try { + input = args[0].asString().getBytes("UTF-8"); + } catch (UnsupportedEncodingException ex) { + input = args[0].asString().getBytes(); + } + } + return input; + } + + private Base64.Encoder getEncoder(Value[] args) { + if (args.length == 2 && args[1].asInt() == TYPE_URL_SAFE) { + return Base64.getUrlEncoder(); + } + return Base64.getEncoder(); + } + + private Base64.Decoder getDecoder(Value[] args) { + if (args.length == 2 && args[1].asInt() == TYPE_URL_SAFE) { + return Base64.getUrlDecoder(); + } + return Base64.getDecoder(); + } +} diff --git a/src/test/resources/modules/base64/base64.own b/src/test/resources/modules/base64/base64.own new file mode 100644 index 0000000..841dfdd --- /dev/null +++ b/src/test/resources/modules/base64/base64.own @@ -0,0 +1,31 @@ +use "base64" +use "functional" +use "types" + +base64Example = [0x42, 0x61, 0x73, 0x65, 0x36, 0x34, 0x20, 0x45, 0x78, 0x61, 0x6D, 0x70, 0x6C, 0x65] +base64Example_enc = [0x51, 0x6D, 0x46, 0x7A, 0x5A, 0x54, 0x59, 0x30, + 0x49, 0x45, 0x56, 0x34, 0x59, 0x57, 0x31, 0x77, + 0x62, 0x47, 0x55, 0x3D] +unicode = map([0xD0, 0xAE, 0xD0, 0xBD, 0xD0, 0xB8, 0xD0, 0xBA, 0xD0, 0xBE, 0xD0, 0xB4], ::byte) +unicode_enc = [0x30, 0x4B, 0x37, 0x51, 0x76, 0x64, 0x43, 0x34, 0x30, 0x4C, 0x72, 0x51, 0x76, 0x74, 0x43, 0x30] + +def testBase64Encode() { + assertEquals(base64Example_enc, base64encode(base64Example)) + assertEquals(base64Example_enc, base64encode("Base64 Example")) + assertEquals(unicode_enc, base64encode(unicode)) + assertEquals(unicode_enc, base64encode("Юникод")) +} + +def testBase64EncodeToString() { + assertEquals("QmFzZTY0IEV4YW1wbGU=", base64encodeToString(base64Example)) + assertEquals("QmFzZTY0IEV4YW1wbGU=", base64encodeToString("Base64 Example")) + assertEquals("0K7QvdC40LrQvtC0", base64encodeToString(unicode)) + assertEquals("0K7QvdC40LrQvtC0", base64encodeToString("Юникод")) +} + +def testBase64Decode() { + assertEquals(base64Example, base64decode("QmFzZTY0IEV4YW1wbGU=")) + assertEquals(base64Example, base64decode(base64Example_enc)) + assertEquals(unicode, base64decode("0K7QvdC40LrQvtC0")) + assertEquals(unicode, base64decode(unicode_enc)) +} \ No newline at end of file