Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
5 changes: 5 additions & 0 deletions MANIFEST
Original file line number Diff line number Diff line change
Expand Up @@ -987,6 +987,9 @@ t/complex/aastex631_deluxetable.xml
t/complex/aliceblog.pdf
t/complex/aliceblog.tex
t/complex/aliceblog.xml
t/complex/candidates.pdf
t/complex/candidates.tex
t/complex/candidates.xml
t/complex/cleveref_minimal.pdf
t/complex/cleveref_minimal.tex
t/complex/cleveref_minimal.xml
Expand Down Expand Up @@ -1016,6 +1019,8 @@ t/complex/si.pdf
t/complex/si.tex
t/complex/si.xml
t/complex/sunset.jpg
t/complex/sunset,encoded.gif
t/complex/sunset,encoded.jpg
t/complex/tcilatex_minimal.pdf
t/complex/tcilatex_minimal.tex
t/complex/tcilatex_minimal.xml
Expand Down
3 changes: 1 addition & 2 deletions lib/LaTeXML/Common/Model/DTD.pm
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,6 @@ use LaTeXML::Util::Pathname;
use LaTeXML::Global;
use LaTeXML::Common::Error;
use LaTeXML::Common::XML;
use URI::file;

#**********************************************************************
# NOTE: Arglist is DTD specific.
Expand Down Expand Up @@ -118,7 +117,7 @@ sub readDTD {
paths => $STATE->lookupValue('SEARCHPATHS'),
installation_subdir => 'resources/DTD');
if ($dtdfile) {
$dtd = XML::LibXML::Dtd->new($$self{public_id}, URI::file->new($dtdfile));
$dtd = XML::LibXML::Dtd->new($$self{public_id}, pathname_to_file_url($dtdfile));
$how = " from $dtdfile ";
Error('misdefined', $$self{system_id}, undef,
"Parsing of DTD \"$$self{public_id}\" \"$$self{system_id}\" failed")
Expand Down
2 changes: 1 addition & 1 deletion lib/LaTeXML/Core.pm
Original file line number Diff line number Diff line change
Expand Up @@ -263,7 +263,7 @@ sub convertDocument {
my @dedup = ();
while (my $check = shift(@copy)) {
unshift(@dedup, $check) if !(grep { $_ eq $check } @dedup); }
$document->insertPI('latexml', searchpaths => join(',', @dedup)); } }
$document->insertPI('latexml', searchpaths => pathname_to_urls(@dedup)); } }
foreach my $preload_by_reference (@{ $$self{preload} }) {
my $preload = $preload_by_reference; # copy preload value, as we want to preserve the hash as-is, for (potential) future daemon calls
next if $preload =~ /\.pool$/;
Expand Down
2 changes: 1 addition & 1 deletion lib/LaTeXML/Engine/TeX_FileIO.pool.ltxml
Original file line number Diff line number Diff line change
Expand Up @@ -243,7 +243,7 @@ DefConstructor('\lx@special@graphics OptionalKeyVals:SpecialPS Semiverbatim',
my $bottom = -$voffset;
$options .= "," if $options;
$options .= "trim=$left $bottom 0 0,clip=true"; } }
(options => $options, path => $path, candidates => join(',', @candidates)); },
(options => $options, path => pathname_to_url($path), candidates => pathname_to_urls(@candidates)); },
mode => 'restricted_horizontal');
# Since these ultimately generate external resources, it can be useful to have a handle on them.
Tag('ltx:graphics', afterOpen => sub { GenerateID(@_, 'g'); });
Expand Down
4 changes: 2 additions & 2 deletions lib/LaTeXML/Package/epsf.sty.ltxml
Original file line number Diff line number Diff line change
Expand Up @@ -57,8 +57,8 @@ DefConstructor('\epsfbox[] Semiverbatim',
$options .= ($options ? ',' : '') . 'width=' . ToString($w); }
if ($h->valueOf > 0) {
$options .= ($options ? ',' : '') . 'height=' . ToString($h); }
(graphic => $file,
candidates => join(',', @candidates),
(graphic => pathname_to_url($file),
candidates => pathname_to_urls(@candidates),
options => $options); });

Let('\epsfgetlitbb', '\epsfbox');
Expand Down
6 changes: 3 additions & 3 deletions lib/LaTeXML/Package/epsfig.sty.ltxml
Original file line number Diff line number Diff line change
Expand Up @@ -47,9 +47,9 @@ DefConstructor('\psfig RequiredKeyVals:epsGin',
if (my $base = LookupValue('SOURCEDIRECTORY')) {
@candidates = map { pathname_relative($_, $base) } @candidates; }
my $options = ToString($kv);
(graphic => $file,
candidates => join(',', @candidates),
options => $options); });
(graphic => pathname_to_url($file),
candidates => pathname_to_urls(@candidates),
options => $options); });

Let('\epsfig', '\psfig');

Expand Down
6 changes: 3 additions & 3 deletions lib/LaTeXML/Package/graphics.sty.ltxml
Original file line number Diff line number Diff line change
Expand Up @@ -248,7 +248,7 @@ DefConstructor('\reflectbox {}',
DefConstructor('\graphicspath DirectoryList', sub {
my ($document, $paths, %props) = @_;
foreach my $path (@{ $props{paths} }) {
$document->insertPI('latexml', graphicspath => $path); } },
$document->insertPI('latexml', graphicspath => pathname_to_url($path)); } },
properties => sub {
my ($stomach, $paths) = @_;
my @paths = ();
Expand Down Expand Up @@ -297,8 +297,8 @@ DefConstructor('\@includegraphics OptionalMatch:* [][] Semiverbatim',
my ($stomach, $starred, $op1, $op2, $graphic) = @_;
my $options = graphicS_options($starred, $op1, $op2);
my ($path, @candidates) = image_candidates(ToString($graphic));
(graphic => $path,
candidates => join(',', @candidates),
(graphic => pathname_to_url($path),
candidates => pathname_to_urls(@candidates),
options => $options); },
alias => '\includegraphics');

Expand Down
4 changes: 2 additions & 2 deletions lib/LaTeXML/Package/graphicx.sty.ltxml
Original file line number Diff line number Diff line change
Expand Up @@ -65,8 +65,8 @@ DefConstructor('\@includegraphicx OptionalMatch:* OptionalKeyVals:Gin Semiverbat
my $options = graphicX_options($starred, $kv);
my ($path, @candidates) = image_candidates(ToString($graphic));
my $alt = $kv && $kv->getValue('alt');
(path => $path,
candidates => join(',', @candidates),
(path => pathname_to_url($path),
candidates => pathname_to_urls(@candidates),
(defined $alt ? (alt => $alt) : ()),
options => $options); },
mode => 'restricted_horizontal', enterHorizontal => 1);
Expand Down
4 changes: 2 additions & 2 deletions lib/LaTeXML/Package/pgfsys-latexml.def.ltxml
Original file line number Diff line number Diff line change
Expand Up @@ -617,8 +617,8 @@ DefConstructor('\lxSVG@includegraphics{}{} Semiverbatim',
paths => LookupValue('GRAPHICSPATHS'));
if (my $base = LookupValue('SOURCEDIRECTORY')) {
@candidates = map { pathname_relative($_, $base) } @candidates; }
(graphic => $graphic,
candidates => join(',', @candidates),
(graphic => pathname_to_url($graphic),
candidates => pathname_to_urls(@candidates),
options => $options); },
alias => '\includegraphics');

Expand Down
12 changes: 6 additions & 6 deletions lib/LaTeXML/Package/psfrag.sty.ltxml
Original file line number Diff line number Diff line change
Expand Up @@ -87,8 +87,8 @@ DefConstructor('\lx@psfrag@includegraphics OptionalMatch:* [][] Semiverbatim',
my $options = graphicS_options($starred, $op1, $op2);
my ($path, @candidates) = image_candidates(ToString($graphic));
my $ifpicture = psfrag_requirepicture(@candidates);
(graphic => $path,
candidates => join(',', @candidates),
(path => pathname_to_url($path),
candidates => pathname_to_urls(@candidates),
options => $options,
pic => $ifpicture); },
afterDigest => sub {
Expand All @@ -110,8 +110,8 @@ DefConstructor('\lx@psfrag@includegraphicx OptionalMatch:* OptionalKeyVals:Gin S
my $options = graphicX_options($starred, $kv);
my ($path, @candidates) = image_candidates(ToString($graphic));
my $ifpicture = psfrag_requirepicture(@candidates);
(path => $path,
candidates => join(',', @candidates),
(path => pathname_to_url($path),
candidates => pathname_to_urls(@candidates),
options => $options,
pic => $ifpicture); },
afterDigest => sub {
Expand All @@ -133,8 +133,8 @@ DefConstructor('\lx@psfrag@epsfbox[] Semiverbatim',
my $options = ($clip ? ($bb ? "viewport=$bb, clip" : "clip") : '');
my ($path, @candidates) = image_candidates(ToString($graphic));
my $ifpicture = psfrag_requirepicture(@candidates);
(graphic => $path,
candidates => join(',', @candidates),
(graphic => pathname_to_url($path),
candidates => pathname_to_urls(@candidates),
options => $options,
pic => $ifpicture); },
afterDigest => sub {
Expand Down
6 changes: 3 additions & 3 deletions lib/LaTeXML/Post.pm
Original file line number Diff line number Diff line change
Expand Up @@ -664,7 +664,6 @@ use DB_File;
use Unicode::Normalize;
use LaTeXML::Post; # to import error handling...
use LaTeXML::Common::Error;
use URI::file;
use base qw(LaTeXML::Common::Object);
our $NSURI = "http://dlmf.nist.gov/LaTeXML";
our $XPATH = LaTeXML::Common::XML::XPath->new(ltx => $NSURI);
Expand Down Expand Up @@ -821,7 +820,7 @@ sub setDocument_internal {
@paths = @{ $$self{searchpaths} } if $$self{searchpaths};
foreach my $pi (@{ $$self{processingInstructions} }) {
if ($pi =~ /^\s*searchpaths\s*=\s*([\"\'])(.*?)\1\s*$/) {
push(@paths, split(',', $2)); } }
push(@paths, pathname_from_urls($2)); } }
### No, this ultimately can be the xml source, which may be the destination;
### adding this gets the wrong graphics (already processed!)
### push(@paths, pathname_absolute($$self{sourceDirectory})) if $$self{sourceDirectory};
Expand Down Expand Up @@ -857,7 +856,8 @@ sub setDocument_internal {
else {
Fatal('unexpected', $root, undef, "Dont know how to use '$root' as document element"); }
# set URI to destination
$$self{document}->setURI(URI::file->new($self->getDestination));
my $url = pathname_to_file_url($self->getDestination);
$$self{document}->setURI($url) if defined $url;
return $self; }

our @MonthNames = (qw( January February March April May June
Expand Down
5 changes: 3 additions & 2 deletions lib/LaTeXML/Post/CrossRef.pm
Original file line number Diff line number Diff line change
Expand Up @@ -650,8 +650,9 @@ sub generateURL {
if ($location = $object->getValue('location')) {
my $doclocation = $doc->siteRelativeDestination;
my $pathdir = pathname_directory($doclocation);
my $url = pathname_relative(($location =~ m|^/| ? $location : '/' . $location),
my $relpath = pathname_relative(($location =~ m|^/| ? $location : '/' . $location),
($pathdir =~ m|^/| ? $pathdir : '/' . $pathdir));
my $url = pathname_to_url($relpath);
my $extension = $$self{extension} || 'xml';
my $urlstyle = $$self{urlstyle} || 'file';
if ($urlstyle eq 'server') {
Expand All @@ -667,7 +668,7 @@ sub generateURL {
$url .= '#' . $fragid; }
elsif ($location eq $doclocation) {
$url = ''; }
return pathname_to_url($url); }
return $url; }
else {
$self->note_missing('warn', 'File location for ID', $id); } }
else {
Expand Down
8 changes: 4 additions & 4 deletions lib/LaTeXML/Post/Graphics.pm
Original file line number Diff line number Diff line change
Expand Up @@ -53,7 +53,7 @@ sub new {
$$self{trivial_scaling} = $options{trivial_scaling} || 1;
$$self{graphics_types} = $options{graphics_types}
|| [qw(svg png gif jpg jpeg
eps ps postscript ai pdf)];
eps ps postscript ai pdf)];
$$self{type_properties} = $options{type_properties}
|| {
ai => { destination_type => 'png',
Expand Down Expand Up @@ -123,7 +123,7 @@ sub findGraphicsPaths {
my @paths = ();
foreach my $pi ($doc->findnodes('.//processing-instruction("latexml")')) {
if ($pi->textContent =~ /^\s*graphicspath\s*=\s*([\"\'])(.*?)\1\s*$/) {
push(@paths, $2); } }
push(@paths, pathname_from_url($2)); } }
return @paths; }

sub getGraphicsSourceTypes {
Expand All @@ -133,9 +133,9 @@ sub getGraphicsSourceTypes {
# Return the pathname to an appropriate image.
sub findGraphicFile {
my ($self, $doc, $node) = @_;
if (my $source = $node->getAttribute('graphic')) {
if (my $source = pathname_from_url($node->getAttribute('graphic'))) {
# if we already have a usable candidate, save ourselves the work
my @paths = grep { -e $_ } split(',', $node->getAttribute('candidates') || '');
my @paths = grep { -e $_ } pathname_from_urls($node->getAttribute('candidates') || '');
if (!scalar(@paths)) {
# Find all acceptable image files, in order of search paths
my ($dir, $name, $reqtype) = pathname_split($source);
Expand Down
8 changes: 4 additions & 4 deletions lib/LaTeXML/Post/Manifest/Epub.pm
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,7 @@ package LaTeXML::Post::Manifest::Epub;
use strict;
use warnings;
use File::Find qw(find);
use URI::file;
use LaTeXML::Util::Pathname;

our $uuid_tiny_installed;

Expand All @@ -27,7 +27,7 @@ BEGIN {
use base qw(LaTeXML::Post::Manifest);
use LaTeXML::Util::Pathname;
use File::Spec::Functions qw(catdir);
use POSIX qw(strftime);
use POSIX qw(strftime);
use LaTeXML::Post; # for error handling!
our $container_content = <<'EOL';
<?xml version="1.0"?>
Expand Down Expand Up @@ -171,7 +171,7 @@ sub process {
# Add to manifest
my $manifest = $$self{opf_manifest};
my $item = $manifest->addNewChild(undef, 'item');
my $item_url = URI::file->new($relative_destination);
my $item_url = pathname_to_url($relative_destination);
my $item_id = url_id($item_url);
$item->setAttribute('id', $item_id);
$item->setAttribute('href', $item_url);
Expand Down Expand Up @@ -215,7 +215,7 @@ sub finalize {
$file_type = 'application/octet-stream'; }

my $file_item = $manifest->addNewChild(undef, 'item');
my $file_url = URI::file->new($file);
my $file_url = pathname_to_url($file);
$file_item->setAttribute('id', url_id($file_url));
$file_item->setAttribute('href', $file_url);
$file_item->setAttribute('media-type', $file_type); }
Expand Down
2 changes: 1 addition & 1 deletion lib/LaTeXML/Util/Image.pm
Original file line number Diff line number Diff line change
Expand Up @@ -252,7 +252,7 @@ sub image_graphicx_sizer {
my ($whatsit) = @_;
if (my $candidates = $whatsit->getProperty('candidates')) {
my $dpi = ($STATE && $STATE->lookupValue('DPI')) || $DPI;
foreach my $source (split(/,/, $candidates)) {
foreach my $source (pathname_from_urls($candidates)) {
if (!pathname_is_absolute($source)) {
if (my $base = $STATE->lookupValue('SOURCEDIRECTORY')) {
$source = pathname_concat($base, $source); } }
Expand Down
61 changes: 51 additions & 10 deletions lib/LaTeXML/Util/Pathname.pm
Original file line number Diff line number Diff line change
Expand Up @@ -31,6 +31,7 @@ use warnings;
use File::Spec;
use File::Copy;
use File::Which;
use URI::file;
use Cwd;
use base qw(Exporter);
our @EXPORT = qw( &pathname_find &pathname_findall &pathname_kpsewhich
Expand All @@ -39,6 +40,7 @@ our @EXPORT = qw( &pathname_find &pathname_findall &pathname_kpsewhich
&pathname_timestamp
&pathname_concat
&pathname_relative &pathname_absolute &pathname_to_url
&pathname_to_urls &pathname_from_url &pathname_from_urls &pathname_to_file_url
&pathname_is_absolute &pathname_is_contained
&pathname_is_url &pathname_is_literaldata
&pathname_is_raw
Expand Down Expand Up @@ -212,13 +214,34 @@ sub pathname_absolute {
? File::Spec->rel2abs($pathname, ($base ? pathname_canonical($base) : pathname_cwd()))
: $pathname); }

# conversions to/from file URLs

# remove file:// part for backwards compatibility
sub pathname_to_url {
my ($pathname) = @_;
return unless defined $pathname;
my $relative_pathname = pathname_relative($pathname);
if ($SEP ne '/') {
$relative_pathname = join('/', split(/\Q$SEP\E/, $relative_pathname)); }
return $relative_pathname; }
return unless defined $_[0];
my $url = URI::file->new(pathname_canonical($_[0]))->path;
$url =~ s/,/%2C/g;
return $url; }

sub pathname_to_urls {
return join(',', map { pathname_to_url($_) } @_); }

sub pathname_from_url {
return unless defined $_[0];
return URI->new($_[0], 'file')->file; }

sub pathname_from_urls {
return unless defined $_[0];
my @urls = split(/,/, $_[0]);
my @nonempty = grep { $_ } @urls;
return map { pathname_from_url($_) } @nonempty; }
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Apologies in advance for the naming nit-picking.

pathname_from_urls probably wants to indicate the many-to-many map. So an extra s -
pathnames_from_urls

Similarly for the _to_ variant.

Also, we probably want to decide if we want to drop the _file from _file_url, or the opposite - to use it everywhere. As indicated, a URL is ambiguous. Indeed a relative pathname on linux such as ./subdir/a/b/c/test.png is also a match for a relative URL.

So maybe all of your new methods should be fileurl/fileurls as suffixes... But maybe don't rush to take my feedback before we hear from @brucemiller .

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

want to decide if we want to drop the _file from _file_url, or the opposite - to use it everywhere

Additional datapoint: most of the times LaTeXML wants an URL path (e.g. resources, images, CrossRef). The _file_url variant is for DTD and setURI which require actual URLs and may do strange things with absolute URL paths (not sure how, but I wouldn't risk it). Third use is for candidates and search paths in this PR, where we should stick to paths for backwards compatibility.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

probably wants to indicate the many-to-many map. So an extra s -
pathnames_from_urls

Makes sense. I was just uncertain as to whether pathname_ was meant as a namespace as opposed to an actual word.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Looking back at (and rebasing) this PR, a summary of why the PR looks like this:

  • the URL without file: must remain for backward compatibility with external tools that do not expect it
  • the file: scheme can be omitted because those 'urls' are used in contexts where file: is implied (e.g. graphics candidates)
  • pathname_to_url(s?) is the version without file: scheme, for backward compatibility with the previous pathname_to_url (which was never about producing complete well formed URLs!)
  • pathname_to_file_url exists only for those rare situations in which the file: scheme is actually required (DTD and document URI)

So the naming problem really comes from the original pathname_to_url not producing URLs in the first place. We could rename pathname_to_url to pathname_urlencode, which is more accurate.


# complete file:// URL
sub pathname_to_file_url {
return unless defined $_[0];
my $url = URI::file->new(pathname_canonical($_[0]))->as_string;
$url =~ s/,/%2C/g;
return $url; }

#======================================================================
# Actual file system operations.
Expand Down Expand Up @@ -377,6 +400,7 @@ sub candidate_pathnames {
opendir(my $dir_handle, $dir) or next;
my @dir_files = readdir($dir_handle);
closedir($dir_handle);
my @dir_paths;
for my $local_file (@dir_files) {
for my $regex_pair (@regexes) {
my ($i_regex, $regex) = @$regex_pair;
Expand All @@ -386,7 +410,8 @@ sub candidate_pathnames {
if ($local_file =~ m/$regex/) {
# if we are only interested in the first match, return it:
return ($full_file) if $options{findfirst};
push(@paths, $full_file); } } } } }
push(@dir_paths, $full_file); } } } }
push(@paths, sort @dir_paths); }
# Fallback: if no strict matches were found, return any existing case-insensitive matches
# Defer the -f check until we are sure we need it, to keep the usual cases fast.
return @paths ? @paths : @nocase_paths; }
Expand Down Expand Up @@ -553,10 +578,26 @@ Returns the absolute pathname resulting from interpretting
C<$path> relative to the directory C<$base>. If C<$path>
is already absolute, it is returned unchanged.

=item C<< $relative_url = pathname_to_url($path); >>
=item C<< $url = pathname_to_file_url($path); >>

Creates a file URL for a given pathname.

=item C<< $url = pathname_to_url($path); >>

Creates a file URL for a given pathname without the file:// scheme.

=item C<< $url = pathname_to_urls(@paths); >>

Create a comma separated list of file URLs for a given list of pathnames.

=item C<< $path = pathname_from_url($url); >>

Create a pathname, with local OS path separators, from a file URL.

=item C<< @paths = pathname_from_urls($urls); >>

Creates a local, relative URL for a given pathname,
also ensuring proper path separators on non-Unix systems.
Create a list of pathnames, with local OS path separator, from a
comma separated list of file URLs.

=back

Expand Down
4 changes: 2 additions & 2 deletions lib/LaTeXML/resources/RelaxNG/LaTeXML-misc.rnc
Original file line number Diff line number Diff line change
Expand Up @@ -82,12 +82,12 @@ graphics_attributes =
## the path to the graphics file. This is the (often minimally specified) path
## to a graphics file omitting the type extension. Once resolved to a specific
## image file, the \attr{imagesrc} (from Imageable.attributes) is used.
attribute graphic { text }?,
attribute graphic { xsd:anyURI }?,

## a comma separated list of candidate graphics files that could be used to
## for \attr{graphic}. A post-processor or application may choose from these,
## or may make its own selection or synthesis to implement the graphic for a given target.
attribute candidates { text }?,
attribute candidates { xsd:anyURI, (",", xsd:anyURI)* }?,

## an encoding of the scaling and positioning options
## to be used in processing the graphic.
Expand Down
Loading