private object DecodeMapToType(Type expectedType, long offset, int size, out long outOffset, InjectableValues injectables) { var constructor = _typeAcivatorCreator.GetActivator(expectedType); var parameters = constructor.DefaultParameters(); for (var i = 0; i < size; i++) { var key = DecodeKey(offset, out offset); if (constructor.DeserializationParameters.ContainsKey(key)) { var param = constructor.DeserializationParameters[key]; var paramType = param.ParameterType; var value = Decode(paramType, offset, out offset, injectables); parameters[param.Position] = value; } else { offset = NextValueOffset(offset, 1); } } SetInjectables(constructor, parameters, injectables); SetAlwaysCreatedParams(constructor, parameters, injectables); outOffset = offset; return(constructor.Activator(parameters)); }
private object Decode(Type expectedType, long offset, out long outOffset, InjectableValues injectables = null) { int size; var type = CtrlData(offset, out size, out offset); return(DecodeByType(expectedType, type, offset, size, out outOffset, injectables)); }
/// <summary> /// Decodes the type of the by. /// </summary> /// <param name="expectedType"></param> /// <param name="type">The type.</param> /// <param name="offset">The offset.</param> /// <param name="size">The size.</param> /// <param name="outOffset">The out offset</param> /// <param name="injectables"></param> /// <returns></returns> /// <exception cref="Exception">Unable to handle type!</exception> private object DecodeByType(Type expectedType, ObjectType type, long offset, int size, out long outOffset, InjectableValues injectables) { outOffset = offset + size; switch (type) { case ObjectType.Pointer: var pointer = DecodePointer(offset, size, out offset); outOffset = offset; if (!_followPointers) { return(pointer); } long ignore; var result = Decode(expectedType, Convert.ToInt32(pointer), out ignore, injectables); return(result); case ObjectType.Map: return(DecodeMap(expectedType, offset, size, out outOffset, injectables)); case ObjectType.Array: return(DecodeArray(expectedType, size, offset, out outOffset, injectables)); case ObjectType.Boolean: outOffset = offset; return(DecodeBoolean(expectedType, size)); case ObjectType.Utf8String: return(DecodeString(expectedType, offset, size)); case ObjectType.Double: return(DecodeDouble(expectedType, offset, size)); case ObjectType.Float: return(DecodeFloat(expectedType, offset, size)); case ObjectType.Bytes: return(DecodeBytes(expectedType, offset, size)); case ObjectType.Uint16: return(DecodeInteger(expectedType, offset, size)); case ObjectType.Uint32: return(DecodeLong(expectedType, offset, size)); case ObjectType.Int32: return(DecodeInteger(expectedType, offset, size)); case ObjectType.Uint64: return(DecodeUInt64(expectedType, offset, size)); case ObjectType.Uint128: return(DecodeBigInteger(expectedType, offset, size)); default: throw new InvalidDatabaseException("Unable to handle type:" + type); } }
private T ResolveDataPointer <T>(int pointer, InjectableValues injectables) where T : class { var resolved = (pointer - Metadata.NodeCount) + Metadata.SearchTreeSize; if (resolved >= _database.Length) { throw new InvalidDatabaseException( "The MaxMind Db file's search tree is corrupt: " + "contains pointer larger than the database."); } return(Decoder.Decode <T>(resolved, out long ignore, injectables)); }
/// <summary> /// Decodes the array. /// </summary> /// <param name="expectedType"></param> /// <param name="size">The size.</param> /// <param name="offset">The offset.</param> /// <param name="outOffset">The out offset.</param> /// <param name="injectables"></param> /// <returns></returns> private object DecodeArray(Type expectedType, int size, long offset, out long outOffset, InjectableValues injectables) { var genericArgs = expectedType.GetGenericArguments(); var argType = genericArgs.Length == 0 ? typeof(object) : genericArgs[0]; var interfaceType = typeof(ICollection <>).MakeGenericType(argType); var array = _listActivatorCreator.GetActivator(expectedType)(size); for (var i = 0; i < size; i++) { var r = Decode(argType, offset, out offset, injectables); interfaceType.GetMethod("Add").Invoke(array, new[] { r }); } outOffset = offset; return(array); }
/// <summary> /// Decodes the map. /// </summary> /// <param name="expectedType"></param> /// <param name="offset">The offset.</param> /// <param name="size">The size.</param> /// <param name="outOffset">The out offset.</param> /// <param name="injectables"></param> /// <returns></returns> private object DecodeMap(Type expectedType, long offset, int size, out long outOffset, InjectableValues injectables) { var objDictType = typeof(Dictionary <string, object>); if (!expectedType.GetTypeInfo().IsGenericType&& expectedType.IsAssignableFrom(objDictType)) { expectedType = objDictType; } // Currently we don't support non-dict generic types if (expectedType.GetTypeInfo().IsGenericType) { return(DecodeMapToDictionary(expectedType, offset, size, out outOffset, injectables)); } return(DecodeMapToType(expectedType, offset, size, out outOffset, injectables)); }
private object DecodeMapToDictionary(Type expectedType, long offset, int size, out long outOffset, InjectableValues injectables) { var genericArgs = expectedType.GetGenericArguments(); if (genericArgs.Length != 2) { throw new DeserializationException( $"Unexpected number of Dictionary generic arguments: {genericArgs.Length}"); } var obj = (IDictionary)_dictionaryActivatorCreator.GetActivator(expectedType)(size); for (var i = 0; i < size; i++) { var key = Decode(genericArgs[0], offset, out offset); var value = Decode(genericArgs[1], offset, out offset, injectables); obj.Add(key, value); } outOffset = offset; return(obj); }
/// <summary> /// Decodes the object at the specified offset. /// </summary> /// <param name="offset">The offset.</param> /// <param name="outOffset">The out offset</param> /// <param name="injectables"></param> /// <returns>An object containing the data read from the stream</returns> internal T Decode <T>(long offset, out long outOffset, InjectableValues injectables = null) where T : class { return(Decode(typeof(T), offset, out outOffset, injectables) as T); }
private static void SetInjectables(TypeActivator constructor, object[] parameters, InjectableValues injectables) { foreach (var item in constructor.InjectableParameters) { if (injectables == null || !injectables.Values.ContainsKey(item.Key)) { throw new DeserializationException($"No injectable value found for {item.Key}"); } parameters[item.Value.Position] = injectables.Values[item.Key]; } }
private void SetAlwaysCreatedParams(TypeActivator constructor, object[] parameters, InjectableValues injectables) { foreach (var param in constructor.AlwaysCreatedParameters) { if (parameters[param.Position] == null) { var activator = _typeAcivatorCreator.GetActivator(param.ParameterType); var cstorParams = activator.DefaultParameters(); SetInjectables(activator, cstorParams, injectables); SetAlwaysCreatedParams(activator, cstorParams, injectables); parameters[param.Position] = activator.Activator(cstorParams); } } }
/// <summary> /// Finds the data related to the specified address. /// </summary> /// <param name="ipAddress">The IP address.</param> /// <param name="prefixLength">The network prefix length for the network record in the database containing the IP address looked up.</param> /// <param name="injectables">Value to inject during deserialization</param> /// <returns>An object containing the IP related data</returns> public T Find <T>(IPAddress ipAddress, out int prefixLength, InjectableValues injectables = null) where T : class { var pointer = FindAddressInTree(ipAddress, out prefixLength); return(pointer == 0 ? null : ResolveDataPointer <T>(pointer, injectables)); }
/// <summary> /// Get an enumerator that iterates all data nodes in the database. Do not modify the object as it may be cached. /// </summary> /// <param name="injectables">Value to inject during deserialization</param> /// <param name="cacheSize">The size of the data cache. This can greatly speed enumeration at the cost of memory usage.</param> /// <returns>Enumerator for all data nodes</returns> public IEnumerable <Reader.ReaderIteratorNode <T> > FindAll <T>(InjectableValues injectables = null, int cacheSize = 16384) where T : class { int byteCount = (Metadata.IPVersion == 6 ? 16 : 4); int prefixMax = byteCount * 8; List <NetNode> nodes = new List <NetNode>(); NetNode root = new NetNode { IPBytes = new byte[byteCount] }; nodes.Add(root); CachedDictionary <int, T> dataCache = new CachedDictionary <int, T>(cacheSize, null); while (nodes.Count > 0) { NetNode node = nodes[nodes.Count - 1]; nodes.RemoveAt(nodes.Count - 1); while (true) { if (node.Pointer < Metadata.NodeCount) { byte[] ipRight = new byte[byteCount]; Array.Copy(node.IPBytes, ipRight, ipRight.Length); if (ipRight.Length <= (node.Bit >> 3)) { throw new InvalidDataException("Invalid search tree, bad bit " + node.Bit); } ipRight[node.Bit >> 3] |= (byte)(1 << (7 - (node.Bit % 8))); int rightPointer = ReadNode(node.Pointer, 1); node.Bit++; nodes.Add(new NetNode { Pointer = rightPointer, IPBytes = ipRight, Bit = node.Bit }); node.Pointer = ReadNode(node.Pointer, 0); } else { if (node.Pointer > Metadata.NodeCount) { // data node, we are done with this branch if (!dataCache.TryGetValue(node.Pointer, out T data)) { data = ResolveDataPointer <T>(node.Pointer, injectables); dataCache.Add(node.Pointer, data); } bool isIPV4 = true; for (int i = 0; i < node.IPBytes.Length - 4; i++) { if (node.IPBytes[i] != 0) { isIPV4 = false; break; } } if (!isIPV4 || node.IPBytes.Length == 4) { yield return(new ReaderIteratorNode <T>(new IPAddress(node.IPBytes), node.Bit, data)); } else { yield return(new ReaderIteratorNode <T>(new IPAddress(node.IPBytes.Skip(12).Take(4).ToArray()), node.Bit - 96, data)); } } // else node is an empty node (terminator node), we are done with this branch break; } } } }
/// <summary> /// Finds the data related to the specified address. /// </summary> /// <param name="ipAddress">The IP address.</param> /// <param name="injectables">Value to inject during deserialization</param> /// <returns>An object containing the IP related data</returns> public T Find <T>(IPAddress ipAddress, InjectableValues injectables = null) where T : class { return(Find <T>(ipAddress, out _, injectables)); }
/// <summary> /// Finds the data related to the specified address. /// </summary> /// <param name="ipAddress">The IP address.</param> /// <param name="injectables">Value to inject during deserialization</param> /// <returns>An object containing the IP related data</returns> public T Find <T>(IPAddress ipAddress, InjectableValues injectables = null) where T : class { int prefixLength; return(Find <T>(ipAddress, out prefixLength, injectables)); }