XMLWriter.cpp 7.4 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272
  1. #include "Main.h"
  2. #include "Feeds.h"
  3. #include "RFCDate.h"
  4. #include "Downloaded.h"
  5. #include "../nu/AutoLock.h"
  6. #include "Defaults.h"
  7. #include "../Agave/Language/api_language.h"
  8. using namespace Nullsoft::Utility;
  9. static void XMLWriteString(FILE *fp, const wchar_t *str)
  10. {
  11. for (const wchar_t *itr = str; *itr; itr=CharNextW(itr))
  12. {
  13. switch (*itr)
  14. {
  15. case '<': fputws(L"&lt;", fp); break;
  16. case '>': fputws(L"&gt;", fp); break;
  17. case '&': fputws(L"&amp;", fp); break;
  18. case '\"': fputws(L"&quot;", fp); break;
  19. case '\'': fputws(L"&apos;", fp); break;
  20. default: fputwc(*itr, fp); break;
  21. }
  22. }
  23. }
  24. static void InstaProp(FILE *fp, const wchar_t *property, const wchar_t *value)
  25. {
  26. fwprintf(fp, L" %s=\"", property);
  27. XMLWriteString(fp, value);
  28. fputws(L"\"", fp);
  29. }
  30. static void InstaProp(FILE *fp, const wchar_t *property, int value)
  31. {
  32. fwprintf(fp, L" %s=\"%i\"", property, value);
  33. }
  34. static void InstaPropI64(FILE *fp, const wchar_t *property, int64_t value)
  35. {
  36. fwprintf(fp, L" %s=\"%I64d\"", property, value);
  37. }
  38. static void InstaPropTime(FILE *fp, const wchar_t *property, __time64_t value)
  39. {
  40. fwprintf(fp, L" %s=\"%I64u\"", property, value);
  41. }
  42. static void InstaProp(FILE *fp, const wchar_t *property, float value)
  43. {
  44. _fwprintf_l(fp, L" %s=\"%3.3f\"", WASABI_API_LNG->Get_C_NumericLocale(), property, value);
  45. }
  46. static void InstaProp(FILE *fp, const wchar_t *property, bool value)
  47. {
  48. fwprintf(fp, L" %s=\"", property);
  49. if (value)
  50. fputws(L"true\"", fp);
  51. else
  52. fputws(L"false\"", fp);
  53. }
  54. static void InstaTag(FILE *fp, const wchar_t *tag, const wchar_t *content)
  55. {
  56. if (content && !((INT_PTR)content < 65536) && *content)
  57. {
  58. fwprintf(fp, L"<%s>", tag);
  59. XMLWriteString(fp, content);
  60. fwprintf(fp, L"</%s>\r\n", tag);
  61. }
  62. }
  63. static void InstaTag(FILE *fp, const wchar_t *tag, unsigned int uint)
  64. {
  65. fwprintf(fp, L"<%s>%u</%s>", tag, uint, tag);
  66. }
  67. static void InstaTag(FILE *fp, const wchar_t *tag, __time64_t uint)
  68. {
  69. fwprintf(fp, L"<%s>%I64u</%s>", tag, uint, tag);
  70. }
  71. static void BuildXMLString(FILE *fp, const RSS::Item &item)
  72. {
  73. fputws(L"<item", fp);
  74. InstaProp(fp, L"winamp:listened", item.listened);
  75. InstaProp(fp, L"winamp:downloaded", item.downloaded);
  76. fputws(L">\r\n", fp);
  77. InstaTag(fp, L"title", item.itemName);
  78. if (item.url && item.url[0])
  79. {
  80. fputws(L"<enclosure", fp);
  81. InstaProp(fp, L"url", item.url);
  82. InstaPropI64(fp, L"length", item.size);
  83. fputws(L"/>\r\n", fp);
  84. }
  85. InstaTag(fp, L"guid", item.guid);
  86. InstaTag(fp, L"description", item.description);
  87. InstaTag(fp, L"link", item.link);
  88. if (item.duration && item.duration[0])
  89. {
  90. InstaTag(fp, L"itunes:duration", item.duration);
  91. }
  92. if (item.publishDate)
  93. {
  94. wchar_t date_str[128] = {0};
  95. MakeRFCDateString(item.publishDate, date_str, 128);
  96. InstaTag(fp, L"pubDate", date_str);
  97. }
  98. if (item.sourceUrl && item.sourceUrl[0])
  99. {
  100. fputws(L"<source",fp);
  101. InstaProp(fp, L"src", item.sourceUrl);
  102. fputws(L"/>\r\n", fp);
  103. }
  104. fputws(L"</item>\r\n", fp);
  105. }
  106. static void BuildXMLString(FILE *fp, Channel &channel)
  107. {
  108. fputws(L"<channel", fp);
  109. wchar_t date_str[128] = {0};
  110. MakeRFCDateString(channel.lastUpdate, date_str, 128);
  111. InstaProp(fp, L"winamp:lastupdate", date_str);
  112. fputws(L">\r\n", fp);
  113. // write update settings for this channel
  114. fputws(L"<winamp:update", fp);
  115. InstaProp(fp, L"usedefaultupdate", channel.useDefaultUpdate);
  116. InstaProp(fp, L"needsrefresh", channel.needsRefresh);
  117. if (!channel.useDefaultUpdate)
  118. {
  119. InstaProp(fp, L"autoupdate", channel.autoUpdate);
  120. InstaPropTime(fp, L"updatetime", channel.updateTime);
  121. }
  122. fputws(L"/>\r\n", fp);
  123. if (!channel.useDefaultUpdate)
  124. {
  125. fputws(L"<winamp:download", fp);
  126. InstaProp(fp, L"autodownload", channel.autoDownload);
  127. if (channel.autoDownload)
  128. {
  129. InstaProp(fp, L"autoDownloadEpisodes", channel.autoDownloadEpisodes);
  130. }
  131. fputws(L"/>\r\n", fp);
  132. }
  133. InstaTag(fp, L"winamp:url", channel.url);
  134. InstaTag(fp, L"title", channel.title);
  135. InstaTag(fp, L"link", channel.link);
  136. InstaTag(fp, L"description", channel.description);
  137. if (channel.ttl)
  138. InstaTag(fp, L"ttl", channel.ttl);
  139. fputws(L"\r\n", fp);
  140. Channel::ItemList::iterator itemItr;
  141. for (itemItr = channel.items.begin();itemItr != channel.items.end(); itemItr++)
  142. BuildXMLString(fp, *itemItr);
  143. fputws(L"</channel>\r\n", fp);
  144. }
  145. void SaveChannels(const wchar_t *fileName, ChannelList &channels)
  146. {
  147. FILE *fp = _wfopen(fileName, L"wb");
  148. if (fp)
  149. {
  150. ChannelList::iterator itr;
  151. wchar_t BOM = 0xFEFF;
  152. fwrite(&BOM, sizeof(BOM), 1, fp);
  153. fputws(L"<?xml version=\"1.0\" encoding=\"UTF-16\"?>\r\n", fp);
  154. fputws(L"<rss version=\"2.0\" xmlns:winamp=\"http://www.winamp.com\">\r\n", fp);
  155. for (itr = channels.begin();itr != channels.end();itr++)
  156. BuildXMLString(fp, *itr);
  157. fputws(L"</rss>", fp);
  158. fclose(fp);
  159. }
  160. }
  161. static void BuildXMLPreferences(FILE *fp)
  162. {
  163. fputws(L"<download", fp);
  164. InstaProp(fp, L"downloadpath", defaultDownloadPath);
  165. InstaProp(fp, L"autodownload", autoDownload);
  166. InstaProp(fp, L"autoDownloadEpisodes", autoDownloadEpisodes);
  167. InstaProp(fp, L"needToMakePodcastsView", needToMakePodcastsView);
  168. fputws(L"/>\r\n", fp);
  169. fputws(L"<update", fp);
  170. InstaPropTime(fp, L"updatetime", updateTime);
  171. InstaProp(fp, L"autoupdate", autoUpdate);
  172. InstaProp(fp, L"updateonlaunch", updateOnLaunch);
  173. fputws(L"/>\r\n", fp);
  174. fputws(L"<subscriptions", fp);
  175. InstaProp(fp, L"htmldivider", htmlDividerPercent);
  176. InstaProp(fp, L"channeldivider", channelDividerPercent);
  177. InstaProp(fp, L"itemtitlewidth", itemTitleWidth);
  178. InstaProp(fp, L"itemdatewidth", itemDateWidth);
  179. InstaProp(fp, L"itemmediawidth", itemMediaWidth);
  180. InstaProp(fp, L"itemsizewidth", itemSizeWidth);
  181. InstaProp(fp, L"currentitemsort", currentItemSort);
  182. InstaProp(fp, L"itemsortascending", itemSortAscending);
  183. InstaProp(fp, L"channelsortascending", channelSortAscending);
  184. InstaProp(fp, L"channelLastSelection", channelLastSelection);
  185. fputws(L"/>\r\n", fp);
  186. fputws(L"<downloadsView", fp);
  187. InstaProp(fp, L"downloadsChannelWidth", downloadsChannelWidth);
  188. InstaProp(fp, L"downloadsItemWidth", downloadsItemWidth);
  189. InstaProp(fp, L"downloadsProgressWidth", downloadsProgressWidth);
  190. InstaProp(fp, L"downloadsPathWidth", downloadsPathWidth);
  191. InstaProp(fp, L"downloadsItemSort", downloadsItemSort);
  192. InstaProp(fp, L"downloadsSortAscending", downloadsSortAscending);
  193. fputws(L"/>\r\n", fp);
  194. fputws(L"<service", fp);
  195. InstaProp(fp, L"url", serviceUrl);
  196. fputws(L"/>\r\n", fp);
  197. }
  198. static void BuildXMLDownloads(FILE *fp, DownloadList &downloads)
  199. {
  200. fputws(L"<downloads>", fp);
  201. AutoLock lock (downloads);
  202. DownloadList::const_iterator itr;
  203. for ( itr = downloads.begin(); itr != downloads.end(); itr++ )
  204. {
  205. fputws(L"<download>", fp);
  206. InstaTag(fp, L"channel", itr->channel);
  207. InstaTag(fp, L"item", itr->item);
  208. InstaTag(fp, L"url", itr->url);
  209. InstaTag(fp, L"path", itr->path);
  210. InstaTag(fp, L"publishDate", itr->publishDate);
  211. fputws(L"</download>\r\n", fp);
  212. }
  213. fputws(L"</downloads>", fp);
  214. }
  215. void SaveSettings(const wchar_t *fileName, DownloadList &downloads)
  216. {
  217. FILE *fp = _wfopen(fileName, L"wb");
  218. if (fp)
  219. {
  220. wchar_t BOM = 0xFEFF;
  221. fwrite(&BOM, sizeof(BOM), 1, fp);
  222. fputws(L"<?xml version=\"1.0\" encoding=\"UTF-16\"?>\r\n", fp);
  223. fputws(L"<winamp:preferences xmlns:winamp=\"http://www.winamp.com\" version=\"2\">\r\n", fp);
  224. BuildXMLPreferences(fp);
  225. BuildXMLDownloads(fp, downloads);
  226. fputws(L"</winamp:preferences>", fp);
  227. fclose(fp);
  228. }
  229. }