XmlRpcGenerator.cs 15 KB

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