| /* |
| * Licensed to the Apache Software Foundation (ASF) under one or more |
| * contributor license agreements. See the NOTICE file distributed with |
| * this work for additional information regarding copyright ownership. |
| * The ASF licenses this file to You under the Apache License, Version 2.0 |
| * (the "License"); you may not use this file except in compliance with |
| * the License. You may obtain a copy of the License at |
| * |
| * http://www.apache.org/licenses/LICENSE-2.0 |
| * |
| * Unless required by applicable law or agreed to in writing, software |
| * distributed under the License is distributed on an "AS IS" BASIS, |
| * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. |
| * See the License for the specific language governing permissions and |
| * limitations under the License. |
| */ |
| |
| /* $Id$ */ |
| |
| package org.apache.fop.pdf; |
| |
| import java.awt.Dimension; |
| import java.awt.Rectangle; |
| import java.io.ByteArrayOutputStream; |
| import java.io.File; |
| import java.util.Arrays; |
| import java.util.Collection; |
| import java.util.regex.Matcher; |
| import java.util.regex.Pattern; |
| |
| import static java.util.regex.Pattern.quote; |
| |
| import javax.xml.transform.stream.StreamResult; |
| |
| import org.junit.Assert; |
| import org.junit.Test; |
| import org.junit.runner.RunWith; |
| import org.junit.runners.Parameterized; |
| import org.junit.runners.Parameterized.Parameters; |
| |
| import org.apache.fop.apps.FOUserAgent; |
| import org.apache.fop.apps.FopFactory; |
| import org.apache.fop.fonts.FontInfo; |
| import org.apache.fop.render.intermediate.IFContext; |
| import org.apache.fop.render.intermediate.IFException; |
| import org.apache.fop.render.intermediate.extensions.Link; |
| import org.apache.fop.render.intermediate.extensions.URIAction; |
| import org.apache.fop.render.pdf.PDFDocumentHandler; |
| |
| @RunWith(Parameterized.class) |
| public class PDFLinkTestCase { |
| private String target; |
| private String expected; |
| |
| public PDFLinkTestCase(String target, String expected) { |
| this.target = target; |
| this.expected = expected; |
| } |
| |
| @Parameters |
| public static Collection links() { |
| return Arrays.asList(new Object[][] { |
| // Windows absolute paths |
| {"c:\\foobar.txt", quote("<< /Type /Filespec /F (c:/foobar.txt)")}, //0 |
| {"c:\\foo bar.txt", quote("<< /Type /Filespec /F (c:/foo bar.txt)")}, |
| {"c:\\foo\\bar.txt", quote("<< /Type /Filespec /F (c:/foo/bar.txt)")}, |
| {"c:\\foo\\bar 2.txt", quote("<< /Type /Filespec /F (c:/foo/bar 2.txt)")}, |
| |
| // Windows absolute paths using "/" |
| {"c:/foo bar.txt", quote("<< /Type /Filespec /F (c:/foo bar.txt)")}, //4 |
| {"c:/foo/bar.txt", quote("<< /Type /Filespec /F (c:/foo/bar.txt)")}, |
| {"c:/foo/bar 2.txt", quote("<< /Type /Filespec /F (c:/foo/bar 2.txt)")}, |
| |
| // Linux absolute paths |
| {"/foobar.txt", quote("<< /Type /Filespec /F (/foobar.txt)")}, //7 |
| {"/foo/bar.txt", quote("<< /Type /Filespec /F (/foo/bar.txt)")}, |
| {"/foo/bar 2.txt", quote("<< /Type /Filespec /F (/foo/bar 2.txt)")}, |
| {"/foo bar.txt", quote("<< /Type /Filespec /F (/foo bar.txt)")}, |
| |
| // Relative paths |
| {"foobar.txt", quote("<< /URI (foobar.txt)")}, //11 |
| {"foo bar.txt", quote("<< /URI (foo%20bar.txt)")}, |
| {"./foobar.txt", quote("<< /URI (./foobar.txt)")}, |
| {"./foo bar.txt", quote("<< /URI (./foo%20bar.txt)")}, |
| {"../foobar.txt", quote("<< /URI (../foobar.txt)")}, |
| {"../foo bar.txt", quote("<< /URI (../foo%20bar.txt)")}, |
| |
| // Windows network paths |
| {"\\\\foo\\bar.txt", quote("<< /Type /Filespec /F (\\\\\\\\foo\\\\bar.txt)")}, //17 |
| {"\\\\foo\\bar 2.txt", quote("<< /Type /Filespec /F (\\\\\\\\foo\\\\bar 2.txt)")}, |
| {"\\\\foo\\a\\bar.txt", quote("<< /Type /Filespec /F (\\\\\\\\foo\\\\a\\\\bar.txt)")}, |
| {"\\\\foo\\a\\bar 2.txt", quote("<< /Type /Filespec /F (\\\\\\\\foo\\\\a\\\\bar 2.txt)")}, |
| |
| // Windows network path using "/" |
| {"//foo/a/bar.txt", quote("<< /Type /Filespec /F (\\\\\\\\foo\\\\a\\\\bar.txt)")}, // 21 |
| {"//foo/a/bar 2.txt", quote("<< /Type /Filespec /F (\\\\\\\\foo\\\\a\\\\bar 2.txt)")}, |
| |
| // Non ASCII |
| // foo bar.txt (unicode) |
| {"\uFF46\uFF4F\uFF4F\u3000\uFF42\uFF41\uFF52.txt", quote( |
| "<< /URI (%EF%BD%86%EF%BD%8F%EF%BD%8F%E3%80%80%EF%BD%82%EF%BD%81%EF%BD%92.txt)")}, //23 |
| // c:/foo/foo bar.txt (unicode) |
| {"c:/foo/\uFF46\uFF4F\uFF4F\u3000\uFF42\uFF41\uFF52.txt", quote( |
| "<< /Type /Filespec /F " |
| + "<FEFF0063003A002F0066006F006F002FFF46FF4FFF4F3000FF42FF41FF52002E007400780074> " |
| + "/UF <FEFF0063003A002F0066006F006F002FFF46FF4FFF4F3000FF42FF41FF52002E007400780074>")}, |
| // \\foo\bar 2\foo bar.txt (unicode) |
| {"\\\\foo\\bar 2\\\uFF46\uFF4F\uFF4F\u3000\uFF42\uFF41\uFF52.txt", quote("<< /Type /Filespec /F " |
| + "<FEFF005C005C0066006F006F005C00620061007200200032005CFF46FF4FFF4F3000FF42FF41FF52002E007400780074> " |
| + "/UF " |
| + "<FEFF005C005C0066006F006F005C00620061007200200032005CFF46FF4FFF4F3000FF42FF41FF52002E007400780074>")}, |
| |
| // PDF, Windows absolute paths |
| {"c:\\foobar.pdf", quote("<< /Type /Filespec /F (c:/foobar.pdf)")}, //26 |
| {"c:\\foo bar.pdf", quote("<< /Type /Filespec /F (c:/foo bar.pdf)")}, |
| {"c:\\foo\\bar.pdf", quote("<< /Type /Filespec /F (c:/foo/bar.pdf)")}, |
| {"c:\\foo\\bar 2.pdf", quote("<< /Type /Filespec /F (c:/foo/bar 2.pdf)")}, |
| |
| // PDF, Linux absolute paths |
| {"/foobar.pdf", quote("<< /Type /Filespec /F (/foobar.pdf)")}, //30 |
| {"/foo bar.pdf", quote("<< /Type /Filespec /F (/foo bar.pdf)")}, |
| {"/foo/bar.pdf", quote("<< /Type /Filespec /F (/foo/bar.pdf)")}, |
| {"/foo/bar 2.pdf", quote("<< /Type /Filespec /F (/foo/bar 2.pdf)")}, |
| |
| // PDF, Relative paths |
| {"foobar.pdf", quote("<< /Type /Filespec /F (foobar.pdf)")}, //34 |
| {"foo bar.pdf", quote("<< /Type /Filespec /F (foo bar.pdf)")}, |
| {"./foobar.pdf", quote("<< /Type /Filespec /F (./foobar.pdf)")}, |
| {"./foo bar.pdf", quote("<< /Type /Filespec /F (./foo bar.pdf)")}, |
| {"../foobar.pdf", quote("<< /Type /Filespec /F (../foobar.pdf)")}, |
| {"../foo bar.pdf", quote("<< /Type /Filespec /F (../foo bar.pdf)")}, |
| |
| // PDF, Windows network paths |
| {"\\\\foo\\bar.pdf", quote("<< /Type /Filespec /F (\\\\\\\\foo\\\\bar.pdf)")}, //40 |
| {"\\\\foo\\bar 2.pdf", quote("<< /Type /Filespec /F (\\\\\\\\foo\\\\bar 2.pdf)")}, |
| {"\\\\foo\\a\\bar.pdf", quote("<< /Type /Filespec /F (\\\\\\\\foo\\\\a\\\\bar.pdf)")}, |
| {"\\\\foo\\a\\bar 2.pdf", quote("<< /Type /Filespec /F (\\\\\\\\foo\\\\a\\\\bar 2.pdf)")}, |
| |
| // PDF with fragments, Windows absolute paths |
| {"c:\\foobar.pdf#page=2", quote("<< /Type /Filespec /F (c:/foobar.pdf)") + ".*" + quote("/S /GoToR") + ".*" |
| + quote("/D [ 2 /XYZ null null null ]")}, //44 |
| {"c:\\foo bar.pdf#dest=aa", quote("<< /Type /Filespec /F (c:/foo bar.pdf)") + ".*" + quote("/S /GoToR") |
| + ".*" + quote("/D (aa)")}, |
| {"c:\\foo\\bar.pdf#page=2", quote("<< /Type /Filespec /F (c:/foo/bar.pdf)") + ".*" + quote("/S /GoToR") |
| + ".*" + quote("/D [ 2 /XYZ null null null ]")}, |
| {"c:\\foo\\bar 2.pdf#dest=aa", quote("<< /Type /Filespec /F (c:/foo/bar 2.pdf)") + ".*" + quote("/S /GoToR") |
| + ".*" + quote("/D (aa)")}, |
| |
| // PDF with fragments, Windows absolute paths using "/" |
| {"c:/foo bar.pdf#page=2", quote("<< /Type /Filespec /F (c:/foo bar.pdf)") + ".*" + quote("/S /GoToR") |
| + ".*" + quote("/D [ 2 /XYZ null null null ]")}, //48 |
| {"c:/foo/bar.pdf#dest=aa", quote("<< /Type /Filespec /F (c:/foo/bar.pdf)") + ".*" + quote("/S /GoToR") |
| + ".*" + quote("/D (aa)")}, |
| {"c:/foo/bar 2.pdf#page=2", quote("<< /Type /Filespec /F (c:/foo/bar 2.pdf)") + ".*" + quote("/S /GoToR") |
| + ".*" + quote("/D [ 2 /XYZ null null null ]")}, |
| |
| // PDF with fragments, Linux absolute paths |
| {"/foobar.pdf#dest=aa", quote("<< /Type /Filespec /F (/foobar.pdf)") + ".*" + quote("/S /GoToR") + ".*" |
| + quote("/D (aa)")}, //51 |
| {"/foo/bar.pdf#page=2", quote("<< /Type /Filespec /F (/foo/bar.pdf)") + ".*" + quote("/S /GoToR") + ".*" |
| + quote("/D [ 2 /XYZ null null null ]")}, |
| {"/foo/bar 2.pdf#dest=aa", quote("<< /Type /Filespec /F (/foo/bar 2.pdf)") + ".*" + quote("/S /GoToR") |
| + ".*" + quote("/D (aa)")}, |
| {"/foo bar.pdf#page=2", quote("<< /Type /Filespec /F (/foo bar.pdf)") + ".*" + quote("/S /GoToR") + ".*" |
| + quote("/D [ 2 /XYZ null null null ]")}, |
| |
| // PDF with fragments, Relative paths |
| {"foobar.pdf#dest=aa", quote("<< /Type /Filespec /F (foobar.pdf)") + ".*" + quote("/S /GoToR") + ".*" |
| + quote("/D (aa)")}, //55 |
| {"foo bar.pdf#page=2", quote("<< /Type /Filespec /F (foo bar.pdf)") + ".*" + quote("/S /GoToR") + ".*" |
| + quote("/D [ 2 /XYZ null null null ]")}, |
| {"./foobar.pdf#dest=aa", quote("<< /Type /Filespec /F (./foobar.pdf)") + ".*" + quote("/S /GoToR") |
| + ".*" + quote("/D (aa)")}, |
| {"./foo bar.pdf#page=2", quote("<< /Type /Filespec /F (./foo bar.pdf)") + ".*" + quote("/S /GoToR") + ".*" |
| + quote("/D [ 2 /XYZ null null null ]")}, |
| {"../foobar.pdf#dest=aa", quote("<< /Type /Filespec /F (../foobar.pdf)") + ".*" + quote("/S /GoToR") |
| + ".*" + quote("/D (aa)")}, |
| {"../foo bar.pdf#page=2", quote("<< /Type /Filespec /F (../foo bar.pdf)") + ".*" + quote("/S /GoToR") + ".*" |
| + quote("/D [ 2 /XYZ null null null ]")}, |
| |
| // PDF with fragments, Windows network paths |
| {"\\\\foo\\bar.pdf#dest=aa", quote("<< /Type /Filespec /F (\\\\\\\\foo\\\\bar.pdf)") + ".*" |
| + quote("/S /GoToR") + ".*" + quote("/D (aa)")}, //61 |
| {"\\\\foo\\bar 2.pdf#page=2", quote("<< /Type /Filespec /F (\\\\\\\\foo\\\\bar 2.pdf)") + ".*" |
| + quote("/S /GoToR") + ".*" + quote("/D [ 2 /XYZ null null null ]")}, |
| {"\\\\foo\\a\\bar.pdf#dest=aa", quote("<< /Type /Filespec /F (\\\\\\\\foo\\\\a\\\\bar.pdf)") + ".*" |
| + quote("/S /GoToR") + ".*" + quote("/D (aa)")}, |
| {"\\\\foo\\a\\bar 2.pdf#page=2", quote("<< /Type /Filespec /F (\\\\\\\\foo\\\\a\\\\bar 2.pdf)") + ".*" |
| + quote("/S /GoToR") + ".*" + quote("/D [ 2 /XYZ null null null ]")}, |
| |
| // file:// prefix, Windows absolute paths |
| {"file://c:\\foobar.txt", quote("<< /Type /Filespec /F (c:/foobar.txt)")}, //65 |
| {"file://c:\\foo bar.txt", quote("<< /Type /Filespec /F (c:/foo bar.txt)")}, |
| {"file://c:\\foo\\bar.txt", quote("<< /Type /Filespec /F (c:/foo/bar.txt)")}, |
| {"file://c:\\foo\\bar 2.txt", quote("<< /Type /Filespec /F (c:/foo/bar 2.txt)")}, |
| |
| // file:// prefix, Windows absolute paths using "/" |
| {"file://c:/foo bar.txt", quote("<< /Type /Filespec /F (c:/foo bar.txt)")}, //69 |
| {"file://c:/foo/bar.txt", quote("<< /Type /Filespec /F (c:/foo/bar.txt)")}, |
| {"file://c:/foo/bar 2.txt", quote("<< /Type /Filespec /F (c:/foo/bar 2.txt)")}, |
| |
| // file:// prefix, Linux absolute paths |
| {"file:///foobar.txt", quote("<< /Type /Filespec /F (/foobar.txt)")}, //72 |
| {"file:///foo/bar.txt", quote("<< /Type /Filespec /F (/foo/bar.txt)")}, |
| {"file:///foo/bar 2.txt", quote("<< /Type /Filespec /F (/foo/bar 2.txt)")}, |
| {"file:///foo bar.txt", quote("<< /Type /Filespec /F (/foo bar.txt)")}, |
| |
| // file:// prefix, Relative paths |
| {"file://foobar.txt", quote("<< /Type /Filespec /F (foobar.txt)")}, //76 |
| {"file://foo bar.txt", quote("<< /Type /Filespec /F (foo bar.txt)")}, |
| {"file://./foobar.txt", quote("<< /Type /Filespec /F (./foobar.txt)")}, |
| {"file://./foo bar.txt", quote("<< /Type /Filespec /F (./foo bar.txt)")}, |
| {"file://../foobar.txt", quote("<< /Type /Filespec /F (../foobar.txt)")}, |
| {"file://../foo bar.txt", quote("<< /Type /Filespec /F (../foo bar.txt)")}, |
| |
| // file:// prefix, Windows network paths |
| {"file://\\\\foo\\bar.txt", quote("<< /Type /Filespec /F (\\\\\\\\foo\\\\bar.txt)")}, //82 |
| {"file://\\\\foo\\bar 2.txt", quote("<< /Type /Filespec /F (\\\\\\\\foo\\\\bar 2.txt)")}, |
| {"file://\\\\foo\\a\\bar.txt", quote("<< /Type /Filespec /F (\\\\\\\\foo\\\\a\\\\bar.txt)")}, |
| {"file://\\\\foo\\a\\bar 2.txt", quote("<< /Type /Filespec /F (\\\\\\\\foo\\\\a\\\\bar 2.txt)")}, |
| |
| // file:// prefix, Windows network path using "/" |
| {"file:////foo/a/bar.txt", quote("<< /Type /Filespec /F (\\\\\\\\foo\\\\a\\\\bar.txt)")}, // 86 |
| {"file:////foo/a/bar 2.txt", quote("<< /Type /Filespec /F (\\\\\\\\foo\\\\a\\\\bar 2.txt)")}, |
| {"file:////foobar.txt", quote("<< /Type /Filespec /F (\\\\\\\\foobar.txt)")}, |
| |
| // Proper file:// for windows paths |
| {"file:///c:/foo%20bar.txt", quote("<< /Type /Filespec /F (c:/foo bar.txt)")}, //89 |
| {"file:///c:/foo/bar.txt", quote("<< /Type /Filespec /F (c:/foo/bar.txt)")}, |
| {"file:///c:/foo/bar%202.txt", quote("<< /Type /Filespec /F (c:/foo/bar 2.txt)")}, |
| |
| // Proper file:// for linux paths |
| {"file:///foo/bar%202.txt", quote("<< /Type /Filespec /F (/foo/bar 2.txt)")}, //92 |
| |
| // file:// PDF, Windows absolute paths |
| {"file://c:\\foobar.pdf", quote("<< /Type /Filespec /F (c:/foobar.pdf)")}, //93 |
| {"file://c:\\foo bar.pdf", quote("<< /Type /Filespec /F (c:/foo bar.pdf)")}, |
| {"file://c:\\foo\\bar.pdf", quote("<< /Type /Filespec /F (c:/foo/bar.pdf)")}, |
| {"file://c:\\foo\\bar 2.pdf", quote("<< /Type /Filespec /F (c:/foo/bar 2.pdf)")}, |
| |
| // file:// PDF, Linux absolute paths |
| {"file:///foobar.pdf", quote("<< /Type /Filespec /F (/foobar.pdf)")}, //97 |
| {"file:///foo bar.pdf", quote("<< /Type /Filespec /F (/foo bar.pdf)")}, |
| {"file:///foo/bar.pdf", quote("<< /Type /Filespec /F (/foo/bar.pdf)")}, |
| {"file:///foo/bar 2.pdf", quote("<< /Type /Filespec /F (/foo/bar 2.pdf)")}, |
| |
| // file:// PDF, Relative paths |
| {"file://foobar.pdf", quote("<< /Type /Filespec /F (foobar.pdf)")}, //101 |
| {"file://foo bar.pdf", quote("<< /Type /Filespec /F (foo bar.pdf)")}, |
| {"file://./foobar.pdf", quote("<< /Type /Filespec /F (./foobar.pdf)")}, |
| {"file://./foo bar.pdf", quote("<< /Type /Filespec /F (./foo bar.pdf)")}, |
| {"file://../foobar.pdf", quote("<< /Type /Filespec /F (../foobar.pdf)")}, |
| {"file://../foo bar.pdf", quote("<< /Type /Filespec /F (../foo bar.pdf)")}, |
| |
| // file:// PDF, Windows network paths |
| {"file://\\\\foo\\bar.pdf", quote("<< /Type /Filespec /F (\\\\\\\\foo\\\\bar.pdf)")}, //107 |
| {"file://\\\\foo\\bar 2.pdf", quote("<< /Type /Filespec /F (\\\\\\\\foo\\\\bar 2.pdf)")}, |
| {"file://\\\\foo\\a\\bar.pdf", quote("<< /Type /Filespec /F (\\\\\\\\foo\\\\a\\\\bar.pdf)")}, |
| {"file://\\\\foo\\a\\bar 2.pdf", quote("<< /Type /Filespec /F (\\\\\\\\foo\\\\a\\\\bar 2.pdf)")}, |
| |
| // Proper file:// for windows paths |
| {"file:///c:/foo%20bar.pdf", quote("<< /Type /Filespec /F (c:/foo bar.pdf)")}, //111 |
| {"file:///c:/foo/bar.pdf", quote("<< /Type /Filespec /F (c:/foo/bar.pdf)")}, |
| {"file:///c:/foo/bar%202.pdf", quote("<< /Type /Filespec /F (c:/foo/bar 2.pdf)")}, |
| |
| // Proper file:// PDF, for linux paths |
| {"file:///foo/bar%202.pdf", quote("<< /Type /Filespec /F (/foo/bar 2.pdf)")}, //114 |
| |
| // file:// PDF with fragments, Windows absolute paths |
| {"file://c:\\foobar.pdf#page=2", quote("<< /Type /Filespec /F (c:/foobar.pdf)") + ".*" |
| + quote("/S /GoToR") + ".*" + quote("/D [ 2 /XYZ null null null ]")}, //115 |
| {"file://c:\\foo bar.pdf#dest=aa", quote("<< /Type /Filespec /F (c:/foo bar.pdf)") + ".*" |
| + quote("/S /GoToR") + ".*" + quote("/D (aa)")}, |
| {"file://c:\\foo\\bar.pdf#page=2", quote("<< /Type /Filespec /F (c:/foo/bar.pdf)") + ".*" |
| + quote("/S /GoToR") + ".*" + quote("/D [ 2 /XYZ null null null ]")}, |
| {"file://c:\\foo\\bar 2.pdf#dest=aa", quote("<< /Type /Filespec /F (c:/foo/bar 2.pdf)") + ".*" |
| + quote("/S /GoToR") + ".*" + quote("/D (aa)")}, |
| |
| // file:// PDF with fragments, Windows absolute paths using "/" |
| {"file://c:/foo bar.pdf#page=2", quote("<< /Type /Filespec /F (c:/foo bar.pdf)") + ".*" |
| + quote("/S /GoToR") + ".*" + quote("/D [ 2 /XYZ null null null ]")}, //119 |
| {"file://c:/foo/bar.pdf#dest=aa", quote("<< /Type /Filespec /F (c:/foo/bar.pdf)") + ".*" |
| + quote("/S /GoToR") + ".*" + quote("/D (aa)")}, |
| {"file://c:/foo/bar 2.pdf#page=2", quote("<< /Type /Filespec /F (c:/foo/bar 2.pdf)") + ".*" |
| + quote("/S /GoToR") + ".*" + quote("/D [ 2 /XYZ null null null ]")}, |
| |
| // file:// PDF with fragments, Linux absolute paths |
| {"file:///foobar.pdf#dest=aa", quote("<< /Type /Filespec /F (/foobar.pdf)") + ".*" |
| + quote("/S /GoToR") + ".*" + quote("/D (aa)")}, //122 |
| {"file:///foo/bar.pdf#page=2", quote("<< /Type /Filespec /F (/foo/bar.pdf)") + ".*" |
| + quote("/S /GoToR") + ".*" + quote("/D [ 2 /XYZ null null null ]")}, |
| {"file:///foo/bar 2.pdf#dest=aa", quote("<< /Type /Filespec /F (/foo/bar 2.pdf)") + ".*" |
| + quote("/S /GoToR") + ".*" + quote("/D (aa)")}, |
| {"file:///foo bar.pdf#page=2", quote("<< /Type /Filespec /F (/foo bar.pdf)") + ".*" |
| + quote("/S /GoToR") + ".*" + quote("/D [ 2 /XYZ null null null ]")}, |
| |
| // file:// PDF with fragments, Relative paths |
| {"file://foobar.pdf#dest=aa", quote("<< /Type /Filespec /F (foobar.pdf)") + ".*" |
| + quote("/S /GoToR") + ".*" + quote("/D (aa)")}, //126 |
| {"file://foo bar.pdf#page=2", quote("<< /Type /Filespec /F (foo bar.pdf)") + ".*" |
| + quote("/S /GoToR") + ".*" + quote("/D [ 2 /XYZ null null null ]")}, |
| {"file://./foobar.pdf#dest=aa", quote("<< /Type /Filespec /F (./foobar.pdf)") + ".*" |
| + quote("/S /GoToR") + ".*" + quote("/D (aa)")}, |
| {"file://./foo bar.pdf#page=2", quote("<< /Type /Filespec /F (./foo bar.pdf)") + ".*" |
| + quote("/S /GoToR") + ".*" + quote("/D [ 2 /XYZ null null null ]")}, |
| {"file://../foobar.pdf#dest=aa", quote("<< /Type /Filespec /F (../foobar.pdf)") + ".*" |
| + quote("/S /GoToR") + ".*" + quote("/D (aa)")}, |
| {"file://../foo bar.pdf#page=2", quote("<< /Type /Filespec /F (../foo bar.pdf)") + ".*" |
| + quote("/S /GoToR") + ".*" + quote("/D [ 2 /XYZ null null null ]")}, |
| |
| // file:// PDF with fragments, Windows network paths |
| {"file://\\\\foo\\bar.pdf#dest=aa", quote("<< /Type /Filespec /F (\\\\\\\\foo\\\\bar.pdf)") + ".*" |
| + quote("/S /GoToR") + ".*" + quote("/D (aa)")}, //132 |
| {"file://\\\\foo\\bar 2.pdf#page=2", quote("<< /Type /Filespec /F (\\\\\\\\foo\\\\bar 2.pdf)") |
| + ".*" + quote("/S /GoToR") + ".*" + quote("/D [ 2 /XYZ null null null ]")}, |
| {"file://\\\\foo\\a\\bar.pdf#dest=aa", quote("<< /Type /Filespec /F (\\\\\\\\foo\\\\a\\\\bar.pdf)") |
| + ".*" + quote("/S /GoToR") + ".*" + quote("/D (aa)")}, |
| {"file://\\\\foo\\a\\bar 2.pdf#page=2", |
| quote("<< /Type /Filespec /F (\\\\\\\\foo\\\\a\\\\bar 2.pdf)") + ".*" |
| + quote("/S /GoToR") + ".*" + quote("/D [ 2 /XYZ null null null ]")}, |
| |
| // Proper file:// PDF with fragments, Windows network paths |
| {"file:////foo/bar.pdf#dest=aa", quote("<< /Type /Filespec /F (\\\\\\\\foo\\\\bar.pdf)") + ".*" |
| + quote("/S /GoToR") + ".*" + quote("/D (aa)")}, //136 |
| {"file:////foo/bar%202.pdf#page=2", quote("<< /Type /Filespec /F (\\\\\\\\foo\\\\bar 2.pdf)") + ".*" |
| + quote("/S /GoToR") + ".*" + quote("/D [ 2 /XYZ null null null ]")}, |
| {"file:////foo/a/bar.pdf#dest=aa", quote("<< /Type /Filespec /F (\\\\\\\\foo\\\\a\\\\bar.pdf)") |
| + ".*" + quote("/S /GoToR") + ".*" + quote("/D (aa)")}, |
| {"file:////foo/a/bar%202.pdf#page=2", quote("<< /Type /Filespec /F (\\\\\\\\foo\\\\a\\\\bar 2.pdf)") |
| + ".*" + quote("/S /GoToR") + ".*" + quote("/D [ 2 /XYZ null null null ]")}, |
| |
| // Proper file:// PDF, for linux paths |
| {"file:///foo/bar%202.pdf#page=2", quote("<< /Type /Filespec /F (/foo/bar 2.pdf)") + ".*" |
| + quote("/S /GoToR") + ".*" + quote("/D [ 2 /XYZ null null null ]")}, //140 |
| |
| // file: Relative paths |
| {"file:foobar.txt", quote("<< /Type /Filespec /F (foobar.txt)")}, //141 |
| {"file:foo bar.txt", quote("<< /Type /Filespec /F (foo bar.txt)")}, |
| {"file:./foobar.txt", quote("<< /Type /Filespec /F (./foobar.txt)")}, |
| {"file:./foo bar.txt", quote("<< /Type /Filespec /F (./foo bar.txt)")}, |
| {"file:../foobar.txt", quote("<< /Type /Filespec /F (../foobar.txt)")}, |
| {"file:../foo bar.txt", quote("<< /Type /Filespec /F (../foo bar.txt)")}, |
| {"file:\uFF46\uFF4F\uFF4F\u3000\uFF42\uFF41\uFF52.txt", |
| quote("<< /Type /Filespec /F <FEFFFF46FF4FFF4F3000FF42FF41FF52002E007400780074> " |
| + "/UF <FEFFFF46FF4FFF4F3000FF42FF41FF52002E007400780074>")}, |
| |
| // file: PDF Relative paths |
| {"file:foobar.pdf", quote("<< /Type /Filespec /F (foobar.pdf)")}, //148 |
| {"file:foo bar.pdf", quote("<< /Type /Filespec /F (foo bar.pdf)")}, |
| {"file:./foobar.pdf", quote("<< /Type /Filespec /F (./foobar.pdf)")}, |
| {"file:./foo bar.pdf", quote("<< /Type /Filespec /F (./foo bar.pdf)")}, |
| {"file:../foobar.pdf", quote("<< /Type /Filespec /F (../foobar.pdf)")}, |
| {"file:../foo bar.pdf", quote("<< /Type /Filespec /F (../foo bar.pdf)")}, |
| |
| // file: PDF with fragments, Relative paths |
| {"file:foobar.pdf#dest=aa", quote("<< /Type /Filespec /F (foobar.pdf)") + ".*" |
| + quote("/S /GoToR") + ".*" + quote("/D (aa)")}, //154 |
| {"file:foo bar.pdf#page=2", quote("<< /Type /Filespec /F (foo bar.pdf)") + ".*" |
| + quote("/S /GoToR") + ".*" + quote("/D [ 2 /XYZ null null null ]")}, |
| {"file:./foobar.pdf#dest=aa", quote("<< /Type /Filespec /F (./foobar.pdf)") + ".*" |
| + quote("/S /GoToR") + ".*" + quote("/D (aa)")}, |
| {"file:./foo bar.pdf#page=2", quote("<< /Type /Filespec /F (./foo bar.pdf)") + ".*" |
| + quote("/S /GoToR") + ".*" + quote("/D [ 2 /XYZ null null null ]")}, |
| {"file:../foobar.pdf#dest=aa", quote("<< /Type /Filespec /F (../foobar.pdf)") + ".*" |
| + quote("/S /GoToR") + ".*" + quote("/D (aa)")}, |
| {"file:../foo bar.pdf#page=2", quote("<< /Type /Filespec /F (../foo bar.pdf)") + ".*" |
| + quote("/S /GoToR") + ".*" + quote("/D [ 2 /XYZ null null null ]")}, |
| |
| // file: prefix, Windows absolute paths |
| {"file:c:\\foobar.txt", quote("<< /Type /Filespec /F (c:/foobar.txt)")}, //160 |
| {"file:c:\\foo bar.txt", quote("<< /Type /Filespec /F (c:/foo bar.txt)")}, |
| {"file:c:\\foo\\bar.txt", quote("<< /Type /Filespec /F (c:/foo/bar.txt)")}, |
| {"file:c:\\foo\\bar 2.txt", quote("<< /Type /Filespec /F (c:/foo/bar 2.txt)")}, |
| |
| // PDF, Linux absolute paths |
| {"file:/foobar.pdf", quote("<< /Type /Filespec /F (/foobar.pdf)")}, //164 |
| {"file:/foo bar.pdf", quote("<< /Type /Filespec /F (/foo bar.pdf)")}, |
| {"file:/foo%20bar.pdf", quote("<< /Type /Filespec /F (/foo bar.pdf)")}, |
| {"file:/foo/bar.pdf", quote("<< /Type /Filespec /F (/foo/bar.pdf)")}, |
| {"file:/foo/bar 2.pdf", quote("<< /Type /Filespec /F (/foo/bar 2.pdf)")}, |
| {"file:/foo/bar%202.pdf", quote("<< /Type /Filespec /F (/foo/bar 2.pdf)")}, |
| |
| // Web links |
| {"https://xmlgraphics.apache.org/fop/", quote("<< /URI (https://xmlgraphics.apache.org/fop/)")}, //170 |
| {"http://xmlgraphics.apache.org/fop/", quote("<< /URI (http://xmlgraphics.apache.org/fop/)")}, |
| {"https://xmlgraphics.apache.org/fop/examples.html", |
| quote("<< /URI (https://xmlgraphics.apache.org/fop/examples.html)")}, |
| {"https://xmlgraphics.apache.org/fop/fo/fonts.fo.pdf", |
| quote("<< /URI (https://xmlgraphics.apache.org/fop/fo/fonts.fo.pdf)")}, |
| {"https://xmlgraphics.apache.org/fop/fo/fonts.fo.pdf#page=2", |
| quote("<< /URI (https://xmlgraphics.apache.org/fop/fo/fonts.fo.pdf#page=2)")}, |
| {"https://xmlgraphics.apache.org/fop/fo/fonts.fo", |
| quote("<< /URI (https://xmlgraphics.apache.org/fop/fo/fonts.fo)")}, |
| |
| // HTML files |
| {"examples.html#foo", quote("<< /URI (examples.html#foo)")}, //177 |
| {"examples.html?foo#bar", quote("/URI (examples.html?foo#bar)")}, |
| {"examples.html", quote("<< /URI (examples.html)")}, |
| {"file:examples.html", quote("<< /Type /Filespec /F (examples.html)")}, |
| |
| // parenthesis |
| {"simple_report_(version2.pdf", quote("<< /Type /Filespec /F (simple_report_\\(version2.pdf)")} |
| }); |
| } |
| |
| @Test |
| public void testLinks() throws IFException { |
| FOUserAgent ua = FopFactory.newInstance(new File(".").toURI()).newFOUserAgent(); |
| PDFDocumentHandler docHandler = new PDFDocumentHandler(new IFContext(ua)); |
| docHandler.setFontInfo(new FontInfo()); |
| ByteArrayOutputStream out = new ByteArrayOutputStream(); |
| docHandler.setResult(new StreamResult(out)); |
| docHandler.startDocument(); |
| docHandler.startPage(0, "", "", new Dimension()); |
| docHandler.getDocumentNavigationHandler().renderLink(new Link( |
| new URIAction(target, false), new Rectangle())); |
| docHandler.endDocument(); |
| |
| // Normalize spaces between word for easier testing |
| String outString = out.toString().replaceAll("\\s+", " "); |
| |
| Pattern r = Pattern.compile(expected); |
| Matcher m = r.matcher(outString); |
| Assert.assertTrue(target + " " + outString, m.find()); |
| } |
| } |