Merge pull request #22 from guzba/master

fuzz svg + always pixieerror
This commit is contained in:
treeform 2020-12-04 10:37:18 -08:00 committed by GitHub
commit da351692d8
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
3 changed files with 46 additions and 28 deletions

View file

@ -5,16 +5,14 @@ import chroma, pixie/images, pixie/common, pixie/paths, vmath, xmlparser, xmltre
const svgSignature* = "<?xml" const svgSignature* = "<?xml"
var tmp: Image
proc draw(img: Image, matStack: var seq[Mat3], xml: XmlNode) = proc draw(img: Image, matStack: var seq[Mat3], xml: XmlNode) =
case xml.tag: case xml.tag:
of "g": of "g":
let fill = xml.attr("fill") let
let stroke = xml.attr("stroke") fill = xml.attr("fill")
let strokeWidth = xml.attr("stroke-width") stroke = xml.attr("stroke")
let transform = xml.attr("transform") strokeWidth = xml.attr("stroke-width")
transform = xml.attr("transform")
if transform != "": if transform != "":
if transform.startsWith("matrix("): if transform.startsWith("matrix("):
@ -29,10 +27,8 @@ proc draw(img: Image, matStack: var seq[Mat3], xml: XmlNode) =
m[7] = parseFloat(arr[5]) m[7] = parseFloat(arr[5])
matStack.add(matStack[^1] * m) matStack.add(matStack[^1] * m)
else: else:
var m = mat3()
matStack.add(m)
raise newException( raise newException(
PixieError, "Unsupported transform: " & transform & ".") PixieError, "Unsupported SVG transform: " & transform & ".")
for child in xml: for child in xml:
if child.tag == "path": if child.tag == "path":
@ -40,7 +36,8 @@ proc draw(img: Image, matStack: var seq[Mat3], xml: XmlNode) =
if fill != "none" and fill != "": if fill != "none" and fill != "":
let fillColor = parseHtmlColor(fill).rgba let fillColor = parseHtmlColor(fill).rgba
var (bounds, fillImg) = fillPathBounds(d, fillColor, mat = matStack[^1]) let (bounds, fillImg) =
fillPathBounds(d, fillColor, mat = matStack[^1])
img.draw(fillImg, bounds.xy) img.draw(fillImg, bounds.xy)
if stroke != "none" and stroke != "": if stroke != "none" and stroke != "":
@ -48,7 +45,8 @@ proc draw(img: Image, matStack: var seq[Mat3], xml: XmlNode) =
let strokeWidth = let strokeWidth =
if strokeWidth == "": 1.0 # Default stroke width is 1px if strokeWidth == "": 1.0 # Default stroke width is 1px
else: parseFloat(strokeWidth) else: parseFloat(strokeWidth)
var (bounds, strokeImg) = strokePathBounds(d, strokeColor, strokeWidth, mat = matStack[^1]) let (bounds, strokeImg) =
strokePathBounds(d, strokeColor, strokeWidth, mat = matStack[^1])
img.draw(strokeImg, bounds.xy) img.draw(strokeImg, bounds.xy)
else: else:
@ -58,22 +56,25 @@ proc draw(img: Image, matStack: var seq[Mat3], xml: XmlNode) =
discard matStack.pop() discard matStack.pop()
else: else:
raise newException(PixieError, "Unsupported tag: " & xml.tag & ".") raise newException(PixieError, "Unsupported SVG tag: " & xml.tag & ".")
proc decodeSvg*(data: string): Image = proc decodeSvg*(data: string): Image =
## Render SVG file and return the image. ## Render SVG file and return the image.
var xml = parseXml(data) try:
assert xml.tag == "svg" var xml = parseXml(data)
var viewBox = xml.attr "viewBox" assert xml.tag == "svg"
let box = viewBox.split(" ") var viewBox = xml.attr "viewBox"
assert parseInt(box[0]) == 0 let box = viewBox.split(" ")
assert parseInt(box[1]) == 0 assert parseInt(box[0]) == 0
let w = parseInt(box[2]) assert parseInt(box[1]) == 0
let h = parseInt(box[3]) let w = parseInt(box[2])
result = newImage(w, h) let h = parseInt(box[3])
result = newImage(w, h)
tmp = result.copy() var matStack = @[mat3()]
for n in xml:
var matStack = @[mat3()] result.draw(matStack, n)
for n in xml: except PixieError as e:
result.draw(matStack, n) raise e
except:
raise newException(PixieError, "Unable to load SVG")

View file

@ -3,4 +3,4 @@ import pixie/fileformats/svg, benchy
let data = readFile("tests/images/svg/Ghostscript_Tiger.svg") let data = readFile("tests/images/svg/Ghostscript_Tiger.svg")
timeIt "svg decode": timeIt "svg decode":
discard decodeSvg(data) keep decodeSvg(data)

17
tests/fuzz_svg.nim Normal file
View file

@ -0,0 +1,17 @@
import random, strformat, pixie/fileformats/svg, pixie/common
randomize()
let original = readFile("tests/images/svg/Ghostscript_Tiger.svg")
for i in 0 ..< 10_000:
var data = original
let
pos = rand(data.len)
value = rand(255).char
data[pos] = value
echo &"{i} {pos} {value}"
try:
discard decodeSvg(data)
except PixieError:
discard