ext/RMagick/rmutil.c in rmagick-3.0.0 vs ext/RMagick/rmutil.c in rmagick-3.1.0

- old
+ new

@@ -227,10 +227,31 @@ } } /** + * Raise exception if ary argument was invalid type + * + * No Ruby usage (internal function) + * + * @param ary the array + * @return the array that is converted type of argument object if needed + * @throw TypeError + */ +VALUE +rm_check_ary_type(VALUE ary) +{ + VALUE checked = rb_check_array_type(ary); + if (NIL_P(checked)) + { + rb_raise(rb_eTypeError, "wrong argument type %"PRIsVALUE" was given. (must respond to :to_ary)", rb_obj_class(ary)); + } + return checked; +} + + +/** * Raise an error if the image has been destroyed. * * No Ruby usage (internal function) * * @param obj the image @@ -597,10 +618,25 @@ return NUM2QUANTUM(v); } /** + * Returns a pointer to an image structure initialized to default values + * + * No Ruby usage (internal function) + * + * @param info the info + * @return the created image + */ +Image * +rm_acquire_image(ImageInfo *info) +{ + return AcquireImage(info); +} + + +/** * Send the "cur_image" method to the object. If 'img' is an ImageList, then * cur_image is self[\@scene]. If 'img' is an image, then cur_image is simply * 'self'. * * No Ruby usage (internal function) @@ -619,16 +655,16 @@ * Map the color intensity to a named color. * * No Ruby usage (internal function) * * @param image the image - * @param color the color intensity as a PixelPacket + * @param color the color intensity as a PixelColor * @return the named color as a String - * @see rm_pixelpacket_to_color_name_info + * @see rm_pixelcolor_to_color_name_info */ VALUE -rm_pixelpacket_to_color_name(Image *image, PixelPacket *color) +rm_pixelcolor_to_color_name(Image *image, PixelColor *color) { char name[MaxTextExtent]; ExceptionInfo *exception; exception = AcquireExceptionInfo(); @@ -647,44 +683,72 @@ * No Ruby usage (internal function) * * Notes: * - Simply create an Image from the Info, call QueryColorname, and then * destroy the Image. - * - If the Info structure is NULL, creates a new one. * - The default depth is always used, and the matte value is set to False, * which means "don't use the alpha channel". * * @param info the info - * @param color the color intensity as a PixelPacket + * @param color the color intensity as a PixelColor * @return the named color as a String - * @see rm_pixelpacket_to_color_name + * @see rm_pixelcolor_to_color_name */ VALUE -rm_pixelpacket_to_color_name_info(Info *info, PixelPacket *color) +rm_pixelcolor_to_color_name_info(Info *info, PixelColor *color) { Image *image; - Info *my_info; VALUE color_name; - my_info = info ? info : CloneImageInfo(NULL); + image = rm_acquire_image(info); + if (!image) + { + rb_raise(rb_eNoMemError, "not enough memory to continue."); + } - image = AcquireImage(info); image->matte = MagickFalse; - color_name = rm_pixelpacket_to_color_name(image, color); + color_name = rm_pixelcolor_to_color_name(image, color); (void) DestroyImage(image); - if (!info) - { - (void) DestroyImageInfo(my_info); - } - RB_GC_GUARD(color_name); - return color_name; } +/** + * Initializes the MagickPixel structure. + * + * No Ruby usage (internal function) + * + * @param image the image + * @param pp the MagickPixel + */ +void +rm_init_magickpixel(const Image *image, MagickPixel *pp) +{ + GetMagickPixelPacket(image, pp); +} /** + * Initializes the MagickPixel structure to the specified color. + * + * No Ruby usage (internal function) + * + * @param pp the MagickPixel + * @param color the color + */ +void +rm_set_magickpixel(MagickPixel *pp, const char *color) +{ + ExceptionInfo *exception; + + exception = AcquireExceptionInfo(); + (void) QueryMagickColor(color, pp, exception); + // This exception is ignored because the color comes from places where we control + // the value and it is very unlikely that an exception will be thrown. + (void) DestroyExceptionInfo(exception); +} + +/** * Write a temporary copy of the image to the IM registry. * * No Ruby usage (internal function) * * Notes: @@ -771,11 +835,11 @@ void rm_not_implemented(void) { rb_raise(rb_eNotImpError, "the `%s' method is not supported by ImageMagick " - MagickLibVersionText, rb_id2name(THIS_FUNC())); + MagickLibVersionText, rb_id2name(rb_frame_this_func())); } /** * Create a new ImageMagickError object and raise an exception. @@ -785,28 +849,25 @@ * Notes: * - This funky technique allows me to safely add additional information to * the ImageMagickError object in both 1.6.8 and 1.8.0. * * @param msg the error mesage - * @param loc the location of the error * @throw ImageMagickError * @see www.ruby_talk.org/36408. */ void -rm_magick_error(const char *msg, const char *loc) +rm_magick_error(const char *msg) { - VALUE exc, mesg, extra; + VALUE exc, mesg; mesg = rb_str_new2(msg); - extra = loc ? rb_str_new2(loc) : Qnil; - exc = rb_funcall(Class_ImageMagickError, rm_ID_new, 2, mesg, extra); + exc = rb_funcall(Class_ImageMagickError, rm_ID_new, 2, mesg, Qnil); (void) rb_funcall(rb_cObject, rb_intern("raise"), 1, exc); RB_GC_GUARD(exc); RB_GC_GUARD(mesg); - RB_GC_GUARD(extra); } /** * Initialize a new ImageMagickError object - store the "loc" string in the @@ -895,11 +956,10 @@ * @param images a list of images * @param info the info */ void rm_set_user_artifact(Image *images, Info *info) { -#if defined(HAVE_SETIMAGEARTIFACT) Image *image; const char *value; value = GetImageOption(info, "user"); if (value) @@ -909,14 +969,10 @@ { (void) SetImageArtifact(image, "user", value); image = GetNextImageInList(image); } } -#else - images = images; - info = info; -#endif } /** * Collect optional method arguments via Magick::OptionalMethodArguments. @@ -951,11 +1007,10 @@ return; } -#if defined(HAVE_SETIMAGEARTIFACT) /** * Copy image options from the Info structure to the Image structure. * * No Ruby usage (internal function) * @@ -977,11 +1032,10 @@ property[MaxTextExtent-1] = '\0'; (void) SetImageArtifact(image, property, value); } } } -#endif /** * Propagate ImageInfo values to the Image * @@ -1011,11 +1065,11 @@ image->border_color = info->border_color; } if (info->colorspace != UndefinedColorspace) { - image->colorspace = info->colorspace; + SetImageColorspace(image, info->colorspace); } if (info->compression != UndefinedCompression) { image->compression = info->compression; @@ -1107,16 +1161,14 @@ if (option) { image->transparent_color = info->transparent_color; } -#if defined(HAVE_ST_TYPE) if (info->type != UndefinedType) { image->type = info->type; } -#endif if (info->units != UndefinedResolution) { if (image->units != info->units) { @@ -1146,13 +1198,11 @@ } image->units = info->units; } -#if defined(HAVE_SETIMAGEARTIFACT) copy_options(image, info); -#endif } /** * Replicate old (ImageMagick < 6.3.2) EXIF:* functionality using @@ -1443,37 +1493,44 @@ const char *tag, const MagickOffsetType of, const MagickSizeType sp, void *client_data) { -#if !defined(_WIN32) VALUE rval; VALUE method, offset, span; +// Default Ruby minimum stack size +#define RUBY_VM_THREAD_MACHINE_STACK_SIZE_MIN ( 16 * 1024 * sizeof(VALUE)) /* 64 KB or 128 KB */ + + // Check stack length manually instead of ruby_stack_check() for old Ruby. + if (ruby_stack_length(NULL) > RUBY_VM_THREAD_MACHINE_STACK_SIZE_MIN) + { + // If there is not enough stack or the using stack size shows an abnormal value in Ruby, + // skip the callback and continue ImageMagick process. + return MagickTrue; + } + tag = tag; // defeat gcc message #if defined(HAVE_LONG_LONG) // defined in Ruby's defines.h offset = rb_ll2inum(of); span = rb_ull2inum(sp); #else offset = rb_int2big((long)of); span = rb_uint2big((unsigned long)sp); #endif - method = rb_str_new2(rb_id2name(THIS_FUNC())); + method = rb_id2str(rb_frame_this_func()); rval = rb_funcall((VALUE)client_data, rm_ID_call, 3, method, offset, span); RB_GC_GUARD(rval); RB_GC_GUARD(method); RB_GC_GUARD(offset); RB_GC_GUARD(span); return RTEST(rval) ? MagickTrue : MagickFalse; -#else - return MagickTrue; -#endif } /** * Remove the ImageMagick links between images in an scene sequence. @@ -1549,11 +1606,41 @@ (void) DestroyExceptionInfo(exception); } +#define ERROR_MSG_SIZE 1024 /** + * Formats the exception into the message buffer + * + * No Ruby usage (internal function) + * + * @param severity information about the severity of the error + * @param reason the reason for the error + * @param description description of the error + * @param msg the buffer where the exception message should be formated in + */ +static void +format_exception(const ExceptionType severity, const char *reason, const char *description, char *msg) +{ + int len; + memset(msg, 0, sizeof(ERROR_MSG_SIZE)); + +#if defined(HAVE_SNPRINTF) + len = snprintf(msg, ERROR_MSG_SIZE, "%s%s%s", +#else + len = sprintf(msg, "%.500s%s%.500s", +#endif + GetLocaleExceptionMessage(severity, reason), + description ? ": " : "", + description ? GetLocaleExceptionMessage(severity, description) : ""); + + msg[len] = '\0'; +} + + +/** * Call handle_exception if there is an exception to handle. * * No Ruby usage (internal function) * * @param exception information about the exception @@ -1584,63 +1671,54 @@ * @param description description of the warning */ void rm_warning_handler(const ExceptionType severity, const char *reason, const char *description) { - ExceptionType dummy; - - rb_warning("RMagick: %s: `%s'", reason, description); - dummy = severity; - dummy = dummy; + rb_warning("RMagick: %s%s%s", + GetLocaleExceptionMessage(severity, reason), + description ? ": " : "", + description ? GetLocaleExceptionMessage(severity, description) : ""); } /** * Called from ImageMagick for a error. * * No Ruby usage (internal function) * - * @param severity information about the severity of the error (ignored) + * @param severity information about the severity of the error * @param reason the reason for the error * @param description description of the error */ void rm_error_handler(const ExceptionType severity, const char *reason, const char *description) { - char msg[500]; - int len; - ExceptionType dummy; + char msg[ERROR_MSG_SIZE]; - memset(msg, 0, sizeof(msg)); -#if defined(HAVE_SNPRINTF) - len = snprintf(msg, sizeof(msg), "%s: `%s'", reason, description); -#else - len = sprintf(msg, "%.250s: `%.240s'", reason, description); -#endif - msg[len] = '\0'; + format_exception(severity, reason, description, msg); - rm_magick_error(msg, NULL); - dummy = severity; - dummy = dummy; + rm_magick_error(msg); } /** * Called from ImageMagick for a fatal error. * * No Ruby usage (internal function) * * @param severity information about the severity of the error * @param reason the reason for the error - * @param description description of the error (ignored) + * @param description description of the error * @throw FatalImageMagickError */ void rm_fatal_error_handler(const ExceptionType severity, const char *reason, const char *description) { - rb_raise(Class_FatalImageMagickError, "%s", GetLocaleExceptionMessage(severity, reason)); - description = description; + rb_raise(Class_FatalImageMagickError, "%s%s%s", + GetLocaleExceptionMessage(severity, reason), + description ? ": " : "", + description ? GetLocaleExceptionMessage(severity, description) : ""); } /** * Called when rm_check_exception determines that we need to either issue a @@ -1655,31 +1733,16 @@ * or DestroyOnError) */ static void handle_exception(ExceptionInfo *exception, Image *imglist, ErrorRetention retention) { + char msg[ERROR_MSG_SIZE]; - char reason[500]; - char desc[500]; - char msg[sizeof(reason)+sizeof(desc)+20]; - - memset(msg, 0, sizeof(msg)); - - // Handle simple warning if (exception->severity < ErrorException) { -#if defined(HAVE_SNPRINTF) - snprintf(msg, sizeof(msg)-1, "RMagick: %s%s%s", -#else - sprintf(msg, "RMagick: %.500s%s%.500s", -#endif - GetLocaleExceptionMessage(exception->severity, exception->reason), - exception->description ? ": " : "", - exception->description ? GetLocaleExceptionMessage(exception->severity, exception->description) : ""); - msg[sizeof(msg)-1] = '\0'; - rb_warning("%s", msg); + rm_warning_handler(exception->severity, exception->reason, exception->description); // Caller deletes ExceptionInfo... return; } @@ -1700,44 +1763,15 @@ { rm_split(imglist); } } + format_exception(exception->severity, exception->reason, exception->description, msg); - // Clone the ExceptionInfo with all arguments on the stack. - memset(reason, 0, sizeof(reason)); - memset(desc, 0, sizeof(desc)); - - if (exception->reason) - { - strncpy(reason, exception->reason, sizeof(reason)-1); - reason[sizeof(reason)-1] = '\0'; - } - if (exception->description) - { - strncpy(desc, exception->description, sizeof(desc)-1); - desc[sizeof(desc)-1] = '\0'; - } - - -#if defined(HAVE_SNPRINTF) - snprintf(msg, sizeof(msg)-1, "%s%s%s", - GetLocaleExceptionMessage(exception->severity, reason), - desc[0] ? ": " : "", - desc[0] ? GetLocaleExceptionMessage(exception->severity, desc) : ""); -#else - sprintf(msg, "%.*s%s%.*s", - sizeof(reason)-1, GetLocaleExceptionMessage(exception->severity, reason), - desc[0] ? ": " : "", - sizeof(desc)-1, desc[0] ? GetLocaleExceptionMessage(exception->severity, desc) : ""); -#endif - - msg[sizeof(msg)-1] = '\0'; - (void) DestroyExceptionInfo(exception); - rm_magick_error(msg, NULL); + rm_magick_error(msg); } /** * RMagick expected a result. If it got NULL instead raise an exception. @@ -1752,7 +1786,57 @@ { if (!image) { rb_raise(rb_eRuntimeError, MagickPackageName " library function failed to return a result."); } +} + + +/** + * Checks if an error should be raised for the exception. + * + * No Ruby usage (internal function) + * + * @param exception information about the exception + * @param retention retention strategy for the exception in case there was no error + */ +MagickBooleanType +rm_should_raise_exception(ExceptionInfo *exception, const ExceptionRetention retention) +{ + if (exception->severity < ErrorException) + { + if (exception->severity != UndefinedException) + { + rm_warning_handler(exception->severity, exception->reason, exception->description); + } + + if (retention == DestroyExceptionRetention) + { + (void) DestroyExceptionInfo(exception); + } + + return MagickFalse; + } + + return MagickTrue; +} + + +/** + * Raises an exception. + * + * No Ruby usage (internal function) + * + * @param exception information about the exception + */ +void +rm_raise_exception(ExceptionInfo *exception) +{ + char msg[ERROR_MSG_SIZE]; + + format_exception(exception->severity, exception->reason, exception->description, msg); + + (void) DestroyExceptionInfo(exception); + + rm_magick_error(msg); }