From 839f52bc18dda4ce96b87c630c935d559e3bcb60 Mon Sep 17 00:00:00 2001 From: Manolo Gouy Date: Tue, 31 Oct 2017 16:56:23 +0000 Subject: [PATCH] Fix for STR#3421: Fl_SVG_Image crashes if passed an svg file that is a static const char* string git-svn-id: file:///fltk/svn/fltk/branches/branch-1.4@12536 ea41ed52-d2ee-0310-a9c1-e6b18d33e121 --- FL/Fl_SVG_Image.H | 62 +++++++++++++++++++++++++++++++++-- examples/howto-simple-svg.cxx | 2 +- src/Fl_SVG_Image.cxx | 18 +++++----- 3 files changed, 71 insertions(+), 11 deletions(-) diff --git a/FL/Fl_SVG_Image.H b/FL/Fl_SVG_Image.H index 0965b2639..b734ded77 100644 --- a/FL/Fl_SVG_Image.H +++ b/FL/Fl_SVG_Image.H @@ -43,6 +43,64 @@ struct NSVGimage; The FLTK library can optionally be built without SVG support; in that case, class Fl_SVG_Image is unavailable. + + Example of displaying a hard-coded svg file: + \code + #include + #include + #include + #include + + // A black rotated rectangle + const char *svg_data = "\n" + " \n"; + + int main(int argc, char **argv) { + Fl_SVG_Image *svg = new Fl_SVG_Image(0, svg_data); // create SVG object + Fl_Window *win = new Fl_Window(720, 486, "svg test"); + Fl_Box *box = new Fl_Box(0,0,win->w(),win->h()); + box->image(svg); // assign svg object to Fl_Box + win->end(); + win->show(argc,argv); + return(Fl::run()); + } + \endcode + + Example of displaying an svg image from a file: + \code + #include // errno + #include // strerror + #include + #include + #include + #include + #include + int main(int argc, char **argv) { + Fl_Window *win = new Fl_Window(720, 486, "svg test"); + Fl_Box *box = new Fl_Box(0,0,win->w(),win->h()); + + // Load svg image from disk, assign to a box + const char *svgpath = "/var/tmp/simple.svg"; + Fl_SVG_Image *svg = new Fl_SVG_Image(svgpath); // load SVG object from disk + switch ( svg->fail() ) { + case Fl_Image::ERR_FILE_ACCESS: + // File couldn't load? show path + os error to user + fl_alert("%s: %s", svgpath, strerror(errno)); + return 1; + case Fl_Image::ERR_FORMAT: + // Parsing error + fl_alert("%s: couldn't decode image", svgpath); + return 1; + } + box->image(svg); // assign svg object to box + + win->end(); + win->show(argc,argv); + return(Fl::run()); + } + \endcode + */ class FL_EXPORT Fl_SVG_Image : public Fl_RGB_Image { private: @@ -58,7 +116,7 @@ private: float average_weight_; float svg_scaling_(int W, int H); void rasterize_(int W, int H); - void init_(const char *filename, char *filedata, Fl_SVG_Image *copy_source); + void init_(const char *filename, const char *filedata, Fl_SVG_Image *copy_source); Fl_SVG_Image(Fl_SVG_Image *source); protected: virtual int draw_scaled(int X, int Y, int W, int H); @@ -66,7 +124,7 @@ public: /** Set this to \c false to allow image re-scaling that alters the image aspect ratio. Upon object creation, \c proportional is set to \c true, and the aspect ratio is kept constant.*/ bool proportional; - Fl_SVG_Image(const char *filename, char *filedata = NULL); + Fl_SVG_Image(const char *filename, const char *filedata = NULL); virtual ~Fl_SVG_Image(); virtual Fl_Image *copy(int W, int H); void resize(int width, int height); diff --git a/examples/howto-simple-svg.cxx b/examples/howto-simple-svg.cxx index 6b7c6bc11..b9f41fd71 100644 --- a/examples/howto-simple-svg.cxx +++ b/examples/howto-simple-svg.cxx @@ -59,7 +59,7 @@ int main(int argc, char **argv) { fl_message("You need to build fltk with --enable-nanosvg to use this example."); return(1); #else - Fl_SVG_Image *svg = new Fl_SVG_Image(NULL, (char*)strdup(svg_logo)); // XXX: strdup() shouldn't be needed -- see STR #3421 + Fl_SVG_Image *svg = new Fl_SVG_Image(NULL, svg_logo); Fl_Window *win = new Fl_Window(720, 486, "svg test"); Fl_Box *box = new Fl_Box(10,10,720-20,486-20); box->image(svg); diff --git a/src/Fl_SVG_Image.cxx b/src/Fl_SVG_Image.cxx index 557388c49..3ee48cd5f 100644 --- a/src/Fl_SVG_Image.cxx +++ b/src/Fl_SVG_Image.cxx @@ -48,9 +48,9 @@ static double strtoll(const char *str, char **endptr, int base) { \param filename A full path and name pointing to a .svg or .svgz file, or NULL. \param filedata A pointer to the memory location of the SVG image data. This parameter allows to load an SVG image from in-memory data, and is used when \p filename is NULL. - \note In-memory SVG data is modified by the object constructor and is no longer used after construction. + \note In-memory SVG data is parsed by the object constructor and is no longer used after construction. */ -Fl_SVG_Image::Fl_SVG_Image(const char *filename, char *filedata) : Fl_RGB_Image(NULL, 0, 0, 4) { +Fl_SVG_Image::Fl_SVG_Image(const char *filename, const char *filedata) : Fl_RGB_Image(NULL, 0, 0, 4) { init_(filename, filedata, NULL); } @@ -113,9 +113,9 @@ static char *svg_inflate(const char *fname) { } #endif -void Fl_SVG_Image::init_(const char *filename, char *filedata, Fl_SVG_Image *copy_source) { +void Fl_SVG_Image::init_(const char *filename, const char *in_filedata, Fl_SVG_Image *copy_source) { if (copy_source) { - filename = filedata = NULL; + filename = in_filedata = NULL; counted_svg_image_ = copy_source->counted_svg_image_; counted_svg_image_->ref_count++; } else { @@ -123,6 +123,7 @@ void Fl_SVG_Image::init_(const char *filename, char *filedata, Fl_SVG_Image *cop counted_svg_image_->svg_image = NULL; counted_svg_image_->ref_count = 1; } + char *filedata = NULL; to_desaturate_ = false; average_weight_ = 1; proportional = true; @@ -130,7 +131,6 @@ void Fl_SVG_Image::init_(const char *filename, char *filedata, Fl_SVG_Image *cop #if defined(HAVE_LIBZ) filedata = svg_inflate(filename); #else - filedata = NULL; FILE *fp = fl_fopen(filename, "rb"); if (fp) { fseek(fp, 0, SEEK_END); @@ -140,8 +140,7 @@ void Fl_SVG_Image::init_(const char *filename, char *filedata, Fl_SVG_Image *cop if (filedata) { if (fread(filedata, 1, size, fp) == size) { filedata[size] = '\0'; - } - else { + } else { free(filedata); filedata = NULL; } @@ -150,10 +149,13 @@ void Fl_SVG_Image::init_(const char *filename, char *filedata, Fl_SVG_Image *cop } #endif // HAVE_LIBZ if (!filedata) ld(ERR_FILE_ACCESS); + } else { + // XXX: Make internal copy -- nsvgParse() modifies filedata during parsing (!) + filedata = in_filedata ? strdup(in_filedata) : NULL; } if (filedata) { counted_svg_image_->svg_image = nsvgParse(filedata, "px", 96); - if (filename) free(filedata); + free(filedata); // made with svg_inflate|malloc|strdup if (counted_svg_image_->svg_image->width == 0 || counted_svg_image_->svg_image->height == 0) { d(-1); ld(ERR_FORMAT);