import javafx.util.Pair;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.Map;

public class FormatUtil {
    private static final String ERROR = "error";
    private static final char MASK = '*';
    private static final char FILL = '.';
    private static final Map<Character, Short> mapping = new HashMap<>();

    private static final int STEP_0 = 0;
    private static final int STEP_3 = 1;
    private static final int STEP_15 = 2;
    private static final int STEP_OVER_15 = 3;


    private static final HeadBuilder hBuilder = new HeadBuilder();
    private static final ContentBuilder cBuilder = new ContentBuilder();

    public static void parseMapping(String s) {
        try {
            s = s.trim().replaceAll("\n", "");
            String content = s.substring(1, s.length() - 1);
            if (!s.startsWith("{") || !s.endsWith("}")) {
                throw new Exception(" mapping {} format error");
            }
            String[] mappings = content.split(",");
            String temp;
            String[] t;
            for (String s1 : mappings) {
                s1 = s1.trim();
                if (!s1.startsWith("[") || !s1.endsWith("]"))
                    throw new Exception(" mapping [] format error");
                temp = s1.substring(1, s1.length() - 1);
                t = temp.split(":");
                mapping.put(t[0].charAt(0), Short.valueOf(t[1]));
            }
        } catch (Exception e) {
            Log.e("Format", e.getMessage());
        }
    }

    /**
     * 压缩
     */
    public static String on(String s) {
        if (s == null || s.isEmpty())
            return ERROR;
        try {
            char[] header = hBuilder.build(s);
            short[] shorts = cBuilder.build(s);

            StringBuilder stringBuilder = new StringBuilder();
            for (char ch : header) {
                stringBuilder.append(ch);
            }
            for (int x : shorts) {
                stringBuilder.append((char) x);
            }
            return stringBuilder.toString();
        } catch (Exception e) {
            Log.e("format error :", s);
        }
        return ERROR;
    }

    /**
     * 解压缩
     */
    public static String off(String s) {
        if (s == null || s.isEmpty())
            return ERROR;
        try {
            char[] chars = hBuilder.unBuild(s);
            StringBuilder stringBuilder = new StringBuilder(chars.length * 3);
            for (char c : chars) {
                stringBuilder.append(cBuilder.getOriginalChar((short) c));
            }
            //删除填充的小数点
            cBuilder.trimPoint(stringBuilder);
            cBuilder.trimPoint(stringBuilder);

            for (int i : hBuilder.upCharIndex) {
                stringBuilder.replace(i, i + 1, stringBuilder.substring(i, i + 1).toUpperCase());
            }
            return stringBuilder.toString();
        } catch (Exception e) {
            Log.e("Format off error:", e.getMessage());
        }
        return ERROR;
    }


    static final class HeadBuilder {

        private final ArrayList<Integer> upCharIndex = new ArrayList<>(8);

        public char[] build(String s) {
            int len = s.length();
            upCharIndex.clear();
            int maxDistance = 0;
            int lastIndex = 0, upCharCount = 0;
            char c;
            boolean b;

            for (int i = 0; i < len; i++) {
                c = s.charAt(i);
                b = Character.isUpperCase(c);
                if (b || c == FILL) {
                    if (i - lastIndex >= maxDistance) {
                        maxDistance = i - lastIndex;
                    }
                    upCharIndex.add(i - lastIndex);
                    lastIndex = i;
                }
                if (b) upCharCount++;
            }
            if (upCharCount == 0) {
                char empty = FILL;
                empty &= 0;
                return new char[]{empty};
            }
            int type = stepType(maxDistance);
            return handleHead(type);
        }

        public char[] unBuild(String s) {
            char[] chars = s.toCharArray();
            Pair<Integer, Integer> info = getInfoByHeadChar(chars[0]);

            int size = getSizeByType(info.getValue()) + 1;
            if (info.getKey() != 0) {
                char[] c = new char[size];
                System.arraycopy(chars, 0, c, 0, size);
                unHandleHead(c, info.getKey(), size);
            }
            char[] c2 = new char[chars.length - size];
            System.arraycopy(chars, size, c2, 0, chars.length - size);
            return c2;
        }


        private void unHandleHead(char[] c, int stepType, int size) {
            upCharIndex.clear();
            int distance = getStepDistance(stepType);
            if (distance != 0) {
                int flag = getBitFlag(distance);
                int d1 = 12 / distance;
                int d2 = 16 / distance;
                for (int i = 0; i < size; i++) {
                    if (i == 0) {
                        recoverCharIndex(c[i] << 4, d1, flag, distance);
                    } else {
                        recoverCharIndex(c[i], d2, flag, distance);
                    }
                }
            }
        }

        private void recoverCharIndex(int s, int d, int f, int distance) {
            int k;
            int index;
            int lastIndex = upCharIndex.isEmpty() ? 0 : upCharIndex.get(upCharIndex.size() - 1);
            for (k = 1; k <= d; k++) {
                index = s & f;
                if (distance == 3)
                    index >>= 13;
                else if (distance == 4)
                    index >>= 12;
                else if (distance == 6)
                    index >>= 10;
                else {
                    continue;
                }
                if (upCharIndex.size() != 0 && index == 0)
                    return;
                index = lastIndex + index;
                upCharIndex.add(index);
                lastIndex = index;
                s = s << distance;
            }
        }

        private int getBitFlag(int d) {
            if (d == 3)
                return 7 << 13;
            if (d == 4)
                return 15 << 12;
            return 63 << 10;
        }


        /**
         * 从首字符中取出,步长类型,填充字符个数类型
         *
         * @param h 首字符
         * @return first:步长类型,second:填充字符个数类型
         */
        public Pair<Integer, Integer> getInfoByHeadChar(char h) {
            int stepType = h & 49152;//2^15+2^14;
            int sizeType = h << 2 & 49152;
            return new Pair<>(stepType >> 14, sizeType >> 14);
        }


        private char[] handleHead(int type) {
            char ch = FILL;
            ch &= 0;
            ch = bitToLeft(ch, type, 14);
            if (upCharIndex.size() == 0)
                return new char[]{ch};
            int stepDistance = getStepDistance(type);
            int ch1 = 12 / stepDistance;

            //每个字符可以存储几个位置
            int sizeOfChar = 16 / stepDistance;
            int size = upCharIndex.size() - ch1;
            if (size < 0) {
                size = 0;
                ch1 = upCharIndex.size();
            }
            int n = (size % sizeOfChar == 0) ? 0 : 1;
            size = size / sizeOfChar + n;
            char[] chars = new char[size + 1];
            ch = bitToLeft(ch, getTypeBySize(size), 12);

            int k, j;
            //记录大写字母位置与char中
            for (int i = 0; i < chars.length; i++) {
                if (i == 0) {
                    for (j = 0, k = 1; j < ch1; j++, k++) {
                        ch = bitToLeft(ch, upCharIndex.get(j), 12 - (k * stepDistance));
                    }
                    chars[i] = ch;
                } else {
                    char emptyCh = FILL;
                    emptyCh &= 0;
                    int start = (i - 1) * sizeOfChar + ch1;
                    for (j = start, k = 1; j < start + sizeOfChar; j++, k++) {
                        if (j == upCharIndex.size())
                            break;
                        emptyCh = bitToLeft(emptyCh, upCharIndex.get(j), 16 - (k * stepDistance));
                    }
                    chars[i] = emptyCh;
                }
            }
            return chars;
        }


        private char bitToLeft(char c, int i, int site) {
            c |= i << site;
            return c;
        }


        /**
         * 获取步长。
         *
         * @param maxDistance 最长字符串
         * @return 类型 STEP_0:长度为0,STEP_3:长度小于8的字符串,其他雷同。
         */
        public int stepType(int maxDistance) {
            if (maxDistance == 0)
                return STEP_0;
            if (maxDistance < 8) {
                return STEP_3;
            }
            if (maxDistance > 15) {
                return STEP_OVER_15;
            }
            return STEP_15;
        }


        /**
         * 目前填充字符最大为3,如有更大,直接废弃。
         */
        public int getTypeBySize(int size) {
            return size;
        }

        public int getSizeByType(int t) {
            return t;
        }

        private int getStepDistance(int type) {
            if (type == 0)
                return 0;
            if (type == 1)
                return 3;
            return type == STEP_15 ? 4 : 6;
        }


    }

    static final class ContentBuilder {

        public short[] build(String s) {

            s = handleString(s);

            char[] chars = s.toCharArray();
            short[] shorts = new short[chars.length / 3];

            for (int i = 0, j = 0; i < chars.length; i += 3, j++) {
                shorts[j] = buildShort(chars[i], chars[i + 1], chars[i + 2]);
            }
            return shorts;
        }

        public String handleString(String s) {
            int f;
            if ((f = s.length() % 3) != 0) {
                StringBuilder sBuilder = new StringBuilder(s);
                for (f = 3 - f; f > 0; f--)
                    sBuilder.append(FILL);
                s = sBuilder.toString();
            }
            return s.toLowerCase();
        }


        public void trimPoint(StringBuilder stringBuilder) {
            if (stringBuilder.lastIndexOf(String.valueOf(FILL)) == stringBuilder.length() - 1)
                stringBuilder.deleteCharAt(stringBuilder.length() - 1);
        }

        public String getOriginalChar(short s) {
            int low = s & 31;
            int mid = s >> 5 & 31;
            int high = s >> 10 & 31;
            Character[] characters = new Character[3];
            int count = 0;
            for (Map.Entry<Character, Short> entry : mapping.entrySet()) {
                if (entry.getValue() == high) {
                    characters[0] = entry.getKey();
                    ++count;
                }
                if (entry.getValue() == mid) {
                    characters[1] = entry.getKey();
                    ++count;
                }
                if (entry.getValue() == low) {
                    characters[2] = entry.getKey();
                    ++count;
                }
                if (count == 3)
                    break;
            }

            return String.valueOf(characters[0]) + characters[1] +
                    characters[2];
        }

        /**
         * 将三个short合并成一个short
         *
         * @param high 合并到新Short的高位
         * @param mid  合并到新mid的中间位
         * @param low  合并到新Short的地位
         * @return 新Short
         */
        public short buildShort(char high, char mid, char low) {
            short b = 0;

            b |= getShortFromMapping(high) << 10;
            b |= getShortFromMapping(mid) << 5;
            b |= getShortFromMapping(low);
            return b;
        }

        public short getShortFromMapping(char ch) {
            if (mapping.containsKey(ch))
                return mapping.get(ch);
            return mapping.get(MASK);
        }
    }

}
Copy the code