Imported Upstream version 3.6.0

Former-commit-id: da6be194a6b1221998fc28233f2503bd61dd9d14
This commit is contained in:
Jo Shields
2014-08-13 10:39:27 +01:00
commit a575963da9
50588 changed files with 8155799 additions and 0 deletions

View File

@ -0,0 +1,338 @@
2010-07-27 Andreia Gaita <avidigal@novell.com>
* JsonSerializationReader.cs: Add Char type to the switch. Reads the
content as a string and validates its length
2010-07-27 Andreia Gaita <avidigal@novell.com>
* JsonSerializationReader.cs, JsonSerializationWriter.cs:
Add a special case for IDictionary, since KeyValuePair objects
have private setters and can't be processed via the normal
object code path.
2010-07-06 Atsushi Enomoto <atsushi@ximian.com>
* TypeMap.cs :
Do not try to add static members as serialization targets.
Support OnDeserializing and OnDeserialized. Fixed bug #615800.
2010-07-06 Atsushi Enomoto <atsushi@ximian.com>
* JsonSerializationWriter.cs : it cannot serialize DateTime in
double, which causes crash in deserializer.
2010-07-06 Atsushi Enomoto <atsushi@ximian.com>
* TypeMap.cs : when an object is null, return null, not just an
uninitialized object.
2010-07-06 Atsushi Enomoto <atsushi@ximian.com>
* DataContractJsonSerializer_2_1.cs : add extra methods for
Sys.SM.Web.Extensions build.
2010-07-06 Atsushi Enomoto <atsushi@ximian.com>
* JsonReader.cs : do not keep Attribute state once Read() is called.
2010-04-24 Atsushi Enomoto <atsushi@ximian.com>
* JsonSerializationReader.cs : use List<T> if the contract member
type is interface.
2010-03-16 Jb Evain <jbevain@novell.com>
* DataContractJsonSerializer.cs: use MOONLIGHT symbol to
disambiguate MonoTouch and Moonlight code.
2010-03-13 Kornél Pál <kornelpal@gmail.com>
* JavaScriptReader.cs: Deserialize "false" correctly.
Fixed bug #586712.
2010-03-10 Atsushi Enomoto <atsushi@ximian.com>
* JavaScriptReader.cs : moved from Sys.Json/JsonReader.cs.
2010-03-10 Atsushi Enomoto <atsushi@ximian.com>
* JavaScriptObjectDeserializer.cs : new internal file, which is
used by System.Json (for moonlight compatibility).
2010-03-09 Atsushi Enomoto <atsushi@ximian.com>
* JsonSerializationWriter.cs, JsonSerializationReader.cs,
JsonWriter.cs : Fix DateTime serialization and "\/" string escape
issues. Fixed bug #586169.
2010-02-24 Atsushi Enomoto <atsushi@ximian.com>
* JsonWriter.cs : write NaN, INF, -INF as JSON string, not JSON number.
Fixed bug #573691.
2010-01-27 Atsushi Enomoto <atsushi@ximian.com>
* DataContractJsonSerializer.cs : KnownTypes does not include root
type. Fixed bug #573689.
2010-01-27 Atsushi Enomoto <atsushi@ximian.com>
* JsonSerializationReader.cs : oops, wrong fix, should consume the
reader.
2010-01-27 Atsushi Enomoto <atsushi@ximian.com>
* JsonSerializationReader.cs : "null" for string should be read as
null, not String.Empty. Fixed bug #573690.
2010-01-26 Sebastien Pouliot <sebastien@ximian.com>
* DataContractJsonSerializer_2_1.cs: Don't hide [Field|Method]
AccessException inside a SerializationException but in a
SecurityException.
2010-01-25 Sebastien Pouliot <sebastien@ximian.com>
* DataContractJsonSerializer_2_1.cs: New. Simpler version for
Moonlight since it does not inherit from the same base type nor
does it overrides any base methods.
2010-01-08 Atsushi Enomoto <atsushi@ximian.com>
* TypeMap.cs : forward port r145077 (see change line for 2009-10-29).
2009-12-14 Atsushi Enomoto <atsushi@ximian.com>
* TypeMap.cs : handle [Serializable] objects such as KeyValuePair<,>
like we do in 2.0. Removed previous workarounds. (Do not serialize
and deserialize nonpublic members in "default" mappings.)
2009-12-11 Chris Toshok <toshok@ximian.com>
* TypeMap.cs (CreateDefaultTypeMap): only include non-public
property info when dealing with KeyValuePair<,>. This is *not*
the way MS handles it, but we emulate things much better with this
hack.
2009-12-11 Atsushi Enomoto <atsushi@ximian.com>
* JsonReader.cs : e- and e+ was resulting in wrong parse error.
This should fix part of bug #531904.
2009-12-08 Chris Toshok <toshok@ximian.com>
* JsonSerializationReader.cs (DeserializeGenericCollection): in
the 2.1 case we still need to convert the List<> to an array.
2009-12-07 Chris Toshok <toshok@ximian.com>
* JsonReaderWriterFactory.cs (CreateJsonReader): pass null for the
encoding parameter instead of calling Detect. The jsonreader's
PushbackReader will autodetect.
(Detect): remove. a BufferedStream created from an unseekable
stream is itself unseekable, which makes it just as useless. This
breaks netflix's isostore file parsing.
* JsonReader.cs (PushbackReader): add a ctor which doesn't take an
encoding, for the autodetecting reader case. for this ctor, pass
true to StreamReader's ctor for detectEncodingFromByteOrderMarks.
2009-12-06 Chris Toshok <toshok@ximian.com>
* JsonSerializationReader.cs (DeserializeGenericCollection): this
is jb's (iirc) patch, actually. Types subclassing from
ICollection<T> need to be supported, and since it's an interface
the implementation might be explicit. So instead of groveling
around in the actual type, we need to dispatch through the
interface's method.
* TypeMap.cs (CreateDefaultTypeMap): we need to include non-public
properties, since KeyValuePair items must be able to write to Key
and Value properties.
* JsonReader.cs (ReadContent): for builtin values (null, true,
false), use TryReadString instead of individual ReadChar's, since
they aren't reversible if the string didn't match. In the default
case, if we're LameSilverlightLiseralParser, we need to push back
the current character onto the stream -- this is because for
netflix's AppConfig.json we were parsing "frameRatePolicy" as
"rameRatePolicy" (the 'f' was triggering the "false" parsing).
(class PushBackReader): add this class to unify all the pushing
back of characters we need to do. 1 character (JsonReader's old
"saved_char") isn't enough given that you could have a property
named, e.g., "falsifiable", and we'd need 4 characters worth of
pushback to recognize that correctly.
2009-11-20 Atsushi Enomoto <atsushi@ximian.com>
* DataContractJsonSerializer.cs, JsonReader.cs : Silverlight uses
LAME parser that allows object member name as *raw* string
without double-quotes. (This also reverts the previous change.)
2009-11-12 Atsushi Enomoto <atsushi@ximian.com>
* JsonSerializationReader.cs : reuse generic collection search
logic in KnownTypeCollection.cs. Fixed bug #551671.
2009-10-30 Andreia Gaita <avidigal@novell.com>
* DataContractJsonSerializer.cs: SL accepts keys without "", so tweak
the data to fix the quotes before passing it to the deserializer
2009-10-29 Chris Toshok <toshok@ximian.com>
* TypeMap.cs (Deserialize): use
FormatterServices.GetUninitializedObject instead of
Activator.CreateInstance, since we shouldn't be invoking the
default ctor.
(forward ported to trunk on 2010-01-08 by atsushi)
2009-10-23 Atsushi Enomoto <atsushi@ximian.com>
* DataContractJsonSerializer.cs
TypeMap.cs
JsonSerializationReader.cs : add experimental monotouch build.
2009-10-08 Atsushi Enomoto <atsushi@ximian.com>
* DataContractJsonSerializer.cs, JsonSerializationWriter.cs:
alwaysEmitTypeInformation is false by default. It is for __type
attribute, not for type attribute. __type name is always with ":#".
* TypeMap.cs : sort members in default typemap (it is ordered).
Uncomment EmitDefaultValue.
* JsonWriter.cs : handle "null" string (it is somewhat messy).
2009-10-05 Atsushi Enomoto <atsushi@ximian.com>
* JsonReader.cs : copy string literal parser from System.Json.
2009-09-22 Atsushi Enomoto <atsushi@ximian.com>
* JsonSerializationWriter.cs : output "type" attribute on bool
values too.
* JsonSerializationReader.cs : type loading attempt was insufficient
and hence often missed indicated types to deserialize.
2009-09-15 Atsushi Enomoto <atsushi@ximian.com>
* JsonWriter.cs : use Stream as its output directly and avoid
extraneous preamble output. Fix interop with .NET.
2009-09-07 Atsushi Enomoto <atsushi@ximian.com>
* JsonReaderWriterFactory.cs : check null stream (fix test failure).
2009-03-13 Andreia Gaita <avidigal@novell.com>
* JsonReader.cs: fix depth calculation
2009-03-12 Geoff Norton <gnorton@novell.com>
* TypeMap.cs: Avoid checking the getter/setter information until after
checking if we have the required attribute decorated.
2009-03-12 Andreia Gaita <avidigal@novell.com>
* JsonReaderWriterFactory.cs: try to auto-detect encoding for streams
without BOM
2009-03-02 Chris Toshok <toshok@ximian.com>
* JsonReader.cs: 2.1 has HasValue.
2009-02-02 Atsushi Enomoto <atsushi@ximian.com>
* JsonReader.cs : show invalid input character in the error
message.
2009-02-02 Atsushi Enomoto <atsushi@ximian.com>
* TypeMap.cs : in 2.1 do not use non-2.1 CreateInstance().
2009-02-02 Atsushi Enomoto <atsushi@ximian.com>
* TypeMap.cs : allow get-only collections. Note that they are not
always deserializable (in .NET either).
2009-02-02 Atsushi Enomoto <atsushi@ximian.com>
* TypeMap.cs : DataContractJsonSerializer in RTM does not seem to
reject contract-less types. So populate map for public members.
* DataContractJsonSerializer.cs : close XmlWriter to flush stream
(and it closes the stream by default).
2009-02-02 Andreia Gaita <avidigal@novell.com>
* JsonSerializationReader.cs : Use 2.1 "approved" calls for Enum.Parse
and Convert.ChangeType
2008-02-18 Atsushi Enomoto <atsushi@ximian.com>
* DataContractJsonSerializer.cs : IsStartObject() could raise
an arbitrary exception, so wrap it inside try-catch too to enclose
with SerializationException.
* JsonSerializationReader.cs : support DBNull.
2008-01-30 Atsushi Enomoto <atsushi@ximian.com>
* DataContractJsonSerializer.cs : fixed .ctor(type, knonwTypes) that
missed to delegate knownTypes correctly.
* JsonSerializationReader.cs : consider KnownTypes correctly.
Take "__type" fully into consideration, not just for arrays.
2008-01-30 Atsushi Enomoto <atsushi@ximian.com>
* JsonReader.cs : GetAttribute() was not still missing support for
__type.
2008-01-30 Atsushi Enomoto <atsushi@ximian.com>
* JsonReader.cs : now __type is fully supported in every methods and
properties in correct shape.
2008-01-30 Atsushi Enomoto <atsushi@ximian.com>
* JsonReader.cs : Do not consume "__type" (which is the first content
of an object) as an element content. It must be handled as an
attribute (it needs more changes).
2008-01-24 Atsushi Enomoto <atsushi@ximian.com>
* JsonSerializationReader.cs : when deserializing primitive strings,
make use of "type" attribute (they are supposed to exist).
Output source reader location if available.
* JsonReader.cs : implement IXmlLineInfo.
2008-01-24 Atsushi Enomoto <atsushi@ximian.com>
* JsonSerializationReader.cs : new, for JSON deserialization support.
* DataContractJsonSerializer.cs, TypeMap.cs :
basic support for deserialization.
2008-01-24 Atsushi Enomoto <atsushi@ximian.com>
* DataContractJsonSerializer.cs,
TypeMap.cs,
JsonSerializationWriter.cs : split the first to those three files.
2008-01-24 Atsushi Enomoto <atsushi@ximian.com>
* DataContractJsonSerializer.cs : Uri and Guid are serialized as
string. XmlQualifiedName is serialized as local:ns.
2008-01-22 Atsushi Enomoto <atsushi@ximian.com>
* JsonWriter.cs : allow __type attribute. It required couple of
changes all around the class.
* DataContractJsonSerializer.cs : implemented large part of
serialization support (deserialization is not done yet).
2007-12-05 Atsushi Enomoto <atsushi@ximian.com>
* DataContractJsonSerializer.cs :
moved from System.Runtime.Serialization and changed the namespace.
* JsonReader.cs, JsonWriter.cs, JsonReaderWriterFactory.cs,
IXmlJsonReaderInitializer.cs, IXmlJsonWriterInitializer.cs :
moved from System.Xml and changed the namespace.

View File

@ -0,0 +1,289 @@
//
// DataContractJsonSerializer.cs
//
// Author:
// Atsushi Enomoto <atsushi@ximian.com>
//
// Copyright (C) 2007-2008 Novell, Inc (http://www.novell.com)
//
// Permission is hereby granted, free of charge, to any person obtaining
// a copy of this software and associated documentation files (the
// "Software"), to deal in the Software without restriction, including
// without limitation the rights to use, copy, modify, merge, publish,
// distribute, sublicense, and/or sell copies of the Software, and to
// permit persons to whom the Software is furnished to do so, subject to
// the following conditions:
//
// The above copyright notice and this permission notice shall be
// included in all copies or substantial portions of the Software.
//
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
// EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
// NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
// LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
// OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
// WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
//
using System;
using System.Collections;
using System.Collections.Generic;
using System.Collections.ObjectModel;
using System.Globalization;
using System.IO;
using System.Linq;
using System.Reflection;
using System.Text;
using System.Xml;
namespace System.Runtime.Serialization.Json
{
public sealed class DataContractJsonSerializer : XmlObjectSerializer
{
const string default_root_name = "root";
#region lengthy constructor list
public DataContractJsonSerializer (Type type)
: this (type, Type.EmptyTypes)
{
}
public DataContractJsonSerializer (Type type, IEnumerable<Type> knownTypes)
: this (type, default_root_name, knownTypes)
{
}
public DataContractJsonSerializer (Type type, string rootName)
: this (type, rootName, Type.EmptyTypes)
{
}
public DataContractJsonSerializer (Type type, XmlDictionaryString rootName)
: this (type, rootName != null ? rootName.Value : default_root_name, Type.EmptyTypes)
{
}
public DataContractJsonSerializer (Type type, string rootName, IEnumerable<Type> knownTypes)
: this (type, rootName, knownTypes, int.MaxValue, false, false)
{
}
public DataContractJsonSerializer (Type type, XmlDictionaryString rootName, IEnumerable<Type> knownTypes)
: this (type, rootName != null ? rootName.Value : default_root_name, knownTypes)
{
}
DataContractJsonSerializer(Type type, string rootName, IEnumerable<Type> knownTypes, int maxItemsInObjectGraph, bool ignoreExtensionDataObject, bool alwaysEmitTypeInformation)
{
if (type == null)
throw new ArgumentNullException ("type");
if (rootName == null)
throw new ArgumentNullException ("rootName");
if (maxItemsInObjectGraph < 0)
throw new ArgumentOutOfRangeException ("maxItemsInObjectGraph");
this.type = type;
known_types = new ReadOnlyCollection<Type> (knownTypes != null ? knownTypes.ToArray () : Type.EmptyTypes);
root = rootName;
max_items = maxItemsInObjectGraph;
ignore_extension = ignoreExtensionDataObject;
always_emit_type = alwaysEmitTypeInformation;
}
public DataContractJsonSerializer (Type type, IEnumerable<Type> knownTypes, int maxItemsInObjectGraph, bool ignoreExtensionDataObject, IDataContractSurrogate dataContractSurrogate, bool alwaysEmitTypeInformation)
: this (type, default_root_name, knownTypes, maxItemsInObjectGraph, ignoreExtensionDataObject, alwaysEmitTypeInformation)
{
}
public DataContractJsonSerializer (Type type, string rootName, IEnumerable<Type> knownTypes, int maxItemsInObjectGraph, bool ignoreExtensionDataObject, IDataContractSurrogate dataContractSurrogate, bool alwaysEmitTypeInformation)
: this (type, rootName, knownTypes, maxItemsInObjectGraph, ignoreExtensionDataObject, alwaysEmitTypeInformation)
{
surrogate = dataContractSurrogate;
}
public DataContractJsonSerializer (Type type, XmlDictionaryString rootName, IEnumerable<Type> knownTypes, int maxItemsInObjectGraph, bool ignoreExtensionDataObject, IDataContractSurrogate dataContractSurrogate, bool alwaysEmitTypeInformation)
: this (type, rootName != null ? rootName.Value : default_root_name, knownTypes, maxItemsInObjectGraph, ignoreExtensionDataObject, dataContractSurrogate, alwaysEmitTypeInformation)
{
}
#if NET_4_5
public DataContractJsonSerializer (Type type, DataContractJsonSerializerSettings settings)
: this (type, settings.RootName, settings.KnownTypes, settings.MaxItemsInObjectGraph, settings.IgnoreExtensionDataObject,
settings.DataContractSurrogate, false)
{
}
#endif
#endregion
Type type;
string root;
ReadOnlyCollection<Type> known_types;
int max_items;
bool ignore_extension;
bool always_emit_type;
IDataContractSurrogate surrogate;
[MonoTODO]
public IDataContractSurrogate DataContractSurrogate {
get { return surrogate; }
}
[MonoTODO]
public bool IgnoreExtensionDataObject {
get { return ignore_extension; }
}
[MonoTODO]
public ReadOnlyCollection<Type> KnownTypes {
get { return known_types; }
}
public int MaxItemsInObjectGraph {
get { return max_items; }
}
public override bool IsStartObject (XmlReader reader)
{
if (reader == null)
throw new ArgumentNullException ("reader");
reader.MoveToContent ();
return reader.IsStartElement (root, String.Empty);
}
public override bool IsStartObject (XmlDictionaryReader reader)
{
return IsStartObject ((XmlReader) reader);
}
public override object ReadObject (Stream stream)
{
#if NET_2_1
var r = (JsonReader) JsonReaderWriterFactory.CreateJsonReader(stream, XmlDictionaryReaderQuotas.Max);
r.LameSilverlightLiteralParser = true;
return ReadObject(r);
#else
return ReadObject (JsonReaderWriterFactory.CreateJsonReader (stream, new XmlDictionaryReaderQuotas ()));
#endif
}
public override object ReadObject (XmlDictionaryReader reader)
{
return ReadObject (reader, true);
}
public override object ReadObject (XmlReader reader)
{
return ReadObject (reader, true);
}
public override object ReadObject (XmlDictionaryReader reader, bool verifyObjectName)
{
return ReadObject ((XmlReader) reader, verifyObjectName);
}
public override object ReadObject (XmlReader reader, bool verifyObjectName)
{
if (reader == null)
throw new ArgumentNullException ("reader");
try {
if (verifyObjectName && !IsStartObject (reader))
throw new SerializationException (String.Format ("Expected element was '{0}', but the actual input element was '{1}' in namespace '{2}'", root, reader.LocalName, reader.NamespaceURI));
return new JsonSerializationReader (this, reader, type, verifyObjectName).ReadRoot ();
} catch (SerializationException) {
throw;
} catch (InvalidDataContractException) {
throw;
} catch (System.Reflection.TargetInvocationException ex) {
throw ex.InnerException;
} catch (Exception ex) {
throw new SerializationException ("Deserialization has failed", ex);
}
}
public override void WriteObject (Stream stream, object graph)
{
using (var xw = JsonReaderWriterFactory.CreateJsonWriter (stream))
WriteObject (xw, graph);
}
public override void WriteObject (XmlWriter writer, object graph)
{
try {
WriteStartObject (writer, graph);
WriteObjectContent (writer, graph);
WriteEndObject (writer);
} catch (NotImplementedException) {
throw;
} catch (InvalidDataContractException) {
throw;
} catch (Exception ex) {
throw new SerializationException (String.Format ("There was an error during serialization for object of type {0}", graph != null ? graph.GetType () : null), ex);
}
}
public override void WriteObject (XmlDictionaryWriter writer, object graph)
{
WriteObject ((XmlWriter) writer, graph);
}
public override void WriteStartObject (XmlDictionaryWriter writer, object graph)
{
WriteStartObject ((XmlWriter) writer, graph);
}
public override void WriteStartObject (XmlWriter writer, object graph)
{
if (writer == null)
throw new ArgumentNullException ("writer");
writer.WriteStartElement (root);
}
public override void WriteObjectContent (XmlDictionaryWriter writer, object graph)
{
WriteObjectContent ((XmlWriter) writer, graph);
}
public override void WriteObjectContent (XmlWriter writer, object graph)
{
new JsonSerializationWriter (this, writer, type, always_emit_type).WriteObjectContent (graph, true, false);
}
public override void WriteEndObject (XmlDictionaryWriter writer)
{
WriteEndObject ((XmlWriter) writer);
}
public override void WriteEndObject (XmlWriter writer)
{
if (writer == null)
throw new ArgumentNullException ("writer");
writer.WriteEndElement ();
}
#if NET_4_5
[MonoTODO]
public DateTimeFormat DateTimeFormat {
get { throw new NotImplementedException (); }
}
[MonoTODO]
public EmitTypeInformation EmitTypeInformation {
get { throw new NotImplementedException (); }
}
[MonoTODO]
public bool SerializeReadOnlyTypes {
get { throw new NotImplementedException (); }
}
[MonoTODO]
public bool UseSimpleDictionaryFormat {
get { throw new NotImplementedException (); }
}
#endif
}
}

View File

@ -0,0 +1,45 @@
//
// DataContractJsonSerializerSettings.cs
//
// Author:
// Martin Baulig <martin.baulig@xamarin.com>
//
// Copyright (c) 2013 Xamarin Inc. (http://www.xamarin.com)
//
// Permission is hereby granted, free of charge, to any person obtaining a copy
// of this software and associated documentation files (the "Software"), to deal
// in the Software without restriction, including without limitation the rights
// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
// copies of the Software, and to permit persons to whom the Software is
// furnished to do so, subject to the following conditions:
//
// The above copyright notice and this permission notice shall be included in
// all copies or substantial portions of the Software.
//
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
// THE SOFTWARE.
using System;
using System.Xml;
using System.Collections.Generic;
namespace System.Runtime.Serialization.Json
{
public class DataContractJsonSerializerSettings
{
public IDataContractSurrogate DataContractSurrogate { get; set; }
public DateTimeFormat DateTimeFormat { get; set; }
public EmitTypeInformation EmitTypeInformation { get; set; }
public bool IgnoreExtensionDataObject { get; set; }
public IEnumerable<Type> KnownTypes { get; set; }
public int MaxItemsInObjectGraph { get; set; }
public string RootName { get; set; }
public bool SerializeReadOnlyTypes { get; set; }
public bool UseSimpleDictionaryFormat { get; set; }
}
}

View File

@ -0,0 +1,43 @@
//
// IXmlJsonReaderInitializer.cs
//
// Author:
// Atsushi Enomoto <atsushi@ximian.com>
//
// Copyright (C) 2007 Novell, Inc (http://www.novell.com)
//
// Permission is hereby granted, free of charge, to any person obtaining
// a copy of this software and associated documentation files (the
// "Software"), to deal in the Software without restriction, including
// without limitation the rights to use, copy, modify, merge, publish,
// distribute, sublicense, and/or sell copies of the Software, and to
// permit persons to whom the Software is furnished to do so, subject to
// the following conditions:
//
// The above copyright notice and this permission notice shall be
// included in all copies or substantial portions of the Software.
//
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
// EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
// NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
// LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
// OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
// WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
//
using System;
using System.Collections.Generic;
using System.Globalization;
using System.IO;
using System.Text;
using System.Xml;
namespace System.Runtime.Serialization.Json
{
public interface IXmlJsonReaderInitializer
{
void SetInput (byte [] buffer, int offset, int count, Encoding encoding, XmlDictionaryReaderQuotas quotas, OnXmlDictionaryReaderClose onClose);
void SetInput (Stream stream, Encoding encoding, XmlDictionaryReaderQuotas quotas, OnXmlDictionaryReaderClose onClose);
}
}

View File

@ -0,0 +1,41 @@
//
// IXmlJsonWriterInitializer.cs
//
// Author:
// Atsushi Enomoto <atsushi@ximian.com>
//
// Copyright (C) 2007 Novell, Inc (http://www.novell.com)
//
// Permission is hereby granted, free of charge, to any person obtaining
// a copy of this software and associated documentation files (the
// "Software"), to deal in the Software without restriction, including
// without limitation the rights to use, copy, modify, merge, publish,
// distribute, sublicense, and/or sell copies of the Software, and to
// permit persons to whom the Software is furnished to do so, subject to
// the following conditions:
//
// The above copyright notice and this permission notice shall be
// included in all copies or substantial portions of the Software.
//
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
// EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
// NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
// LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
// OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
// WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
//
using System;
using System.Collections.Generic;
using System.Globalization;
using System.IO;
using System.Text;
using System.Xml;
namespace System.Runtime.Serialization.Json
{
public interface IXmlJsonWriterInitializer
{
void SetOutput (Stream stream, Encoding encoding, bool ownsStream);
}
}

View File

@ -0,0 +1,342 @@
using System;
using System.Collections;
using System.Collections.Generic;
using System.Globalization;
using System.IO;
using System.Linq;
using System.Text;
namespace System.Runtime.Serialization.Json
{
internal class JavaScriptReader
{
TextReader r;
int line = 1, column = 0;
// bool raise_on_number_error; // FIXME: use it
public JavaScriptReader (TextReader reader, bool raiseOnNumberError)
{
if (reader == null)
throw new ArgumentNullException ("reader");
this.r = reader;
// raise_on_number_error = raiseOnNumberError;
}
public object Read ()
{
object v = ReadCore ();
SkipSpaces ();
if (r.Read () >= 0)
throw JsonError (String.Format ("extra characters in JSON input"));
return v;
}
object ReadCore ()
{
SkipSpaces ();
int c = PeekChar ();
if (c < 0)
throw JsonError ("Incomplete JSON input");
switch (c) {
case '[':
ReadChar ();
var list = new List<object> ();
SkipSpaces ();
if (PeekChar () == ']') {
ReadChar ();
return list;
}
while (true) {
list.Add (ReadCore ());
SkipSpaces ();
c = PeekChar ();
if (c != ',')
break;
ReadChar ();
continue;
}
if (ReadChar () != ']')
throw JsonError ("JSON array must end with ']'");
return list.ToArray ();
case '{':
ReadChar ();
var obj = new Dictionary<string,object> ();
SkipSpaces ();
if (PeekChar () == '}') {
ReadChar ();
return obj;
}
while (true) {
SkipSpaces ();
if (PeekChar () == '}')
break;
string name = ReadStringLiteral ();
SkipSpaces ();
Expect (':');
SkipSpaces ();
obj [name] = ReadCore (); // it does not reject duplicate names.
SkipSpaces ();
c = ReadChar ();
if (c == ',')
continue;
if (c == '}')
break;
}
#if MONOTOUCH
int idx = 0;
KeyValuePair<string, object> [] ret = new KeyValuePair<string, object>[obj.Count];
foreach (KeyValuePair <string, object> kvp in obj)
ret [idx++] = kvp;
return ret;
#else
return obj.ToArray ();
#endif
case 't':
Expect ("true");
return true;
case 'f':
Expect ("false");
return false;
case 'n':
Expect ("null");
// FIXME: what should we return?
return (string) null;
case '"':
return ReadStringLiteral ();
default:
if ('0' <= c && c <= '9' || c == '-')
return ReadNumericLiteral ();
else
throw JsonError (String.Format ("Unexpected character '{0}'", (char) c));
}
}
int peek;
bool has_peek;
bool prev_lf;
int PeekChar ()
{
if (!has_peek) {
peek = r.Read ();
has_peek = true;
}
return peek;
}
int ReadChar ()
{
int v = has_peek ? peek : r.Read ();
has_peek = false;
if (prev_lf) {
line++;
column = 0;
prev_lf = false;
}
if (v == '\n')
prev_lf = true;
column++;
return v;
}
void SkipSpaces ()
{
while (true) {
switch (PeekChar ()) {
case ' ': case '\t': case '\r': case '\n':
ReadChar ();
continue;
default:
return;
}
}
}
// It could return either int, long or decimal, depending on the parsed value.
object ReadNumericLiteral ()
{
bool negative = false;
if (PeekChar () == '-') {
negative = true;
ReadChar ();
if (PeekChar () < 0)
throw JsonError ("Invalid JSON numeric literal; extra negation");
}
int c;
decimal val = 0;
int x = 0;
bool zeroStart = PeekChar () == '0';
for (; ; x++) {
c = PeekChar ();
if (c < '0' || '9' < c)
break;
val = val * 10 + (c - '0');
ReadChar ();
if (zeroStart && x == 1 && c == '0')
throw JsonError ("leading multiple zeros are not allowed");
}
// fraction
bool hasFrac = false;
decimal frac = 0;
int fdigits = 0;
if (PeekChar () == '.') {
hasFrac = true;
ReadChar ();
if (PeekChar () < 0)
throw JsonError ("Invalid JSON numeric literal; extra dot");
decimal d = 10;
while (true) {
c = PeekChar ();
if (c < '0' || '9' < c)
break;
ReadChar ();
frac += (c - '0') / d;
d *= 10;
fdigits++;
}
if (fdigits == 0)
throw JsonError ("Invalid JSON numeric literal; extra dot");
}
frac = Decimal.Round (frac, fdigits);
c = PeekChar ();
if (c != 'e' && c != 'E') {
if (!hasFrac) {
if (negative && int.MinValue <= -val ||
!negative && val <= int.MaxValue)
return (int) (negative ? -val : val);
if (negative && long.MinValue <= -val ||
!negative && val <= long.MaxValue)
return (long) (negative ? -val : val);
}
var v = val + frac;
return negative ? -v : v;
}
// exponent
ReadChar ();
int exp = 0;
if (PeekChar () < 0)
throw new ArgumentException ("Invalid JSON numeric literal; incomplete exponent");
bool negexp = false;
c = PeekChar ();
if (c == '-') {
ReadChar ();
negexp = true;
}
else if (c == '+')
ReadChar ();
if (PeekChar () < 0)
throw JsonError ("Invalid JSON numeric literal; incomplete exponent");
while (true) {
c = PeekChar ();
if (c < '0' || '9' < c)
break;
exp = exp * 10 + (c - '0');
ReadChar ();
}
// it is messy to handle exponent, so I just use Decimal.Parse() with assured JSON format.
if (negexp)
return new Decimal ((double) (val + frac) / Math.Pow (10, exp));
int [] bits = Decimal.GetBits (val + frac);
return new Decimal (bits [0], bits [1], bits [2], negative, (byte) exp);
}
StringBuilder vb = new StringBuilder ();
string ReadStringLiteral ()
{
if (PeekChar () != '"')
throw JsonError ("Invalid JSON string literal format");
ReadChar ();
vb.Length = 0;
while (true) {
int c = ReadChar ();
if (c < 0)
throw JsonError ("JSON string is not closed");
if (c == '"')
return vb.ToString ();
else if (c != '\\') {
vb.Append ((char) c);
continue;
}
// escaped expression
c = ReadChar ();
if (c < 0)
throw JsonError ("Invalid JSON string literal; incomplete escape sequence");
switch (c) {
case '"':
case '\\':
case '/':
vb.Append ((char) c);
break;
case 'b':
vb.Append ('\x8');
break;
case 'f':
vb.Append ('\f');
break;
case 'n':
vb.Append ('\n');
break;
case 'r':
vb.Append ('\r');
break;
case 't':
vb.Append ('\t');
break;
case 'u':
ushort cp = 0;
for (int i = 0; i < 4; i++) {
cp <<= 4;
if ((c = ReadChar ()) < 0)
throw JsonError ("Incomplete unicode character escape literal");
if ('0' <= c && c <= '9')
cp += (ushort) (c - '0');
if ('A' <= c && c <= 'F')
cp += (ushort) (c - 'A' + 10);
if ('a' <= c && c <= 'f')
cp += (ushort) (c - 'a' + 10);
}
vb.Append ((char) cp);
break;
default:
throw JsonError ("Invalid JSON string literal; unexpected escape character");
}
}
}
void Expect (char expected)
{
int c;
if ((c = ReadChar ()) != expected)
throw JsonError (String.Format ("Expected '{0}', got '{1}'", expected, (char) c));
}
void Expect (string expected)
{
for (int i = 0; i < expected.Length; i++)
if (ReadChar () != expected [i])
throw JsonError (String.Format ("Expected '{0}', differed at {1}", expected, i));
}
Exception JsonError (string msg)
{
return new ArgumentException (String.Format ("{0}. At line {1}, column {2}", msg, line, column));
}
}
}

File diff suppressed because it is too large Load Diff

View File

@ -0,0 +1,79 @@
//
// JsonReaderWriterFactory.cs
//
// Author:
// Atsushi Enomoto <atsushi@ximian.com>
//
// Copyright (C) 2007 Novell, Inc (http://www.novell.com)
//
// Permission is hereby granted, free of charge, to any person obtaining
// a copy of this software and associated documentation files (the
// "Software"), to deal in the Software without restriction, including
// without limitation the rights to use, copy, modify, merge, publish,
// distribute, sublicense, and/or sell copies of the Software, and to
// permit persons to whom the Software is furnished to do so, subject to
// the following conditions:
//
// The above copyright notice and this permission notice shall be
// included in all copies or substantial portions of the Software.
//
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
// EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
// NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
// LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
// OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
// WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
//
using System;
using System.IO;
using System.Text;
using System.Xml;
namespace System.Runtime.Serialization.Json
{
public static class JsonReaderWriterFactory
{
public static XmlDictionaryReader CreateJsonReader (byte [] buffer, XmlDictionaryReaderQuotas quotas)
{
if (buffer == null)
throw new ArgumentNullException ("buffer");
return CreateJsonReader (buffer, 0, buffer.Length, quotas);
}
public static XmlDictionaryReader CreateJsonReader (byte [] buffer, int offset, int count, XmlDictionaryReaderQuotas quotas)
{
return CreateJsonReader (buffer, offset, count, null, quotas, null);
}
public static XmlDictionaryReader CreateJsonReader (byte [] buffer, int offset, int count, Encoding encoding, XmlDictionaryReaderQuotas quotas, OnXmlDictionaryReaderClose onClose)
{
return new JsonReader (buffer, offset, count, encoding, quotas, onClose);
}
public static XmlDictionaryReader CreateJsonReader (Stream stream, XmlDictionaryReaderQuotas quotas)
{
return CreateJsonReader (stream, null, quotas, null);
}
public static XmlDictionaryReader CreateJsonReader (Stream stream, Encoding encoding, XmlDictionaryReaderQuotas quotas, OnXmlDictionaryReaderClose onClose)
{
return new JsonReader (stream, encoding, quotas, onClose);
}
public static XmlDictionaryWriter CreateJsonWriter (Stream stream)
{
return CreateJsonWriter (stream, new UTF8Encoding (false, true));
}
public static XmlDictionaryWriter CreateJsonWriter (Stream stream, Encoding encoding)
{
return CreateJsonWriter (stream, encoding, false);
}
public static XmlDictionaryWriter CreateJsonWriter (Stream stream, Encoding encoding, bool ownsStream)
{
return new JsonWriter (stream, encoding, ownsStream);
}
}
}

View File

@ -0,0 +1,412 @@
//
// JsonSerializationReader.cs
//
// Author:
// Atsushi Enomoto <atsushi@ximian.com>
//
// Copyright (C) 2008 Novell, Inc (http://www.novell.com)
//
// Permission is hereby granted, free of charge, to any person obtaining
// a copy of this software and associated documentation files (the
// "Software"), to deal in the Software without restriction, including
// without limitation the rights to use, copy, modify, merge, publish,
// distribute, sublicense, and/or sell copies of the Software, and to
// permit persons to whom the Software is furnished to do so, subject to
// the following conditions:
//
// The above copyright notice and this permission notice shall be
// included in all copies or substantial portions of the Software.
//
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
// EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
// NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
// LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
// OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
// WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
//
using System;
using System.Collections;
using System.Collections.Generic;
using System.Collections.ObjectModel;
using System.Globalization;
using System.IO;
using System.Linq;
using System.Reflection;
using System.Text;
using System.Xml;
namespace System.Runtime.Serialization.Json
{
class JsonSerializationReader
{
DataContractJsonSerializer serializer;
XmlReader reader;
int serialized_object_count;
bool verify_object_name;
Dictionary<Type, TypeMap> typemaps = new Dictionary<Type, TypeMap> ();
Type root_type;
public JsonSerializationReader (DataContractJsonSerializer serializer, XmlReader reader, Type rootType, bool verifyObjectName)
{
this.serializer = serializer;
this.reader = reader;
this.root_type = rootType;
this.verify_object_name = verifyObjectName;
}
public XmlReader Reader {
get { return reader; }
}
public object ReadRoot ()
{
TypeMap rootMap = GetTypeMap (root_type);
object v = ReadObject (root_type);
return v;
}
public object ReadObject (Type type)
{
return ReadObject (type, null);
}
public object ReadObject (Type type, object instance)
{
if (serialized_object_count ++ == serializer.MaxItemsInObjectGraph)
throw SerializationError (String.Format ("The object graph exceeded the maximum object count '{0}' specified in the serializer", serializer.MaxItemsInObjectGraph));
bool nullable = false;
if (type.IsGenericType && type.GetGenericTypeDefinition () == typeof (Nullable<>)) {
nullable = true;
type = Nullable.GetUnderlyingType (type);
}
bool isNull = reader.GetAttribute ("type") == "null";
switch (Type.GetTypeCode (type)) {
case TypeCode.DBNull:
string dbn = reader.ReadElementContentAsString ();
if (dbn != String.Empty)
throw new SerializationException (String.Format ("The only expected DBNull value string is '{{}}'. Tha actual input was '{0}'.", dbn));
return DBNull.Value;
case TypeCode.String:
if (isNull) {
reader.ReadElementContentAsString ();
return null;
}
else
return reader.ReadElementContentAsString ();
case TypeCode.Char:
var c = reader.ReadElementContentAsString ();
if (c.Length > 1)
throw new XmlException ("Invalid JSON char");
return Char.Parse(c);
case TypeCode.Single:
case TypeCode.Double:
case TypeCode.Decimal:
return ReadValueType (type, nullable);
case TypeCode.Byte:
case TypeCode.SByte:
case TypeCode.Int16:
case TypeCode.Int32:
case TypeCode.UInt16:
case TypeCode.UInt32:
case TypeCode.Int64:
if (type.IsEnum)
return Enum.ToObject (type, Convert.ChangeType (reader.ReadElementContentAsLong (), Enum.GetUnderlyingType (type), null));
else
return ReadValueType (type, nullable);
case TypeCode.UInt64:
if (type.IsEnum)
return Enum.ToObject (type, Convert.ChangeType (reader.ReadElementContentAsDecimal (), Enum.GetUnderlyingType (type), null));
else
return ReadValueType (type, nullable);
case TypeCode.Boolean:
return ReadValueType (type, nullable);
case TypeCode.DateTime:
// it does not use ReadElementContentAsDateTime(). Different string format.
var s = reader.ReadElementContentAsString ();
if (s.Length < 2 || !s.StartsWith ("/Date(", StringComparison.Ordinal) || !s.EndsWith (")/", StringComparison.Ordinal)) {
if (nullable)
return null;
throw new XmlException ("Invalid JSON DateTime format. The value format should be '/Date(UnixTime)/'");
}
// The date can contain [SIGN]LONG, [SIGN]LONG+HOURSMINUTES or [SIGN]LONG-HOURSMINUTES
// the format for HOURSMINUTES is DDDD
int tidx = s.IndexOf ('-', 8);
if (tidx == -1)
tidx = s.IndexOf ('+', 8);
int minutes = 0;
if (tidx == -1){
s = s.Substring (6, s.Length - 8);
} else {
int offset;
int.TryParse (s.Substring (tidx+1, s.Length-3-tidx), out offset);
minutes = (offset % 100) + (offset / 100) * 60;
if (s [tidx] == '-')
minutes = -minutes;
s = s.Substring (6, tidx-6);
}
var date = new DateTime (1970, 1, 1).AddMilliseconds (long.Parse (s));
if (minutes != 0)
date = date.AddMinutes (minutes);
return date;
default:
if (type == typeof (Guid)) {
return new Guid (reader.ReadElementContentAsString ());
} else if (type == typeof (Uri)) {
if (isNull) {
reader.ReadElementContentAsString ();
return null;
}
else
return new Uri (reader.ReadElementContentAsString (), UriKind.RelativeOrAbsolute);
} else if (type == typeof (XmlQualifiedName)) {
s = reader.ReadElementContentAsString ();
int idx = s.IndexOf (':');
return idx < 0 ? new XmlQualifiedName (s) : new XmlQualifiedName (s.Substring (0, idx), s.Substring (idx + 1));
} else if (type != typeof (object)) {
// strongly-typed object
if (reader.IsEmptyElement) {
// empty -> null array or object
reader.Read ();
return null;
}
Type ct = GetCollectionElementType (type);
if (ct != null) {
return DeserializeGenericCollection (type, ct, instance);
} else {
TypeMap map = GetTypeMap (type);
return map.Deserialize (this, instance);
}
}
else
return ReadInstanceDrivenObject ();
}
}
object ReadValueType (Type type, bool nullable)
{
string s = reader.ReadElementContentAsString ();
return nullable && s.Trim ().Length == 0 ? null : Convert.ChangeType (s, type, CultureInfo.InvariantCulture);
}
Type GetRuntimeType (string name)
{
name = ToRuntimeTypeName (name);
if (serializer.KnownTypes != null)
foreach (Type t in serializer.KnownTypes)
if (t.FullName == name)
return t;
var ret = root_type.Assembly.GetType (name, false) ?? Type.GetType (name, false);
if (ret != null)
return ret;
// We probably have to iterate all the existing
// assemblies that are loaded in current domain.
foreach (var ass in AppDomain.CurrentDomain.GetAssemblies ()) {
ret = ass.GetType (name, false);
if (ret != null)
return ret;
}
return null;
}
object ReadInstanceDrivenObject ()
{
string type = reader.GetAttribute ("type");
switch (type) {
case "null":
reader.Skip ();
return null;
case "object":
string runtimeType = reader.GetAttribute ("__type");
if (runtimeType != null) {
Type t = GetRuntimeType (runtimeType);
if (t == null)
throw SerializationError (String.Format ("Cannot load type '{0}'", runtimeType));
return ReadObject (t);
}
break;
}
string v = reader.ReadElementContentAsString ();
switch (type) {
case "boolean":
switch (v) {
case "true":
return true;
case "false":
return false;
default:
throw SerializationError (String.Format ("Invalid JSON boolean value: {0}", v));
}
case "string":
return v;
case "number":
int i;
if (int.TryParse (v, NumberStyles.None, CultureInfo.InvariantCulture, out i))
return i;
long l;
if (long.TryParse (v, NumberStyles.None, CultureInfo.InvariantCulture, out l))
return l;
ulong ul;
if (ulong.TryParse (v, NumberStyles.None, CultureInfo.InvariantCulture, out ul))
return ul;
double dbl;
if (double.TryParse (v, NumberStyles.None, CultureInfo.InvariantCulture, out dbl))
return dbl;
decimal dec;
if (decimal.TryParse (v, NumberStyles.None, CultureInfo.InvariantCulture, out dec))
return dec;
throw SerializationError (String.Format ("Invalid JSON input: {0}", v));
default:
throw SerializationError (String.Format ("Unexpected type: {0}", type));
}
}
string FormatTypeName (Type type)
{
return type.Namespace == null ? type.Name : String.Format ("{0}:#{1}", type.Name, type.Namespace);
}
string ToRuntimeTypeName (string s)
{
int idx = s.IndexOf (":#", StringComparison.Ordinal);
return idx < 0 ? s : String.Concat (s.Substring (idx + 2), ".", s.Substring (0, idx));
}
Type GetCollectionElementType (Type type)
{
if (type.IsArray)
return type.GetElementType ();
var inter = type.GetInterface ("System.Collections.Generic.IEnumerable`1", false);
if (inter != null)
return inter.GetGenericArguments () [0];
if (typeof (IEnumerable).IsAssignableFrom (type))
// return typeof(object) for mere collection.
return typeof (object);
else
return null;
}
object DeserializeGenericCollection (Type collectionType, Type elementType, object collectionInstance)
{
reader.ReadStartElement ();
object ret;
if (collectionType.IsInterface)
collectionType = typeof (List<>).MakeGenericType (elementType);
if (TypeMap.IsDictionary (collectionType)) {
if (collectionInstance == null)
collectionInstance = Activator.CreateInstance (collectionType);
var keyType = elementType.IsGenericType ? elementType.GetGenericArguments () [0] : typeof (object);
var valueType = elementType.IsGenericType ? elementType.GetGenericArguments () [1] : typeof (object);
MethodInfo add = collectionType.GetMethod ("Add", new Type [] { keyType, valueType });
for (reader.MoveToContent (); reader.NodeType != XmlNodeType.EndElement; reader.MoveToContent ()) {
if (!reader.IsStartElement ("item"))
throw SerializationError (String.Format ("Expected element 'item', but found '{0}' in namespace '{1}'", reader.LocalName, reader.NamespaceURI));
// reading a KeyValuePair in the form of <Key .../><Value .../>
reader.Read ();
reader.MoveToContent ();
object key = ReadObject (keyType);
reader.MoveToContent ();
object val = ReadObject (valueType);
reader.Read ();
add.Invoke (collectionInstance, new [] { key, val });
}
ret = collectionInstance;
} else if (typeof (IList).IsAssignableFrom (collectionType)) {
#if NET_2_1
Type listType = collectionType.IsArray ? typeof (List<>).MakeGenericType (elementType) : null;
#else
Type listType = collectionType.IsArray ? typeof (ArrayList) : null;
#endif
IList c;
if (collectionInstance == null)
c = (IList) Activator.CreateInstance (listType ?? collectionType);
else
c = (IList) collectionInstance;
for (reader.MoveToContent (); reader.NodeType != XmlNodeType.EndElement; reader.MoveToContent ()) {
if (!reader.IsStartElement ("item"))
throw SerializationError (String.Format ("Expected element 'item', but found '{0}' in namespace '{1}'", reader.LocalName, reader.NamespaceURI));
Type et = elementType == typeof (object) || elementType.IsAbstract ? null : elementType;
object elem = ReadObject (et ?? typeof (object));
c.Add (elem);
}
#if NET_2_1
if (collectionType.IsArray) {
Array array = Array.CreateInstance (elementType, c.Count);
c.CopyTo (array, 0);
ret = array;
}
else
ret = c;
#else
ret = collectionType.IsArray ? ((ArrayList) c).ToArray (elementType) : c;
#endif
} else {
if (collectionInstance == null)
collectionInstance = Activator.CreateInstance (collectionType);
MethodInfo add;
if (collectionInstance.GetType ().IsGenericType &&
collectionInstance.GetType ().GetGenericTypeDefinition () == typeof (LinkedList<>))
add = collectionType.GetMethod ("AddLast", new Type [] { elementType });
else
add = collectionType.GetMethod ("Add", new Type [] { elementType });
if (add == null) {
var icoll = typeof (ICollection<>).MakeGenericType (elementType);
if (icoll.IsAssignableFrom (collectionInstance.GetType ()))
add = icoll.GetMethod ("Add");
}
if (add == null)
throw new MissingMethodException (elementType.FullName, "Add");
for (reader.MoveToContent (); reader.NodeType != XmlNodeType.EndElement; reader.MoveToContent ()) {
if (!reader.IsStartElement ("item"))
throw SerializationError (String.Format ("Expected element 'item', but found '{0}' in namespace '{1}'", reader.LocalName, reader.NamespaceURI));
object element = ReadObject (elementType);
add.Invoke (collectionInstance, new object [] { element });
}
ret = collectionInstance;
}
reader.ReadEndElement ();
return ret;
}
TypeMap GetTypeMap (Type type)
{
TypeMap map;
if (!typemaps.TryGetValue (type, out map)) {
map = TypeMap.CreateTypeMap (type);
typemaps [type] = map;
}
return map;
}
Exception SerializationError (string basemsg)
{
IXmlLineInfo li = reader as IXmlLineInfo;
if (li == null || !li.HasLineInfo ())
return new SerializationException (basemsg);
else
return new SerializationException (String.Format ("{0}. Error at {1} ({2},{3})", basemsg, reader.BaseURI, li.LineNumber, li.LinePosition));
}
}
}

View File

@ -0,0 +1,210 @@
//
// JsonSerializationWriter.cs
//
// Author:
// Atsushi Enomoto <atsushi@ximian.com>
//
// Copyright (C) 2008 Novell, Inc (http://www.novell.com)
//
// Permission is hereby granted, free of charge, to any person obtaining
// a copy of this software and associated documentation files (the
// "Software"), to deal in the Software without restriction, including
// without limitation the rights to use, copy, modify, merge, publish,
// distribute, sublicense, and/or sell copies of the Software, and to
// permit persons to whom the Software is furnished to do so, subject to
// the following conditions:
//
// The above copyright notice and this permission notice shall be
// included in all copies or substantial portions of the Software.
//
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
// EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
// NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
// LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
// OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
// WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
//
using System;
using System.Collections;
using System.Collections.Generic;
using System.Collections.ObjectModel;
using System.Globalization;
using System.IO;
using System.Reflection;
using System.Text;
using System.Xml;
namespace System.Runtime.Serialization.Json
{
class JsonSerializationWriter
{
DataContractJsonSerializer serializer;
XmlWriter writer;
int serialized_object_count;
bool always_emit_type;
Dictionary<Type, TypeMap> typemaps = new Dictionary<Type, TypeMap> ();
Type root_type;
public JsonSerializationWriter (DataContractJsonSerializer serializer, XmlWriter writer, Type rootType, bool alwaysEmitTypeInformation)
{
this.serializer = serializer;
this.writer = writer;
this.root_type = rootType;
this.always_emit_type = alwaysEmitTypeInformation;
}
public XmlWriter Writer {
get { return writer; }
}
public void WriteObjectContent (object graph, bool top, bool outputTypeName)
{
if (graph == null) {
if (top)
GetTypeMap (root_type); // to make sure to reject invalid contracts
writer.WriteAttributeString ("type", "null");
writer.WriteString (null);
return;
}
if (serialized_object_count ++ == serializer.MaxItemsInObjectGraph)
throw new SerializationException (String.Format ("The object graph exceeded the maximum object count '{0}' specified in the serializer", serializer.MaxItemsInObjectGraph));
var type = graph.GetType ();
if (type.IsGenericType && type.GetGenericTypeDefinition () == typeof (Nullable<>))
type = type.GetGenericArguments () [0];
switch (Type.GetTypeCode (type)) {
case TypeCode.Char:
case TypeCode.String:
writer.WriteString (graph.ToString ());
break;
case TypeCode.Single:
case TypeCode.Double:
writer.WriteAttributeString ("type", "number");
writer.WriteString (((IFormattable) graph).ToString ("R", CultureInfo.InvariantCulture));
break;
case TypeCode.Byte:
case TypeCode.SByte:
case TypeCode.Int16:
case TypeCode.Int32:
case TypeCode.Int64:
case TypeCode.UInt16:
case TypeCode.UInt32:
case TypeCode.UInt64:
case TypeCode.Decimal:
writer.WriteAttributeString ("type", "number");
if (type.IsEnum)
graph = ((IConvertible) graph).ToType (Enum.GetUnderlyingType (type), CultureInfo.InvariantCulture);
writer.WriteString (((IFormattable) graph).ToString ("G", CultureInfo.InvariantCulture));
break;
case TypeCode.Boolean:
writer.WriteAttributeString ("type", "boolean");
if ((bool) graph)
writer.WriteString ("true");
else
writer.WriteString ("false");
break;
case TypeCode.DateTime:
writer.WriteString (String.Format (CultureInfo.InvariantCulture, "/Date({0})/", (long) ((DateTime) graph).Subtract (new DateTime (1970, 1, 1)).TotalMilliseconds));
break;
default:
if (graph is Guid) {
goto case TypeCode.String;
} else if (graph is Uri) {
goto case TypeCode.String;
} else if (graph is XmlQualifiedName) {
XmlQualifiedName qn = (XmlQualifiedName) graph;
writer.WriteString (qn.Name);
writer.WriteString (":");
writer.WriteString (qn.Namespace);
} else if (TypeMap.IsDictionary (type)) {
writer.WriteAttributeString ("type", "array");
bool otn = !(graph is Array && type.GetElementType () != typeof (object));
var d = graph as IDictionary;
if (d != null) {
// Optimize the IDictionary case to avoid reflection
foreach (object k in d.Keys)
WriteItem (k, d [k], otn);
} else {
// we can't typecast to IDictionary<,> and can't use dynamic for iOS support
var itemGetter = GetDictionaryProperty (type, "Item");
var keysGetter = GetDictionaryProperty (type, "Keys");
var argarr = new object [1];
foreach (object o in (IEnumerable) keysGetter.GetValue (graph, null)) {
argarr [0] = o;
WriteItem (o, itemGetter.GetValue (graph, argarr), otn);
}
}
} else if (graph is Array || TypeMap.IsEnumerable (type)) {
writer.WriteAttributeString ("type", "array");
foreach (object o in (IEnumerable) graph) {
writer.WriteStartElement ("item");
// when it is typed, then no need to output "__type"
WriteObjectContent (o, false, !(graph is Array && type.GetElementType () != typeof (object)));
writer.WriteEndElement ();
}
} else { // object
TypeMap tm = GetTypeMap (type);
if (tm != null) {
// FIXME: I'm not sure how it is determined whether __type is written or not...
if (outputTypeName || always_emit_type)
writer.WriteAttributeString ("__type", FormatTypeName (type));
tm.Serialize (this, graph, "object");
}
else
// it does not emit type="object" (as the graph is regarded as a string)
// writer.WriteString (graph.ToString ());
throw new InvalidDataContractException (String.Format ("Type {0} cannot be serialized by this JSON serializer", type));
}
break;
}
}
void WriteItem (object key, object value, bool outputTypeName)
{
writer.WriteStartElement ("item");
writer.WriteAttributeString ("type", "object");
// outputting a KeyValuePair as <Key .. /><Value ... />
writer.WriteStartElement ("Key");
WriteObjectContent (key, false, outputTypeName);
writer.WriteEndElement ();
writer.WriteStartElement ("Value");
WriteObjectContent (value, false, outputTypeName);
writer.WriteEndElement ();
writer.WriteEndElement ();
}
PropertyInfo GetDictionaryProperty (Type type, string propertyName)
{
var p = type.GetProperty (propertyName);
if (p != null)
return p;
// check explicit - but the generic names might differ, e.g. TKey,TValue vs T,V
var ap = type.GetProperties (BindingFlags.Instance | BindingFlags.NonPublic);
foreach (var cp in ap) {
if (!cp.Name.EndsWith (propertyName, StringComparison.Ordinal))
continue;
if (cp.Name.StartsWith ("System.Collections.Generic.IDictionary<", StringComparison.Ordinal))
return cp;
}
return null;
}
string FormatTypeName (Type type)
{
return String.Format ("{0}:#{1}", type.Name, type.Namespace);
}
TypeMap GetTypeMap (Type type)
{
TypeMap map;
if (!typemaps.TryGetValue (type, out map)) {
map = TypeMap.CreateTypeMap (type);
typemaps [type] = map;
}
return map;
}
}
}

View File

@ -0,0 +1,374 @@
//
// TypeMap.cs
//
// Author:
// Atsushi Enomoto <atsushi@ximian.com>
//
// Copyright (C) 2008 Novell, Inc (http://www.novell.com)
//
// Permission is hereby granted, free of charge, to any person obtaining
// a copy of this software and associated documentation files (the
// "Software"), to deal in the Software without restriction, including
// without limitation the rights to use, copy, modify, merge, publish,
// distribute, sublicense, and/or sell copies of the Software, and to
// permit persons to whom the Software is furnished to do so, subject to
// the following conditions:
//
// The above copyright notice and this permission notice shall be
// included in all copies or substantial portions of the Software.
//
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
// EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
// NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
// LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
// OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
// WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
//
using System;
using System.Collections;
using System.Collections.Generic;
using System.Collections.ObjectModel;
using System.Globalization;
using System.IO;
using System.Linq;
using System.Reflection;
using System.Runtime.CompilerServices;
using System.Runtime.Serialization;
using System.Text;
using System.Xml;
namespace System.Runtime.Serialization.Json
{
class TypeMap
{
static bool IsInvalidNCName (string name)
{
if (name == null || name.Length == 0)
return true;
try {
XmlConvert.VerifyNCName (name);
} catch (XmlException) {
return true;
}
return false;
}
public static TypeMap CreateTypeMap (Type type)
{
object [] atts = type.GetCustomAttributes (typeof (DataContractAttribute), true);
if (atts.Length == 1)
return CreateTypeMap (type, (DataContractAttribute) atts [0]);
atts = type.GetCustomAttributes (typeof (SerializableAttribute), false);
if (atts.Length == 1)
return CreateTypeMap (type, null);
if (IsPrimitiveType (type))
return null;
return CreateDefaultTypeMap (type);
}
static bool IsPrimitiveType (Type type)
{
if (type.IsEnum)
return true;
if (Type.GetTypeCode (type) != TypeCode.Object)
return true; // FIXME: it is likely hacky
return false;
}
static TypeMap CreateDefaultTypeMap (Type type)
{
var l = new List<TypeMapMember> ();
foreach (var fi in type.GetFields ())
if (!fi.IsStatic)
l.Add (new TypeMapField (fi, null));
foreach (var pi in type.GetProperties ())
if (pi.CanRead && pi.CanWrite && !pi.GetGetMethod (true).IsStatic && pi.GetIndexParameters ().Length == 0)
l.Add (new TypeMapProperty (pi, null));
l.Sort ((x, y) => x.Order != y.Order ? x.Order - y.Order : String.Compare (x.Name, y.Name, StringComparison.Ordinal));
return new TypeMap (type, null, l.ToArray ());
}
internal static bool IsDictionary (Type type)
{
Type inter;
inter = type.GetInterface ("System.Collections.IDictionary", false);
if (inter != null
&& type.GetMethod ("Add", new Type[] { typeof (object), typeof (object) }) != null)
return true;
inter = type.GetInterface ("System.Collections.Generic.IDictionary`2", false);
if (inter != null
&& type.GetMethod ("Add", new Type[] { inter.GetGenericArguments() [0],
inter.GetGenericArguments() [1] }) != null)
return true;
return false;
}
internal static bool IsEnumerable (Type type)
{
if (type.IsGenericType &&
type.GetGenericTypeDefinition() == typeof (LinkedList<>))
return true;
if (IsPrimitiveType (type) || IsDictionary (type))
return false;
Type inter;
inter = type.GetInterface ("System.Collections.Generic.IReadOnlyCollection`1", false);
if (inter != null)
return true;
inter = type.GetInterface ("System.Collections.IEnumerable", false);
if (inter != null && type.GetMethod ("Add", new Type[] { typeof (object) }) != null)
return true;
inter = type.GetInterface ("System.Collections.Generic.IEnumerable`1", false);
if (inter != null && type.GetMethod ("Add", new Type[] { inter.GetGenericArguments() [0] }) != null)
return true;
return false;
}
static TypeMap CreateTypeMap (Type type, DataContractAttribute dca)
{
if (dca != null && dca.Name != null && IsInvalidNCName (dca.Name))
throw new InvalidDataContractException (String.Format ("DataContractAttribute for type '{0}' has an invalid name", type));
List<TypeMapMember> members = new List<TypeMapMember> ();
foreach (FieldInfo fi in type.GetFields (binding_flags)) {
if (fi.GetCustomAttributes (typeof (CompilerGeneratedAttribute), false).Length > 0)
continue;
if (dca != null) {
object [] atts = fi.GetCustomAttributes (typeof (DataMemberAttribute), true);
if (atts.Length == 0)
continue;
DataMemberAttribute dma = (DataMemberAttribute) atts [0];
members.Add (new TypeMapField (fi, dma));
} else {
if (fi.GetCustomAttributes (typeof (IgnoreDataMemberAttribute), false).Length > 0)
continue;
members.Add (new TypeMapField (fi, null));
}
}
if (dca != null) {
foreach (PropertyInfo pi in type.GetProperties (binding_flags)) {
object [] atts = pi.GetCustomAttributes (typeof (DataMemberAttribute), true);
if (atts.Length == 0)
continue;
if (pi.GetIndexParameters ().Length > 0)
continue;
if (IsEnumerable (pi.PropertyType) || IsDictionary (pi.PropertyType)) {
if (!pi.CanRead)
throw new InvalidDataContractException (String.Format ("Property {0} must have a getter", pi));
}
else if (!pi.CanRead || !pi.CanWrite)
throw new InvalidDataContractException (String.Format ("Non-collection property {0} must have both getter and setter", pi));
DataMemberAttribute dma = (DataMemberAttribute) atts [0];
members.Add (new TypeMapProperty (pi, dma));
}
}
members.Sort (delegate (TypeMapMember m1, TypeMapMember m2) { return m1.Order != m2.Order ? m1.Order - m2.Order : String.CompareOrdinal (m1.Name, m2.Name); });
return new TypeMap (type, dca == null ? null : dca.Name, members.ToArray ());
}
Type type;
string element;
TypeMapMember [] members;
static readonly Type [] deser_methods_args = new Type [] { typeof (StreamingContext) };
const BindingFlags binding_flags = BindingFlags.Public | BindingFlags.NonPublic | BindingFlags.Instance;
public TypeMap (Type type, string element, TypeMapMember [] orderedMembers)
{
this.type = type;
this.element = element;
this.members = orderedMembers;
foreach (var mi in type.GetMethods (binding_flags)) {
if (mi.GetCustomAttributes (typeof (OnDeserializingAttribute), false).Length > 0)
OnDeserializing = mi;
else if (mi.GetCustomAttributes (typeof (OnDeserializedAttribute), false).Length > 0)
OnDeserialized = mi;
else if (mi.GetCustomAttributes (typeof (OnSerializingAttribute), false).Length > 0)
OnSerializing = mi;
else if (mi.GetCustomAttributes (typeof (OnSerializedAttribute), false).Length > 0)
OnSerialized = mi;
}
}
public MethodInfo OnDeserializing { get; set; }
public MethodInfo OnDeserialized { get; set; }
public MethodInfo OnSerializing { get; set; }
public MethodInfo OnSerialized { get; set; }
public virtual void Serialize (JsonSerializationWriter outputter, object graph, string type)
{
if (OnSerializing != null)
OnSerializing.Invoke (graph, new object [] {new StreamingContext (StreamingContextStates.All)});
outputter.Writer.WriteAttributeString ("type", type);
foreach (TypeMapMember member in members) {
object memberObj = member.GetMemberOf (graph);
// FIXME: consider EmitDefaultValue
outputter.Writer.WriteStartElement (member.Name);
outputter.WriteObjectContent (memberObj, false, false);
outputter.Writer.WriteEndElement ();
}
if (OnSerialized != null)
OnSerialized.Invoke (graph, new object [] {new StreamingContext (StreamingContextStates.All)});
}
internal static object CreateInstance (Type type)
{
if (TypeMap.IsDictionary (type)) {
if (type.IsGenericType)
return Activator.CreateInstance (typeof (Dictionary<,>).MakeGenericType (type.GetGenericArguments ()));
else
return new Hashtable ();
} else if (TypeMap.IsEnumerable (type)) {
if (type.IsGenericType)
return Activator.CreateInstance (typeof (List<>).MakeGenericType (type.GetGenericArguments ()));
else
return new ArrayList ();
}
else
return FormatterServices.GetUninitializedObject (type);
}
public virtual object Deserialize (JsonSerializationReader jsr, object o)
{
XmlReader reader = jsr.Reader;
bool isNull = reader.GetAttribute ("type") == "null";
object ret = isNull ? null : CreateInstance (type);
if (ret != null && OnDeserializing != null)
OnDeserializing.Invoke (ret, new object [] {new StreamingContext (StreamingContextStates.All)});
Dictionary<TypeMapMember,bool> filled = new Dictionary<TypeMapMember,bool> ();
reader.ReadStartElement ();
for (reader.MoveToContent (); reader.NodeType != XmlNodeType.EndElement; reader.MoveToContent ()) {
bool consumed = false;
for (int i = 0; i < members.Length; i++) {
TypeMapMember mm = members [i];
if (mm.Name == reader.LocalName && reader.NamespaceURI == String.Empty) {
if (filled.ContainsKey (mm))
throw new SerializationException (String.Format ("Object content '{0}' for '{1}' already appeared in the reader", reader.LocalName, type));
mm.SetMemberValue (ret, jsr);
filled [mm] = true;
consumed = true;
break;
}
}
if (!consumed)
reader.Skip ();
}
reader.ReadEndElement ();
if (ret != null && OnDeserialized != null)
OnDeserialized.Invoke (ret, new object [] {new StreamingContext (StreamingContextStates.All)});
return ret;
}
}
abstract class TypeMapMember
{
MemberInfo mi;
DataMemberAttribute dma;
protected TypeMapMember (MemberInfo mi, DataMemberAttribute dma)
{
this.mi = mi;
this.dma = dma;
}
public string Name {
get { return dma == null ? mi.Name : dma.Name ?? mi.Name; }
}
public bool EmitDefaultValue {
get { return dma != null && dma.EmitDefaultValue; }
}
public bool IsRequired {
get { return dma != null && dma.IsRequired; }
}
public int Order {
get { return dma != null ? dma.Order : -1; }
}
public abstract Type Type { get; }
public abstract object GetMemberOf (object owner);
public abstract void SetMemberValue (object owner, JsonSerializationReader value);
}
class TypeMapField : TypeMapMember
{
FieldInfo field;
public TypeMapField (FieldInfo fi, DataMemberAttribute dma)
: base (fi, dma)
{
this.field = fi;
}
public override Type Type {
get { return field.FieldType; }
}
public override object GetMemberOf (object owner)
{
return field.GetValue (owner);
}
public override void SetMemberValue (object owner, JsonSerializationReader jsr)
{
field.SetValue (owner, jsr.ReadObject (this.Type));
}
}
class TypeMapProperty : TypeMapMember
{
PropertyInfo property;
public TypeMapProperty (PropertyInfo pi, DataMemberAttribute dma)
: base (pi, dma)
{
this.property = pi;
}
public override Type Type {
get { return property.PropertyType; }
}
public override object GetMemberOf (object owner)
{
return property.GetValue (owner, null);
}
public override void SetMemberValue (object owner, JsonSerializationReader jsr)
{
var pSetter = this.property.GetSetMethod (true);
if (pSetter != null) {
property.SetValue (owner, jsr.ReadObject (this.Type), null);
} else { // no setter
var oldValue = property.GetValue (owner, null);
try {
jsr.ReadObject (this.Type, oldValue);
} catch (MissingMethodException e) {
throw new InvalidDataContractException (string.Format ("No set method for property '{0}' "
+ "in type '{1}'.", this.property.Name, this.property.PropertyType.FullName), e);
}
}
}
}
}