You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

PDFLinkTestCase.java 26KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420
  1. /*
  2. * Licensed to the Apache Software Foundation (ASF) under one or more
  3. * contributor license agreements. See the NOTICE file distributed with
  4. * this work for additional information regarding copyright ownership.
  5. * The ASF licenses this file to You under the Apache License, Version 2.0
  6. * (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. *
  9. * http://www.apache.org/licenses/LICENSE-2.0
  10. *
  11. * Unless required by applicable law or agreed to in writing, software
  12. * distributed under the License is distributed on an "AS IS" BASIS,
  13. * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
  14. * See the License for the specific language governing permissions and
  15. * limitations under the License.
  16. */
  17. /* $Id$ */
  18. package org.apache.fop.pdf;
  19. import java.awt.Dimension;
  20. import java.awt.Rectangle;
  21. import java.io.ByteArrayOutputStream;
  22. import java.io.File;
  23. import java.util.Arrays;
  24. import java.util.Collection;
  25. import java.util.regex.Matcher;
  26. import java.util.regex.Pattern;
  27. import static java.util.regex.Pattern.quote;
  28. import javax.xml.transform.stream.StreamResult;
  29. import org.junit.Assert;
  30. import org.junit.Test;
  31. import org.junit.runner.RunWith;
  32. import org.junit.runners.Parameterized;
  33. import org.junit.runners.Parameterized.Parameters;
  34. import org.apache.fop.apps.FOUserAgent;
  35. import org.apache.fop.apps.FopFactory;
  36. import org.apache.fop.fonts.FontInfo;
  37. import org.apache.fop.render.intermediate.IFContext;
  38. import org.apache.fop.render.intermediate.IFException;
  39. import org.apache.fop.render.intermediate.extensions.Link;
  40. import org.apache.fop.render.intermediate.extensions.URIAction;
  41. import org.apache.fop.render.pdf.PDFDocumentHandler;
  42. @RunWith(Parameterized.class)
  43. public class PDFLinkTestCase {
  44. private String target;
  45. private String expected;
  46. public PDFLinkTestCase(String target, String expected) {
  47. this.target = target;
  48. this.expected = expected;
  49. }
  50. @Parameters
  51. public static Collection links() {
  52. return Arrays.asList(new Object[][] {
  53. // Windows absolute paths
  54. {"c:\\foobar.txt", quote("<< /Type /Filespec /F (c:/foobar.txt)")}, //0
  55. {"c:\\foo bar.txt", quote("<< /Type /Filespec /F (c:/foo bar.txt)")},
  56. {"c:\\foo\\bar.txt", quote("<< /Type /Filespec /F (c:/foo/bar.txt)")},
  57. {"c:\\foo\\bar 2.txt", quote("<< /Type /Filespec /F (c:/foo/bar 2.txt)")},
  58. // Windows absolute paths using "/"
  59. {"c:/foo bar.txt", quote("<< /Type /Filespec /F (c:/foo bar.txt)")}, //4
  60. {"c:/foo/bar.txt", quote("<< /Type /Filespec /F (c:/foo/bar.txt)")},
  61. {"c:/foo/bar 2.txt", quote("<< /Type /Filespec /F (c:/foo/bar 2.txt)")},
  62. // Linux absolute paths
  63. {"/foobar.txt", quote("<< /Type /Filespec /F (/foobar.txt)")}, //7
  64. {"/foo/bar.txt", quote("<< /Type /Filespec /F (/foo/bar.txt)")},
  65. {"/foo/bar 2.txt", quote("<< /Type /Filespec /F (/foo/bar 2.txt)")},
  66. {"/foo bar.txt", quote("<< /Type /Filespec /F (/foo bar.txt)")},
  67. // Relative paths
  68. {"foobar.txt", quote("<< /URI (foobar.txt)")}, //11
  69. {"foo bar.txt", quote("<< /URI (foo%20bar.txt)")},
  70. {"./foobar.txt", quote("<< /URI (./foobar.txt)")},
  71. {"./foo bar.txt", quote("<< /URI (./foo%20bar.txt)")},
  72. {"../foobar.txt", quote("<< /URI (../foobar.txt)")},
  73. {"../foo bar.txt", quote("<< /URI (../foo%20bar.txt)")},
  74. // Windows network paths
  75. {"\\\\foo\\bar.txt", quote("<< /Type /Filespec /F (\\\\\\\\foo\\\\bar.txt)")}, //17
  76. {"\\\\foo\\bar 2.txt", quote("<< /Type /Filespec /F (\\\\\\\\foo\\\\bar 2.txt)")},
  77. {"\\\\foo\\a\\bar.txt", quote("<< /Type /Filespec /F (\\\\\\\\foo\\\\a\\\\bar.txt)")},
  78. {"\\\\foo\\a\\bar 2.txt", quote("<< /Type /Filespec /F (\\\\\\\\foo\\\\a\\\\bar 2.txt)")},
  79. // Windows network path using "/"
  80. {"//foo/a/bar.txt", quote("<< /Type /Filespec /F (\\\\\\\\foo\\\\a\\\\bar.txt)")}, // 21
  81. {"//foo/a/bar 2.txt", quote("<< /Type /Filespec /F (\\\\\\\\foo\\\\a\\\\bar 2.txt)")},
  82. // Non ASCII
  83. // foo bar.txt (unicode)
  84. {"\uFF46\uFF4F\uFF4F\u3000\uFF42\uFF41\uFF52.txt", quote(
  85. "<< /URI (%EF%BD%86%EF%BD%8F%EF%BD%8F%E3%80%80%EF%BD%82%EF%BD%81%EF%BD%92.txt)")}, //23
  86. // c:/foo/foo bar.txt (unicode)
  87. {"c:/foo/\uFF46\uFF4F\uFF4F\u3000\uFF42\uFF41\uFF52.txt", quote(
  88. "<< /Type /Filespec /F "
  89. + "<FEFF0063003A002F0066006F006F002FFF46FF4FFF4F3000FF42FF41FF52002E007400780074> "
  90. + "/UF <FEFF0063003A002F0066006F006F002FFF46FF4FFF4F3000FF42FF41FF52002E007400780074>")},
  91. // \\foo\bar 2\foo bar.txt (unicode)
  92. {"\\\\foo\\bar 2\\\uFF46\uFF4F\uFF4F\u3000\uFF42\uFF41\uFF52.txt", quote("<< /Type /Filespec /F "
  93. + "<FEFF005C005C0066006F006F005C00620061007200200032005CFF46FF4FFF4F3000FF42FF41FF52002E007400780074> "
  94. + "/UF "
  95. + "<FEFF005C005C0066006F006F005C00620061007200200032005CFF46FF4FFF4F3000FF42FF41FF52002E007400780074>")},
  96. // PDF, Windows absolute paths
  97. {"c:\\foobar.pdf", quote("<< /Type /Filespec /F (c:/foobar.pdf)")}, //26
  98. {"c:\\foo bar.pdf", quote("<< /Type /Filespec /F (c:/foo bar.pdf)")},
  99. {"c:\\foo\\bar.pdf", quote("<< /Type /Filespec /F (c:/foo/bar.pdf)")},
  100. {"c:\\foo\\bar 2.pdf", quote("<< /Type /Filespec /F (c:/foo/bar 2.pdf)")},
  101. // PDF, Linux absolute paths
  102. {"/foobar.pdf", quote("<< /Type /Filespec /F (/foobar.pdf)")}, //30
  103. {"/foo bar.pdf", quote("<< /Type /Filespec /F (/foo bar.pdf)")},
  104. {"/foo/bar.pdf", quote("<< /Type /Filespec /F (/foo/bar.pdf)")},
  105. {"/foo/bar 2.pdf", quote("<< /Type /Filespec /F (/foo/bar 2.pdf)")},
  106. // PDF, Relative paths
  107. {"foobar.pdf", quote("<< /URI (foobar.pdf)")}, //34
  108. {"foo bar.pdf", quote("<< /URI (foo%20bar.pdf)")},
  109. {"./foobar.pdf", quote("<< /URI (./foobar.pdf)")},
  110. {"./foo bar.pdf", quote("<< /URI (./foo%20bar.pdf)")},
  111. {"../foobar.pdf", quote("<< /URI (../foobar.pdf)")},
  112. {"../foo bar.pdf", quote("<< /URI (../foo%20bar.pdf)")},
  113. // PDF, Windows network paths
  114. {"\\\\foo\\bar.pdf", quote("<< /Type /Filespec /F (\\\\\\\\foo\\\\bar.pdf)")}, //40
  115. {"\\\\foo\\bar 2.pdf", quote("<< /Type /Filespec /F (\\\\\\\\foo\\\\bar 2.pdf)")},
  116. {"\\\\foo\\a\\bar.pdf", quote("<< /Type /Filespec /F (\\\\\\\\foo\\\\a\\\\bar.pdf)")},
  117. {"\\\\foo\\a\\bar 2.pdf", quote("<< /Type /Filespec /F (\\\\\\\\foo\\\\a\\\\bar 2.pdf)")},
  118. // PDF with fragments, Windows absolute paths
  119. {"c:\\foobar.pdf#page=2", quote("<< /Type /Filespec /F (c:/foobar.pdf)") + ".*" + quote("/S /GoToR") + ".*"
  120. + quote("/D [ 2 /XYZ null null null ]")}, //44
  121. {"c:\\foo bar.pdf#dest=aa", quote("<< /Type /Filespec /F (c:/foo bar.pdf)") + ".*" + quote("/S /GoToR")
  122. + ".*" + quote("/D (aa)")},
  123. {"c:\\foo\\bar.pdf#page=2", quote("<< /Type /Filespec /F (c:/foo/bar.pdf)") + ".*" + quote("/S /GoToR")
  124. + ".*" + quote("/D [ 2 /XYZ null null null ]")},
  125. {"c:\\foo\\bar 2.pdf#dest=aa", quote("<< /Type /Filespec /F (c:/foo/bar 2.pdf)") + ".*" + quote("/S /GoToR")
  126. + ".*" + quote("/D (aa)")},
  127. // PDF with fragments, Windows absolute paths using "/"
  128. {"c:/foo bar.pdf#page=2", quote("<< /Type /Filespec /F (c:/foo bar.pdf)") + ".*" + quote("/S /GoToR")
  129. + ".*" + quote("/D [ 2 /XYZ null null null ]")}, //48
  130. {"c:/foo/bar.pdf#dest=aa", quote("<< /Type /Filespec /F (c:/foo/bar.pdf)") + ".*" + quote("/S /GoToR")
  131. + ".*" + quote("/D (aa)")},
  132. {"c:/foo/bar 2.pdf#page=2", quote("<< /Type /Filespec /F (c:/foo/bar 2.pdf)") + ".*" + quote("/S /GoToR")
  133. + ".*" + quote("/D [ 2 /XYZ null null null ]")},
  134. // PDF with fragments, Linux absolute paths
  135. {"/foobar.pdf#dest=aa", quote("<< /Type /Filespec /F (/foobar.pdf)") + ".*" + quote("/S /GoToR") + ".*"
  136. + quote("/D (aa)")}, //51
  137. {"/foo/bar.pdf#page=2", quote("<< /Type /Filespec /F (/foo/bar.pdf)") + ".*" + quote("/S /GoToR") + ".*"
  138. + quote("/D [ 2 /XYZ null null null ]")},
  139. {"/foo/bar 2.pdf#dest=aa", quote("<< /Type /Filespec /F (/foo/bar 2.pdf)") + ".*" + quote("/S /GoToR")
  140. + ".*" + quote("/D (aa)")},
  141. {"/foo bar.pdf#page=2", quote("<< /Type /Filespec /F (/foo bar.pdf)") + ".*" + quote("/S /GoToR") + ".*"
  142. + quote("/D [ 2 /XYZ null null null ]")},
  143. // PDF with fragments, Relative paths
  144. {"foobar.pdf#dest=aa", quote("<< /URI (foobar.pdf#dest=aa)")}, //55
  145. {"foo bar.pdf#page=2", quote("<< /URI (foo%20bar.pdf#page=2)")},
  146. {"./foobar.pdf#dest=aa", quote("<< /URI (./foobar.pdf#dest=aa)")},
  147. {"./foo bar.pdf#page=2", quote("<< /URI (./foo%20bar.pdf#page=2)")},
  148. {"../foobar.pdf#dest=aa", quote("<< /URI (../foobar.pdf#dest=aa)")},
  149. {"../foo bar.pdf#page=2", quote("<< /URI (../foo%20bar.pdf#page=2)")},
  150. // PDF with fragments, Windows network paths
  151. {"\\\\foo\\bar.pdf#dest=aa", quote("<< /Type /Filespec /F (\\\\\\\\foo\\\\bar.pdf)") + ".*"
  152. + quote("/S /GoToR") + ".*" + quote("/D (aa)")}, //61
  153. {"\\\\foo\\bar 2.pdf#page=2", quote("<< /Type /Filespec /F (\\\\\\\\foo\\\\bar 2.pdf)") + ".*"
  154. + quote("/S /GoToR") + ".*" + quote("/D [ 2 /XYZ null null null ]")},
  155. {"\\\\foo\\a\\bar.pdf#dest=aa", quote("<< /Type /Filespec /F (\\\\\\\\foo\\\\a\\\\bar.pdf)") + ".*"
  156. + quote("/S /GoToR") + ".*" + quote("/D (aa)")},
  157. {"\\\\foo\\a\\bar 2.pdf#page=2", quote("<< /Type /Filespec /F (\\\\\\\\foo\\\\a\\\\bar 2.pdf)") + ".*"
  158. + quote("/S /GoToR") + ".*" + quote("/D [ 2 /XYZ null null null ]")},
  159. // file:// prefix, Windows absolute paths
  160. {"file://c:\\foobar.txt", quote("<< /Type /Filespec /F (c:/foobar.txt)")}, //65
  161. {"file://c:\\foo bar.txt", quote("<< /Type /Filespec /F (c:/foo bar.txt)")},
  162. {"file://c:\\foo\\bar.txt", quote("<< /Type /Filespec /F (c:/foo/bar.txt)")},
  163. {"file://c:\\foo\\bar 2.txt", quote("<< /Type /Filespec /F (c:/foo/bar 2.txt)")},
  164. // file:// prefix, Windows absolute paths using "/"
  165. {"file://c:/foo bar.txt", quote("<< /Type /Filespec /F (c:/foo bar.txt)")}, //69
  166. {"file://c:/foo/bar.txt", quote("<< /Type /Filespec /F (c:/foo/bar.txt)")},
  167. {"file://c:/foo/bar 2.txt", quote("<< /Type /Filespec /F (c:/foo/bar 2.txt)")},
  168. // file:// prefix, Linux absolute paths
  169. {"file:///foobar.txt", quote("<< /Type /Filespec /F (/foobar.txt)")}, //72
  170. {"file:///foo/bar.txt", quote("<< /Type /Filespec /F (/foo/bar.txt)")},
  171. {"file:///foo/bar 2.txt", quote("<< /Type /Filespec /F (/foo/bar 2.txt)")},
  172. {"file:///foo bar.txt", quote("<< /Type /Filespec /F (/foo bar.txt)")},
  173. // file:// prefix, Relative paths
  174. {"file://foobar.txt", quote("<< /Type /Filespec /F (foobar.txt)")}, //76
  175. {"file://foo bar.txt", quote("<< /Type /Filespec /F (foo bar.txt)")},
  176. {"file://./foobar.txt", quote("<< /Type /Filespec /F (./foobar.txt)")},
  177. {"file://./foo bar.txt", quote("<< /Type /Filespec /F (./foo bar.txt)")},
  178. {"file://../foobar.txt", quote("<< /Type /Filespec /F (../foobar.txt)")},
  179. {"file://../foo bar.txt", quote("<< /Type /Filespec /F (../foo bar.txt)")},
  180. // file:// prefix, Windows network paths
  181. {"file://\\\\foo\\bar.txt", quote("<< /Type /Filespec /F (\\\\\\\\foo\\\\bar.txt)")}, //82
  182. {"file://\\\\foo\\bar 2.txt", quote("<< /Type /Filespec /F (\\\\\\\\foo\\\\bar 2.txt)")},
  183. {"file://\\\\foo\\a\\bar.txt", quote("<< /Type /Filespec /F (\\\\\\\\foo\\\\a\\\\bar.txt)")},
  184. {"file://\\\\foo\\a\\bar 2.txt", quote("<< /Type /Filespec /F (\\\\\\\\foo\\\\a\\\\bar 2.txt)")},
  185. // file:// prefix, Windows network path using "/"
  186. {"file:////foo/a/bar.txt", quote("<< /Type /Filespec /F (\\\\\\\\foo\\\\a\\\\bar.txt)")}, // 86
  187. {"file:////foo/a/bar 2.txt", quote("<< /Type /Filespec /F (\\\\\\\\foo\\\\a\\\\bar 2.txt)")},
  188. {"file:////foobar.txt", quote("<< /Type /Filespec /F (\\\\\\\\foobar.txt)")},
  189. // Proper file:// for windows paths
  190. {"file:///c:/foo%20bar.txt", quote("<< /Type /Filespec /F (c:/foo bar.txt)")}, //89
  191. {"file:///c:/foo/bar.txt", quote("<< /Type /Filespec /F (c:/foo/bar.txt)")},
  192. {"file:///c:/foo/bar%202.txt", quote("<< /Type /Filespec /F (c:/foo/bar 2.txt)")},
  193. // Proper file:// for linux paths
  194. {"file:///foo/bar%202.txt", quote("<< /Type /Filespec /F (/foo/bar 2.txt)")}, //92
  195. // file:// PDF, Windows absolute paths
  196. {"file://c:\\foobar.pdf", quote("<< /Type /Filespec /F (c:/foobar.pdf)")}, //93
  197. {"file://c:\\foo bar.pdf", quote("<< /Type /Filespec /F (c:/foo bar.pdf)")},
  198. {"file://c:\\foo\\bar.pdf", quote("<< /Type /Filespec /F (c:/foo/bar.pdf)")},
  199. {"file://c:\\foo\\bar 2.pdf", quote("<< /Type /Filespec /F (c:/foo/bar 2.pdf)")},
  200. // file:// PDF, Linux absolute paths
  201. {"file:///foobar.pdf", quote("<< /Type /Filespec /F (/foobar.pdf)")}, //97
  202. {"file:///foo bar.pdf", quote("<< /Type /Filespec /F (/foo bar.pdf)")},
  203. {"file:///foo/bar.pdf", quote("<< /Type /Filespec /F (/foo/bar.pdf)")},
  204. {"file:///foo/bar 2.pdf", quote("<< /Type /Filespec /F (/foo/bar 2.pdf)")},
  205. // file:// PDF, Relative paths
  206. {"file://foobar.pdf", quote("<< /Type /Filespec /F (foobar.pdf)")}, //101
  207. {"file://foo bar.pdf", quote("<< /Type /Filespec /F (foo bar.pdf)")},
  208. {"file://./foobar.pdf", quote("<< /Type /Filespec /F (./foobar.pdf)")},
  209. {"file://./foo bar.pdf", quote("<< /Type /Filespec /F (./foo bar.pdf)")},
  210. {"file://../foobar.pdf", quote("<< /Type /Filespec /F (../foobar.pdf)")},
  211. {"file://../foo bar.pdf", quote("<< /Type /Filespec /F (../foo bar.pdf)")},
  212. // file:// PDF, Windows network paths
  213. {"file://\\\\foo\\bar.pdf", quote("<< /Type /Filespec /F (\\\\\\\\foo\\\\bar.pdf)")}, //107
  214. {"file://\\\\foo\\bar 2.pdf", quote("<< /Type /Filespec /F (\\\\\\\\foo\\\\bar 2.pdf)")},
  215. {"file://\\\\foo\\a\\bar.pdf", quote("<< /Type /Filespec /F (\\\\\\\\foo\\\\a\\\\bar.pdf)")},
  216. {"file://\\\\foo\\a\\bar 2.pdf", quote("<< /Type /Filespec /F (\\\\\\\\foo\\\\a\\\\bar 2.pdf)")},
  217. // Proper file:// for windows paths
  218. {"file:///c:/foo%20bar.pdf", quote("<< /Type /Filespec /F (c:/foo bar.pdf)")}, //111
  219. {"file:///c:/foo/bar.pdf", quote("<< /Type /Filespec /F (c:/foo/bar.pdf)")},
  220. {"file:///c:/foo/bar%202.pdf", quote("<< /Type /Filespec /F (c:/foo/bar 2.pdf)")},
  221. // Proper file:// PDF, for linux paths
  222. {"file:///foo/bar%202.pdf", quote("<< /Type /Filespec /F (/foo/bar 2.pdf)")}, //114
  223. // file:// PDF with fragments, Windows absolute paths
  224. {"file://c:\\foobar.pdf#page=2", quote("<< /Type /Filespec /F (c:/foobar.pdf)") + ".*"
  225. + quote("/S /GoToR") + ".*" + quote("/D [ 2 /XYZ null null null ]")}, //115
  226. {"file://c:\\foo bar.pdf#dest=aa", quote("<< /Type /Filespec /F (c:/foo bar.pdf)") + ".*"
  227. + quote("/S /GoToR") + ".*" + quote("/D (aa)")},
  228. {"file://c:\\foo\\bar.pdf#page=2", quote("<< /Type /Filespec /F (c:/foo/bar.pdf)") + ".*"
  229. + quote("/S /GoToR") + ".*" + quote("/D [ 2 /XYZ null null null ]")},
  230. {"file://c:\\foo\\bar 2.pdf#dest=aa", quote("<< /Type /Filespec /F (c:/foo/bar 2.pdf)") + ".*"
  231. + quote("/S /GoToR") + ".*" + quote("/D (aa)")},
  232. // file:// PDF with fragments, Windows absolute paths using "/"
  233. {"file://c:/foo bar.pdf#page=2", quote("<< /Type /Filespec /F (c:/foo bar.pdf)") + ".*"
  234. + quote("/S /GoToR") + ".*" + quote("/D [ 2 /XYZ null null null ]")}, //119
  235. {"file://c:/foo/bar.pdf#dest=aa", quote("<< /Type /Filespec /F (c:/foo/bar.pdf)") + ".*"
  236. + quote("/S /GoToR") + ".*" + quote("/D (aa)")},
  237. {"file://c:/foo/bar 2.pdf#page=2", quote("<< /Type /Filespec /F (c:/foo/bar 2.pdf)") + ".*"
  238. + quote("/S /GoToR") + ".*" + quote("/D [ 2 /XYZ null null null ]")},
  239. // file:// PDF with fragments, Linux absolute paths
  240. {"file:///foobar.pdf#dest=aa", quote("<< /Type /Filespec /F (/foobar.pdf)") + ".*"
  241. + quote("/S /GoToR") + ".*" + quote("/D (aa)")}, //122
  242. {"file:///foo/bar.pdf#page=2", quote("<< /Type /Filespec /F (/foo/bar.pdf)") + ".*"
  243. + quote("/S /GoToR") + ".*" + quote("/D [ 2 /XYZ null null null ]")},
  244. {"file:///foo/bar 2.pdf#dest=aa", quote("<< /Type /Filespec /F (/foo/bar 2.pdf)") + ".*"
  245. + quote("/S /GoToR") + ".*" + quote("/D (aa)")},
  246. {"file:///foo bar.pdf#page=2", quote("<< /Type /Filespec /F (/foo bar.pdf)") + ".*"
  247. + quote("/S /GoToR") + ".*" + quote("/D [ 2 /XYZ null null null ]")},
  248. // file:// PDF with fragments, Relative paths
  249. {"file://foobar.pdf#dest=aa", quote("<< /Type /Filespec /F (foobar.pdf)") + ".*"
  250. + quote("/S /GoToR") + ".*" + quote("/D (aa)")}, //126
  251. {"file://foo bar.pdf#page=2", quote("<< /Type /Filespec /F (foo bar.pdf)") + ".*"
  252. + quote("/S /GoToR") + ".*" + quote("/D [ 2 /XYZ null null null ]")},
  253. {"file://./foobar.pdf#dest=aa", quote("<< /Type /Filespec /F (./foobar.pdf)") + ".*"
  254. + quote("/S /GoToR") + ".*" + quote("/D (aa)")},
  255. {"file://./foo bar.pdf#page=2", quote("<< /Type /Filespec /F (./foo bar.pdf)") + ".*"
  256. + quote("/S /GoToR") + ".*" + quote("/D [ 2 /XYZ null null null ]")},
  257. {"file://../foobar.pdf#dest=aa", quote("<< /Type /Filespec /F (../foobar.pdf)") + ".*"
  258. + quote("/S /GoToR") + ".*" + quote("/D (aa)")},
  259. {"file://../foo bar.pdf#page=2", quote("<< /Type /Filespec /F (../foo bar.pdf)") + ".*"
  260. + quote("/S /GoToR") + ".*" + quote("/D [ 2 /XYZ null null null ]")},
  261. // file:// PDF with fragments, Windows network paths
  262. {"file://\\\\foo\\bar.pdf#dest=aa", quote("<< /Type /Filespec /F (\\\\\\\\foo\\\\bar.pdf)") + ".*"
  263. + quote("/S /GoToR") + ".*" + quote("/D (aa)")}, //132
  264. {"file://\\\\foo\\bar 2.pdf#page=2", quote("<< /Type /Filespec /F (\\\\\\\\foo\\\\bar 2.pdf)")
  265. + ".*" + quote("/S /GoToR") + ".*" + quote("/D [ 2 /XYZ null null null ]")},
  266. {"file://\\\\foo\\a\\bar.pdf#dest=aa", quote("<< /Type /Filespec /F (\\\\\\\\foo\\\\a\\\\bar.pdf)")
  267. + ".*" + quote("/S /GoToR") + ".*" + quote("/D (aa)")},
  268. {"file://\\\\foo\\a\\bar 2.pdf#page=2",
  269. quote("<< /Type /Filespec /F (\\\\\\\\foo\\\\a\\\\bar 2.pdf)") + ".*"
  270. + quote("/S /GoToR") + ".*" + quote("/D [ 2 /XYZ null null null ]")},
  271. // Proper file:// PDF with fragments, Windows network paths
  272. {"file:////foo/bar.pdf#dest=aa", quote("<< /Type /Filespec /F (\\\\\\\\foo\\\\bar.pdf)") + ".*"
  273. + quote("/S /GoToR") + ".*" + quote("/D (aa)")}, //136
  274. {"file:////foo/bar%202.pdf#page=2", quote("<< /Type /Filespec /F (\\\\\\\\foo\\\\bar 2.pdf)") + ".*"
  275. + quote("/S /GoToR") + ".*" + quote("/D [ 2 /XYZ null null null ]")},
  276. {"file:////foo/a/bar.pdf#dest=aa", quote("<< /Type /Filespec /F (\\\\\\\\foo\\\\a\\\\bar.pdf)")
  277. + ".*" + quote("/S /GoToR") + ".*" + quote("/D (aa)")},
  278. {"file:////foo/a/bar%202.pdf#page=2", quote("<< /Type /Filespec /F (\\\\\\\\foo\\\\a\\\\bar 2.pdf)")
  279. + ".*" + quote("/S /GoToR") + ".*" + quote("/D [ 2 /XYZ null null null ]")},
  280. // Proper file:// PDF, for linux paths
  281. {"file:///foo/bar%202.pdf#page=2", quote("<< /Type /Filespec /F (/foo/bar 2.pdf)") + ".*"
  282. + quote("/S /GoToR") + ".*" + quote("/D [ 2 /XYZ null null null ]")}, //140
  283. // file: Relative paths
  284. {"file:foobar.txt", quote("<< /Type /Filespec /F (foobar.txt)")}, //141
  285. {"file:foo bar.txt", quote("<< /Type /Filespec /F (foo bar.txt)")},
  286. {"file:./foobar.txt", quote("<< /Type /Filespec /F (./foobar.txt)")},
  287. {"file:./foo bar.txt", quote("<< /Type /Filespec /F (./foo bar.txt)")},
  288. {"file:../foobar.txt", quote("<< /Type /Filespec /F (../foobar.txt)")},
  289. {"file:../foo bar.txt", quote("<< /Type /Filespec /F (../foo bar.txt)")},
  290. {"file:\uFF46\uFF4F\uFF4F\u3000\uFF42\uFF41\uFF52.txt",
  291. quote("<< /Type /Filespec /F <FEFFFF46FF4FFF4F3000FF42FF41FF52002E007400780074> "
  292. + "/UF <FEFFFF46FF4FFF4F3000FF42FF41FF52002E007400780074>")},
  293. // file: PDF Relative paths
  294. {"file:foobar.pdf", quote("<< /Type /Filespec /F (foobar.pdf)")}, //148
  295. {"file:foo bar.pdf", quote("<< /Type /Filespec /F (foo bar.pdf)")},
  296. {"file:./foobar.pdf", quote("<< /Type /Filespec /F (./foobar.pdf)")},
  297. {"file:./foo bar.pdf", quote("<< /Type /Filespec /F (./foo bar.pdf)")},
  298. {"file:../foobar.pdf", quote("<< /Type /Filespec /F (../foobar.pdf)")},
  299. {"file:../foo bar.pdf", quote("<< /Type /Filespec /F (../foo bar.pdf)")},
  300. // file: PDF with fragments, Relative paths
  301. {"file:foobar.pdf#dest=aa", quote("<< /Type /Filespec /F (foobar.pdf)") + ".*"
  302. + quote("/S /GoToR") + ".*" + quote("/D (aa)")}, //154
  303. {"file:foo bar.pdf#page=2", quote("<< /Type /Filespec /F (foo bar.pdf)") + ".*"
  304. + quote("/S /GoToR") + ".*" + quote("/D [ 2 /XYZ null null null ]")},
  305. {"file:./foobar.pdf#dest=aa", quote("<< /Type /Filespec /F (./foobar.pdf)") + ".*"
  306. + quote("/S /GoToR") + ".*" + quote("/D (aa)")},
  307. {"file:./foo bar.pdf#page=2", quote("<< /Type /Filespec /F (./foo bar.pdf)") + ".*"
  308. + quote("/S /GoToR") + ".*" + quote("/D [ 2 /XYZ null null null ]")},
  309. {"file:../foobar.pdf#dest=aa", quote("<< /Type /Filespec /F (../foobar.pdf)") + ".*"
  310. + quote("/S /GoToR") + ".*" + quote("/D (aa)")},
  311. {"file:../foo bar.pdf#page=2", quote("<< /Type /Filespec /F (../foo bar.pdf)") + ".*"
  312. + quote("/S /GoToR") + ".*" + quote("/D [ 2 /XYZ null null null ]")},
  313. // file: prefix, Windows absolute paths
  314. {"file:c:\\foobar.txt", quote("<< /Type /Filespec /F (c:/foobar.txt)")}, //160
  315. {"file:c:\\foo bar.txt", quote("<< /Type /Filespec /F (c:/foo bar.txt)")},
  316. {"file:c:\\foo\\bar.txt", quote("<< /Type /Filespec /F (c:/foo/bar.txt)")},
  317. {"file:c:\\foo\\bar 2.txt", quote("<< /Type /Filespec /F (c:/foo/bar 2.txt)")},
  318. // PDF, Linux absolute paths
  319. {"file:/foobar.pdf", quote("<< /Type /Filespec /F (/foobar.pdf)")}, //164
  320. {"file:/foo bar.pdf", quote("<< /Type /Filespec /F (/foo bar.pdf)")},
  321. {"file:/foo%20bar.pdf", quote("<< /Type /Filespec /F (/foo bar.pdf)")},
  322. {"file:/foo/bar.pdf", quote("<< /Type /Filespec /F (/foo/bar.pdf)")},
  323. {"file:/foo/bar 2.pdf", quote("<< /Type /Filespec /F (/foo/bar 2.pdf)")},
  324. {"file:/foo/bar%202.pdf", quote("<< /Type /Filespec /F (/foo/bar 2.pdf)")},
  325. // Web links
  326. {"https://xmlgraphics.apache.org/fop/", quote("<< /URI (https://xmlgraphics.apache.org/fop/)")}, //170
  327. {"http://xmlgraphics.apache.org/fop/", quote("<< /URI (http://xmlgraphics.apache.org/fop/)")},
  328. {"https://xmlgraphics.apache.org/fop/examples.html",
  329. quote("<< /URI (https://xmlgraphics.apache.org/fop/examples.html)")},
  330. {"https://xmlgraphics.apache.org/fop/fo/fonts.fo.pdf",
  331. quote("<< /URI (https://xmlgraphics.apache.org/fop/fo/fonts.fo.pdf)")},
  332. {"https://xmlgraphics.apache.org/fop/fo/fonts.fo.pdf#page=2",
  333. quote("<< /URI (https://xmlgraphics.apache.org/fop/fo/fonts.fo.pdf#page=2)")},
  334. {"https://xmlgraphics.apache.org/fop/fo/fonts.fo",
  335. quote("<< /URI (https://xmlgraphics.apache.org/fop/fo/fonts.fo)")},
  336. // HTML files
  337. {"examples.html#foo", quote("<< /URI (examples.html#foo)")}, //177
  338. {"examples.html?foo#bar", quote("/URI (examples.html?foo#bar)")},
  339. {"examples.html", quote("<< /URI (examples.html)")},
  340. {"file:examples.html", quote("<< /Type /Filespec /F (examples.html)")},
  341. // parenthesis
  342. {"simple_report_(version2.pdf", quote("<< /URI (simple_report_\\(version2.pdf)")}
  343. });
  344. }
  345. @Test
  346. public void testLinks() throws IFException {
  347. FOUserAgent ua = FopFactory.newInstance(new File(".").toURI()).newFOUserAgent();
  348. PDFDocumentHandler docHandler = new PDFDocumentHandler(new IFContext(ua));
  349. docHandler.setFontInfo(new FontInfo());
  350. ByteArrayOutputStream out = new ByteArrayOutputStream();
  351. docHandler.setResult(new StreamResult(out));
  352. docHandler.startDocument();
  353. docHandler.startPage(0, "", "", new Dimension());
  354. docHandler.getDocumentNavigationHandler().renderLink(new Link(
  355. new URIAction(target, false), new Rectangle()));
  356. docHandler.endDocument();
  357. // Normalize spaces between word for easier testing
  358. String outString = out.toString().replaceAll("\\s+", " ");
  359. Pattern r = Pattern.compile(expected);
  360. Matcher m = r.matcher(outString);
  361. Assert.assertTrue(m.find());
  362. }
  363. }