mirror of
https://github.com/Eaglercraft-TeaVM-Fork/eagler-teavm.git
synced 2024-12-22 16:14:10 -08:00
parent
dd0b9f70df
commit
ada086a864
|
@ -18,33 +18,47 @@ package org.teavm.classlib.impl;
|
||||||
import java.util.Arrays;
|
import java.util.Arrays;
|
||||||
|
|
||||||
public final class Base64Impl {
|
public final class Base64Impl {
|
||||||
private static byte[] alphabet = new byte[64];
|
public static byte[] alphabet = new byte[64];
|
||||||
private static int[] reverse = new int[256];
|
public static byte[] urlAlphabet = new byte[64];
|
||||||
|
public static int[] reverse = new int[256];
|
||||||
|
public static int[] urlReverse = new int[256];
|
||||||
|
|
||||||
static {
|
static {
|
||||||
int i = 0;
|
int i = 0;
|
||||||
for (char c = 'A'; c <= 'Z'; ++c) {
|
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) {
|
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) {
|
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(reverse, -1);
|
||||||
|
Arrays.fill(urlReverse, -1);
|
||||||
for (i = 0; i < alphabet.length; ++i) {
|
for (i = 0; i < alphabet.length; ++i) {
|
||||||
reverse[alphabet[i]] = i;
|
reverse[alphabet[i]] = i;
|
||||||
|
urlReverse[urlAlphabet[i]] = i;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private Base64Impl() {
|
private Base64Impl() {
|
||||||
}
|
}
|
||||||
|
|
||||||
public static byte[] decode(byte[] text) {
|
public static byte[] decode(byte[] text, int[] mapping) {
|
||||||
int outputSize = (text.length / 4) * 3;
|
int outputSize = (text.length / 4) * 3;
|
||||||
int rem = text.length % 4;
|
int rem = text.length % 4;
|
||||||
if (rem == 2 || rem == 3) {
|
if (rem == 2 || rem == 3) {
|
||||||
|
@ -55,11 +69,15 @@ public final class Base64Impl {
|
||||||
--outputSize;
|
--outputSize;
|
||||||
}
|
}
|
||||||
byte[] output = new byte[outputSize];
|
byte[] output = new byte[outputSize];
|
||||||
decode(text, output);
|
decode(text, output, mapping);
|
||||||
return output;
|
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 inputSize = text.length;
|
||||||
int i;
|
int i;
|
||||||
for (i = text.length - 1; i >= 0 && text[i] == '='; --i) {
|
for (i = text.length - 1; i >= 0 && text[i] == '='; --i) {
|
||||||
|
@ -70,10 +88,10 @@ public final class Base64Impl {
|
||||||
i = 0;
|
i = 0;
|
||||||
int j = 0;
|
int j = 0;
|
||||||
while (i < triples) {
|
while (i < triples) {
|
||||||
int a = decode(text[i++]);
|
int a = decode(mapping, text[i++]);
|
||||||
int b = decode(text[i++]);
|
int b = decode(mapping, text[i++]);
|
||||||
int c = decode(text[i++]);
|
int c = decode(mapping, text[i++]);
|
||||||
int d = decode(text[i++]);
|
int d = decode(mapping, text[i++]);
|
||||||
int out = (a << 18) | (b << 12) | (c << 6) | d;
|
int out = (a << 18) | (b << 12) | (c << 6) | d;
|
||||||
output[j++] = (byte) (out >>> 16);
|
output[j++] = (byte) (out >>> 16);
|
||||||
output[j++] = (byte) (out >>> 8);
|
output[j++] = (byte) (out >>> 8);
|
||||||
|
@ -82,23 +100,23 @@ public final class Base64Impl {
|
||||||
|
|
||||||
int rem = inputSize - i;
|
int rem = inputSize - i;
|
||||||
if (rem == 2) {
|
if (rem == 2) {
|
||||||
int a = decode(text[i]);
|
int a = decode(mapping, text[i]);
|
||||||
int b = decode(text[i + 1]);
|
int b = decode(mapping, text[i + 1]);
|
||||||
output[j] = (byte) ((a << 2) | (b >>> 4));
|
output[j] = (byte) ((a << 2) | (b >>> 4));
|
||||||
} else if (rem == 3) {
|
} else if (rem == 3) {
|
||||||
int a = decode(text[i]);
|
int a = decode(mapping, text[i]);
|
||||||
int b = decode(text[i + 1]);
|
int b = decode(mapping, text[i + 1]);
|
||||||
int c = decode(text[i + 2]);
|
int c = decode(mapping, text[i + 2]);
|
||||||
output[j] = (byte) ((a << 2) | (b >>> 4));
|
output[j] = (byte) ((a << 2) | (b >>> 4));
|
||||||
output[j + 1] = (byte) ((b << 4) | (c >>> 2));
|
output[j + 1] = (byte) ((b << 4) | (c >>> 2));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private static int decode(byte c) {
|
private static int decode(int[] mapping, byte c) {
|
||||||
return reverse[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;
|
int outputSize = ((data.length + 2) / 3) * 4;
|
||||||
if (!pad) {
|
if (!pad) {
|
||||||
int rem = data.length % 3;
|
int rem = data.length % 3;
|
||||||
|
@ -107,38 +125,42 @@ public final class Base64Impl {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
byte[] output = new byte[outputSize];
|
byte[] output = new byte[outputSize];
|
||||||
encode(data, output, pad);
|
encode(data, output, mapping, pad);
|
||||||
return output;
|
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 triples = (data.length / 3) * 3;
|
||||||
|
|
||||||
int i = 0;
|
int i = 0;
|
||||||
int j;
|
int j;
|
||||||
for (j = 0; j < triples;) {
|
for (j = 0; j < triples;) {
|
||||||
output[i++] = encode((byte) (data[j] >>> 2));
|
output[i++] = encode(mapping, (byte) (data[j] >>> 2));
|
||||||
output[i++] = encode((byte) ((data[j] << 4) | ((data[j + 1] & 0xFF) >>> 4)));
|
output[i++] = encode(mapping, (byte) ((data[j] << 4) | ((data[j + 1] & 0xFF) >>> 4)));
|
||||||
++j;
|
++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;
|
++j;
|
||||||
output[i++] = encode(data[j]);
|
output[i++] = encode(mapping, data[j]);
|
||||||
++j;
|
++j;
|
||||||
}
|
}
|
||||||
|
|
||||||
int rem = data.length - j;
|
int rem = data.length - j;
|
||||||
if (rem == 1) {
|
if (rem == 1) {
|
||||||
output[i++] = encode((byte) (data[j] >>> 2));
|
output[i++] = encode(mapping, (byte) (data[j] >>> 2));
|
||||||
output[i++] = encode((byte) (data[j] << 4));
|
output[i++] = encode(mapping, (byte) (data[j] << 4));
|
||||||
if (pad) {
|
if (pad) {
|
||||||
output[i++] = '=';
|
output[i++] = '=';
|
||||||
output[i++] = '=';
|
output[i++] = '=';
|
||||||
}
|
}
|
||||||
} else if (rem == 2) {
|
} else if (rem == 2) {
|
||||||
output[i++] = encode((byte) (data[j] >>> 2));
|
output[i++] = encode(mapping, (byte) (data[j] >>> 2));
|
||||||
output[i++] = encode((byte) ((data[j] << 4) | (data[j + 1] >>> 4)));
|
output[i++] = encode(mapping, (byte) ((data[j] << 4) | ((data[j + 1] & 0xFF) >>> 4)));
|
||||||
++j;
|
++j;
|
||||||
output[i++] = encode((byte) (data[j] << 2));
|
output[i++] = encode(mapping, (byte) (data[j] << 2));
|
||||||
if (pad) {
|
if (pad) {
|
||||||
output[i++] = '=';
|
output[i++] = '=';
|
||||||
}
|
}
|
||||||
|
@ -147,7 +169,7 @@ public final class Base64Impl {
|
||||||
return i;
|
return i;
|
||||||
}
|
}
|
||||||
|
|
||||||
private static byte encode(byte b) {
|
private static byte encode(byte[] mapping, byte b) {
|
||||||
return alphabet[b & 63];
|
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("qwerty", decode("cXdlcnR5"));
|
||||||
assertEquals("qwertyu", decode("cXdlcnR5dQ=="));
|
assertEquals("qwertyu", decode("cXdlcnR5dQ=="));
|
||||||
assertEquals("qwertyu", decode("cXdlcnR5dQ"));
|
assertEquals("qwertyu", decode("cXdlcnR5dQ"));
|
||||||
|
assertEquals("юзернейм:пароль", decode("0Y7Qt9C10YDQvdC10LnQvDrQv9Cw0YDQvtC70Yw="));
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
|
@ -44,6 +45,7 @@ public class Base64Test {
|
||||||
assertEquals("cXdlcnQ=", encode("qwert"));
|
assertEquals("cXdlcnQ=", encode("qwert"));
|
||||||
assertEquals("cXdlcnR5", encode("qwerty"));
|
assertEquals("cXdlcnR5", encode("qwerty"));
|
||||||
assertEquals("cXdlcnR5dQ==", encode("qwertyu"));
|
assertEquals("cXdlcnR5dQ==", encode("qwertyu"));
|
||||||
|
assertEquals("0Y7Qt9C10YDQvdC10LnQvDrQv9Cw0YDQvtC70Yw=", encode("юзернейм:пароль"));
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@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