XmlRpcGenerator.cs 14 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327
  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 IXmlRpcValue ReadValue(XmlReader xmlReader)
  225. {
  226. while (xmlReader.Read())
  227. {
  228. if (xmlReader.Name == "value" && xmlReader.IsStartElement())
  229. {
  230. xmlReader.Read();
  231. if (xmlReader.Name == "string" && xmlReader.IsStartElement())
  232. {
  233. return new XmlRpcValueBasic(xmlReader.ReadString(), XmlRpcBasicValueType.String);
  234. }
  235. else if (xmlReader.Name == "int" && xmlReader.IsStartElement())
  236. {
  237. return new XmlRpcValueBasic(int.Parse(xmlReader.ReadString(), UsCulture), XmlRpcBasicValueType.Int);
  238. }
  239. else if (xmlReader.Name == "boolean" && xmlReader.IsStartElement())
  240. {
  241. return new XmlRpcValueBasic(xmlReader.ReadString() == "1", XmlRpcBasicValueType.Boolean);
  242. }
  243. else if (xmlReader.Name == "double" && xmlReader.IsStartElement())
  244. {
  245. return new XmlRpcValueBasic(double.Parse(xmlReader.ReadString(), UsCulture), XmlRpcBasicValueType.Double);
  246. }
  247. else if (xmlReader.Name == "dateTime.iso8601" && xmlReader.IsStartElement())
  248. {
  249. string date = xmlReader.ReadString();
  250. int year = int.Parse(date.Substring(0, 4), UsCulture);
  251. int month = int.Parse(date.Substring(4, 2), UsCulture);
  252. int day = int.Parse(date.Substring(6, 2), UsCulture);
  253. int hour = int.Parse(date.Substring(9, 2), UsCulture);
  254. int minute = int.Parse(date.Substring(12, 2), UsCulture);//19980717T14:08:55
  255. int sec = int.Parse(date.Substring(15, 2), UsCulture);
  256. DateTime time = new DateTime(year, month, day, hour, minute, sec);
  257. return new XmlRpcValueBasic(time, XmlRpcBasicValueType.dateTime_iso8601);
  258. }
  259. else if (xmlReader.Name == "base64" && xmlReader.IsStartElement())
  260. {
  261. return new XmlRpcValueBasic(BitConverter.ToInt64(Convert.FromBase64String(xmlReader.ReadString()), 0)
  262. , XmlRpcBasicValueType.Double);
  263. }
  264. else if (xmlReader.Name == "struct" && xmlReader.IsStartElement())
  265. {
  266. XmlRpcValueStruct strct = new XmlRpcValueStruct(new List<XmlRpcStructMember>());
  267. // Read members...
  268. while (xmlReader.Read())
  269. {
  270. if (xmlReader.Name == "member" && xmlReader.IsStartElement())
  271. {
  272. XmlRpcStructMember member = new XmlRpcStructMember("", null);
  273. xmlReader.Read();// read name
  274. member.Name = xmlReader.ReadString();
  275. IXmlRpcValue val = ReadValue(xmlReader);
  276. if (val != null)
  277. {
  278. member.Data = val;
  279. strct.Members.Add(member);
  280. }
  281. }
  282. else if (xmlReader.Name == "struct" && !xmlReader.IsStartElement())
  283. {
  284. return strct;
  285. }
  286. }
  287. return strct;
  288. }
  289. else if (xmlReader.Name == "array" && xmlReader.IsStartElement())
  290. {
  291. XmlRpcValueArray array = new XmlRpcValueArray();
  292. // Read members...
  293. while (xmlReader.Read())
  294. {
  295. if (xmlReader.Name == "array" && !xmlReader.IsStartElement())
  296. {
  297. return array;
  298. }
  299. else
  300. {
  301. IXmlRpcValue val = ReadValue(xmlReader);
  302. if (val != null)
  303. array.Values.Add(val);
  304. }
  305. }
  306. return array;
  307. }
  308. }
  309. else break;
  310. }
  311. return null;
  312. }
  313. }
  314. }