From c1b555a9419c8fd38b66dd40a56a560e24e4d6b7 Mon Sep 17 00:00:00 2001 From: simonbachmann Date: Sat, 8 Apr 2017 12:50:06 +0000 Subject: Fixed bug in format suboptions parsing (crash with no value to -colorformat) --- generic/tkImgListFormat.c | 587 +++++++++++++++++++++++++++------------------- tests/imgListFormat.test | 339 +++++++++++++++----------- 2 files changed, 540 insertions(+), 386 deletions(-) diff --git a/generic/tkImgListFormat.c b/generic/tkImgListFormat.c index a20a102..d0c72ff 100644 --- a/generic/tkImgListFormat.c +++ b/generic/tkImgListFormat.c @@ -3,7 +3,7 @@ * * Implements the default image data format. I.e. the format used for * [imageName data] and [imageName put] if no other format is specified. - * + * * The default format consits of a list of scan lines (rows) with each * list element being itself a list of pixels (or columns). For details, * see the manpage photo.n @@ -22,12 +22,13 @@ * * Authors: * Paul Mackerras (paulus@cs.anu.edu.au), - * Department of Computer Science, - * Australian National University. + * Department of Computer Science, + * Australian National University. * - * Simon Bachmann (simonbachmann@bluewin.ch) + * Simon Bachmann (simonbachmann@bluewin.ch) */ + #include "tkImgPhoto.h" /* @@ -35,7 +36,7 @@ */ #define TK_PHOTO_ALLOC_FAILURE_MESSAGE \ - "not enough free memory for image buffer" + "not enough free memory for image buffer" /* @@ -81,12 +82,12 @@ static const char *const colorFormatNames[] = { */ struct FormatOptions { - int options; /* Individual bits indicate which options were - * specified - see below. */ - Tcl_Obj *formatName; /* Name specified without an option. */ + int options; /* Individual bits indicate which options were + * specified - see below. */ + Tcl_Obj *formatName; /* Name specified without an option. */ enum ColorFormatType colorFormat; - /* The color format type given with the - * -colorformat option */ + /* The color format type given with the + * -colorformat option */ }; /* @@ -132,8 +133,18 @@ static int ParseColor(Tcl_Interp *interp, Tcl_Obj *specObj, Display *display, Colormap colormap, unsigned char *redPtr, unsigned char *greenPtr, unsigned char *bluePtr, unsigned char *alphaPtr); -static int ParseColorAsList(Tcl_Interp *interp, Tcl_Obj *specObj, - unsigned char *redPtr, unsigned char *greenPtr, +static int ParseColorAsList(Tcl_Interp *interp, const char *colorString, + int colorStrLen, unsigned char *redPtr, + unsigned char *greenPtr, unsigned char *bluePtr, + unsigned char *alphaPtr); +static int ParseColorAsHex(Tcl_Interp *interp, const char *colorString, + int colorStrLen, Display *display, Colormap colormap, + unsigned char *redPtr, unsigned char *greenPtr, + unsigned char *bluePtr, unsigned char *alphaPtr); +static int ParseColorAsStandard(Tcl_Interp *interp, + const char *colorString, int colorStrLen, + Display *display, Colormap colormap, + unsigned char *redPtr, unsigned char *greenPtr, unsigned char *bluePtr, unsigned char *alphaPtr); /* @@ -149,7 +160,6 @@ Tk_PhotoImageFormat tkImgFmtDefault = { NULL, /* fileWriteProc: format doesn't support file write */ StringWriteDef /* stringWriteProc */ }; - /* *---------------------------------------------------------------------- @@ -237,8 +247,14 @@ ParseFormatOptions( switch (1 << optIndex) { case OPT_COLORFORMAT: - /*TODO: what if there's not value for option??? (->test!!!) */ *indexPtr = ++index; + if (index >= objc) { + Tcl_SetObjResult(interp, Tcl_ObjPrintf("the \"%s\" option " + "requires a value", Tcl_GetString(objv[index - 1]))); + Tcl_SetErrorCode(interp, "TK", "IMAGE", "PHOTO", + "MISSING_VALUE", NULL); + return TCL_ERROR; + } if (Tcl_GetIndexFromObj(NULL, objv[index], colorFormatNames, "", TCL_EXACT, &typeIndex) != TCL_OK || (typeIndex != COLORFORMAT_LIST @@ -402,7 +418,7 @@ StringMatchDef( != TCL_OK) { return 0; } - + /* * Looks like we have valid data for this format. * We do not check any pixel values - that's the job of ImgStringRead() @@ -412,7 +428,7 @@ StringMatchDef( *heightPtr = rowCount; return 1; - + } /* @@ -437,14 +453,14 @@ StringMatchDef( static int StringReadDef( - Tcl_Interp *interp, /* leave error messages here */ + Tcl_Interp *interp, /* leave error messages here */ Tcl_Obj *data, /* the data to parse */ - Tcl_Obj *formatString, /* value of the -format option */ - Tk_PhotoHandle imageHandle, /* write data to this image */ - int destX, int destY, /* start writing data at this point + Tcl_Obj *formatString, /* value of the -format option */ + Tk_PhotoHandle imageHandle, /* write data to this image */ + int destX, int destY, /* start writing data at this point * in destination image*/ - int width, int height, /* dimensions of area to write to */ - int srcX, int srcY) /* start reading source data at these + int width, int height, /* dimensions of area to write to */ + int srcX, int srcY) /* start reading source data at these * coordinates */ { Tcl_Obj **rowListPtr, **colListPtr; @@ -565,16 +581,15 @@ StringReadDef( /* * Write image data to destHandle */ - if (Tk_PhotoPutBlock(interp, imageHandle, &srcBlock, destX, destY, width, height, TK_PHOTO_COMPOSITE_SET) != TCL_OK) { goto errorExit; } - + ckfree(srcBlock.pixelPtr); + + return TCL_OK; - return TCL_OK; - errorExit: ckfree(srcBlock.pixelPtr); @@ -601,9 +616,9 @@ StringReadDef( static int StringWriteDef( - Tcl_Interp *interp, - Tcl_Obj *formatString, - Tk_PhotoImageBlock *blockPtr) + Tcl_Interp *interp, /* For the result and errors */ + Tcl_Obj *formatString, /* The value of the -format option */ + Tk_PhotoImageBlock *blockPtr) /* The image data to convert */ { int greenOffset, blueOffset, alphaOffset, hasAlpha; Tcl_Obj *data, **objv = NULL; @@ -730,234 +745,236 @@ StringWriteDef( */ static int ParseColor( - Tcl_Interp *interp, /* error messages go there */ - Tcl_Obj *specObj, /* the color data to parse */ - Display *display, /* display of main window, needed to parse - * standard Tk colors */ - Colormap colormap, /* colormap of current display */ - unsigned char *redPtr, /* the result is written to these pointers */ + Tcl_Interp *interp, /* error messages go there */ + Tcl_Obj *specObj, /* the color data to parse */ + Display *display, /* display of main window, needed to parse + * standard Tk colors */ + Colormap colormap, /* colormap of current display */ + unsigned char *redPtr, /* the result is written to these pointers */ unsigned char *greenPtr, unsigned char *bluePtr, unsigned char *alphaPtr) { - const char *specString, *suffixString, *colorString; - Tcl_Obj *colorObj = NULL; - unsigned int i, charCount, colorVals[4]; - XColor parsedColor; - int parsedAsList; + const char *specString; + int charCount; /* - * If the string representation of color data is invalid, try to parse it - * as a list first, in order to avoid shimmering. - */ - - parsedAsList = 0; - if (specObj->bytes == NULL) { - if (ParseColorAsList(interp, specObj, redPtr, greenPtr, bluePtr, - alphaPtr) == TCL_OK) { - goto okExit; - } else { - Tcl_ResetResult(interp); - } - parsedAsList = 1; - } - - /* - * Next, try the formats that have no suffix + * Try to guess the color format */ - specString = Tcl_GetString(specObj); - if (strlen(specString) == 0) { + + specString = Tcl_GetStringFromObj(specObj, &charCount); + + if (charCount == 0) { /* Empty string */ *redPtr = *greenPtr = *bluePtr = *alphaPtr = 0; - goto okExit; + return TCL_OK; } - - charCount = strlen(specString); - if (specString[0] == '#' - && (charCount - 1 == 4 || charCount - 1 == 8)) { - int hexDigitsOnly = 1; - for (i = 1; i < charCount; i++) { - if ( ! isxdigit(UCHAR(specString[i]))) { - hexDigitsOnly = 0; - break; - } - } - - if (hexDigitsOnly) { - /* - * Bug 7c49a7f5: - * As tempting as it may be, don't use the 'hh' modifier in the - * format string for sscanf here. It is a C99 addition, and can - * cause buffer overruns with some older compilers. - */ - - switch (charCount - 1) { - case 4: - /* #ARGB format */ - sscanf(specString, "#%1x%1x%1x%1x", colorVals + 3, - colorVals, colorVals + 1, colorVals + 2); - *redPtr = (unsigned char) colorVals[0] * 0x11; - *greenPtr = (unsigned char) colorVals[1] * 0x11; - *bluePtr = (unsigned char) colorVals[2] * 0x11; - *alphaPtr = (unsigned char) colorVals[3] * 0x11; - goto okExit; - break; - case 8: - /* #AARRGGBB format */ - sscanf(specString, "#%2x%2x%2x%2x", colorVals + 3, - colorVals, colorVals + 1, colorVals + 2); - *redPtr = (unsigned char) colorVals[0]; - *greenPtr = (unsigned char) colorVals[1]; - *bluePtr = (unsigned char) colorVals[2]; - *alphaPtr = (unsigned char) colorVals[3]; - goto okExit; - break; - default: - Tcl_Panic("unexpected switch fallthrough"); - } - } + if (charCount > TK_PHOTO_MAX_COLOR_CHARS) { + Tcl_SetObjResult(interp, Tcl_ObjPrintf("invalid color")); + Tcl_SetErrorCode(interp, "TK", "IMAGE", "PHOTO", + "INVALID_COLOR", NULL); + return TCL_ERROR; } - + if (specString[0] == '#') { + return ParseColorAsHex(interp, specString, charCount, display, + colormap, redPtr, greenPtr, bluePtr, alphaPtr); + } + if (ParseColorAsList(interp, specString, charCount, + redPtr, greenPtr, bluePtr, alphaPtr) == TCL_OK) { + return TCL_OK; + } + /* - * Split color data string in color and suffix parts + * Parsing the color as standard Tk color always is the last option tried + * because TkParseColor() is very slow with values it cannot parse. */ - if ((suffixString = strrchr(specString, '@')) == NULL - && ((suffixString = strrchr(specString, '#')) == NULL - || suffixString == specString)) { - suffixString = specString + strlen(specString); - colorString = specString; - colorObj = specObj; - } else { - colorObj = Tcl_NewStringObj(specString, suffixString - specString); - colorString = Tcl_GetString(colorObj); - } + Tcl_ResetResult(interp); + return ParseColorAsStandard(interp, specString, charCount, display, + colormap, redPtr, greenPtr, bluePtr, alphaPtr); + +} + +/* + *---------------------------------------------------------------------- + * + * ParseColorAsList -- + * + * This function extracts color and alpha values from a list of 3 or 4 + * integers (the list color format). + * + * Results: + * On success, writes red, green, blue and alpha values to the + * corresponding pointers. If the color spec contains no alpha + * information, 255 is taken as transparency value. + * Returns a standard Tcl result. + * + * Side effects: + * Does *not* leave error messages in interp. The reason is that + * it is not always possible to tell if the list format was even + * intended and thus it is hard to return meaningful messages. + * A general error message from the caller is probably the best + * alternative. + * + *---------------------------------------------------------------------- + */ +static int +ParseColorAsList( + Tcl_Interp *interp, /* not used */ + const char *colorString, /* the color data to parse */ + int colorStrLen, /* length of the color string */ + unsigned char *redPtr, /* the result is written to these pointers */ + unsigned char *greenPtr, + unsigned char *bluePtr, + unsigned char *alphaPtr) +{ - /* - * Try to parse as standard Tk color. - * - * We don't use Tk_GetColor() et al. here, as those functions - * migth return a color that does not exaxtly match the given name - * if the colormap is full. Also, we don't really want the color to be - * added to the colormap. + /* + * This is kinda ugly. The code would be certainly nicer if it + * used Tcl_ListObjGetElements() and Tcl_GetIntFromObj(). But with + * strtol() it's *much* faster. */ - if (TkParseColor(display, colormap, colorString, &parsedColor)) { - char *tmpString; - double fracAlpha; - unsigned int suffixAlpha; - - /* - * parse the Suffix - */ + const char *curPos; + int values[4]; + int i; - switch (suffixString[0]) { - case '\0': - suffixAlpha = 255; - break; - case '@': - fracAlpha = strtod(suffixString + 1, &tmpString); - if (*tmpString != '\0') { - Tcl_SetObjResult(interp, Tcl_ObjPrintf("invalid alpha " - "suffix \"%s\": expected floating-point value", - suffixString)); - Tcl_SetErrorCode(interp, "TK", "IMAGE", "PHOTO", - "INVALID COLOR", NULL); - goto errorExit; - } - if (fracAlpha < 0 || fracAlpha > 1) { - Tcl_SetObjResult(interp, Tcl_ObjPrintf("invalid alpha suffix" - " \"%s\": value must be in the range from 0 to 1", - suffixString)); - Tcl_SetErrorCode(interp, "TK", "IMAGE", "PHOTO", - "INVALID_COLOR", NULL); - goto errorExit; - } - suffixAlpha = (unsigned int) floor(fracAlpha * 255 + 0.5); - break; - case '#': - if (strlen(suffixString + 1) < 1 || strlen(suffixString + 1)> 2) { - Tcl_SetObjResult(interp, Tcl_ObjPrintf( - "invalid alpha suffix \"%s\"", suffixString)); - Tcl_SetErrorCode(interp, "TK", "IMAGE", "PHOTO", - "INVALID_COLOR", NULL); - goto errorExit; - } - for (i = 1; i <= strlen(suffixString + 1); i++) { - if ( ! isxdigit(UCHAR(suffixString[i]))) { - Tcl_SetObjResult(interp, Tcl_ObjPrintf( - "invalid alpha suffix \"%s\": expected hex digit", - suffixString)); - Tcl_SetErrorCode(interp, "TK", "IMAGE", "PHOTO", - "INVALID_COLOR", NULL); - goto errorExit; - } - } - if (strlen(suffixString + 1) == 1) { - sscanf(suffixString, "#%1x", &suffixAlpha); - suffixAlpha *= 0x11; - } else { - sscanf(suffixString, "#%2x", &suffixAlpha); - } - break; - default: - Tcl_Panic("unexpected switch fallthrough"); - } - *redPtr = (unsigned char) (parsedColor.red >> 8); - *greenPtr = (unsigned char) (parsedColor.green >> 8); - *bluePtr = (unsigned char) (parsedColor.blue >> 8); - *alphaPtr = (unsigned char) suffixAlpha; + curPos = colorString; + i = 0; - goto okExit; - } - /* - * Last, try to parse as a list, if we didn't already. + * strtol can give false positives with a sequence of space chars. + * To avoid that, avance the pointer to the next non-blank char. */ - if ( !parsedAsList && ParseColorAsList(interp, specObj, redPtr, greenPtr, - bluePtr, alphaPtr) == TCL_OK) { - goto okExit; + + while(isspace(*curPos)) { + ++curPos; + } + while (i < 4 && *curPos != '\0') { + values[i] = strtol(curPos, (char **)&curPos, 0); + if (values[i] < 0 || values[i] > 255) { + return TCL_ERROR; + } + while(isspace(*curPos)) { + ++curPos; + } + ++i; } - Tcl_ResetResult(interp); - /* - * Looks like we can't figure it out and must give up... - */ - Tcl_SetObjResult(interp, Tcl_ObjPrintf( - "invalid color name \"%s\"", specString)); - Tcl_SetErrorCode(interp, "TK", "IMAGE", "PHOTO", - "INVALID_COLOR", NULL); - goto errorExit; - - okExit: - if (colorObj != NULL && colorObj != specObj) { - Tcl_DecrRefCount(colorObj); + if (i < 3 || *curPos != '\0') { + return TCL_ERROR; + } + if (i < 4) { + values[3] = 255; } - return TCL_OK; + *redPtr = values[0]; + *greenPtr = values[1]; + *bluePtr = values[2]; + *alphaPtr = values[3]; - errorExit: - if (colorObj != NULL && colorObj != specObj) { - Tcl_DecrRefCount(colorObj); + return TCL_OK; +} + +/* + *---------------------------------------------------------------------- + * + * ParseColorAsHex -- + * + * This function extracts color and alpha values from a string + * starting with '#', followed by hex digits. It undestands both + * the #ARGB form and the #RBG (with optional suffix) + * + * Results: + * On success, writes red, green, blue and alpha values to the + * corresponding pointers. If the color spec contains no alpha + * information, 255 is taken as transparency value. + * Returns a standard Tcl result. + * + * Side effects: + * None. + * + *---------------------------------------------------------------------- + */ +static int +ParseColorAsHex( + Tcl_Interp *interp, /* error messages are left here */ + const char *colorString, /* the color data to parse */ + int colorStrLen, /* length of the color string */ + Display *display, /* display of main window */ + Colormap colormap, /* colormap of current display */ + unsigned char *redPtr, /* the result is written to these pointers */ + unsigned char *greenPtr, + unsigned char *bluePtr, + unsigned char *alphaPtr) +{ + int i; + unsigned int colorVals[4]; + + if (colorStrLen - 1 != 4 && colorStrLen - 1 != 8) { + return ParseColorAsStandard(interp, colorString, colorStrLen, + display, colormap, redPtr, greenPtr, bluePtr, alphaPtr); + } + for (i = 1; i < colorStrLen; i++) { + if (!isxdigit(UCHAR(colorString[i]))) { + /* + * There still is a chance that this is a Tk color with + * an alpha suffix + */ + + return ParseColorAsStandard(interp, colorString, colorStrLen, + display, colormap, redPtr, greenPtr, bluePtr, alphaPtr); + } } + + /* + * Bug 7c49a7f5: + * As tempting as it may be, don't use the 'hh' modifier in the + * format string for sscanf here. It is a C99 addition, and can + * cause buffer overruns with some older compilers. + */ + switch (colorStrLen - 1) { + case 4: + /* #ARGB format */ + sscanf(colorString, "#%1x%1x%1x%1x", colorVals + 3, + colorVals, colorVals + 1, colorVals + 2); + *redPtr = (unsigned char) colorVals[0] * 0x11; + *greenPtr = (unsigned char) colorVals[1] * 0x11; + *bluePtr = (unsigned char) colorVals[2] * 0x11; + *alphaPtr = (unsigned char) colorVals[3] * 0x11; + return TCL_OK; + case 8: + /* #AARRGGBB format */ + sscanf(colorString, "#%2x%2x%2x%2x", colorVals + 3, + colorVals, colorVals + 1, colorVals + 2); + *redPtr = (unsigned char) colorVals[0]; + *greenPtr = (unsigned char) colorVals[1]; + *bluePtr = (unsigned char) colorVals[2]; + *alphaPtr = (unsigned char) colorVals[3]; + return TCL_OK; + default: + Tcl_Panic("unexpected switch fallthrough"); + } + + /* Shouldn't get here */ return TCL_ERROR; } /* *---------------------------------------------------------------------- * - * ParseColorAsList -- + * ParseColorAsStandard -- * - * This function extracts color and alpha values from a list of 3 or 4 - * integers (the list color format). + * This function tries to split a color stirng in a color and a + * suffix part and to extract color and alpha values from them. The + * color part is treated as regular Tk color. * * Results: * On success, writes red, green, blue and alpha values to the * corresponding pointers. If the color spec contains no alpha * information, 255 is taken as transparency value. - * If the input cannot be parsed, leaves an error message in - * interp. Returns a standard Tcl result. + * Returns a standard Tcl result. * * Side effects: * None. @@ -965,51 +982,119 @@ ParseColor( *---------------------------------------------------------------------- */ static int -ParseColorAsList( - Tcl_Interp *interp, /* error messages go there */ - Tcl_Obj *specObj, /* the color data to parse */ - unsigned char *redPtr, /* the result is written to these pointers */ +ParseColorAsStandard( + Tcl_Interp *interp, /* error messages are left here */ + const char *specString, /* the color data to parse */ + int specStrLen, /* length of the color string */ + Display *display, /* display of main window */ + Colormap colormap, /* colormap of current display */ + unsigned char *redPtr, /* the result is written to these pointers */ unsigned char *greenPtr, unsigned char *bluePtr, unsigned char *alphaPtr) { - int listLen; - unsigned int i; - int values[4]; - Tcl_Obj *curValue; - const char *specString; - - - if (Tcl_ListObjLength(interp, specObj, &listLen) != TCL_OK - || listLen < 3 || listLen > 4) { - specString = Tcl_GetString(specObj); - Tcl_SetObjResult(interp, Tcl_ObjPrintf("invalid color name \"%s\"", - specString)); - Tcl_SetErrorCode(interp, "TK", "IMAGE", "PHOTO", - "INVALID_COLOR", NULL); - return TCL_ERROR; + XColor parsedColor; + const char *suffixString, *colorString; + char colorBuffer[TK_PHOTO_MAX_COLOR_CHARS + 1]; + char *tmpString; + double fracAlpha; + unsigned int suffixAlpha; + int i; + + /* + * Split color data string in color and suffix parts + */ + + if ((suffixString = strrchr(specString, '@')) == NULL + && ((suffixString = strrchr(specString, '#')) == NULL + || suffixString == specString)) { + suffixString = specString + specStrLen; + colorString = specString; + } else { + strncpy(colorBuffer, specString, suffixString - specString); + colorBuffer[suffixString - specString] = '\0'; + colorString = (const char*)colorBuffer; } - values[3] = -1; - for (i = 0; i < (unsigned)listLen; i++) { - if (Tcl_ListObjIndex(interp, specObj, i, &curValue) != TCL_OK) { + + /* + * Try to parse as standard Tk color. + * + * We don't use Tk_GetColor() et al. here, as those functions + * migth return a color that does not exaxtly match the given name + * if the colormap is full. Also, we don't really want the color to be + * added to the colormap. + */ + + if ( ! TkParseColor(display, colormap, colorString, &parsedColor)) { + Tcl_SetObjResult(interp, Tcl_ObjPrintf( + "invalid color name \"%s\"", specString)); + Tcl_SetErrorCode(interp, "TK", "IMAGE", "PHOTO", + "INVALID_COLOR", NULL); + return TCL_ERROR; + } + + /* + * parse the Suffix + */ + + switch (suffixString[0]) { + case '\0': + suffixAlpha = 255; + break; + case '@': + fracAlpha = strtod(suffixString + 1, &tmpString); + if (*tmpString != '\0') { + Tcl_SetObjResult(interp, Tcl_ObjPrintf("invalid alpha " + "suffix \"%s\": expected floating-point value", + suffixString)); + Tcl_SetErrorCode(interp, "TK", "IMAGE", "PHOTO", + "INVALID COLOR", NULL); return TCL_ERROR; } - if (Tcl_GetIntFromObj(interp, curValue, values + i) != TCL_OK) { + if (fracAlpha < 0 || fracAlpha > 1) { + Tcl_SetObjResult(interp, Tcl_ObjPrintf("invalid alpha suffix" + " \"%s\": value must be in the range from 0 to 1", + suffixString)); + Tcl_SetErrorCode(interp, "TK", "IMAGE", "PHOTO", + "INVALID_COLOR", NULL); return TCL_ERROR; } - if (values[i] < 0 || values[i] > 255) { - Tcl_SetObjResult(interp, Tcl_ObjPrintf("invalid color: " - "expected integers in the range from 0 to 255")); + suffixAlpha = (unsigned int) floor(fracAlpha * 255 + 0.5); + break; + case '#': + if (strlen(suffixString + 1) < 1 || strlen(suffixString + 1)> 2) { + Tcl_SetObjResult(interp, Tcl_ObjPrintf( + "invalid alpha suffix \"%s\"", suffixString)); Tcl_SetErrorCode(interp, "TK", "IMAGE", "PHOTO", "INVALID_COLOR", NULL); return TCL_ERROR; } + for (i = 1; i <= (int)strlen(suffixString + 1); i++) { + if ( ! isxdigit(UCHAR(suffixString[i]))) { + Tcl_SetObjResult(interp, Tcl_ObjPrintf( + "invalid alpha suffix \"%s\": expected hex digit", + suffixString)); + Tcl_SetErrorCode(interp, "TK", "IMAGE", "PHOTO", + "INVALID_COLOR", NULL); + return TCL_ERROR; + } + } + if (strlen(suffixString + 1) == 1) { + sscanf(suffixString, "#%1x", &suffixAlpha); + suffixAlpha *= 0x11; + } else { + sscanf(suffixString, "#%2x", &suffixAlpha); + } + break; + default: + Tcl_Panic("unexpected switch fallthrough"); } - *redPtr = values[0]; - *greenPtr = values[1]; - *bluePtr = values[2]; - *alphaPtr = values[3] == -1 ? 255 : values[3]; + *redPtr = (unsigned char) (parsedColor.red >> 8); + *greenPtr = (unsigned char) (parsedColor.green >> 8); + *bluePtr = (unsigned char) (parsedColor.blue >> 8); + *alphaPtr = (unsigned char) suffixAlpha; + return TCL_OK; } @@ -1039,4 +1124,12 @@ TkDebugPhotoStringMatchDef( { return StringMatchDef(data, formatString, widthPtr, heightPtr, interp); } + +/* Local Variables: */ +/* mode: c */ +/* fill-column: 78 */ +/* c-basic-offset: 4 */ +/* tab-width: 8 */ +/* indent-tabs-mode: nil */ +/* End: */ diff --git a/tests/imgListFormat.test b/tests/imgListFormat.test index b371421..02f4988 100644 --- a/tests/imgListFormat.test +++ b/tests/imgListFormat.test @@ -54,7 +54,12 @@ test imgListFormat-1.4 {ParseFormatOptions: option not allowed} -setup { imageCleanup } -returnCodes error -result \ {bad format option "-colorformat": no options allowed} -test imgListFormat-1.5 {ParseFormatOptions: bad -colorformat val #1} -setup { +test imgListFormat-1.5 {ParseFormatOptions: no -colorformat value} -setup { + image create photo photo1 -data black +} -body { + photo1 data -format {default -colorformat} +} -returnCodes error -result {the "-colorformat" option requires a value} +test imgListFormat-1.6 {ParseFormatOptions: bad -colorformat val #1} -setup { image create photo photo1 } -body { photo1 put yellow @@ -63,19 +68,19 @@ test imgListFormat-1.5 {ParseFormatOptions: bad -colorformat val #1} -setup { imageCleanup } -returnCodes error -result \ {bad color format "bogus": must be rgb, argb, or list} -test imgListFormat-1.6 {ParseFormatOptions: bad -colorformat val #2} -setup { +test imgListFormat-1.7 {ParseFormatOptions: bad -colorformat val #2} -setup { image create photo photo1 } -body { photo1 data -format {default -colorformat tkcolor} } -returnCodes error -result \ {bad color format "tkcolor": must be rgb, argb, or list} -test imgListFormat-1.7 {ParseFormatOptions: bad -colorformat #3} -setup { +test imgListFormat-1.8 {ParseFormatOptions: bad -colorformat #3} -setup { image create photo photo1 } -body { photo1 data -format {default -colorformat emptystring} } -returnCodes error -result \ {bad color format "emptystring": must be rgb, argb, or list} -test imgListFormat-1.8 {ParseFormatOptions: bad -colorformat #4} -setup { +test imgListFormat-1.9 {ParseFormatOptions: bad -colorformat #4} -setup { image create photo photo1 } -body { photo1 data -format {default -colorformat rgb-short} @@ -83,13 +88,13 @@ test imgListFormat-1.8 {ParseFormatOptions: bad -colorformat #4} -setup { imageCleanup } -returnCodes error -result \ {bad color format "rgb-short": must be rgb, argb, or list} -test imgListFormat-1.9 {ParseFormatOptions: bad -colorformat #5} -setup { +test imgListFormat-1.10 {ParseFormatOptions: bad -colorformat #5} -setup { image create photo photo1 } -body { photo1 data -format {default -colorformat argb-short} } -returnCodes error -result \ {bad color format "argb-short": must be rgb, argb, or list} -test imgListFormat-1.10 {valid colorformats} -setup { +test imgListFormat-1.11 {valid colorformats} -setup { image create photo photo1 } -body { photo1 put white#78 @@ -322,7 +327,48 @@ test imgListFormat-5.10 {StringWriteDef: test some pixels #5} -constraints { imageCleanup } -result {{0 78 185 225} {161 65 0 170} {255 202 159 175}} -test imgListFormat-6.1 {ParseColor: list format} -setup { +test imgListFormat-6.1 {ParseColor: empty string} -setup { + image create photo photo1 + set result {} +} -body { + photo1 put {{"" ""} {"" ""}} + lappend result [image width photo1] + lappend result [image height photo1] + lappend result [photo1 get 1 1 -withalpha] + set result +} -cleanup { + unset result + imageCleanup +} -result {2 2 {0 0 0 0}} +test imgListFormat-6.2 {ParseColor: empty string, mixed} -setup { + image create photo photo1 +} -body { + photo1 put {{black white} {{} white}} + list [photo1 get 0 0 -withalpha] [photo1 get 0 1 -withalpha] +} -cleanup { + imageCleanup +} -result {{0 0 0 255} {0 0 0 0}} +test imgListFormat-6.3 {ParseColor: color name too long} -setup { + image create photo photo1 + set longstr {} + for {set i 1} {$i <= 100} {incr i} { + append longstr "z" + } +} -body { + photo1 put [list [list blue] [list $longstr]] +} -cleanup { + imageCleanup + unset longstr +} -returnCodes error -result {invalid color} +test imgListFormat-6.4 {ParseColor: #XXX color, different forms} -setup { + image create photo photo1 +} -body { + photo1 put {{#A123 #334455} {#012 #fffefd#00}} + photo1 data -format {default -colorformat argb} +} -cleanup { + imageCleanup +} -result {{#aa112233 #ff334455} {#ff001122 #00fffefd}} +test imgListFormat-6.5 {ParseColor: list format} -setup { image create photo photo1 } -body { photo1 put [list [list [list 255 255 255]]] @@ -330,7 +376,7 @@ test imgListFormat-6.1 {ParseColor: list format} -setup { } -cleanup { imageCleanup } -result {255 255 255 255} -test imgListFormat-6.2 {ParseColor: string format in list rep} -setup { +test imgListFormat-6.6 {ParseColor: string format} -setup { image create photo photo1 } -body { photo1 put [list [list [list white]]] @@ -338,35 +384,141 @@ test imgListFormat-6.2 {ParseColor: string format in list rep} -setup { } -cleanup { imageCleanup } -result {255 255 255 255} -test imgListFormat-6.3 {ParseColor: empty string} -setup { +test imgListFormat-6.7 {ParseColor: invalid color} -setup { + image create photo photo1 +} -body { + photo1 put {{blue red} {green bogus}} +} -cleanup { + imageCleanup +} -returnCodes error -result {invalid color name "bogus"} +test imgListFormat-6.8 {ParseColor: overall test} -setup { image create photo photo1 set result {} } -body { - photo1 put {{"" ""} {"" ""}} - lappend result [image width photo1] - lappend result [image height photo1] - lappend result [photo1 get 1 1 -withalpha] + photo1 put { + {snow@0.5 snow#80 snow#8 #fffffafafafa@0.5 #fffffabbfacc#8} + {#fffffafffaff#80 #ffffaafaa@.5 #ffffaafaa#8 #ffffaafaa#80 #fee#8} + {#fee#80 #fee@0.5 #fffafa@0.5 #fffafa#8 #fffafa#80} + {{0xff 250 0xfa 128} {255 250 250} #8fee #80fffafa snow}} + for {set y 0} {$y < 4} {incr y} { + for {set x 0} {$x < 5} {incr x} { + lappend result [photo1 get $x $y -withalpha] + } + } set result } -cleanup { + imageCleanup unset result +} -result \ +{{255 250 250 128} {255 250 250 128} {255 250 250 136} {255 250 250 128}\ +{255 250 250 136} {255 250 250 128} {255 250 250 128} {255 250 250 136}\ +{255 250 250 128} {255 238 238 136} {255 238 238 128} {255 238 238 128}\ +{255 250 250 128} {255 250 250 136} {255 250 250 128} {255 250 250 128}\ +{255 250 250 255} {255 238 238 136} {255 250 250 128} {255 250 250 255}} + +# Note: these tests were written for an earlier implementation of +# ParseColorAsList. For this reason, their order and layout do not follow the +# current code very well. Test coverage is pretty good, nevertheless. +test imgListFormat-7.1 {ParseColorAsList: invalid list} -setup { + image create photo photo1 +} -body { + photo1 put {{{123 45 67 89} {123 45 " 67}}} + #" +} -cleanup { imageCleanup -} -result {2 2 {0 0 0 0}} -test imgListFormat-6.4 {ImgPhotoParsecolor: empty string, mixed} -setup { +} -returnCodes error -result {invalid color name "123 45 " 67"} +#" +test imgListFormat-7.2 {ParseColorAsList: too few elements in list} -setup { image create photo photo1 } -body { - photo1 put {{black white} {{} white}} - list [photo1 get 0 0 -withalpha] [photo1 get 0 1 -withalpha] + photo1 put {{{0 255 0 255} {0 255}}} } -cleanup { imageCleanup -} -result {{0 0 0 255} {0 0 0 0}} -test imgListFormat-6.5 {ParseColor: invalid hex digit} -setup { +} -returnCodes error -result {invalid color name "0 255"} +test imgListFormat-7.3 {ParseColorAsList: too many elements in list} -setup { + image create photo photo1 +} -body { + photo1 put {{{0 100 200 255} {0 100 200 255 0}}} +} -returnCodes error -result {invalid color name "0 100 200 255 0"} +test imgListFormat-7.4 {ParseColorAsList: not an integer value} -setup { + image create photo photo1 +} -body { + photo1 put {{{9 0xf3 87 65} {43 21 10 1.0}}} +} -cleanup { + imageCleanup +} -returnCodes error -result {invalid color name "43 21 10 1.0"} +test imgListFormat-7.5 {ParseColorAsList: negative value in list} -setup { + image create photo photo1 +} -body { + photo1 put {{{121 121 121} {121 121 -1}}} +} -cleanup { + imageCleanup +} -returnCodes error -result {invalid color name "121 121 -1"} +test imgListFormat-7.6 {ParseColorAsList: value in list too large} -setup { + image create photo photo1 +} -body { + photo1 put {{{0 1 2 3} {254 255 256}}} +} -cleanup { + imageCleanup +} -returnCodes error -result {invalid color name "254 255 256"} +test imgListFormat-7.7 {ParseColorAsList: suffix not allowed} -setup { + image create photo photo1 +} -body { + photo1 put {{{100 100 100} {100 100 100#FE}}} +} -cleanup { + imageCleanup +} -returnCodes error -result {invalid color name "100 100 100#FE"} +test imgListFormat-7.8 {ParseColorAsList: valid list form} -setup { + image create photo photo1 +} -body { + photo1 put {{{0x0 0x10 0xfe 0xff} {0 100 254}} + {{30 30 30 0} {1 1 254 1}}} + list [photo1 get 0 0 -withalpha] [photo1 get 1 0 -withalpha] \ + [photo1 get 0 1 -withalpha] [photo1 get 1 1 -withalpha] +} -cleanup { + imageCleanup +} -result {{0 16 254 255} {0 100 254 255} {30 30 30 0} {1 1 254 1}} +test imgListFormat-7.9 {ParseColorAsList: additional spaces in list} -setup { + image create photo photo1 +} -body { + photo1 put { { { 1 2 3} {1 2 3} } { {1 2 3 } { 1 2 3 4 } } } + photo1 data -format {default -colorformat argb} +} -cleanup { + imageCleanup +} -result {{#ff010203 #ff010203} {#ff010203 #04010203}} +test imgListFormat-7.10 {ParseColorAsList: list format, string rep} -setup { + image create photo photo1 +} -body { + photo1 put {{"111 222 33 44"}} + photo1 get 0 0 -withalpha +} -cleanup { + imageCleanup +} -result {111 222 33 44} + +test imgListFormat-8.1 {ParseColorAsHex: RGB format} -setup { + image create photo photo1 +} -body { + photo1 put {{#010 #001100}} + photo1 data +} -cleanup { + imageCleanup +} -result {{#001100 #001100}} +test imgListFormat-8.2 {ParseColorAsHex: invalid hex digit} -setup { image create photo photo1 } -body { photo1 put {#ABCD #ABCZ} } -cleanup { imageCleanup } -returnCodes error -result {invalid color name "#ABCZ"} -test imgListFormat-6.6 {ParseColor: valid #ARGB color} -setup { +test imgListFormat-8.3 {ParseColorAsHex: RGB with suffix, 8 chars} -setup { + image create photo photo1 +} -body { + photo1 put {{#FFfFFf #AbCdef#0}} + photo1 data +} -cleanup { + imageCleanup +} -result {{#ffffff #abcdef}} +test imgListFormat-8.4 {ParseColor: valid #ARGB color} -setup { image create photo photo1 } -body { photo1 put {{#0d9bd502 #F7ac}} @@ -374,7 +526,9 @@ test imgListFormat-6.6 {ParseColor: valid #ARGB color} -setup { } -cleanup { imageCleanup } -result {{155 213 2 13} {119 170 204 255}} -test imgListFormat-6.7 {ParseColor: Tk color, valid suffixes} -setup { + +test imgListFormat-9.1 {ParseColorAsStandard: + Tk color, valid suffixes} -setup { image create photo photo1 set result {} } -body { @@ -388,7 +542,8 @@ test imgListFormat-6.7 {ParseColor: Tk color, valid suffixes} -setup { unset result imageCleanup } -result {{0 0 255 181} {17 68 51 204} {136 221 68 26} {255 0 255 255}} -test imgListFormat-6.8 {ParseColor: Tk color with and w/o suffixes} -setup { +test imgListFormat-9.2 {ParseColorAsStandard: + Tk color with and w/o suffixes} -setup { image create photo photo1 set result {} } -body { @@ -402,7 +557,12 @@ test imgListFormat-6.8 {ParseColor: Tk color with and w/o suffixes} -setup { unset result imageCleanup } -result {{82 216 160 255} {34 187 85 255} {238 68 119 3} {128 0 0 68}} -test imgListFormat-6.9 {ParseColor: @A suffix, not a float} -setup { +test imgListFormat-9.3 {ParseColorAsStandard: wrong digit count} -setup { + image create photo photo1 +} -body { + photo1 put {{#000 #00}} +} -returnCodes error -result {invalid color name "#00"} +test imgListFormat-9.4 {ParseColorAsStandard: @A suffix, not a float} -setup { image create photo photo1 } -body { photo1 put {{blue@0.5 blue@bogus}} @@ -410,7 +570,7 @@ test imgListFormat-6.9 {ParseColor: @A suffix, not a float} -setup { imageCleanup } -returnCodes error -result \ {invalid alpha suffix "@bogus": expected floating-point value} -test imgListFormat-6.10 {ParseColor: @A, value too low} -setup { +test imgListFormat-9.5 {ParseColorAsStandard: @A, value too low} -setup { image create photo photo1 } -body { photo1 put {green@.1 green@-0.1} @@ -418,7 +578,7 @@ test imgListFormat-6.10 {ParseColor: @A, value too low} -setup { imageCleanup } -returnCodes error -result \ {invalid alpha suffix "@-0.1": value must be in the range from 0 to 1} -test imgListFormat-6.11 {ParseColor: @A, value too high} -setup { +test imgListFormat-9.6 {ParseColorAsStandard: @A, value too high} -setup { image create photo photo1 } -body { photo1 put {#000000@0 #000000@1.0001} @@ -426,7 +586,7 @@ test imgListFormat-6.11 {ParseColor: @A, value too high} -setup { imageCleanup } -returnCodes error -result \ {invalid alpha suffix "@1.0001": value must be in the range from 0 to 1} -test imgListFormat-6.12 {ParseColor: @A suffix, edge values} -setup { +test imgListFormat-9.7 {ParseColorAsStandard: @A suffix, edge values} -setup { imageCleanup image create photo photo1 } -body { @@ -437,158 +597,59 @@ test imgListFormat-6.12 {ParseColor: @A suffix, edge values} -setup { } -cleanup { imageCleanup } -result {{255 255 0 0} {255 255 0 31} {255 255 0 32} {255 255 0 255}} -test imgListFormat-6.13 {ParseColor: # suffix, no hex digits} -setup { +test imgListFormat-9.8 {ParseColorAsStandard: # suffix, no hex digits} -setup { image create photo photo1 } -body { photo1 put {{black#f} {black#}} } -cleanup { imageCleanup } -returnCodes error -result {invalid alpha suffix "#"} -test imgListFormat-6.14 {ParseColor: # suffix, too many digits} -setup { +test imgListFormat-9.9 {ParseColorAsStandard: + '#' suffix, too many digits} -setup { image create photo photo1 } -body { photo1 put {{#ABC#12 #ABC#123}} } -cleanup { imageCleanup -} -returnCodes error -result \ - {invalid alpha suffix "#123"} -test imgListFormat-6.15 {ParseColor: invalid digit in #X suffix} -setup { +} -returnCodes error -result {invalid alpha suffix "#123"} +test imgListFormat-9.10 {ParseColorAsStandard: + invalid digit in #X suffix} -setup { image create photo photo1 } -body { photo1 put {#000#a #000#g} } -cleanup { imageCleanup } -returnCodes error -result {invalid alpha suffix "#g": expected hex digit} -test imgListFormat-6.16 {ParseColor: invalid digit in #XX suffix} -setup { +test imgListFormat-9.11 {ParseColorAsStandard: + invalid digit in #XX suffix} -setup { image create photo photo1 } -body { photo1 put {green#2 green#2W} } -cleanup { imageCleanup } -returnCodes error -result {invalid alpha suffix "#2W": expected hex digit} -test imgListFormat-6.17 {ParseColor: list format, string rep} -setup { - image create photo photo1 -} -body { - photo1 put {{"111 222 33 44"}} - photo1 get 0 0 -withalpha -} -cleanup { - imageCleanup -} -result {111 222 33 44} -test imgListFormat-6.18 {ParseColor: invalid color: wrong digit #} -setup { - image create photo photo1 -} -body { - photo1 put {{#000 #00}} -} -returnCodes error -result {invalid color name "#00"} -test imgListFormat-6.19 {ParseColor: invalid color: not a hex digit} -setup { +test imgListFormat-9.12 {ParseColorAsStandard: + invalid color: not a hex digit} -setup { image create photo photo1 } -body { photo1 put {#ABCDEF@.99 #ABCDEG@.99} } -cleanup { imageCleanup } -returnCodes error -result {invalid color name "#ABCDEG@.99"} -test imgListFormat-6.20 {ParseColor: suffix not allowed #1} -setup { +test imgListFormat-9.13 {ParseColorAsStandard: suffix not allowed #1} -setup { image create photo photo1 } -body { photo1 put {#ABC@.5 #ABCD@0.5} } -cleanup { imageCleanup -} -returnCodes error -result \ - {invalid color name "#ABCD@0.5"} -test imgListFormat-6.21 {ParseColor: suffix not allowed #2} -setup { - image create photo photo1 -} -body { - photo1 put {{{100 100 100} {100 100 100#FE}}} -} -cleanup { - imageCleanup -} -returnCodes error -result \ - {invalid color name "100 100 100#FE"} -test imgListFormat-6.22 {ParseColor: suffix not allowed #3} -setup { +} -returnCodes error -result {invalid color name "#ABCD@0.5"} +test imgListFormat-9.14 {ParseColorAsStandard: suffix not allowed #2} -setup { image create photo photo1 } -body { photo1 put {#1111 #1111#1} } -cleanup { imageCleanup -} -returnCodes error -result \ - {invalid color name "#1111#1"} -test imgListFormat-6.23 {ParseColor: overall test} -setup { - image create photo photo1 - set result {} -} -body { - photo1 put { - {snow@0.5 snow#80 snow#8 #fffffafafafa@0.5 #fffffabbfacc#8} - {#fffffafffaff#80 #ffffaafaa@.5 #ffffaafaa#8 #ffffaafaa#80 #fee#8} - {#fee#80 #fee@0.5 #fffafa@0.5 #fffafa#8 #fffafa#80} - {{0xff 250 0xfa 128} {255 250 250} #8fee #80fffafa snow}} - for {set y 0} {$y < 4} {incr y} { - for {set x 0} {$x < 5} {incr x} { - lappend result [photo1 get $x $y -withalpha] - } - } - set result -} -cleanup { - imageCleanup - unset result -} -result \ -{{255 250 250 128} {255 250 250 128} {255 250 250 136} {255 250 250 128}\ -{255 250 250 136} {255 250 250 128} {255 250 250 128} {255 250 250 136}\ -{255 250 250 128} {255 238 238 136} {255 238 238 128} {255 238 238 128}\ -{255 250 250 128} {255 250 250 136} {255 250 250 128} {255 250 250 128}\ -{255 250 250 255} {255 238 238 136} {255 250 250 128} {255 250 250 255}} - -# Note: the error messages from ParseColorAsList are currently discarded. All -# we'll ever get is a "invalid color mame xx" message. -test imgListFormat-7.1 {ParseColorAsListAsList: invalid list} -setup { - image create photo photo1 -} -body { - photo1 put {{{123 45 67 89} {123 45 " 67}}} - #" -} -cleanup { - imageCleanup -} -returnCodes error -result {invalid color name "123 45 " 67"} -#" -test imgListFormat-7.2 {ParseColorAsList: too few elements in list} -setup { - image create photo photo1 -} -body { - photo1 put {{{0 255 0 255} {0 255}}} -} -cleanup { - imageCleanup -} -returnCodes error -result {invalid color name "0 255"} -test imgListFormat-7.3 {ParseColorAsList: too many elements in list} -setup { - image create photo photo1 -} -body { - photo1 put {{{0 100 200 255} {0 100 200 255 0}}} -} -returnCodes error -result {invalid color name "0 100 200 255 0"} -test imgListFormat-7.4 {ParseColorAsList: not an integer value} -setup { - image create photo photo1 -} -body { - photo1 put {{{9 0xf3 87 65} {43 21 10 1.0}}} -} -cleanup { - imageCleanup -} -returnCodes error -result {invalid color name "43 21 10 1.0"} -test imgListFormat-7.5 {ParseColorAsList: negative value in list} -setup { - image create photo photo1 -} -body { - photo1 put {{{121 121 121} {121 121 -1}}} -} -cleanup { - imageCleanup -} -returnCodes error -result {invalid color name "121 121 -1"} -test imgListFormat-7.6 {ParseColorAsList: value in list too large} -setup { - image create photo photo1 -} -body { - photo1 put {{{0 1 2 3} {254 255 256}}} -} -cleanup { - imageCleanup -} -returnCodes error -result {invalid color name "254 255 256"} -test imgListFormat-7.7 {ParseColorAsList: valid list form} -setup { - image create photo photo1 -} -body { - photo1 put {{{0x0 0x10 0xfe 0xff} {0 100 254}} - {{30 30 30 0} {1 1 254 1}}} - list [photo1 get 0 0 -withalpha] [photo1 get 1 0 -withalpha] \ - [photo1 get 0 1 -withalpha] [photo1 get 1 1 -withalpha] -} -cleanup { - imageCleanup -} -result {{0 16 254 255} {0 100 254 255} {30 30 30 0} {1 1 254 1}} +} -returnCodes error -result {invalid color name "#1111#1"} # --------------------------------------------------------------------- -- cgit v0.12