/* This file is part of OpenSubtitles Handler A library that handle OpenSubtitles.org XML-RPC methods. Copyright © Ala Ibrahim Hadid 2013 This program is free software: you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation, either version 3 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program. If not, see . */ using System; using System.Globalization; using System.Text; using System.Collections.Generic; using System.IO; using System.Xml; using OpenSubtitlesHandler; namespace XmlRpcHandler { /// /// A class for making XML-RPC requests. The requests then can be sent directly as http request. /// public class XmlRpcGenerator { /// /// Generate XML-RPC request using method call. /// /// The method call /// The request in xml. public static byte[] Generate(XmlRpcMethodCall method) { return Generate(new XmlRpcMethodCall[] { method }); } /// /// Generate XML-RPC request using method calls array. /// /// The method calls array /// The request in utf8 xml string as buffer public static byte[] Generate(XmlRpcMethodCall[] methods) { if (methods == null) throw new Exception("No method to write !"); if (methods.Length == 0) throw new Exception("No method to write !"); // Create xml XmlWriterSettings sett = new XmlWriterSettings(); sett.Indent = true; sett.Encoding = Encoding.UTF8; using (var ms = new MemoryStream()) { using (XmlWriter XMLwrt = XmlWriter.Create(ms, sett)) { // Let's write the methods foreach (XmlRpcMethodCall method in methods) { XMLwrt.WriteStartElement("methodCall");//methodCall XMLwrt.WriteStartElement("methodName");//methodName XMLwrt.WriteString(method.Name); XMLwrt.WriteEndElement();//methodName XMLwrt.WriteStartElement("params");//params // Write values foreach (IXmlRpcValue p in method.Parameters) { XMLwrt.WriteStartElement("param");//param if (p is XmlRpcValueBasic) { WriteBasicValue(XMLwrt, (XmlRpcValueBasic)p); } else if (p is XmlRpcValueStruct) { WriteStructValue(XMLwrt, (XmlRpcValueStruct)p); } else if (p is XmlRpcValueArray) { WriteArrayValue(XMLwrt, (XmlRpcValueArray)p); } XMLwrt.WriteEndElement();//param } XMLwrt.WriteEndElement();//params XMLwrt.WriteEndElement();//methodCall } XMLwrt.Flush(); return ms.ToArray(); } } } /// /// Decode response then return the values /// /// The response xml string as provided by server as methodResponse /// public static XmlRpcMethodCall[] DecodeMethodResponse(string xmlResponse) { List methods = new List(); XmlReaderSettings sett = new XmlReaderSettings(); sett.DtdProcessing = DtdProcessing.Ignore; sett.IgnoreWhitespace = true; MemoryStream str; if (xmlResponse.Contains(@"encoding=""utf-8""")) { str = new MemoryStream(Encoding.UTF8.GetBytes(xmlResponse)); } else { str = new MemoryStream(Utilities.GetASCIIBytes(xmlResponse)); } using (str) { using (XmlReader XMLread = XmlReader.Create(str, sett)) { XmlRpcMethodCall call = new XmlRpcMethodCall("methodResponse"); // Read parameters while (XMLread.Read()) { if (XMLread.Name == "param" && XMLread.IsStartElement()) { IXmlRpcValue val = ReadValue(XMLread); if (val != null) call.Parameters.Add(val); } } methods.Add(call); return methods.ToArray(); } } } private static void WriteBasicValue(XmlWriter XMLwrt, XmlRpcValueBasic val) { XMLwrt.WriteStartElement("value");//value switch (val.ValueType) { case XmlRpcBasicValueType.String: XMLwrt.WriteStartElement("string"); if (val.Data != null) XMLwrt.WriteString(val.Data.ToString()); XMLwrt.WriteEndElement(); break; case XmlRpcBasicValueType.Int: XMLwrt.WriteStartElement("int"); if (val.Data != null) XMLwrt.WriteString(val.Data.ToString()); XMLwrt.WriteEndElement(); break; case XmlRpcBasicValueType.Boolean: XMLwrt.WriteStartElement("boolean"); if (val.Data != null) XMLwrt.WriteString(((bool)val.Data) ? "1" : "0"); XMLwrt.WriteEndElement(); break; case XmlRpcBasicValueType.Double: XMLwrt.WriteStartElement("double"); if (val.Data != null) XMLwrt.WriteString(val.Data.ToString()); XMLwrt.WriteEndElement(); break; case XmlRpcBasicValueType.dateTime_iso8601: XMLwrt.WriteStartElement("dateTime.iso8601"); // Get date time format if (val.Data != null) { DateTime time = (DateTime)val.Data; string dt = time.Year + time.Month.ToString("D2") + time.Day.ToString("D2") + "T" + time.Hour.ToString("D2") + ":" + time.Minute.ToString("D2") + ":" + time.Second.ToString("D2"); XMLwrt.WriteString(dt); } XMLwrt.WriteEndElement(); break; case XmlRpcBasicValueType.base64: XMLwrt.WriteStartElement("base64"); if (val.Data != null) XMLwrt.WriteString(Convert.ToBase64String(BitConverter.GetBytes((long)val.Data))); XMLwrt.WriteEndElement(); break; } XMLwrt.WriteEndElement();//value } private static void WriteStructValue(XmlWriter XMLwrt, XmlRpcValueStruct val) { XMLwrt.WriteStartElement("value");//value XMLwrt.WriteStartElement("struct");//struct foreach (XmlRpcStructMember member in val.Members) { XMLwrt.WriteStartElement("member");//member XMLwrt.WriteStartElement("name");//name XMLwrt.WriteString(member.Name); XMLwrt.WriteEndElement();//name if (member.Data is XmlRpcValueBasic) { WriteBasicValue(XMLwrt, (XmlRpcValueBasic)member.Data); } else if (member.Data is XmlRpcValueStruct) { WriteStructValue(XMLwrt, (XmlRpcValueStruct)member.Data); } else if (member.Data is XmlRpcValueArray) { WriteArrayValue(XMLwrt, (XmlRpcValueArray)member.Data); } XMLwrt.WriteEndElement();//member } XMLwrt.WriteEndElement();//struct XMLwrt.WriteEndElement();//value } private static void WriteArrayValue(XmlWriter XMLwrt, XmlRpcValueArray val) { XMLwrt.WriteStartElement("value");//value XMLwrt.WriteStartElement("array");//array XMLwrt.WriteStartElement("data");//data foreach (IXmlRpcValue o in val.Values) { if (o is XmlRpcValueBasic) { WriteBasicValue(XMLwrt, (XmlRpcValueBasic)o); } else if (o is XmlRpcValueStruct) { WriteStructValue(XMLwrt, (XmlRpcValueStruct)o); } else if (o is XmlRpcValueArray) { WriteArrayValue(XMLwrt, (XmlRpcValueArray)o); } } XMLwrt.WriteEndElement();//data XMLwrt.WriteEndElement();//array XMLwrt.WriteEndElement();//value } private static readonly CultureInfo UsCulture = new CultureInfo("en-US"); private static string ReadString(XmlReader reader) { if (reader.NodeType == XmlNodeType.Element) { return reader.ReadElementContentAsString(); } return reader.ReadContentAsString(); } private static IXmlRpcValue ReadValue(XmlReader xmlReader, bool skipRead = false) { while (skipRead || xmlReader.Read()) { if (xmlReader.Name == "value" && xmlReader.IsStartElement()) { xmlReader.Read(); if (xmlReader.Name == "string" && xmlReader.IsStartElement()) { return new XmlRpcValueBasic(ReadString(xmlReader), XmlRpcBasicValueType.String); } else if (xmlReader.Name == "int" && xmlReader.IsStartElement()) { return new XmlRpcValueBasic(int.Parse(ReadString(xmlReader), UsCulture), XmlRpcBasicValueType.Int); } else if (xmlReader.Name == "boolean" && xmlReader.IsStartElement()) { return new XmlRpcValueBasic(ReadString(xmlReader) == "1", XmlRpcBasicValueType.Boolean); } else if (xmlReader.Name == "double" && xmlReader.IsStartElement()) { return new XmlRpcValueBasic(double.Parse(ReadString(xmlReader), UsCulture), XmlRpcBasicValueType.Double); } else if (xmlReader.Name == "dateTime.iso8601" && xmlReader.IsStartElement()) { string date = ReadString(xmlReader); int year = int.Parse(date.Substring(0, 4), UsCulture); int month = int.Parse(date.Substring(4, 2), UsCulture); int day = int.Parse(date.Substring(6, 2), UsCulture); int hour = int.Parse(date.Substring(9, 2), UsCulture); int minute = int.Parse(date.Substring(12, 2), UsCulture);//19980717T14:08:55 int sec = int.Parse(date.Substring(15, 2), UsCulture); DateTime time = new DateTime(year, month, day, hour, minute, sec); return new XmlRpcValueBasic(time, XmlRpcBasicValueType.dateTime_iso8601); } else if (xmlReader.Name == "base64" && xmlReader.IsStartElement()) { return new XmlRpcValueBasic(BitConverter.ToInt64(Convert.FromBase64String(ReadString(xmlReader)), 0) , XmlRpcBasicValueType.Double); } else if (xmlReader.Name == "struct" && xmlReader.IsStartElement()) { XmlRpcValueStruct strct = new XmlRpcValueStruct(new List()); // Read members... while (xmlReader.Read()) { if (xmlReader.Name == "member" && xmlReader.IsStartElement()) { XmlRpcStructMember member = new XmlRpcStructMember("", null); xmlReader.Read();// read name member.Name = ReadString(xmlReader); IXmlRpcValue val = ReadValue(xmlReader, true); if (val != null) { member.Data = val; strct.Members.Add(member); } } else if (xmlReader.Name == "struct" && !xmlReader.IsStartElement()) { return strct; } } return strct; } else if (xmlReader.Name == "array" && xmlReader.IsStartElement()) { XmlRpcValueArray array = new XmlRpcValueArray(); // Read members... while (xmlReader.Read()) { if (xmlReader.Name == "array" && !xmlReader.IsStartElement()) { return array; } else { IXmlRpcValue val = ReadValue(xmlReader); if (val != null) array.Values.Add(val); } } return array; } } else break; if (skipRead) { return null; } } return null; } } }