JSONCkecker(Java语言版本)

// MIT License
//
// Copyright (c) 2016 Michel Kraemer
// Copyright (c) 2005 JSON.org
//
// Permission is hereby granted, free of charge, to any person obtaining
// a copy of this software and associated documentation files (the
// "Software"), to deal in the Software without restriction, including
// without limitation the rights to use, copy, modify, merge, publish,
// distribute, sublicense, and/or sell copies of the Software, and to
// permit persons to whom the Software is furnished to do so, subject to
// the following conditions:
//
// The above copyright notice and this permission notice shall be
// included in all copies or substantial portions of the Software.
//
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
// EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
// NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
// LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
// OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
// WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.

package de.undercouch.actson;

/**
 * This class is based on the file
 * <a href="http://www.json.org/JSON_checker/">JSON_checker.c</a>
 * from <a href="http://www.json.org/">JSON.org</a>
 * @author Michel Kraemer
 * @author JSON.org
 */
public class JsonChecker {
  private static final int __ = -1; // the universal error code

  /**
   * Characters are mapped into these 31 character classes. This allows for
   * a significant reduction in the size of the state transition table.
   */
  private static final int C_SPACE =  0;  // space
  private static final int C_WHITE =  1;  // other whitespace
  private static final int C_LCURB =  2;  // {
  private static final int C_RCURB =  3;  // }
  private static final int C_LSQRB =  4;  // [
  private static final int C_RSQRB =  5;  // ]
  private static final int C_COLON =  6;  // :
  private static final int C_COMMA =  7;  // ,
  private static final int C_QUOTE =  8;  // "
  private static final int C_BACKS =  9;  // \
  private static final int C_SLASH = 10;  // /
  private static final int C_PLUS  = 11;  // +
  private static final int C_MINUS = 12;  // -
  private static final int C_POINT = 13;  // .
  private static final int C_ZERO  = 14;  // 0
  private static final int C_DIGIT = 15;  // 123456789
  private static final int C_LOW_A = 16;  // a
  private static final int C_LOW_B = 17;  // b
  private static final int C_LOW_C = 18;  // c
  private static final int C_LOW_D = 19;  // d
  private static final int C_LOW_E = 20;  // e
  private static final int C_LOW_F = 21;  // f
  private static final int C_LOW_L = 22;  // l
  private static final int C_LOW_N = 23;  // n
  private static final int C_LOW_R = 24;  // r
  private static final int C_LOW_S = 25;  // s
  private static final int C_LOW_T = 26;  // t
  private static final int C_LOW_U = 27;  // u
  private static final int C_ABCDF = 28;  // ABCDF
  private static final int C_E     = 29;  // E
  private static final int C_ETC   = 30;  // everything else

  /**
   * This array maps the 128 ASCII characters into character classes.
   * The remaining Unicode characters should be mapped to C_ETC.
   * Non-whitespace control characters are errors.
   */
  private final static int[] ascii_class = {
    __,      __,      __,      __,      __,      __,      __,      __,
    __,      C_WHITE, C_WHITE, __,      __,      C_WHITE, __,      __,
    __,      __,      __,      __,      __,      __,      __,      __,
    __,      __,      __,      __,      __,      __,      __,      __,

    C_SPACE, C_ETC,   C_QUOTE, C_ETC,   C_ETC,   C_ETC,   C_ETC,   C_ETC,
    C_ETC,   C_ETC,   C_ETC,   C_PLUS,  C_COMMA, C_MINUS, C_POINT, C_SLASH,
    C_ZERO,  C_DIGIT, C_DIGIT, C_DIGIT, C_DIGIT, C_DIGIT, C_DIGIT, C_DIGIT,
    C_DIGIT, C_DIGIT, C_COLON, C_ETC,   C_ETC,   C_ETC,   C_ETC,   C_ETC,

    C_ETC,   C_ABCDF, C_ABCDF, C_ABCDF, C_ABCDF, C_E,     C_ABCDF, C_ETC,
    C_ETC,   C_ETC,   C_ETC,   C_ETC,   C_ETC,   C_ETC,   C_ETC,   C_ETC,
    C_ETC,   C_ETC,   C_ETC,   C_ETC,   C_ETC,   C_ETC,   C_ETC,   C_ETC,
    C_ETC,   C_ETC,   C_ETC,   C_LSQRB, C_BACKS, C_RSQRB, C_ETC,   C_ETC,

    C_ETC,   C_LOW_A, C_LOW_B, C_LOW_C, C_LOW_D, C_LOW_E, C_LOW_F, C_ETC,
    C_ETC,   C_ETC,   C_ETC,   C_ETC,   C_LOW_L, C_ETC,   C_LOW_N, C_ETC,
    C_ETC,   C_ETC,   C_LOW_R, C_LOW_S, C_LOW_T, C_LOW_U, C_ETC,   C_ETC,
    C_ETC,   C_ETC,   C_ETC,   C_LCURB, C_ETC,   C_RCURB, C_ETC,   C_ETC
  };
  
  /**
   * The state codes.
   */
  private static final int GO =  0;  // start
  private static final int OK =  1;  // ok
  private static final int OB =  2;  // object
  private static final int KE =  3;  // key
  private static final int CO =  4;  // colon
  private static final int VA =  5;  // value
  private static final int AR =  6;  // array
  private static final int ST =  7;  // string
  private static final int ES =  8;  // escape
  private static final int U1 =  9;  // u1
  private static final int U2 = 10;  // u2
  private static final int U3 = 11;  // u3
  private static final int U4 = 12;  // u4
  private static final int MI = 13;  // minus
  private static final int ZE = 14;  // zero
  private static final int IN = 15;  // integer
  private static final int FR = 16;  // fraction
  private static final int E1 = 17;  // e
  private static final int E2 = 18;  // ex
  private static final int E3 = 19;  // exp
  private static final int T1 = 20;  // tr
  private static final int T2 = 21;  // tru
  private static final int T3 = 22;  // true
  private static final int F1 = 23;  // fa
  private static final int F2 = 24;  // fal
  private static final int F3 = 25;  // fals
  private static final int F4 = 26;  // false
  private static final int N1 = 27;  // nu
  private static final int N2 = 28;  // nul
  private static final int N3 = 29;  // null

  /**
   * The state transition table takes the current state and the current symbol,
   * and returns either a new state or an action. An action is represented as a
   * negative number. A JSON text is accepted if at the end of the text the
   * state is OK and if the mode is MODE_DONE.
   */
  private static int[][] state_transition_table = {
  /*               white                                      1-9                                   ABCDF  etc
               space |  {  }  [  ]  :  ,  "  \  /  +  -  .  0  |  a  b  c  d  e  f  l  n  r  s  t  u  |  E  |*/
  /*start  GO*/ {GO,GO,-6,__,-5,__,__,__,__,__,__,__,__,__,__,__,__,__,__,__,__,__,__,__,__,__,__,__,__,__,__},
  /*ok     OK*/ {OK,OK,__,-8,__,-7,__,-3,__,__,__,__,__,__,__,__,__,__,__,__,__,__,__,__,__,__,__,__,__,__,__},
  /*object OB*/ {OB,OB,__,-9,__,__,__,__,ST,__,__,__,__,__,__,__,__,__,__,__,__,__,__,__,__,__,__,__,__,__,__},
  /*key    KE*/ {KE,KE,__,__,__,__,__,__,ST,__,__,__,__,__,__,__,__,__,__,__,__,__,__,__,__,__,__,__,__,__,__},
  /*colon  CO*/ {CO,CO,__,__,__,__,-2,__,__,__,__,__,__,__,__,__,__,__,__,__,__,__,__,__,__,__,__,__,__,__,__},
  /*value  VA*/ {VA,VA,-6,__,-5,__,__,__,ST,__,__,__,MI,__,ZE,IN,__,__,__,__,__,F1,__,N1,__,__,T1,__,__,__,__},
  /*array  AR*/ {AR,AR,-6,__,-5,-7,__,__,ST,__,__,__,MI,__,ZE,IN,__,__,__,__,__,F1,__,N1,__,__,T1,__,__,__,__},
  /*string ST*/ {ST,__,ST,ST,ST,ST,ST,ST,-4,ES,ST,ST,ST,ST,ST,ST,ST,ST,ST,ST,ST,ST,ST,ST,ST,ST,ST,ST,ST,ST,ST},
  /*escape ES*/ {__,__,__,__,__,__,__,__,ST,ST,ST,__,__,__,__,__,__,ST,__,__,__,ST,__,ST,ST,__,ST,U1,__,__,__},
  /*u1     U1*/ {__,__,__,__,__,__,__,__,__,__,__,__,__,__,U2,U2,U2,U2,U2,U2,U2,U2,__,__,__,__,__,__,U2,U2,__},
  /*u2     U2*/ {__,__,__,__,__,__,__,__,__,__,__,__,__,__,U3,U3,U3,U3,U3,U3,U3,U3,__,__,__,__,__,__,U3,U3,__},
  /*u3     U3*/ {__,__,__,__,__,__,__,__,__,__,__,__,__,__,U4,U4,U4,U4,U4,U4,U4,U4,__,__,__,__,__,__,U4,U4,__},
  /*u4     U4*/ {__,__,__,__,__,__,__,__,__,__,__,__,__,__,ST,ST,ST,ST,ST,ST,ST,ST,__,__,__,__,__,__,ST,ST,__},
  /*minus  MI*/ {__,__,__,__,__,__,__,__,__,__,__,__,__,__,ZE,IN,__,__,__,__,__,__,__,__,__,__,__,__,__,__,__},
  /*zero   ZE*/ {OK,OK,__,-8,__,-7,__,-3,__,__,__,__,__,FR,__,__,__,__,__,__,__,__,__,__,__,__,__,__,__,__,__},
  /*int    IN*/ {OK,OK,__,-8,__,-7,__,-3,__,__,__,__,__,FR,IN,IN,__,__,__,__,E1,__,__,__,__,__,__,__,__,E1,__},
  /*frac   FR*/ {OK,OK,__,-8,__,-7,__,-3,__,__,__,__,__,__,FR,FR,__,__,__,__,E1,__,__,__,__,__,__,__,__,E1,__},
  /*e      E1*/ {__,__,__,__,__,__,__,__,__,__,__,E2,E2,__,E3,E3,__,__,__,__,__,__,__,__,__,__,__,__,__,__,__},
  /*ex     E2*/ {__,__,__,__,__,__,__,__,__,__,__,__,__,__,E3,E3,__,__,__,__,__,__,__,__,__,__,__,__,__,__,__},
  /*exp    E3*/ {OK,OK,__,-8,__,-7,__,-3,__,__,__,__,__,__,E3,E3,__,__,__,__,__,__,__,__,__,__,__,__,__,__,__},
  /*tr     T1*/ {__,__,__,__,__,__,__,__,__,__,__,__,__,__,__,__,__,__,__,__,__,__,__,__,T2,__,__,__,__,__,__},
  /*tru    T2*/ {__,__,__,__,__,__,__,__,__,__,__,__,__,__,__,__,__,__,__,__,__,__,__,__,__,__,__,T3,__,__,__},
  /*true   T3*/ {__,__,__,__,__,__,__,__,__,__,__,__,__,__,__,__,__,__,__,__,OK,__,__,__,__,__,__,__,__,__,__},
  /*fa     F1*/ {__,__,__,__,__,__,__,__,__,__,__,__,__,__,__,__,F2,__,__,__,__,__,__,__,__,__,__,__,__,__,__},
  /*fal    F2*/ {__,__,__,__,__,__,__,__,__,__,__,__,__,__,__,__,__,__,__,__,__,__,F3,__,__,__,__,__,__,__,__},
  /*fals   F3*/ {__,__,__,__,__,__,__,__,__,__,__,__,__,__,__,__,__,__,__,__,__,__,__,__,__,F4,__,__,__,__,__},
  /*false  F4*/ {__,__,__,__,__,__,__,__,__,__,__,__,__,__,__,__,__,__,__,__,OK,__,__,__,__,__,__,__,__,__,__},
  /*nu     N1*/ {__,__,__,__,__,__,__,__,__,__,__,__,__,__,__,__,__,__,__,__,__,__,__,__,__,__,__,N2,__,__,__},
  /*nul    N2*/ {__,__,__,__,__,__,__,__,__,__,__,__,__,__,__,__,__,__,__,__,__,__,N3,__,__,__,__,__,__,__,__},
  /*null   N3*/ {__,__,__,__,__,__,__,__,__,__,__,__,__,__,__,__,__,__,__,__,__,__,OK,__,__,__,__,__,__,__,__},
  };

  /**
   * These modes can be pushed on the stack.
   */
  private static final int MODE_ARRAY  = 0;
  private static final int MODE_DONE   = 1;
  private static final int MODE_KEY    = 2;
  private static final int MODE_OBJECT = 3;
  
  /**
   * The stack containing the current modes
   */
  private int[] stack;
  
  /**
   * The top of the stack (-1 if the stack is empty)
   */
  private int top = -1;
  
  /**
   * The current state
   */
  private int state;
  
  /**
   * Push a mode onto the stack
   * @param mode the mode to push
   * @return false if there is overflow
   */
  private boolean push(int mode) {
    ++top;
    if (top >= stack.length) {
        return false;
    }
    stack[top] = mode;
    return true;
  }
  
  /**
   * Pop the stack, assuring that the current mode matches the expectation
   * @param mode the expected mode
   * @return false if there is underflow or if the modes mismatch
   */
  private boolean pop(int mode) {
    if (top < 0 || stack[top] != mode) {
      return false;
    }
    --top;
    return true;
  }
  
  /**
   * Constructs the JsonChecker
   */
  public JsonChecker() {
    this(16);
  }

  /**
   * Constructs the JsonChecker
   * @param depth the maximum number of nested states
   */
  public JsonChecker(int depth) {
    stack = new int[depth];
    top = -1;
    state = GO;
    push(MODE_DONE);
  }

  /**
   * Call this function for each character (or partial character) in your JSON text.
   * It can accept UTF-8, UTF-16, or UTF-32.
   * @param nextChar the character to feed
   * @return <code>true</code> if things are looking ok so far, <code>false</code>
   * if it rejects the text.
   */
  public boolean feed(char nextChar) {
    // Determine the character's class.
    int nextClass;
    if (nextChar < 0) {
        return false;
    }
    if (nextChar >= 128) {
        nextClass = C_ETC;
    } else {
        nextClass = ascii_class[nextChar];
        if (nextClass <= __) {
            return false;
        }
    }
    
    // Get the next state from the state transition table.
    int nextState = state_transition_table[state][nextClass];
    if (nextState >= 0) {
      // Change the state.
      state = nextState;
    } else {
      // Or perform one of the actions.
      switch (nextState) {
      // empty }
      case -9:
        if (!pop(MODE_KEY)) {
            return false;
        }
        state = OK;
        break;

      // }
      case -8:
        if (!pop(MODE_OBJECT)) {
            return false;
        }
        state = OK;
        break;

      // ]
      case -7:
        if (!pop(MODE_ARRAY)) {
            return false;
        }
        state = OK;
        break;

      // {
      case -6:
        if (!push(MODE_KEY)) {
            return false;
        }
        state = OB;
        break;

      // [
      case -5:
        if (!push(MODE_ARRAY)) {
            return false;
        }
        state = AR;
        break;

      // "
      case -4:
        switch (stack[top]) {
        case MODE_KEY:
          state = CO;
          break;
        case MODE_ARRAY:
        case MODE_OBJECT:
          state = OK;
          break;
        default:
          return false;
        }
        break;

      // ,
      case -3:
        switch (stack[top]) {
        case MODE_OBJECT:
          // A comma causes a flip from object mode to key mode.
          if (!pop(MODE_OBJECT) || !push(MODE_KEY)) {
              return false;
          }
          state = KE;
          break;
        case MODE_ARRAY:
          state = VA;
          break;
        default:
          return false;
        }
        break;

      // :
      case -2:
        // A colon causes a flip from key mode to object mode.
        if (!pop(MODE_KEY) || !push(MODE_OBJECT)) {
          return false;
        }
        state = VA;
        break;

      // Bad action.
      default:
        return false;
      }
    }
    return true;
  }

  /**
   * This method should be called after all of the characters have been
   * processed, but only if every call to {@link #feed(char)} returned
   * <code>true</code>.
   * @return <code>true</code> if the JSON text was accepted.
   */
  public boolean done() {
    return state == OK && pop(MODE_DONE);
  }
}

 

posted @ 2017-02-09 14:18  大数据从业者FelixZh  阅读(404)  评论(0编辑  收藏  举报