Пример #1
0
        static IMicheline ReadFlat(BinaryReader reader)
        {
            Stack <IMicheline> stack = new();
            IMicheline         node, top;
            MichelinePrim      prim;
            MichelineArray     arr;
            int tag, cnt, args, annots;

start:
            tag = reader.ReadByte();
            if (tag >= 0x80)
            {
                prim = new() { Prim = (PrimType)reader.ReadByte() };

                annots = tag & 0x0F;
                if (annots > 0)
                {
                    if (annots == 0x0F)
                    {
                        annots = reader.Read7BitInt();
                    }
                    prim.Annots = new(annots);
                }

                args = (tag & 0x70) >> 4;
                if (args > 0)
                {
                    if (args == 0x07)
                    {
                        args = reader.Read7BitInt();
                    }
                    prim.Args = new(args);

                    stack.Push(prim);
                    goto start;
                }

                if (prim.Annots != null)
                {
                    ReadAnnots(reader, prim);
                }

                node = prim;
            }
            else
            {
                cnt = tag & 0x1F;
                if (cnt == 0x1F)
                {
                    cnt = reader.Read7BitInt();
                }

                switch ((MichelineType)(tag & 0xE0))
                {
                case MichelineType.Array:
                    node = new MichelineArray(cnt);
                    if (cnt > 0)
                    {
                        stack.Push(node);
                        goto start;
                    }
                    break;

                case MichelineType.Bytes:
                    node = new MichelineBytes(reader.ReadBytes(cnt));
                    break;

                case MichelineType.Int:
                    node = new MichelineInt(new BigInteger(reader.ReadBytes(cnt)));
                    break;

                case MichelineType.String:
                    node = new MichelineString(Utf8.Convert(reader.ReadBytes(cnt)));
                    break;

                default:
                    throw new FormatException("Invalid micheline tag");
                }
            }
finish:
            if (stack.Count == 0)
            {
                return(node);
            }
            top = stack.Peek();
            if (top is MichelinePrim p)
            {
                p.Args.Add(node);
                if (p.Args.Count < p.Args.Capacity)
                {
                    goto start;
                }
                if (p.Annots != null)
                {
                    ReadAnnots(reader, p);
                }
            }
            else
            {
                arr = (MichelineArray)top;
                arr.Add(node);
                if (arr.Count < arr.Capacity)
                {
                    goto start;
                }
            }
            node = stack.Pop();
            goto finish;
        }
Пример #2
0
        public override IMicheline Read(ref Utf8JsonReader reader, Type typeToConvert, JsonSerializerOptions options)
        {
            Stack <IMicheline> stack = new();
            IMicheline         node, top;
            MichelinePrim      prim;
            string             prop;

start:
            switch (reader.TokenType)
            {
            case JsonTokenType.StartObject:
                reader.Read();
                if (reader.TokenType != JsonTokenType.PropertyName)
                {
                    throw new FormatException("Empty Micheline node");
                }
                prop = reader.GetString();
                reader.Read();
                switch (prop)
                {
                case "prim":
                    stack.Push(new MichelinePrim {
                        Prim = PrimTypeConverter.ParsePrim(reader.GetString())
                    });
                    reader.Read();
                    goto start;

                case "args":
                    stack.Push(new MichelinePrim());
                    if (reader.TokenType == JsonTokenType.StartArray)
                    {
                        reader.Read();
                        if (reader.TokenType != JsonTokenType.EndArray)
                        {
                            stack.Push(new MichelineArray(2));
                            goto start;
                        }
                    }
                    else if (reader.TokenType != JsonTokenType.Null)
                    {
                        throw new FormatException("Invalid prim args");
                    }
                    reader.Read();
                    goto start;

                case "annots":
                    List <IAnnotation> annots = null;
                    if (reader.TokenType == JsonTokenType.StartArray)
                    {
                        reader.Read();
                        if (reader.TokenType == JsonTokenType.String)
                        {
                            annots = new(2);
                            annots.Add(AnnotationConverter.ParseAnnotation(reader.GetString()));
                            reader.Read();
                            while (reader.TokenType == JsonTokenType.String)
                            {
                                annots.Add(AnnotationConverter.ParseAnnotation(reader.GetString()));
                                reader.Read();
                            }
                        }
                        if (reader.TokenType != JsonTokenType.EndArray)
                        {
                            throw new FormatException("Invalid prim annotation");
                        }
                    }
                    else if (reader.TokenType != JsonTokenType.Null)
                    {
                        throw new FormatException("Invalid prim annots");
                    }
                    stack.Push(new MichelinePrim {
                        Annots = annots
                    });
                    reader.Read();
                    goto start;

                case "bytes":
                    if (reader.TokenType != JsonTokenType.String)
                    {
                        throw new FormatException("Invalid Micheline bytes node");
                    }
                    node = new MichelineBytes(Hex.Parse(reader.GetString()));
                    break;

                case "string":
                    if (reader.TokenType != JsonTokenType.String)
                    {
                        throw new FormatException("Invalid Micheline string node");
                    }
                    node = new MichelineString(reader.GetString());
                    break;

                case "int":
                    if (reader.TokenType != JsonTokenType.String)
                    {
                        throw new FormatException("Invalid Micheline int node");
                    }
                    node = new MichelineInt(BigInteger.Parse(reader.GetString()));
                    break;

                default:
                    throw new FormatException("Invalid Micheline node");
                }
                reader.Read();
                if (reader.TokenType != JsonTokenType.EndObject)
                {
                    throw new FormatException($"Invalid Micheline {node.Type} node");
                }
                goto endNode;

            case JsonTokenType.PropertyName:
                prim = (MichelinePrim)stack.Peek();
                prop = reader.GetString();
                reader.Read();
                switch (prop)
                {
                case "prim":
                    prim.Prim = PrimTypeConverter.ParsePrim(reader.GetString());
                    reader.Read();
                    goto start;

                case "args":
                    if (reader.TokenType == JsonTokenType.StartArray)
                    {
                        reader.Read();
                        if (reader.TokenType != JsonTokenType.EndArray)
                        {
                            stack.Push(new MichelineArray(2));
                            goto start;
                        }
                    }
                    else if (reader.TokenType != JsonTokenType.Null)
                    {
                        throw new FormatException("Invalid prim args");
                    }
                    reader.Read();
                    goto start;

                case "annots":
                    List <IAnnotation> annots = null;
                    if (reader.TokenType == JsonTokenType.StartArray)
                    {
                        reader.Read();
                        if (reader.TokenType == JsonTokenType.String)
                        {
                            annots = new(2);
                            annots.Add(AnnotationConverter.ParseAnnotation(reader.GetString()));
                            reader.Read();
                            while (reader.TokenType == JsonTokenType.String)
                            {
                                annots.Add(AnnotationConverter.ParseAnnotation(reader.GetString()));
                                reader.Read();
                            }
                        }
                        if (reader.TokenType != JsonTokenType.EndArray)
                        {
                            throw new FormatException("Invalid prim annotation");
                        }
                    }
                    else if (reader.TokenType != JsonTokenType.Null)
                    {
                        throw new FormatException("Invalid prim annots");
                    }
                    prim.Annots = annots;
                    reader.Read();
                    goto start;

                default:
                    throw new FormatException();
                }

            case JsonTokenType.EndObject:
                node = stack.Pop();
endNode:
                if (stack.Count == 0)
                {
                    return(node);
                }
                ((MichelineArray)stack.Peek()).Add(node);
                reader.Read();
                goto start;

            case JsonTokenType.StartArray:
                stack.Push(new MichelineArray());
                reader.Read();
                goto start;

            case JsonTokenType.EndArray:
                node = stack.Pop();
                if (stack.Count == 0)
                {
                    return(node);
                }
                top = stack.Peek();
                if (top is MichelinePrim pr)
                {
                    pr.Args = (MichelineArray)node;
                }
                else
                {
                    ((MichelineArray)top).Add(node);
                }
                reader.Read();
                goto start;

            default:
                throw new FormatException("Invalid Micheline format");
            }
        }