Skip to content

Instantly share code, notes, and snippets.

@markcastle
Last active August 6, 2019 14:32
Show Gist options
  • Save markcastle/324cb4fa03048404ee1ecbac5174a7b5 to your computer and use it in GitHub Desktop.
Save markcastle/324cb4fa03048404ee1ecbac5174a7b5 to your computer and use it in GitHub Desktop.
Extremely fast Json encoder for c# with no dependancies (except StringBuilder).
/*
* Copyright 2017, 2018, 2019 Captive Reality Ltd - All Rights Reserved
* Permission to use, copy, modify, and/or distribute this software for any purpose with or without fee is
* hereby granted, provided that the above copyright notice and this permission notice appear in all copies.
* THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE
* INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE
* FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM
* LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION,
* ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
*
* Source: https://gist.github.com/markcastle/324cb4fa03048404ee1ecbac5174a7b5
*
* Description:
* Extremely fast Json encoder for c# with no dependancies (except StringBuilder).
* This is not a json parser.
* We can also automatically do some auto escaping.
* Written by Mark Castle <mark.castle@captivereality.com>, July 2017
*
* Usage:
*
* Utils.Json json = new Utils.Json();
* json.Add("App", "AppName");
* json.Add("Integer1", intVariable1);
* json.Add("Integer2", intVariable2);
* json.Add("Integer3", intVariable3);
* return json.toString();
*
* Changelog:
* 26/07/2017 - Created by MC
*
* references:
*
*/
using System;
using System.Text;
namespace CaptiveReality.Utils
{
/// <summary>
/// Very fast Json builder utility.
/// Builds JSON only (eg, Cannot Parse Json)
/// </summary>
public class Json
{
StringBuilder _json = new StringBuilder();
/// <summary>
/// Constructor
/// </summary>
public Json()
{
}
/// <summary>
/// Add a string value
/// </summary>
/// <param name="name"></param>
/// <param name="value"></param>
public void AddJson(string name, string value)
{
if (_json.Length != 0)
{
_json.Append(",");
}
_json.Append("\"").Append(name).Append("\":").Append(value);
}
public void Append(string jsonToAppend)
{
if (_json.Length != 0)
{
_json.Append(",");
}
_json.Append(jsonToAppend);
}
/// <summary>
/// Merge a json string with our existing json.
/// </summary>
/// <param name="jsonToMerge"></param>
public void Merge(string jsonToMerge)
{
if (_json.Length != 0)
{
_json.Append(",");
}
_json.Append(jsonToMerge.TrimStart('{').TrimEnd('}'));
}
/// <summary>
/// Add a float
/// Converts floats using zero decimal places. Possibly not what is wanted for most normal use, but it is what I want for memory bytes.
/// </summary>
/// <param name="name"></param>
/// <param name="value"></param>
public void Add(string name, float value)
{
if (_json.Length != 0)
{
_json.Append(",");
}
_json.Append("\"").Append(name).Append("\":").Append(value.ToString("{0:0.#######}"));
}
/// <summary>
/// Add an integer value
/// </summary>
/// <param name="name"></param>
/// <param name="value"></param>
public void Add(string name, int value)
{
if (_json.Length != 0)
{
_json.Append(",");
}
_json.Append("\"").Append(name).Append("\":").Append(value.ToString());
}
/// <summary>
/// Add Json
/// </summary>
/// <param name="name"></param>
/// <param name="value"></param>
public void Add(string name, Json value)
{
if (_json.Length != 0)
{
_json.Append(",");
}
_json.Append("\"").Append(name).Append("\":").Append(value.toString());
}
/// <summary>
/// Add string with auto escaping
/// </summary>
/// <param name="name"></param>
/// <param name="value"></param>
/// <param name="cleanForJson"></param>
public void Add(string name, string value, bool cleanForJson = true)
{
if (_json.Length != 0)
{
_json.Append(",");
}
_json.Append("\"").Append(name).Append("\":").Append("\"").Append((cleanForJson ? escapeForJson(value) : value)).Append("\"");
}
/// <summary>
/// Add a bool
/// </summary>
/// <param name="name"></param>
/// <param name="value"></param>
public void Add(string name, bool value)
{
if (_json.Length != 0)
{
_json.Append(",");
}
_json.Append("\"").Append(name).Append("\":").Append((value ? "true" : "false"));
}
/// <summary>
/// Clear everything
/// </summary>
public void Clear()
{
_json = new StringBuilder();
}
/// <summary>
/// Convert to a string
/// </summary>
/// <returns></returns>
public string toString()
{
return "{" + _json.ToString() + "}";
}
/// <summary>
/// Return the string builder representation
/// </summary>
/// <returns></returns>
public StringBuilder toStringBuilder()
{
return _json;
}
/// <summary>
/// Append
/// </summary>
/// <param name="jsonToAppend"></param>
public void Append(StringBuilder jsonToAppend)
{
if (_json.Length != 0)
{
_json.Append(",");
}
_json.Append(jsonToAppend);
}
/// <summary>
/// Auto string escaping
/// </summary>
/// <param name="s"></param>
/// <returns></returns>
public static string escapeForJson(string s)
{
if (s == null || s.Length == 0)
{
return "";
}
char c = '\0';
int i;
int len = s.Length;
StringBuilder sb = new StringBuilder(len + 4);
string t;
for (i = 0; i < len; i += 1)
{
c = s[i];
switch (c)
{
case '\\':
case '"':
sb.Append('\\');
sb.Append(c);
break;
case '/':
sb.Append('\\');
sb.Append(c);
break;
case '\b':
sb.Append("\\b");
break;
case '\t':
sb.Append("\\t");
break;
case '\n':
sb.Append("\\n");
break;
case '\f':
sb.Append("\\f");
break;
case '\r':
sb.Append("\\r");
break;
default:
if (c < ' ')
{
t = "000" + String.Format("X", c);
sb.Append("\\u" + t.Substring(t.Length - 4));
}
else
{
sb.Append(c);
}
break;
}
}
return sb.ToString();
}
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment