XmlRpcGenerator.cs 15 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350
  1. /* This file is part of OpenSubtitles Handler
  2. A library that handle OpenSubtitles.org XML-RPC methods.
  3. Copyright © Ala Ibrahim Hadid 2013
  4. This program is free software: you can redistribute it and/or modify
  5. it under the terms of the GNU General Public License as published by
  6. the Free Software Foundation, either version 3 of the License, or
  7. (at your option) any later version.
  8. This program is distributed in the hope that it will be useful,
  9. but WITHOUT ANY WARRANTY; without even the implied warranty of
  10. MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
  11. GNU General Public License for more details.
  12. You should have received a copy of the GNU General Public License
  13. along with this program. If not, see <http://www.gnu.org/licenses/>.
  14. */
  15. using System;
  16. using System.Collections.Generic;
  17. using System.Globalization;
  18. using System.IO;
  19. using System.Text;
  20. using System.Xml;
  21. using OpenSubtitlesHandler;
  22. namespace XmlRpcHandler
  23. {
  24. /// <summary>
  25. /// A class for making XML-RPC requests. The requests then can be sent directly as http request.
  26. /// </summary>
  27. public class XmlRpcGenerator
  28. {
  29. /// <summary>
  30. /// Generate XML-RPC request using method call.
  31. /// </summary>
  32. /// <param name="method">The method call</param>
  33. /// <returns>The request in xml.</returns>
  34. public static byte[] Generate(XmlRpcMethodCall method)
  35. { return Generate(new XmlRpcMethodCall[] { method }); }
  36. /// <summary>
  37. /// Generate XML-RPC request using method calls array.
  38. /// </summary>
  39. /// <param name="methods">The method calls array</param>
  40. /// <returns>The request in utf8 xml string as buffer</returns>
  41. public static byte[] Generate(XmlRpcMethodCall[] methods)
  42. {
  43. if (methods == null)
  44. throw new Exception("No method to write !");
  45. if (methods.Length == 0)
  46. throw new Exception("No method to write !");
  47. // Create xml
  48. var sett = new XmlWriterSettings();
  49. sett.Indent = true;
  50. sett.Encoding = Encoding.UTF8;
  51. using (var ms = new MemoryStream())
  52. {
  53. using (var XMLwrt = XmlWriter.Create(ms, sett))
  54. {
  55. // Let's write the methods
  56. foreach (XmlRpcMethodCall method in methods)
  57. {
  58. XMLwrt.WriteStartElement("methodCall");//methodCall
  59. XMLwrt.WriteStartElement("methodName");//methodName
  60. XMLwrt.WriteString(method.Name);
  61. XMLwrt.WriteEndElement();//methodName
  62. XMLwrt.WriteStartElement("params");//params
  63. // Write values
  64. foreach (IXmlRpcValue p in method.Parameters)
  65. {
  66. XMLwrt.WriteStartElement("param");//param
  67. if (p is XmlRpcValueBasic)
  68. {
  69. WriteBasicValue(XMLwrt, (XmlRpcValueBasic)p);
  70. }
  71. else if (p is XmlRpcValueStruct)
  72. {
  73. WriteStructValue(XMLwrt, (XmlRpcValueStruct)p);
  74. }
  75. else if (p is XmlRpcValueArray)
  76. {
  77. WriteArrayValue(XMLwrt, (XmlRpcValueArray)p);
  78. }
  79. XMLwrt.WriteEndElement();//param
  80. }
  81. XMLwrt.WriteEndElement();//params
  82. XMLwrt.WriteEndElement();//methodCall
  83. }
  84. XMLwrt.Flush();
  85. return ms.ToArray();
  86. }
  87. }
  88. }
  89. /// <summary>
  90. /// Decode response then return the values
  91. /// </summary>
  92. /// <param name="xmlResponse">The response xml string as provided by server as methodResponse</param>
  93. /// <returns></returns>
  94. public static XmlRpcMethodCall[] DecodeMethodResponse(string xmlResponse)
  95. {
  96. var methods = new List<XmlRpcMethodCall>();
  97. var sett = new XmlReaderSettings();
  98. sett.DtdProcessing = DtdProcessing.Ignore;
  99. sett.IgnoreWhitespace = true;
  100. MemoryStream str;
  101. if (xmlResponse.Contains(@"encoding=""utf-8"""))
  102. {
  103. str = new MemoryStream(Encoding.UTF8.GetBytes(xmlResponse));
  104. }
  105. else
  106. {
  107. str = new MemoryStream(Utilities.GetASCIIBytes(xmlResponse));
  108. }
  109. using (str)
  110. {
  111. using (var XMLread = XmlReader.Create(str, sett))
  112. {
  113. var call = new XmlRpcMethodCall("methodResponse");
  114. // Read parameters
  115. while (XMLread.Read())
  116. {
  117. if (XMLread.Name == "param" && XMLread.IsStartElement())
  118. {
  119. IXmlRpcValue val = ReadValue(XMLread);
  120. if (val != null)
  121. call.Parameters.Add(val);
  122. }
  123. }
  124. methods.Add(call);
  125. return methods.ToArray();
  126. }
  127. }
  128. }
  129. private static void WriteBasicValue(XmlWriter XMLwrt, XmlRpcValueBasic val)
  130. {
  131. XMLwrt.WriteStartElement("value");//value
  132. switch (val.ValueType)
  133. {
  134. case XmlRpcBasicValueType.String:
  135. XMLwrt.WriteStartElement("string");
  136. if (val.Data != null)
  137. XMLwrt.WriteString(val.Data.ToString());
  138. XMLwrt.WriteEndElement();
  139. break;
  140. case XmlRpcBasicValueType.Int:
  141. XMLwrt.WriteStartElement("int");
  142. if (val.Data != null)
  143. XMLwrt.WriteString(val.Data.ToString());
  144. XMLwrt.WriteEndElement();
  145. break;
  146. case XmlRpcBasicValueType.Boolean:
  147. XMLwrt.WriteStartElement("boolean");
  148. if (val.Data != null)
  149. XMLwrt.WriteString(((bool)val.Data) ? "1" : "0");
  150. XMLwrt.WriteEndElement();
  151. break;
  152. case XmlRpcBasicValueType.Double:
  153. XMLwrt.WriteStartElement("double");
  154. if (val.Data != null)
  155. XMLwrt.WriteString(val.Data.ToString());
  156. XMLwrt.WriteEndElement();
  157. break;
  158. case XmlRpcBasicValueType.dateTime_iso8601:
  159. XMLwrt.WriteStartElement("dateTime.iso8601");
  160. // Get date time format
  161. if (val.Data != null)
  162. {
  163. var time = (DateTime)val.Data;
  164. string dt = time.Year + time.Month.ToString("D2") + time.Day.ToString("D2") +
  165. "T" + time.Hour.ToString("D2") + ":" + time.Minute.ToString("D2") + ":" +
  166. time.Second.ToString("D2");
  167. XMLwrt.WriteString(dt);
  168. }
  169. XMLwrt.WriteEndElement();
  170. break;
  171. case XmlRpcBasicValueType.base64:
  172. XMLwrt.WriteStartElement("base64");
  173. if (val.Data != null)
  174. XMLwrt.WriteString(Convert.ToBase64String(BitConverter.GetBytes((long)val.Data)));
  175. XMLwrt.WriteEndElement();
  176. break;
  177. }
  178. XMLwrt.WriteEndElement();//value
  179. }
  180. private static void WriteStructValue(XmlWriter XMLwrt, XmlRpcValueStruct val)
  181. {
  182. XMLwrt.WriteStartElement("value");//value
  183. XMLwrt.WriteStartElement("struct");//struct
  184. foreach (XmlRpcStructMember member in val.Members)
  185. {
  186. XMLwrt.WriteStartElement("member");//member
  187. XMLwrt.WriteStartElement("name");//name
  188. XMLwrt.WriteString(member.Name);
  189. XMLwrt.WriteEndElement();//name
  190. if (member.Data is XmlRpcValueBasic)
  191. {
  192. WriteBasicValue(XMLwrt, (XmlRpcValueBasic)member.Data);
  193. }
  194. else if (member.Data is XmlRpcValueStruct)
  195. {
  196. WriteStructValue(XMLwrt, (XmlRpcValueStruct)member.Data);
  197. }
  198. else if (member.Data is XmlRpcValueArray)
  199. {
  200. WriteArrayValue(XMLwrt, (XmlRpcValueArray)member.Data);
  201. }
  202. XMLwrt.WriteEndElement();//member
  203. }
  204. XMLwrt.WriteEndElement();//struct
  205. XMLwrt.WriteEndElement();//value
  206. }
  207. private static void WriteArrayValue(XmlWriter XMLwrt, XmlRpcValueArray val)
  208. {
  209. XMLwrt.WriteStartElement("value");//value
  210. XMLwrt.WriteStartElement("array");//array
  211. XMLwrt.WriteStartElement("data");//data
  212. foreach (IXmlRpcValue o in val.Values)
  213. {
  214. if (o is XmlRpcValueBasic)
  215. {
  216. WriteBasicValue(XMLwrt, (XmlRpcValueBasic)o);
  217. }
  218. else if (o is XmlRpcValueStruct)
  219. {
  220. WriteStructValue(XMLwrt, (XmlRpcValueStruct)o);
  221. }
  222. else if (o is XmlRpcValueArray)
  223. {
  224. WriteArrayValue(XMLwrt, (XmlRpcValueArray)o);
  225. }
  226. }
  227. XMLwrt.WriteEndElement();//data
  228. XMLwrt.WriteEndElement();//array
  229. XMLwrt.WriteEndElement();//value
  230. }
  231. private static readonly CultureInfo UsCulture = new CultureInfo("en-US");
  232. private static string ReadString(XmlReader reader)
  233. {
  234. if (reader.NodeType == XmlNodeType.Element)
  235. {
  236. return reader.ReadElementContentAsString();
  237. }
  238. return reader.ReadContentAsString();
  239. }
  240. private static IXmlRpcValue ReadValue(XmlReader xmlReader, bool skipRead = false)
  241. {
  242. while (skipRead || xmlReader.Read())
  243. {
  244. if (xmlReader.Name == "value" && xmlReader.IsStartElement())
  245. {
  246. xmlReader.Read();
  247. if (xmlReader.Name == "string" && xmlReader.IsStartElement())
  248. {
  249. return new XmlRpcValueBasic(ReadString(xmlReader), XmlRpcBasicValueType.String);
  250. }
  251. else if (xmlReader.Name == "int" && xmlReader.IsStartElement())
  252. {
  253. return new XmlRpcValueBasic(int.Parse(ReadString(xmlReader), UsCulture), XmlRpcBasicValueType.Int);
  254. }
  255. else if (xmlReader.Name == "boolean" && xmlReader.IsStartElement())
  256. {
  257. return new XmlRpcValueBasic(ReadString(xmlReader) == "1", XmlRpcBasicValueType.Boolean);
  258. }
  259. else if (xmlReader.Name == "double" && xmlReader.IsStartElement())
  260. {
  261. return new XmlRpcValueBasic(double.Parse(ReadString(xmlReader), UsCulture), XmlRpcBasicValueType.Double);
  262. }
  263. else if (xmlReader.Name == "dateTime.iso8601" && xmlReader.IsStartElement())
  264. {
  265. string date = ReadString(xmlReader);
  266. int year = int.Parse(date.Substring(0, 4), UsCulture);
  267. int month = int.Parse(date.Substring(4, 2), UsCulture);
  268. int day = int.Parse(date.Substring(6, 2), UsCulture);
  269. int hour = int.Parse(date.Substring(9, 2), UsCulture);
  270. int minute = int.Parse(date.Substring(12, 2), UsCulture);//19980717T14:08:55
  271. int sec = int.Parse(date.Substring(15, 2), UsCulture);
  272. var time = new DateTime(year, month, day, hour, minute, sec);
  273. return new XmlRpcValueBasic(time, XmlRpcBasicValueType.dateTime_iso8601);
  274. }
  275. else if (xmlReader.Name == "base64" && xmlReader.IsStartElement())
  276. {
  277. return new XmlRpcValueBasic(BitConverter.ToInt64(Convert.FromBase64String(ReadString(xmlReader)), 0)
  278. , XmlRpcBasicValueType.Double);
  279. }
  280. else if (xmlReader.Name == "struct" && xmlReader.IsStartElement())
  281. {
  282. var strct = new XmlRpcValueStruct(new List<XmlRpcStructMember>());
  283. // Read members...
  284. while (xmlReader.Read())
  285. {
  286. if (xmlReader.Name == "member" && xmlReader.IsStartElement())
  287. {
  288. var member = new XmlRpcStructMember("", null);
  289. xmlReader.Read();// read name
  290. member.Name = ReadString(xmlReader);
  291. IXmlRpcValue val = ReadValue(xmlReader, true);
  292. if (val != null)
  293. {
  294. member.Data = val;
  295. strct.Members.Add(member);
  296. }
  297. }
  298. else if (xmlReader.Name == "struct" && !xmlReader.IsStartElement())
  299. {
  300. return strct;
  301. }
  302. }
  303. return strct;
  304. }
  305. else if (xmlReader.Name == "array" && xmlReader.IsStartElement())
  306. {
  307. var array = new XmlRpcValueArray();
  308. // Read members...
  309. while (xmlReader.Read())
  310. {
  311. if (xmlReader.Name == "array" && !xmlReader.IsStartElement())
  312. {
  313. return array;
  314. }
  315. else
  316. {
  317. IXmlRpcValue val = ReadValue(xmlReader);
  318. if (val != null)
  319. array.Values.Add(val);
  320. }
  321. }
  322. return array;
  323. }
  324. }
  325. else break;
  326. if (skipRead)
  327. {
  328. return null;
  329. }
  330. }
  331. return null;
  332. }
  333. }
  334. }