2 using System.Collections;
3 using System.Collections.Generic;
4 using System.Globalization;
9 namespace System.Runtime.Serialization.Json
11 internal class JavaScriptReader
14 int line = 1, column = 0;
15 // bool raise_on_number_error; // FIXME: use it
17 public JavaScriptReader (TextReader reader, bool raiseOnNumberError)
20 throw new ArgumentNullException ("reader");
22 // raise_on_number_error = raiseOnNumberError;
27 object v = ReadCore ();
30 throw JsonError (String.Format ("extra characters in JSON input"));
39 throw JsonError ("Incomplete JSON input");
43 var list = new List<object> ();
45 if (PeekChar () == ']') {
50 list.Add (ReadCore ());
58 if (ReadChar () != ']')
59 throw JsonError ("JSON array must end with ']'");
60 return list.ToArray ();
63 var obj = new Dictionary<string,object> ();
65 if (PeekChar () == '}') {
71 if (PeekChar () == '}') {
75 string name = ReadStringLiteral ();
79 obj [name] = ReadCore (); // it does not reject duplicate names.
89 KeyValuePair<string, object> [] ret = new KeyValuePair<string, object>[obj.Count];
90 foreach (KeyValuePair <string, object> kvp in obj)
95 return obj.ToArray ();
105 // FIXME: what should we return?
106 return (string) null;
108 return ReadStringLiteral ();
110 if ('0' <= c && c <= '9' || c == '-')
111 return ReadNumericLiteral ();
113 throw JsonError (String.Format ("Unexpected character '{0}'", (char) c));
132 int v = has_peek ? peek : r.Read ();
152 switch (PeekChar ()) {
153 case ' ': case '\t': case '\r': case '\n':
162 // It could return either int, long or decimal, depending on the parsed value.
163 object ReadNumericLiteral ()
165 var sb = new StringBuilder ();
167 if (PeekChar () == '-') {
168 sb.Append ((char) ReadChar ());
173 bool zeroStart = PeekChar () == '0';
176 if (c < '0' || '9' < c)
178 sb.Append ((char) ReadChar ());
179 if (zeroStart && x == 1)
180 throw JsonError ("leading zeros are not allowed");
182 if (x == 0) // Reached e.g. for "- "
183 throw JsonError ("Invalid JSON numeric literal; no digit found");
186 bool hasFrac = false;
188 if (PeekChar () == '.') {
190 sb.Append ((char) ReadChar ());
192 throw JsonError ("Invalid JSON numeric literal; extra dot");
195 if (c < '0' || '9' < c)
197 sb.Append ((char) ReadChar ());
201 throw JsonError ("Invalid JSON numeric literal; extra dot");
205 if (c != 'e' && c != 'E') {
208 if (int.TryParse (sb.ToString (), NumberStyles.Float, CultureInfo.InvariantCulture, out valueInt))
212 if (long.TryParse (sb.ToString (), NumberStyles.Float, CultureInfo.InvariantCulture, out valueLong))
216 if (ulong.TryParse (sb.ToString (), NumberStyles.Float, CultureInfo.InvariantCulture, out valueUlong))
219 decimal valueDecimal;
220 if (decimal.TryParse (sb.ToString (), NumberStyles.Float, CultureInfo.InvariantCulture, out valueDecimal) && valueDecimal != 0)
224 sb.Append ((char) ReadChar ());
226 throw new ArgumentException ("Invalid JSON numeric literal; incomplete exponent");
230 sb.Append ((char) ReadChar ());
233 sb.Append ((char) ReadChar ());
236 throw JsonError ("Invalid JSON numeric literal; incomplete exponent");
239 if (c < '0' || '9' < c)
241 sb.Append ((char) ReadChar ());
245 return double.Parse (sb.ToString (), NumberStyles.Float, CultureInfo.InvariantCulture);
248 StringBuilder vb = new StringBuilder ();
250 string ReadStringLiteral ()
252 if (PeekChar () != '"')
253 throw JsonError ("Invalid JSON string literal format");
260 throw JsonError ("JSON string is not closed");
262 return vb.ToString ();
263 else if (c != '\\') {
264 vb.Append ((char) c);
268 // escaped expression
271 throw JsonError ("Invalid JSON string literal; incomplete escape sequence");
276 vb.Append ((char) c);
295 for (int i = 0; i < 4; i++) {
297 if ((c = ReadChar ()) < 0)
298 throw JsonError ("Incomplete unicode character escape literal");
299 if ('0' <= c && c <= '9')
300 cp += (ushort) (c - '0');
301 if ('A' <= c && c <= 'F')
302 cp += (ushort) (c - 'A' + 10);
303 if ('a' <= c && c <= 'f')
304 cp += (ushort) (c - 'a' + 10);
306 vb.Append ((char) cp);
309 throw JsonError ("Invalid JSON string literal; unexpected escape character");
314 void Expect (char expected)
317 if ((c = ReadChar ()) != expected)
318 throw JsonError (String.Format ("Expected '{0}', got '{1}'", expected, (char) c));
321 void Expect (string expected)
323 for (int i = 0; i < expected.Length; i++)
324 if (ReadChar () != expected [i])
325 throw JsonError (String.Format ("Expected '{0}', differed at {1}", expected, i));
328 Exception JsonError (string msg)
330 return new ArgumentException (String.Format ("{0}. At line {1}, column {2}", msg, line, column));