Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

macOS: XML error: error in path data: number expected (premature end of data) #240

Closed
kiryph opened this issue Apr 27, 2023 · 11 comments
Closed
Assignees
Labels
Milestone

Comments

@kiryph
Copy link

kiryph commented Apr 27, 2023

I am using Asymptote which in turns uses dvisvgm.

I get for following asymptote file

draw(unitcircle);

the error

XML error: error in path data: number expected (premature end of data)

Running asymptote verbose with keep intermediate files

/Library/TeX/texbin/asy -keep -vv -f svg demo-unitcircle.asy

shows that the error is printed by dvisvgm (see last lines):

/Library/TeX/texbin/kpsewhich --var-value=TEXMFMAIN
/Library/TeX/texbin/kpsewhich --var-value=ASYMPTOTE_HOME
Using configuration directory /Users/kiryph/.asy
Using history /Users/kiryph/.asy/history
Welcome to Asymptote version 2.85
cd /Users/kiryph
Processing demo-unitcircle
Loading plain from /usr/local/texlive/2023/texmf-dist/asymptote/plain.asy
Including plain_constants from /usr/local/texlive/2023/texmf-dist/asymptote/plain_constants.asy
Loading version from /usr/local/texlive/2023/texmf-dist/asymptote/version.asy
Including plain_strings from /usr/local/texlive/2023/texmf-dist/asymptote/plain_strings.asy
Including plain_pens from /usr/local/texlive/2023/texmf-dist/asymptote/plain_pens.asy
Including plain_paths from /usr/local/texlive/2023/texmf-dist/asymptote/plain_paths.asy
Including plain_filldraw from /usr/local/texlive/2023/texmf-dist/asymptote/plain_filldraw.asy
Including plain_margins from /usr/local/texlive/2023/texmf-dist/asymptote/plain_margins.asy
Including plain_picture from /usr/local/texlive/2023/texmf-dist/asymptote/plain_picture.asy
Loading plain_scaling from /usr/local/texlive/2023/texmf-dist/asymptote/plain_scaling.asy
Loading simplex from /usr/local/texlive/2023/texmf-dist/asymptote/simplex.asy
Loading plain_bounds from /usr/local/texlive/2023/texmf-dist/asymptote/plain_bounds.asy
Including plain_scaling from /usr/local/texlive/2023/texmf-dist/asymptote/plain_scaling.asy
Including plain_prethree from /usr/local/texlive/2023/texmf-dist/asymptote/plain_prethree.asy
Including plain_Label from /usr/local/texlive/2023/texmf-dist/asymptote/plain_Label.asy
Including plain_arcs from /usr/local/texlive/2023/texmf-dist/asymptote/plain_arcs.asy
Including plain_boxes from /usr/local/texlive/2023/texmf-dist/asymptote/plain_boxes.asy
Including plain_shipout from /usr/local/texlive/2023/texmf-dist/asymptote/plain_shipout.asy
Including plain_markers from /usr/local/texlive/2023/texmf-dist/asymptote/plain_markers.asy
Including plain_arrows from /usr/local/texlive/2023/texmf-dist/asymptote/plain_arrows.asy
Including plain_debugger from /usr/local/texlive/2023/texmf-dist/asymptote/plain_debugger.asy
Loading demo-unitcircle.asy from demo-unitcircle.asy
latex \nonstopmode\input demo-unitcircle_.tex
This is pdfTeX, Version 3.141592653-2.6-1.40.25 (TeX Live 2023) (preloaded format=latex)
 restricted \write18 enabled.
entering extended mode
LaTeX2e <2022-11-01> patch level 1
L3 programming layer <2023-03-30>
(./demo-unitcircle_.tex
(/usr/local/texlive/2023/texmf-dist/tex/latex/base/article.cls
Document Class: article 2022/07/02 v1.4n Standard LaTeX document class
(/usr/local/texlive/2023/texmf-dist/tex/latex/base/size12.clo))
(/usr/local/texlive/2023/texmf-dist/tex/latex/graphics/graphicx.sty
(/usr/local/texlive/2023/texmf-dist/tex/latex/graphics/keyval.sty)
(/usr/local/texlive/2023/texmf-dist/tex/latex/graphics/graphics.sty
(/usr/local/texlive/2023/texmf-dist/tex/latex/graphics/trig.sty)
(/usr/local/texlive/2023/texmf-dist/tex/latex/graphics-cfg/graphics.cfg)
(/usr/local/texlive/2023/texmf-dist/tex/latex/graphics-def/dvips.def)))
(/usr/local/texlive/2023/texmf-dist/tex/latex/l3backend/l3backend-dvips.def)
No file demo-unitcircle_.aux.
[1] (./demo-unitcircle_.aux) )
Output written on demo-unitcircle_.dvi (1 page, 720 bytes).
Transcript written on demo-unitcircle_.log.
dvisvgm -n -v3 --optimize -odemo-unitcircle.svg demo-unitcircle_.dvi
XML error: error in path data: number expected (premature end of data)
  _shipout(prefix,f,currentpatterns,format,wait,view,t);
          ^
/usr/local/texlive/2023/texmf-dist/asymptote/plain_shipout.asy: 116.11: runtime: shipout failed

My Environment:

macOS 12.6.3
MacTeX 2023
❯ dvisvgm -V1
dvisvgm 3.0.3 (x86_64-apple-darwin18.7.0)
-----------------------------------------
brotli:      1.0.9
clipper:     6.2.1
freetype:    2.13.0
Ghostscript: 10.0.0
kpathsea:    6.3.5
mutool:      1.22.0
potrace:     1.16
xxhash:      0.8.1
zlib:        1.2.13

Ghostscript 10.00.0 with libgs from https://www.tug.org/mactex/morepackages.html (watchout to customize the installation to include libgs)

@mgieseki
Copy link
Owner

Sorry, I can't help with Asymptote issues here. Please upload the corresponding DVI file demo-unitcircle_.dvi.

@mgieseki mgieseki self-assigned this Apr 27, 2023
@kiryph
Copy link
Author

kiryph commented Apr 27, 2023

How should I upload the dvi file?
Is following fine:

÷����À�;�����è� TeX output 2023.04.27:1504�����������������������������������������ÿÿÿÿ�ï�header=l3backend-dvips.pro��h�®��´lR�-�®��÷lR�����8�ôï>dvisvgm:bbox f 57.659449bp 64.563436bp 60.159449bp 67.063436bpï®dvisvgm:raw{?nl}<g transform='matrix(0.996264 0 0 0.996264 57.6594 64.5634)'>{?nl}<path d='M 0 2.50937L 2.50937 2.50937L 2.50937 0L 0 0L 0 2.50937Z' fill='#ffffff'/>{?nl}</g>ò���Çdvisvgm:raw{?nl}<g transform='matrix(0.996264 0 0 0.996264 57.6594 64.5634)'>{?nl}<path d='M 2.25844 1.25469C 2.25844 0.700332 1.80904 0.250938 1.25469 0.250937C 0.700332 0.250937 0.250937 0.700332 0.250937 1.25469C 0.250937 1.80904 0.700332 2.25844 1.25469 2.25844C 1.80904 2.25844 2.25844 1.80904 2.25844 1.25469Z' fill='none' stroke='#000000' stroke-linecap='round' stroke-linejoin='round' stroke-miterlimit='10.0375' stroke-width='0.501875'/>{?nl}</g>�����������ø���*���À�;�����è�h�®�;�®����ù���V�ßßßßßßß

ZIP file
demo-unitcircle_.dvi.zip

@mgieseki
Copy link
Owner

Thanks for uploading the file. Unfortunately, I can't reproduce the error. The file converts correctly on my machines (Linux and Windows). Maybe someone needs to take a closer look at this on a Mac (which I don't have access to).

@kiryph
Copy link
Author

kiryph commented Apr 27, 2023

Currently, I am little bit lost:

  1. I have already tried three different Ghostscript versions

based on recent issues on macOS


  1. A rectangle compiles fine on macOS for SVG/WebGL output:
draw(box((0,0), (2,1)));

A diff between both intermediate tex files containing special commands:

 \special{dvisvgm:raw{?nl}%
-<g transform='matrix(0.996264 0 0 0.996264 56.6594 65.5634)'>{?nl}%
-<path d='M 0 1.50562L 2.50937 1.50562L 2.50937 0L 0 0L 0 1.50562Z' fill='#ffffff'/>{?nl}%
+<g transform='matrix(0.996264 0 0 0.996264 57.6594 64.5634)'>{?nl}%
+<path d='M 0 2.50937L 2.50937 2.50937L 2.50937 0L 0 0L 0 2.50937Z' fill='#ffffff'/>{?nl}%
 </g>}\catcode`\#=6%
 \catcode`\#=11%
 \special{dvisvgm:raw{?nl}%
-<g transform='matrix(0.996264 0 0 0.996264 56.6594 65.5634)'>{?nl}%
-<path d='M 0.250937 1.25469L 2.25844 1.25469L 2.25844 0.250937L 0.250937 0.250937L 0.250937 1.25469Z' fill='none' stroke='#000000' stroke-linecap='round' stroke-linejoin='round' stroke-miterlimit='10.0375' stroke-width='0.501875'/>{?nl}%
+<g transform='matrix(0.996264 0 0 0.996264 57.6594 64.5634)'>{?nl}%
+<path d='M 2.25844 1.25469C 2.25844 0.700332, 1.80904 0.250938, 1.25469 0.250937C 0.700332 0.250937, 0.250937 0.700332, 0.250937 1.25469C 0.250937 1.80904, 0.700332 2.25844, 1.25469 2.25844C 1.80904 2.25844, 2.25844 1.80904, 2.25844 1.25469Z' fill='none' stroke='#000000' stroke-linecap='round' stroke-linejoin='round' stroke-miterlimit='10.0375' stroke-width='0.501875'/>{?nl}%

shows that the most outstanding difference is the cubic Bézier curve.

The error XML error: error in path data: number expected (premature end of data)
comes from GraphicsPathParser.hpp.

  1. I have already raised an issue at asymptote.

vectorgraphics/asymptote#375

As you say, it seems to be that the generated dvi file is fine. So it might not be an issue on the side of asymptote but a platform-specific one.


Do you have an idea in which direction I could look? Is there anything platform-dependent regarding the GraphsPathParser.hpp?

My current assumption is that I have to compile dvisvgm myself with debug symbols to see what is going on in GraphsPathParser which I would really like to avoid.

@mgieseki
Copy link
Owner

I guess it's this issue. The behavior of operator >> differs between libstdc++ and libc++ if applied to floating point numbers. libc++ seems to be the default on Mac.
While ligstdc++ just stops parsing a number as soon as an unexpected character occurs, libc++ immediately raises an error. So, when parsing the path commands M 0 2.50937L 2.50937 2.50937 on a Mac, it fails at the L because it's not a valid digit of the y-coordinate. libstdc++ just stops and returns the proper value 2.50937.
I think I need to find some workaround for this. At the moment, there's probably nothing you can do about it.

@kiryph
Copy link
Author

kiryph commented Apr 27, 2023

Thanks for pointing out this difference between the two implementations of the STL regarding the operator >>. This sounds like the reason, even though the rectangle example works.

What baffles me in particular is that this issue is 10 years old (llvm/llvm-project#18156).

Writing correct parsers is IMHO always challenging, and something like SVG might be one of the even more complicated ones (xml+properties like paths). However, finding a license-compatible lightweight ready to use, actively maintained third-party library is also not a simple story.

Anyhow, I hope you find a workaround in the parser of dvisvgm and can fix it in one of the next releases of dvisvgm.

@kiryph
Copy link
Author

kiryph commented Apr 28, 2023

I did a little bit of further digging:

I took the test example from llvm/llvm-project#18156 and added a few lines related to SVG path parsing:

demo-double-stream.cpp
#include <sstream>
#include <iostream>

using namespace std;

void extract_double(const string & s)
{
  stringstream ss;
  double d;
  
  // testing number only
  ss << s;
  ss >> d;
  if(!ss.fail())
    cout << "'" << ss.str() << "' converted to " << d << endl;
  else
    cout << "'" << ss.str() << "' failed to convert to double" << endl;
}

int main()
{
  cout << "local is " << setlocale(LC_ALL, NULL) << endl;
  
  extract_double("-4.9");
  extract_double("-4.9 X");
  extract_double("-4.9_");

  cout << endl << "SVG Path parsing:" << endl;
  extract_double("2.50937L");
  extract_double("0L");
  extract_double("2.50937Z");

  cout << endl << "Issue between libc++ (llvm) and libstdc++ (gcc):" << endl;
  extract_double("-4.9d");
  extract_double("-4.9X");

  cout << "SVG Path parsing:" << endl;
  extract_double("1.25469C");
}

The results are

libc++ (llvm)

❯ clang++ -o parse_double-libc++ demo-double-stream.cpp
❯ ./parse_double-libc++
local is C
'-4.9' converted to -4.9
'-4.9 X' converted to -4.9
'-4.9_' converted to -4.9

SVG Path parsing:
'2.50937L' converted to 2.50937
'0L' converted to 0
'2.50937Z' converted to 2.50937

Issue between libc++ (llvm) and libstdc++ (gcc):
'-4.9d' failed to convert to double
'-4.9X' failed to convert to double
SVG Path parsing:
'1.25469C' failed to convert to double

libstdc++ (gcc)

❯ g++-12 -o parse_double-libstdc++ demo-double-stream.cpp
❯ ./parse_double-libstdc++
local is C
'-4.9' converted to -4.9
'-4.9 X' converted to -4.9
'-4.9_' converted to -4.9

SVG Path parsing:
'2.50937L' converted to 2.50937
'0L' converted to 0
'2.50937Z' converted to 2.50937

Issue between libc++ (llvm) and libstdc++ (gcc):
'-4.9d' converted to -4.9
'-4.9X' converted to -4.9
SVG Path parsing:
'1.25469C' converted to 1.25469

This confirms that libc++ throws an error for 1.25469C where libstdc++ does not.

Since this issue for libc++ is quite old and shows no sign of an upstream change, IMHO
dvisvgm should take this into account.

As a first step it should be specifically mentioned that libc++ (LLVM) cannot be used for dvisvgm and suggest to use libstdc++ (GCC). However, libstdc++ is not by default available on macOS and makes installation on macOS more complicated. There might also be other reasons why someone would like to use libc++.

Possible options to allow libc++

All of them sound like a major change in the code (new dependencies or a rewrite of the path parser).

I will try to compile dvisvgm myself using libstdc++ on macOS for now.

@muzimuzhi
Copy link

I will try to compile dvisvgm myself using libstdc++ on macOS for now.

I hardly know anything about how to compile either dvisvgm or Asymptote on macOS (though I'm on macOS), but if it's a litter bit easier to compile Asymptote on macOS using default settings, for a workaround it seems you can patch Asymptote to always insert a space before M, L, C, and Z.

Relevant lines in Asymptote https://github.com/vectorgraphics/asymptote/blob/494e8120ee967aa9c71ae26e2476b5632211b6e2/texfile.h#L419-L436

Or, does Asymptote allow executing user scripts after it writes to a tex file and before it runs latex command?

@kiryph
Copy link
Author

kiryph commented Apr 28, 2023

I hardly know anything about how to compile either dvisvgm or Asymptote on macOS (though I'm on macOS), but if it's a litter bit easier to compile Asymptote on macOS using default settings, for a workaround it seems you can patch Asymptote to always insert a space before M, L, C, and Z.

That's actually a suggestion I consider now. I am already struggling compiling dvisvgm since the kpathsea dependency is not easy to fulfil:

Thanks.

Or, does Asymptote allow executing user scripts after it writes to a tex file and before it runs latex command?

Not that I am aware of. I could add a workaround with the --keep option of asy. After the dvisvgm command fails, I could run a script to insert the spaces and run dvisvgm once again. Not a fan and the whole story becomes a little bit of a nightmare.

@kiryph kiryph changed the title XML error: error in path data: number expected (premature end of data) XML error on macOS: error in path data: number expected (premature end of data) Apr 28, 2023
@kiryph kiryph changed the title XML error on macOS: error in path data: number expected (premature end of data) macOS: XML error: error in path data: number expected (premature end of data) Apr 28, 2023
@kiryph
Copy link
Author

kiryph commented Apr 28, 2023

I have now patched Asymptote and compiled it myself:

--- a/texfile.h
+++ b/texfile.h
@@ -417,22 +417,22 @@ public:
   }

   void moveto(pair z) {
-    *out << "M";
+    *out << " M";
     writeshifted(z);
   }

   void lineto(pair z) {
-    *out << "L";
+    *out << " L";
     writeshifted(z);
   }

   void curveto(pair zp, pair zm, pair z1) {
-    *out << "C";
+    *out << " C";
     writeshifted(zp); writeshifted(zm); writeshifted(z1);
   }

   void closepath() {
-    *out << "Z";
+    *out << " Z";
   }
❯ asy --version
Asymptote version 2.86-8 [(C) 2004 Andy Hammerlindl, John C. Bowman, Tom Prince]

ENABLED OPTIONS:
V3D      3D vector graphics output
WebGL    3D HTML rendering
OpenGL   3D OpenGL rendering
SSBO     GLSL shader storage buffer objects
GSL      GNU Scientific Library (special functions)
FFTW3    Fast Fourier transforms
XDR      External Data Representation (portable binary file format for V3D)
CURL     URL support
LSP      Language Server Protocol
Readline Interactive history and editing
GC       Boehm garbage collector
threads  Render OpenGL in separate thread

DISABLED OPTIONS:
Eigen    Eigenvalue library
Sigsegv  Distinguish stack overflows from segmentation faults

Now I get a webgl output for draw(unitcircle);

However, I leave this issue open, since dvisvgm should handle all valid svg input correctly. Either dvisvgm should not compile with libc++ or find a workaround to deal with the difference between libc++ and libstdc++.

@mgieseki
Copy link
Owner

I've fixed the issue locally and will commit the patch after some more testing.

@mgieseki mgieseki added the bug label Apr 28, 2023
@mgieseki mgieseki added this to the 3.1 milestone Jul 6, 2023
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
Projects
None yet
Development

No branches or pull requests

3 participants