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; }
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"); } }