XmlRpcGenerator.cs 14 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328
  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. var requestXmlPath = Path.Combine(Path.GetTempPath(), "request.xml");
  50. sett.Encoding = Encoding.UTF8;
  51. FileStream str = new FileStream(requestXmlPath, FileMode.Create, FileAccess.Write);
  52. XmlWriter XMLwrt = XmlWriter.Create(str, 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. str.Close();
  85. string requestContent = File.ReadAllText(requestXmlPath);
  86. return Encoding.UTF8.GetBytes(requestContent);
  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. XmlReader XMLread = XmlReader.Create(str, sett);
  105. XmlRpcMethodCall call = new XmlRpcMethodCall("methodResponse");
  106. // Read parameters
  107. while (XMLread.Read())
  108. {
  109. if (XMLread.Name == "param" && XMLread.IsStartElement())
  110. {
  111. IXmlRpcValue val = ReadValue(XMLread);
  112. if (val != null)
  113. call.Parameters.Add(val);
  114. }
  115. }
  116. methods.Add(call);
  117. XMLread.Close();
  118. return methods.ToArray();
  119. }
  120. private static void WriteBasicValue(XmlWriter XMLwrt, XmlRpcValueBasic val)
  121. {
  122. XMLwrt.WriteStartElement("value");//value
  123. switch (val.ValueType)
  124. {
  125. case XmlRpcBasicValueType.String:
  126. XMLwrt.WriteStartElement("string");
  127. if (val.Data != null)
  128. XMLwrt.WriteString(val.Data.ToString());
  129. XMLwrt.WriteEndElement();
  130. break;
  131. case XmlRpcBasicValueType.Int:
  132. XMLwrt.WriteStartElement("int");
  133. if (val.Data != null)
  134. XMLwrt.WriteString(val.Data.ToString());
  135. XMLwrt.WriteEndElement();
  136. break;
  137. case XmlRpcBasicValueType.Boolean:
  138. XMLwrt.WriteStartElement("boolean");
  139. if (val.Data != null)
  140. XMLwrt.WriteString(((bool)val.Data) ? "1" : "0");
  141. XMLwrt.WriteEndElement();
  142. break;
  143. case XmlRpcBasicValueType.Double:
  144. XMLwrt.WriteStartElement("double");
  145. if (val.Data != null)
  146. XMLwrt.WriteString(val.Data.ToString());
  147. XMLwrt.WriteEndElement();
  148. break;
  149. case XmlRpcBasicValueType.dateTime_iso8601:
  150. XMLwrt.WriteStartElement("dateTime.iso8601");
  151. // Get date time format
  152. if (val.Data != null)
  153. {
  154. DateTime time = (DateTime)val.Data;
  155. string dt = time.Year + time.Month.ToString("D2") + time.Day.ToString("D2") +
  156. "T" + time.Hour.ToString("D2") + ":" + time.Minute.ToString("D2") + ":" +
  157. time.Second.ToString("D2");
  158. XMLwrt.WriteString(dt);
  159. }
  160. XMLwrt.WriteEndElement();
  161. break;
  162. case XmlRpcBasicValueType.base64:
  163. XMLwrt.WriteStartElement("base64");
  164. if (val.Data != null)
  165. XMLwrt.WriteString(Convert.ToBase64String(BitConverter.GetBytes((long)val.Data)));
  166. XMLwrt.WriteEndElement();
  167. break;
  168. }
  169. XMLwrt.WriteEndElement();//value
  170. }
  171. private static void WriteStructValue(XmlWriter XMLwrt, XmlRpcValueStruct val)
  172. {
  173. XMLwrt.WriteStartElement("value");//value
  174. XMLwrt.WriteStartElement("struct");//struct
  175. foreach (XmlRpcStructMember member in val.Members)
  176. {
  177. XMLwrt.WriteStartElement("member");//member
  178. XMLwrt.WriteStartElement("name");//name
  179. XMLwrt.WriteString(member.Name);
  180. XMLwrt.WriteEndElement();//name
  181. if (member.Data is XmlRpcValueBasic)
  182. {
  183. WriteBasicValue(XMLwrt, (XmlRpcValueBasic)member.Data);
  184. }
  185. else if (member.Data is XmlRpcValueStruct)
  186. {
  187. WriteStructValue(XMLwrt, (XmlRpcValueStruct)member.Data);
  188. }
  189. else if (member.Data is XmlRpcValueArray)
  190. {
  191. WriteArrayValue(XMLwrt, (XmlRpcValueArray)member.Data);
  192. }
  193. XMLwrt.WriteEndElement();//member
  194. }
  195. XMLwrt.WriteEndElement();//struct
  196. XMLwrt.WriteEndElement();//value
  197. }
  198. private static void WriteArrayValue(XmlWriter XMLwrt, XmlRpcValueArray val)
  199. {
  200. XMLwrt.WriteStartElement("value");//value
  201. XMLwrt.WriteStartElement("array");//array
  202. XMLwrt.WriteStartElement("data");//data
  203. foreach (IXmlRpcValue o in val.Values)
  204. {
  205. if (o is XmlRpcValueBasic)
  206. {
  207. WriteBasicValue(XMLwrt, (XmlRpcValueBasic)o);
  208. }
  209. else if (o is XmlRpcValueStruct)
  210. {
  211. WriteStructValue(XMLwrt, (XmlRpcValueStruct)o);
  212. }
  213. else if (o is XmlRpcValueArray)
  214. {
  215. WriteArrayValue(XMLwrt, (XmlRpcValueArray)o);
  216. }
  217. }
  218. XMLwrt.WriteEndElement();//data
  219. XMLwrt.WriteEndElement();//array
  220. XMLwrt.WriteEndElement();//value
  221. }
  222. private static readonly CultureInfo UsCulture = new CultureInfo("en-US");
  223. private static IXmlRpcValue ReadValue(XmlReader xmlReader)
  224. {
  225. while (xmlReader.Read())
  226. {
  227. if (xmlReader.Name == "value" && xmlReader.IsStartElement())
  228. {
  229. xmlReader.Read();
  230. if (xmlReader.Name == "string" && xmlReader.IsStartElement())
  231. {
  232. return new XmlRpcValueBasic(xmlReader.ReadString(), XmlRpcBasicValueType.String);
  233. }
  234. else if (xmlReader.Name == "int" && xmlReader.IsStartElement())
  235. {
  236. return new XmlRpcValueBasic(int.Parse(xmlReader.ReadString(), UsCulture), XmlRpcBasicValueType.Int);
  237. }
  238. else if (xmlReader.Name == "boolean" && xmlReader.IsStartElement())
  239. {
  240. return new XmlRpcValueBasic(xmlReader.ReadString() == "1", XmlRpcBasicValueType.Boolean);
  241. }
  242. else if (xmlReader.Name == "double" && xmlReader.IsStartElement())
  243. {
  244. return new XmlRpcValueBasic(double.Parse(xmlReader.ReadString(), UsCulture), XmlRpcBasicValueType.Double);
  245. }
  246. else if (xmlReader.Name == "dateTime.iso8601" && xmlReader.IsStartElement())
  247. {
  248. string date = xmlReader.ReadString();
  249. int year = int.Parse(date.Substring(0, 4), UsCulture);
  250. int month = int.Parse(date.Substring(4, 2), UsCulture);
  251. int day = int.Parse(date.Substring(6, 2), UsCulture);
  252. int hour = int.Parse(date.Substring(9, 2), UsCulture);
  253. int minute = int.Parse(date.Substring(12, 2), UsCulture);//19980717T14:08:55
  254. int sec = int.Parse(date.Substring(15, 2), UsCulture);
  255. DateTime time = new DateTime(year, month, day, hour, minute, sec);
  256. return new XmlRpcValueBasic(time, XmlRpcBasicValueType.dateTime_iso8601);
  257. }
  258. else if (xmlReader.Name == "base64" && xmlReader.IsStartElement())
  259. {
  260. return new XmlRpcValueBasic(BitConverter.ToInt64(Convert.FromBase64String(xmlReader.ReadString()), 0)
  261. , XmlRpcBasicValueType.Double);
  262. }
  263. else if (xmlReader.Name == "struct" && xmlReader.IsStartElement())
  264. {
  265. XmlRpcValueStruct strct = new XmlRpcValueStruct(new List<XmlRpcStructMember>());
  266. // Read members...
  267. while (xmlReader.Read())
  268. {
  269. if (xmlReader.Name == "member" && xmlReader.IsStartElement())
  270. {
  271. XmlRpcStructMember member = new XmlRpcStructMember("", null);
  272. xmlReader.Read();// read name
  273. member.Name = xmlReader.ReadString();
  274. IXmlRpcValue val = ReadValue(xmlReader);
  275. if (val != null)
  276. {
  277. member.Data = val;
  278. strct.Members.Add(member);
  279. }
  280. }
  281. else if (xmlReader.Name == "struct" && !xmlReader.IsStartElement())
  282. {
  283. return strct;
  284. }
  285. }
  286. return strct;
  287. }
  288. else if (xmlReader.Name == "array" && xmlReader.IsStartElement())
  289. {
  290. XmlRpcValueArray array = new XmlRpcValueArray();
  291. // Read members...
  292. while (xmlReader.Read())
  293. {
  294. if (xmlReader.Name == "array" && !xmlReader.IsStartElement())
  295. {
  296. return array;
  297. }
  298. else
  299. {
  300. IXmlRpcValue val = ReadValue(xmlReader);
  301. if (val != null)
  302. array.Values.Add(val);
  303. }
  304. }
  305. return array;
  306. }
  307. }
  308. else break;
  309. }
  310. return null;
  311. }
  312. }
  313. }