XmlRpcGenerator.cs 14 KB

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