ln.json/ByteParser.cs

289 lines
5.6 KiB
C#

using System;
using System.Text;
using System.Collections.Generic;
using sharp.extensions;
using System.Globalization;
namespace sharp.json
{
public class ByteParser
{
private static ASCIIEncoding encoding = new ASCIIEncoding();
static System.Tuple<char,char>[] escapeCharacters = {
System.Tuple.Create('\\','\\'),
System.Tuple.Create('/','/'),
System.Tuple.Create('"','"'),
System.Tuple.Create('b','\b'),
System.Tuple.Create('f','\f'),
System.Tuple.Create('n','\n'),
System.Tuple.Create('r','\r'),
System.Tuple.Create('t','\t'),
};
static List<char> numberScan = new List<char>(new char[] { '-', '0', '1', '2', '3', '4', '5', '7', '8', '9', '.','E','e' });
char[] buffer;
int position;
public ByteParser(string source)
{
this.buffer = source.ToCharArray();
this.position = 0;
}
public char Peek(){
//if (position >= buffer.Length){
// return 0;
//}
return buffer[position];
}
public string Peek(int len){
return new String(buffer.Segment(position,len).Extend(len));
}
public char Read(){
if (position < buffer.Length){
return buffer[position++];
}
throw new Exception("End of buffer reached. No more characters available!");
}
public char[] Read(int len){
if ((position) < buffer.Length){
char[] r = buffer.Segment(position, len).Extend(len);
position += r.Length;
return r;
}
throw new Exception("End of buffer reached. No more characters available!");
}
private Int64 parseInt64(){
Int64 t = 0;
char ch = Read();
bool neg = false;
if (ch == '-'){
neg = true;
ch = Read();
}
if (!ch.isDigit()){
throw new FormatException("JSON: Number format error");
}
while (true){
t *= 10;
t += (int)(ch - '0');
if (!Peek().isDigit()){
break;
}
ch = Read();
}
if (neg){
t *= -1;
}
return t;
}
public JSON parseNumber(){
List<char> digits = new List<char>();
do
{
char n = (char)Peek();
if (!numberScan.Contains(n)){
break;
}
digits.Add(n);
Read();
} while (true);
string sv = new String(digits.ToArray());
if ((sv.IndexOf(".") > 0)||(sv.IndexOf("E") > 0)||(sv.IndexOf("e") > 0))
{
return new JSONNumber(double.Parse(sv,CultureInfo.InvariantCulture));
} else {
return new JSONNumber(Int64.Parse(sv));
}
//Int64 i64 = parseInt64();
//if (Peek() == '.'){
// Read();
// Int64 dec = parseInt64();
// int lg10 = (int)Math.Log10(dec);
// i64 = i64 * lg10;
// if (i64 < 0){
// i64 -= dec;
// } else {
// i64 += dec;
// }
// return new JSONNumber(((double)i64) / (double)lg10 );
//} else {
// return new JSONNumber(i64);
//}
}
public JSON parseObject(){
if (Read() != '{'){
throw new FormatException("parser error: JSON Object should begin with '{'");
}
JSONObject o = new JSONObject();
scanWhitespace();
if (Peek() == '}'){
return o;
} else {
while (true){
string name = parseStringInternal();
scanWhitespace();
if (Read() != ':'){
throw new FormatException(String.Format("parser error: expected ':' but got '{0}'",buffer[position-1]));
}
scanWhitespace();
o[name] = parseValue();
scanWhitespace();
char n = Read();
if (n == '}'){
break;
}
if (n == ','){
scanWhitespace();
continue;
}
throw new FormatException("parser error: expected ',' or '}' but got '"+n+"'");
}
}
return o;
}
public JSON parseArray(){
if (Read() != '['){
throw new FormatException("parser error: JSON array should begin with '['");
}
JSONArray o = new JSONArray();
scanWhitespace();
if (Peek() == ']'){
return o;
} else {
while (true){
o.Add(parseValue());
scanWhitespace();
char n = Read();
if (n == ']'){
break;
}
if (n == ','){
scanWhitespace();
continue;
}
throw new FormatException(String.Format("parser error: expected ',' or ']' but got '{0}'",n));
}
}
return o;
}
private string parseStringInternal(){
StringBuilder sb = new StringBuilder();
if (Read() != '"'){
throw new FormatException(String.Format("JSON string must start with '\"' but got '{0}'",buffer[position-1]));
}
while (Peek() != '"'){
char ch = Read();
sb.Append(ch);
if (ch == '\\')
{
ch = Read();
sb.Append(ch);
}
}
Read();
return sb.ToString();
}
public JSON parseString(){
return new JSONString(parseStringInternal());
}
public JSON parseValue(){
scanWhitespace();
char peek = Peek();
switch (peek){
case '{':
return parseObject();
case '[':
return parseArray();
case '"':
return parseString();
}
if ((peek >= '0' && peek <= '9') || (peek == '-')){
return parseNumber();
}
String p = Peek(4).ToLower();
if (p.Equals("true")){
position+=4;
return JSONSpecial.True;
}
if (p.Equals("null")){
position+=4;
return JSONSpecial.Null;
}
p = Peek(5).ToLower();
if (p.Equals("false")){
position+=5;
return JSONSpecial.False;
}
throw new FormatException(String.Format("Could not parse source at character '{0}' at position {1}",Peek(),position));
}
public JSON parse(){
return parseValue();
}
private int findNext(char c){
int p = position;
while (p < buffer.Length){
if (buffer[p] == c){
return p - position;
}
}
return -1;
}
private int scanWhitespace(){
while (position < buffer.Length){
if (buffer[position] > 0x20){
return position;
}
position++;
}
return position;
}
}
}