summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--generic/tkImgSVGnano.c64
-rw-r--r--tests/imgSVGnano.test54
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