Sunday, December 07, 2008

Someone's asked for my hack of JsonWriter from Facebook.NET

Got an email today asking for the source to HackJsonWriter - the code I ripped out of Facebook.NET on Codeplex - as described here.

If you want to include this code in your projects then you probably need to add a comment attributing it back to Facebook.NET -not sure what the open source license is on that project (but it should be OK as you'll be using Facebook.NET anyway)

Also, importantly.... unless you are updating an old project, my advice is do not use Facebook.NET - the FacebookToolkit from Microsoft (also on Codeplex) looks a much better way to go!

Here's the very longwinded code:

using System;

using System.Collections.Generic;

using System.Web;

using System.Text;

using System.Globalization;

using System.Collections;

using System.ComponentModel;

using System.IO;

internal sealed class IndentedTextWriter : TextWriter

{

// Fields

private int _indentLevel;

private bool _minimize;

private bool _tabsPending;

private string _tabString;

private TextWriter _writer;

// Methods

public IndentedTextWriter(TextWriter writer, bool minimize) : base(CultureInfo.InvariantCulture)

{

this._writer = writer;

this._minimize = minimize;

if (this._minimize)

{

this.NewLine = "\r";

}

this._tabString = " ";

this._indentLevel = 0;

this._tabsPending = false;

}

public override void Close()

{

this._writer.Close();

}

public override void Flush()

{

this._writer.Flush();

}

private void OutputTabs()

{

if (this._tabsPending)

{

if (!this._minimize)

{

for (int i = 0; i < this._indentLevel; i++)

{

this._writer.Write(this._tabString);

}

}

this._tabsPending = false;

}

}

public override void Write(bool value)

{

this.OutputTabs();

this._writer.Write(value);

}

public override void Write(char value)

{

this.OutputTabs();

this._writer.Write(value);

}

public override void Write(string s)

{

this.OutputTabs();

this._writer.Write(s);

}

public override void Write(char[] buffer)

{

this.OutputTabs();

this._writer.Write(buffer);

}

public override void Write(double value)

{

this.OutputTabs();

this._writer.Write(value);

}

public override void Write(int value)

{

this.OutputTabs();

this._writer.Write(value);

}

public override void Write(long value)

{

this.OutputTabs();

this._writer.Write(value);

}

public override void Write(object value)

{

this.OutputTabs();

this._writer.Write(value);

}

public override void Write(float value)

{

this.OutputTabs();

this._writer.Write(value);

}

public override void Write(string format, params object[] arg)

{

this.OutputTabs();

this._writer.Write(format, arg);

}

public override void Write(string format, object arg0)

{

this.OutputTabs();

this._writer.Write(format, arg0);

}

public override void Write(char[] buffer, int index, int count)

{

this.OutputTabs();

this._writer.Write(buffer, index, count);

}

public override void Write(string format, object arg0, object arg1)

{

this.OutputTabs();

this._writer.Write(format, arg0, arg1);

}

public override void WriteLine()

{

this.OutputTabs();

this._writer.WriteLine();

this._tabsPending = true;

}

public override void WriteLine(bool value)

{

this.OutputTabs();

this._writer.WriteLine(value);

this._tabsPending = true;

}

public override void WriteLine(char value)

{

this.OutputTabs();

this._writer.WriteLine(value);

this._tabsPending = true;

}

public override void WriteLine(double value)

{

this.OutputTabs();

this._writer.WriteLine(value);

this._tabsPending = true;

}

public override void WriteLine(int value)

{

this.OutputTabs();

this._writer.WriteLine(value);

this._tabsPending = true;

}

public override void WriteLine(char[] buffer)

{

this.OutputTabs();

this._writer.WriteLine(buffer);

this._tabsPending = true;

}

public override void WriteLine(long value)

{

this.OutputTabs();

this._writer.WriteLine(value);

this._tabsPending = true;

}

public override void WriteLine(object value)

{

this.OutputTabs();

this._writer.WriteLine(value);

this._tabsPending = true;

}

public override void WriteLine(float value)

{

this.OutputTabs();

this._writer.WriteLine(value);

this._tabsPending = true;

}

public override void WriteLine(string s)

{

this.OutputTabs();

this._writer.WriteLine(s);

this._tabsPending = true;

}

public override void WriteLine(uint value)

{

this.OutputTabs();

this._writer.WriteLine(value);

this._tabsPending = true;

}

public override void WriteLine(string format, params object[] arg)

{

this.OutputTabs();

this._writer.WriteLine(format, arg);

this._tabsPending = true;

}

public override void WriteLine(string format, object arg0)

{

this.OutputTabs();

this._writer.WriteLine(format, arg0);

this._tabsPending = true;

}

public override void WriteLine(string format, object arg0, object arg1)

{

this.OutputTabs();

this._writer.WriteLine(format, arg0, arg1);

this._tabsPending = true;

}

public override void WriteLine(char[] buffer, int index, int count)

{

this.OutputTabs();

this._writer.WriteLine(buffer, index, count);

this._tabsPending = true;

}

public void WriteLineNoTabs(string s)

{

this._writer.WriteLine(s);

}

public void WriteNewLine()

{

if (!this._minimize)

{

this.WriteLine();

}

}

public void WriteSignificantNewLine()

{

this.WriteLine();

}

public void WriteTrimmed(string text)

{

if (!this._minimize)

{

this.Write(text);

}

else

{

this.Write(text.Trim());

}

}

// Properties

public override Encoding Encoding

{

get

{

return this._writer.Encoding;

}

}

public int Indent

{

get

{

return this._indentLevel;

}

set

{

if (value <>

{

value = 0;

}

this._indentLevel = value;

}

}

public override string NewLine

{

get

{

return this._writer.NewLine;

}

set

{

this._writer.NewLine = value;

}

}

}

///

/// Summary description for HackJsonWriter

///

public class HackJsonWriter

{

// Fields

private Stack _scopes;

private IndentedTextWriter _writer;

// Methods

public HackJsonWriter(TextWriter writer)

: this(writer, true)

{

}

public HackJsonWriter(TextWriter writer, bool minimizeWhitespace)

{

this._writer = new IndentedTextWriter(writer, minimizeWhitespace);

this._scopes = new Stack();

}

public void EndScope()

{

if (this._scopes.Count == 0)

{

throw new InvalidOperationException("No active scope to end.");

}

this._writer.WriteLine();

this._writer.Indent--;

if (this._scopes.Pop().Type == ScopeType.Array)

{

this._writer.Write("]");

}

else

{

this._writer.Write("}");

}

}

internal static string QuoteJScriptString(string s)

{

if (string.IsNullOrEmpty(s))

{

return string.Empty;

}

StringBuilder builder = null;

int startIndex = 0;

int count = 0;

for (int i = 0; i <>

{

char ch = s[i];

if ((((ch == '\r') || (ch == '\t')) || ((ch == '"') || (ch == '\''))) || (((ch == '\\') || (ch == '\r')) || ((ch < ' ') || (ch > '\x007f'))))

{

if (builder == null)

{

builder = new StringBuilder(s.Length + 6);

}

if (count > 0)

{

builder.Append(s, startIndex, count);

}

startIndex = i + 1;

count = 0;

}

switch (ch)

{

case '\'':

{

builder.Append(@"\'");

continue;

}

case '\\':

{

builder.Append(@"\\");

continue;

}

case '\t':

{

builder.Append(@"\t");

continue;

}

case '\n':

{

builder.Append(@"\n");

continue;

}

case '\r':

{

builder.Append(@"\r");

continue;

}

case '"':

{

builder.Append("\\\"");

continue;

}

}

if ((ch < ' ') || (ch > '\x007f'))

{

builder.AppendFormat(CultureInfo.InvariantCulture, @"\u{0:x4}", new object[] { (int)ch });

}

else

{

count++;

}

}

string str = s;

if (builder == null)

{

return str;

}

if (count > 0)

{

builder.Append(s, startIndex, count);

}

return builder.ToString();

}

public void StartArrayScope()

{

this.StartScope(ScopeType.Array);

}

public void StartObjectScope()

{

this.StartScope(ScopeType.Object);

}

private void StartScope(ScopeType type)

{

if (this._scopes.Count != 0)

{

Scope scope = this._scopes.Peek();

if ((scope.Type == ScopeType.Array) && (scope.ObjectCount != 0))

{

this._writer.WriteTrimmed(", ");

}

scope.ObjectCount++;

}

Scope item = new Scope(type);

this._scopes.Push(item);

if (type == ScopeType.Array)

{

this._writer.Write("[");

}

else

{

this._writer.Write("{");

}

this._writer.Indent++;

this._writer.WriteLine();

}

private void WriteCore(string text, bool quotes)

{

if (this._scopes.Count != 0)

{

Scope scope = this._scopes.Peek();

if (scope.Type == ScopeType.Array)

{

if (scope.ObjectCount != 0)

{

this._writer.WriteTrimmed(", ");

}

scope.ObjectCount++;

}

}

if (quotes)

{

this._writer.Write('"');

}

this._writer.Write(text);

if (quotes)

{

this._writer.Write('"');

}

}

public void WriteName(string name)

{

if (string.IsNullOrEmpty(name))

{

throw new ArgumentNullException("name");

}

if (this._scopes.Count == 0)

{

throw new InvalidOperationException("No active scope to write into.");

}

if (this._scopes.Peek().Type != ScopeType.Object)

{

throw new InvalidOperationException("Names can only be written into Object scopes.");

}

Scope scope = this._scopes.Peek();

if (scope.Type == ScopeType.Object)

{

if (scope.ObjectCount != 0)

{

this._writer.WriteTrimmed(", ");

}

scope.ObjectCount++;

}

this._writer.Write("\"");

this._writer.Write(name);

this._writer.WriteTrimmed("\": ");

}

public void WriteValue(bool value)

{

this.WriteCore(value ? "true" : "false", false);

}

public void WriteValue(ICollection items)

{

if ((items == null) || (items.Count == 0))

{

this.WriteCore("[]", false);

}

else

{

this.StartArrayScope();

foreach (object obj2 in items)

{

this.WriteValue(obj2);

}

this.EndScope();

}

}

public void WriteValue(IDictionary record)

{

if ((record == null) || (record.Count == 0))

{

this.WriteCore("{}", false);

}

else

{

this.StartObjectScope();

foreach (DictionaryEntry entry in record)

{

string key = entry.Key as string;

if (string.IsNullOrEmpty(key))

{

throw new ArgumentException("Key of unsupported type contained in Hashtable.");

}

this.WriteName(key);

this.WriteValue(entry.Value);

}

this.EndScope();

}

}

internal static readonly DateTime MinDate;

internal static readonly long MinDateTimeTicks;

// Methods

static HackJsonWriter()

{

DateTime time = new DateTime(0x7b2, 1, 1, 0, 0, 0);

MinDateTimeTicks = time.Ticks;

MinDate = new DateTime(100, 1, 1, 0, 0, 0);

}

public void WriteValue(DateTime dateTime)

{

if (dateTime <>

{

throw new ArgumentOutOfRangeException("dateTime");

}

this.WriteCore(@"\@" + (((dateTime.Ticks - HackJsonWriter.MinDateTimeTicks) / 0x2710L)).ToString(CultureInfo.InvariantCulture) + "@", true);

}

public void WriteValue(double value)

{

this.WriteCore(value.ToString(CultureInfo.InvariantCulture), false);

}

public void WriteValue(int value)

{

this.WriteCore(value.ToString(CultureInfo.InvariantCulture), false);

}

public void WriteValue(object o)

{

if (o == null)

{

this.WriteCore("null", false);

}

else if (o is bool)

{

this.WriteValue((bool)o);

}

else if (o is int)

{

this.WriteValue((int)o);

}

else if (o is float)

{

this.WriteValue((float)o);

}

else if (o is double)

{

this.WriteValue((double)o);

}

else if (o is DateTime)

{

this.WriteValue((DateTime)o);

}

else if (o is string)

{

this.WriteValue((string)o);

}

else if (o is IDictionary)

{

this.WriteValue((IDictionary)o);

}

else if (o is ICollection)

{

this.WriteValue((ICollection)o);

}

else

{

this.StartObjectScope();

foreach (PropertyDescriptor descriptor in TypeDescriptor.GetProperties(o))

{

this.WriteName(descriptor.Name);

this.WriteValue(descriptor.GetValue(o));

}

this.EndScope();

}

}

public void WriteValue(float value)

{

this.WriteCore(value.ToString(CultureInfo.InvariantCulture), false);

}

public void WriteValue(string s)

{

if (s == null)

{

this.WriteCore("null", false);

}

else

{

this.WriteCore(QuoteJScriptString(s), true);

}

}

// Nested Types

private sealed class Scope

{

// Fields

private int _objectCount;

private HackJsonWriter.ScopeType _type;

// Methods

public Scope(HackJsonWriter.ScopeType type)

{

this._type = type;

}

// Properties

public int ObjectCount

{

get

{

return this._objectCount;

}

set

{

this._objectCount = value;

}

}

public HackJsonWriter.ScopeType Type

{

get

{

return this._type;

}

}

}

private enum ScopeType

{

Array,

Object

}

}

1 comment:

  1. i suggest zipping this up because the code is completely unsuable in such way...i mean:

    public int Indent

    {

    get

    {

    return this._indentLevel;

    }

    set

    {

    if (value <>

    {

    value = 0;

    }

    and

    for (int i = 0; i <>

    {

    ...cleary the blogging app you're using is screwing up the display

    ReplyDelete