ogre.rb 0.1-i686-linux → 0.2-i686-linux

Sign up to get free protection for your applications and to get access to all the features.
Files changed (368) hide show
  1. data/README +43 -5
  2. data/Rakefile +67 -165
  3. data/lib/application.rb +2 -1
  4. data/lib/application_frame_listener.rb +17 -17
  5. data/lib/ogre.so +0 -0
  6. data/lib/ruby_ois.so +0 -0
  7. data/ogre.rb +3 -0
  8. data/samples/Ogre.log +358 -257
  9. data/samples/cel_shading.rb +85 -0
  10. data/samples/grass.rb +1 -1
  11. data/samples/media/materials/programs/CelShading.cg +63 -0
  12. data/samples/media/materials/scripts/CelShading.material +68 -0
  13. data/samples/media/materials/textures/cel_shading_diffuse.png +0 -0
  14. data/samples/media/materials/textures/cel_shading_edge.png +0 -0
  15. data/samples/media/materials/textures/cel_shading_specular.png +0 -0
  16. data/samples/ogre.cfg +1 -2
  17. data/samples/plugins.cfg +3 -2
  18. data/test/ogre.cfg +10 -0
  19. data/{samples/navi → test}/plugins.cfg +2 -4
  20. data/test/test_helper.rb +67 -0
  21. data/test/unit/constants_test.rb +66 -0
  22. data/test/unit/frame_stats_proxy_test.rb +28 -0
  23. data/test/unit/math_test.rb +20 -0
  24. data/test/unit/mesh_test.rb +15 -0
  25. data/test/unit/methods_test.rb +98 -0
  26. data/test/unit/movable_object_test.rb +19 -0
  27. data/test/unit/name_value_pair_list_test.rb +12 -0
  28. data/test/unit/overlay_element_test.rb +20 -0
  29. data/test/unit/render_target_test.rb +11 -0
  30. data/test/unit/resource_test.rb +26 -0
  31. data/test/unit/scene_manager_test.rb +21 -0
  32. metadata +25 -356
  33. data/samples/navi/Media/NaviDemo.material +0 -60
  34. data/samples/navi/Media/OgreCore.zip +0 -0
  35. data/samples/navi/Media/cerulean.jpg +0 -0
  36. data/samples/navi/Media/clouds.jpg +0 -0
  37. data/samples/navi/Media/controlsNaviMask.png +0 -0
  38. data/samples/navi/Media/grass.jpg +0 -0
  39. data/samples/navi/Media/knot.mesh +0 -0
  40. data/samples/navi/Media/testNaviMask.png +0 -0
  41. data/samples/navi/NaviLocal/Navi.js +0 -136
  42. data/samples/navi/NaviLocal/buttonBg.jpg +0 -0
  43. data/samples/navi/NaviLocal/controls.html +0 -303
  44. data/samples/navi/NaviLocal/knobBg.jpg +0 -0
  45. data/samples/navi/NaviLocal/moo.dropdownmenu.js +0 -87
  46. data/samples/navi/NaviLocal/mootools.v1.1.js +0 -6964
  47. data/samples/navi/NaviLocal/naviLogo.html +0 -32
  48. data/samples/navi/NaviLocal/naviLogo.png +0 -0
  49. data/samples/navi/NaviLocal/pageBg.jpg +0 -0
  50. data/samples/navi/NaviLocal/sliderBg.jpg +0 -0
  51. data/samples/navi/NaviLocal/test.html +0 -5
  52. data/samples/navi/NaviLocal/welcome.html +0 -36
  53. data/samples/navi/NaviLocal/welcome.png +0 -0
  54. data/samples/navi/chrome/chromelist.txt +0 -597
  55. data/samples/navi/chrome/classic.jar +0 -0
  56. data/samples/navi/chrome/classic.manifest +0 -4
  57. data/samples/navi/chrome/comm.jar +0 -0
  58. data/samples/navi/chrome/comm.manifest +0 -2
  59. data/samples/navi/chrome/en-US.jar +0 -0
  60. data/samples/navi/chrome/en-US.manifest +0 -9
  61. data/samples/navi/chrome/toolkit.jar +0 -0
  62. data/samples/navi/chrome/toolkit.manifest +0 -6
  63. data/samples/navi/components/FeedProcessor.js +0 -1825
  64. data/samples/navi/components/alerts.xpt +0 -0
  65. data/samples/navi/components/appshell.xpt +0 -0
  66. data/samples/navi/components/appstartup.xpt +0 -0
  67. data/samples/navi/components/auth.dll +0 -0
  68. data/samples/navi/components/autocomplete.xpt +0 -0
  69. data/samples/navi/components/autoconfig.dll +0 -0
  70. data/samples/navi/components/autoconfig.xpt +0 -0
  71. data/samples/navi/components/caps.xpt +0 -0
  72. data/samples/navi/components/chardet.xpt +0 -0
  73. data/samples/navi/components/chrome.xpt +0 -0
  74. data/samples/navi/components/commandhandler.xpt +0 -0
  75. data/samples/navi/components/commandlines.xpt +0 -0
  76. data/samples/navi/components/composer.xpt +0 -0
  77. data/samples/navi/components/compreg.dat +0 -1474
  78. data/samples/navi/components/content_base.xpt +0 -0
  79. data/samples/navi/components/content_html.xpt +0 -0
  80. data/samples/navi/components/content_htmldoc.xpt +0 -0
  81. data/samples/navi/components/content_xmldoc.xpt +0 -0
  82. data/samples/navi/components/content_xslt.xpt +0 -0
  83. data/samples/navi/components/content_xtf.xpt +0 -0
  84. data/samples/navi/components/directory.xpt +0 -0
  85. data/samples/navi/components/docshell_base.xpt +0 -0
  86. data/samples/navi/components/dom.xpt +0 -0
  87. data/samples/navi/components/dom_base.xpt +0 -0
  88. data/samples/navi/components/dom_canvas.xpt +0 -0
  89. data/samples/navi/components/dom_core.xpt +0 -0
  90. data/samples/navi/components/dom_css.xpt +0 -0
  91. data/samples/navi/components/dom_events.xpt +0 -0
  92. data/samples/navi/components/dom_html.xpt +0 -0
  93. data/samples/navi/components/dom_loadsave.xpt +0 -0
  94. data/samples/navi/components/dom_range.xpt +0 -0
  95. data/samples/navi/components/dom_sidebar.xpt +0 -0
  96. data/samples/navi/components/dom_storage.xpt +0 -0
  97. data/samples/navi/components/dom_stylesheets.xpt +0 -0
  98. data/samples/navi/components/dom_svg.xpt +0 -0
  99. data/samples/navi/components/dom_traversal.xpt +0 -0
  100. data/samples/navi/components/dom_views.xpt +0 -0
  101. data/samples/navi/components/dom_xbl.xpt +0 -0
  102. data/samples/navi/components/dom_xpath.xpt +0 -0
  103. data/samples/navi/components/dom_xul.xpt +0 -0
  104. data/samples/navi/components/downloads.xpt +0 -0
  105. data/samples/navi/components/editor.xpt +0 -0
  106. data/samples/navi/components/embed_base.xpt +0 -0
  107. data/samples/navi/components/extensions.xpt +0 -0
  108. data/samples/navi/components/exthandler.xpt +0 -0
  109. data/samples/navi/components/fastfind.xpt +0 -0
  110. data/samples/navi/components/feeds.xpt +0 -0
  111. data/samples/navi/components/find.xpt +0 -0
  112. data/samples/navi/components/gfx.xpt +0 -0
  113. data/samples/navi/components/gksvgrenderer.xpt +0 -0
  114. data/samples/navi/components/history.xpt +0 -0
  115. data/samples/navi/components/htmlparser.xpt +0 -0
  116. data/samples/navi/components/imglib2.xpt +0 -0
  117. data/samples/navi/components/inspector.xpt +0 -0
  118. data/samples/navi/components/intl.xpt +0 -0
  119. data/samples/navi/components/intlcmpt.xpt +0 -0
  120. data/samples/navi/components/jar.xpt +0 -0
  121. data/samples/navi/components/jsconsole-clhandler.js +0 -170
  122. data/samples/navi/components/jsconsole.xpt +0 -0
  123. data/samples/navi/components/jsdservice.xpt +0 -0
  124. data/samples/navi/components/layout_base.xpt +0 -0
  125. data/samples/navi/components/layout_printing.xpt +0 -0
  126. data/samples/navi/components/layout_xul.xpt +0 -0
  127. data/samples/navi/components/layout_xul_tree.xpt +0 -0
  128. data/samples/navi/components/locale.xpt +0 -0
  129. data/samples/navi/components/lwbrk.xpt +0 -0
  130. data/samples/navi/components/mimetype.xpt +0 -0
  131. data/samples/navi/components/mozbrwsr.xpt +0 -0
  132. data/samples/navi/components/mozfind.xpt +0 -0
  133. data/samples/navi/components/necko.xpt +0 -0
  134. data/samples/navi/components/necko_about.xpt +0 -0
  135. data/samples/navi/components/necko_cache.xpt +0 -0
  136. data/samples/navi/components/necko_cookie.xpt +0 -0
  137. data/samples/navi/components/necko_data.xpt +0 -0
  138. data/samples/navi/components/necko_dns.xpt +0 -0
  139. data/samples/navi/components/necko_file.xpt +0 -0
  140. data/samples/navi/components/necko_ftp.xpt +0 -0
  141. data/samples/navi/components/necko_http.xpt +0 -0
  142. data/samples/navi/components/necko_res.xpt +0 -0
  143. data/samples/navi/components/necko_socket.xpt +0 -0
  144. data/samples/navi/components/necko_strconv.xpt +0 -0
  145. data/samples/navi/components/necko_viewsource.xpt +0 -0
  146. data/samples/navi/components/nsCloseAllWindows.js +0 -143
  147. data/samples/navi/components/nsDefaultCLH.js +0 -231
  148. data/samples/navi/components/nsDictionary.js +0 -148
  149. data/samples/navi/components/nsExtensionManager.js +0 -8497
  150. data/samples/navi/components/nsHelperAppDlg.js +0 -990
  151. data/samples/navi/components/nsInterfaceInfoToIDL.js +0 -590
  152. data/samples/navi/components/nsKillAll.js +0 -200
  153. data/samples/navi/components/nsPostUpdateWin.js +0 -711
  154. data/samples/navi/components/nsProgressDialog.js +0 -949
  155. data/samples/navi/components/nsProxyAutoConfig.js +0 -396
  156. data/samples/navi/components/nsResetPref.js +0 -175
  157. data/samples/navi/components/nsURLFormatter.js +0 -179
  158. data/samples/navi/components/nsUpdateService.js +0 -3074
  159. data/samples/navi/components/nsXULAppInstall.js +0 -301
  160. data/samples/navi/components/nsXmlRpcClient.js +0 -1038
  161. data/samples/navi/components/oji.xpt +0 -0
  162. data/samples/navi/components/passwordmgr.xpt +0 -0
  163. data/samples/navi/components/pipboot.xpt +0 -0
  164. data/samples/navi/components/pipnss.xpt +0 -0
  165. data/samples/navi/components/plugin.xpt +0 -0
  166. data/samples/navi/components/pref.xpt +0 -0
  167. data/samples/navi/components/prefetch.xpt +0 -0
  168. data/samples/navi/components/profile.xpt +0 -0
  169. data/samples/navi/components/progressDlg.xpt +0 -0
  170. data/samples/navi/components/proxyObject.xpt +0 -0
  171. data/samples/navi/components/rdf.xpt +0 -0
  172. data/samples/navi/components/satchel.xpt +0 -0
  173. data/samples/navi/components/saxparser.xpt +0 -0
  174. data/samples/navi/components/shistory.xpt +0 -0
  175. data/samples/navi/components/storage.xpt +0 -0
  176. data/samples/navi/components/toolkitprofile.xpt +0 -0
  177. data/samples/navi/components/transformiix.dll +0 -0
  178. data/samples/navi/components/txmgr.xpt +0 -0
  179. data/samples/navi/components/txtsvc.xpt +0 -0
  180. data/samples/navi/components/uconv.xpt +0 -0
  181. data/samples/navi/components/unicharutil.xpt +0 -0
  182. data/samples/navi/components/universalchardet.dll +0 -0
  183. data/samples/navi/components/update.xpt +0 -0
  184. data/samples/navi/components/uriloader.xpt +0 -0
  185. data/samples/navi/components/urlformatter.xpt +0 -0
  186. data/samples/navi/components/webBrowser_core.xpt +0 -0
  187. data/samples/navi/components/webbrowserpersist.xpt +0 -0
  188. data/samples/navi/components/webshell_idls.xpt +0 -0
  189. data/samples/navi/components/websrvcs.dll +0 -0
  190. data/samples/navi/components/websrvcs.xpt +0 -0
  191. data/samples/navi/components/widget.xpt +0 -0
  192. data/samples/navi/components/windowds.xpt +0 -0
  193. data/samples/navi/components/windowwatcher.xpt +0 -0
  194. data/samples/navi/components/xml-rpc.xpt +0 -0
  195. data/samples/navi/components/xmlextras.dll +0 -0
  196. data/samples/navi/components/xpcom_base.xpt +0 -0
  197. data/samples/navi/components/xpcom_components.xpt +0 -0
  198. data/samples/navi/components/xpcom_ds.xpt +0 -0
  199. data/samples/navi/components/xpcom_io.xpt +0 -0
  200. data/samples/navi/components/xpcom_obsolete.xpt +0 -0
  201. data/samples/navi/components/xpcom_thread.xpt +0 -0
  202. data/samples/navi/components/xpcom_xpti.xpt +0 -0
  203. data/samples/navi/components/xpconnect.xpt +0 -0
  204. data/samples/navi/components/xpinstall.xpt +0 -0
  205. data/samples/navi/components/xpti.dat +0 -1424
  206. data/samples/navi/components/xulapp.xpt +0 -0
  207. data/samples/navi/components/xulapp_setup.xpt +0 -0
  208. data/samples/navi/components/xuldoc.xpt +0 -0
  209. data/samples/navi/components/xulrunner.xpt +0 -0
  210. data/samples/navi/components/xultmpl.xpt +0 -0
  211. data/samples/navi/components/xulutil.dll +0 -0
  212. data/samples/navi/controlsNaviMask.png +0 -0
  213. data/samples/navi/greprefs/all.js +0 -1344
  214. data/samples/navi/greprefs/security-prefs.js +0 -69
  215. data/samples/navi/greprefs/xpinstall.js +0 -2
  216. data/samples/navi/navi_demo.rb +0 -207
  217. data/samples/navi/plugins/NPSWF32.dll +0 -0
  218. data/samples/navi/plugins/flashplayer.xpt +0 -0
  219. data/samples/navi/plugins/npnul32.dll +0 -0
  220. data/samples/navi/res/EditorOverride.css +0 -359
  221. data/samples/navi/res/Thumbs.db +0 -0
  222. data/samples/navi/res/arrow.gif +0 -0
  223. data/samples/navi/res/arrowd.gif +0 -0
  224. data/samples/navi/res/bloatcycle.html +0 -40
  225. data/samples/navi/res/broken-image.gif +0 -0
  226. data/samples/navi/res/charsetData.properties +0 -199
  227. data/samples/navi/res/charsetalias.properties +0 -517
  228. data/samples/navi/res/cmessage.txt +0 -1
  229. data/samples/navi/res/dtd/xhtml11.dtd +0 -300
  230. data/samples/navi/res/entityTables/html40Latin1.properties +0 -146
  231. data/samples/navi/res/entityTables/html40Special.properties +0 -69
  232. data/samples/navi/res/entityTables/html40Symbols.properties +0 -164
  233. data/samples/navi/res/entityTables/htmlEntityVersions.properties +0 -50
  234. data/samples/navi/res/entityTables/transliterate.properties +0 -2367
  235. data/samples/navi/res/fonts/fontEncoding.properties +0 -127
  236. data/samples/navi/res/fonts/fontNameMap.properties +0 -134
  237. data/samples/navi/res/forms.css +0 -531
  238. data/samples/navi/res/grabber.gif +0 -0
  239. data/samples/navi/res/hiddenWindow.html +0 -1
  240. data/samples/navi/res/html/Thumbs.db +0 -0
  241. data/samples/navi/res/html/gopher-audio.gif +0 -0
  242. data/samples/navi/res/html/gopher-binary.gif +0 -0
  243. data/samples/navi/res/html/gopher-find.gif +0 -0
  244. data/samples/navi/res/html/gopher-image.gif +0 -0
  245. data/samples/navi/res/html/gopher-menu.gif +0 -0
  246. data/samples/navi/res/html/gopher-movie.gif +0 -0
  247. data/samples/navi/res/html/gopher-sound.gif +0 -0
  248. data/samples/navi/res/html/gopher-telnet.gif +0 -0
  249. data/samples/navi/res/html/gopher-text.gif +0 -0
  250. data/samples/navi/res/html/gopher-unknown.gif +0 -0
  251. data/samples/navi/res/html.css +0 -478
  252. data/samples/navi/res/langGroups.properties +0 -236
  253. data/samples/navi/res/language.properties +0 -259
  254. data/samples/navi/res/loading-image.gif +0 -0
  255. data/samples/navi/res/quirk.css +0 -282
  256. data/samples/navi/res/samples/Anieyes.gif +0 -0
  257. data/samples/navi/res/samples/Thumbs.db +0 -0
  258. data/samples/navi/res/samples/aform.css +0 -69
  259. data/samples/navi/res/samples/beeptest.html +0 -18
  260. data/samples/navi/res/samples/bform.css +0 -45
  261. data/samples/navi/res/samples/bg.jpg +0 -0
  262. data/samples/navi/res/samples/cform.css +0 -40
  263. data/samples/navi/res/samples/checkboxTest.xul +0 -47
  264. data/samples/navi/res/samples/demoform.css +0 -97
  265. data/samples/navi/res/samples/find.html +0 -97
  266. data/samples/navi/res/samples/gear1.gif +0 -0
  267. data/samples/navi/res/samples/image_props.html +0 -58
  268. data/samples/navi/res/samples/mozform.css +0 -256
  269. data/samples/navi/res/samples/printsetup.html +0 -175
  270. data/samples/navi/res/samples/raptor.jpg +0 -0
  271. data/samples/navi/res/samples/rock_gra.gif +0 -0
  272. data/samples/navi/res/samples/scrollbarTest1.xul +0 -66
  273. data/samples/navi/res/samples/scrollbarTest2.xul +0 -19
  274. data/samples/navi/res/samples/sliderTest1.xul +0 -14
  275. data/samples/navi/res/samples/soundtest.html +0 -20
  276. data/samples/navi/res/samples/test.wav +0 -0
  277. data/samples/navi/res/samples/test0.html +0 -220
  278. data/samples/navi/res/samples/test1.html +0 -84
  279. data/samples/navi/res/samples/test10.html +0 -16
  280. data/samples/navi/res/samples/test11.html +0 -42
  281. data/samples/navi/res/samples/test12.html +0 -79
  282. data/samples/navi/res/samples/test13.html +0 -126
  283. data/samples/navi/res/samples/test14.html +0 -5
  284. data/samples/navi/res/samples/test15.html +0 -5
  285. data/samples/navi/res/samples/test16.html +0 -124
  286. data/samples/navi/res/samples/test2.html +0 -41
  287. data/samples/navi/res/samples/test3.html +0 -126
  288. data/samples/navi/res/samples/test4.html +0 -335
  289. data/samples/navi/res/samples/test5.html +0 -199
  290. data/samples/navi/res/samples/test6.html +0 -335
  291. data/samples/navi/res/samples/test7.html +0 -11
  292. data/samples/navi/res/samples/test8-1.html +0 -66
  293. data/samples/navi/res/samples/test8.html +0 -662
  294. data/samples/navi/res/samples/test8dom.html +0 -64
  295. data/samples/navi/res/samples/test8sca.html +0 -308
  296. data/samples/navi/res/samples/test8siz.html +0 -224
  297. data/samples/navi/res/samples/test8tab.html +0 -9
  298. data/samples/navi/res/samples/test9.html +0 -12
  299. data/samples/navi/res/samples/test9a.html +0 -39
  300. data/samples/navi/res/samples/test9b.html +0 -16
  301. data/samples/navi/res/samples/test_ed.html +0 -5
  302. data/samples/navi/res/samples/test_form.html +0 -34
  303. data/samples/navi/res/samples/test_gfx.html +0 -75
  304. data/samples/navi/res/samples/test_lbox.html +0 -100
  305. data/samples/navi/res/samples/test_pr.html +0 -87
  306. data/samples/navi/res/samples/test_weight.html +0 -45
  307. data/samples/navi/res/samples/toolbarTest1.xul +0 -51
  308. data/samples/navi/res/samples/treeTest1.css +0 -62
  309. data/samples/navi/res/samples/treeTest1.xul +0 -110
  310. data/samples/navi/res/samples/xulTest.css +0 -130
  311. data/samples/navi/res/svg.css +0 -64
  312. data/samples/navi/res/table-add-column-after-active.gif +0 -0
  313. data/samples/navi/res/table-add-column-after-hover.gif +0 -0
  314. data/samples/navi/res/table-add-column-after.gif +0 -0
  315. data/samples/navi/res/table-add-column-before-active.gif +0 -0
  316. data/samples/navi/res/table-add-column-before-hover.gif +0 -0
  317. data/samples/navi/res/table-add-column-before.gif +0 -0
  318. data/samples/navi/res/table-add-row-after-active.gif +0 -0
  319. data/samples/navi/res/table-add-row-after-hover.gif +0 -0
  320. data/samples/navi/res/table-add-row-after.gif +0 -0
  321. data/samples/navi/res/table-add-row-before-active.gif +0 -0
  322. data/samples/navi/res/table-add-row-before-hover.gif +0 -0
  323. data/samples/navi/res/table-add-row-before.gif +0 -0
  324. data/samples/navi/res/table-remove-column-active.gif +0 -0
  325. data/samples/navi/res/table-remove-column-hover.gif +0 -0
  326. data/samples/navi/res/table-remove-column.gif +0 -0
  327. data/samples/navi/res/table-remove-row-active.gif +0 -0
  328. data/samples/navi/res/table-remove-row-hover.gif +0 -0
  329. data/samples/navi/res/table-remove-row.gif +0 -0
  330. data/samples/navi/res/throbber/Thumbs.db +0 -0
  331. data/samples/navi/res/throbber/anim.gif +0 -0
  332. data/samples/navi/res/throbber/anims00.gif +0 -0
  333. data/samples/navi/res/throbber/anims01.gif +0 -0
  334. data/samples/navi/res/throbber/anims02.gif +0 -0
  335. data/samples/navi/res/throbber/anims03.gif +0 -0
  336. data/samples/navi/res/throbber/anims04.gif +0 -0
  337. data/samples/navi/res/throbber/anims05.gif +0 -0
  338. data/samples/navi/res/throbber/anims06.gif +0 -0
  339. data/samples/navi/res/throbber/anims07.gif +0 -0
  340. data/samples/navi/res/throbber/anims08.gif +0 -0
  341. data/samples/navi/res/throbber/anims09.gif +0 -0
  342. data/samples/navi/res/throbber/anims10.gif +0 -0
  343. data/samples/navi/res/throbber/anims11.gif +0 -0
  344. data/samples/navi/res/throbber/anims12.gif +0 -0
  345. data/samples/navi/res/throbber/anims13.gif +0 -0
  346. data/samples/navi/res/throbber/anims14.gif +0 -0
  347. data/samples/navi/res/throbber/anims15.gif +0 -0
  348. data/samples/navi/res/throbber/anims16.gif +0 -0
  349. data/samples/navi/res/throbber/anims17.gif +0 -0
  350. data/samples/navi/res/throbber/anims18.gif +0 -0
  351. data/samples/navi/res/throbber/anims19.gif +0 -0
  352. data/samples/navi/res/throbber/anims20.gif +0 -0
  353. data/samples/navi/res/throbber/anims21.gif +0 -0
  354. data/samples/navi/res/throbber/anims22.gif +0 -0
  355. data/samples/navi/res/throbber/anims23.gif +0 -0
  356. data/samples/navi/res/throbber/anims24.gif +0 -0
  357. data/samples/navi/res/throbber/anims25.gif +0 -0
  358. data/samples/navi/res/throbber/anims26.gif +0 -0
  359. data/samples/navi/res/throbber/anims27.gif +0 -0
  360. data/samples/navi/res/throbber/anims28.gif +0 -0
  361. data/samples/navi/res/throbber/anims29.gif +0 -0
  362. data/samples/navi/res/ua.css +0 -235
  363. data/samples/navi/res/viewer.properties +0 -1
  364. data/samples/navi/res/viewsource.css +0 -118
  365. data/samples/navi/res/wincharset.properties +0 -55
  366. data/samples/navi/resources.cfg +0 -14
  367. data/samples/navi/testNaviMask.png +0 -0
  368. data/samples/render_run_log.5796 +0 -891
@@ -1,1825 +0,0 @@
1
- /* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
2
- /* ***** BEGIN LICENSE BLOCK *****
3
- * Version: MPL 1.1/GPL 2.0/LGPL 2.1
4
- *
5
- * The contents of this file are subject to the Mozilla Public License Version
6
- * 1.1 (the "License"); you may not use this file except in compliance with
7
- * the License. You may obtain a copy of the License at
8
- * http://www.mozilla.org/MPL/
9
- *
10
- * Software distributed under the License is distributed on an "AS IS" basis,
11
- * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
12
- * for the specific language governing rights and limitations under the
13
- * License.
14
- *
15
- * The Original Code is mozilla.org code.
16
- *
17
- * The Initial Developer of the Original Code is Robert Sayre.
18
- * Portions created by the Initial Developer are Copyright (C) 2006
19
- * the Initial Developer. All Rights Reserved.
20
- *
21
- * Contributor(s):
22
- * Ben Goodger <beng@google.com>
23
- * Myk Melez <myk@mozilla.org>
24
- *
25
- * Alternatively, the contents of this file may be used under the terms of
26
- * either the GNU General Public License Version 2 or later (the "GPL"), or
27
- * the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
28
- * in which case the provisions of the GPL or the LGPL are applicable instead
29
- * of those above. If you wish to allow use of your version of this file only
30
- * under the terms of either the GPL or the LGPL, and not to allow others to
31
- * use your version of this file under the terms of the MPL, indicate your
32
- * decision by deleting the provisions above and replace them with the notice
33
- * and other provisions required by the GPL or the LGPL. If you do not delete
34
- * the provisions above, a recipient may use your version of this file under
35
- * the terms of any one of the MPL, the GPL or the LGPL.
36
- *
37
- * ***** END LICENSE BLOCK ***** */
38
-
39
- function LOG(str) {
40
- dump("*** " + str + "\n");
41
- }
42
-
43
- const Ci = Components.interfaces;
44
- const Cc = Components.classes;
45
- const Cr = Components.results;
46
-
47
- const IO_CONTRACTID = "@mozilla.org/network/io-service;1"
48
- const BAG_CONTRACTID = "@mozilla.org/hash-property-bag;1"
49
- const ARRAY_CONTRACTID = "@mozilla.org/array;1";
50
- const SAX_CONTRACTID = "@mozilla.org/saxparser/xmlreader;1";
51
- const UNESCAPE_CONTRACTID = "@mozilla.org/feed-unescapehtml;1";
52
-
53
- var gIoService = Cc[IO_CONTRACTID].getService(Ci.nsIIOService);
54
- var gUnescapeHTML = Cc[UNESCAPE_CONTRACTID].
55
- getService(Ci.nsIScriptableUnescapeHTML);
56
-
57
- const XMLNS = "http://www.w3.org/XML/1998/namespace";
58
- const RSS090NS = "http://my.netscape.com/rdf/simple/0.9/";
59
-
60
- /***** Some general utils *****/
61
- function strToURI(link, base) {
62
- var base = base || null;
63
- try {
64
- return gIoService.newURI(link, null, base);
65
- }
66
- catch(e) {
67
- return null;
68
- }
69
- }
70
-
71
- function isArray(a) {
72
- return isObject(a) && a.constructor == Array;
73
- }
74
-
75
- function isObject(a) {
76
- return (a && typeof a == "object") || isFunction(a);
77
- }
78
-
79
- function isFunction(a) {
80
- return typeof a == "function";
81
- }
82
-
83
- function isIID(a, iid) {
84
- var rv = false;
85
- try {
86
- a.QueryInterface(iid);
87
- rv = true;
88
- }
89
- catch(e) {
90
- }
91
- return rv;
92
- }
93
-
94
- function isIArray(a) {
95
- return isIID(a, Ci.nsIArray);
96
- }
97
-
98
- function isIFeedContainer(a) {
99
- return isIID(a, Ci.nsIFeedContainer);
100
- }
101
-
102
- function stripTags(someHTML) {
103
- return someHTML.replace(/<[^>]+>/g,"");
104
- }
105
-
106
- /**
107
- * Searches through an array of links and returns a JS array
108
- * of matching property bags.
109
- */
110
- const IANA_URI = "http://www.iana.org/assignments/relation/";
111
- function findAtomLinks(rel, links) {
112
- var rvLinks = [];
113
- for (var i = 0; i < links.length; ++i) {
114
- var linkElement = links.queryElementAt(i, Ci.nsIPropertyBag2);
115
- // atom:link MUST have @href
116
- if (bagHasKey(linkElement, "href")) {
117
- var relAttribute = null;
118
- if (bagHasKey(linkElement, "rel"))
119
- relAttribute = linkElement.getPropertyAsAString("rel")
120
- if ((!relAttribute && rel == "alternate") || relAttribute == rel) {
121
- rvLinks.push(linkElement);
122
- continue;
123
- }
124
- // catch relations specified by IANA URI
125
- if (relAttribute == IANA_URI + rel) {
126
- rvLinks.push(linkElement);
127
- }
128
- }
129
- }
130
- return rvLinks;
131
- }
132
-
133
- function xmlEscape(s) {
134
- s = s.replace(/&/g, "&amp;");
135
- s = s.replace(/>/g, "&gt;");
136
- s = s.replace(/</g, "&lt;");
137
- s = s.replace(/"/g, "&quot;");
138
- s = s.replace(/'/g, "&apos;");
139
- return s;
140
- }
141
-
142
- function arrayContains(array, element) {
143
- for (var i = 0; i < array.length; ++i) {
144
- if (array[i] == element) {
145
- return true;
146
- }
147
- }
148
- return false;
149
- }
150
-
151
- // XXX add hasKey to nsIPropertyBag
152
- function bagHasKey(bag, key) {
153
- try {
154
- bag.getProperty(key);
155
- return true;
156
- }
157
- catch (e) {
158
- return false;
159
- }
160
- }
161
-
162
- function makePropGetter(key) {
163
- return function FeedPropGetter(bag) {
164
- try {
165
- return value = bag.getProperty(key);
166
- }
167
- catch(e) {
168
- }
169
- return null;
170
- }
171
- }
172
-
173
-
174
-
175
- /**
176
- * XXX Thunderbird's W3C-DTF function
177
- *
178
- * Converts a W3C-DTF (subset of ISO 8601) date string to an IETF date
179
- * string. W3C-DTF is described in this note:
180
- * http://www.w3.org/TR/NOTE-datetime IETF is obtained via the Date
181
- * object's toUTCString() method. The object's toString() method is
182
- * insufficient because it spells out timezones on Win32
183
- * (f.e. "Pacific Standard Time" instead of "PST"), which Mail doesn't
184
- * grok. For info, see
185
- * http://lxr.mozilla.org/mozilla/source/js/src/jsdate.c#1526.
186
- */
187
- const HOURS_TO_MINUTES = 60;
188
- const MINUTES_TO_SECONDS = 60;
189
- const SECONDS_TO_MILLISECONDS = 1000;
190
- const MINUTES_TO_MILLISECONDS = MINUTES_TO_SECONDS * SECONDS_TO_MILLISECONDS;
191
- const HOURS_TO_MILLISECONDS = HOURS_TO_MINUTES * MINUTES_TO_MILLISECONDS;
192
- function W3CToIETFDate(dateString) {
193
-
194
- var parts = dateString.match(/(\d\d\d\d)(-(\d\d))?(-(\d\d))?(T(\d\d):(\d\d)(:(\d\d)(\.(\d+))?)?(Z|([+-])(\d\d):(\d\d))?)?/);
195
-
196
- // Here's an example of a W3C-DTF date string and what .match returns for it.
197
- //
198
- // date: 2003-05-30T11:18:50.345-08:00
199
- // date.match returns array values:
200
- //
201
- // 0: 2003-05-30T11:18:50-08:00,
202
- // 1: 2003,
203
- // 2: -05,
204
- // 3: 05,
205
- // 4: -30,
206
- // 5: 30,
207
- // 6: T11:18:50-08:00,
208
- // 7: 11,
209
- // 8: 18,
210
- // 9: :50,
211
- // 10: 50,
212
- // 11: .345,
213
- // 12: 345,
214
- // 13: -08:00,
215
- // 14: -,
216
- // 15: 08,
217
- // 16: 00
218
-
219
- // Create a Date object from the date parts. Note that the Date
220
- // object apparently can't deal with empty string parameters in lieu
221
- // of numbers, so optional values (like hours, minutes, seconds, and
222
- // milliseconds) must be forced to be numbers.
223
- var date = new Date(parts[1], parts[3] - 1, parts[5], parts[7] || 0,
224
- parts[8] || 0, parts[10] || 0, parts[12] || 0);
225
-
226
- // We now have a value that the Date object thinks is in the local
227
- // timezone but which actually represents the date/time in the
228
- // remote timezone (f.e. the value was "10:00 EST", and we have
229
- // converted it to "10:00 PST" instead of "07:00 PST"). We need to
230
- // correct that. To do so, we're going to add the offset between
231
- // the remote timezone and UTC (to convert the value to UTC), then
232
- // add the offset between UTC and the local timezone //(to convert
233
- // the value to the local timezone).
234
-
235
- // Ironically, W3C-DTF gives us the offset between UTC and the
236
- // remote timezone rather than the other way around, while the
237
- // getTimezoneOffset() method of a Date object gives us the offset
238
- // between the local timezone and UTC rather than the other way
239
- // around. Both of these are the additive inverse (i.e. -x for x)
240
- // of what we want, so we have to invert them to use them by
241
- // multipying by -1 (f.e. if "the offset between UTC and the remote
242
- // timezone" is -5 hours, then "the offset between the remote
243
- // timezone and UTC" is -5*-1 = 5 hours).
244
-
245
- // Note that if the timezone portion of the date/time string is
246
- // absent (which violates W3C-DTF, although ISO 8601 allows it), we
247
- // assume the value to be in UTC.
248
-
249
- // The offset between the remote timezone and UTC in milliseconds.
250
- var remoteToUTCOffset = 0;
251
- if (parts[13] && parts[13] != "Z") {
252
- var direction = (parts[14] == "+" ? 1 : -1);
253
- if (parts[15])
254
- remoteToUTCOffset += direction * parts[15] * HOURS_TO_MILLISECONDS;
255
- if (parts[16])
256
- remoteToUTCOffset += direction * parts[16] * MINUTES_TO_MILLISECONDS;
257
- }
258
- remoteToUTCOffset = remoteToUTCOffset * -1; // invert it
259
-
260
- // The offset between UTC and the local timezone in milliseconds.
261
- var UTCToLocalOffset = date.getTimezoneOffset() * MINUTES_TO_MILLISECONDS;
262
- UTCToLocalOffset = UTCToLocalOffset * -1; // invert it
263
- date.setTime(date.getTime() + remoteToUTCOffset + UTCToLocalOffset);
264
-
265
- return date.toUTCString();
266
- }
267
-
268
- const RDF_NS = "http://www.w3.org/1999/02/22-rdf-syntax-ns#";
269
- // namespace map
270
- var gNamespaces = {
271
- "http://webns.net/mvcb/":"admin",
272
- "http://backend.userland.com/rss":"",
273
- "http://blogs.law.harvard.edu/tech/rss":"",
274
- "http://www.w3.org/2005/Atom":"atom",
275
- "http://purl.org/atom/ns#":"atom03",
276
- "http://purl.org/rss/1.0/modules/content/":"content",
277
- "http://purl.org/dc/elements/1.1/":"dc",
278
- "http://purl.org/dc/terms/":"dcterms",
279
- "http://www.w3.org/1999/02/22-rdf-syntax-ns#":"rdf",
280
- "http://purl.org/rss/1.0/":"rss1",
281
- "http://my.netscape.com/rdf/simple/0.9/":"rss1",
282
- "http://wellformedweb.org/CommentAPI/":"wfw",
283
- "http://purl.org/rss/1.0/modules/wiki/":"wiki",
284
- "http://www.w3.org/XML/1998/namespace":"xml"
285
- }
286
-
287
-
288
- function FeedResult() {}
289
- FeedResult.prototype = {
290
- bozo: false,
291
- doc: null,
292
- version: null,
293
- headers: null,
294
- uri: null,
295
- stylesheet: null,
296
-
297
- registerExtensionPrefix: function FR_registerExtensionPrefix(ns, prefix) {
298
- throw Cr.NS_ERROR_NOT_IMPLEMENTED;
299
- },
300
-
301
- QueryInterface: function FR_QI(iid) {
302
- if (iid.equals(Ci.nsIFeedResult) ||
303
- iid.equals(Ci.nsISupports))
304
- return this;
305
-
306
- throw Cr.NS_ERROR_NOINTERFACE;
307
- },
308
- }
309
-
310
- function Feed() {
311
- this.subtitle = null;
312
- this.title = null;
313
- this.items = Cc[ARRAY_CONTRACTID].createInstance(Ci.nsIMutableArray);
314
- this.link = null;
315
- this.id = null;
316
- this.generator = null;
317
- this.authors = Cc[ARRAY_CONTRACTID].createInstance(Ci.nsIMutableArray);
318
- this.contributors = Cc[ARRAY_CONTRACTID].createInstance(Ci.nsIMutableArray);
319
- this.baseURI = null;
320
- }
321
-
322
- Feed.prototype = {
323
- searchLists: {
324
- subtitle: ["description","dc:description","rss1:description",
325
- "atom03:tagline","atom:subtitle"],
326
- items: ["items","atom03_entries","entries"],
327
- id: ["atom:id","rdf:about"],
328
- generator: ["generator"],
329
- authors : ["authors"],
330
- contributors: ["contributors"],
331
- title: ["title","rss1:title", "atom03:title","atom:title"],
332
- link: [["link",strToURI],["rss1:link",strToURI]],
333
- categories: ["categories", "dc:subject"],
334
- rights: ["atom03:rights","atom:rights"],
335
- cloud: ["cloud"],
336
- image: ["image", "rss1:image", "atom:logo"],
337
- textInput: ["textInput", "rss1:textinput"],
338
- skipDays: ["skipDays"],
339
- skipHours: ["skipHours"],
340
- updated: ["pubDate", "lastBuildDate", "atom03:modified", "dc:date",
341
- "dcterms:modified", "atom:updated"]
342
- },
343
-
344
- normalize: function Feed_normalize() {
345
- fieldsToObj(this, this.searchLists);
346
- if (this.skipDays)
347
- this.skipDays = this.skipDays.getProperty("days");
348
- if (this.skipHours)
349
- this.skipHours = this.skipHours.getProperty("hours");
350
-
351
- if (this.updated)
352
- this.updated = dateParse(this.updated);
353
-
354
- // Assign Atom link if needed
355
- if (bagHasKey(this.fields, "links"))
356
- this._atomLinksToURI();
357
-
358
- // Resolve relative image links
359
- if (this.image && bagHasKey(this.image, "url")) {
360
- this._resolveImageLink();
361
- }
362
-
363
- this._resetBagMembersToRawText([this.searchLists.subtitle,
364
- this.searchLists.title]);
365
- },
366
-
367
- _atomLinksToURI: function Feed_linkToURI() {
368
- var links = this.fields.getPropertyAsInterface("links", Ci.nsIArray);
369
- var alternates = findAtomLinks("alternate", links);
370
- if (alternates.length > 0) {
371
- var href = alternates[0].getPropertyAsAString("href");
372
- var base;
373
- if (bagHasKey(alternates[0], "xml:base"))
374
- base = alternates[0].getPropertyAsAString("xml:base");
375
- this.link = this._resolveURI(href, base);
376
- }
377
- },
378
-
379
- _resolveImageLink: function Feed_resolveImageLink() {
380
- var base;
381
- if (bagHasKey(this.image, "xml:base"))
382
- base = this.image.getPropertyAsAString("xml:base");
383
- var url = this._resolveURI(this.image.getPropertyAsAString("url"), base);
384
- if (url)
385
- this.image.setPropertyAsAString("url", url.spec);
386
- },
387
-
388
- _resolveURI: function Feed_resolveURI(linkSpec, baseSpec) {
389
- var uri = null;
390
- try {
391
- var base = baseSpec ? strToURI(baseSpec, this.baseURI) : this.baseURI;
392
- uri = strToURI(linkSpec, base);
393
- }
394
- catch(e) {
395
- LOG(e);
396
- }
397
-
398
- return uri;
399
- },
400
-
401
- // reset the bag to raw contents, not text constructs
402
- _resetBagMembersToRawText: function Feed_resetBagMembers(fieldLists) {
403
- for (var i=0; i<fieldLists.length; i++) {
404
- for (var j=0; j<fieldLists[i].length; j++) {
405
- if (bagHasKey(this.fields, fieldLists[i][j])) {
406
- var textConstruct = this.fields.getProperty(fieldLists[i][j]);
407
- this.fields.setPropertyAsAString(fieldLists[i][j],
408
- textConstruct.text);
409
- }
410
- }
411
- }
412
- },
413
-
414
- QueryInterface: function Feed_QI(iid) {
415
- if (iid.equals(Ci.nsIFeed) ||
416
- iid.equals(Ci.nsIFeedContainer) ||
417
- iid.equals(Ci.nsISupports))
418
- return this;
419
- throw Cr.NS_ERROR_NOINTERFACE;
420
- }
421
- }
422
-
423
- function Entry() {
424
- this.summary = null;
425
- this.content = null;
426
- this.title = null;
427
- this.fields = Cc["@mozilla.org/hash-property-bag;1"].
428
- createInstance(Ci.nsIWritablePropertyBag2);
429
- this.link = null;
430
- this.id = null;
431
- this.baseURI = null;
432
- this.updated = null;
433
- this.published = null;
434
- this.authors = Cc[ARRAY_CONTRACTID].createInstance(Ci.nsIMutableArray);
435
- this.contributors = Cc[ARRAY_CONTRACTID].createInstance(Ci.nsIMutableArray);
436
- }
437
-
438
- Entry.prototype = {
439
- fields: null,
440
- enclosures: null,
441
- mediaContent: null,
442
-
443
- searchLists: {
444
- title: ["title", "rss1:title", "atom03:title", "atom:title"],
445
- link: [["link",strToURI],["rss1:link",strToURI]],
446
- id: [["guid", makePropGetter("guid")], "rdf:about",
447
- "atom03:id", "atom:id"],
448
- authors : ["authors"],
449
- contributors: ["contributors"],
450
- summary: ["description", "rss1:description", "dc:description",
451
- "atom03:summary", "atom:summary"],
452
- content: ["content:encoded","atom03:content","atom:content"],
453
- rights: ["atom03:rights","atom:rights"],
454
- published: ["atom03:issued", "dcterms:issued", "atom:published"],
455
- updated: ["pubDate", "atom03:modified", "dc:date", "dcterms:modified",
456
- "atom:updated"]
457
- },
458
-
459
- normalize: function Entry_normalize() {
460
- fieldsToObj(this, this.searchLists);
461
-
462
- // Assign Atom link if needed
463
- if (bagHasKey(this.fields, "links"))
464
- this._atomLinksToURI();
465
-
466
- // The link might be a guid w/ permalink=true
467
- if (!this.link && bagHasKey(this.fields, "guid")) {
468
- var guid = this.fields.getProperty("guid");
469
- var isPermaLink = true;
470
-
471
- if (bagHasKey(guid, "isPermaLink"))
472
- isPermaLink = guid.getProperty("isPermaLink").toLowerCase() != "false";
473
-
474
- if (guid && isPermaLink)
475
- this.link = strToURI(guid.getProperty("guid"));
476
- }
477
-
478
- if (this.updated)
479
- this.updated = dateParse(this.updated);
480
- if (this.published)
481
- this.published = dateParse(this.published);
482
-
483
- this._resetBagMembersToRawText([this.searchLists.content,
484
- this.searchLists.summary,
485
- this.searchLists.title]);
486
- },
487
-
488
- QueryInterface: function(iid) {
489
- if (iid.equals(Ci.nsIFeedEntry) ||
490
- iid.equals(Ci.nsIFeedContainer) ||
491
- iid.equals(Ci.nsISupports))
492
- return this;
493
-
494
- throw Cr.NS_ERROR_NOINTERFACE;
495
- }
496
- }
497
-
498
- Entry.prototype._atomLinksToURI = Feed.prototype._atomLinksToURI;
499
- Entry.prototype._resolveURI = Feed.prototype._resolveURI;
500
- Entry.prototype._resetBagMembersToRawText =
501
- Feed.prototype._resetBagMembersToRawText;
502
-
503
- // TextConstruct represents and element that could contain (X)HTML
504
- function TextConstruct() {
505
- this.lang = null;
506
- this.base = null;
507
- this.type = "text";
508
- this.text = null;
509
- }
510
-
511
- TextConstruct.prototype = {
512
- plainText: function TC_plainText() {
513
- if (this.type != "text") {
514
- return gUnescapeHTML.unescape(stripTags(this.text));
515
- }
516
- return this.text;
517
- },
518
-
519
- createDocumentFragment: function TC_createDocumentFragment(element) {
520
- if (this.type == "text") {
521
- var doc = element.ownerDocument;
522
- var docFragment = doc.createDocumentFragment();
523
- var node = doc.createTextNode(this.text);
524
- docFragment.appendChild(node);
525
- return docFragment;
526
- }
527
- var isXML;
528
- if (this.type == "xhtml")
529
- isXML = true
530
- else if (this.type == "html")
531
- isXML = false;
532
- else
533
- return null;
534
-
535
- return gUnescapeHTML.parseFragment(this.text, isXML, this.base, element);
536
- },
537
-
538
- QueryInterface: function(iid) {
539
- if (iid.equals(Ci.nsIFeedTextConstruct) ||
540
- iid.equals(Ci.nsISupports))
541
- return this;
542
-
543
- throw Cr.NS_ERROR_NOINTERFACE;
544
- }
545
- }
546
-
547
- // Generator represents the software that produced the feed
548
- function Generator() {
549
- this.lang = null;
550
- this.agent = null;
551
- this.version = null;
552
- this.uri = null;
553
-
554
- // nsIFeedElementBase
555
- this._attributes = null;
556
- this.baseURI = null;
557
- }
558
-
559
- Generator.prototype = {
560
-
561
- get attributes() {
562
- return this._attributes;
563
- },
564
-
565
- set attributes(value) {
566
- this._attributes = value;
567
- this.version = this._attributes.getValueFromName("","version");
568
- var uriAttribute = this._attributes.getValueFromName("","uri") ||
569
- this._attributes.getValueFromName("","url");
570
- this.uri = strToURI(uriAttribute, this.baseURI);
571
-
572
- // RSS1
573
- uriAttribute = this._attributes.getValueFromName(RDF_NS,"resource");
574
- if (uriAttribute) {
575
- this.agent = uriAttribute;
576
- this.uri = strToURI(uriAttribute, this.baseURI);
577
- }
578
- },
579
-
580
- QueryInterface: function(iid) {
581
- if (iid.equals(Ci.nsIFeedGenerator) ||
582
- iid.equals(Ci.nsIFeedElementBase) ||
583
- iid.equals(Ci.nsISupports))
584
- return this;
585
-
586
- throw Cr.NS_ERROR_NOINTERFACE;
587
- }
588
- }
589
-
590
- function Person() {
591
- this.name = null;
592
- this.uri = null;
593
- this.email = null;
594
-
595
- // nsIFeedElementBase
596
- this.attributes = null;
597
- this.baseURI = null;
598
- }
599
-
600
- Person.prototype = {
601
- QueryInterface: function(iid) {
602
- if (iid.equals(Ci.nsIFeedPerson) ||
603
- iid.equals(Ci.nsIFeedElementBase) ||
604
- iid.equals(Ci.nsISupports))
605
- return this;
606
-
607
- throw Cr.NS_ERROR_NOINTERFACE;
608
- }
609
- }
610
-
611
- /**
612
- * Map a list of fields into properties on a container.
613
- *
614
- * @param container An nsIFeedContainer
615
- * @param fields A list of fields to search for. List members can
616
- * be a list, in which case the second member is
617
- * transformation function (like parseInt).
618
- */
619
- function fieldsToObj(container, fields) {
620
- var props,prop,field,searchList;
621
- for (var key in fields) {
622
- searchList = fields[key];
623
- for (var i=0; i < searchList.length; ++i) {
624
- props = searchList[i];
625
- prop = null;
626
- field = isArray(props) ? props[0] : props;
627
- try {
628
- prop = container.fields.getProperty(field);
629
- }
630
- catch(e) {
631
- }
632
- if (prop) {
633
- prop = isArray(props) ? props[1](prop) : prop;
634
- container[key] = prop;
635
- }
636
- }
637
- }
638
- }
639
-
640
- /**
641
- * Lower cases an element's localName property
642
- * @param element A DOM element.
643
- *
644
- * @returns The lower case localName property of the specified element
645
- */
646
- function LC(element) {
647
- return element.localName.toLowerCase();
648
- }
649
-
650
- // TODO move these post-processor functions
651
- // create a generator element
652
- function atomGenerator(s, generator) {
653
- generator.QueryInterface(Ci.nsIFeedGenerator);
654
- generator.agent = trimString(s);
655
- return generator;
656
- }
657
-
658
- // post-process atom:logo to create an RSS2-like structure
659
- function atomLogo(s, logo) {
660
- logo.setPropertyAsAString("url", trimString(s));
661
- }
662
-
663
- // post-process an RSS category, map it to the Atom fields.
664
- function rssCatTerm(s, cat) {
665
- // add slash handling?
666
- cat.setPropertyAsAString("term", trimString(s));
667
- return cat;
668
- }
669
-
670
- // post-process a GUID
671
- function rssGuid(s, guid) {
672
- guid.setPropertyAsAString("guid", trimString(s));
673
- return guid;
674
- }
675
-
676
- // post-process an RSS author element
677
- //
678
- // It can contain a field like this:
679
- //
680
- // <author>lawyer@boyer.net (Lawyer Boyer)</author>
681
- //
682
- // or, delightfully, a field like this:
683
- //
684
- // <dc:creator>Simon St.Laurent (mailto:simonstl@simonstl.com)</dc:creator>
685
- //
686
- // We want to split this up and assign it to corresponding Atom
687
- // fields.
688
- //
689
- function rssAuthor(s,author) {
690
- author.QueryInterface(Ci.nsIFeedPerson);
691
- // check for RSS2 string format
692
- var chars = trimString(s);
693
- var matches = chars.match(/(.*)\((.*)\)/);
694
- var emailCheck =
695
- /^([a-zA-Z0-9_\.\-])+\@(([a-zA-Z0-9\-])+\.)+([a-zA-Z0-9]{2,4})+$/;
696
- if (matches) {
697
- var match1 = trimString(matches[1]);
698
- var match2 = trimString(matches[2]);
699
- if (match2.indexOf("mailto:") == 0)
700
- match2 = match2.substring(7);
701
- if (emailCheck.test(match1)) {
702
- author.email = match1;
703
- author.name = match2;
704
- }
705
- else if (emailCheck.test(match2)) {
706
- author.email = match2;
707
- author.name = match1;
708
- }
709
- else {
710
- // put it back together
711
- author.name = match1 + " (" + match2 + ")";
712
- }
713
- }
714
- else {
715
- author.name = chars;
716
- if (chars.indexOf('@'))
717
- author.email = chars;
718
- }
719
- return author;
720
- }
721
-
722
- //
723
- // skipHours and skipDays map to arrays, so we need to change the
724
- // string to an nsISupports in order to stick it in there.
725
- //
726
- function rssArrayElement(s) {
727
- var str = Cc["@mozilla.org/supports-string;1"].
728
- createInstance(Ci.nsISupportsString);
729
- str.data = s;
730
- str.QueryInterface(Ci.nsISupportsString);
731
- return str;
732
- }
733
-
734
- /***** Some feed utils from TBird *****/
735
-
736
- /**
737
- * Tests a RFC822 date against a regex.
738
- * @param aDateStr A string to test as an RFC822 date.
739
- *
740
- * @returns A boolean indicating whether the string is a valid RFC822 date.
741
- */
742
- function isValidRFC822Date(aDateStr) {
743
- var regex = new RegExp(RFC822_RE);
744
- return regex.test(aDateStr);
745
- }
746
-
747
- /**
748
- * Removes leading and trailing whitespace from a string.
749
- * @param s The string to trim.
750
- *
751
- * @returns A new string with whitespace stripped.
752
- */
753
- function trimString(s) {
754
- return(s.replace(/^\s+/, "").replace(/\s+$/, ""));
755
- }
756
-
757
- // Regular expression matching RFC822 dates
758
- const RFC822_RE = "^(((Mon)|(Tue)|(Wed)|(Thu)|(Fri)|(Sat)|(Sun)), *)?\\d\\d?"
759
- + " +((Jan)|(Feb)|(Mar)|(Apr)|(May)|(Jun)|(Jul)|(Aug)|(Sep)|(Oct)|(Nov)|(Dec))"
760
- + " +\\d\\d(\\d\\d)? +\\d\\d:\\d\\d(:\\d\\d)? +(([+-]?\\d\\d\\d\\d)|(UT)|(GMT)"
761
- + "|(EST)|(EDT)|(CST)|(CDT)|(MST)|(MDT)|(PST)|(PDT)|\\w)$";
762
-
763
- /**
764
- * XXX -- need to decide what this should return.
765
- * XXX -- Is there a Date class usable from C++?
766
- *
767
- * Tries tries parsing various date formats.
768
- * @param dateString
769
- * A string that is supposedly an RFC822 or RFC3339 date.
770
- * @returns A Date.toString XXX--fixme
771
- */
772
- function dateParse(dateString) {
773
- var date = trimString(dateString);
774
-
775
- if (date.search(/^\d\d\d\d/) != -1) //Could be a ISO8601/W3C date
776
- return W3CToIETFDate(dateString);
777
-
778
- if (isValidRFC822Date(date))
779
- return date;
780
-
781
- if (!isNaN(parseInt(date, 10))) {
782
- //It's an integer, so maybe it's a timestamp
783
- var d = new Date(parseInt(date, 10) * 1000);
784
- var now = new Date();
785
- var yeardiff = now.getFullYear() - d.getFullYear();
786
- if ((yeardiff >= 0) && (yeardiff < 3)) {
787
- // it's quite likely the correct date. 3 years is an arbitrary cutoff,
788
- // but this is an invalid date format, and there's no way to verify
789
- // its correctness.
790
- return d.toString();
791
- }
792
- }
793
- // Can't help.
794
- return null;
795
- }
796
-
797
-
798
- const XHTML_NS = "http://www.w3.org/1999/xhtml";
799
-
800
- // The XHTMLHandler handles inline XHTML found in things like atom:summary
801
- function XHTMLHandler(processor, isAtom) {
802
- this._buf = "";
803
- this._processor = processor;
804
- this._depth = 0;
805
- this._isAtom = isAtom;
806
- }
807
-
808
- // The fidelity can be improved here, to allow handling of stuff like
809
- // SVG and MathML. XXX
810
- XHTMLHandler.prototype = {
811
- startDocument: function XH_startDocument() {
812
- },
813
- endDocument: function XH_endDocument() {
814
- },
815
- startElement: function XH_startElement(uri, localName, qName, attributes) {
816
- ++this._depth;
817
-
818
- // RFC4287 requires XHTML to be wrapped in a div that is *not* part of
819
- // the content. This prevents people from screwing up namespaces, but
820
- // we need to skip it here.
821
- if (this._isAtom && this._depth == 1 && localName == "div")
822
- return;
823
-
824
- // If it's an XHTML element, record it. Otherwise, it's ignored.
825
- if (uri == XHTML_NS) {
826
- this._buf += "<" + localName;
827
- for (var i=0; i < attributes.length; ++i) {
828
- // XHTML attributes aren't in a namespace
829
- if (attributes.getURI(i) == "") {
830
- this._buf += (" " + attributes.getLocalName(i) + "='" +
831
- xmlEscape(attributes.getValue(i)) + "'");
832
- }
833
- }
834
- this._buf += ">";
835
- }
836
- },
837
- endElement: function XH_endElement(uri, localName, qName) {
838
- --this._depth;
839
-
840
- // We need to skip outer divs in Atom. See comment in startElement.
841
- if (this._isAtom && this._depth == 0 && localName == "div")
842
- return;
843
-
844
- // When we peek too far, go back to the main processor
845
- if (this._depth < 0) {
846
- this._processor.returnFromXHTMLHandler(trimString(this._buf),
847
- uri, localName, qName);
848
- return;
849
- }
850
- // If it's an XHTML element, record it. Otherwise, it's ignored.
851
- if (uri == XHTML_NS) {
852
- this._buf += "</" + localName + ">";
853
- }
854
- },
855
- characters: function XH_characters(data) {
856
- this._buf += xmlEscape(data);
857
- },
858
- startPrefixMapping: function XH_startPrefixMapping() {
859
- },
860
- endPrefixMapping: function XH_endPrefixMapping() {
861
- },
862
- processingInstruction: function XH_processingInstruction() {
863
- },
864
- }
865
-
866
- /**
867
- * The ExtensionHandler deals with elements we haven't explicitly
868
- * added to our transition table in the FeedProcessor.
869
- */
870
- function ExtensionHandler(processor) {
871
- this._buf = "";
872
- this._depth = 0;
873
- this._hasChildElements = false;
874
-
875
- // The FeedProcessor
876
- this._processor = processor;
877
-
878
- // Fields of the outermost extension element.
879
- this._localName = null;
880
- this._uri = null;
881
- this._qName = null;
882
- this._attrs = null;
883
- }
884
-
885
- ExtensionHandler.prototype = {
886
- startDocument: function EH_startDocument() {
887
- },
888
- endDocument: function EH_endDocument() {
889
- },
890
- startElement: function EH_startElement(uri, localName, qName, attrs) {
891
- ++this._depth;
892
- var prefix = gNamespaces[uri] ? gNamespaces[uri] + ":" : "";
893
- var key = prefix + localName;
894
-
895
- if (this._depth == 1) {
896
- this._uri = uri;
897
- this._localName = localName;
898
- this._qName = qName;
899
- this._attrs = attrs;
900
- }
901
-
902
- // if we descend into another element, we won't send text
903
- this._hasChildElements = (this._depth > 1);
904
-
905
- },
906
- endElement: function EH_endElement(uri, localName, qName) {
907
- --this._depth;
908
- if (this._depth == 0) {
909
- var text = this._hasChildElements ? null : trimString(this._buf);
910
- this._processor.returnFromExtHandler(this._uri, this._localName,
911
- text, this._attrs);
912
- }
913
- },
914
- characters: function EH_characters(data) {
915
- if (!this._hasChildElements)
916
- this._buf += data;
917
- },
918
- startPrefixMapping: function EH_startPrefixMapping() {
919
- },
920
- endPrefixMapping: function EH_endPrefixMapping() {
921
- },
922
- processingInstruction: function EH_processingInstruction() {
923
- },
924
- };
925
-
926
-
927
- /**
928
- * ElementInfo is a simple container object that describes
929
- * some characteristics of a feed element. For example, it
930
- * says whether an element can be expected to appear more
931
- * than once inside a given entry or feed.
932
- */
933
- function ElementInfo(fieldName, containerClass, closeFunc, isArray) {
934
- this.fieldName = fieldName;
935
- this.containerClass = containerClass;
936
- this.closeFunc = closeFunc;
937
- this.isArray = isArray;
938
- this.isWrapper = false;
939
- }
940
-
941
- /**
942
- * FeedElementInfo represents a feed element, usually the root.
943
- */
944
- function FeedElementInfo(fieldName, feedVersion) {
945
- this.isWrapper = false;
946
- this.fieldName = fieldName;
947
- this.feedVersion = feedVersion;
948
- }
949
-
950
- /**
951
- * Some feed formats include vestigial wrapper elements that we don't
952
- * want to include in our object model, but we do need to keep track
953
- * of during parsing.
954
- */
955
- function WrapperElementInfo(fieldName) {
956
- this.isWrapper = true;
957
- this.fieldName = fieldName;
958
- }
959
-
960
- /***** The Processor *****/
961
- function FeedProcessor() {
962
- this._reader = Cc[SAX_CONTRACTID].createInstance(Ci.nsISAXXMLReader);
963
- this._buf = "";
964
- this._feed = Cc[BAG_CONTRACTID].createInstance(Ci.nsIWritablePropertyBag2);
965
- this._handlerStack = [];
966
- this._xmlBaseStack = []; // sparse array keyed to nesting depth
967
- this._depth = 0;
968
- this._state = "START";
969
- this._result = null;
970
- this._extensionHandler = null;
971
- this._xhtmlHandler = null;
972
-
973
- // The nsIFeedResultListener waiting for the parse results
974
- this.listener = null;
975
-
976
- // These elements can contain (X)HTML or plain text.
977
- // We keep a table here that contains their default treatment
978
- this._textConstructs = {"atom:title":"text",
979
- "atom:summary":"text",
980
- "atom:rights":"text",
981
- "atom:content":"text",
982
- "atom:subtitle":"text",
983
- "description":"html",
984
- "rss1:description":"html",
985
- "dc:description":"html",
986
- "content:encoded":"html",
987
- "title":"text",
988
- "rss1:title":"text",
989
- "atom03:title":"text",
990
- "atom03:tagline":"text",
991
- "atom03:summary":"text",
992
- "atom03:content":"text"};
993
- this._stack = [];
994
-
995
- this._trans = {
996
- "START": {
997
- //If we hit a root RSS element, treat as RSS2.
998
- "rss": new FeedElementInfo("RSS2", "rss2"),
999
-
1000
- // If we hit an RDF element, if could be RSS1, but we can't
1001
- // verify that until we hit a rss1:channel element.
1002
- "rdf:RDF": new WrapperElementInfo("RDF"),
1003
-
1004
- // If we hit a Atom 1.0 element, treat as Atom 1.0.
1005
- "atom:feed": new FeedElementInfo("Atom", "atom"),
1006
-
1007
- // Treat as Atom 0.3
1008
- "atom03:feed": new FeedElementInfo("Atom03", "atom03"),
1009
- },
1010
-
1011
- /********* RSS2 **********/
1012
- "IN_RSS2": {
1013
- "channel": new WrapperElementInfo("channel")
1014
- },
1015
-
1016
- "IN_CHANNEL": {
1017
- "item": new ElementInfo("items", Cc[ENTRY_CONTRACTID], null, true),
1018
- "managingEditor": new ElementInfo("authors", Cc[PERSON_CONTRACTID],
1019
- rssAuthor, true),
1020
- "dc:creator": new ElementInfo("authors", Cc[PERSON_CONTRACTID],
1021
- rssAuthor, true),
1022
- "dc:author": new ElementInfo("authors", Cc[PERSON_CONTRACTID],
1023
- rssAuthor, true),
1024
- "dc:contributor": new ElementInfo("contributors", Cc[PERSON_CONTRACTID],
1025
- rssAuthor, true),
1026
- "category": new ElementInfo("categories", null, rssCatTerm, true),
1027
- "cloud": new ElementInfo("cloud", null, null, false),
1028
- "image": new ElementInfo("image", null, null, false),
1029
- "textInput": new ElementInfo("textInput", null, null, false),
1030
- "skipDays": new ElementInfo("skipDays", null, null, false),
1031
- "skipHours": new ElementInfo("skipHours", null, null, false),
1032
- "generator": new ElementInfo("generator", Cc[GENERATOR_CONTRACTID],
1033
- atomGenerator, false),
1034
- },
1035
-
1036
- "IN_ITEMS": {
1037
- "author": new ElementInfo("authors", Cc[PERSON_CONTRACTID],
1038
- rssAuthor, true),
1039
- "dc:creator": new ElementInfo("authors", Cc[PERSON_CONTRACTID],
1040
- rssAuthor, true),
1041
- "dc:author": new ElementInfo("authors", Cc[PERSON_CONTRACTID],
1042
- rssAuthor, true),
1043
- "dc:contributor": new ElementInfo("contributors", Cc[PERSON_CONTRACTID],
1044
- rssAuthor, true),
1045
- "category": new ElementInfo("categories", null, rssCatTerm, true),
1046
- "enclosure": new ElementInfo("enclosure", null, null, true),
1047
- "guid": new ElementInfo("guid", null, rssGuid, false)
1048
- },
1049
-
1050
- "IN_SKIPDAYS": {
1051
- "day": new ElementInfo("days", null, rssArrayElement, true)
1052
- },
1053
-
1054
- "IN_SKIPHOURS":{
1055
- "hour": new ElementInfo("hours", null, rssArrayElement, true)
1056
- },
1057
-
1058
- /********* RSS1 **********/
1059
- "IN_RDF": {
1060
- // If we hit a rss1:channel, we can verify that we have RSS1
1061
- "rss1:channel": new FeedElementInfo("rdf_channel", "rss1"),
1062
- "rss1:image": new ElementInfo("image", null, null, false),
1063
- "rss1:textinput": new ElementInfo("textInput", null, null, false),
1064
- "rss1:item": new ElementInfo("items", Cc[ENTRY_CONTRACTID], null, true),
1065
- },
1066
-
1067
- "IN_RDF_CHANNEL": {
1068
- "admin:generatorAgent": new ElementInfo("generator",
1069
- Cc[GENERATOR_CONTRACTID],
1070
- null, false),
1071
- "dc:creator": new ElementInfo("authors", Cc[PERSON_CONTRACTID],
1072
- rssAuthor, true),
1073
- "dc:author": new ElementInfo("authors", Cc[PERSON_CONTRACTID],
1074
- rssAuthor, true),
1075
- "dc:contributor": new ElementInfo("contributors", Cc[PERSON_CONTRACTID],
1076
- rssAuthor, true),
1077
- },
1078
-
1079
- /********* ATOM 1.0 **********/
1080
- "IN_ATOM": {
1081
- "atom:author": new ElementInfo("authors", Cc[PERSON_CONTRACTID],
1082
- null, true),
1083
- "atom:generator": new ElementInfo("generator", Cc[GENERATOR_CONTRACTID],
1084
- atomGenerator, false),
1085
- "atom:contributor": new ElementInfo("contributors", Cc[PERSON_CONTRACTID],
1086
- null, true),
1087
- "atom:link": new ElementInfo("links", null, null, true),
1088
- "atom:logo": new ElementInfo("atom:logo", null, atomLogo, false),
1089
- "atom:entry": new ElementInfo("entries", Cc[ENTRY_CONTRACTID],
1090
- null, true)
1091
- },
1092
-
1093
- "IN_ENTRIES": {
1094
- "atom:author": new ElementInfo("authors", Cc[PERSON_CONTRACTID],
1095
- null, true),
1096
- "atom:contributor": new ElementInfo("contributors", Cc[PERSON_CONTRACTID],
1097
- null, true),
1098
- "atom:link": new ElementInfo("links", null, null, true),
1099
- },
1100
-
1101
- /********* ATOM 0.3 **********/
1102
- "IN_ATOM03": {
1103
- "atom03:author": new ElementInfo("authors", Cc[PERSON_CONTRACTID],
1104
- null, true),
1105
- "atom03:contributor": new ElementInfo("contributors",
1106
- Cc[PERSON_CONTRACTID],
1107
- null, true),
1108
- "atom03:link": new ElementInfo("links", null, null, true),
1109
- "atom03:entry": new ElementInfo("atom03_entries", Cc[ENTRY_CONTRACTID],
1110
- null, true),
1111
- "atom03:generator": new ElementInfo("generator", Cc[GENERATOR_CONTRACTID],
1112
- atomGenerator, false),
1113
- },
1114
-
1115
- "IN_ATOM03_ENTRIES": {
1116
- "atom03:author": new ElementInfo("authors", Cc[PERSON_CONTRACTID],
1117
- null, true),
1118
- "atom03:contributor": new ElementInfo("contributors",
1119
- Cc[PERSON_CONTRACTID],
1120
- null, true),
1121
- "atom03:link": new ElementInfo("links", null, null, true),
1122
- "atom03:entry": new ElementInfo("atom03_entries", Cc[ENTRY_CONTRACTID],
1123
- null, true)
1124
- }
1125
- }
1126
- }
1127
-
1128
- // See startElement for a long description of how feeds are processed.
1129
- FeedProcessor.prototype = {
1130
-
1131
- // Set ourselves as the SAX handler, and set the base URI
1132
- _init: function FP_init(uri) {
1133
- this._reader.contentHandler = this;
1134
- this._reader.errorHandler = this;
1135
- this._result = Cc[FR_CONTRACTID].createInstance(Ci.nsIFeedResult);
1136
- if (uri) {
1137
- this._result.uri = uri;
1138
- this._reader.baseURI = uri;
1139
- this._xmlBaseStack[0] = uri;
1140
- }
1141
- },
1142
-
1143
- // This function is called once we figure out what type of feed
1144
- // we're dealing with. Some feed types require digging a bit further
1145
- // than the root.
1146
- _docVerified: function FP_docVerified(version) {
1147
- this._result.doc = Cc[FEED_CONTRACTID].createInstance(Ci.nsIFeed);
1148
- this._result.doc.baseURI =
1149
- this._xmlBaseStack[this._xmlBaseStack.length - 1];
1150
- this._result.doc.fields = this._feed;
1151
- this._result.version = version;
1152
- },
1153
-
1154
- // When we're done with the feed, let the listener know what
1155
- // happened.
1156
- _sendResult: function FP_sendResult() {
1157
- try {
1158
- // Can be null when a non-feed is fed to us
1159
- if (this._result.doc)
1160
- this._result.doc.normalize();
1161
- }
1162
- catch (e) {
1163
- LOG("FIXME: " + e);
1164
- }
1165
-
1166
- try {
1167
- if (this.listener != null)
1168
- this.listener.handleResult(this._result);
1169
- }
1170
- finally {
1171
- this._result = null;
1172
- this._reader = null;
1173
- }
1174
- },
1175
-
1176
- // Parsing functions
1177
- parseFromStream: function FP_parseFromStream(stream, uri) {
1178
- this._init(uri);
1179
- this._reader.parseFromStream(stream, null, stream.available(),
1180
- "application/xml");
1181
- this._reader = null;
1182
- },
1183
-
1184
- parseFromString: function FP_parseFromString(inputString, uri) {
1185
- this._init(uri);
1186
- this._reader.parseFromString(inputString, "application/xml");
1187
- this._reader = null;
1188
- },
1189
-
1190
- parseAsync: function FP_parseAsync(requestObserver, uri) {
1191
- this._init(uri);
1192
- this._reader.parseAsync(requestObserver);
1193
- },
1194
-
1195
- // nsIStreamListener
1196
-
1197
- // The XMLReader will throw sensible exceptions if these get called
1198
- // out of order.
1199
- onStartRequest: function FP_onStartRequest(request, context) {
1200
- this._reader.onStartRequest(request, context);
1201
- },
1202
-
1203
- onStopRequest: function FP_onStopRequest(request, context, statusCode) {
1204
- this._reader.onStopRequest(request, context, statusCode);
1205
- },
1206
-
1207
- onDataAvailable:
1208
- function FP_onDataAvailable(request, context, inputStream, offset, count) {
1209
- this._reader.onDataAvailable(request, context, inputStream, offset, count);
1210
- },
1211
-
1212
- // nsISAXErrorHandler
1213
-
1214
- // We only care about fatal errors. When this happens, we may have
1215
- // parsed through the feed metadata and some number of entries. The
1216
- // listener can still show some of that data if it wants, and we'll
1217
- // set the bozo bit to indicate we were unable to parse all the way
1218
- // through.
1219
- fatalError: function FP_reportError() {
1220
- this._result.bozo = true;
1221
- //XXX need to QI to FeedProgressListener
1222
- this._sendResult();
1223
- },
1224
-
1225
- // nsISAXContentHandler
1226
-
1227
- startDocument: function FP_startDocument() {
1228
- //LOG("----------");
1229
- },
1230
-
1231
- endDocument: function FP_endDocument() {
1232
- this._sendResult();
1233
- },
1234
-
1235
- // The transitions defined above identify elements that contain more
1236
- // than just text. For example RSS items contain many fields, and so
1237
- // do Atom authors. The only commonly used elements that contain
1238
- // mixed content are Atom Text Constructs of type="xhtml", which we
1239
- // delegate to another handler for cleaning. That leaves a couple
1240
- // different types of elements to deal with: those that should occur
1241
- // only once, such as title elements, and those that can occur
1242
- // multiple times, such as the RSS category element and the Atom
1243
- // link element. Most of the RSS1/DC elements can occur multiple
1244
- // times in theory, but in practice, the only ones that do have
1245
- // analogues in Atom.
1246
- //
1247
- // Some elements are also groups of attributes or sub-elements,
1248
- // while others are simple text fields. For the most part, we don't
1249
- // have to pay explicit attention to the simple text elements,
1250
- // unless we want to post-process the resulting string to transform
1251
- // it into some richer object like a Date or URI.
1252
- //
1253
- // Elements that have more sophisticated content models still end up
1254
- // being dictionaries, whether they are based on attributes like RSS
1255
- // cloud, sub-elements like Atom author, or even items and
1256
- // entries. These elements are treated as "containers". It's
1257
- // theoretically possible for a container to have an attribute with
1258
- // the same universal name as a sub-element, but none of the feed
1259
- // formats allow this by default, and I don't of any extension that
1260
- // works this way.
1261
- //
1262
- startElement: function FP_startElement(uri, localName, qName, attributes) {
1263
- this._buf = "";
1264
- ++this._depth;
1265
- var elementInfo;
1266
-
1267
- //LOG("<" + localName + ">");
1268
-
1269
- // Check for xml:base
1270
- var base = attributes.getValueFromName(XMLNS, "base");
1271
- if (base) {
1272
- this._xmlBaseStack[this._depth] =
1273
- strToURI(base, this._xmlBaseStack[this._xmlBaseStack.length - 1]);
1274
- }
1275
-
1276
- // To identify the element we're dealing with, we look up the
1277
- // namespace URI in our gNamespaces dictionary, which will give us
1278
- // a "canonical" prefix for a namespace URI. For example, this
1279
- // allows Dublin Core "creator" elements to be consistently mapped
1280
- // to "dc:creator", for easy field access by consumer code. This
1281
- // strategy also happens to shorten up our state table.
1282
- var key = this._prefixForNS(uri) + localName;
1283
-
1284
- // Check to see if we need to hand this off to our XHTML handler.
1285
- // The elements we're dealing with will look like this:
1286
- //
1287
- // <title type="xhtml">
1288
- // <div xmlns="http://www.w3.org/1999/xhtml">
1289
- // A title with <b>bold</b> and <i>italics</i>.
1290
- // </div>
1291
- // </title>
1292
- //
1293
- // When it returns in returnFromXHTMLHandler, the handler should
1294
- // give us back a string like this:
1295
- //
1296
- // "A title with <b>bold</b> and <i>italics</i>."
1297
- //
1298
- // The Atom spec explicitly says the div is not part of the content,
1299
- // and explicitly allows whitespace collapsing.
1300
- //
1301
- if ((this._result.version == "atom" || this._result.version == "atom03") &&
1302
- this._textConstructs[key] != null) {
1303
- var type = attributes.getValueFromName("","type");
1304
- if (type != null && type.indexOf("xhtml") >= 0) {
1305
- this._xhtmlHandler =
1306
- new XHTMLHandler(this, (this._result.version == "atom"));
1307
- this._reader.contentHandler = this._xhtmlHandler;
1308
- return;
1309
- }
1310
- }
1311
-
1312
- // Check our current state, and see if that state has a defined
1313
- // transition. For example, this._trans["atom:entry"]["atom:author"]
1314
- // will have one, and it tells us to add an item to our authors array.
1315
- if (this._trans[this._state] && this._trans[this._state][key]) {
1316
- elementInfo = this._trans[this._state][key];
1317
- }
1318
- else {
1319
- // If we don't have a transition, hand off to extension handler
1320
- this._extensionHandler = new ExtensionHandler(this);
1321
- this._reader.contentHandler = this._extensionHandler;
1322
- this._extensionHandler.startElement(uri, localName, qName, attributes);
1323
- return;
1324
- }
1325
-
1326
- // This distinguishes wrappers like 'channel' from elements
1327
- // we'd actually like to do something with (which will test true).
1328
- this._handlerStack[this._depth] = elementInfo;
1329
- if (elementInfo.isWrapper) {
1330
- this._state = "IN_" + elementInfo.fieldName.toUpperCase();
1331
- this._stack.push([this._feed, this._state]);
1332
- }
1333
- else if (elementInfo.feedVersion) {
1334
- this._state = "IN_" + elementInfo.fieldName.toUpperCase();
1335
-
1336
- // Check for the older RSS2 variants
1337
- if (elementInfo.feedVersion == "rss2")
1338
- elementInfo.feedVersion = this._findRSSVersion(attributes);
1339
- else if (uri == RSS090NS)
1340
- elementInfo.feedVersion = "rss090";
1341
-
1342
- this._docVerified(elementInfo.feedVersion);
1343
- this._stack.push([this._feed, this._state]);
1344
- this._mapAttributes(this._feed, attributes);
1345
- }
1346
- else {
1347
- this._state = this._processComplexElement(elementInfo, attributes);
1348
- }
1349
- },
1350
-
1351
- // In the endElement handler, we decrement the stack and look
1352
- // for cleanup/transition functions to execute. The second part
1353
- // of the state transition works as above in startElement, but
1354
- // the state we're looking for is prefixed with an underscore
1355
- // to distinguish endElement events from startElement events.
1356
- endElement: function FP_endElement(uri, localName, qName) {
1357
- var elementInfo = this._handlerStack[this._depth];
1358
- //LOG("</" + localName + ">");
1359
- if (elementInfo && !elementInfo.isWrapper)
1360
- this._closeComplexElement(elementInfo);
1361
-
1362
- // cut down xml:base context
1363
- if (this._xmlBaseStack.length == this._depth + 1)
1364
- this._xmlBaseStack = this._xmlBaseStack.slice(0, this._depth);
1365
-
1366
- // our new state is whatever is at the top of the stack now
1367
- if (this._stack.length > 0)
1368
- this._state = this._stack[this._stack.length - 1][1];
1369
- this._handlerStack = this._handlerStack.slice(0, this._depth);
1370
- --this._depth;
1371
- },
1372
-
1373
- // Buffer up character data. The buffer is cleared with every
1374
- // opening element.
1375
- characters: function FP_characters(data) {
1376
- this._buf += data;
1377
- },
1378
-
1379
- // TODO: It would be nice to check new prefixes here, and if they
1380
- // don't conflict with the ones we've defined, throw them in a
1381
- // dictionary to check.
1382
- startPrefixMapping: function FP_startPrefixMapping() {
1383
- },
1384
- endPrefixMapping: function FP_endPrefixMapping() {
1385
- },
1386
- processingInstruction: function FP_processingInstruction(target, data) {
1387
- if (target == "xml-stylesheet") {
1388
- var hrefAttribute = data.match(/href=[\"\'](.*?)[\"\']/);
1389
- if (hrefAttribute && hrefAttribute.length == 2)
1390
- this._result.stylesheet = gIoService.newURI(hrefAttribute[1], null,
1391
- this._result.uri);
1392
- }
1393
- },
1394
-
1395
- // end of nsISAXContentHandler
1396
-
1397
- // Handle our more complicated elements--those that contain
1398
- // attributes and child elements.
1399
- _processComplexElement:
1400
- function FP__processComplexElement(elementInfo, attributes) {
1401
- var obj, key, prefix;
1402
-
1403
- // If the container is an entry/item, it'll need to have its
1404
- // more esoteric properties put in the 'fields' property bag.
1405
- if (elementInfo.containerClass == Cc[ENTRY_CONTRACTID]) {
1406
- obj = elementInfo.containerClass.createInstance(Ci.nsIFeedEntry);
1407
- obj.baseURI = this._xmlBaseStack[this._xmlBaseStack.length - 1];
1408
- this._mapAttributes(obj.fields, attributes);
1409
- }
1410
- else if (elementInfo.containerClass) {
1411
- obj = elementInfo.containerClass.createInstance(Ci.nsIFeedElementBase);
1412
- obj.baseURI = this._xmlBaseStack[this._xmlBaseStack.length - 1];
1413
- obj.attributes = attributes; // just set the SAX attributes
1414
- }
1415
- else {
1416
- obj = Cc[BAG_CONTRACTID].createInstance(Ci.nsIWritablePropertyBag2);
1417
- this._mapAttributes(obj, attributes);
1418
- }
1419
-
1420
- // We should have a container/propertyBag that's had its
1421
- // attributes processed. Now we need to attach it to its
1422
- // container.
1423
- var newProp;
1424
-
1425
- // First we'll see what's on top of the stack.
1426
- var container = this._stack[this._stack.length - 1][0];
1427
-
1428
- // Check to see if it has the property
1429
- var prop;
1430
- try {
1431
- prop = container.getProperty(elementInfo.fieldName);
1432
- }
1433
- catch(e) {
1434
- }
1435
-
1436
- if (elementInfo.isArray) {
1437
- if (!prop) {
1438
- container.setPropertyAsInterface(elementInfo.fieldName,
1439
- Cc[ARRAY_CONTRACTID].
1440
- createInstance(Ci.nsIMutableArray));
1441
- }
1442
-
1443
- newProp = container.getProperty(elementInfo.fieldName);
1444
- // XXX This QI should not be necessary, but XPConnect seems to fly
1445
- // off the handle in the browser, and loses track of the interface
1446
- // on large files. Bug 335638.
1447
- newProp.QueryInterface(Ci.nsIMutableArray);
1448
- newProp.appendElement(obj,false);
1449
-
1450
- // If new object is an nsIFeedContainer, we want to deal with
1451
- // its member nsIPropertyBag instead.
1452
- if (isIFeedContainer(obj))
1453
- newProp = obj.fields;
1454
-
1455
- }
1456
- else {
1457
- // If it doesn't, set it.
1458
- if (!prop) {
1459
- container.setPropertyAsInterface(elementInfo.fieldName,obj);
1460
- }
1461
- newProp = container.getProperty(elementInfo.fieldName);
1462
- }
1463
-
1464
- // make our new state name, and push the property onto the stack
1465
- var newState = "IN_" + elementInfo.fieldName.toUpperCase();
1466
- this._stack.push([newProp, newState, obj]);
1467
- return newState;
1468
- },
1469
-
1470
- // Sometimes we need reconcile the element content with the object
1471
- // model for a given feed. We use helper functions to do the
1472
- // munging, but we need to identify array types here, so the munging
1473
- // happens only to the last element of an array.
1474
- _closeComplexElement: function FP__closeComplexElement(elementInfo) {
1475
- var stateTuple = this._stack.pop();
1476
- var container = stateTuple[0];
1477
- var containerParent = stateTuple[2];
1478
- var element = null;
1479
- var isArray = isIArray(container);
1480
-
1481
- // If it's an array and we have to post-process,
1482
- // grab the last element
1483
- if (isArray)
1484
- element = container.queryElementAt(container.length - 1, Ci.nsISupports);
1485
- else
1486
- element = container;
1487
-
1488
- // Run the post-processing function if there is one.
1489
- if (elementInfo.closeFunc)
1490
- element = elementInfo.closeFunc(this._buf, element);
1491
-
1492
- // If an nsIFeedContainer was on top of the stack,
1493
- // we need to normalize it
1494
- if (elementInfo.containerClass == Cc[ENTRY_CONTRACTID])
1495
- containerParent.normalize();
1496
-
1497
- // If it's an array, re-set the last element
1498
- if (isArray)
1499
- container.replaceElementAt(element, container.length - 1, false);
1500
- },
1501
-
1502
- _prefixForNS: function FP_prefixForNS(uri) {
1503
- if (!uri)
1504
- return "";
1505
- var prefix = gNamespaces[uri];
1506
- if (prefix)
1507
- return prefix + ":";
1508
- if (uri.toLowerCase().indexOf("http://backend.userland.com") == 0)
1509
- return "";
1510
- else
1511
- return null;
1512
- },
1513
-
1514
- _mapAttributes: function FP__mapAttributes(bag, attributes) {
1515
- // Cycle through the attributes, and set our properties using the
1516
- // prefix:localNames we find in our namespace dictionary.
1517
- for (var i = 0; i < attributes.length; ++i) {
1518
- var key = this._prefixForNS(attributes.getURI(i)) + attributes.getLocalName(i);
1519
- var val = attributes.getValue(i);
1520
- bag.setPropertyAsAString(key, val);
1521
- }
1522
- },
1523
-
1524
- // Only for RSS2esque formats
1525
- _findRSSVersion: function FP__findRSSVersion(attributes) {
1526
- var versionAttr = trimString(attributes.getValueFromName("", "version"));
1527
- var versions = { "0.91":"rss091",
1528
- "0.92":"rss092",
1529
- "0.93":"rss093",
1530
- "0.94":"rss094" }
1531
- if (versions[versionAttr])
1532
- return versions[versionAttr];
1533
- if (versionAttr.substr(0,2) != "2.")
1534
- return "rssUnknown";
1535
- return "rss2";
1536
- },
1537
-
1538
- // unknown element values are returned here. See startElement above
1539
- // for how this works.
1540
- returnFromExtHandler:
1541
- function FP_returnExt(uri, localName, chars, attributes) {
1542
- --this._depth;
1543
-
1544
- // take control of the SAX events
1545
- this._reader.contentHandler = this;
1546
- if (localName == null && chars == null)
1547
- return;
1548
-
1549
- // we don't take random elements inside rdf:RDF
1550
- if (this._state == "IN_RDF")
1551
- return;
1552
-
1553
- // Grab the top of the stack
1554
- var top = this._stack[this._stack.length - 1];
1555
- if (!top)
1556
- return;
1557
-
1558
- var container = top[0];
1559
- // Grab the last element if it's an array
1560
- if (isIArray(container)) {
1561
- var contract = this._handlerStack[this._depth].containerClass;
1562
- // check if it's something specific, but not an entry
1563
- if (contract && contract != Cc[ENTRY_CONTRACTID]) {
1564
- var el = container.queryElementAt(container.length - 1,
1565
- Ci.nsIFeedElementBase);
1566
- // XXX there must be a way to flatten these interfaces
1567
- if (contract == Cc[PERSON_CONTRACTID])
1568
- el.QueryInterface(Ci.nsIFeedPerson);
1569
- else
1570
- return; // don't know about this interface
1571
-
1572
- var propName = localName;
1573
- var prefix = gNamespaces[uri];
1574
-
1575
- // synonyms
1576
- if ((uri == "" ||
1577
- prefix &&
1578
- ((prefix.indexOf("atom") > -1) ||
1579
- (prefix.indexOf("rss") > -1))) &&
1580
- (propName == "url" || propName == "href"))
1581
- propName = "uri";
1582
-
1583
- try {
1584
- if (el[propName] !== "undefined") {
1585
- var propValue = chars;
1586
- // convert URI-bearing values to an nsIURI
1587
- if (propName == "uri") {
1588
- var base = this._xmlBaseStack[this._xmlBaseStack.length - 1];
1589
- propValue = strToURI(chars, base);
1590
- }
1591
- el[propName] = propValue;
1592
- }
1593
- }
1594
- catch(e) {
1595
- // ignore XPConnect errors
1596
- }
1597
- // the rest of the function deals with entry- and feed-level stuff
1598
- return;
1599
- }
1600
- else {
1601
- container = container.queryElementAt(container.length - 1,
1602
- Ci.nsIWritablePropertyBag2);
1603
- }
1604
- }
1605
-
1606
- // Make the buffer our new property
1607
- var propName = this._prefixForNS(uri) + localName;
1608
-
1609
- // But, it could be something containing HTML. If so,
1610
- // we need to know about that.
1611
- if (this._textConstructs[propName] != null &&
1612
- this._handlerStack[this._depth].containerClass !== null) {
1613
- var newProp = Cc[TEXTCONSTRUCT_CONTRACTID].
1614
- createInstance(Ci.nsIFeedTextConstruct);
1615
- newProp.text = chars;
1616
- // Look up the default type in our table
1617
- var type = this._textConstructs[propName];
1618
- var typeAttribute = attributes.getValueFromName("","type");
1619
- if (this._result.version == "atom" && typeAttribute != null) {
1620
- type = typeAttribute;
1621
- }
1622
- else if (this._result.version == "atom03" && typeAttribute != null) {
1623
- if (typeAttribute.toLowerCase().indexOf("xhtml") >= 0) {
1624
- type = "xhtml";
1625
- }
1626
- else if (typeAttribute.toLowerCase().indexOf("html") >= 0) {
1627
- type = "html";
1628
- }
1629
- else if (typeAttribute.toLowerCase().indexOf("text") >= 0) {
1630
- type = "text";
1631
- }
1632
- }
1633
-
1634
- // If it's rss feed-level description, it's not supposed to have html
1635
- if (this._result.version.indexOf("rss") >= 0 &&
1636
- this._handlerStack[this._depth].containerClass != ENTRY_CONTRACTID) {
1637
- type = "text";
1638
- }
1639
-
1640
- newProp.type = type;
1641
- newProp.base = this._xmlBaseStack[this._xmlBaseStack.length - 1];
1642
- container.setPropertyAsInterface(propName, newProp);
1643
- }
1644
- else {
1645
- container.setPropertyAsAString(propName, chars);
1646
- }
1647
-
1648
- },
1649
-
1650
- // Sometimes, we'll hand off SAX handling duties to an XHTMLHandler
1651
- // (see above) that will scrape out non-XHTML stuff, normalize
1652
- // namespaces, and remove the wrapper div from Atom 1.0. When the
1653
- // XHTMLHandler is done, it'll callback here.
1654
- returnFromXHTMLHandler:
1655
- function FP_returnFromXHTMLHandler(chars, uri, localName, qName) {
1656
- // retake control of the SAX content events
1657
- this._reader.contentHandler = this;
1658
-
1659
- // Grab the top of the stack
1660
- var top = this._stack[this._stack.length - 1];
1661
- if (!top)
1662
- return;
1663
- var container = top[0];
1664
-
1665
- // Assign the property
1666
- var newProp = newProp = Cc[TEXTCONSTRUCT_CONTRACTID].
1667
- createInstance(Ci.nsIFeedTextConstruct);
1668
- newProp.text = chars;
1669
- newProp.type = "xhtml";
1670
- newProp.base = this._xmlBaseStack[this._xmlBaseStack.length - 1];
1671
- container.setPropertyAsInterface(this._prefixForNS(uri) + localName,
1672
- newProp);
1673
-
1674
- // XHTML will cause us to peek too far. The XHTML handler will
1675
- // send us an end element to call. RFC4287-valid feeds allow a
1676
- // more graceful way to handle this. Unfortunately, we can't count
1677
- // on compliance at this point.
1678
- this.endElement(uri, localName, qName);
1679
- },
1680
-
1681
- // nsISupports
1682
- QueryInterface: function FP_QueryInterface(iid) {
1683
- if (iid.equals(Ci.nsIFeedProcessor) ||
1684
- iid.equals(Ci.nsISAXContentHandler) ||
1685
- iid.equals(Ci.nsISAXErrorHandler) ||
1686
- iid.equals(Ci.nsIStreamListener) ||
1687
- iid.equals(Ci.nsIRequestObserver) ||
1688
- iid.equals(Ci.nsISupports))
1689
- return this;
1690
-
1691
- throw Cr.NS_ERROR_NOINTERFACE;
1692
- },
1693
- }
1694
-
1695
- const FP_CONTRACTID = "@mozilla.org/feed-processor;1";
1696
- const FP_CLASSID = Components.ID("{26acb1f0-28fc-43bc-867a-a46aabc85dd4}");
1697
- const FP_CLASSNAME = "Feed Processor";
1698
- const FR_CONTRACTID = "@mozilla.org/feed-result;1";
1699
- const FR_CLASSID = Components.ID("{072a5c3d-30c6-4f07-b87f-9f63d51403f2}");
1700
- const FR_CLASSNAME = "Feed Result";
1701
- const FEED_CONTRACTID = "@mozilla.org/feed;1";
1702
- const FEED_CLASSID = Components.ID("{5d0cfa97-69dd-4e5e-ac84-f253162e8f9a}");
1703
- const FEED_CLASSNAME = "Feed";
1704
- const ENTRY_CONTRACTID = "@mozilla.org/feed-entry;1";
1705
- const ENTRY_CLASSID = Components.ID("{8e4444ff-8e99-4bdd-aa7f-fb3c1c77319f}");
1706
- const ENTRY_CLASSNAME = "Feed Entry";
1707
- const TEXTCONSTRUCT_CONTRACTID = "@mozilla.org/feed-textconstruct;1";
1708
- const TEXTCONSTRUCT_CLASSID =
1709
- Components.ID("{b992ddcd-3899-4320-9909-924b3e72c922}");
1710
- const TEXTCONSTRUCT_CLASSNAME = "Feed Text Construct";
1711
- const GENERATOR_CONTRACTID = "@mozilla.org/feed-generator;1";
1712
- const GENERATOR_CLASSID =
1713
- Components.ID("{414af362-9ad8-4296-898e-62247f25a20e}");
1714
- const GENERATOR_CLASSNAME = "Feed Generator";
1715
- const PERSON_CONTRACTID = "@mozilla.org/feed-person;1";
1716
- const PERSON_CLASSID = Components.ID("{95c963b7-20b2-11db-92f6-001422106990}");
1717
- const PERSON_CLASSNAME = "Feed Person";
1718
-
1719
- function GenericComponentFactory(ctor) {
1720
- this._ctor = ctor;
1721
- }
1722
-
1723
- GenericComponentFactory.prototype = {
1724
-
1725
- _ctor: null,
1726
-
1727
- // nsIFactory
1728
- createInstance: function(outer, iid) {
1729
- if (outer != null)
1730
- throw Cr.NS_ERROR_NO_AGGREGATION;
1731
- return (new this._ctor()).QueryInterface(iid);
1732
- },
1733
-
1734
- // nsISupports
1735
- QueryInterface: function(iid) {
1736
- if (iid.equals(Ci.nsIFactory) ||
1737
- iid.equals(Ci.nsISupports))
1738
- return this;
1739
- throw Cr.NS_ERROR_NO_INTERFACE;
1740
- },
1741
-
1742
- };
1743
-
1744
- var Module = {
1745
- QueryInterface: function(iid) {
1746
- if (iid.equals(Ci.nsIModule) ||
1747
- iid.equals(Ci.nsISupports))
1748
- return this;
1749
-
1750
- throw Cr.NS_ERROR_NO_INTERFACE;
1751
- },
1752
-
1753
- getClassObject: function(cm, cid, iid) {
1754
- if (!iid.equals(Ci.nsIFactory))
1755
- throw Cr.NS_ERROR_NOT_IMPLEMENTED;
1756
-
1757
- if (cid.equals(FP_CLASSID))
1758
- return new GenericComponentFactory(FeedProcessor);
1759
- if (cid.equals(FR_CLASSID))
1760
- return new GenericComponentFactory(FeedResult);
1761
- if (cid.equals(FEED_CLASSID))
1762
- return new GenericComponentFactory(Feed);
1763
- if (cid.equals(ENTRY_CLASSID))
1764
- return new GenericComponentFactory(Entry);
1765
- if (cid.equals(TEXTCONSTRUCT_CLASSID))
1766
- return new GenericComponentFactory(TextConstruct);
1767
- if (cid.equals(GENERATOR_CLASSID))
1768
- return new GenericComponentFactory(Generator);
1769
- if (cid.equals(PERSON_CLASSID))
1770
- return new GenericComponentFactory(Person);
1771
-
1772
- throw Cr.NS_ERROR_NO_INTERFACE;
1773
- },
1774
-
1775
- registerSelf: function(cm, file, location, type) {
1776
- var cr = cm.QueryInterface(Ci.nsIComponentRegistrar);
1777
- // Feed Processor
1778
- cr.registerFactoryLocation(FP_CLASSID, FP_CLASSNAME,
1779
- FP_CONTRACTID, file, location, type);
1780
- // Feed Result
1781
- cr.registerFactoryLocation(FR_CLASSID, FR_CLASSNAME,
1782
- FR_CONTRACTID, file, location, type);
1783
- // Feed
1784
- cr.registerFactoryLocation(FEED_CLASSID, FEED_CLASSNAME,
1785
- FEED_CONTRACTID, file, location, type);
1786
- // Entry
1787
- cr.registerFactoryLocation(ENTRY_CLASSID, ENTRY_CLASSNAME,
1788
- ENTRY_CONTRACTID, file, location, type);
1789
- // Text Construct
1790
- cr.registerFactoryLocation(TEXTCONSTRUCT_CLASSID, TEXTCONSTRUCT_CLASSNAME,
1791
- TEXTCONSTRUCT_CONTRACTID, file, location, type);
1792
- // Generator
1793
- cr.registerFactoryLocation(GENERATOR_CLASSID, GENERATOR_CLASSNAME,
1794
- GENERATOR_CONTRACTID, file, location, type);
1795
- // Person
1796
- cr.registerFactoryLocation(PERSON_CLASSID, PERSON_CLASSNAME,
1797
- PERSON_CONTRACTID, file, location, type);
1798
- },
1799
-
1800
- unregisterSelf: function(cm, location, type) {
1801
- var cr = cm.QueryInterface(Ci.nsIComponentRegistrar);
1802
- // Feed Processor
1803
- cr.unregisterFactoryLocation(FP_CLASSID, location);
1804
- // Feed Result
1805
- cr.unregisterFactoryLocation(FR_CLASSID, location);
1806
- // Feed
1807
- cr.unregisterFactoryLocation(FEED_CLASSID, location);
1808
- // Entry
1809
- cr.unregisterFactoryLocation(ENTRY_CLASSID, location);
1810
- // Text Construct
1811
- cr.unregisterFactoryLocation(TEXTCONSTRUCT_CLASSID, location);
1812
- // Generator
1813
- cr.unregisterFactoryLocation(GENERATOR_CLASSID, location);
1814
- // Person
1815
- cr.unregisterFactoryLocation(PERSON_CLASSID, location);
1816
- },
1817
-
1818
- canUnload: function(cm) {
1819
- return true;
1820
- },
1821
- };
1822
-
1823
- function NSGetModule(cm, file) {
1824
- return Module;
1825
- }