using System; using System.IO; using System.Linq; using System.Text; using Utf8Json.Internal; using Utf8Json.Resolvers; namespace Utf8Json { /// /// High-Level API of Utf8Json. /// public static partial class JsonSerializer { static IJsonFormatterResolver defaultResolver; /// /// FormatterResolver that used resolver less overloads. If does not set it, used StandardResolver.Default. /// public static IJsonFormatterResolver DefaultResolver { get { if (defaultResolver == null) { defaultResolver = StandardResolver.Default; } return defaultResolver; } } /// /// Is resolver decided? /// public static bool IsInitialized { get { return defaultResolver != null; } } /// /// Set default resolver of Utf8Json APIs. /// /// public static void SetDefaultResolver(IJsonFormatterResolver resolver) { defaultResolver = resolver; } /// /// Serialize to binary with default resolver. /// public static byte[] Serialize(T obj) { return Serialize(obj, defaultResolver); } /// /// Serialize to binary with specified resolver. /// public static byte[] Serialize(T value, IJsonFormatterResolver resolver) { if (resolver == null) resolver = DefaultResolver; var writer = new JsonWriter(MemoryPool.GetBuffer()); var formatter = resolver.GetFormatterWithVerify(); formatter.Serialize(ref writer, value, resolver); return writer.ToUtf8ByteArray(); } public static void Serialize(ref JsonWriter writer, T value) { Serialize(ref writer, value, defaultResolver); } public static void Serialize(ref JsonWriter writer, T value, IJsonFormatterResolver resolver) { if (resolver == null) resolver = DefaultResolver; var formatter = resolver.GetFormatterWithVerify(); formatter.Serialize(ref writer, value, resolver); } /// /// Serialize to stream. /// public static void Serialize(Stream stream, T value) { Serialize(stream, value, defaultResolver); } /// /// Serialize to stream with specified resolver. /// public static void Serialize(Stream stream, T value, IJsonFormatterResolver resolver) { if (resolver == null) resolver = DefaultResolver; var buffer = SerializeUnsafe(value, resolver); stream.Write(buffer.Array, buffer.Offset, buffer.Count); } #if NETSTANDARD /// /// Serialize to stream(write async). /// public static System.Threading.Tasks.Task SerializeAsync(Stream stream, T value) { return SerializeAsync(stream, value, defaultResolver); } /// /// Serialize to stream(write async) with specified resolver. /// public static async System.Threading.Tasks.Task SerializeAsync(Stream stream, T value, IJsonFormatterResolver resolver) { if (resolver == null) resolver = DefaultResolver; var buf = BufferPool.Default.Rent(); try { var writer = new JsonWriter(buf); var formatter = resolver.GetFormatterWithVerify(); formatter.Serialize(ref writer, value, resolver); var buffer = writer.GetBuffer(); await stream.WriteAsync(buffer.Array, buffer.Offset, buffer.Count).ConfigureAwait(false); } finally { BufferPool.Default.Return(buf); } } #endif /// /// Serialize to binary. Get the raw memory pool byte[]. The result can not share across thread and can not hold, so use quickly. /// public static ArraySegment SerializeUnsafe(T obj) { return SerializeUnsafe(obj, defaultResolver); } /// /// Serialize to binary with specified resolver. Get the raw memory pool byte[]. The result can not share across thread and can not hold, so use quickly. /// public static ArraySegment SerializeUnsafe(T value, IJsonFormatterResolver resolver) { if (resolver == null) resolver = DefaultResolver; var writer = new JsonWriter(MemoryPool.GetBuffer()); var formatter = resolver.GetFormatterWithVerify(); formatter.Serialize(ref writer, value, resolver); return writer.GetBuffer(); } /// /// Serialize to JsonString. /// public static string ToJsonString(T value) { return ToJsonString(value, defaultResolver); } /// /// Serialize to JsonString with specified resolver. /// public static string ToJsonString(T value, IJsonFormatterResolver resolver) { if (resolver == null) resolver = DefaultResolver; var writer = new JsonWriter(MemoryPool.GetBuffer()); var formatter = resolver.GetFormatterWithVerify(); formatter.Serialize(ref writer, value, resolver); return writer.ToString(); } public static T Deserialize(string json) { return Deserialize(json, defaultResolver); } public static T Deserialize(string json, IJsonFormatterResolver resolver) { return Deserialize(StringEncoding.UTF8.GetBytes(json), resolver); } public static T Deserialize(byte[] bytes) { return Deserialize(bytes, defaultResolver); } public static T Deserialize(byte[] bytes, IJsonFormatterResolver resolver) { return Deserialize(bytes, 0, resolver); } public static T Deserialize(byte[] bytes, int offset) { return Deserialize(bytes, offset, defaultResolver); } public static T Deserialize(byte[] bytes, int offset, IJsonFormatterResolver resolver) { if (resolver == null) resolver = DefaultResolver; var reader = new JsonReader(bytes, offset); var formatter = resolver.GetFormatterWithVerify(); return formatter.Deserialize(ref reader, resolver); } public static T Deserialize(ref JsonReader reader) { return Deserialize(ref reader, defaultResolver); } public static T Deserialize(ref JsonReader reader, IJsonFormatterResolver resolver) { if (resolver == null) resolver = DefaultResolver; var formatter = resolver.GetFormatterWithVerify(); return formatter.Deserialize(ref reader, resolver); } public static T Deserialize(Stream stream) { return Deserialize(stream, defaultResolver); } public static T Deserialize(Stream stream, IJsonFormatterResolver resolver) { if (resolver == null) resolver = DefaultResolver; #if NETSTANDARD && !NET45 var ms = stream as MemoryStream; if (ms != null) { ArraySegment buf2; if (ms.TryGetBuffer(out buf2)) { // when token is number, can not use from pool(can not find end line). var token = new JsonReader(buf2.Array, buf2.Offset).GetCurrentJsonToken(); if (token == JsonToken.Number) { var buf3 = new byte[buf2.Count]; Buffer.BlockCopy(buf2.Array, buf2.Offset, buf3, 0, buf3.Length); return Deserialize(buf3, 0, resolver); } return Deserialize(buf2.Array, buf2.Offset, resolver); } } #endif { var buf = MemoryPool.GetBuffer(); var len = FillFromStream(stream, ref buf); // when token is number, can not use from pool(can not find end line). var token = new JsonReader(buf).GetCurrentJsonToken(); if (token == JsonToken.Number) { buf = BinaryUtil.FastCloneWithResize(buf, len); } return Deserialize(buf, resolver); } } #if NETSTANDARD public static System.Threading.Tasks.Task DeserializeAsync(Stream stream) { return DeserializeAsync(stream, defaultResolver); } public static async System.Threading.Tasks.Task DeserializeAsync(Stream stream, IJsonFormatterResolver resolver) { if (resolver == null) resolver = DefaultResolver; var buffer = BufferPool.Default.Rent(); var buf = buffer; try { int length = 0; int read; while ((read = await stream.ReadAsync(buf, length, buf.Length - length).ConfigureAwait(false)) > 0) { length += read; if (length == buf.Length) { BinaryUtil.FastResize(ref buf, length * 2); } } // when token is number, can not use from pool(can not find end line). var token = new JsonReader(buf).GetCurrentJsonToken(); if (token == JsonToken.Number) { buf = BinaryUtil.FastCloneWithResize(buf, length); } return Deserialize(buf, resolver); } finally { BufferPool.Default.Return(buffer); } } #endif public static string PrettyPrint(byte[] json) { return PrettyPrint(json, 0); } public static string PrettyPrint(byte[] json, int offset) { var reader = new JsonReader(json, offset); var writer = new JsonWriter(MemoryPool.GetBuffer()); WritePrittyPrint(ref reader, ref writer, 0); return writer.ToString(); } public static string PrettyPrint(string json) { var reader = new JsonReader(Encoding.UTF8.GetBytes(json)); var writer = new JsonWriter(MemoryPool.GetBuffer()); WritePrittyPrint(ref reader, ref writer, 0); return writer.ToString(); } public static byte[] PrettyPrintByteArray(byte[] json) { return PrettyPrintByteArray(json, 0); } public static byte[] PrettyPrintByteArray(byte[] json, int offset) { var reader = new JsonReader(json, offset); var writer = new JsonWriter(MemoryPool.GetBuffer()); WritePrittyPrint(ref reader, ref writer, 0); return writer.ToUtf8ByteArray(); } public static byte[] PrettyPrintByteArray(string json) { var reader = new JsonReader(Encoding.UTF8.GetBytes(json)); var writer = new JsonWriter(MemoryPool.GetBuffer()); WritePrittyPrint(ref reader, ref writer, 0); return writer.ToUtf8ByteArray(); } static readonly byte[][] indent = Enumerable.Range(0, 100).Select(x => Encoding.UTF8.GetBytes(new string(' ', x * 2))).ToArray(); static readonly byte[] newLine = Encoding.UTF8.GetBytes(Environment.NewLine); static void WritePrittyPrint(ref JsonReader reader, ref JsonWriter writer, int depth) { var token = reader.GetCurrentJsonToken(); switch (token) { case JsonToken.BeginObject: { writer.WriteBeginObject(); writer.WriteRaw(newLine); var c = 0; while (reader.ReadIsInObject(ref c)) { if (c != 1) { writer.WriteRaw((byte)','); writer.WriteRaw(newLine); } writer.WriteRaw(indent[depth + 1]); writer.WritePropertyName(reader.ReadPropertyName()); writer.WriteRaw((byte)' '); WritePrittyPrint(ref reader, ref writer, depth + 1); } writer.WriteRaw(newLine); writer.WriteRaw(indent[depth]); writer.WriteEndObject(); } break; case JsonToken.BeginArray: { writer.WriteBeginArray(); writer.WriteRaw(newLine); var c = 0; while (reader.ReadIsInArray(ref c)) { if (c != 1) { writer.WriteRaw((byte)','); writer.WriteRaw(newLine); } writer.WriteRaw(indent[depth + 1]); WritePrittyPrint(ref reader, ref writer, depth + 1); } writer.WriteRaw(newLine); writer.WriteRaw(indent[depth]); writer.WriteEndArray(); } break; case JsonToken.Number: { var v = reader.ReadDouble(); writer.WriteDouble(v); } break; case JsonToken.String: { var v = reader.ReadString(); writer.WriteString(v); } break; case JsonToken.True: case JsonToken.False: { var v = reader.ReadBoolean(); writer.WriteBoolean(v); } break; case JsonToken.Null: { reader.ReadIsNull(); writer.WriteNull(); } break; default: break; } } static int FillFromStream(Stream input, ref byte[] buffer) { int length = 0; int read; while ((read = input.Read(buffer, length, buffer.Length - length)) > 0) { length += read; if (length == buffer.Length) { BinaryUtil.FastResize(ref buffer, length * 2); } } return length; } static class MemoryPool { [ThreadStatic] static byte[] buffer = null; public static byte[] GetBuffer() { if (buffer == null) { buffer = new byte[65536]; } return buffer; } } } }