Skip to content

Fix duplicate clip-path attribute and restore piped stdin input - #52

Open
turbinefish wants to merge 2 commits into
kakwa:masterfrom
lanbingtech:fix/dup-clip-path-and-piped-stdin
Open

Fix duplicate clip-path attribute and restore piped stdin input#52
turbinefish wants to merge 2 commits into
kakwa:masterfrom
lanbingtech:fix/dup-clip-path-and-piped-stdin

Conversation

@turbinefish

Copy link
Copy Markdown

Two independent fixes found while converting EMF figures extracted from real Office documents. Both are reproducible on current master and on the 1.8.1 tag.

1. endFormDraw() emits a second clip-path attribute

startPathDraw() already writes clip-path when it opens the element.
endFormDraw() wrote it a second time on the same element, so any record that goes through both (the pie/chord/arc family) produced:

    <path clip-path="url(#clip-N)" ... clip-path="url(#clip-N)" />

That is not well-formed XML (duplicate attribute), so a conforming SVG renderer rejects the whole document. One such record makes the entire figure unrenderable, not merely mis-drawn:

    $ emf2svg-conv -i chart.emf -o chart.svg && rsvg-convert -o chart.png chart.svg
    Error reading SVG chart.svg: XML parse error: Attribute clip-path redefined

Dropping the duplicated call in endFormDraw() is enough; the attribute is still emitted once, by startPathDraw().

2. emf2svg-conv can no longer read a pipe

The converter seeks to the end of the input to size its buffer before reading.
That works for a regular file but not for a pipe, where the reported size is 0,so the tool aborts (std::bad_alloc) on:

    $ cat figure.emf | emf2svg-conv -i /dev/stdin -o /dev/stdout

Reading the stream sequentially restores the pre-1.8 behaviour. Ownership of the buffer is unchanged, so the rest of main() is untouched.

Verification

Tested on 12 EMF files extracted from real-world Office documents (a Word design
document and a legacy PowerPoint deck), all of them dual EMF/EMF+ files:

  • Before: 11/12 converted, 1/12 was rejected outright by the renderer.
  • After: 12/12 convert and render, and the 11 previously working outputs are byte-for-byte identical — so the first change only affects the records that were producing invalid markup.
  • The pipe path was verified end to end with cat f.emf | emf2svg-conv -i /dev/stdin -o /dev/stdout | rsvg-convert -b white.

Happy to split this into two pull requests if you prefer them separate.

G.Z added 2 commits August 28, 2026 21:27
startPathDraw() already writes the clip-path attribute when it opens the
element. endFormDraw() wrote it a second time on the same element, so any
record that goes through both (the pie/chord/arc family) produced

    <path clip-path="url(#clip-N)" ... clip-path="url(#clip-N)" />

which is not well-formed XML (duplicate attribute). A conforming SVG
renderer rejects the whole document, so a single such record makes the
entire figure unrenderable -- not merely mis-drawn.

Dropping the duplicated call in endFormDraw() is enough: the attribute is
still emitted once, by startPathDraw().

Verified on 12 real-world EMF files taken from Office documents: before
the change 11/12 rendered and 1/12 was rejected outright; after it 12/12
render, and the 11 previously working outputs are byte-for-byte identical,
so the change only affects the records that were producing invalid markup.
The CLI sized its input buffer with seekg(end) + tellg(). That only works
on a seekable stream: when the input is a pipe -- which is what
"-i /dev/stdin" is in the common `producer | emf2svg-conv -i /dev/stdin`
shape -- tellg() returns -1, the value wraps around when stored in a
size_t, and `new char[size]` throws std::bad_alloc, so the process aborts
before reading a single byte.

Reading through std::istreambuf_iterator (the variant that was already
sitting commented out right below) needs no seeking and handles regular
files and pipes alike. 1.1.0 accepted piped input; the seek-based sizing
introduced in the 1.8 series regressed it.

Ownership of `contents` is unchanged (still new[]/delete[]), so the rest
of the function is untouched.
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant