All Downloads are FREE. Search and download functionalities are using the official Maven repository.

com.moon.core.json.JSONParser Maven / Gradle / Ivy

package com.moon.core.json;

import com.moon.core.lang.StringUtil;
import com.moon.core.lang.ThrowUtil;
import com.moon.core.lang.ref.IntAccessor;

import java.util.Objects;

/**
 * @author moonsky
 */
final class JSONParser {

    final static char QUOTES = '\"';
    final static char LEFT_O = '{';
    final static char LEFT_A = '[';
    final static char RIGHT_O = '}';
    final static char RIGHT_A = ']';
    final static char COLON = ':';
    final static char COMMA = ',';
    final static char DOT = '.';

    private final static char a = 'a';
    private final static char e = 'e';
    private final static char f = 'f';
    private final static char l = 'l';
    private final static char n = 'n';
    private final static char r = 'r';
    private final static char s = 's';
    private final static char t = 't';
    private final static char u = 'u';

    final static char COMMENT_F = '/';
    final static char BACKSLASH = '\\';

    final static int WIN_FIRST_CHAR = 65279;

    final static Boolean TRUE = Boolean.TRUE;
    final static Boolean FALSE = Boolean.FALSE;

    IntAccessor accessor = IntAccessor.of(0);

    private String source;

    private int length;

    private JSON data;

    public JSONParser(String source) {
        this.source = source;
        if (StringUtil.isWebUndefined(source)) {
            this.data = null;
        } else {
            this.length = source.length();
        }
    }

    public JSON toJSON() {
        if (data == null) {
            parse(this.source, this.source.length());
        }
        return data;
    }

    public JSON getData() {
        return toJSON();
    }

    private char startIndexChar() {
        int i = 0;
        int len = this.length;
        char ch;
        do {
            ch = source.charAt(i);
            if (ch != WIN_FIRST_CHAR && ch != 0 && !Character.isWhitespace(ch)) {
                accessor.set(i + 1);
                return ch;
            }
            i++;
        } while (i < len);
        return ThrowUtil.runtime("Not any content of json: " + source);
    }

    /**
     * 返回第一个不为空的字符
     *
     * @param source
     * @param len
     * @param accessor
     * @return
     */
    private char skipWriteSpace(final String source, final int len, IntAccessor accessor) {
        int i = accessor.get();

        char ch;
        for (; i < len; i++) {
            ch = source.charAt(i);
            if (Character.isWhitespace(ch)) {
                continue;
            }
            accessor.set(i + 1);
            return ch;
        }
        return ThrowUtil.runtime(source);
    }

    private void checkRestChars(final String source, IntAccessor accessor) {
        int i = accessor.get();
        int len = length;
        char ch;
        for (; i < len; i++) {
            ch = source.charAt(i);
            if (Character.isWhitespace(ch)) {
                continue;
            }
            ThrowUtil.runtime(
                source.substring(accessor.get()));
        }
    }

    public void parse(final String source, final int len) {
        char curr = startIndexChar();
        Object json = parseNext(source, len, curr);
        if (json == null) {
            data = null;
        } else if (json == TRUE) {
            data = JSONBoolean.TRUE;
        } else if (json == FALSE) {
            data = JSONBoolean.FALSE;
        } else if (json instanceof Double) {
            data = new JSONNumber((double) json);
        } else if (json instanceof String) {
            data = new JSONString((String) json);
        } else if (json instanceof JSONArray) {
            data = (JSONArray) json;
        } else if (json instanceof JSONObject) {
            data = (JSONObject) json;
        } else {
            ThrowUtil.runtime(source);
        }
        checkRestChars(source, accessor);
    }

    private Object parseNext(final String source, final int len, char curr) {
        switch (curr) {
            /**
             * 对象
             */
            case LEFT_O:
                return parseObject(source, len, new JSONObject());
            /**
             * 数组
             */
            case LEFT_A:
                return parseArray(source, len, new JSONArray());
            /**
             * 字符串
             */
            case QUOTES:
                return parseString(source, len);
            /**
             * true
             */
            case t:
                return parseBoolean(source, curr);
            /**
             * false
             */
            case f:
                return parseBoolean(source, curr);
            /**
             * null
             */
            case n:
                return parseNull(source, curr);
            default:
                if (Character.isDigit(curr)) {
                    return parseDouble(source, len, curr);
                } else {
                    return ThrowUtil.runtime(source);
                }
        }
    }

    private JSONArray parseArray(final String source, final int len, JSONArray ret) {
        char curr = skipWriteSpace(source, len, accessor);
        if (curr == RIGHT_A) {
            return ret;
        }
        if (curr == COMMA) {
            curr = skipWriteSpace(source, len, accessor);
        }
        ret.add(parseNext(source, len, curr));
        if (skipWriteSpace(source, len, accessor) == RIGHT_A) {
            return ret;
        }
        return parseArray(source, len, ret);
    }

    private JSONObject parseObject(final String source, final int len, JSONObject ret) {
        char curr = skipWriteSpace(source, len, accessor);
        if (curr == QUOTES) {
            String key = parseString(source, len);
            curr = skipWriteSpace(source, len, accessor);
            if (curr == COLON) {
                curr = skipWriteSpace(source, len, accessor);
                Object value = parseNext(source, len, curr);
                curr = skipWriteSpace(source, len, accessor);
                if (curr == COMMA) {
                    ret.put(key, value);
                    return parseObject(source, len, ret);
                } else if (curr == RIGHT_O) {
                    ret.put(key, value);
                    return ret;
                }
            }
        } else if (curr == RIGHT_O) {
            return ret;
        }
        return ThrowUtil.runtime(source.substring(accessor.get()));
    }

    private Object parseNull(final String source, final char curr) {
        int idx = accessor.get();
        if (curr == n
            && source.charAt(idx++) == u
            && source.charAt(idx++) == l
            && source.charAt(idx++) == l) {
            accessor.set(idx);
            return null;
        }
        return ThrowUtil.runtime(source.substring(accessor.get()));
    }

    private Object parseBoolean(final String source, final char curr) {
        int idx = accessor.get();
        if (curr == t) {
            if (source.charAt(idx++) == r
                && source.charAt(idx++) == u
                && source.charAt(idx++) == e) {
                accessor.set(idx);
                return true;
            }
        } else if (curr == f) {
            if (source.charAt(idx++) == a
                && source.charAt(idx++) == l
                && source.charAt(idx++) == s
                && source.charAt(idx++) == e) {
                accessor.set(idx);
                return false;
            }
        }
        return ThrowUtil.runtime(source.substring(accessor.get()));
    }

    /**
     * 通过
     *
     * @param source
     * @param len
     * @return
     */
    private Number parseDouble(final String source, final int len, final char curr) {
        int size = 8, index = 0;
        char[] cache = setChar(new char[size], curr, index++, size), newCache;
        final int start = accessor.get();

        char ch, dot = DOT;
        boolean isDouble = false;
        for (int i = start; i < len; i++) {
            ch = source.charAt(i);
            if (Character.isDigit(ch)) {
                newCache = setChar(cache, ch, index++, size);
                if (newCache != cache) {
                    cache = newCache;
                    size = newCache.length;
                }
                continue;
            }

            if (ch == dot) {
                if (isDouble) {
                    ThrowUtil.runtime(source.substring(start, len));
                }
                isDouble = true;
                newCache = setChar(cache, ch, index++, size);
                if (newCache != cache) {
                    cache = newCache;
                    size = newCache.length;
                }
                continue;
            }

            accessor.set(i);
            String str = toStr(cache, index);
            return isDouble ? Double.valueOf(str) : Long.parseLong(str);
        }
        return ThrowUtil.runtime(source);
    }

    /**
     * 通过
     *
     * @param source
     * @param len
     * @return
     */
    private String parseString(final String source, final int len) {
        int size = 16, index = 0;

        char[] cache = new char[size], newCache;
        final int start = accessor.get();

        char curr, end = QUOTES;
        for (int i = start; i < len; i++) {
            curr = source.charAt(i);
            if (curr == end) {
                accessor.set(i + 1);
                return i == start ? "" : toStr(cache, index);
            } else if (curr == BACKSLASH) {
                newCache = parseEscapeChar(source, i++, curr, cache, index++, size);
                if (newCache != cache) {
                    cache = newCache;
                    size = newCache.length;
                }
            } else {
                newCache = setChar(cache, curr, index++, size);
                if (newCache != cache) {
                    cache = newCache;
                    size = newCache.length;
                }
            }
        }
        return ThrowUtil.runtime(source.substring(start));
    }

    private char[] parseEscapeChar(final String source, int srcIndex, char curr,
                                   char[] chars, int arrIndex, int len) {
        char ch = source.charAt(srcIndex + 1);
        char[][] escapes = JSONCfg.ESCAPES;
        for (int i = 0; i < escapes.length; i++) {
            if (ch == escapes[i][0]) {
                curr = escapes[i][1];
                break;
            }
        }
        return setChar(chars, curr, arrIndex, len);
    }

    private char[] setChar(char[] chars, char ch, int index, int len) {
        if (index < len) {
            chars[index] = ch;
            return chars;
        } else {
            char[] newArr = new char[len << 1];
            System.arraycopy(chars, 0, newArr, 0, len);
            newArr[index] = ch;
            return newArr;
        }
    }

    private String toStr(char[] arr, int end) {
        return new String(arr, 0, end);
    }

    @Override
    public int hashCode() { return Objects.hashCode(source); }

    @Override
    public String toString() { return Objects.toString(source); }
}




© 2015 - 2025 Weber Informatics LLC | Privacy Policy