diff options
-rw-r--r-- | generic/tkImgSVGnano.c | 64 | ||||
-rw-r--r-- | tests/imgSVGnano.test | 54 |
2 files changed, 96 insertions, 22 deletions
diff --git a/generic/tkImgSVGnano.c b/generic/tkImgSVGnano.c index 4cdb648..61db86b 100644 --- a/generic/tkImgSVGnano.c +++ b/generic/tkImgSVGnano.c @@ -52,6 +52,8 @@ typedef struct { RastOpts ropts; } NSVGcache; +static const void * MemMem(const void *haystack, size_t haysize, + const void *needle, size_t needlen); static int FileMatchSVG(Tcl_Channel chan, const char *fileName, Tcl_Obj *format, int *widthPtr, int *heightPtr, Tcl_Interp *interp); @@ -101,6 +103,46 @@ Tk_PhotoImageFormat tkImgFmtSVGnano = { /* *---------------------------------------------------------------------- * + * MemMem -- + * + * Like strstr() but operating on memory buffers with sizes. + * + *---------------------------------------------------------------------- + */ + +static const void * +MemMem(const void *haystack, size_t haylen, + const void *needle, size_t needlen) +{ + const void *hayend, *second, *p; + unsigned char first; + + if ((needlen <= 0) || (haylen < needlen)) { + return NULL; + } + hayend = (const void *) ((char *) haystack + haylen - needlen); + first = ((char *) needle)[0]; + second = (const void *) ((char *) needle + 1); + needlen -= 1; + while (haystack < hayend) { + p = memchr(haystack, first, (char *) hayend - (char *) haystack); + if (p == NULL) { + break; + } + if (needlen == 0) { + return p; + } + haystack = (const void *) ((char *) p + 1); + if (memcmp(second, haystack, needlen) == 0) { + return p; + } + } + return NULL; +} + +/* + *---------------------------------------------------------------------- + * * FileMatchSVG -- * * This function is invoked by the photo image type to see if a file @@ -132,12 +174,24 @@ FileMatchSVG( (void)fileName; CleanCache(interp); - if (Tcl_ReadChars(chan, dataObj, -1, 0) == TCL_IO_FAILURE) { + if (Tcl_ReadChars(chan, dataObj, 4096, 0) == TCL_IO_FAILURE) { /* in case of an error reading the file */ Tcl_DecrRefCount(dataObj); return 0; } data = TkGetStringFromObj(dataObj, &length); + /* should have a '<svg' and a '>' in the first 4k */ + if ((memchr(data, '>', length) == NULL) || + (MemMem(data, length, "<svg", 4) == NULL)) { + Tcl_DecrRefCount(dataObj); + return 0; + } + if (!Tcl_Eof(chan) && (Tcl_ReadChars(chan, dataObj, -1, 1) == TCL_IO_FAILURE)) { + /* in case of an error reading the file */ + Tcl_DecrRefCount(dataObj); + return 0; + } + data = Tcl_GetStringFromObj(dataObj, &length); nsvgImage = ParseSVGWithOptions(interp, data, length, formatObj, &ropts); Tcl_DecrRefCount(dataObj); if (nsvgImage != NULL) { @@ -237,13 +291,19 @@ StringMatchSVG( int *widthPtr, int *heightPtr, Tcl_Interp *interp) { - TkSizeT length; + TkSizeT length, testLength; const char *data; RastOpts ropts; NSVGimage *nsvgImage; CleanCache(interp); data = TkGetStringFromObj(dataObj, &length); + /* should have a '<svg' and a '>' in the first 4k */ + testLength = (length > 4096) ? 4096 : length; + if ((memchr(data, '>', testLength) == NULL) || + (MemMem(data, testLength, "<svg", 4) == NULL)) { + return 0; + } nsvgImage = ParseSVGWithOptions(interp, data, length, formatObj, &ropts); if (nsvgImage != NULL) { GetScaleFromParameters(nsvgImage, &ropts, widthPtr, heightPtr); diff --git a/tests/imgSVGnano.test b/tests/imgSVGnano.test index e2789c2..1dad3a5 100644 --- a/tests/imgSVGnano.test +++ b/tests/imgSVGnano.test @@ -12,20 +12,23 @@ tcltest::loadTestedCommands imageInit namespace eval svgnano { + variable data - set data(plus) {<svg xmlns="http://www.w3.org/2000/svg" width="100" height="100"> -<path fill="none" stroke="#000000" d="M0 0 h16 v16 h-16 z"/> -<path fill="none" stroke="#000000" d="M8 4 v 8 M4 8 h 8"/> -<circle fill="yellow" stroke="red" cx="10" cy="80" r="10" /> -<ellipse fill="none" stroke="blue" stroke-width="3" cx="60" cy="60" rx="10" ry="20" /> -<line x1="10" y1="90" x2="50" y2="99"/> -<rect fill="none" stroke="green" x="20" y="20" width="60" height="50" rx="3" ry="3"/> -<polyline fill="red" stroke="purple" points="80,10 90,20 85,40"/> -<polygon fill ="yellow" points="80,80 70,85 90,90"/> -</svg>} - set data(bad) {<svg xmlns="http://www.w3.org/2000/svg" width="0" height="0:w -"> -</svg>} + + set data(plus) {\ + <svg xmlns="http://www.w3.org/2000/svg" width="100" height="100"> + <path fill="none" stroke="#000000" d="M0 0 h16 v16 h-16 z"/> + <path fill="none" stroke="#000000" d="M8 4 v 8 M4 8 h 8"/> + <circle fill="yellow" stroke="red" cx="10" cy="80" r="10" /> + <ellipse fill="none" stroke="blue" stroke-width="3" cx="60" cy="60" rx="10" ry="20" /> + <line x1="10" y1="90" x2="50" y2="99"/> + <rect fill="none" stroke="green" x="20" y="20" width="60" height="50" rx="3" ry="3"/> + <polyline fill="red" stroke="purple" points="80,10 90,20 85,40"/> + <polygon fill ="yellow" points="80,80 70,85 90,90"/> + </svg>} + set data(bad) {<svg xmlns="http://www.w3.org/2000/svg" width="0" height="0:w"> + </svg>\ + } tcltest::makeFile $data(plus) plus.svg set data(plusFilePath) [file join [tcltest::configure -tmpdir] plus.svg] @@ -33,6 +36,7 @@ namespace eval svgnano { tcltest::makeFile $data(bad) bad.svg set data(badFilePath) [file join [tcltest::configure -tmpdir] bad.svg] + test imgSVGnano-1.1 {reading simple image} -setup { catch {rename foo ""} } -body { @@ -72,6 +76,7 @@ test imgSVGnano-1.4 {image options} -setup { } -cleanup { rename foo "" } -result {100 100} + test imgSVGnano-1.5 {reading simple image from file} -setup { catch {rename foo ""} } -body { @@ -80,8 +85,7 @@ test imgSVGnano-1.5 {reading simple image from file} -setup { } -cleanup { rename foo "" } -result {100 100} - -test imgSVGnano-1.6 {simple image with options} -setup { +test imgSVGnano-1.6 {simple image from file with options} -setup { catch {rename foo ""} } -body { image create photo foo -file $data(plusFilePath) -format {svg -dpi 100 -scale 3} @@ -89,14 +93,15 @@ test imgSVGnano-1.6 {simple image with options} -setup { } -cleanup { rename foo "" } -result {300 300} -test imgSVGnano-1.7 {Very small scale gives 1x1 image} -body { + +test imgSVGnano-1.7 {very small scale gives 1x1 image} -body { image create photo foo -format "svg -scale 0.000001"\ -data $data(plus) list [image width foo] [image height foo] } -cleanup { rename foo "" } -result {1 1} -test imgSVGnano-1.8 {Very small scale gives 1x1 image from file} -body { +test imgSVGnano-1.8 {very small scale gives 1x1 image, from file} -body { image create photo foo -format "svg -scale 0.000001"\ -file $data(plusFilePath) list [image width foo] [image height foo] @@ -152,7 +157,7 @@ test imgSVGnano-3.6 {no number parameter to -scaletoheight} -body { -data $data(plus) } -returnCodes error -result {expected integer but got "invalid"} -test imgSVGnano-3.7 {Option -scaletowidth} -body { +test imgSVGnano-3.7 {option -scaletowidth} -body { image create photo foo -format "svg -scaletowidth 20"\ -data $data(plus) image width foo @@ -160,7 +165,7 @@ test imgSVGnano-3.7 {Option -scaletowidth} -body { rename foo "" } -result 20 -test imgSVGnano-3.8 {Option -scaletoheight} -body { +test imgSVGnano-3.8 {option -scaletoheight} -body { image create photo foo -format "svg -scaletoheight 20"\ -data $data(plus) image height foo @@ -194,7 +199,6 @@ test imgSVGnano-4.1 {reread file on configure -scale} -setup { unset res } -result {100 100 200 200} - test imgSVGnano-4.2 {error on file not accessible on reread due to configure} -setup { catch {rename foo ""} tcltest::makeFile $data(plus) tmpplus.svg @@ -235,6 +239,16 @@ test imgSVGnano-5.1 {bug ea665e08f3 - too many values in parameters of the trans rename foo "" } -result {foo} +test imgSVGnano-5.2 {bug d6e9b4db40 - "<svg" and ">" must be present} -body { + image create photo foo -format svg -data\ + {<?xml version="1.0"?><!DOCTYPE svg PUBLIC\ + "-//W3C//DTD SVG 1.0//EN\" \ + "http://www.w3.org/TR/2001/REC-SVG-20010904/DTD/svg10.dtd">\ + <sERRORvBADFILEg xmlns="http://www.w3.org/2000/svg">\ + <circle cx="6.5cm" cy="2cm" r="100" transform="skewX(1 1)"/>\ + </g></svg>} +} -returnCodes error -result {couldn't recognize image data} + };# end of namespace svgnano namespace delete svgnano |