using System;
using System.Collections.Generic;
using System.Linq;
using System.Runtime.Serialization;
using System.Text;
using System.Xml;
namespace DotNetOAuth {
///
/// Serializes/deserializes OAuth messages for/from transit.
///
internal class ProtocolMessageSerializer where T : IProtocolMessage {
DataContractSerializer serializer;
const string rootName = "root";
internal ProtocolMessageSerializer() {
serializer = new DataContractSerializer(typeof(T), rootName, Protocol.DataContractNamespace);
}
///
/// Reads the data from a message instance and returns a series of name=value pairs for the fields that must be included in the message.
///
/// The message to be serialized.
internal IDictionary Serialize(T message) {
if (message == null) throw new ArgumentNullException("message");
var fields = new Dictionary();
XmlWriter writer = new ProtocolMessageSerializer.PseudoXmlWriter(fields);
serializer.WriteObjectContent(writer, message);
writer.Close();
return fields;
}
///
/// Reads name=value pairs into an OAuth message.
///
/// The name=value pairs that were read in from the transport.
internal T Deserialize(IDictionary fields) {
if (fields == null) throw new ArgumentNullException("fields");
var reader = new PseudoXmlReader(fields);
//var reader = new XmlTextReader(new StringReader("Andrew15"));
T result = (T)serializer.ReadObject(reader, false);
return result;
}
///
/// Writes out a dictionary as if it were XML.
///
class PseudoXmlWriter : XmlWriter {
Dictionary dictionary;
string key;
StringBuilder value = new StringBuilder();
internal PseudoXmlWriter(Dictionary dictionary) {
this.dictionary = dictionary;
}
public override void WriteStartElement(string prefix, string localName, string ns) {
key = localName;
value.Length = 0;
}
public override void WriteString(string text) {
if (!string.IsNullOrEmpty(key)) {
value.Append(text);
}
}
public override void WriteEndElement() {
if (key != null) {
dictionary[key] = value.ToString();
key = null;
value.Length = 0;
}
}
public override WriteState WriteState {
get { return WriteState.Element; }
}
public override void WriteStartAttribute(string prefix, string localName, string ns) {
key = null;
}
public override void WriteEndAttribute() { }
public override void Close() { }
#region Unimplemented methods
public override void Flush() {
throw new NotImplementedException();
}
public override string LookupPrefix(string ns) {
throw new NotImplementedException();
}
public override void WriteBase64(byte[] buffer, int index, int count) {
throw new NotImplementedException();
}
public override void WriteCData(string text) {
throw new NotImplementedException();
}
public override void WriteCharEntity(char ch) {
throw new NotImplementedException();
}
public override void WriteChars(char[] buffer, int index, int count) {
throw new NotImplementedException();
}
public override void WriteComment(string text) {
throw new NotImplementedException();
}
public override void WriteDocType(string name, string pubid, string sysid, string subset) {
throw new NotImplementedException();
}
public override void WriteEndDocument() {
throw new NotImplementedException();
}
public override void WriteEntityRef(string name) {
throw new NotImplementedException();
}
public override void WriteFullEndElement() {
throw new NotImplementedException();
}
public override void WriteProcessingInstruction(string name, string text) {
throw new NotImplementedException();
}
public override void WriteRaw(string data) {
throw new NotImplementedException();
}
public override void WriteRaw(char[] buffer, int index, int count) {
throw new NotImplementedException();
}
public override void WriteStartDocument(bool standalone) {
throw new NotImplementedException();
}
public override void WriteStartDocument() {
throw new NotImplementedException();
}
public override void WriteSurrogateCharEntity(char lowChar, char highChar) {
throw new NotImplementedException();
}
public override void WriteWhitespace(string ws) {
throw new NotImplementedException();
}
#endregion
}
///
/// Reads in a dictionary as if it were XML.
///
class PseudoXmlReader : XmlReader {
IDictionary dictionary;
IEnumerator keyEnumerator;
bool isFinished;
int depth;
XmlNodeType currentNode = XmlNodeType.None;
internal PseudoXmlReader(IDictionary dictionary) {
this.dictionary = dictionary;
keyEnumerator = dictionary.Keys.OrderBy(key => key, StringComparer.Ordinal).GetEnumerator();
}
public override int AttributeCount {
get { return 0; }
}
public override bool IsEmptyElement {
get {
if (keyEnumerator.Current == null) {
return isFinished;
}
string value;
bool result = !dictionary.TryGetValue(keyEnumerator.Current, out value) || String.IsNullOrEmpty(value);
return result;
}
}
public override string LocalName {
get { return keyEnumerator.Current; }
}
public override bool MoveToElement() {
bool result = currentNode != XmlNodeType.Element && depth > 0;
currentNode = depth > 0 ? XmlNodeType.Element : XmlNodeType.None;
return result;
}
public override bool MoveToNextAttribute() {
if (depth == 1 && currentNode != XmlNodeType.Attribute) {
currentNode = XmlNodeType.Attribute;
return true;
} else {
return false;
}
}
public override string NamespaceURI {
get {
string result = depth == 1 && currentNode == XmlNodeType.Attribute ?
"http://www.w3.org/2000/xmlns/" : Protocol.DataContractNamespace;
return result;
}
}
public override XmlNodeType NodeType {
get { return currentNode; }
}
public override bool Read() {
if (isFinished) {
if (depth > 0) {
depth--;
}
return depth > 0;
}
switch (depth) {
case 0: // moving to root node
depth++; // -> 1
currentNode = XmlNodeType.Element;
return true;
case 1: // moving to first content node
depth++; // -> 2
isFinished = !keyEnumerator.MoveNext();
currentNode = isFinished ? XmlNodeType.EndElement : XmlNodeType.Element;
return true;
case 2: // content node
switch (currentNode) {
case XmlNodeType.Element:
currentNode = XmlNodeType.Text;
return true;
case XmlNodeType.Text:
currentNode = XmlNodeType.EndElement;
return true;
case XmlNodeType.EndElement:
bool result = keyEnumerator.MoveNext();
if (!result) {
isFinished = true;
depth--;
currentNode = XmlNodeType.EndElement;
} else {
currentNode = XmlNodeType.Element;
}
return true;
}
break;
}
throw new InvalidOperationException();
}
public override string Value {
get { return dictionary[keyEnumerator.Current]; }
}
#region Unimplemented methods
public override string BaseURI {
get { throw new NotImplementedException(); }
}
public override void Close() {
throw new NotImplementedException();
}
public override int Depth {
get { throw new NotImplementedException(); }
}
public override bool EOF {
get { throw new NotImplementedException(); }
}
public override string GetAttribute(int i) {
throw new NotImplementedException();
}
public override string GetAttribute(string name, string namespaceURI) {
throw new NotImplementedException();
}
public override string GetAttribute(string name) {
throw new NotImplementedException();
}
public override bool HasValue {
get { throw new NotImplementedException(); }
}
public override string LookupNamespace(string prefix) {
throw new NotImplementedException();
}
public override bool MoveToAttribute(string name, string ns) {
throw new NotImplementedException();
}
public override bool MoveToAttribute(string name) {
throw new NotImplementedException();
}
public override bool MoveToFirstAttribute() {
throw new NotImplementedException();
}
public override XmlNameTable NameTable {
get { throw new NotImplementedException(); }
}
public override string Prefix {
get { throw new NotImplementedException(); }
}
public override ReadState ReadState {
get { throw new NotImplementedException(); }
}
public override bool ReadAttributeValue() {
throw new NotImplementedException();
}
public override void ResolveEntity() {
throw new NotImplementedException();
}
#endregion
}
}
}