예제 #1
0
파일: Json.cs 프로젝트: njmube/Nemo
 internal void Append(JsonValue value)
 {
     value.Parent = this;
     if (this.LastChild != null)
     {
         this.LastChild = this.LastChild.NexSibling = value;
     }
     else
     {
         this.FirstChild = this.LastChild = value;
     }
 }
예제 #2
0
파일: Json.cs 프로젝트: njmube/Nemo
 private static void CheckTop(JsonValue top, int charPosition)
 {
     if (top == null)
     {
         throw new JsonParserException(charPosition, "Unexpected character");
     }
 }
예제 #3
0
파일: Json.cs 프로젝트: njmube/Nemo
        public static JsonValue Parse(string json)
        {
            JsonValue root = null;
            JsonValue top = null;
            string name = null;

            var escaped_newlines = 0;

            char[] jsonArray = null;
            var i = 0;
            for (; i < json.Length; i++)
            {
                var ch = json[i];

                // skip white space
                if (ch == '\x20' || ch == '\x9' || ch == '\xD' || ch == '\xA')
                {
                    continue;
                }

                switch (ch)
                {
                    case '{':
                    case '[':
                        {
                            // create new value
                            var value = new JsonValue { Name = name };

                            // name
                            name = null;

                            // type
                            value.Type = ch == '{' ? JsonType.Object : JsonType.Array;

                            // set top and root
                            if (top != null)
                            {
                                top.Append(value);
                            }
                            else if (root == null)
                            {
                                root = value;
                            }
                            else
                            {
                                throw new JsonParserException(i, "Second root. Only one root allowed");
                            }
                            top = value;
                        }
                        break;

                    case '}':
                    case ']':
                        {
                            if (top == null || top.Type != ((ch == '}') ? JsonType.Object : JsonType.Array))
                            {
                                throw new JsonParserException(i, "Mismatch closing brace/bracket");
                            }

                            // set top
                            top = top.Parent;
                        }
                        break;

                    case ':':
                        if (top == null || top.Type != JsonType.Object)
                        {
                            throw new JsonParserException(i, "Unexpected character");
                        }
                        break;

                    case ',':
                        CheckTop(top, i);
                        break;

                    case '"':
                        {
                            CheckTop(top, i);

                            // skip '"' character
                            i++;
                            ch = json[i];

                            var first = i;
                            var last = i;
                            var ch_last = ch;
                            while (i < json.Length)
                            {
                                if (ch < '\x20')
                                {
                                    throw new JsonParserException(first, "Control characters not allowed in strings");
                                }
                                if (ch == '\\')
                                {
                                    switch (json[i + 1])
                                    {
                                        case '"':
                                            ch_last = '"';
                                            break;
                                        case '\\':
                                            ch_last = '\\';
                                            break;
                                        case '/':
                                            ch_last = '/';
                                            break;
                                        case 'b':
                                            ch_last = '\b';
                                            break;
                                        case 'f':
                                            ch_last = '\f';
                                            break;
                                        case 'n':
                                            ch_last = '\n';
                                            ++escaped_newlines;
                                            break;
                                        case 'r':
                                            ch_last = '\r';
                                            break;
                                        case 't':
                                            ch_last = '\t';
                                            break;
                                        case 'u':
                                        {
                                            if (jsonArray == null)
                                            {
                                                jsonArray = json.ToCharArray();
                                            }

                                            uint codepoint;
                                            if (HexToInteger(json.Substring(i + 2, 4), out codepoint) != 4)
                                            {
                                                throw new JsonParserException(i, "Bad unicode codepoint");
                                            }

                                            if (codepoint <= 0x7F)
                                            {
                                                ch_last = (char)codepoint;
                                            }
                                            else if (codepoint <= 0x7FF)
                                            {
                                                last++;
                                                jsonArray[last] = (char)(0xC0 | (codepoint >> 6));
                                                last++;
                                                jsonArray[last] = (char)(0x80 | (codepoint & 0x3F));
                                            }
                                            else if (codepoint <= 0xFFFF)
                                            {
                                                last++;
                                                jsonArray[last] = (char)(0xE0 | (codepoint >> 12));
                                                last++;
                                                jsonArray[last] = (char)(0x80 | ((codepoint >> 6) & 0x3F));
                                                last++;
                                                jsonArray[last] = (char)(0x80 | (codepoint & 0x3F));
                                            }
                                        }
                                            i += 4;
                                            break;
                                        default:
                                            throw new JsonParserException(first, "Unrecognized escape sequence");
                                    }

                                    last++;
                                    i++;
                                }
                                else if (ch == '"')
                                {
                                    break;
                                }
                                else
                                {
                                    last++;
                                    i++;
                                    ch = json[i];
                                }
                            }

                            if (name == null && top.Type == JsonType.Object)
                            {
                                // field name in object
                                name = json.Substring(first, i - first);
                            }
                            else
                            {
                                // new string value
                                var value = new JsonValue { Name = name };

                                name = null;

                                value.Type = JsonType.String;

                                string s;
                                if (jsonArray != null)
                                {
                                    var slice = new char[i - first];
                                    Array.Copy(jsonArray, first, slice, 0, i - first);
                                    s = new string(slice);
                                }
                                else
                                {
                                    s = json.Substring(first, i - first);
                                }
                                value.Value = new TypeUnion<string, long, decimal, bool>(s);

                                top.Append(value);
                            }
                        }
                        break;

                    case 'n':
                    case 't':
                    case 'f':
                        {
                            CheckTop(top, i);

                            // new null/bool value
                            var value = new JsonValue { Name = name };

                            name = null;

                            // null
                            if (ch == 'n' && json[i + 1] == 'u' && json[i + 2] == 'l' && json[i + 3] == 'l')
                            {
                                value.Type = JsonType.Null;
                                i += 3;
                            }
                            // true
                            else if (ch == 't' && json[i + 1] == 'r' && json[i + 2] == 'u' && json[i + 3] == 'e')
                            {
                                value.Type = JsonType.Boolean;
                                value.Value = new TypeUnion<string, long, decimal, bool>(true);
                                i += 3;
                            }
                            // false
                            else if (ch == 'f' && json[i + 1] == 'a' && json[i + 2] == 'l' && json[i + 3] == 's' && jsonArray[i + 4] == 'e')
                            {
                                value.Type = JsonType.Boolean;
                                value.Value = new TypeUnion<string, long, decimal, bool>(false);
                                i += 4;
                            }
                            else
                            {
                                throw new JsonParserException(i, "Unknown identifier");
                            }

                            top.Append(value);
                        }
                        break;

                    case '-':
                    case '0':
                    case '1':
                    case '2':
                    case '3':
                    case '4':
                    case '5':
                    case '6':
                    case '7':
                    case '8':
                    case '9':
                        {
                            CheckTop(top, i);

                            // new number value
                            var value = new JsonValue { Name = name };

                            name = null;

                            value.Type = JsonType.Integer;

                            int first = i;
                            while (ch != '\x20' && ch != '\x9' && ch != '\xD' && ch != '\xA' && ch != ',' && ch != ']' && ch != '}')
                            {
                                if (ch == '.' || ch == 'e' || ch == 'E')
                                {
                                    value.Type = JsonType.Decimal;
                                }
                                i++;
                                ch = json[i];
                            }

                            if (value.Type == JsonType.Integer)
                            {
                                long n;
                                if (TextToInteger(json.Substring(first, i - first), out n) != i - first)
                                {
                                    throw new JsonParserException(first, "Bad integer number");
                                }
                                else
                                {
                                    value.Value = new TypeUnion<string, long, decimal, bool>(n);
                                }
                                i--;
                            }

                            if (value.Type == JsonType.Decimal)
                            {
                                decimal d;
                                if (TextToDecimal(json.Substring(first, i - first), out d) != i - first)
                                {
                                    throw new JsonParserException(first, "Bad decimal number");
                                }
                                value.Value = new TypeUnion<string, long, decimal, bool>(d);
                                i--;
                            }

                            top.Append(value);
                        }
                        break;

                    default:
                        throw new JsonParserException(i, "Unexpected character");
                }
            }

            if (top != null)
            {
                throw new JsonParserException(i, "Not all objects/arrays have been properly closed");
            }

            return root;
        }
예제 #4
0
 private static int ComputeTypeMatchRank(JsonValue jsonObject, Type objectType)
 {
     var propertyNames = Reflector.GetAllProperties(objectType).Select(p => p.Name);
     var jsonNames = new HashSet<string>();
     var child = jsonObject.FirstChild;
     while (child != null)
     {
         if (child.Name != null)
         {
             jsonNames.Add(child.Name);
         }
         child = child.NexSibling;
     }
     jsonNames.UnionWith(propertyNames);
     return jsonNames.Count;
 }
예제 #5
0
        public static object ReadObject(JsonValue root, Type objectType)
        {
            JsonValue current = root.FirstChild ?? root;

            object result = null;
            object listResult = null;
            Type elementType = null;
            var reflectedType = Reflector.GetReflectedType(objectType);
            var simpleElement = false;
            var dictionary = false;
            JsonValue listRoot = null;

            if (root.Type == JsonType.Object)
            {
                if (reflectedType.IsDataEntity)
                {
                    result = ObjectFactory.Create(objectType);
                    elementType = objectType;
                }
                else if (reflectedType.IsDictionary)
                {
                    var types = objectType.GetGenericArguments();
                    result = Dictionary.Create(types[0], types[1]);
                    elementType = types[1];
                    dictionary = true;
                }
            }
            else if (root.Type == JsonType.Array)
            {
                if (reflectedType.IsDataEntity)
                {
                    result = List.Create(objectType);
                    elementType = objectType;
                }
                else if (reflectedType.IsDataEntityList)
                {
                    elementType = reflectedType.ElementType;
                    if (!reflectedType.IsInterface)
                    {
                        listResult = (IList)Nemo.Reflection.Activator.New(objectType);
                    }
                    else
                    {
                        listResult = List.Create(elementType);
                    }
                    result = ObjectFactory.Create(elementType);
                    listRoot = current;
                }
                else if (reflectedType.IsSimpleList)
                {
                    elementType = reflectedType.ElementType;
                    result = List.Create(elementType);
                    simpleElement = true;
                }
            }

            if (elementType == null && root.Parent == null)
            {
                return result;
            }

            IDictionary<string, ReflectedProperty> propertyMap = null;
            if (elementType != null && !simpleElement && !dictionary)
            {
                propertyMap = Reflector.GetPropertyNameMap(elementType);
            }

            if (listRoot != null)
            {
                current = listRoot.FirstChild;
            }

            while (current != null)
            {
                ReflectedProperty property = null;
                if (propertyMap == null || (current.Name != null && propertyMap.TryGetValue(current.Name, out property)))
                {
                    switch (current.Type)
                    {
                        case JsonType.Boolean:
                            if (property != null && (root.Type == JsonType.Object || (listRoot != null && listRoot.Type == JsonType.Object)))
                            {
                                ((IDataEntity)result).Property(property.PropertyName, current.Value.As<bool>());
                            }
                            if (result is IList)
                            {
                                ((IList)result).Add(current.Value.As<bool>());
                            }
                            else if (result is IDictionary)
                            {
                                ((IDictionary)result).Add(current.Name, current.Value.As<bool>());
                            }
                            else
                            {
                                result = current.Value.As<bool>();
                            }
                            break;
                        case JsonType.Decimal:
                            if (property != null && (root.Type == JsonType.Object || (listRoot != null && listRoot.Type == JsonType.Object)))
                            {
                                var value = current.Value.As<decimal>();
                                var typeCode = Type.GetTypeCode(property.PropertyType);
                                checked
                                {
                                    switch (typeCode)
                                    {
                                        case TypeCode.Double:
                                            ((IDataEntity)result).Property(property.PropertyName, (double)value);
                                            break;
                                        case TypeCode.Single:
                                            ((IDataEntity)result).Property(property.PropertyName, (float)value);
                                            break;
                                        case TypeCode.Decimal:
                                            ((IDataEntity)result).Property(property.PropertyName, value);
                                            break;
                                    }
                                }
                            }
                            else
                            {
                                var value = current.Value.As<decimal>();
                                var typeCode = Type.GetTypeCode(elementType ?? objectType);
                                checked
                                {
                                    switch (typeCode)
                                    {
                                        case TypeCode.Double:
                                            if (result is IList)
                                            {
                                                ((IList)result).Add((double)value);
                                            }
                                            else if (result is IDictionary)
                                            {
                                                ((IDictionary)result).Add(current.Name, (double)value);
                                            }
                                            else
                                            {
                                                result = (double)value;
                                            }
                                            break;
                                        case TypeCode.Single:
                                            if (result is IList)
                                            {
                                                ((IList)result).Add((float)value);
                                            }
                                            else if (result is IDictionary)
                                            {
                                                ((IDictionary)result).Add(current.Name, (float)value);
                                            }
                                            else
                                            {
                                                result = (float)value;
                                            }
                                            break;
                                        case TypeCode.Decimal:
                                            if (result is IList)
                                            {
                                                ((IList)result).Add(value);
                                            }
                                            else if (result is IDictionary)
                                            {
                                                ((IDictionary)result).Add(current.Name, value);
                                            }
                                            else
                                            {
                                                result = value;
                                            }
                                            break;
                                    }
                                }
                            }
                            break;
                        case JsonType.Integer:
                            if (property != null && (root.Type == JsonType.Object || (listRoot != null && listRoot.Type == JsonType.Object)))
                            {
                                var value = current.Value.As<long>();
                                var typeCode = Type.GetTypeCode(property.PropertyType);
                                checked
                                {
                                    switch (typeCode)
                                    {
                                        case TypeCode.Byte:
                                            ((IDataEntity)result).Property(property.PropertyName, (byte)value);
                                            break;
                                        case TypeCode.SByte:
                                            ((IDataEntity)result).Property(property.PropertyName, (sbyte)value);
                                            break;
                                        case TypeCode.Int16:
                                            ((IDataEntity)result).Property(property.PropertyName, (short)value);
                                            break;
                                        case TypeCode.Int32:
                                            ((IDataEntity)result).Property(property.PropertyName, (int)value);
                                            break;
                                        case TypeCode.Int64:
                                            ((IDataEntity)result).Property(property.PropertyName, value);
                                            break;
                                        case TypeCode.UInt16:
                                            ((IDataEntity)result).Property(property.PropertyName, (ushort)value);
                                            break;
                                        case TypeCode.UInt32:
                                            ((IDataEntity)result).Property(property.PropertyName, (uint)value);
                                            break;
                                        case TypeCode.UInt64:
                                            ((IDataEntity)result).Property(property.PropertyName, (ulong)value);
                                            break;
                                    }
                                }
                            }
                            else
                            {
                                var value = current.Value.As<long>();
                                var typeCode = Type.GetTypeCode(elementType ?? objectType);
                                checked
                                {
                                    switch (typeCode)
                                    {
                                        case TypeCode.Byte:
                                            if (result is IList)
                                            {
                                                ((IList)result).Add((byte)value);
                                            }
                                            else if (result is IDictionary)
                                            {
                                                ((IDictionary)result).Add(current.Name, (byte)value);
                                            }
                                            else
                                            {
                                                result = (byte)value;
                                            }
                                            break;
                                        case TypeCode.SByte:
                                            if (result is IList)
                                            {
                                                ((IList)result).Add((sbyte)value);
                                            }
                                            else if (result is IDictionary)
                                            {
                                                ((IDictionary)result).Add(current.Name, (sbyte)value);
                                            }
                                            else
                                            {
                                                result = (sbyte)value;
                                            }
                                            break;
                                        case TypeCode.Int16:
                                            if (result is IList)
                                            {
                                                ((IList)result).Add((short)value);
                                            }
                                            else if (result is IDictionary)
                                            {
                                                ((IDictionary)result).Add(current.Name, (short)value);
                                            }
                                            else
                                            {
                                                result = (short)value;
                                            }
                                            break;
                                        case TypeCode.Int32:
                                            if (result is IList)
                                            {
                                                ((IList)result).Add((int)value);
                                            }
                                            else if (result is IDictionary)
                                            {
                                                ((IDictionary)result).Add(current.Name, (int)value);
                                            }
                                            else
                                            {
                                                result = (int)value;
                                            }
                                            break;
                                        case TypeCode.Int64:
                                            if (result is IList)
                                            {
                                                ((IList)result).Add(value);
                                            }
                                            else if (result is IDictionary)
                                            {
                                                ((IDictionary)result).Add(current.Name, value);
                                            }
                                            else
                                            {
                                                result = value;
                                            }
                                            break;
                                        case TypeCode.UInt16:
                                            if (result is IList)
                                            {
                                                ((IList)result).Add((ushort)value);
                                            }
                                            else if (result is IDictionary)
                                            {
                                                ((IDictionary)result).Add(current.Name, (ushort)value);
                                            }
                                            else
                                            {
                                                result = (ushort)value;
                                            }
                                            break;
                                        case TypeCode.UInt32:
                                            if (result is IList)
                                            {
                                                ((IList)result).Add((uint)value);
                                            }
                                            else if (result is IDictionary)
                                            {
                                                ((IDictionary)result).Add(current.Name, (uint)value);
                                            }
                                            else
                                            {
                                                result = (uint)value;
                                            }
                                            break;
                                        case TypeCode.UInt64:
                                            if (result is IList)
                                            {
                                                ((IList)result).Add((ulong)value);
                                            }
                                            else if (result is IDictionary)
                                            {
                                                ((IDictionary)result).Add(current.Name, (ulong)value);
                                            }
                                            else
                                            {
                                                result = (ulong)value;
                                            }
                                            break;
                                    }
                                }
                            }
                            break;
                        case JsonType.String:
                            if (property != null && (root.Type == JsonType.Object || (listRoot != null && listRoot.Type == JsonType.Object)))
                            {
                                var value = current.Value.As<string>();
                                if (property.PropertyType == typeof(string))
                                {
                                    ((IDataEntity)result).Property(property.PropertyName, value);
                                }
                                else if (property.PropertyType == typeof(DateTime))
                                {
                                    DateTime date;
                                    if (DateTime.TryParse(value, out date))
                                    {
                                        ((IDataEntity)result).Property(property.PropertyName, date);
                                    }
                                }
                                else if (property.PropertyType == typeof(TimeSpan))
                                {
                                    TimeSpan time;
                                    if (TimeSpan.TryParse(value, out time))
                                    {
                                        ((IDataEntity)result).Property(property.PropertyName, time);
                                    }
                                }
                                else if (property.PropertyType == typeof(DateTimeOffset))
                                {
                                    DateTimeOffset date;
                                    if (DateTimeOffset.TryParse(value, out date))
                                    {
                                        ((IDataEntity)result).Property(property.PropertyName, date);
                                    }
                                }
                                else if (property.PropertyType == typeof(Guid))
                                {
                                    Guid guid;
                                    if (Guid.TryParse(value, out guid))
                                    {
                                        ((IDataEntity)result).Property(property.PropertyName, guid);
                                    }
                                }
                                else if (property.PropertyType == typeof(char) && !string.IsNullOrEmpty(value))
                                {
                                    ((IDataEntity)result).Property(property.PropertyName, value[0]);
                                }
                            }
                            else
                            {
                                var value = current.Value.As<string>();
                                var type = elementType ?? objectType;
                                if (type == typeof(string))
                                {
                                    if (result is IList)
                                    {
                                        ((IList)result).Add(value);
                                    }
                                    else if (result is IDictionary)
                                    {
                                        ((IDictionary)result).Add(current.Name, value);
                                    }
                                    else
                                    {
                                        result = value;
                                    }
                                }
                                else if (type == typeof(DateTime))
                                {
                                    DateTime date;
                                    if (DateTime.TryParse(value, out date))
                                    {
                                        if (result is IList)
                                        {
                                            ((IList)result).Add(date);
                                        }
                                        else if (result is IDictionary)
                                        {
                                            ((IDictionary)result).Add(current.Name, date);
                                        }
                                        else
                                        {
                                            result = date;
                                        }
                                    }
                                }
                                else if (type == typeof(TimeSpan))
                                {
                                    TimeSpan time;
                                    if (TimeSpan.TryParse(value, out time))
                                    {
                                        if (result is IList)
                                        {
                                            ((IList)result).Add(time);
                                        }
                                        else if (result is IDictionary)
                                        {
                                            ((IDictionary)result).Add(current.Name, time);
                                        }
                                        else
                                        {
                                            result = time;
                                        }
                                    }
                                }
                                else if (type == typeof(DateTimeOffset))
                                {
                                    DateTimeOffset date;
                                    if (DateTimeOffset.TryParse(value, out date))
                                    {
                                        if (result is IList)
                                        {
                                            ((IList)result).Add(date);
                                        }
                                        else if (result is IDictionary)
                                        {
                                            ((IDictionary)result).Add(current.Name, date);
                                        }
                                        else
                                        {
                                            result = date;
                                        }
                                    }
                                }
                                else if (type == typeof(Guid))
                                {
                                    Guid guid;
                                    if (Guid.TryParse(value, out guid))
                                    {
                                        if (result is IList)
                                        {
                                            ((IList)result).Add(guid);
                                        }
                                        else if (result is IDictionary)
                                        {
                                            ((IDictionary)result).Add(current.Name, guid);
                                        }
                                        else
                                        {
                                            result = guid;
                                        }
                                    }
                                }
                                else if (type == typeof(char) && !string.IsNullOrEmpty(value))
                                {
                                    if (result is IList)
                                    {
                                        ((IList)result).Add(value[0]);
                                    }
                                    else if (result is IDictionary)
                                    {
                                        ((IDictionary)result).Add(current.Name, value[0]);
                                    }
                                    else
                                    {
                                        result = value[0];
                                    }
                                }
                            }
                            break;
                        case JsonType.Object:
                            {
                                var propertyType = property.PropertyType;
                                var item = ReadObject(current, propertyType);

                                if (root.Type == JsonType.Object)
                                {
                                    ((IDataEntity)result).Property(property.PropertyName, item);
                                }
                                else if (root.Type == JsonType.Array)
                                {
                                    ((IList)result).Add(item);
                                }
                            }
                            break;
                        case JsonType.Array:
                            {
                                if (root.Type == JsonType.Object)
                                {
                                    if (property != null)
                                    {
                                        IList list;
                                        if (!property.IsListInterface)
                                        {
                                            list = (IList)Nemo.Reflection.Activator.New(property.PropertyType);
                                        }
                                        else
                                        {
                                            list = List.Create(property.ElementType, property.Distinct, property.Sorted);
                                        }
                                        var child = current.FirstChild;
                                        while (child != null)
                                        {
                                            var item = (IDataEntity)ReadObject(child, property.ElementType);
                                            list.Add(item);
                                            child = child.NexSibling;
                                        }
                                        ((IDataEntity)result).Property(property.PropertyName, list);
                                    }
                                    else if (result is IDictionary)
                                    {
                                        var listType = Reflector.GetReflectedType(elementType);
                                        if (elementType.IsArray)
                                        {
                                            var list = (IList)ReadObject(current, typeof(List<>).MakeGenericType(listType.ElementType));
                                            ((IDictionary)result).Add(current.Name, List.CreateArray(listType.ElementType, list));
                                        }
                                        else
                                        {
                                            var list = (IList)ReadObject(current, elementType);
                                            ((IDictionary)result).Add(current.Name, list);
                                        }
                                    }
                                }
                                break;
                            }
                    }
                }

                current = current.NexSibling;
                if (listRoot != null && current == null)
                {
                    ((IList)listResult).Add(result);
                    result = ObjectFactory.Create(elementType);
                    listRoot = listRoot.NexSibling;
                    if (listRoot != null)
                    {
                        current = listRoot.FirstChild;
                    }
                }
            }
            return listResult ?? result;
        }
예제 #6
0
파일: Json.cs 프로젝트: stepaside/Nemo
 internal void Append(JsonValue value)
 {
     //if (value.Name != null)
     //{
     //    _properties.Add(value.Name, value);
     //}
     value.Parent = this;
     if (LastChild != null)
     {
         LastChild = LastChild.NexSibling = value;
     }
     else
     {
         FirstChild = LastChild = value;
     }
 }