public void Encode(RubyToken token, string file, RubyEncoderOptions options) { using (var stream = File.Open(file, FileMode.Create, FileAccess.Write, FileShare.ReadWrite)) { Encode(token, stream, options); } }
public void Encode(RubyToken token, Stream stream, RubyEncoderOptions options) { using (var writer = new BinaryWriter(stream)) { writer.Write((short)0x0804); WriteEntry(token, new WriteContext { Writer = writer }, options ?? new RubyEncoderOptions()); } }
internal static void WriteEntry(RubyToken token, WriteContext context, RubyEncoderOptions options) { switch (token.Type) { case RubyTokenType.Array: var rubyArray = (RubyArray)token; context.Data.Add(rubyArray); context.Writer.Write((byte)RubyType.Array); WriteNumber(rubyArray.Count, context); foreach (var item in rubyArray) { WriteEntry(item, context, options); } break; case RubyTokenType.Object: var rubyObject = (RubyObject)token; context.Data.Add(rubyObject); if (rubyObject.RubyClass.Name == "encoder:Hash") { context.Writer.Write((byte)RubyType.Hash); WriteNumber(rubyObject.Properties.Count, context); foreach (var property in rubyObject.Properties) { var rubyKey = long.TryParse(property.Key, out var numberKey) ? new RubyValue(numberKey) : new RubyValue(property.Key); WriteEntry(rubyKey, context, options); WriteEntry(property.Value, context, options); } } else if (options.UserEncoders.TryGetValue(rubyObject.RubyClass.Name, out var encoder)) { context.Writer.Write((byte)RubyType.UserDefined); WriteSymbolDefinition(rubyObject.RubyClass.Name, context); var bytes = encoder(rubyObject); WriteNumber(bytes.Length, context); context.Writer.Write(bytes, 0, bytes.Length); } else { context.Writer.Write((byte)RubyType.Object); WriteSymbolDefinition(rubyObject.RubyClass.Name, context); WriteNumber(rubyObject.Properties.Count, context); foreach (var property in rubyObject.Properties) { WriteSymbolDefinition("@" + property.Key, context); WriteEntry(property.Value, context, options); } } break; case RubyTokenType.Boolean: context.Writer.Write((byte)(token.GetValue <bool>() ? RubyType.True : RubyType.False)); break; case RubyTokenType.String: context.Writer.Write((byte)RubyType.String); WriteString(token.GetValue <string>(), context); break; case RubyTokenType.Bytes: context.Writer.Write((byte)RubyType.String); WriteBytes(token.GetValue <byte[]>(), context); break; case RubyTokenType.Number: context.Writer.Write((byte)RubyType.Number); WriteNumber(token.GetValue <long>(), context); break; case RubyTokenType.Float: context.Writer.Write((byte)RubyType.Decimal); context.Data.Add(token); WriteFloat(token.GetValue <double>(), context); break; case RubyTokenType.Null: context.Writer.Write((byte)RubyType.Nil); break; default: throw new InvalidOperationException($"Cannot write type of {token.Type}."); } }