Code:
/ 4.0 / 4.0 / untmp / DEVDIV_TFS / Dev10 / Releases / RTMRel / ndp / fx / src / DataWeb / Server / System / Data / Services / Serializers / JsonReader.cs / 1305376 / JsonReader.cs
//----------------------------------------------------------------------
//
// Copyright (c) Microsoft Corporation. All rights reserved.
//
//
// Provides a reader implementaion for Json format
//
//
// @owner [....]
//---------------------------------------------------------------------
namespace System.Data.Services.Serializers
{
#region Namespaces.
using System;
using System.Collections;
using System.Diagnostics;
using System.Globalization;
using System.IO;
using System.Text;
using System.Text.RegularExpressions;
using System.Collections.Generic;
#endregion Namespaces.
/// Json text reader.
/// Does not dispose the reader, since we don't own the underlying stream.
internal sealed class JsonReader
{
/// Compiled Regex for DateTime Format.
private static readonly Regex DateTimeFormat = new Regex(@"^/Date\((?-?[0-9]+)\)/", RegexOptions.Compiled);
/// Maximum recursion limit on reader.
private const int RecursionLimit = 200;
/// Reader to reader text into
private readonly StreamReader reader;
/// Depth of recursion.
private int recursionDepth;
///
/// Creates a new instance of Json reader which readers the json text
/// from the given reader
///
/// text reader from which json payload needs to be read.
/// Does not dispose the reader, since we don't own the underlying stream.
public JsonReader(StreamReader reader)
{
Debug.Assert(reader != null, "reader != null");
this.reader = reader;
}
///
/// Converts the given value into the right type
///
/// returns the clr object instance which
public object ReadValue()
{
this.RecurseEnter();
object value = null;
bool allowNull = false;
char ch = this.PeekNextSignificantCharacter();
if (ch == '[')
{
value = this.ReadArray();
}
else if (ch == '{')
{
value = this.ReadObject();
}
else if ((ch == '\'') || (ch == '"'))
{
bool hasLeadingSlash;
string s = this.ReadString(out hasLeadingSlash);
value = s; // may be overwritten with a DateTime if ends up being a date/time
// Atlas format for date/time
if (hasLeadingSlash)
{
Match match = DateTimeFormat.Match(s);
if (match.Success)
{
string ticksStr = match.Groups["ticks"].Value;
long ticks;
if (long.TryParse(ticksStr, NumberStyles.Integer, NumberFormatInfo.InvariantInfo, out ticks))
{
// The javascript ticks start from 1/1/1970 but FX DateTime ticks start from 1/1/0001
DateTime dateTime = new DateTime(ticks * 10000 + JsonWriter.DatetimeMinTimeTicks, DateTimeKind.Utc);
value = dateTime;
}
}
}
}
else if (Char.IsDigit(ch) || (ch == '-') || (ch == '.'))
{
value = this.ReadNumber();
}
else if ((ch == 't') || (ch == 'f'))
{
value = this.ReadBoolean();
}
else if (ch == 'n')
{
this.ReadNull();
allowNull = true;
}
if ((value == null) && (allowNull == false))
{
throw DataServiceException.CreateBadRequestError(Strings.BadRequestStream_InvalidContent);
}
this.RecurseLeave();
// if there is junk data at the end of the stream ex. {...}junk
// then an exception will be thrown.
if (this.recursionDepth == 0)
{
// at the end of the stream
if (this.PeekNextSignificantCharacter() != '\0')
{
throw DataServiceException.CreateBadRequestError(Strings.BadRequestStream_InvalidContent);
}
}
return value;
}
///
/// Gets the next character from the reader. This function moves the enumerator by 1 position
///
/// the next charater from the current reader position
private char ReadNextCharacter()
{
int result = this.reader.Read();
if (result < 0)
{
throw DataServiceException.CreateBadRequestError(Strings.BadRequestStream_InvalidContent);
}
Debug.Assert(result <= char.MaxValue, "result <= char.MaxValue");
return (char)result;
}
///
/// peeks the next character from the reader. This does not move the current reader position.
///
/// the next character from the current reader position
private char PeekNextCharacter()
{
if (this.reader.EndOfStream)
{
return '\0';
}
int result = this.reader.Peek();
Debug.Assert(result >= 0, "Peek must not return value < 0 since we are not at EndOfStream yet.");
Debug.Assert(result <= char.MaxValue, "result <= char.MaxValue");
return (char)result;
}
///
/// Returns the next count characters from the reader's current position
///
/// number of characters to return
/// string consisting of next count characters
private string GetCharacters(int count)
{
StringBuilder stringBuilder = new StringBuilder();
for (int i = 0; i < count; i++)
{
char ch = this.ReadNextCharacter();
stringBuilder.Append(ch);
}
return stringBuilder.ToString();
}
///
/// Sets the readers position to the next significant character position
///
/// returns the next significant character without changing the current position of the reader
private char PeekNextSignificantCharacter()
{
char ch = this.PeekNextCharacter();
while ((ch != '\0') && Char.IsWhiteSpace(ch))
{
this.ReadNextCharacter();
ch = this.PeekNextCharacter();
}
return ch;
}
///
/// Converts the given text into an arrayList
///
/// returns the arraylist containing the list of objects
private ArrayList ReadArray()
{
ArrayList array = new ArrayList();
// Consume the '['
this.ReadNextCharacter();
while (true)
{
char ch = this.PeekNextSignificantCharacter();
if (ch == '\0')
{
throw DataServiceException.CreateBadRequestError(Strings.BadRequestStream_InvalidContent);
}
if (ch == ']')
{
this.ReadNextCharacter();
return array;
}
if (array.Count != 0)
{
if (ch != ',')
{
throw DataServiceException.CreateBadRequestError(Strings.BadRequestStream_MissingArrayMemberSeperator);
}
else
{
this.ReadNextCharacter();
}
}
object item = this.ReadValue();
array.Add(item);
}
}
///
/// Reads the boolean value
///
/// returns the boolean value as read from the reader
private bool ReadBoolean()
{
string s = this.ReadName(/* allowQuotes */ false);
if (s != null)
{
if (s.Equals(XmlConstants.XmlTrueLiteral, StringComparison.Ordinal))
{
return true;
}
else if (s.Equals(XmlConstants.XmlFalseLiteral, StringComparison.Ordinal))
{
return false;
}
}
throw DataServiceException.CreateBadRequestError(Strings.BadRequestStream_InvalidKeyword(s));
}
///
/// Reads the name string from the reader
///
/// true, if you want to allow quotes, otherwise false
/// string name value
private string ReadName(bool allowQuotes)
{
char ch = this.PeekNextSignificantCharacter();
if ((ch == '"') || (ch == '\''))
{
if (allowQuotes)
{
return this.ReadString();
}
}
else
{
StringBuilder sb = new StringBuilder();
while (true)
{
ch = this.PeekNextCharacter();
if ((ch == '_') || Char.IsLetterOrDigit(ch) || ch == '$')
{
this.ReadNextCharacter();
sb.Append(ch);
}
else
{
return sb.ToString();
}
}
}
return null;
}
///
/// Reads the null literal from the reader
///
private void ReadNull()
{
string s = this.ReadName(/* allowQuotes */ false);
if (s == null)
{
throw DataServiceException.CreateBadRequestError(Strings.BadRequestStream_MissingMemberName);
}
else if (!s.Equals("null", StringComparison.Ordinal))
{
throw DataServiceException.CreateBadRequestError(Strings.BadRequestStream_InvalidKeyword(s));
}
}
/// Reads the number from the reader.
/// reads the clr number object
private object ReadNumber()
{
char ch = this.ReadNextCharacter();
StringBuilder sb = new StringBuilder();
sb.Append(ch);
while (true)
{
ch = this.PeekNextSignificantCharacter();
if (Char.IsDigit(ch) || (ch == '.') || (ch == 'E') || (ch == 'e') || (ch == '-') || (ch == '+'))
{
this.ReadNextCharacter();
sb.Append(ch);
}
else
{
break;
}
}
string s = sb.ToString();
Double doubleValue;
int intValue;
// We will first try and convert this int32. If this succeeds, great. Otherwise, we will try
// and convert this into a double.
if (Int32.TryParse(s, NumberStyles.Integer, NumberFormatInfo.InvariantInfo, out intValue))
{
return intValue;
}
else if (Double.TryParse(s, NumberStyles.Float, NumberFormatInfo.InvariantInfo, out doubleValue))
{
return doubleValue;
}
throw DataServiceException.CreateBadRequestError(Strings.BadRequestStream_InvalidContent);
}
///
/// Reads the object from the reader
///
/// returns hashtable containing the list of property names and values
private JsonObjectRecords ReadObject()
{
JsonObjectRecords record = new JsonObjectRecords();
// Consume the '{'
this.ReadNextCharacter();
while (true)
{
char ch = this.PeekNextSignificantCharacter();
if (ch == '\0')
{
// Unterminated Object literal
throw DataServiceException.CreateBadRequestError(Strings.BadRequestStream_InvalidContent);
}
if (ch == '}')
{
this.ReadNextCharacter();
return record;
}
if (record.Count != 0)
{
if (ch != ',')
{
throw DataServiceException.CreateBadRequestError(Strings.BadRequestStream_MissingMemberSeperator);
}
else
{
this.ReadNextCharacter();
}
}
string name = this.ReadName(/* allowQuotes */ true);
if (String.IsNullOrEmpty(name))
{
throw DataServiceException.CreateBadRequestError(Strings.BadRequestStream_InvalidJsonNameSpecifiedOrExtraComma);
}
ch = this.PeekNextSignificantCharacter();
// Unexpected name/value pair syntax in object literal
if (ch != ':')
{
throw DataServiceException.CreateBadRequestError(Strings.BadRequestStream_MissingNameValueSeperator(name));
}
else
{
this.ReadNextCharacter();
}
object item = this.ReadValue();
record.Add(name, item);
}
}
///
/// Read the string value from the reader
///
/// returns the string value read from the reader
private string ReadString()
{
bool dummy;
return this.ReadString(out dummy);
}
///
/// Read the string value from the reader
///
/// out parameter indicating whether the string has a leading slash or not
/// returns the string value read from the reader
private string ReadString(out bool hasLeadingSlash)
{
char endQuoteCharacter = this.ReadNextCharacter();
char ch = this.ReadNextCharacter();
hasLeadingSlash = (ch == '\\') ? true : false;
StringBuilder sb = new StringBuilder();
while (true)
{
if (ch == '\\')
{
ch = this.ReadNextCharacter();
// From 4627, section 2.5: Strings, here's the list of characters that we should be escaping
if (ch == 'u')
{
string unicodeSequence = this.GetCharacters(4);
Debug.Assert(unicodeSequence != null, "unicodeSequence != null");
ch = (char)Int32.Parse(unicodeSequence, NumberStyles.HexNumber, CultureInfo.InvariantCulture);
sb.Append(ch);
}
else if (ch == 'b')
{
sb.Append('\b');
}
else if (ch == 'f')
{
sb.Append('\f');
}
else if (ch == 'n')
{
sb.Append('\n');
}
else if (ch == 'r')
{
sb.Append('\r');
}
else if (ch == 't')
{
sb.Append('\t');
}
else if (ch == '\\' || ch == '\"' || ch == '/' || ch == '\'')
{
sb.Append(ch);
}
else
{
throw DataServiceException.CreateBadRequestError(Strings.BadRequestStream_InvalidJsonUnrecognizedEscapeSequence);
}
}
else
if (ch == endQuoteCharacter)
{
return sb.ToString();
}
else
{
sb.Append(ch);
}
ch = this.ReadNextCharacter();
}
}
/// Marks the fact that a recursive method was entered, and checks that the depth is allowed.
private void RecurseEnter()
{
WebUtil.RecurseEnter(RecursionLimit, ref this.recursionDepth);
}
/// Marks the fact that a recursive method is leaving..
private void RecurseLeave()
{
WebUtil.RecurseLeave(ref this.recursionDepth);
}
///
/// Represent one Json Object.
///
/// This class honors the original ordering of the inner elements of the json object.
public class JsonObjectRecords
{
///
/// A list of keys in the object
///
private List orderedKeys;
///
/// The actual storage of key-value pair
///
private Dictionary entries;
///
/// Constructor
///
public JsonObjectRecords()
{
this.orderedKeys = new List();
this.entries = new Dictionary(EqualityComparer.Default);
}
///
/// Number of elements in this object
///
public int Count
{
get { return this.orderedKeys.Count; }
}
///
/// A list of keys in the object, in the order which they are deserialized
///
public List OrderedKeys
{
get { return this.orderedKeys; }
}
///
/// The actual storage of key-value pair
///
public Dictionary Entries
{
get { return this.entries; }
}
///
/// Add a new element into the object
///
/// Key
/// Value
public void Add(String key, Object value)
{
// Json Object used to be a hashtable
// It will automatically resolve duplicated keys
// however, for that scenario, we must not update the order table
if (!this.entries.ContainsKey(key))
{
this.orderedKeys.Add(key);
}
this.entries[key] = value;
}
}
}
}
// File provided for Reference Use Only by Microsoft Corporation (c) 2007.
Link Menu

This book is available now!
Buy at Amazon US or
Buy at Amazon UK
- QueryContinueDragEvent.cs
- ColumnReorderedEventArgs.cs
- ScriptResourceDefinition.cs
- PasswordValidationException.cs
- TouchEventArgs.cs
- TCPClient.cs
- ExportFileRequest.cs
- DataBindingHandlerAttribute.cs
- KeyPressEvent.cs
- baseaxisquery.cs
- CodePropertyReferenceExpression.cs
- ViewGenResults.cs
- RawStylusInputCustomData.cs
- ImageCodecInfoPrivate.cs
- MessageFilterException.cs
- CompiledIdentityConstraint.cs
- XmlArrayItemAttribute.cs
- Mappings.cs
- XsdDataContractExporter.cs
- Mutex.cs
- XD.cs
- GridViewUpdatedEventArgs.cs
- InvalidStoreProtectionKeyException.cs
- ToolStripContainerDesigner.cs
- SqlTransaction.cs
- SqlProviderManifest.cs
- ExtentKey.cs
- TypeInfo.cs
- TextTreeRootTextBlock.cs
- PageSettings.cs
- StickyNoteAnnotations.cs
- RenderData.cs
- StateBag.cs
- RefType.cs
- Page.cs
- DynamicMethod.cs
- ParamArrayAttribute.cs
- CellConstant.cs
- TextUtf8RawTextWriter.cs
- AnonymousIdentificationSection.cs
- ReadOnlyDataSourceView.cs
- CaseCqlBlock.cs
- DbDataRecord.cs
- LinqDataSourceDeleteEventArgs.cs
- HttpApplicationFactory.cs
- CompilerHelpers.cs
- DeviceContext.cs
- Propagator.cs
- GridViewEditEventArgs.cs
- DataGridRelationshipRow.cs
- DataContractSerializerOperationFormatter.cs
- CodeComment.cs
- ElementHostPropertyMap.cs
- UInt64Converter.cs
- HtmlTableCell.cs
- XmlSchemaRedefine.cs
- HttpListenerResponse.cs
- GeometryDrawing.cs
- ExpressionEditorAttribute.cs
- DoubleCollection.cs
- PagerSettings.cs
- NativeCppClassAttribute.cs
- hresults.cs
- WebConvert.cs
- TagPrefixAttribute.cs
- XmlReaderDelegator.cs
- SelectionRange.cs
- Errors.cs
- precedingsibling.cs
- EntityViewContainer.cs
- ProvideValueServiceProvider.cs
- EmulateRecognizeCompletedEventArgs.cs
- Util.cs
- _ProxyChain.cs
- ToolStripManager.cs
- DataChangedEventManager.cs
- XmlBinaryReader.cs
- CryptoApi.cs
- XamlWriter.cs
- EditorResources.cs
- SpellerError.cs
- InlineCategoriesDocument.cs
- MetaForeignKeyColumn.cs
- SQLStringStorage.cs
- RtfControls.cs
- ClientSettingsSection.cs
- AuthenticationManager.cs
- WindowsScrollBar.cs
- DockPattern.cs
- MetabaseReader.cs
- ProfessionalColorTable.cs
- CategoryAttribute.cs
- CodeThrowExceptionStatement.cs
- BuildManagerHost.cs
- WebPartCancelEventArgs.cs
- CodeArrayCreateExpression.cs
- BlurBitmapEffect.cs
- CompilationUnit.cs
- DefaultEventAttribute.cs
- SkipQueryOptionExpression.cs