mirror of
https://github.com/Eaglercraft-TeaVM-Fork/eagler-teavm.git
synced 2024-12-22 08:14:09 -08:00
parent
dd0b9f70df
commit
ada086a864
|
@ -18,33 +18,47 @@ package org.teavm.classlib.impl;
|
|||
import java.util.Arrays;
|
||||
|
||||
public final class Base64Impl {
|
||||
private static byte[] alphabet = new byte[64];
|
||||
private static int[] reverse = new int[256];
|
||||
public static byte[] alphabet = new byte[64];
|
||||
public static byte[] urlAlphabet = new byte[64];
|
||||
public static int[] reverse = new int[256];
|
||||
public static int[] urlReverse = new int[256];
|
||||
|
||||
static {
|
||||
int i = 0;
|
||||
for (char c = 'A'; c <= 'Z'; ++c) {
|
||||
alphabet[i++] = (byte) c;
|
||||
alphabet[i] = (byte) c;
|
||||
urlAlphabet[i] = (byte) c;
|
||||
i++;
|
||||
}
|
||||
for (char c = 'a'; c <= 'z'; ++c) {
|
||||
alphabet[i++] = (byte) c;
|
||||
alphabet[i] = (byte) c;
|
||||
urlAlphabet[i] = (byte) c;
|
||||
i++;
|
||||
}
|
||||
for (char c = '0'; c <= '9'; ++c) {
|
||||
alphabet[i++] = (byte) c;
|
||||
alphabet[i] = (byte) c;
|
||||
urlAlphabet[i] = (byte) c;
|
||||
i++;
|
||||
}
|
||||
alphabet[i++] = '+';
|
||||
alphabet[i++] = '/';
|
||||
alphabet[i] = '+';
|
||||
urlAlphabet[i] = '-';
|
||||
i++;
|
||||
alphabet[i] = '/';
|
||||
urlAlphabet[i] = '_';
|
||||
i++;
|
||||
|
||||
Arrays.fill(reverse, -1);
|
||||
Arrays.fill(urlReverse, -1);
|
||||
for (i = 0; i < alphabet.length; ++i) {
|
||||
reverse[alphabet[i]] = i;
|
||||
urlReverse[urlAlphabet[i]] = i;
|
||||
}
|
||||
}
|
||||
|
||||
private Base64Impl() {
|
||||
}
|
||||
|
||||
public static byte[] decode(byte[] text) {
|
||||
public static byte[] decode(byte[] text, int[] mapping) {
|
||||
int outputSize = (text.length / 4) * 3;
|
||||
int rem = text.length % 4;
|
||||
if (rem == 2 || rem == 3) {
|
||||
|
@ -55,11 +69,15 @@ public final class Base64Impl {
|
|||
--outputSize;
|
||||
}
|
||||
byte[] output = new byte[outputSize];
|
||||
decode(text, output);
|
||||
decode(text, output, mapping);
|
||||
return output;
|
||||
}
|
||||
|
||||
public static void decode(byte[] text, byte[] output) {
|
||||
public static byte[] decode(byte[] text) {
|
||||
return decode(text, reverse);
|
||||
}
|
||||
|
||||
public static void decode(byte[] text, byte[] output, int[] mapping) {
|
||||
int inputSize = text.length;
|
||||
int i;
|
||||
for (i = text.length - 1; i >= 0 && text[i] == '='; --i) {
|
||||
|
@ -70,10 +88,10 @@ public final class Base64Impl {
|
|||
i = 0;
|
||||
int j = 0;
|
||||
while (i < triples) {
|
||||
int a = decode(text[i++]);
|
||||
int b = decode(text[i++]);
|
||||
int c = decode(text[i++]);
|
||||
int d = decode(text[i++]);
|
||||
int a = decode(mapping, text[i++]);
|
||||
int b = decode(mapping, text[i++]);
|
||||
int c = decode(mapping, text[i++]);
|
||||
int d = decode(mapping, text[i++]);
|
||||
int out = (a << 18) | (b << 12) | (c << 6) | d;
|
||||
output[j++] = (byte) (out >>> 16);
|
||||
output[j++] = (byte) (out >>> 8);
|
||||
|
@ -82,23 +100,23 @@ public final class Base64Impl {
|
|||
|
||||
int rem = inputSize - i;
|
||||
if (rem == 2) {
|
||||
int a = decode(text[i]);
|
||||
int b = decode(text[i + 1]);
|
||||
int a = decode(mapping, text[i]);
|
||||
int b = decode(mapping, text[i + 1]);
|
||||
output[j] = (byte) ((a << 2) | (b >>> 4));
|
||||
} else if (rem == 3) {
|
||||
int a = decode(text[i]);
|
||||
int b = decode(text[i + 1]);
|
||||
int c = decode(text[i + 2]);
|
||||
int a = decode(mapping, text[i]);
|
||||
int b = decode(mapping, text[i + 1]);
|
||||
int c = decode(mapping, text[i + 2]);
|
||||
output[j] = (byte) ((a << 2) | (b >>> 4));
|
||||
output[j + 1] = (byte) ((b << 4) | (c >>> 2));
|
||||
}
|
||||
}
|
||||
|
||||
private static int decode(byte c) {
|
||||
return reverse[c];
|
||||
private static int decode(int[] mapping, byte c) {
|
||||
return mapping[c];
|
||||
}
|
||||
|
||||
public static byte[] encode(byte[] data, boolean pad) {
|
||||
public static byte[] encode(byte[] data, byte[] mapping, boolean pad) {
|
||||
int outputSize = ((data.length + 2) / 3) * 4;
|
||||
if (!pad) {
|
||||
int rem = data.length % 3;
|
||||
|
@ -107,38 +125,42 @@ public final class Base64Impl {
|
|||
}
|
||||
}
|
||||
byte[] output = new byte[outputSize];
|
||||
encode(data, output, pad);
|
||||
encode(data, output, mapping, pad);
|
||||
return output;
|
||||
}
|
||||
|
||||
public static int encode(byte[] data, byte[] output, boolean pad) {
|
||||
public static byte[] encode(byte[] data, boolean pad) {
|
||||
return encode(data, alphabet, pad);
|
||||
}
|
||||
|
||||
public static int encode(byte[] data, byte[] output, byte[] mapping, boolean pad) {
|
||||
int triples = (data.length / 3) * 3;
|
||||
|
||||
int i = 0;
|
||||
int j;
|
||||
for (j = 0; j < triples;) {
|
||||
output[i++] = encode((byte) (data[j] >>> 2));
|
||||
output[i++] = encode((byte) ((data[j] << 4) | ((data[j + 1] & 0xFF) >>> 4)));
|
||||
output[i++] = encode(mapping, (byte) (data[j] >>> 2));
|
||||
output[i++] = encode(mapping, (byte) ((data[j] << 4) | ((data[j + 1] & 0xFF) >>> 4)));
|
||||
++j;
|
||||
output[i++] = encode((byte) ((data[j] << 2) | ((data[j + 1] & 0xFF) >>> 6)));
|
||||
output[i++] = encode(mapping, (byte) ((data[j] << 2) | ((data[j + 1] & 0xFF) >>> 6)));
|
||||
++j;
|
||||
output[i++] = encode(data[j]);
|
||||
output[i++] = encode(mapping, data[j]);
|
||||
++j;
|
||||
}
|
||||
|
||||
int rem = data.length - j;
|
||||
if (rem == 1) {
|
||||
output[i++] = encode((byte) (data[j] >>> 2));
|
||||
output[i++] = encode((byte) (data[j] << 4));
|
||||
output[i++] = encode(mapping, (byte) (data[j] >>> 2));
|
||||
output[i++] = encode(mapping, (byte) (data[j] << 4));
|
||||
if (pad) {
|
||||
output[i++] = '=';
|
||||
output[i++] = '=';
|
||||
}
|
||||
} else if (rem == 2) {
|
||||
output[i++] = encode((byte) (data[j] >>> 2));
|
||||
output[i++] = encode((byte) ((data[j] << 4) | (data[j + 1] >>> 4)));
|
||||
output[i++] = encode(mapping, (byte) (data[j] >>> 2));
|
||||
output[i++] = encode(mapping, (byte) ((data[j] << 4) | ((data[j + 1] & 0xFF) >>> 4)));
|
||||
++j;
|
||||
output[i++] = encode((byte) (data[j] << 2));
|
||||
output[i++] = encode(mapping, (byte) (data[j] << 2));
|
||||
if (pad) {
|
||||
output[i++] = '=';
|
||||
}
|
||||
|
@ -147,7 +169,7 @@ public final class Base64Impl {
|
|||
return i;
|
||||
}
|
||||
|
||||
private static byte encode(byte b) {
|
||||
return alphabet[b & 63];
|
||||
private static byte encode(byte[] mapping, byte b) {
|
||||
return mapping[b & 63];
|
||||
}
|
||||
}
|
||||
|
|
|
@ -0,0 +1,62 @@
|
|||
/*
|
||||
* Copyright 2023 ihromant.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
package org.teavm.classlib.java.util;
|
||||
|
||||
import org.teavm.classlib.impl.Base64Impl;
|
||||
|
||||
public class TBase64 {
|
||||
public static Encoder getEncoder() {
|
||||
return new Encoder(Base64Impl.alphabet, true);
|
||||
}
|
||||
|
||||
public static Encoder getUrlEncoder() {
|
||||
return new Encoder(Base64Impl.urlAlphabet, false);
|
||||
}
|
||||
|
||||
public static class Encoder {
|
||||
private final byte[] mapping;
|
||||
private final boolean padding;
|
||||
|
||||
private Encoder(byte[] mapping, boolean padding) {
|
||||
this.mapping = mapping;
|
||||
this.padding = padding;
|
||||
}
|
||||
|
||||
public byte[] encode(byte[] src) {
|
||||
return Base64Impl.encode(src, mapping, padding);
|
||||
}
|
||||
}
|
||||
|
||||
public Decoder getDecoder() {
|
||||
return new Decoder(Base64Impl.reverse);
|
||||
}
|
||||
|
||||
public Decoder getUrlDecoder() {
|
||||
return new Decoder(Base64Impl.urlReverse);
|
||||
}
|
||||
|
||||
public static class Decoder {
|
||||
private final int[] mapping;
|
||||
|
||||
private Decoder(int[] mapping) {
|
||||
this.mapping = mapping;
|
||||
}
|
||||
|
||||
public byte[] decode(byte[] src) {
|
||||
return Base64Impl.decode(src, mapping);
|
||||
}
|
||||
}
|
||||
}
|
|
@ -33,6 +33,7 @@ public class Base64Test {
|
|||
assertEquals("qwerty", decode("cXdlcnR5"));
|
||||
assertEquals("qwertyu", decode("cXdlcnR5dQ=="));
|
||||
assertEquals("qwertyu", decode("cXdlcnR5dQ"));
|
||||
assertEquals("юзернейм:пароль", decode("0Y7Qt9C10YDQvdC10LnQvDrQv9Cw0YDQvtC70Yw="));
|
||||
}
|
||||
|
||||
@Test
|
||||
|
@ -44,6 +45,7 @@ public class Base64Test {
|
|||
assertEquals("cXdlcnQ=", encode("qwert"));
|
||||
assertEquals("cXdlcnR5", encode("qwerty"));
|
||||
assertEquals("cXdlcnR5dQ==", encode("qwertyu"));
|
||||
assertEquals("0Y7Qt9C10YDQvdC10LnQvDrQv9Cw0YDQvtC70Yw=", encode("юзернейм:пароль"));
|
||||
}
|
||||
|
||||
@Test
|
||||
|
|
|
@ -0,0 +1,99 @@
|
|||
/*
|
||||
* Copyright 2023 ihromant.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
package org.teavm.classlib.impl;
|
||||
|
||||
import static org.junit.Assert.*;
|
||||
import java.io.UnsupportedEncodingException;
|
||||
import org.junit.Test;
|
||||
|
||||
@RunWith(TeaVMTestRunner.class)
|
||||
@WholeClassCompilation
|
||||
public class Base64Test {
|
||||
@Test
|
||||
public void decoderWorks() {
|
||||
Decoder decoder = Base64.getDecoder();
|
||||
assertEquals("q", decoder.decode("cQ=="));
|
||||
assertEquals("qw", decoder.decode("cXc="));
|
||||
assertEquals("qwe", decoder.decode("cXdl"));
|
||||
assertEquals("qwer", decoder.decode("cXdlcg=="));
|
||||
assertEquals("qwert", decoder.decode("cXdlcnQ="));
|
||||
assertEquals("qwerty", decoder.decode("cXdlcnR5"));
|
||||
assertEquals("qwertyu", decoder.decode("cXdlcnR5dQ=="));
|
||||
assertEquals("юзернейм:пароль", decoder.decode("0Y7Qt9C10YDQvdC10LnQvDrQv9Cw0YDQvtC70Yw="));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void encoderWorks() {
|
||||
Encoder encoder = Base64.getEncoder();
|
||||
assertEquals("cQ==", encoder.encode("q"));
|
||||
assertEquals("cXc=", encoder.encode("qw"));
|
||||
assertEquals("cXdl", encoder.encode("qwe"));
|
||||
assertEquals("cXdlcg==", encoder.encode("qwer"));
|
||||
assertEquals("cXdlcnQ=", encoder.encode("qwert"));
|
||||
assertEquals("cXdlcnR5", encoder.encode("qwerty"));
|
||||
assertEquals("cXdlcnR5dQ==", encoder.encode("qwertyu"));
|
||||
assertEquals("0Y7Qt9C10YDQvdC10LnQvDrQv9Cw0YDQvtC70Yw=", encoder.encode("юзернейм:пароль"));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void urlDecoderWorks() {
|
||||
Decoder decoder = Base64.getUrlDecoder();
|
||||
assertEquals("q", decoder.decode("cQ"));
|
||||
assertEquals("qw", decoder.decode("cXc"));
|
||||
assertEquals("qwe", decoder.decode("cXdl"));
|
||||
assertEquals("qwer", decoder.decode("cXdlcg"));
|
||||
assertEquals("qwerty", decoder.decode("cXdlcnR5"));
|
||||
assertEquals("qwertyu", decoder.decode("cXdlcnR5dQ"));
|
||||
assertEquals("юзернейм:пароль", decoder.decode("0Y7Qt9C10YDQvdC10LnQvDrQv9Cw0YDQvtC70Yw"));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void urlEncoderWorks() {
|
||||
Encoder encoder = Base64.getUrlEncoder();
|
||||
assertEquals("cQ", encoder.encodeNoPad("q"));
|
||||
assertEquals("cXc", encoder.encodeNoPad("qw"));
|
||||
assertEquals("cXdl", encoder.encodeNoPad("qwe"));
|
||||
assertEquals("cXdlcg", encoder.encodeNoPad("qwer"));
|
||||
assertEquals("cXdlcnQ", encoder.encodeNoPad("qwert"));
|
||||
assertEquals("cXdlcnR5", encoder.encodeNoPad("qwerty"));
|
||||
assertEquals("cXdlcnR5dQ", encoder.encodeNoPad("qwertyu"));
|
||||
assertEquals("0Y7Qt9C10YDQvdC10LnQvDrQv9Cw0YDQvtC70Yw", encoder.encode("юзернейм:пароль"));
|
||||
}
|
||||
|
||||
private String decode(String text) {
|
||||
try {
|
||||
return new String(Base64Impl.decode(text.getBytes("UTF-8")), "UTF-8");
|
||||
} catch (UnsupportedEncodingException e) {
|
||||
return "";
|
||||
}
|
||||
}
|
||||
|
||||
private String encode(String text) {
|
||||
try {
|
||||
return new String(Base64Impl.encode(text.getBytes("UTF-8"), true), "UTF-8");
|
||||
} catch (UnsupportedEncodingException e) {
|
||||
return "";
|
||||
}
|
||||
}
|
||||
|
||||
private String encodeNoPad(String text) {
|
||||
try {
|
||||
return new String(Base64Impl.encode(text.getBytes("UTF-8"), false), "UTF-8");
|
||||
} catch (UnsupportedEncodingException e) {
|
||||
return "";
|
||||
}
|
||||
}
|
||||
}
|
Loading…
Reference in New Issue
Block a user