/** * */ package mobvista.dmp.datasource.adn_sdk; import java.util.HashMap; import java.util.Map; /** * The implementation's mechanism is similar to BASE64, but encode table is not * same. So, it can't be decode by BASE64 decoder * * @author chaocai * Created at 2018.1.11 * Mintegral.com */ public class CommonMVEncoder { private static Map<Character, Character> Base64MapEncoder; private static Map<Character, Character> Base64MapDecoder; private static final char[] S_BASE64_CHAR = { 'A', 'B', 'C', 'D', 'E', 'F', 'G', 'H', 'I', 'J', 'K', 'L', 'M', 'N', 'O', 'P', 'Q', 'R', 'S', 'T', 'U', 'V', 'W', 'X', 'Y', 'Z', 'a', 'b', 'c', 'd', 'e', 'f', 'g', 'h', 'i', 'j', 'k', 'l', 'm', 'n', 'o', 'p', 'q', 'r', 's', 't', 'u', 'v', 'w', 'x', 'y', 'z', '0', '1', '2', '3', '4', '5', '6', '7', '8', '9', '+', '/' }; private static char[] S_MV_ENCODER_CHAR; // private static char[] S_MV_DECODER_CHAR; // static { // Base64MapDecoder = new HashMap<Character, Character>(); // Base64MapDecoder.put('v', 'A'); // Base64MapDecoder.put('S', 'B'); // Base64MapDecoder.put('o', 'C'); // Base64MapDecoder.put('a', 'D'); // Base64MapDecoder.put('j', 'E'); // Base64MapDecoder.put('c', 'F'); // Base64MapDecoder.put('7', 'G'); // Base64MapDecoder.put('d', 'H'); // Base64MapDecoder.put('R', 'I'); // Base64MapDecoder.put('z', 'J'); // Base64MapDecoder.put('p', 'K'); // Base64MapDecoder.put('W', 'L'); // Base64MapDecoder.put('i', 'M'); // Base64MapDecoder.put('f', 'N'); // Base64MapDecoder.put('G', 'O'); // Base64MapDecoder.put('y', 'P'); // Base64MapDecoder.put('N', 'Q'); // Base64MapDecoder.put('x', 'R'); // Base64MapDecoder.put('Z', 'S'); // Base64MapDecoder.put('n', 'T'); // Base64MapDecoder.put('V', 'U'); // Base64MapDecoder.put('5', 'V'); // Base64MapDecoder.put('k', 'W'); // Base64MapDecoder.put('+', 'X'); // Base64MapDecoder.put('D', 'Y'); // Base64MapDecoder.put('H', 'Z'); // Base64MapDecoder.put('L', 'a'); // Base64MapDecoder.put('Y', 'b'); // Base64MapDecoder.put('h', 'c'); // Base64MapDecoder.put('J', 'd'); // Base64MapDecoder.put('4', 'e'); // Base64MapDecoder.put('6', 'f'); // Base64MapDecoder.put('l', 'g'); // Base64MapDecoder.put('t', 'h'); // Base64MapDecoder.put('0', 'i'); // Base64MapDecoder.put('U', 'j'); // Base64MapDecoder.put('3', 'k'); // Base64MapDecoder.put('Q', 'l'); // Base64MapDecoder.put('r', 'm'); // Base64MapDecoder.put('g', 'n'); // Base64MapDecoder.put('E', 'o'); // Base64MapDecoder.put('u', 'p'); // Base64MapDecoder.put('q', 'q'); // Base64MapDecoder.put('8', 'r'); // Base64MapDecoder.put('s', 's'); // Base64MapDecoder.put('w', 't'); // Base64MapDecoder.put('/', 'u'); // Base64MapDecoder.put('X', 'v'); // Base64MapDecoder.put('M', 'w'); // Base64MapDecoder.put('e', 'x'); // Base64MapDecoder.put('B', 'y'); // Base64MapDecoder.put('A', 'z'); // Base64MapDecoder.put('T', '0'); // Base64MapDecoder.put('2', '1'); // Base64MapDecoder.put('F', '2'); // Base64MapDecoder.put('b', '3'); // Base64MapDecoder.put('9', '4'); // Base64MapDecoder.put('P', '5'); // Base64MapDecoder.put('1', '6'); // Base64MapDecoder.put('O', '7'); // Base64MapDecoder.put('I', '8'); // Base64MapDecoder.put('K', '9'); // Base64MapDecoder.put('m', '+'); // Base64MapDecoder.put('C', '/'); // S_MV_DECODER_CHAR = new char[S_BASE64_CHAR.length]; // for (int i = 0; i < S_BASE64_CHAR.length; i++) { // S_MV_DECODER_CHAR[i] = Base64MapDecoder.get(S_BASE64_CHAR[i]); // } // // } static { Base64MapEncoder = new HashMap<Character, Character>(); Base64MapEncoder.put('A', 'v'); Base64MapEncoder.put('B', 'S'); Base64MapEncoder.put('C', 'o'); Base64MapEncoder.put('D', 'a'); Base64MapEncoder.put('E', 'j'); Base64MapEncoder.put('F', 'c'); Base64MapEncoder.put('G', '7'); Base64MapEncoder.put('H', 'd'); Base64MapEncoder.put('I', 'R'); Base64MapEncoder.put('J', 'z'); Base64MapEncoder.put('K', 'p'); Base64MapEncoder.put('L', 'W'); Base64MapEncoder.put('M', 'i'); Base64MapEncoder.put('N', 'f'); Base64MapEncoder.put('O', 'G'); Base64MapEncoder.put('P', 'y'); Base64MapEncoder.put('Q', 'N'); Base64MapEncoder.put('R', 'x'); Base64MapEncoder.put('S', 'Z'); Base64MapEncoder.put('T', 'n'); Base64MapEncoder.put('U', 'V'); Base64MapEncoder.put('V', '5'); Base64MapEncoder.put('W', 'k'); Base64MapEncoder.put('X', '+'); Base64MapEncoder.put('Y', 'D'); Base64MapEncoder.put('Z', 'H'); Base64MapEncoder.put('a', 'L'); Base64MapEncoder.put('b', 'Y'); Base64MapEncoder.put('c', 'h'); Base64MapEncoder.put('d', 'J'); Base64MapEncoder.put('e', '4'); Base64MapEncoder.put('f', '6'); Base64MapEncoder.put('g', 'l'); Base64MapEncoder.put('h', 't'); Base64MapEncoder.put('i', '0'); Base64MapEncoder.put('j', 'U'); Base64MapEncoder.put('k', '3'); Base64MapEncoder.put('l', 'Q'); Base64MapEncoder.put('m', 'r'); Base64MapEncoder.put('n', 'g'); Base64MapEncoder.put('o', 'E'); Base64MapEncoder.put('p', 'u'); Base64MapEncoder.put('q', 'q'); Base64MapEncoder.put('r', '8'); Base64MapEncoder.put('s', 's'); Base64MapEncoder.put('t', 'w'); Base64MapEncoder.put('u', '/'); Base64MapEncoder.put('v', 'X'); Base64MapEncoder.put('w', 'M'); Base64MapEncoder.put('x', 'e'); Base64MapEncoder.put('y', 'B'); Base64MapEncoder.put('z', 'A'); Base64MapEncoder.put('0', 'T'); Base64MapEncoder.put('1', '2'); Base64MapEncoder.put('2', 'F'); Base64MapEncoder.put('3', 'b'); Base64MapEncoder.put('4', '9'); Base64MapEncoder.put('5', 'P'); Base64MapEncoder.put('6', '1'); Base64MapEncoder.put('7', 'O'); Base64MapEncoder.put('8', 'I'); Base64MapEncoder.put('9', 'K'); Base64MapEncoder.put('+', 'm'); Base64MapEncoder.put('/', 'C'); S_MV_ENCODER_CHAR = new char[S_BASE64_CHAR.length]; for (int i = 0; i < S_BASE64_CHAR.length; i++) { S_MV_ENCODER_CHAR[i] = Base64MapEncoder.get(S_BASE64_CHAR[i]); } } private static final char S_PAD = '='; private static final byte[] S_DECODETABLE = new byte[128]; static { for (int i = 0; i < S_DECODETABLE.length; i++) { S_DECODETABLE[i] = Byte.MAX_VALUE; // 127 } for (int i = 0; i < S_MV_ENCODER_CHAR.length; i++) // 0 to 63 { S_DECODETABLE[S_MV_ENCODER_CHAR[i]] = (byte) i; } } private static int decode0(char[] ibuf, byte[] obuf, int wp) { try { int outlen = 3; if (ibuf[3] == S_PAD) { outlen = 2; } if (ibuf[2] == S_PAD) { outlen = 1; } int b0 = S_DECODETABLE[ibuf[0]]; int b1 = S_DECODETABLE[ibuf[1]]; int b2 = S_DECODETABLE[ibuf[2]]; int b3 = S_DECODETABLE[ibuf[3]]; switch (outlen) { case 1: obuf[wp] = (byte) (b0 << 2 & 0xfc | b1 >> 4 & 0x3); return 1; case 2: obuf[wp++] = (byte) (b0 << 2 & 0xfc | b1 >> 4 & 0x3); obuf[wp] = (byte) (b1 << 4 & 0xf0 | b2 >> 2 & 0xf); return 2; case 3: obuf[wp++] = (byte) (b0 << 2 & 0xfc | b1 >> 4 & 0x3); obuf[wp++] = (byte) (b1 << 4 & 0xf0 | b2 >> 2 & 0xf); obuf[wp] = (byte) (b2 << 6 & 0xc0 | b3 & 0x3f); return 3; default: throw new RuntimeException("Internal Error"); } }catch (Exception e){ } return 0; } /** * Decode the data. * * @param data * The encoded data to be decoded * @param off * The offset within the encoded data at which to start decoding * @param len * The length of data to decode * @return The decoded data */ public static byte[] decode(char[] data, int off, int len) { try { char[] ibuf = new char[4]; int ibufcount = 0; byte[] obuf = new byte[(len >> 2) * 3 + 3]; int obufcount = 0; for (int i = off; i < off + len; i++) { char ch = data[i]; if (ch == S_PAD || ch < S_DECODETABLE.length && S_DECODETABLE[ch] != Byte.MAX_VALUE) { ibuf[ibufcount++] = ch; if (ibufcount == ibuf.length) { ibufcount = 0; obufcount += decode0(ibuf, obuf, obufcount); } } } if (obufcount == obuf.length) { return obuf; } byte[] ret = new byte[obufcount]; System.arraycopy(obuf, 0, ret, 0, obufcount); return ret; }catch (Exception e){ } return null; } public static final int BUF_SIZE = 256; /** * Decode the data. * * @param data * The encoded data to be decoded * @return The decoded data */ public static String decodeStr(String data) { byte[] bytes = decode(data); if(bytes != null && bytes.length > 0){ return new String(bytes); } return null; } /** * Decode the data. * * @param data * The encoded data to be decoded * @return The decoded data */ public static byte[] decode(String data) { try{ int ibufcount = 0; int slen = data.length(); char[] ibuf = new char[slen < BUF_SIZE + 3 ? slen : BUF_SIZE + 3]; byte[] obuf = new byte[(slen >> 2) * 3 + 3]; int obufcount = 0; int blen; for (int i = 0; i < slen; i += BUF_SIZE) { // buffer may contain unprocessed characters from previous step if (i + BUF_SIZE <= slen) { data.getChars(i, i + BUF_SIZE, ibuf, ibufcount); blen = BUF_SIZE + ibufcount; } else { data.getChars(i, slen, ibuf, ibufcount); blen = slen - i + ibufcount; } for (int j = ibufcount; j < blen; j++) { char ch = ibuf[j]; if (ch == S_PAD || ch < S_DECODETABLE.length && S_DECODETABLE[ch] != Byte.MAX_VALUE) { ibuf[ibufcount++] = ch; // as soon as we have 4 chars process them if (ibufcount == 4) { ibufcount = 0; obufcount += decode0(ibuf, obuf, obufcount); } } } } if (obufcount == obuf.length) { return obuf; } byte[] ret = new byte[obufcount]; System.arraycopy(obuf, 0, ret, 0, obufcount); return ret; }catch (Exception e){ } return null; } /** * Returns representation of specified byte array. * * @param data * The data to be encoded * @return The encoded data */ public static String encodeStr(String data) { return encode(data.getBytes()); } /** * Returns representation of specified byte array. * * @param data * The data to be encoded * @return The encoded data */ public static String encode(byte[] data) { return encode(data, 0, data.length); } /** * Returns base64 representation of specified byte array. * * @param data * The data to be encoded * @param off * The offset within the data at which to start encoding * @param len * The length of the data to encode * @return The base64 encoded data */ public static String encode(byte[] data, int off, int len) { try{ if (len <= 0) { return ""; } char[] out = new char[(len / 3 << 2) + 4]; int rindex = off; int windex = 0; int rest = len; while (rest >= 3) { int i = ((data[rindex] & 0xff) << 16) + ((data[rindex + 1] & 0xff) << 8) + (data[rindex + 2] & 0xff); out[windex++] = S_MV_ENCODER_CHAR[i >> 18]; out[windex++] = S_MV_ENCODER_CHAR[(i >> 12) & 0x3f]; out[windex++] = S_MV_ENCODER_CHAR[(i >> 6) & 0x3f]; out[windex++] = S_MV_ENCODER_CHAR[i & 0x3f]; rindex += 3; rest -= 3; } if (rest == 1) { int i = data[rindex] & 0xff; out[windex++] = S_MV_ENCODER_CHAR[i >> 2]; out[windex++] = S_MV_ENCODER_CHAR[(i << 4) & 0x3f]; out[windex++] = S_PAD; out[windex++] = S_PAD; } else if (rest == 2) { int i = ((data[rindex] & 0xff) << 8) + (data[rindex + 1] & 0xff); out[windex++] = S_MV_ENCODER_CHAR[i >> 10]; out[windex++] = S_MV_ENCODER_CHAR[(i >> 4) & 0x3f]; out[windex++] = S_MV_ENCODER_CHAR[(i << 2) & 0x3f]; out[windex++] = S_PAD; } return new String(out, 0, windex); }catch (Exception e){ } return null; } }