package z.net.json; import z.net.json.core.DataCharBuffer; import z.net.json.core.IndexBuffer; /** */ public class JsonParser2 { private static final byte FIELD_NAME = 1; private static final byte FIELD_VALUE = 2; private static final byte OBJECT = 3; private static final byte ARRAY = 4; private byte[] stateStack = new byte[256]; private int stateIndex = 0; private int position = 0; private int elementIndex = 0; public void parse(DataCharBuffer buffer, IndexBuffer elementBuffer) { this.position = 0; this.elementIndex = 0; this.stateIndex = 0; this.stateStack[stateIndex] = FIELD_NAME; for(; position < buffer.length; position++) { switch(buffer.data[position]) { case '{' : { setElementDataLength1(elementBuffer, elementIndex, ElementTypes.JSON_OBJECT_START, position); elementIndex++; pushState(OBJECT); setState(FIELD_NAME); break;} case '}' : { setElementDataLength1(elementBuffer, elementIndex, ElementTypes.JSON_OBJECT_END , position); elementIndex++; popState(); break;} case '[' : { setElementDataLength1(elementBuffer, elementIndex, ElementTypes.JSON_ARRAY_START , position); elementIndex++; pushState(ARRAY); setState(FIELD_VALUE); break;} case ']' : { setElementDataLength1(elementBuffer, elementIndex, ElementTypes.JSON_ARRAY_END , position); elementIndex++; popState(); break;} case 'f' : { parseFalse(buffer, elementBuffer); elementIndex++; break;} case 't' : { parseTrue(buffer, elementBuffer); elementIndex++; break;} case 'n' : { parseNull(buffer, elementBuffer); elementIndex++; break;} case '0' : ; case '1' : ; case '2' : ; case '3' : ; case '4' : ; case '5' : ; case '6' : ; case '7' : ; case '8' : ; case '9' : { parseNumberToken(buffer, elementBuffer); elementIndex++; } break; case '"' : { parseStringToken(buffer, elementBuffer, elementIndex, position); elementIndex++; break;} case ':' : { setState(FIELD_VALUE); break; } case ',' : { setState(this.stateStack[this.stateIndex-1] == ARRAY ? FIELD_VALUE : FIELD_NAME); break; } } } elementBuffer.count = this.elementIndex; } private final int parseStringToken(DataCharBuffer buffer, IndexBuffer elementBuffer, int elementIndex, int position) { int tempPos = position; boolean containsEncodedChars = false; boolean endOfStringFound = false; while(!endOfStringFound) { tempPos++; switch(buffer.data[tempPos]) { case '"' : { endOfStringFound = buffer.data[tempPos -1] != '\\'; break; } case '\\' : { containsEncodedChars = true; break; } } } if(this.stateStack[this.stateIndex -1] == OBJECT) { if(this.stateStack[this.stateIndex] == FIELD_NAME) { setElementData(elementBuffer, elementIndex, ElementTypes.JSON_PROPERTY_NAME , position + 1, tempPos - position - 1); } else { if(containsEncodedChars){ setElementData(elementBuffer, elementIndex, ElementTypes.JSON_PROPERTY_VALUE_STRING_ENC, position + 1, tempPos - position - 1); } else { setElementData(elementBuffer, elementIndex, ElementTypes.JSON_PROPERTY_VALUE_STRING, position + 1, tempPos - position - 1); } } } else { // this.stateStack[this.stateIndex -1] == ARRAY if(containsEncodedChars){ setElementData(elementBuffer, elementIndex, ElementTypes.JSON_ARRAY_VALUE_STRING_ENC , position + 1, tempPos - position - 1); } else { setElementData(elementBuffer, elementIndex, ElementTypes.JSON_ARRAY_VALUE_STRING , position + 1, tempPos - position - 1); } } this.position = tempPos; return tempPos; } private boolean parseTrue(DataCharBuffer buffer, IndexBuffer elementBuffer) { if( buffer.data[this.position + 1] == 'r' && buffer.data[this.position + 2] == 'u' && buffer.data[this.position + 3] == 'e' ) { if(this.stateStack[this.stateIndex -1] == OBJECT ) { setElementData(elementBuffer, this.elementIndex, ElementTypes.JSON_PROPERTY_VALUE_BOOLEAN, this.position, 4); } else { setElementData(elementBuffer, this.elementIndex, ElementTypes.JSON_ARRAY_VALUE_BOOLEAN, this.position, 4); } this.position += 3; // +4, but the outer for-loop will add 1 too. return true; } return false; } private boolean parseFalse(DataCharBuffer buffer, IndexBuffer elementBuffer) { if( buffer.data[this.position + 1] == 'a' && buffer.data[this.position + 2] == 'l' && buffer.data[this.position + 3] == 's' && buffer.data[this.position + 4] == 'e' ) { if(this.stateStack[this.stateIndex -1] == OBJECT ) { setElementData(elementBuffer, this.elementIndex, ElementTypes.JSON_PROPERTY_VALUE_BOOLEAN, this.position, 5); } else { setElementData(elementBuffer, this.elementIndex, ElementTypes.JSON_ARRAY_VALUE_BOOLEAN, this.position, 5); } this.position += 4; // +5, but the outer for-loop will add 1 too return true; } return false; } private void parseNumberToken(DataCharBuffer buffer, IndexBuffer elementBuffer) { int tempPos = this.position; boolean isEndOfNumberFound = false; while(!isEndOfNumberFound) { tempPos++; switch(buffer.data[tempPos]){ case '0' : ; case '1' : ; case '2' : ; case '3' : ; case '4' : ; case '5' : ; case '6' : ; case '7' : ; case '8' : ; case '9' : ; case '.' : break; //todo check for double . in numbers. default : { isEndOfNumberFound = true; } } } if(this.stateStack[this.stateIndex -1] == OBJECT) { setElementData(elementBuffer, this.elementIndex, ElementTypes.JSON_PROPERTY_VALUE_NUMBER, this.position, tempPos - this.position); } else { setElementData(elementBuffer, this.elementIndex, ElementTypes.JSON_ARRAY_VALUE_NUMBER, this.position, tempPos - this.position); } this.position = tempPos -1; // -1 because the outer for-loop adds 1 to the position too } private boolean parseNull(DataCharBuffer buffer, IndexBuffer elementBuffer) { if( buffer.data[this.position + 1] == 'u' && buffer.data[this.position + 2] == 'l' && buffer.data[this.position + 3] == 'l' ) { if(this.stateStack[this.stateIndex -1] == OBJECT) { setElementDataNoLength(elementBuffer, this.elementIndex, ElementTypes.JSON_PROPERTY_VALUE_NULL, this.position); } else { setElementDataNoLength(elementBuffer, this.elementIndex, ElementTypes.JSON_ARRAY_VALUE_NULL, this.position); } return true; } return false; } private void setState(byte state){ this.stateStack[this.stateIndex] = state; } private void pushState(byte state){ this.stateStack[this.stateIndex] = state; this.stateIndex++; } private void popState() { this.stateIndex--; } private final void setElementDataNoLength(IndexBuffer elementBuffer, int index, byte type, int position) { elementBuffer.type [index] = type; elementBuffer.position[index] = position; } private final void setElementDataLength1(IndexBuffer elementBuffer, int index, byte type, int position) { elementBuffer.type [index] = type; elementBuffer.position[index] = position; elementBuffer.length [index] = 1; } private final void setElementData(IndexBuffer elementBuffer, int index, byte type, int position, int length) { elementBuffer.type [index] = type; elementBuffer.position[index] = position; elementBuffer.length [index] = length; } }