351 lines
15 KiB
C#
351 lines
15 KiB
C#
/* 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 <http://www.gnu.org/licenses/>.
|
|
*/
|
|
using System;
|
|
using System.Collections.Generic;
|
|
using System.Globalization;
|
|
using System.IO;
|
|
using System.Text;
|
|
using System.Xml;
|
|
using OpenSubtitlesHandler;
|
|
|
|
namespace XmlRpcHandler
|
|
{
|
|
/// <summary>
|
|
/// A class for making XML-RPC requests. The requests then can be sent directly as http request.
|
|
/// </summary>
|
|
public class XmlRpcGenerator
|
|
{
|
|
/// <summary>
|
|
/// Generate XML-RPC request using method call.
|
|
/// </summary>
|
|
/// <param name="method">The method call</param>
|
|
/// <returns>The request in xml.</returns>
|
|
public static byte[] Generate(XmlRpcMethodCall method)
|
|
{ return Generate(new XmlRpcMethodCall[] { method }); }
|
|
/// <summary>
|
|
/// Generate XML-RPC request using method calls array.
|
|
/// </summary>
|
|
/// <param name="methods">The method calls array</param>
|
|
/// <returns>The request in utf8 xml string as buffer</returns>
|
|
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
|
|
var sett = new XmlWriterSettings();
|
|
sett.Indent = true;
|
|
|
|
sett.Encoding = Encoding.UTF8;
|
|
|
|
using (var ms = new MemoryStream())
|
|
{
|
|
using (var XMLwrt = XmlWriter.Create(ms, sett))
|
|
{
|
|
// Let's write the methods
|
|
foreach (var 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 (var 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();
|
|
}
|
|
}
|
|
}
|
|
/// <summary>
|
|
/// Decode response then return the values
|
|
/// </summary>
|
|
/// <param name="xmlResponse">The response xml string as provided by server as methodResponse</param>
|
|
/// <returns></returns>
|
|
public static XmlRpcMethodCall[] DecodeMethodResponse(string xmlResponse)
|
|
{
|
|
var methods = new List<XmlRpcMethodCall>();
|
|
var 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 (var XMLread = XmlReader.Create(str, sett))
|
|
{
|
|
var call = new XmlRpcMethodCall("methodResponse");
|
|
// Read parameters
|
|
while (XMLread.Read())
|
|
{
|
|
if (XMLread.Name == "param" && XMLread.IsStartElement())
|
|
{
|
|
var 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)
|
|
{
|
|
var 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 (var 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 (var 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);
|
|
var 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())
|
|
{
|
|
var strct = new XmlRpcValueStruct(new List<XmlRpcStructMember>());
|
|
// Read members...
|
|
while (xmlReader.Read())
|
|
{
|
|
if (xmlReader.Name == "member" && xmlReader.IsStartElement())
|
|
{
|
|
var member = new XmlRpcStructMember("", null);
|
|
xmlReader.Read();// read name
|
|
member.Name = ReadString(xmlReader);
|
|
|
|
var 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())
|
|
{
|
|
var array = new XmlRpcValueArray();
|
|
// Read members...
|
|
while (xmlReader.Read())
|
|
{
|
|
if (xmlReader.Name == "array" && !xmlReader.IsStartElement())
|
|
{
|
|
return array;
|
|
}
|
|
else
|
|
{
|
|
var val = ReadValue(xmlReader);
|
|
if (val != null)
|
|
array.Values.Add(val);
|
|
}
|
|
}
|
|
return array;
|
|
}
|
|
}
|
|
else break;
|
|
|
|
if (skipRead)
|
|
{
|
|
return null;
|
|
}
|
|
}
|
|
return null;
|
|
}
|
|
}
|
|
}
|