blob: 988a146686602aac7ee280bd82b96ba683052503 [file] [log] [blame]
/*
* 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());
}
}