diff --git a/NzbDrone.Common/NzbDrone.Common.csproj b/NzbDrone.Common/NzbDrone.Common.csproj index a45da81fd..e7c0441a5 100644 --- a/NzbDrone.Common/NzbDrone.Common.csproj +++ b/NzbDrone.Common/NzbDrone.Common.csproj @@ -38,9 +38,8 @@ ..\Libraries\Exceptioneer.WindowsFormsClient.dll - - False - ..\packages\Exceptron.Driver.0.1.0.30\lib\net20\Exceptron.Driver.dll + + ..\packages\Exceptron.Driver.0.1.0.34\lib\net20\Exceptron.Driver.dll ..\packages\Newtonsoft.Json.4.5.4\lib\net40\Newtonsoft.Json.dll diff --git a/NzbDrone.Common/ReportingService.cs b/NzbDrone.Common/ReportingService.cs index 3dda58536..43bc34205 100644 --- a/NzbDrone.Common/ReportingService.cs +++ b/NzbDrone.Common/ReportingService.cs @@ -111,7 +111,7 @@ namespace NzbDrone.Common ApplicationVersion = new EnvironmentProvider().Version.ToString() }; - ExceptronDriver.ThrowsExceptions = !EnvironmentProvider.IsProduction; + ExceptronDriver.ClientConfiguration.ThrowsExceptions = !EnvironmentProvider.IsProduction; ExceptronDriver.Enviroment = EnvironmentProvider.IsProduction ? "Prod" : "Dev"; } diff --git a/NzbDrone.Common/packages.config b/NzbDrone.Common/packages.config index c309ac792..877aabc4c 100644 --- a/NzbDrone.Common/packages.config +++ b/NzbDrone.Common/packages.config @@ -1,6 +1,6 @@  - + \ No newline at end of file diff --git a/packages/Exceptron.Driver.0.1.0.30/Exceptron.Driver.0.1.0.30.nupkg b/packages/Exceptron.Driver.0.1.0.30/Exceptron.Driver.0.1.0.30.nupkg deleted file mode 100644 index 445b8e732..000000000 Binary files a/packages/Exceptron.Driver.0.1.0.30/Exceptron.Driver.0.1.0.30.nupkg and /dev/null differ diff --git a/packages/Exceptron.Driver.0.1.0.30/lib/net20/Exceptron.Driver.dll b/packages/Exceptron.Driver.0.1.0.30/lib/net20/Exceptron.Driver.dll deleted file mode 100644 index c9a96ac93..000000000 Binary files a/packages/Exceptron.Driver.0.1.0.30/lib/net20/Exceptron.Driver.dll and /dev/null differ diff --git a/packages/Exceptron.Driver.0.1.0.34/Exceptron.Driver.0.1.0.34.nupkg b/packages/Exceptron.Driver.0.1.0.34/Exceptron.Driver.0.1.0.34.nupkg new file mode 100644 index 000000000..afe22d692 Binary files /dev/null and b/packages/Exceptron.Driver.0.1.0.34/Exceptron.Driver.0.1.0.34.nupkg differ diff --git a/packages/Exceptron.Driver.0.1.0.34/lib/net20/Exceptron.Driver.dll b/packages/Exceptron.Driver.0.1.0.34/lib/net20/Exceptron.Driver.dll new file mode 100644 index 000000000..d22620a57 Binary files /dev/null and b/packages/Exceptron.Driver.0.1.0.34/lib/net20/Exceptron.Driver.dll differ diff --git a/packages/Exceptron.Driver.0.1.0.34/lib/net20/Exceptron.Driver.pdb b/packages/Exceptron.Driver.0.1.0.34/lib/net20/Exceptron.Driver.pdb new file mode 100644 index 000000000..548a9f199 Binary files /dev/null and b/packages/Exceptron.Driver.0.1.0.34/lib/net20/Exceptron.Driver.pdb differ diff --git a/packages/Exceptron.Driver.0.1.0.34/src/ClientConfiguration.cs b/packages/Exceptron.Driver.0.1.0.34/src/ClientConfiguration.cs new file mode 100644 index 000000000..5a80cdad2 --- /dev/null +++ b/packages/Exceptron.Driver.0.1.0.34/src/ClientConfiguration.cs @@ -0,0 +1,24 @@ +using Exceptron.Driver.Message; + +namespace Exceptron.Driver +{ + public class ClientConfiguration + { + + public ClientConfiguration() + { + ServerUrl = "http://api.exceptron.com/v1a/"; + } + + /// + /// If ExceptronClinet should throw exceptions in case of an error. Default: + /// + /// + /// Its recommended that this flag is set to True during development and in production systems. + /// If an exception is thrown while this flag is set to the thrown exception will be returned in + /// + public bool ThrowsExceptions { get; set; } + + internal string ServerUrl { get; set; } + } +} diff --git a/packages/Exceptron.Driver.0.1.0.34/src/ExceptionClient.cs b/packages/Exceptron.Driver.0.1.0.34/src/ExceptionClient.cs new file mode 100644 index 000000000..642ef9911 --- /dev/null +++ b/packages/Exceptron.Driver.0.1.0.34/src/ExceptionClient.cs @@ -0,0 +1,211 @@ +using System; +using System.Collections.Generic; +using System.Diagnostics; +using System.Globalization; +using System.Reflection; +using System.Threading; +using Exceptron.Driver.Message; + +namespace Exceptron.Driver +{ + public class ExceptionClient + { + private readonly string _apiKey; + internal IRestClient RestClient { get; set; } + + /// + /// Version of Driver + /// + public string DriverVersion + { + get { return Assembly.GetExecutingAssembly().GetName().Version.ToString(); } + } + + + /// + /// Name of Driver + /// + public string DriverName + { + get { return "Official .NET"; } + } + + /// + /// Client Configuration + /// + public ClientConfiguration ClientConfiguration { get; private set; } + + /// + /// Environment that the application is running in + /// + /// + /// Dev, Staging, Production + /// + public string Enviroment { get; set; } + + /// + /// Version of application executing. Default: Version of + /// + public string ApplicationVersion { get; set; } + + + + /// Your Exceptron API Key + public ExceptionClient(string apiKey) + : this(apiKey, new ClientConfiguration()) + { + } + + /// Your Exceptron API Key + /// Configuration to use for this client + private ExceptionClient(string apiKey, ClientConfiguration clientConfiguration) + { + ClientConfiguration = clientConfiguration; + _apiKey = apiKey; + + RestClient = new RestClient(); + + SetApplicationVersion(); + } + + /// + /// Submit an exception to Exceptron Servers. + /// + /// Exception data to be reported to the server + public ExceptionResponse SubmitException(ExceptionData exceptionData) + { + try + { + if (exceptionData == null) + throw new ArgumentNullException("exceptionData"); + + if (exceptionData.Exception == null) + throw new ArgumentException("ExceptionData.Exception Cannot be null.", "exceptionData"); + + var report = new ExceptionReport(); + + report.ap = _apiKey; + report.dn = DriverName; + report.dv = DriverVersion; + report.aver = ApplicationVersion; + + report.ext = exceptionData.Exception.GetType().FullName; + report.stk = ConvertToFrames(exceptionData.Exception); + report.exm = exceptionData.Exception.Message; + + report.cmp = exceptionData.Component; + report.uid = exceptionData.UserId; + report.env = Enviroment; + report.msg = exceptionData.Message; + report.cul = Thread.CurrentThread.CurrentCulture.Name; + report.os = Environment.OSVersion.VersionString; + report.sv = (int)exceptionData.Severity; + + var response = RestClient.Put(ClientConfiguration.ServerUrl, report); + + return response; + } + catch (Exception e) + { + Trace.WriteLine("Unable to submit exception to exceptron. ", e.ToString()); + + if (ClientConfiguration.ThrowsExceptions) + { + throw; + } + else + { + return new ExceptionResponse { Exception = e }; + } + } + } + + + private void SetApplicationVersion() + { + try + { + var entryAssembly = GetWebEntryAssembly(); + + if (entryAssembly == null) + { + entryAssembly = Assembly.GetEntryAssembly(); + } + + if (entryAssembly == null) + { + entryAssembly = Assembly.GetCallingAssembly(); + } + + if (entryAssembly != null) + { + ApplicationVersion = entryAssembly.GetName().Version.ToString(); + } + } + catch (Exception e) + { + Trace.WriteLine("Can't figure out application version.", e.ToString()); + } + } + + static private Assembly GetWebEntryAssembly() + { + if (System.Web.HttpContext.Current == null || + System.Web.HttpContext.Current.ApplicationInstance == null) + { + return null; + } + + var type = System.Web.HttpContext.Current.ApplicationInstance.GetType(); + while (type != null && type.Namespace == "ASP") + { + type = type.BaseType; + } + + return type == null ? null : type.Assembly; + } + + internal static List ConvertToFrames(Exception exception) + { + if (exception == null) return null; + + var stackTrace = new StackTrace(exception, true); + + var frames = stackTrace.GetFrames(); + + if (frames == null) return null; + + var result = new List(); + + for (int index = 0; index < frames.Length; index++) + { + var frame = frames[index]; + var method = frame.GetMethod(); + var declaringType = method.DeclaringType; + + var currentFrame = new Frame + { + i = index, + fn = frame.GetFileName(), + ln = frame.GetFileLineNumber(), + m = method.ToString(), + }; + + + currentFrame.m = currentFrame.m.Substring(currentFrame.m.IndexOf(' ')).Trim(); + + + if (declaringType != null) + { + currentFrame.c = declaringType.FullName; + } + + result.Add(currentFrame); + } + + + return result; + } + + } +} diff --git a/packages/Exceptron.Driver.0.1.0.34/src/ExceptionData.cs b/packages/Exceptron.Driver.0.1.0.34/src/ExceptionData.cs new file mode 100644 index 000000000..db8e5b5ca --- /dev/null +++ b/packages/Exceptron.Driver.0.1.0.34/src/ExceptionData.cs @@ -0,0 +1,54 @@ +using System; + +namespace Exceptron.Driver +{ + /// + /// Represents information that will be used to construct an exception report. + /// + public class ExceptionData + { + /// + /// Exception that is being reported + /// + public Exception Exception { get; set; } + + /// + /// Component that caused this error. + /// + /// + /// It is common to use the logger name that was used to log the exception as the component. + /// + /// + /// DataAccess, Configuration, Registration, etc. + /// + public string Component { get; set; } + + /// + /// ID that will uniquely identify the user + /// + /// + /// This Id does not have to be tied to the user's identity. + /// You can use a system generated unique ID such as GUID. + /// This field is used to report how many unique users are experiencing an error. + /// + /// + /// "62E5C8EF-0CA2-43AB-B278-FC6994F776ED" + /// "Timmy@aol.com" + /// "26437" + /// + public string UserId { get; set; } + + /// + /// Any message that should be attached to this exceptions + /// + /// + /// Something went wrong while checking for application updates. + /// + public string Message { get; set; } + + /// + /// Severity of the exception being reported + /// + public ExceptionSeverity Severity { get; set; } + } +} \ No newline at end of file diff --git a/packages/Exceptron.Driver.0.1.0.34/src/ExceptionSeverity.cs b/packages/Exceptron.Driver.0.1.0.34/src/ExceptionSeverity.cs new file mode 100644 index 000000000..d1bbe849e --- /dev/null +++ b/packages/Exceptron.Driver.0.1.0.34/src/ExceptionSeverity.cs @@ -0,0 +1,28 @@ +namespace Exceptron.Driver +{ + /// + /// Severity of the exception being reported + /// + public enum ExceptionSeverity + { + /// + /// Excepted Error. Can be ignored + /// + None = 0, + + /// + /// Error that can be handled gracefully + /// + Warning = 1, + + /// + /// Blocking user from completing their intended action + /// + Error = 2, + + /// + /// Will most likely cause the application to crash + /// + Fatal = 3 + } +} \ No newline at end of file diff --git a/packages/Exceptron.Driver.0.1.0.34/src/IRestClient.cs b/packages/Exceptron.Driver.0.1.0.34/src/IRestClient.cs new file mode 100644 index 000000000..a1e9a5d48 --- /dev/null +++ b/packages/Exceptron.Driver.0.1.0.34/src/IRestClient.cs @@ -0,0 +1,7 @@ +namespace Exceptron.Driver +{ + internal interface IRestClient + { + TResponse Put(string url, object report) where TResponse : class, new(); + } +} \ No newline at end of file diff --git a/packages/Exceptron.Driver.0.1.0.34/src/Message/ExceptionReport.cs b/packages/Exceptron.Driver.0.1.0.34/src/Message/ExceptionReport.cs new file mode 100644 index 000000000..d3d64c74d --- /dev/null +++ b/packages/Exceptron.Driver.0.1.0.34/src/Message/ExceptionReport.cs @@ -0,0 +1,79 @@ +using System.Collections.Generic; + +namespace Exceptron.Driver.Message +{ + internal class ExceptionReport + { + /// + /// API key + /// + public string ap { get; set; } + + /// + /// Application Version + /// + public string aver { get; set; } + + /// + /// Exception Severity + /// + public int sv { get; set; } + + /// + /// User or Instance ID + /// + public string uid { get; set; } + + /// + /// Type of exception + /// + public string ext { get; set; } + + /// + /// Exception message + /// + public string exm { get; set; } + + /// + /// List of frames that make up the StackTrace of the exception + /// + public List stk { get; set; } + + /// + /// Component that experienced this exception + /// + public string cmp { get; set; } + + /// + /// Environment that this exception occurred in. + /// + /// Dev, Stage, Production + public string env { get; set; } + + /// + /// Message that was logged along with the exception. + /// + public string msg { get; set; } + + /// + /// User's culture in + /// + /// http://msdn.microsoft.com/en-us/library/system.globalization.cultureinfo.name.aspx + public string cul { get; set; } + + /// + /// OS Version + /// + public string os { get; set; } + + /// + /// Name of the driver that generated and is sending this message + /// + public string dn { get; set; } + + /// + /// Version of the driver that generated and is sending this message + /// + public string dv { get; set; } + } +} \ No newline at end of file diff --git a/packages/Exceptron.Driver.0.1.0.34/src/Message/ExceptionResponse.cs b/packages/Exceptron.Driver.0.1.0.34/src/Message/ExceptionResponse.cs new file mode 100644 index 000000000..7277ee31e --- /dev/null +++ b/packages/Exceptron.Driver.0.1.0.34/src/Message/ExceptionResponse.cs @@ -0,0 +1,33 @@ +using System; + +namespace Exceptron.Driver.Message +{ + public class ExceptionResponse + { + /// + /// Exception report reference ID. This ID will be shared across + /// similar exceptions + /// + public string RefId { get; internal set; } + + /// + /// Was the report successfully processed on the server + /// + public bool Successful + { + get + { + return !string.IsNullOrEmpty(RefId); + } + } + + /// + /// Exception that caused the message to fail. + /// + /// + /// This property will only be populated if is set to /> + /// Exception is thrown if is set to . + /// + public Exception Exception { get; internal set; } + } +} \ No newline at end of file diff --git a/packages/Exceptron.Driver.0.1.0.34/src/Message/Frame.cs b/packages/Exceptron.Driver.0.1.0.34/src/Message/Frame.cs new file mode 100644 index 000000000..5334862b3 --- /dev/null +++ b/packages/Exceptron.Driver.0.1.0.34/src/Message/Frame.cs @@ -0,0 +1,30 @@ +namespace Exceptron.Driver.Message +{ + internal class Frame + { + /// + /// Order of current frame + /// + public int i { get; set; } + + /// + /// Line number of the current frame + /// + public int ln { get; set; } + + /// + /// File name of the current frame + /// + public string fn { get; set; } + + /// + /// Method name for current frame + /// + public string m { get; set; } + + /// + /// Class name for current frame + /// + public string c { get; set; } + } +} \ No newline at end of file diff --git a/packages/Exceptron.Driver.0.1.0.34/src/Properties/AssemblyInfo.cs b/packages/Exceptron.Driver.0.1.0.34/src/Properties/AssemblyInfo.cs new file mode 100644 index 000000000..0a891e51b --- /dev/null +++ b/packages/Exceptron.Driver.0.1.0.34/src/Properties/AssemblyInfo.cs @@ -0,0 +1,39 @@ +using System.Reflection; +using System.Runtime.CompilerServices; +using System.Runtime.InteropServices; + +// General Information about an assembly is controlled through the following +// set of attributes. Change these attribute values to modify the information +// associated with an assembly. +[assembly: AssemblyTitle("Exceptron.Driver")] +[assembly: AssemblyDescription("")] +[assembly: AssemblyConfiguration("")] +[assembly: AssemblyCompany("")] +[assembly: AssemblyProduct("Exceptron.Driver")] +[assembly: AssemblyCopyright("Copyright © 2012")] +[assembly: AssemblyTrademark("")] +[assembly: AssemblyCulture("")] + +// Setting ComVisible to false makes the types in this assembly not visible +// to COM components. If you need to access a type in this assembly from +// COM, set the ComVisible attribute to true on that type. +[assembly: ComVisible(false)] + +// The following GUID is for the ID of the typelib if this project is exposed to COM +[assembly: Guid("a463887e-594f-4733-b227-a79f4ffb2158")] + +// Version information for an assembly consists of the following four values: +// +// Major Version +// Minor Version +// Build Number +// Revision +// +// You can specify all the values or you can default the Build and Revision Numbers +// by using the '*' as shown below: +// [assembly: AssemblyVersion("1.0.*")] +[assembly: AssemblyVersion("0.1.0.34")] +[assembly: AssemblyFileVersion("0.1.0.34")] +[assembly: InternalsVisibleTo("Exceptron.Driver.Tests")] +[assembly: InternalsVisibleTo("Exceptron.Api.v1a.Tests")] +[assembly: InternalsVisibleTo("DynamicProxyGenAssembly2")] diff --git a/packages/Exceptron.Driver.0.1.0.34/src/RestClient.cs b/packages/Exceptron.Driver.0.1.0.34/src/RestClient.cs new file mode 100644 index 000000000..714a63fb4 --- /dev/null +++ b/packages/Exceptron.Driver.0.1.0.34/src/RestClient.cs @@ -0,0 +1,79 @@ +using System; +using System.Diagnostics; +using System.IO; +using System.Net; +using System.Text; +using Exceptron.Driver.fastJSON; + +namespace Exceptron.Driver +{ + public sealed class RestClient : IRestClient + { + public TResponse Put(string url, object content) where TResponse : class ,new() + { + + if(content == null) + throw new ArgumentNullException("content can not be null", "content"); + + if (string.IsNullOrEmpty(url)) + throw new ArgumentNullException("url can not be null or empty", "url"); + + Trace.WriteLine("Attempting PUT to " + url); + + var json = JSON.Instance.ToJSON(content); + + byte[] bytes = Encoding.UTF8.GetBytes(json); + var request = (HttpWebRequest)WebRequest.Create(url); + request.Timeout = 10000; + request.Method = "PUT"; + request.ContentType = "application/json"; + request.ContentLength = bytes.Length; + request.Accept = "application/json"; + + var dataStream = request.GetRequestStream(); + dataStream.Write(bytes, 0, bytes.Length); + dataStream.Close(); + var webResponse = request.GetResponse(); + + var responseStream = new StreamReader(webResponse.GetResponseStream(), Encoding.GetEncoding(1252)); + var responseString = responseStream.ReadToEnd(); + + Trace.WriteLine(responseString); + var response = JSON.Instance.ToObject(responseString); + + return response; + + /* try + { + var dataStream = request.GetRequestStream(); + dataStream.Write(bytes, 0, bytes.Length); + dataStream.Close(); + webResponse = request.GetResponse(); + } + catch (WebException ex) + { + Trace.WriteLine("An Error has occurred while Doing HTTP PUT. " + ex); + webResponse = ex.Response; + } + catch (Exception ex) + { + Trace.WriteLine("An Error has occurred while Doing HTTP PUT. " + ex); + } + + var response = new TResponse(); + + if (webResponse != null && webResponse.ContentType.Contains("json")) + { + var responseStream = new StreamReader(webResponse.GetResponseStream(), Encoding.GetEncoding(1252)); + var responseString = responseStream.ReadToEnd(); + + Trace.WriteLine(responseString); + response = JSON.Instance.ToObject(responseString); + } + + if (response == null) response = new TResponse(); + + return response;*/ + } + } +} diff --git a/packages/Exceptron.Driver.0.1.0.34/src/ValidationError.cs b/packages/Exceptron.Driver.0.1.0.34/src/ValidationError.cs new file mode 100644 index 000000000..b6ad2df6f --- /dev/null +++ b/packages/Exceptron.Driver.0.1.0.34/src/ValidationError.cs @@ -0,0 +1,11 @@ +namespace Exceptron.Driver +{ + public class ValidationError + { + public string ErrorCode { get; set; } + + public string FieldName { get; set; } + + public string Message { get; set; } + } +} \ No newline at end of file diff --git a/packages/Exceptron.Driver.0.1.0.34/src/fastJSON/Getters.cs b/packages/Exceptron.Driver.0.1.0.34/src/fastJSON/Getters.cs new file mode 100644 index 000000000..ed22088c1 --- /dev/null +++ b/packages/Exceptron.Driver.0.1.0.34/src/fastJSON/Getters.cs @@ -0,0 +1,20 @@ +//http://fastjson.codeplex.com/ + +using System; +using System.Collections.Generic; + +namespace Exceptron.Driver.fastJSON +{ + internal class Getters + { + public string Name; + public JSON.GenericGetter Getter; + public Type propertyType; + } + + internal class DatasetSchema + { + public List Info { get; set; } + public string Name { get; set; } + } +} diff --git a/packages/Exceptron.Driver.0.1.0.34/src/fastJSON/JSON.cs b/packages/Exceptron.Driver.0.1.0.34/src/fastJSON/JSON.cs new file mode 100644 index 000000000..d49d8ffe7 --- /dev/null +++ b/packages/Exceptron.Driver.0.1.0.34/src/fastJSON/JSON.cs @@ -0,0 +1,854 @@ +//http://fastjson.codeplex.com/ + +using System; +using System.Collections; +using System.Collections.Generic; +using System.Data; +using System.Globalization; +using System.IO; +using System.Reflection; +using System.Reflection.Emit; +using Exceptron.Driver.fastJSON; + +namespace Exceptron.Driver.fastJSON +{ + internal delegate string Serialize(object data); + internal delegate object Deserialize(string data); + + internal class JSON + { + public readonly static JSON Instance = new JSON(); + + private JSON() + { + UseSerializerExtension = false; + SerializeNullValues = false; + UseOptimizedDatasetSchema = false; + UsingGlobalTypes = false; + } + public bool UseOptimizedDatasetSchema = true; + public bool UseFastGuid = true; + public bool UseSerializerExtension = true; + public bool IndentOutput = false; + public bool SerializeNullValues = true; + public bool UseUTCDateTime = false; + public bool ShowReadOnlyProperties = false; + public bool UsingGlobalTypes = true; + + public string ToJSON(object obj) + { + return ToJSON(obj, UseSerializerExtension, UseFastGuid, UseOptimizedDatasetSchema, SerializeNullValues); + } + + public string ToJSON(object obj, + bool enableSerializerExtensions) + { + return ToJSON(obj, enableSerializerExtensions, UseFastGuid, UseOptimizedDatasetSchema, SerializeNullValues); + } + + public string ToJSON(object obj, + bool enableSerializerExtensions, + bool enableFastGuid) + { + return ToJSON(obj, enableSerializerExtensions, enableFastGuid, UseOptimizedDatasetSchema, SerializeNullValues); + } + + public string ToJSON(object obj, + bool enableSerializerExtensions, + bool enableFastGuid, + bool enableOptimizedDatasetSchema, + bool serializeNullValues) + { + return new JSONSerializer(enableOptimizedDatasetSchema, enableFastGuid, enableSerializerExtensions, serializeNullValues, IndentOutput).ConvertToJSON(obj); + } + + public object Parse(string json) + { + return new JsonParser(json).Decode(); + } + + public T ToObject(string json) + { + return (T)ToObject(json, typeof(T)); + } + + public object ToObject(string json) + { + return ToObject(json, null); + } + + public object ToObject(string json, Type type) + { + Dictionary ht = new JsonParser(json).Decode() as Dictionary; + if (ht == null) return null; + return ParseDictionary(ht, null, type); + } + +#if CUSTOMTYPE + internal SafeDictionary _customSerializer = new SafeDictionary(); + internal SafeDictionary _customDeserializer = new SafeDictionary(); + + public void RegisterCustomType(Type type, Serialize serializer, Deserialize deserializer) + { + if (type != null && serializer != null && deserializer != null) + { + _customSerializer.Add(type, serializer); + _customDeserializer.Add(type, deserializer); + // reset property cache + _propertycache = new SafeDictionary>(); + } + } + + internal bool IsTypeRegistered(Type t) + { + Serialize s; + return _customSerializer.TryGetValue(t, out s); + } +#endif + + #region [ PROPERTY GET SET CACHE ] + SafeDictionary _tyname = new SafeDictionary(); + internal string GetTypeAssemblyName(Type t) + { + string val = ""; + if (_tyname.TryGetValue(t, out val)) + return val; + else + { + string s = t.AssemblyQualifiedName; + _tyname.Add(t, s); + return s; + } + } + + SafeDictionary _typecache = new SafeDictionary(); + private Type GetTypeFromCache(string typename) + { + Type val = null; + if (_typecache.TryGetValue(typename, out val)) + return val; + else + { + Type t = Type.GetType(typename); + _typecache.Add(typename, t); + return t; + } + } + + SafeDictionary _constrcache = new SafeDictionary(); + private delegate object CreateObject(); + private object FastCreateInstance(Type objtype) + { + try + { + CreateObject c = null; + if (_constrcache.TryGetValue(objtype, out c)) + { + return c(); + } + else + { + DynamicMethod dynMethod = new DynamicMethod("_", objtype, null, true); + ILGenerator ilGen = dynMethod.GetILGenerator(); + + ilGen.Emit(OpCodes.Newobj, objtype.GetConstructor(Type.EmptyTypes)); + ilGen.Emit(OpCodes.Ret); + c = (CreateObject)dynMethod.CreateDelegate(typeof(CreateObject)); + _constrcache.Add(objtype, c); + return c(); + } + } + catch (Exception exc) + { + throw new Exception(string.Format("Failed to fast create instance for type '{0}' from assemebly '{1}'", + objtype.FullName, objtype.AssemblyQualifiedName), exc); + } + } + + private struct myPropInfo + { + public bool filled; + public Type pt; + public Type bt; + public Type changeType; + public bool isDictionary; + public bool isValueType; + public bool isGenericType; + public bool isArray; + public bool isByteArray; + public bool isGuid; +#if !SILVERLIGHT + public bool isDataSet; + public bool isDataTable; + public bool isHashtable; +#endif + public GenericSetter setter; + public bool isEnum; + public bool isDateTime; + public Type[] GenericTypes; + public bool isInt; + public bool isLong; + public bool isString; + public bool isBool; + public bool isClass; + public GenericGetter getter; + public bool isStringDictionary; + public string Name; +#if CUSTOMTYPE + public bool isCustomType; +#endif + public bool CanWrite; + } + + SafeDictionary> _propertycache = new SafeDictionary>(); + private SafeDictionary Getproperties(Type type, string typename) + { + SafeDictionary sd = null; + if (_propertycache.TryGetValue(typename, out sd)) + { + return sd; + } + else + { + sd = new SafeDictionary(); + PropertyInfo[] pr = type.GetProperties(BindingFlags.NonPublic | BindingFlags.Public | BindingFlags.Instance); + foreach (PropertyInfo p in pr) + { + myPropInfo d = CreateMyProp(p.PropertyType, p.Name); + d.CanWrite = p.CanWrite; + d.setter = CreateSetMethod(p); + d.getter = CreateGetMethod(p); + sd.Add(p.Name, d); + } + + _propertycache.Add(typename, sd); + return sd; + } + } + + private myPropInfo CreateMyProp(Type t, string name) + { + myPropInfo d = new myPropInfo(); + d.filled = true; + d.CanWrite = true; + d.pt = t; + d.Name = name; + d.isDictionary = t.Name.Contains("Dictionary"); + if (d.isDictionary) + d.GenericTypes = t.GetGenericArguments(); + d.isValueType = t.IsValueType; + d.isGenericType = t.IsGenericType; + d.isArray = t.IsArray; + if (d.isArray) + d.bt = t.GetElementType(); + if (d.isGenericType) + d.bt = t.GetGenericArguments()[0]; + d.isByteArray = t == typeof(byte[]); + d.isGuid = (t == typeof(Guid) || t == typeof(Guid?)); +#if !SILVERLIGHT + d.isHashtable = t == typeof(Hashtable); + d.isDataSet = t == typeof(DataSet); + d.isDataTable = t == typeof(DataTable); +#endif + + d.changeType = GetChangeType(t); + d.isEnum = t.IsEnum; + d.isDateTime = t == typeof(DateTime) || t == typeof(DateTime?); + d.isInt = t == typeof(int) || t == typeof(int?); + d.isLong = t == typeof(long) || t == typeof(long?); + d.isString = t == typeof(string); + d.isBool = t == typeof(bool) || t == typeof(bool?); + d.isClass = t.IsClass; + + if (d.isDictionary && d.GenericTypes.Length > 0 && d.GenericTypes[0] == typeof(string)) + d.isStringDictionary = true; + +#if CUSTOMTYPE + if (IsTypeRegistered(t)) + d.isCustomType = true; +#endif + return d; + } + + private delegate void GenericSetter(object target, object value); + + private static GenericSetter CreateSetMethod(PropertyInfo propertyInfo) + { + MethodInfo setMethod = propertyInfo.GetSetMethod(nonPublic: true); + if (setMethod == null) + return null; + + Type[] arguments = new Type[2]; + arguments[0] = arguments[1] = typeof(object); + + DynamicMethod setter = new DynamicMethod("_", typeof(void), arguments, true); + ILGenerator il = setter.GetILGenerator(); + il.Emit(OpCodes.Ldarg_0); + il.Emit(OpCodes.Castclass, propertyInfo.DeclaringType); + il.Emit(OpCodes.Ldarg_1); + + if (propertyInfo.PropertyType.IsClass) + il.Emit(OpCodes.Castclass, propertyInfo.PropertyType); + else + il.Emit(OpCodes.Unbox_Any, propertyInfo.PropertyType); + + il.EmitCall(OpCodes.Callvirt, setMethod, null); + il.Emit(OpCodes.Ret); + + return (GenericSetter)setter.CreateDelegate(typeof(GenericSetter)); + } + + internal delegate object GenericGetter(object obj); + + + private GenericGetter CreateGetMethod(PropertyInfo propertyInfo) + { + MethodInfo getMethod = propertyInfo.GetGetMethod(); + if (getMethod == null) + return null; + + Type[] arguments = new Type[1]; + arguments[0] = typeof(object); + + DynamicMethod getter = new DynamicMethod("_", typeof(object), arguments, true); + ILGenerator il = getter.GetILGenerator(); + il.Emit(OpCodes.Ldarg_0); + il.Emit(OpCodes.Castclass, propertyInfo.DeclaringType); + il.EmitCall(OpCodes.Callvirt, getMethod, null); + + if (!propertyInfo.PropertyType.IsClass) + il.Emit(OpCodes.Box, propertyInfo.PropertyType); + + il.Emit(OpCodes.Ret); + + return (GenericGetter)getter.CreateDelegate(typeof(GenericGetter)); + } + + readonly SafeDictionary> _getterscache = new SafeDictionary>(); + internal List GetGetters(Type type) + { + List val = null; + if (_getterscache.TryGetValue(type, out val)) + return val; + + PropertyInfo[] props = type.GetProperties(BindingFlags.NonPublic | BindingFlags.Public | BindingFlags.Instance); + List getters = new List(); + foreach (PropertyInfo p in props) + { + if (!p.CanWrite && ShowReadOnlyProperties == false) continue; + + object[] att = p.GetCustomAttributes(typeof(System.Xml.Serialization.XmlIgnoreAttribute), false); + if (att != null && att.Length > 0) + continue; + + JSON.GenericGetter g = CreateGetMethod(p); + if (g != null) + { + Getters gg = new Getters(); + gg.Name = p.Name; + gg.Getter = g; + gg.propertyType = p.PropertyType; + getters.Add(gg); + } + } + + + _getterscache.Add(type, getters); + return getters; + } + + private object ChangeType(object value, Type conversionType) + { + if (conversionType == typeof(int)) + return (int)CreateLong((string)value); + + else if (conversionType == typeof(long)) + return CreateLong((string)value); + + else if (conversionType == typeof(string)) + return (string)value; + + else if (conversionType == typeof(Guid)) + return CreateGuid((string)value); + + else if (conversionType.IsEnum) + return CreateEnum(conversionType, (string)value); + + return Convert.ChangeType(value, conversionType, CultureInfo.InvariantCulture); + } + #endregion + + + private object ParseDictionary(Dictionary d, Dictionary globaltypes, Type type) + { + object tn = ""; + if (d.TryGetValue("$types", out tn)) + { + UsingGlobalTypes = true; + globaltypes = new Dictionary(); + foreach (var kv in (Dictionary)tn) + { + globaltypes.Add((string)kv.Value, kv.Key); + } + } + + bool found = d.TryGetValue("$type", out tn); +#if !SILVERLIGHT + if (found == false && type == typeof(System.Object)) + { + return CreateDataset(d, globaltypes); + } +#endif + if (found) + { + if (UsingGlobalTypes) + { + object tname = ""; + if (globaltypes.TryGetValue((string)tn, out tname)) + tn = tname; + } + type = GetTypeFromCache((string)tn); + } + + if (type == null) + throw new Exception("Cannot determine type"); + + string typename = type.FullName; + object o = FastCreateInstance(type); + SafeDictionary props = Getproperties(type, typename); + foreach (string name in d.Keys) + { + if (name == "$map") + { + ProcessMap(o, props, (Dictionary)d[name]); + continue; + } + myPropInfo pi; + if (props.TryGetValue(name, out pi) == false) + continue; + if (pi.filled == true) + { + object v = d[name]; + + if (v != null) + { + object oset = null; + + if (pi.isInt) + oset = (int)CreateLong((string)v); +#if CUSTOMTYPE + else if (pi.isCustomType) + oset = CreateCustom((string)v, pi.pt); +#endif + else if (pi.isLong) + oset = CreateLong((string)v); + + else if (pi.isString) + oset = (string)v; + + else if (pi.isBool) + oset = (bool)v; + + else if (pi.isGenericType && pi.isValueType == false && pi.isDictionary == false) +#if SILVERLIGHT + oset = CreateGenericList((List)v, pi.pt, pi.bt, globaltypes); +#else + oset = CreateGenericList((ArrayList)v, pi.pt, pi.bt, globaltypes); +#endif + else if (pi.isByteArray) + oset = Convert.FromBase64String((string)v); + + else if (pi.isArray && pi.isValueType == false) +#if SILVERLIGHT + oset = CreateArray((List)v, pi.pt, pi.bt, globaltypes); +#else + oset = CreateArray((ArrayList)v, pi.pt, pi.bt, globaltypes); +#endif + else if (pi.isGuid) + oset = CreateGuid((string)v); +#if !SILVERLIGHT + else if (pi.isDataSet) + oset = CreateDataset((Dictionary)v, globaltypes); + + else if (pi.isDataTable) + oset = this.CreateDataTable((Dictionary)v, globaltypes); +#endif + + else if (pi.isStringDictionary) + oset = CreateStringKeyDictionary((Dictionary)v, pi.pt, pi.GenericTypes, globaltypes); + +#if !SILVERLIGHT + else if (pi.isDictionary || pi.isHashtable) + oset = CreateDictionary((ArrayList)v, pi.pt, pi.GenericTypes, globaltypes); +#else + else if (pi.isDictionary) + oset = CreateDictionary((List)v, pi.pt, pi.GenericTypes, globaltypes); +#endif + + else if (pi.isEnum) + oset = CreateEnum(pi.pt, (string)v); + + else if (pi.isDateTime) + oset = CreateDateTime((string)v); + + else if (pi.isClass && v is Dictionary) + oset = ParseDictionary((Dictionary)v, globaltypes, pi.pt); + + else if (pi.isValueType) + oset = ChangeType(v, pi.changeType); + +#if SILVERLIGHT + else if (v is List) + oset = CreateArray((List)v, pi.pt, typeof(object), globaltypes); +#else + else if (v is ArrayList) + oset = CreateArray((ArrayList)v, pi.pt, typeof(object), globaltypes); +#endif + else + oset = v; + + if (pi.CanWrite) + pi.setter(o, oset); + } + } + } + return o; + } + +#if CUSTOMTYPE + private object CreateCustom(string v, Type type) + { + Deserialize d; + _customDeserializer.TryGetValue(type, out d); + return d(v); + } +#endif + + private void ProcessMap(object obj, SafeDictionary props, Dictionary dic) + { + foreach (KeyValuePair kv in dic) + { + myPropInfo p = props[kv.Key]; + object o = p.getter(obj); + Type t = Type.GetType((string)kv.Value); + if (t == typeof(Guid)) + p.setter(obj, CreateGuid((string)o)); + } + } + + private long CreateLong(string s) + { + long num = 0; + bool neg = false; + foreach (char cc in s) + { + if (cc == '-') + neg = true; + else if (cc == '+') + neg = false; + else + { + num *= 10; + num += (int)(cc - '0'); + } + } + + return neg ? -num : num; + } + + private object CreateEnum(Type pt, string v) + { + // TODO : optimize create enum +#if !SILVERLIGHT + return Enum.Parse(pt, v); +#else + return Enum.Parse(pt, v, true); +#endif + } + + private Guid CreateGuid(string s) + { + if (s.Length > 30) + return new Guid(s); + else + return new Guid(Convert.FromBase64String(s)); + } + + private DateTime CreateDateTime(string value) + { + bool utc = false; + // 0123456789012345678 + // datetime format = yyyy-MM-dd HH:mm:ss + int year = (int)CreateLong(value.Substring(0, 4)); + int month = (int)CreateLong(value.Substring(5, 2)); + int day = (int)CreateLong(value.Substring(8, 2)); + int hour = (int)CreateLong(value.Substring(11, 2)); + int min = (int)CreateLong(value.Substring(14, 2)); + int sec = (int)CreateLong(value.Substring(17, 2)); + + if (value.EndsWith("Z")) + utc = true; + + if (UseUTCDateTime == false && utc == false) + return new DateTime(year, month, day, hour, min, sec); + else + return new DateTime(year, month, day, hour, min, sec, DateTimeKind.Utc).ToLocalTime(); + } + +#if SILVERLIGHT + private object CreateArray(List data, Type pt, Type bt, Dictionary globalTypes) + { + Array col = Array.CreateInstance(bt, data.Count); + // create an array of objects + for (int i = 0; i < data.Count; i++)// each (object ob in data) + { + object ob = data[i]; + if (ob is IDictionary) + col.SetValue(ParseDictionary((Dictionary)ob, globalTypes, bt), i); + else + col.SetValue(ChangeType(ob, bt), i); + } + + return col; + } +#else + private object CreateArray(ArrayList data, Type pt, Type bt, Dictionary globalTypes) + { + ArrayList col = new ArrayList(); + // create an array of objects + foreach (object ob in data) + { + if (ob is IDictionary) + col.Add(ParseDictionary((Dictionary)ob, globalTypes, bt)); + else + col.Add(ChangeType(ob, bt)); + } + return col.ToArray(bt); + } +#endif + + +#if SILVERLIGHT + private object CreateGenericList(List data, Type pt, Type bt, Dictionary globalTypes) +#else + private object CreateGenericList(ArrayList data, Type pt, Type bt, Dictionary globalTypes) +#endif + { + IList col = (IList)FastCreateInstance(pt); + // create an array of objects + foreach (object ob in data) + { + if (ob is IDictionary) + col.Add(ParseDictionary((Dictionary)ob, globalTypes, bt)); +#if SILVERLIGHT + else if (ob is List) + col.Add(((List)ob).ToArray()); +#else + else if (ob is ArrayList) + col.Add(((ArrayList)ob).ToArray()); +#endif + else + col.Add(ChangeType(ob, bt)); + } + return col; + } + + private object CreateStringKeyDictionary(Dictionary reader, Type pt, Type[] types, Dictionary globalTypes) + { + var col = (IDictionary)FastCreateInstance(pt); + Type t1 = null; + Type t2 = null; + if (types != null) + { + t1 = types[0]; + t2 = types[1]; + } + + foreach (KeyValuePair values in reader) + { + var key = values.Key;//ChangeType(values.Key, t1); + object val = null; + if (values.Value is Dictionary) + val = ParseDictionary((Dictionary)values.Value, globalTypes, t2); + else + val = ChangeType(values.Value, t2); + col.Add(key, val); + } + + return col; + } + +#if SILVERLIGHT + private object CreateDictionary(List reader, Type pt, Type[] types, Dictionary globalTypes) +#else + private object CreateDictionary(ArrayList reader, Type pt, Type[] types, Dictionary globalTypes) +#endif + { + IDictionary col = (IDictionary)FastCreateInstance(pt); + Type t1 = null; + Type t2 = null; + if (types != null) + { + t1 = types[0]; + t2 = types[1]; + } + + foreach (Dictionary values in reader) + { + object key = values["k"]; + object val = values["v"]; + + if (key is Dictionary) + key = ParseDictionary((Dictionary)key, globalTypes, t1); + else + key = ChangeType(key, t1); + + if (val is Dictionary) + val = ParseDictionary((Dictionary)val, globalTypes, t2); + else + val = ChangeType(val, t2); + + col.Add(key, val); + } + + return col; + } + + private Type GetChangeType(Type conversionType) + { + if (conversionType.IsGenericType && conversionType.GetGenericTypeDefinition().Equals(typeof(Nullable<>))) + return conversionType.GetGenericArguments()[0]; + + return conversionType; + } +#if !SILVERLIGHT + private DataSet CreateDataset(Dictionary reader, Dictionary globalTypes) + { + DataSet ds = new DataSet(); + ds.EnforceConstraints = false; + ds.BeginInit(); + + // read dataset schema here + ReadSchema(reader, ds, globalTypes); + + foreach (KeyValuePair pair in reader) + { + if (pair.Key == "$type" || pair.Key == "$schema") continue; + + ArrayList rows = (ArrayList)pair.Value; + if (rows == null) continue; + + DataTable dt = ds.Tables[pair.Key]; + ReadDataTable(rows, dt); + } + + ds.EndInit(); + + return ds; + } + + private void ReadSchema(Dictionary reader, DataSet ds, Dictionary globalTypes) + { + var schema = reader["$schema"]; + + if (schema is string) + { + TextReader tr = new StringReader((string)schema); + ds.ReadXmlSchema(tr); + } + else + { + DatasetSchema ms = (DatasetSchema)ParseDictionary((Dictionary)schema, globalTypes, typeof(DatasetSchema)); + ds.DataSetName = ms.Name; + for (int i = 0; i < ms.Info.Count; i += 3) + { + if (ds.Tables.Contains(ms.Info[i]) == false) + ds.Tables.Add(ms.Info[i]); + ds.Tables[ms.Info[i]].Columns.Add(ms.Info[i + 1], Type.GetType(ms.Info[i + 2])); + } + } + } + + private void ReadDataTable(ArrayList rows, DataTable dt) + { + dt.BeginInit(); + dt.BeginLoadData(); + List guidcols = new List(); + List datecol = new List(); + + foreach (DataColumn c in dt.Columns) + { + if (c.DataType == typeof(Guid) || c.DataType == typeof(Guid?)) + guidcols.Add(c.Ordinal); + if (UseUTCDateTime && (c.DataType == typeof(DateTime) || c.DataType == typeof(DateTime?))) + datecol.Add(c.Ordinal); + } + + foreach (ArrayList row in rows) + { + object[] v = new object[row.Count]; + row.CopyTo(v, 0); + foreach (int i in guidcols) + { + string s = (string)v[i]; + if (s != null && s.Length < 36) + v[i] = new Guid(Convert.FromBase64String(s)); + } + if (UseUTCDateTime) + { + foreach (int i in datecol) + { + string s = (string)v[i]; + if (s != null) + v[i] = CreateDateTime(s); + } + } + dt.Rows.Add(v); + } + + dt.EndLoadData(); + dt.EndInit(); + } + + DataTable CreateDataTable(Dictionary reader, Dictionary globalTypes) + { + var dt = new DataTable(); + + // read dataset schema here + var schema = reader["$schema"]; + + if (schema is string) + { + TextReader tr = new StringReader((string)schema); + dt.ReadXmlSchema(tr); + } + else + { + var ms = (DatasetSchema)this.ParseDictionary((Dictionary)schema, globalTypes, typeof(DatasetSchema)); + dt.TableName = ms.Info[0]; + for (int i = 0; i < ms.Info.Count; i += 3) + { + dt.Columns.Add(ms.Info[i + 1], Type.GetType(ms.Info[i + 2])); + } + } + + foreach (var pair in reader) + { + if (pair.Key == "$type" || pair.Key == "$schema") + continue; + + var rows = (ArrayList)pair.Value; + if (rows == null) + continue; + + if (!dt.TableName.Equals(pair.Key, StringComparison.InvariantCultureIgnoreCase)) + continue; + + ReadDataTable(rows, dt); + } + + return dt; + } +#endif + } +} \ No newline at end of file diff --git a/packages/Exceptron.Driver.0.1.0.34/src/fastJSON/JsonParser.cs b/packages/Exceptron.Driver.0.1.0.34/src/fastJSON/JsonParser.cs new file mode 100644 index 000000000..569ce1769 --- /dev/null +++ b/packages/Exceptron.Driver.0.1.0.34/src/fastJSON/JsonParser.cs @@ -0,0 +1,408 @@ +//http://fastjson.codeplex.com/ + +using System; +using System.Collections; +using System.Collections.Generic; +using System.Text; + +namespace Exceptron.Driver.fastJSON +{ + /// + /// This class encodes and decodes JSON strings. + /// Spec. details, see http://www.json.org/ + /// + /// JSON uses Arrays and Objects. These correspond here to the datatypes ArrayList and Hashtable. + /// All numbers are parsed to doubles. + /// + internal class JsonParser + { + enum Token + { + None = -1, // Used to denote no Lookahead available + Curly_Open, + Curly_Close, + Squared_Open, + Squared_Close, + Colon, + Comma, + String, + Number, + True, + False, + Null + } + + readonly char[] json; + readonly StringBuilder s = new StringBuilder(); + Token lookAheadToken = Token.None; + int index; + + internal JsonParser(string json) + { + this.json = json.ToCharArray(); + } + + public object Decode() + { + return ParseValue(); + } + + private Dictionary ParseObject() + { + Dictionary table = new Dictionary(); + + ConsumeToken(); // { + + while (true) + { + switch (LookAhead()) + { + + case Token.Comma: + ConsumeToken(); + break; + + case Token.Curly_Close: + ConsumeToken(); + return table; + + default: + { + + // name + string name = ParseString(); + + // : + if (NextToken() != Token.Colon) + { + throw new Exception("Expected colon at index " + index); + } + + // value + object value = ParseValue(); + + table[name] = value; + } + break; + } + } + } + +#if SILVERLIGHT + private List ParseArray() + { + List array = new List(); +#else + private ArrayList ParseArray() + { + ArrayList array = new ArrayList(); +#endif + ConsumeToken(); // [ + + while (true) + { + switch (LookAhead()) + { + + case Token.Comma: + ConsumeToken(); + break; + + case Token.Squared_Close: + ConsumeToken(); + return array; + + default: + { + array.Add(ParseValue()); + } + break; + } + } + } + + private object ParseValue() + { + switch (LookAhead()) + { + case Token.Number: + return ParseNumber(); + + case Token.String: + return ParseString(); + + case Token.Curly_Open: + return ParseObject(); + + case Token.Squared_Open: + return ParseArray(); + + case Token.True: + ConsumeToken(); + return true; + + case Token.False: + ConsumeToken(); + return false; + + case Token.Null: + ConsumeToken(); + return null; + } + + throw new Exception("Unrecognized token at index" + index); + } + + private string ParseString() + { + ConsumeToken(); // " + + s.Length = 0; + + int runIndex = -1; + + while (index < json.Length) + { + var c = json[index++]; + + if (c == '"') + { + if (runIndex != -1) + { + if (s.Length == 0) + return new string(json, runIndex, index - runIndex - 1); + + s.Append(json, runIndex, index - runIndex - 1); + } + return s.ToString(); + } + + if (c != '\\') + { + if (runIndex == -1) + runIndex = index - 1; + + continue; + } + + if (index == json.Length) break; + + if (runIndex != -1) + { + s.Append(json, runIndex, index - runIndex - 1); + runIndex = -1; + } + + switch (json[index++]) + { + case '"': + s.Append('"'); + break; + + case '\\': + s.Append('\\'); + break; + + case '/': + s.Append('/'); + break; + + case 'b': + s.Append('\b'); + break; + + case 'f': + s.Append('\f'); + break; + + case 'n': + s.Append('\n'); + break; + + case 'r': + s.Append('\r'); + break; + + case 't': + s.Append('\t'); + break; + + case 'u': + { + int remainingLength = json.Length - index; + if (remainingLength < 4) break; + + // parse the 32 bit hex into an integer codepoint + uint codePoint = ParseUnicode(json[index], json[index + 1], json[index + 2], json[index + 3]); + s.Append((char)codePoint); + + // skip 4 chars + index += 4; + } + break; + } + } + + throw new Exception("Unexpectedly reached end of string"); + } + + private uint ParseSingleChar(char c1, uint multipliyer) + { + uint p1 = 0; + if (c1 >= '0' && c1 <= '9') + p1 = (uint)(c1 - '0') * multipliyer; + else if (c1 >= 'A' && c1 <= 'F') + p1 = (uint)((c1 - 'A') + 10) * multipliyer; + else if (c1 >= 'a' && c1 <= 'f') + p1 = (uint)((c1 - 'a') + 10) * multipliyer; + return p1; + } + + private uint ParseUnicode(char c1, char c2, char c3, char c4) + { + uint p1 = ParseSingleChar(c1, 0x1000); + uint p2 = ParseSingleChar(c2, 0x100); + uint p3 = ParseSingleChar(c3, 0x10); + uint p4 = ParseSingleChar(c4, 1); + + return p1 + p2 + p3 + p4; + } + + private string ParseNumber() + { + ConsumeToken(); + + // Need to start back one place because the first digit is also a token and would have been consumed + var startIndex = index - 1; + + do + { + var c = json[index]; + + if ((c >= '0' && c <= '9') || c == '.' || c == '-' || c == '+' || c == 'e' || c == 'E') + { + if (++index == json.Length) throw new Exception("Unexpected end of string whilst parsing number"); + continue; + } + + break; + } while (true); + + return new string(json, startIndex, index - startIndex); + } + + private Token LookAhead() + { + if (lookAheadToken != Token.None) return lookAheadToken; + + return lookAheadToken = NextTokenCore(); + } + + private void ConsumeToken() + { + lookAheadToken = Token.None; + } + + private Token NextToken() + { + var result = lookAheadToken != Token.None ? lookAheadToken : NextTokenCore(); + + lookAheadToken = Token.None; + + return result; + } + + private Token NextTokenCore() + { + char c; + + // Skip past whitespace + do + { + c = json[index]; + + if (c > ' ') break; + if (c != ' ' && c != '\t' && c != '\n' && c != '\r') break; + + } while (++index < json.Length); + + if (index == json.Length) + { + throw new Exception("Reached end of string unexpectedly"); + } + + c = json[index]; + + index++; + + //if (c >= '0' && c <= '9') + // return Token.Number; + + switch (c) + { + case '{': + return Token.Curly_Open; + + case '}': + return Token.Curly_Close; + + case '[': + return Token.Squared_Open; + + case ']': + return Token.Squared_Close; + + case ',': + return Token.Comma; + + case '"': + return Token.String; + + case '0': case '1': case '2': case '3': case '4': + case '5': case '6': case '7': case '8': case '9': + case '-': case '+': case '.': + return Token.Number; + + case ':': + return Token.Colon; + + case 'f': + if (json.Length - index >= 4 && + json[index + 0] == 'a' && + json[index + 1] == 'l' && + json[index + 2] == 's' && + json[index + 3] == 'e') + { + index += 4; + return Token.False; + } + break; + + case 't': + if (json.Length - index >= 3 && + json[index + 0] == 'r' && + json[index + 1] == 'u' && + json[index + 2] == 'e') + { + index += 3; + return Token.True; + } + break; + + case 'n': + if (json.Length - index >= 3 && + json[index + 0] == 'u' && + json[index + 1] == 'l' && + json[index + 2] == 'l') + { + index += 3; + return Token.Null; + } + break; + + } + + throw new Exception("Could not find token at index " + --index); + } + } +} diff --git a/packages/Exceptron.Driver.0.1.0.34/src/fastJSON/JsonSerializer.cs b/packages/Exceptron.Driver.0.1.0.34/src/fastJSON/JsonSerializer.cs new file mode 100644 index 000000000..439471fae --- /dev/null +++ b/packages/Exceptron.Driver.0.1.0.34/src/fastJSON/JsonSerializer.cs @@ -0,0 +1,518 @@ +//http://fastjson.codeplex.com/ + +using System; +using System.Collections; +using System.Collections.Generic; +using System.Data; +using System.Globalization; +using System.IO; +using System.Text; + +namespace Exceptron.Driver.fastJSON +{ + internal class JSONSerializer + { + private readonly StringBuilder _output = new StringBuilder(); + readonly bool useMinimalDataSetSchema; + readonly bool fastguid = true; + readonly bool useExtension = true; + readonly bool serializeNulls = true; + readonly int _MAX_DEPTH = 10; + bool _Indent = false; + bool _useGlobalTypes = true; + int _current_depth = 0; + private Dictionary _globalTypes = new Dictionary(); + + internal JSONSerializer(bool UseMinimalDataSetSchema, bool UseFastGuid, bool UseExtensions, bool SerializeNulls, bool IndentOutput) + { + this.useMinimalDataSetSchema = UseMinimalDataSetSchema; + this.fastguid = UseFastGuid; + this.useExtension = UseExtensions; + _Indent = IndentOutput; + this.serializeNulls = SerializeNulls; + if (useExtension == false) + _useGlobalTypes = false; + } + + internal string ConvertToJSON(object obj) + { + WriteValue(obj); + + string str = ""; + if (_useGlobalTypes) + { + StringBuilder sb = new StringBuilder(); + sb.Append("{\"$types\":{"); + bool pendingSeparator = false; + foreach (var kv in _globalTypes) + { + if (pendingSeparator) sb.Append(','); + pendingSeparator = true; + sb.Append("\""); + sb.Append(kv.Key); + sb.Append("\":\""); + sb.Append(kv.Value); + sb.Append("\""); + } + sb.Append("},"); + str = sb.ToString() + _output.ToString(); + } + else + str = _output.ToString(); + + return str; + } + + private void WriteValue(object obj) + { + if (obj == null || obj is DBNull) + _output.Append("null"); + + else if (obj is string || obj is char) + WriteString((string)obj); + + else if (obj is Guid) + WriteGuid((Guid)obj); + + else if (obj is bool) + _output.Append(((bool)obj) ? "true" : "false"); // conform to standard + + else if ( + obj is int || obj is long || obj is double || + obj is decimal || obj is float || + obj is byte || obj is short || + obj is sbyte || obj is ushort || + obj is uint || obj is ulong + ) + _output.Append(((IConvertible)obj).ToString(NumberFormatInfo.InvariantInfo)); + + else if (obj is DateTime) + WriteDateTime((DateTime)obj); + + else if (obj is IDictionary && obj.GetType().IsGenericType && obj.GetType().GetGenericArguments()[0] == typeof(string)) + WriteStringDictionary((IDictionary)obj); + + else if (obj is IDictionary) + WriteDictionary((IDictionary)obj); +#if !SILVERLIGHT + else if (obj is DataSet) + WriteDataset((DataSet)obj); + + else if (obj is DataTable) + this.WriteDataTable((DataTable)obj); +#endif + else if (obj is byte[]) + WriteBytes((byte[])obj); + + else if (obj is Array || obj is IList || obj is ICollection) + WriteArray((IEnumerable)obj); + + else if (obj is Enum) + WriteEnum((Enum)obj); + +#if CUSTOMTYPE + else if (JSON.Instance.IsTypeRegistered(obj.GetType())) + WriteCustom(obj); +#endif + else + WriteObject(obj); + } + +#if CUSTOMTYPE + private void WriteCustom(object obj) + { + Serialize s; + JSON.Instance._customSerializer.TryGetValue(obj.GetType(), out s); + WriteStringFast(s(obj)); + } +#endif + + private void WriteEnum(Enum e) + { + // TODO : optimize enum write + WriteStringFast(e.ToString()); + } + + private void WriteGuid(Guid g) + { + if (fastguid == false) + WriteStringFast(g.ToString()); + else + WriteBytes(g.ToByteArray()); + } + + private void WriteBytes(byte[] bytes) + { +#if !SILVERLIGHT + WriteStringFast(Convert.ToBase64String(bytes, 0, bytes.Length, Base64FormattingOptions.None)); +#else + WriteStringFast(Convert.ToBase64String(bytes, 0, bytes.Length)); +#endif + } + + private void WriteDateTime(DateTime dateTime) + { + // datetime format standard : yyyy-MM-dd HH:mm:ss + DateTime dt = dateTime; + if (JSON.Instance.UseUTCDateTime) + dt = dateTime.ToUniversalTime(); + + _output.Append("\""); + _output.Append(dt.Year.ToString("0000", NumberFormatInfo.InvariantInfo)); + _output.Append("-"); + _output.Append(dt.Month.ToString("00", NumberFormatInfo.InvariantInfo)); + _output.Append("-"); + _output.Append(dt.Day.ToString("00", NumberFormatInfo.InvariantInfo)); + _output.Append(" "); + _output.Append(dt.Hour.ToString("00", NumberFormatInfo.InvariantInfo)); + _output.Append(":"); + _output.Append(dt.Minute.ToString("00", NumberFormatInfo.InvariantInfo)); + _output.Append(":"); + _output.Append(dt.Second.ToString("00", NumberFormatInfo.InvariantInfo)); + + if (JSON.Instance.UseUTCDateTime) + _output.Append("Z"); + + _output.Append("\""); + } +#if !SILVERLIGHT + private DatasetSchema GetSchema(DataTable ds) + { + if (ds == null) return null; + + DatasetSchema m = new DatasetSchema(); + m.Info = new List(); + m.Name = ds.TableName; + + foreach (DataColumn c in ds.Columns) + { + m.Info.Add(ds.TableName); + m.Info.Add(c.ColumnName); + m.Info.Add(c.DataType.ToString()); + } + // TODO : serialize relations and constraints here + + return m; + } + + private DatasetSchema GetSchema(DataSet ds) + { + if (ds == null) return null; + + DatasetSchema m = new DatasetSchema(); + m.Info = new List(); + m.Name = ds.DataSetName; + + foreach (DataTable t in ds.Tables) + { + foreach (DataColumn c in t.Columns) + { + m.Info.Add(t.TableName); + m.Info.Add(c.ColumnName); + m.Info.Add(c.DataType.ToString()); + } + } + // TODO : serialize relations and constraints here + + return m; + } + + private string GetXmlSchema(DataTable dt) + { + using (var writer = new StringWriter()) + { + dt.WriteXmlSchema(writer); + return dt.ToString(); + } + } + + private void WriteDataset(DataSet ds) + { + _output.Append('{'); + if (useExtension) + { + WritePair("$schema", useMinimalDataSetSchema ? (object)GetSchema(ds) : ds.GetXmlSchema()); + _output.Append(','); + } + bool tablesep = false; + foreach (DataTable table in ds.Tables) + { + if (tablesep) _output.Append(","); + tablesep = true; + WriteDataTableData(table); + } + // end dataset + _output.Append('}'); + } + + private void WriteDataTableData(DataTable table) + { + _output.Append('\"'); + _output.Append(table.TableName); + _output.Append("\":["); + DataColumnCollection cols = table.Columns; + bool rowseparator = false; + foreach (DataRow row in table.Rows) + { + if (rowseparator) _output.Append(","); + rowseparator = true; + _output.Append('['); + + bool pendingSeperator = false; + foreach (DataColumn column in cols) + { + if (pendingSeperator) _output.Append(','); + WriteValue(row[column]); + pendingSeperator = true; + } + _output.Append(']'); + } + + _output.Append(']'); + } + + void WriteDataTable(DataTable dt) + { + this._output.Append('{'); + if (this.useExtension) + { + this.WritePair("$schema", this.useMinimalDataSetSchema ? (object)this.GetSchema(dt) : this.GetXmlSchema(dt)); + this._output.Append(','); + } + + WriteDataTableData(dt); + + // end datatable + this._output.Append('}'); + } +#endif + bool _firstWritten = false; + private void WriteObject(object obj) + { + Indent(); + if (_useGlobalTypes == false) + _output.Append('{'); + else + { + if (_firstWritten) + _output.Append("{"); + } + _firstWritten = true; + _current_depth++; + if (_current_depth > _MAX_DEPTH) + throw new Exception("Serializer encountered maximum depth of " + _MAX_DEPTH); + + + Dictionary map = new Dictionary(); + Type t = obj.GetType(); + bool append = false; + if (useExtension) + { + if (_useGlobalTypes == false) + WritePairFast("$type", JSON.Instance.GetTypeAssemblyName(t)); + else + { + int dt = 0; + string ct = JSON.Instance.GetTypeAssemblyName(t); + if (_globalTypes.TryGetValue(ct, out dt) == false) + { + dt = _globalTypes.Count + 1; + _globalTypes.Add(ct, dt); + } + WritePairFast("$type", dt.ToString()); + } + append = true; + } + + List g = JSON.Instance.GetGetters(t); + foreach (var p in g) + { + if (append) + _output.Append(','); + object o = p.Getter(obj); + if ((o == null || o is DBNull) && serializeNulls == false) + append = false; + else + { + WritePair(p.Name, o); + if (o != null && useExtension) + { + Type tt = o.GetType(); + if (tt == typeof(System.Object)) + map.Add(p.Name, tt.ToString()); + } + append = true; + } + } + if (map.Count > 0 && useExtension) + { + _output.Append(",\"$map\":"); + WriteStringDictionary(map); + } + _current_depth--; + Indent(); + _output.Append('}'); + _current_depth--; + + } + + private void Indent() + { + Indent(false); + } + + private void Indent(bool dec) + { + if (_Indent) + { + _output.Append("\r\n"); + for (int i = 0; i < _current_depth - (dec ? 1 : 0); i++) + _output.Append("\t"); + } + } + + private void WritePairFast(string name, string value) + { + if ((value == null) && serializeNulls == false) + return; + Indent(); + WriteStringFast(name); + + _output.Append(':'); + + WriteStringFast(value); + } + + private void WritePair(string name, object value) + { + if ((value == null || value is DBNull) && serializeNulls == false) + return; + Indent(); + WriteStringFast(name); + + _output.Append(':'); + + WriteValue(value); + } + + private void WriteArray(IEnumerable array) + { + Indent(); + _output.Append('['); + + bool pendingSeperator = false; + + foreach (object obj in array) + { + Indent(); + if (pendingSeperator) _output.Append(','); + + WriteValue(obj); + + pendingSeperator = true; + } + Indent(); + _output.Append(']'); + } + + private void WriteStringDictionary(IDictionary dic) + { + Indent(); + _output.Append('{'); + + bool pendingSeparator = false; + + foreach (DictionaryEntry entry in dic) + { + if (pendingSeparator) _output.Append(','); + + WritePair((string)entry.Key, entry.Value); + + pendingSeparator = true; + } + Indent(); + _output.Append('}'); + } + + private void WriteDictionary(IDictionary dic) + { + Indent(); + _output.Append('['); + + bool pendingSeparator = false; + + foreach (DictionaryEntry entry in dic) + { + if (pendingSeparator) _output.Append(','); + Indent(); + _output.Append('{'); + WritePair("k", entry.Key); + _output.Append(","); + WritePair("v", entry.Value); + Indent(); + _output.Append('}'); + + pendingSeparator = true; + } + Indent(); + _output.Append(']'); + } + + private void WriteStringFast(string s) + { + //Indent(); + _output.Append('\"'); + _output.Append(s); + _output.Append('\"'); + } + + private void WriteString(string s) + { + //Indent(); + _output.Append('\"'); + + int runIndex = -1; + + for (var index = 0; index < s.Length; ++index) + { + var c = s[index]; + + if (c >= ' ' && c < 128 && c != '\"' && c != '\\') + { + if (runIndex == -1) + { + runIndex = index; + } + + continue; + } + + if (runIndex != -1) + { + _output.Append(s, runIndex, index - runIndex); + runIndex = -1; + } + + switch (c) + { + case '\t': _output.Append("\\t"); break; + case '\r': _output.Append("\\r"); break; + case '\n': _output.Append("\\n"); break; + case '"': + case '\\': _output.Append('\\'); _output.Append(c); break; + default: + _output.Append("\\u"); + _output.Append(((int)c).ToString("X4", NumberFormatInfo.InvariantInfo)); + break; + } + } + + if (runIndex != -1) + { + _output.Append(s, runIndex, s.Length - runIndex); + } + + _output.Append('\"'); + } + } +} diff --git a/packages/Exceptron.Driver.0.1.0.34/src/fastJSON/SafeDictionary.cs b/packages/Exceptron.Driver.0.1.0.34/src/fastJSON/SafeDictionary.cs new file mode 100644 index 000000000..191975fb4 --- /dev/null +++ b/packages/Exceptron.Driver.0.1.0.34/src/fastJSON/SafeDictionary.cs @@ -0,0 +1,39 @@ +//http://fastjson.codeplex.com/ + +using System.Collections.Generic; + +namespace Exceptron.Driver.fastJSON +{ + internal class SafeDictionary + { + private readonly object _Padlock = new object(); + private readonly Dictionary _Dictionary = new Dictionary(); + + + public bool TryGetValue(TKey key, out TValue value) + { + return _Dictionary.TryGetValue(key, out value); + } + + public TValue this[TKey key] + { + get + { + return _Dictionary[key]; + } + } + public IEnumerator> GetEnumerator() + { + return ((ICollection>)_Dictionary).GetEnumerator(); + } + + public void Add(TKey key, TValue value) + { + lock (_Padlock) + { + if (_Dictionary.ContainsKey(key) == false) + _Dictionary.Add(key, value); + } + } + } +}