123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668 |
-
- using System;
- using System.Collections;
- using System.IO;
- #if FEAT_IKVM
- using Type = IKVM.Reflection.Type;
- using IKVM.Reflection;
- #else
- using System.Reflection;
- #endif
- namespace ProtoBuf
- {
- /// <summary>
- /// Not all frameworks are created equal (fx1.1 vs fx2.0,
- /// micro-framework, compact-framework,
- /// silverlight, etc). This class simply wraps up a few things that would
- /// otherwise make the real code unnecessarily messy, providing fallback
- /// implementations if necessary.
- /// </summary>
- internal sealed class Helpers
- {
- private Helpers() { }
- public static System.Text.StringBuilder AppendLine(System.Text.StringBuilder builder)
- {
- #if CF2
- return builder.Append("\r\n");
- #elif FX11
- return builder.Append(Environment.NewLine);
- #else
- return builder.AppendLine();
- #endif
- }
- public static bool IsNullOrEmpty(string value)
- { // yes, FX11 lacks this!
- return value == null || value.Length == 0;
- }
- [System.Diagnostics.Conditional("DEBUG")]
- public static void DebugWriteLine(string message, object obj)
- {
- #if DEBUG
- string suffix;
- try
- {
- suffix = obj == null ? "(null)" : obj.ToString();
- }
- catch
- {
- suffix = "(exception)";
- }
- DebugWriteLine(message + ": " + suffix);
- #endif
- }
- [System.Diagnostics.Conditional("DEBUG")]
- public static void DebugWriteLine(string message)
- {
- #if DEBUG
- #if MF
- Microsoft.SPOT.Debug.Print(message);
- #else
- System.Diagnostics.Debug.WriteLine(message);
- #endif
- #endif
- }
- [System.Diagnostics.Conditional("TRACE")]
- public static void TraceWriteLine(string message)
- {
- #if TRACE
- #if MF
- Microsoft.SPOT.Trace.Print(message);
- #elif SILVERLIGHT || MONODROID || CF2 || WINRT || IOS || PORTABLE || COREFX
- System.Diagnostics.Debug.WriteLine(message);
- #else
- System.Diagnostics.Trace.WriteLine(message);
- #endif
- #endif
- }
- [System.Diagnostics.Conditional("DEBUG")]
- public static void DebugAssert(bool condition, string message)
- {
- #if DEBUG
- if (!condition)
- {
- #if MF
- Microsoft.SPOT.Debug.Assert(false, message);
- #else
- System.Diagnostics.Debug.Assert(false, message);
- }
- #endif
- #endif
- }
- [System.Diagnostics.Conditional("DEBUG")]
- public static void DebugAssert(bool condition, string message, params object[] args)
- {
- #if DEBUG
- if (!condition) DebugAssert(false, string.Format(message, args));
- #endif
- }
- [System.Diagnostics.Conditional("DEBUG")]
- public static void DebugAssert(bool condition)
- {
- #if DEBUG
- #if MF
- Microsoft.SPOT.Debug.Assert(condition);
- #else
- if(!condition && System.Diagnostics.Debugger.IsAttached) System.Diagnostics.Debugger.Break();
- System.Diagnostics.Debug.Assert(condition);
- #endif
- #endif
- }
- #if !NO_RUNTIME
- public static void Sort(int[] keys, object[] values)
- {
- // bubble-sort; it'll work on MF, has small code,
- // and works well-enough for our sizes. This approach
- // also allows us to do `int` compares without having
- // to go via IComparable etc, so win:win
- bool swapped;
- do {
- swapped = false;
- for (int i = 1; i < keys.Length; i++) {
- if (keys[i - 1] > keys[i]) {
- int tmpKey = keys[i];
- keys[i] = keys[i - 1];
- keys[i - 1] = tmpKey;
- object tmpValue = values[i];
- values[i] = values[i - 1];
- values[i - 1] = tmpValue;
- swapped = true;
- }
- }
- } while (swapped);
- }
- #endif
- public static void BlockCopy(byte[] from, int fromIndex, byte[] to, int toIndex, int count)
- {
- #if MF || WINRT
- Array.Copy(from, fromIndex, to, toIndex, count);
- #else
- Buffer.BlockCopy(from, fromIndex, to, toIndex, count);
- #endif
- }
- public static bool IsInfinity(float value)
- {
- #if MF
- const float inf = (float)1.0 / (float)0.0, minf = (float)-1.0F / (float)0.0;
- return value == inf || value == minf;
- #else
- return float.IsInfinity(value);
- #endif
- }
- #if WINRT || COREFX
- internal static MemberInfo GetInstanceMember(TypeInfo declaringType, string name)
- {
- var members = declaringType.AsType().GetMember(name, BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic);
- switch(members.Length)
- {
- case 0: return null;
- case 1: return members[0];
- default: throw new AmbiguousMatchException(name);
- }
- }
- internal static MethodInfo GetInstanceMethod(Type declaringType, string name)
- {
- foreach (MethodInfo method in declaringType.GetMethods(BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic))
- {
- if (method.Name == name) return method;
- }
- return null;
- }
- internal static MethodInfo GetInstanceMethod(TypeInfo declaringType, string name)
- {
- return GetInstanceMethod(declaringType.AsType(), name); ;
- }
- internal static MethodInfo GetStaticMethod(Type declaringType, string name)
- {
- foreach (MethodInfo method in declaringType.GetMethods(BindingFlags.Static | BindingFlags.Public | BindingFlags.NonPublic))
- {
- if (method.Name == name) return method;
- }
- return null;
- }
- internal static MethodInfo GetStaticMethod(TypeInfo declaringType, string name)
- {
- return GetStaticMethod(declaringType.AsType(), name);
- }
- internal static MethodInfo GetStaticMethod(Type declaringType, string name, Type[] parameterTypes)
- {
- foreach(MethodInfo method in declaringType.GetMethods(BindingFlags.Static | BindingFlags.Public | BindingFlags.NonPublic))
- {
- if (method.Name == name && IsMatch(method.GetParameters(), parameterTypes)) return method;
- }
- return null;
- }
- internal static MethodInfo GetInstanceMethod(Type declaringType, string name, Type[] parameterTypes)
- {
- foreach (MethodInfo method in declaringType.GetMethods(BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic))
- {
- if (method.Name == name && IsMatch(method.GetParameters(), parameterTypes)) return method;
- }
- return null;
- }
- internal static MethodInfo GetInstanceMethod(TypeInfo declaringType, string name, Type[] types)
- {
- return GetInstanceMethod(declaringType.AsType(), name, types);
- }
- #else
- internal static MethodInfo GetInstanceMethod(Type declaringType, string name)
- {
- return declaringType.GetMethod(name, BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic);
- }
- internal static MethodInfo GetStaticMethod(Type declaringType, string name)
- {
- return declaringType.GetMethod(name, BindingFlags.Static | BindingFlags.Public | BindingFlags.NonPublic);
- }
- internal static MethodInfo GetStaticMethod(Type declaringType, string name, Type[] parameterTypes)
- {
- return declaringType.GetMethod(name, BindingFlags.Static | BindingFlags.Public | BindingFlags.NonPublic, null, parameterTypes, null);
- }
- internal static MethodInfo GetInstanceMethod(Type declaringType, string name, Type[] types)
- {
- if(types == null) types = EmptyTypes;
- #if PORTABLE || COREFX
- MethodInfo method = declaringType.GetMethod(name, types);
- if (method != null && method.IsStatic) method = null;
- return method;
- #else
- return declaringType.GetMethod(name, BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic,
- null, types, null);
- #endif
- }
- #endif
- internal static bool IsSubclassOf(Type type, Type baseClass)
- {
- #if WINRT || COREFX
- return type.GetTypeInfo().IsSubclassOf(baseClass);
- #else
- return type.IsSubclassOf(baseClass);
- #endif
- }
- public static bool IsInfinity(double value)
- {
- #if MF
- const double inf = (double)1.0 / (double)0.0, minf = (double)-1.0F / (double)0.0;
- return value == inf || value == minf;
- #else
- return double.IsInfinity(value);
- #endif
- }
- public readonly static Type[] EmptyTypes =
- #if PORTABLE || WINRT || CF2 || CF35
- new Type[0];
- #else
- Type.EmptyTypes;
- #endif
- #if WINRT || COREFX
- private static readonly Type[] knownTypes = new Type[] {
- typeof(bool), typeof(char), typeof(sbyte), typeof(byte),
- typeof(short), typeof(ushort), typeof(int), typeof(uint),
- typeof(long), typeof(ulong), typeof(float), typeof(double),
- typeof(decimal), typeof(string),
- typeof(DateTime), typeof(TimeSpan), typeof(Guid), typeof(Uri),
- typeof(byte[]), typeof(System.Type)};
- private static readonly ProtoTypeCode[] knownCodes = new ProtoTypeCode[] {
- ProtoTypeCode.Boolean, ProtoTypeCode.Char, ProtoTypeCode.SByte, ProtoTypeCode.Byte,
- ProtoTypeCode.Int16, ProtoTypeCode.UInt16, ProtoTypeCode.Int32, ProtoTypeCode.UInt32,
- ProtoTypeCode.Int64, ProtoTypeCode.UInt64, ProtoTypeCode.Single, ProtoTypeCode.Double,
- ProtoTypeCode.Decimal, ProtoTypeCode.String,
- ProtoTypeCode.DateTime, ProtoTypeCode.TimeSpan, ProtoTypeCode.Guid, ProtoTypeCode.Uri,
- ProtoTypeCode.ByteArray, ProtoTypeCode.Type
- };
- #endif
- #if FEAT_IKVM
- public static ProtoTypeCode GetTypeCode(IKVM.Reflection.Type type)
- {
- TypeCode code = IKVM.Reflection.Type.GetTypeCode(type);
- switch (code)
- {
- case TypeCode.Empty:
- case TypeCode.Boolean:
- case TypeCode.Char:
- case TypeCode.SByte:
- case TypeCode.Byte:
- case TypeCode.Int16:
- case TypeCode.UInt16:
- case TypeCode.Int32:
- case TypeCode.UInt32:
- case TypeCode.Int64:
- case TypeCode.UInt64:
- case TypeCode.Single:
- case TypeCode.Double:
- case TypeCode.Decimal:
- case TypeCode.DateTime:
- case TypeCode.String:
- return (ProtoTypeCode)code;
- }
- switch(type.FullName)
- {
- case "System.TimeSpan": return ProtoTypeCode.TimeSpan;
- case "System.Guid": return ProtoTypeCode.Guid;
- case "System.Uri": return ProtoTypeCode.Uri;
- case "System.Byte[]": return ProtoTypeCode.ByteArray;
- case "System.Type": return ProtoTypeCode.Type;
- }
- return ProtoTypeCode.Unknown;
- }
- #endif
- public static ProtoTypeCode GetTypeCode(System.Type type)
- {
- #if WINRT || COREFX
- if(IsEnum(type))
- {
- type = Enum.GetUnderlyingType(type);
- }
- int idx = Array.IndexOf<Type>(knownTypes, type);
- if (idx >= 0) return knownCodes[idx];
- return type == null ? ProtoTypeCode.Empty : ProtoTypeCode.Unknown;
- #else
- TypeCode code = System.Type.GetTypeCode(type);
- switch (code)
- {
- case TypeCode.Empty:
- case TypeCode.Boolean:
- case TypeCode.Char:
- case TypeCode.SByte:
- case TypeCode.Byte:
- case TypeCode.Int16:
- case TypeCode.UInt16:
- case TypeCode.Int32:
- case TypeCode.UInt32:
- case TypeCode.Int64:
- case TypeCode.UInt64:
- case TypeCode.Single:
- case TypeCode.Double:
- case TypeCode.Decimal:
- case TypeCode.DateTime:
- case TypeCode.String:
- return (ProtoTypeCode)code;
- }
- if (type == typeof(TimeSpan)) return ProtoTypeCode.TimeSpan;
- if (type == typeof(Guid)) return ProtoTypeCode.Guid;
- if (type == typeof(Uri)) return ProtoTypeCode.Uri;
- #if PORTABLE
- // In PCLs, the Uri type may not match (WinRT uses Internal/Uri, .Net uses System/Uri), so match on the full name instead
- if (type.FullName == typeof(Uri).FullName) return ProtoTypeCode.Uri;
- #endif
- if (type == typeof(byte[])) return ProtoTypeCode.ByteArray;
- if (type == typeof(System.Type)) return ProtoTypeCode.Type;
- return ProtoTypeCode.Unknown;
- #endif
- }
-
- #if FEAT_IKVM
- internal static IKVM.Reflection.Type GetUnderlyingType(IKVM.Reflection.Type type)
- {
- if (type.IsValueType && type.IsGenericType && type.GetGenericTypeDefinition().FullName == "System.Nullable`1")
- {
- return type.GetGenericArguments()[0];
- }
- return null;
- }
- #endif
- internal static System.Type GetUnderlyingType(System.Type type)
- {
- #if NO_GENERICS
- return null; // never a Nullable<T>, so always returns null
- #else
- return Nullable.GetUnderlyingType(type);
- #endif
- }
- internal static bool IsValueType(Type type)
- {
- #if WINRT || COREFX
- return type.GetTypeInfo().IsValueType;
- #else
- return type.IsValueType;
- #endif
- }
- internal static bool IsSealed(Type type)
- {
- #if WINRT || COREFX
- return type.GetTypeInfo().IsSealed;
- #else
- return type.IsSealed;
- #endif
- }
- internal static bool IsClass(Type type)
- {
- #if WINRT || COREFX
- return type.GetTypeInfo().IsClass;
- #else
- return type.IsClass;
- #endif
- }
- internal static bool IsEnum(Type type)
- {
- #if WINRT || COREFX
- return type.GetTypeInfo().IsEnum;
- #else
- return type.IsEnum;
- #endif
- }
- internal static MethodInfo GetGetMethod(PropertyInfo property, bool nonPublic, bool allowInternal)
- {
- if (property == null) return null;
- #if WINRT || COREFX
- MethodInfo method = property.GetMethod;
- if (!nonPublic && method != null && !method.IsPublic) method = null;
- return method;
- #else
- MethodInfo method = property.GetGetMethod(nonPublic);
- if (method == null && !nonPublic && allowInternal)
- { // could be "internal" or "protected internal"; look for a non-public, then back-check
- method = property.GetGetMethod(true);
- if (method == null && !(method.IsAssembly || method.IsFamilyOrAssembly))
- {
- method = null;
- }
- }
- return method;
- #endif
- }
- internal static MethodInfo GetSetMethod(PropertyInfo property, bool nonPublic, bool allowInternal)
- {
- if (property == null) return null;
- #if WINRT || COREFX
- MethodInfo method = property.SetMethod;
- if (!nonPublic && method != null && !method.IsPublic) method = null;
- return method;
- #else
- MethodInfo method = property.GetSetMethod(nonPublic);
- if (method == null && !nonPublic && allowInternal)
- { // could be "internal" or "protected internal"; look for a non-public, then back-check
- method = property.GetGetMethod(true);
- if (method == null && !(method.IsAssembly || method.IsFamilyOrAssembly))
- {
- method = null;
- }
- }
- return method;
- #endif
- }
- #if FEAT_IKVM
- internal static bool IsMatch(IKVM.Reflection.ParameterInfo[] parameters, IKVM.Reflection.Type[] parameterTypes)
- {
- if (parameterTypes == null) parameterTypes = Helpers.EmptyTypes;
- if (parameters.Length != parameterTypes.Length) return false;
- for (int i = 0; i < parameters.Length; i++)
- {
- if (parameters[i].ParameterType != parameterTypes[i]) return false;
- }
- return true;
- }
- #endif
- #if WINRT || COREFX
- private static bool IsMatch(ParameterInfo[] parameters, Type[] parameterTypes)
- {
- if (parameterTypes == null) parameterTypes = EmptyTypes;
- if (parameters.Length != parameterTypes.Length) return false;
- for (int i = 0; i < parameters.Length; i++)
- {
- if (parameters[i].ParameterType != parameterTypes[i]) return false;
- }
- return true;
- }
- internal static ConstructorInfo GetConstructor(Type type, Type[] parameterTypes, bool nonPublic)
- {
- return GetConstructor(type.GetTypeInfo(), parameterTypes, nonPublic);
- }
- internal static ConstructorInfo GetConstructor(TypeInfo type, Type[] parameterTypes, bool nonPublic)
- {
- foreach (ConstructorInfo ctor in type.DeclaredConstructors)
- {
- if (!nonPublic && !ctor.IsPublic) continue;
- if (IsMatch(ctor.GetParameters(), parameterTypes)) return ctor;
- }
- return null;
- }
- internal static ConstructorInfo[] GetConstructors(TypeInfo typeInfo, bool nonPublic)
- {
- if (nonPublic) return System.Linq.Enumerable.ToArray(typeInfo.DeclaredConstructors);
- return System.Linq.Enumerable.ToArray(
- System.Linq.Enumerable.Where(typeInfo.DeclaredConstructors, x => x.IsPublic));
- }
- internal static PropertyInfo GetProperty(Type type, string name, bool nonPublic)
- {
- return GetProperty(type.GetTypeInfo(), name, nonPublic);
- }
- internal static PropertyInfo GetProperty(TypeInfo type, string name, bool nonPublic)
- {
- return type.GetDeclaredProperty(name);
- }
- #else
- internal static ConstructorInfo GetConstructor(Type type, Type[] parameterTypes, bool nonPublic)
- {
- #if PORTABLE || COREFX
- // pretty sure this will only ever return public, but...
- ConstructorInfo ctor = type.GetConstructor(parameterTypes);
- return (ctor != null && (nonPublic || ctor.IsPublic)) ? ctor : null;
- #else
- return type.GetConstructor(
- nonPublic ? BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic
- : BindingFlags.Instance | BindingFlags.Public,
- null, parameterTypes, null);
- #endif
- }
- internal static ConstructorInfo[] GetConstructors(Type type, bool nonPublic)
- {
- return type.GetConstructors(
- nonPublic ? BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic
- : BindingFlags.Instance | BindingFlags.Public);
- }
- internal static PropertyInfo GetProperty(Type type, string name, bool nonPublic)
- {
- return type.GetProperty(name,
- nonPublic ? BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic
- : BindingFlags.Instance | BindingFlags.Public);
- }
- #endif
- internal static object ParseEnum(Type type, string value)
- {
- #if FEAT_IKVM
- FieldInfo[] fields = type.GetFields();
- foreach (FieldInfo field in fields)
- {
- if (string.Equals(field.Name, value, StringComparison.OrdinalIgnoreCase)) return field.GetRawConstantValue();
- }
- throw new ArgumentException("Enum value could not be parsed: " + value + ", " + type.FullName);
- #else
- return Enum.Parse(type, value, true);
- #endif
- }
- internal static MemberInfo[] GetInstanceFieldsAndProperties(Type type, bool publicOnly)
- {
- #if WINRT
- System.Collections.Generic.List<MemberInfo> members = new System.Collections.Generic.List<MemberInfo>();
- foreach(FieldInfo field in type.GetRuntimeFields())
- {
- if(field.IsStatic) continue;
- if(field.IsPublic || !publicOnly) members.Add(field);
- }
- foreach(PropertyInfo prop in type.GetRuntimeProperties())
- {
- MethodInfo getter = Helpers.GetGetMethod(prop, true, true);
- if(getter == null || getter.IsStatic) continue;
- if(getter.IsPublic || !publicOnly) members.Add(prop);
- }
- return members.ToArray();
- #else
- BindingFlags flags = publicOnly ? BindingFlags.Public | BindingFlags.Instance : BindingFlags.Public | BindingFlags.Instance | BindingFlags.NonPublic;
- PropertyInfo[] props = type.GetProperties(flags);
- FieldInfo[] fields = type.GetFields(flags);
- MemberInfo[] members = new MemberInfo[fields.Length + props.Length];
- props.CopyTo(members, 0);
- fields.CopyTo(members, props.Length);
- return members;
- #endif
- }
- internal static Type GetMemberType(MemberInfo member)
- {
- #if WINRT || PORTABLE || COREFX
- PropertyInfo prop = member as PropertyInfo;
- if (prop != null) return prop.PropertyType;
- FieldInfo fld = member as FieldInfo;
- return fld == null ? null : fld.FieldType;
- #else
- switch(member.MemberType)
- {
- case MemberTypes.Field: return ((FieldInfo) member).FieldType;
- case MemberTypes.Property: return ((PropertyInfo) member).PropertyType;
- default: return null;
- }
- #endif
- }
- internal static bool IsAssignableFrom(Type target, Type type)
- {
- #if WINRT
- return target.GetTypeInfo().IsAssignableFrom(type.GetTypeInfo());
- #else
- return target.IsAssignableFrom(type);
- #endif
- }
- internal static Assembly GetAssembly(Type type)
- {
- #if COREFX
- return type.GetTypeInfo().Assembly;
- #else
- return type.Assembly;
- #endif
- }
- internal static byte[] GetBuffer(MemoryStream ms)
- {
- #if COREFX
- ArraySegment<byte> segment;
- if(!ms.TryGetBuffer(out segment))
- {
- throw new InvalidOperationException("Unable to obtain underlying MemoryStream buffer");
- } else if(segment.Offset != 0)
- {
- throw new InvalidOperationException("Underlying MemoryStream buffer was not zero-offset");
- } else
- {
- return segment.Array;
- }
- #else
- return ms.GetBuffer();
- #endif
- }
- }
- /// <summary>
- /// Intended to be a direct map to regular TypeCode, but:
- /// - with missing types
- /// - existing on WinRT
- /// </summary>
- internal enum ProtoTypeCode
- {
- Empty = 0,
- Unknown = 1, // maps to TypeCode.Object
- Boolean = 3,
- Char = 4,
- SByte = 5,
- Byte = 6,
- Int16 = 7,
- UInt16 = 8,
- Int32 = 9,
- UInt32 = 10,
- Int64 = 11,
- UInt64 = 12,
- Single = 13,
- Double = 14,
- Decimal = 15,
- DateTime = 16,
- String = 18,
- // additions
- TimeSpan = 100,
- ByteArray = 101,
- Guid = 102,
- Uri = 103,
- Type = 104
- }
- }
|