JsonTextCursor.cs 11 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332
  1. using System;
  2. using System.Collections.Generic;
  3. using System.Globalization;
  4. using System.IO;
  5. using System.Text;
  6. namespace Google.ProtocolBuffers.Serialization
  7. {
  8. /// <summary>
  9. /// JSon Tokenizer used by JsonFormatReader
  10. /// </summary>
  11. abstract class JsonCursor
  12. {
  13. public enum JsType { String, Number, Object, Array, True, False, Null }
  14. #region Buffering implementations
  15. class JsonStreamCursor : JsonCursor
  16. {
  17. private readonly byte[] _buffer;
  18. private int _bufferPos;
  19. private readonly Stream _input;
  20. public JsonStreamCursor(Stream input)
  21. {
  22. _input = input;
  23. _next = _input.ReadByte();
  24. }
  25. public JsonStreamCursor(byte[] input)
  26. {
  27. _input = null;
  28. _buffer = input;
  29. _next = _buffer[_bufferPos];
  30. }
  31. protected override int Peek()
  32. {
  33. if (_input != null)
  34. return _next;
  35. else if (_bufferPos < _buffer.Length)
  36. return _buffer[_bufferPos];
  37. else
  38. return -1;
  39. }
  40. protected override int Read()
  41. {
  42. if (_input != null)
  43. {
  44. int result = _next;
  45. _next = _input.ReadByte();
  46. return result;
  47. }
  48. else if (_bufferPos < _buffer.Length)
  49. return _buffer[_bufferPos++];
  50. else
  51. return -1;
  52. }
  53. }
  54. class JsonTextCursor : JsonCursor
  55. {
  56. private readonly char[] _buffer;
  57. private int _bufferPos;
  58. private readonly TextReader _input;
  59. public JsonTextCursor(char[] input)
  60. {
  61. _input = null;
  62. _buffer = input;
  63. _bufferPos = 0;
  64. _next = Peek();
  65. }
  66. public JsonTextCursor(TextReader input)
  67. {
  68. _input = input;
  69. _next = Peek();
  70. }
  71. protected override int Peek()
  72. {
  73. if (_input != null)
  74. return _input.Peek();
  75. else if (_bufferPos < _buffer.Length)
  76. return _buffer[_bufferPos];
  77. else
  78. return -1;
  79. }
  80. protected override int Read()
  81. {
  82. if (_input != null)
  83. return _input.Read();
  84. else if (_bufferPos < _buffer.Length)
  85. return _buffer[_bufferPos++];
  86. else
  87. return -1;
  88. }
  89. }
  90. #endregion
  91. protected int _next;
  92. private int _lineNo, _linePos;
  93. public static JsonCursor CreateInstance(byte[] input) { return new JsonStreamCursor(input); }
  94. public static JsonCursor CreateInstance(Stream input) { return new JsonStreamCursor(input); }
  95. public static JsonCursor CreateInstance(string input) { return new JsonTextCursor(input.ToCharArray()); }
  96. public static JsonCursor CreateInstance(TextReader input) { return new JsonTextCursor(input); }
  97. protected JsonCursor()
  98. {
  99. _lineNo = 1;
  100. _linePos = 0;
  101. }
  102. /// <summary>Returns the next character without actually 'reading' it</summary>
  103. protected abstract int Peek();
  104. /// <summary>Reads the next character in the input</summary>
  105. protected abstract int Read();
  106. public Char NextChar { get { SkipWhitespace(); return (char)_next; } }
  107. #region Assert(...)
  108. [System.Diagnostics.DebuggerNonUserCode]
  109. private string CharDisplay(int ch)
  110. {
  111. return ch == -1 ? "EOF" :
  112. (ch > 32 && ch < 127) ? String.Format("'{0}'", (char)ch) :
  113. String.Format("'\\u{0:x4}'", ch);
  114. }
  115. [System.Diagnostics.DebuggerNonUserCode]
  116. private void Assert(bool cond, char expected)
  117. {
  118. if (!cond)
  119. {
  120. throw new FormatException(
  121. String.Format(CultureInfo.InvariantCulture,
  122. "({0}:{1}) error: Unexpected token {2}, expected: {3}.",
  123. _lineNo, _linePos,
  124. CharDisplay(_next),
  125. CharDisplay(expected)
  126. ));
  127. }
  128. }
  129. [System.Diagnostics.DebuggerNonUserCode]
  130. public void Assert(bool cond, string message)
  131. {
  132. if (!cond)
  133. {
  134. throw new FormatException(
  135. String.Format(CultureInfo.InvariantCulture,
  136. "({0},{1}) error: {2}", _lineNo, _linePos, message));
  137. }
  138. }
  139. [System.Diagnostics.DebuggerNonUserCode]
  140. public void Assert(bool cond, string format, params object[] args)
  141. {
  142. if (!cond)
  143. {
  144. if (args != null && args.Length > 0)
  145. format = String.Format(format, args);
  146. throw new FormatException(
  147. String.Format(CultureInfo.InvariantCulture,
  148. "({0},{1}) error: {2}", _lineNo, _linePos, format));
  149. }
  150. }
  151. #endregion
  152. private char ReadChar()
  153. {
  154. int ch = Read();
  155. Assert(ch != -1, "Unexpected end of file.");
  156. if (ch == '\n')
  157. {
  158. _lineNo++;
  159. _linePos = 0;
  160. }
  161. else if (ch != '\r')
  162. {
  163. _linePos++;
  164. }
  165. _next = Peek();
  166. return (char)ch;
  167. }
  168. public void Consume(char ch) { Assert(TryConsume(ch), ch); }
  169. public bool TryConsume(char ch)
  170. {
  171. SkipWhitespace();
  172. if (_next == ch)
  173. {
  174. ReadChar();
  175. return true;
  176. }
  177. return false;
  178. }
  179. public void Consume(string sequence)
  180. {
  181. SkipWhitespace();
  182. foreach (char ch in sequence)
  183. Assert(ch == ReadChar(), "Expected token '{0}'.", sequence);
  184. }
  185. public void SkipWhitespace()
  186. {
  187. int chnext = _next;
  188. while (chnext != -1)
  189. {
  190. if (!Char.IsWhiteSpace((char)chnext))
  191. break;
  192. ReadChar();
  193. chnext = _next;
  194. }
  195. }
  196. public string ReadString()
  197. {
  198. SkipWhitespace();
  199. Consume('"');
  200. List<Char> sb = new List<char>(100);
  201. while (_next != '"')
  202. {
  203. if (_next == '\\')
  204. {
  205. Consume('\\');//skip the escape
  206. char ch = ReadChar();
  207. switch (ch)
  208. {
  209. case 'b': sb.Add('\b'); break;
  210. case 'f': sb.Add('\f'); break;
  211. case 'n': sb.Add('\n'); break;
  212. case 'r': sb.Add('\r'); break;
  213. case 't': sb.Add('\t'); break;
  214. case 'u':
  215. {
  216. string hex = new string(new char[] { ReadChar(), ReadChar(), ReadChar(), ReadChar() });
  217. int result;
  218. Assert(int.TryParse(hex, NumberStyles.AllowHexSpecifier, CultureInfo.InvariantCulture, out result),
  219. "Expected a 4-character hex specifier.");
  220. sb.Add((char)result);
  221. break;
  222. }
  223. default:
  224. sb.Add(ch); break;
  225. }
  226. }
  227. else
  228. {
  229. Assert(_next != '\n' && _next != '\r' && _next != '\f' && _next != -1, '"');
  230. sb.Add(ReadChar());
  231. }
  232. }
  233. Consume('"');
  234. return new String(sb.ToArray());
  235. }
  236. public string ReadNumber()
  237. {
  238. SkipWhitespace();
  239. List<Char> sb = new List<char>(24);
  240. if (_next == '-')
  241. sb.Add(ReadChar());
  242. Assert(_next >= '0' && _next <= '9', "Expected a numeric type.");
  243. while ((_next >= '0' && _next <= '9') || _next == '.')
  244. sb.Add(ReadChar());
  245. if (_next == 'e' || _next == 'E')
  246. {
  247. sb.Add(ReadChar());
  248. if (_next == '-' || _next == '+')
  249. sb.Add(ReadChar());
  250. Assert(_next >= '0' && _next <= '9', "Expected a numeric type.");
  251. while (_next >= '0' && _next <= '9')
  252. sb.Add(ReadChar());
  253. }
  254. return new String(sb.ToArray());
  255. }
  256. public JsType ReadVariant(out object value)
  257. {
  258. SkipWhitespace();
  259. switch (_next)
  260. {
  261. case 'n': Consume("null"); value = null; return JsType.Null;
  262. case 't': Consume("true"); value = true; return JsType.True;
  263. case 'f': Consume("false"); value = false; return JsType.False;
  264. case '"': value = ReadString(); return JsType.String;
  265. case '{':
  266. {
  267. Consume('{');
  268. while (NextChar != '}')
  269. {
  270. ReadString();
  271. Consume(':');
  272. object tmp;
  273. ReadVariant(out tmp);
  274. if (!TryConsume(','))
  275. break;
  276. }
  277. Consume('}');
  278. value = null;
  279. return JsType.Object;
  280. }
  281. case '[':
  282. {
  283. Consume('[');
  284. List<object> values = new List<object>();
  285. while (NextChar != ']')
  286. {
  287. object tmp;
  288. ReadVariant(out tmp);
  289. values.Add(tmp);
  290. if (!TryConsume(','))
  291. break;
  292. }
  293. Consume(']');
  294. value = values.ToArray();
  295. return JsType.Array;
  296. }
  297. default:
  298. if ((_next >= '0' && _next <= '9') || _next == '-')
  299. {
  300. value = ReadNumber();
  301. return JsType.Number;
  302. }
  303. Assert(false, "Expected a value.");
  304. throw new FormatException();
  305. }
  306. }
  307. }
  308. }