package z.net.json; import z.net.json.core.DataCharBuffer; import z.net.json.core.IndexBuffer; /** */ public class JsonTokenizer { private DataCharBuffer dataBuffer = null; private IndexBuffer tokenBuffer = null; private int tokenIndex = 0; private int dataPosition = 0; private int tokenLength = 0; public JsonTokenizer(IndexBuffer tokenBuffer) { this.tokenBuffer = tokenBuffer; } public JsonTokenizer(DataCharBuffer dataBuffer, IndexBuffer tokenBuffer) { this.dataBuffer = dataBuffer; this.tokenBuffer = tokenBuffer; } public void reinit(DataCharBuffer dataBuffer, IndexBuffer tokenBuffer) { this.dataBuffer = dataBuffer; this.tokenBuffer = tokenBuffer; this.tokenIndex = 0; this.dataPosition= 0; this.tokenLength = 0; } public boolean hasMoreTokens() { return (this.dataPosition + this.tokenLength) < this.dataBuffer.length ; } public void parseToken() { skipWhiteSpace(); //this.tokenLength = 0; this.tokenBuffer.position[this.tokenIndex] = this.dataPosition; char nextChar = this.dataBuffer.data[this.dataPosition]; switch(nextChar) { case '{' : { /*this.tokenLength = 1;*/ this.tokenBuffer.type[this.tokenIndex] = TokenTypes.JSON_CURLY_BRACKET_LEFT; } break; case '}' : { /*this.tokenLength = 1;*/ this.tokenBuffer.type[this.tokenIndex] = TokenTypes.JSON_CURLY_BRACKET_RIGHT; } break; case '[' : { /*this.tokenLength = 1;*/ this.tokenBuffer.type[this.tokenIndex] = TokenTypes.JSON_SQUARE_BRACKET_LEFT ; } break; case ']' : { /*this.tokenLength = 1;*/ this.tokenBuffer.type[this.tokenIndex] = TokenTypes.JSON_SQUARE_BRACKET_RIGHT; } break; case ',' : { /*this.tokenLength = 1;*/ this.tokenBuffer.type[this.tokenIndex] = TokenTypes.JSON_COMMA; } break; case ':' : { /*this.tokenLength = 1;*/ this.tokenBuffer.type[this.tokenIndex] = TokenTypes.JSON_COLON; } break; case '"' : { parseStringToken(); } break; case '0' : ; case '1' : ; case '2' : ; case '3' : ; case '4' : ; case '5' : ; case '6' : ; case '7' : ; case '8' : ; case '9' : { parseNumberToken(); this.tokenBuffer.type[this.tokenIndex] = TokenTypes.JSON_NUMBER_TOKEN; } break; case 'f' : { if(parseFalse()) { this.tokenBuffer.type[this.tokenIndex] = TokenTypes.JSON_BOOLEAN_TOKEN;} } break; case 't' : { if(parseTrue()) { this.tokenBuffer.type[this.tokenIndex] = TokenTypes.JSON_BOOLEAN_TOKEN;} } break; case 'n' : { if(parseNull()) { this.tokenBuffer.type[this.tokenIndex] = TokenTypes.JSON_NULL_TOKEN;} } break; //default : { parseStringToken(); this.tokenBuffer.type[this.tokenIndex] = TokenTypes.JSON_STRING_TOKEN; } } this.tokenBuffer.length[this.tokenIndex] = this.tokenLength; } private boolean parseNull() { if( this.dataBuffer.data[this.dataPosition + 1] == 'u' && this.dataBuffer.data[this.dataPosition + 2] == 'l' && this.dataBuffer.data[this.dataPosition + 3] == 'l' ) { //this.tokenLength = 4; return true; } return false; } private boolean parseTrue() { if( this.dataBuffer.data[this.dataPosition + 1] == 'r' && this.dataBuffer.data[this.dataPosition + 2] == 'u' && this.dataBuffer.data[this.dataPosition + 3] == 'e' ) { this.tokenLength = 4; return true; } return false; } private boolean parseFalse() { if( this.dataBuffer.data[this.dataPosition + 1] == 'a' && this.dataBuffer.data[this.dataPosition + 2] == 'l' && this.dataBuffer.data[this.dataPosition + 3] == 's' && this.dataBuffer.data[this.dataPosition + 4] == 'e' ) { this.tokenLength = 5; return true; } return false; } private void parseNumberToken() { this.tokenLength = 1; boolean isEndOfNumberFound = false; while(!isEndOfNumberFound) { switch(this.dataBuffer.data[this.dataPosition + this.tokenLength]){ case '0' : ; case '1' : ; case '2' : ; case '3' : ; case '4' : ; case '5' : ; case '6' : ; case '7' : ; case '8' : ; case '9' : ; case '.' : { this.tokenLength++; } break; default : { isEndOfNumberFound = true; } } } } private void parseStringToken() { int tempPos = this.dataPosition; boolean containsEncodedChars = false; boolean endOfStringFound = false; while(!endOfStringFound) { tempPos++; switch(this.dataBuffer.data[tempPos]) { case '"' : { endOfStringFound = this.dataBuffer.data[tempPos -1] != '\\'; break; } case '\\' : { containsEncodedChars = true; break; } } } if(containsEncodedChars) { this.tokenBuffer.type[this.tokenIndex] = TokenTypes.JSON_STRING_ENC_TOKEN; } else { this.tokenBuffer.type[this.tokenIndex] = TokenTypes.JSON_STRING_TOKEN; } this.tokenBuffer.position[this.tokenIndex] = this.dataPosition + 1; // +1 to skip over the beginning quote char (") this.tokenLength = (tempPos - this.dataPosition - 1) ; // +2 to include the enclosing quote chars (""). } private void skipWhiteSpace() { boolean isWhiteSpace = true; while(isWhiteSpace) { switch(this.dataBuffer.data[this.dataPosition]) { case ' ' : ; /* falling through - all white space characters are treated the same*/ case '\r' : ; case '\n' : ; case '\t' : { this.dataPosition++; } break; default : { isWhiteSpace = false; } /* any non white space char will break the while loop */ } } } public void nextToken() { switch(this.tokenBuffer.type[this.tokenIndex]){ case TokenTypes.JSON_STRING_TOKEN : { this.dataPosition += this.tokenBuffer.length[this.tokenIndex] + 2; break;} // +2 because of the quotes case TokenTypes.JSON_STRING_ENC_TOKEN : { this.dataPosition += this.tokenBuffer.length[this.tokenIndex] + 2; break;} // +2 because of the quotes case TokenTypes.JSON_CURLY_BRACKET_LEFT : {this.dataPosition++; break;} case TokenTypes.JSON_CURLY_BRACKET_RIGHT : {this.dataPosition++; break;} case TokenTypes.JSON_SQUARE_BRACKET_LEFT : {this.dataPosition++; break;} case TokenTypes.JSON_SQUARE_BRACKET_RIGHT : {this.dataPosition++; break;} case TokenTypes.JSON_COLON : {this.dataPosition++; break;} case TokenTypes.JSON_COMMA : {this.dataPosition++; break;} case TokenTypes.JSON_NULL_TOKEN : {this.dataPosition+=4; break;} default : {this.dataPosition += this.tokenLength;} } //this.dataPosition += this.tokenBuffer.length[this.tokenIndex]; //move data position to end of current token. this.tokenIndex++; //point to next token index array cell. } public int tokenPosition() { return this.tokenBuffer.position[this.tokenIndex]; } public int tokenLength() { return this.tokenBuffer.length[this.tokenIndex]; } public byte tokenType() { return this.tokenBuffer.type[this.tokenIndex]; } }