diff --git a/src/fontcache.c b/src/fontcache.c index ff6d788102..0af7dcb97e 100644 --- a/src/fontcache.c +++ b/src/fontcache.c @@ -156,8 +156,10 @@ ft_cache *msGetFontCache() { } void msFontCacheSetup() { +#ifdef USE_THREAD if (ft_caches) msFontCacheCleanup(); +#endif #ifndef USE_THREAD ft_cache *c = msGetFontCache(); diff --git a/src/mapcairo.c b/src/mapcairo.c index 199de70534..b709f6b50b 100644 --- a/src/mapcairo.c +++ b/src/mapcairo.c @@ -1035,7 +1035,12 @@ int msPreloadSVGSymbol(symbolObj *symbol) { } #else { - cache->svgc = rsvg_handle_new_from_file(symbol->full_pixmap_path, NULL); + if (EQUALN(symbol->full_pixmap_path, "svgc = rsvg_handle_new_from_data( + (const guint8 *)symbol->full_pixmap_path, + strlen(symbol->full_pixmap_path), NULL); + else + cache->svgc = rsvg_handle_new_from_file(symbol->full_pixmap_path, NULL); if (!cache->svgc) { msSetError(MS_RENDERERERR, "failed to load svg file %s", "msPreloadSVGSymbol()", symbol->full_pixmap_path); diff --git a/src/mapcompositingfilter.c b/src/mapcompositingfilter.c index aff90b3f46..fb2fd049d6 100644 --- a/src/mapcompositingfilter.c +++ b/src/mapcompositingfilter.c @@ -177,7 +177,15 @@ int msApplyCompositingFilter(mapObj *map, rasterBufferObj *rb, regmatch_t pmatch[3]; /* test for blurring filter */ +#ifdef USE_PCRE2 + { + char *pat = msPCRE2EscapeBracketBackslashes("blur\\(([0-9]+)\\)"); + regcomp(®ex, pat, REG_EXTENDED); + free(pat); + } +#else regcomp(®ex, "blur\\(([0-9]+)\\)", REG_EXTENDED); +#endif rstatus = regexec(®ex, filter->filter, 2, pmatch, 0); regfree(®ex); if (!rstatus) { @@ -195,7 +203,16 @@ int msApplyCompositingFilter(mapObj *map, rasterBufferObj *rb, } /* test for translation filter */ +#ifdef USE_PCRE2 + { + char *pat = msPCRE2EscapeBracketBackslashes( + "translate\\((-?[0-9]+),(-?[0-9]+)\\)"); + regcomp(®ex, pat, REG_EXTENDED); + free(pat); + } +#else regcomp(®ex, "translate\\((-?[0-9]+),(-?[0-9]+)\\)", REG_EXTENDED); +#endif rstatus = regexec(®ex, filter->filter, 3, pmatch, 0); regfree(®ex); if (!rstatus) { diff --git a/src/maplegend.c b/src/maplegend.c index 4201fffb77..6941fe58da 100644 --- a/src/maplegend.c +++ b/src/maplegend.c @@ -950,7 +950,7 @@ int msEmbedLegend(mapObj *map, imageObj *img) { !MS_MAP_RENDERER(map)->supports_pixel_buffer) { imageType = msStrdup(map->imagetype); /* save format */ if MS_DRIVER_CAIRO(map->outputformat) { -#ifdef USE_SVG_CAIRO +#if defined(USE_SVG_CAIRO) || defined(USE_RSVG) map->outputformat = msSelectOutputFormat( map, "svg" ); #else map->outputformat = msSelectOutputFormat( map, "cairopng" ); @@ -1012,7 +1012,8 @@ int msEmbedLegend(mapObj *map, imageObj *img) { } legendSymbol->renderer = renderer; - legendSymbol->renderer_free_func = renderer->freeSymbol; + legendSymbol->renderer_free_func = + (void (*)(symbolObj *))renderer->freeSymbol; legendSymbol->name = msStrdup(LEGEND_SYMBOL_NAME); diff --git a/src/mapmssql2008.c b/src/mapmssql2008.c index f87f88e46b..6a2d3aedc0 100644 --- a/src/mapmssql2008.c +++ b/src/mapmssql2008.c @@ -747,7 +747,13 @@ static void setConnError(msODBCconn *conn) { conn->errorMessage[len] = 0; } -#ifdef USE_ICONV +/* SPT-14135: every USE_ICONV branch below assumes a 2-byte wchar_t (true on + * Windows, false on Linux/glibc's 4-byte wchar_t), reinterpreting iconv's + * 2-byte-per-char UCS-2LE output as wchar_t elements and corrupting the + * connection string / SQL text / query results. Restrict the wide-char ODBC + * path (SQLDriverConnectW/SQLExecDirectW/SQL_WCHAR) to Windows; elsewhere + * fall back to the plain narrow-char path already used for non-ICONV builds. */ +#if defined(USE_ICONV) && defined(_WIN32) static SQLWCHAR *convertCwchartToSQLWCHAR(const wchar_t *inStr) { SQLWCHAR *outStr; int i, len; @@ -785,7 +791,7 @@ static msODBCconn *mssql2008Connect(const char *connString) { } { -#ifdef USE_ICONV +#if defined(USE_ICONV) && defined(_WIN32) wchar_t *decodedConnString = msConvertWideStringFromUTF8(connString, "UCS-2LE"); SQLWCHAR outConnString[1024]; @@ -832,7 +838,7 @@ static int executeSQL(msODBCconn *conn, const char *sql) { SQLCloseCursor(conn->hstmt); -#ifdef USE_ICONV +#if defined(USE_ICONV) && defined(_WIN32) { wchar_t *decodedSql = msConvertWideStringFromUTF8(sql, "UCS-2LE"); SQLWCHAR *decodedSqlSQLWCHAR = convertCwchartToSQLWCHAR(decodedSql); @@ -1521,7 +1527,7 @@ static int prepare_database(layerObj *layer, rectObj rect, char **query_string, /* adding items to the select list */ for (t = 0; t < layer->numitems; t++) { -#ifdef USE_ICONV +#if defined(USE_ICONV) && defined(_WIN32) query = msStringConcatenate(query, "convert(nvarchar(max), ["); #else query = msStringConcatenate(query, "convert(varchar(max), ["); @@ -2307,7 +2313,7 @@ int msMSSQL2008LayerGetShapeRandom(layerObj *layer, shapeObj *shape, return MS_FAILURE; } -#ifdef USE_ICONV +#if defined(USE_ICONV) && defined(_WIN32) SQLSMALLINT targetType = SQL_WCHAR; #else SQLSMALLINT targetType = SQL_CHAR; @@ -2328,7 +2334,7 @@ int msMSSQL2008LayerGetShapeRandom(layerObj *layer, shapeObj *shape, * include */ /* If we get SQL_NO_TOTAL we do not know how big buffer we need so * we increase it with 512. */ -#ifdef USE_ICONV +#if defined(USE_ICONV) && defined(_WIN32) totalLen -= sizeof(wchar_t); emptyLen = retLen != SQL_NO_TOTAL ? retLen - emptyLen + 2 * sizeof(wchar_t) @@ -2354,7 +2360,7 @@ int msMSSQL2008LayerGetShapeRandom(layerObj *layer, shapeObj *shape, if (totalLen > 0) { /* Pop the value into the shape's value array */ -#ifdef USE_ICONV +#if defined(USE_ICONV) && defined(_WIN32) shape->values[t] = msConvertWideStringToUTF8((wchar_t *)valueBuffer, "UCS-2LE"); msFree(valueBuffer); diff --git a/src/mapregex.c b/src/mapregex.c index 631d2a070d..a4896b3dd7 100644 --- a/src/mapregex.c +++ b/src/mapregex.c @@ -58,6 +58,83 @@ #include #endif +#ifdef USE_PCRE2 +/* PCRE2 escapes backslash inside [...]; POSIX regex doesn't. Double + * lone backslashes in brackets so PCRE2 sees a literal one too. + * Already-paired "\\" is left alone, so this is idempotent. */ +MS_API_EXPORT(char *) msPCRE2EscapeBracketBackslashes(const char *expr) { + size_t len = strlen(expr); + char *out = (char *)msSmallMalloc(len * 2 + 1); + size_t oi = 0; + int in_bracket = 0; + size_t bracket_start = 0; + + for (size_t i = 0; i < len;) { + char c = expr[i]; + + if (!in_bracket) { + if (c == '[') { + in_bracket = 1; + out[oi++] = c; + i++; + if (i < len && expr[i] == '^') { + out[oi++] = expr[i]; + i++; + } + bracket_start = i; + continue; + } + out[oi++] = c; + i++; + continue; + } + + if (c == ']' && i != bracket_start) { + in_bracket = 0; + out[oi++] = c; + i++; + continue; + } + + /* [:class:], [.x.], [=x=] - pass through untouched */ + if (c == '[' && i + 1 < len && + (expr[i + 1] == ':' || expr[i + 1] == '.' || expr[i + 1] == '=')) { + char sub = expr[i + 1]; + out[oi++] = expr[i]; + out[oi++] = expr[i + 1]; + i += 2; + while (i + 1 < len && !(expr[i] == sub && expr[i + 1] == ']')) { + out[oi++] = expr[i]; + i++; + } + if (i + 1 < len) { + out[oi++] = expr[i]; + out[oi++] = expr[i + 1]; + i += 2; + } + continue; + } + + if (c == '\\') { + out[oi++] = '\\'; + out[oi++] = '\\'; + if (i + 1 < len && expr[i + 1] == '\\') { + i += 2; /* already escaped */ + } else { + i += 1; /* lone backslash - double it */ + } + continue; + } + + out[oi++] = c; + i++; + } + + out[oi] = '\0'; + return out; +} +#endif + MS_API_EXPORT(int) ms_regcomp(ms_regex_t *regex, const char *expr, int cflags) { /* Must free in regfree() */ regex_t *sys_regex = (regex_t *)msSmallMalloc(sizeof(regex_t)); @@ -71,7 +148,13 @@ MS_API_EXPORT(int) ms_regcomp(ms_regex_t *regex, const char *expr, int cflags) { reg_cflags |= REG_NOSUB; if (cflags & MS_REG_NEWLINE) reg_cflags |= REG_NEWLINE; +#ifdef USE_PCRE2 + char *escaped_expr = msPCRE2EscapeBracketBackslashes(expr); + int ret = regcomp(sys_regex, escaped_expr, reg_cflags); + free(escaped_expr); +#else int ret = regcomp(sys_regex, expr, reg_cflags); +#endif if (ret != 0) { free(regex->sys_regex); regex->sys_regex = NULL; diff --git a/src/mapregex.h b/src/mapregex.h index ea7c44c3ba..c8615c7320 100644 --- a/src/mapregex.h +++ b/src/mapregex.h @@ -60,6 +60,10 @@ MS_API_EXPORT(int) ms_regexec(const ms_regex_t *, const char *, size_t, ms_regmatch_t[], int); MS_API_EXPORT(void) ms_regfree(ms_regex_t *); +#ifdef USE_PCRE2 +MS_API_EXPORT(char *) msPCRE2EscapeBracketBackslashes(const char *); +#endif + #ifndef BUILDING_REGEX_PROXY /* === regcomp.c === */ diff --git a/src/maprendering.c b/src/maprendering.c index 615f2d2068..1e0cb03e50 100644 --- a/src/maprendering.c +++ b/src/maprendering.c @@ -621,7 +621,8 @@ int msDrawLineSymbol(mapObj *map, imageObj *image, shapeObj *p, styleObj *style, if (symbol->renderer_free_func) symbol->renderer_free_func(symbol); - symbol->renderer_free_func = renderer->freeSymbol; + symbol->renderer_free_func = + (void (*)(symbolObj *))renderer->freeSymbol; } width = style->width * scalefactor; @@ -775,7 +776,8 @@ int msDrawShadeSymbol(mapObj *map, imageObj *image, shapeObj *p, if(symbol->renderer_free_func) symbol->renderer_free_func(symbol); - symbol->renderer_free_func = renderer->freeSymbol; + symbol->renderer_free_func = + (void (*)(symbolObj *))renderer->freeSymbol; } if (style->offsetx != 0 || style->offsety != 0) { @@ -927,7 +929,8 @@ int msDrawMarkerSymbol(mapObj *map, imageObj *image, pointObj *p, if (symbol->renderer_free_func) symbol->renderer_free_func(symbol); - symbol->renderer_free_func = renderer->freeSymbol; + symbol->renderer_free_func = + (void (*)(symbolObj *))renderer->freeSymbol; } if (preloadSymbol(&map->symbolset, symbol, renderer) != MS_SUCCESS) { return MS_FAILURE; diff --git a/src/mapscale.c b/src/mapscale.c index bc1c82b72d..e5fde42e54 100644 --- a/src/mapscale.c +++ b/src/mapscale.c @@ -425,7 +425,7 @@ imageObj *msDrawScalebar(mapObj *map) { MS_INIT_COLOR(map->scalebar.imagecolor, 255, 255, 255, 255); } - msSetOutputFormatOption(format, "DPI", "100"); + msSetOutputFormatOption(format, "DPI", "96"); image = msImageCreate(scalebarWidth, sy, format, map->web.imagepath, map->web.imageurl, map->resolution, map->defresolution, @@ -583,6 +583,9 @@ int msEmbedScalebar(mapObj *map, imageObj *img) { rendererVTableObj *renderer; symbolObj *embeddedSymbol; char *imageType = NULL; + double svgDPI = 0.0; + double scalebarScale = 1.0; + double effSizeX, effSizeY; index = msGetSymbolIndex(&(map->symbolset), "scalebar", MS_FALSE); if (index != -1) @@ -600,7 +603,7 @@ int msEmbedScalebar(mapObj *map, imageObj *img) { !MS_MAP_RENDERER(map)->supports_pixel_buffer) { imageType = msStrdup(map->imagetype); /* save format */ if MS_DRIVER_CAIRO (map->outputformat) { -#ifdef USE_SVG_CAIRO +#if defined(USE_SVG_CAIRO) || defined(USE_RSVG) map->outputformat = msSelectOutputFormat(map, "svg"); #else map->outputformat = msSelectOutputFormat(map, "cairopng"); @@ -614,6 +617,9 @@ int msEmbedScalebar(mapObj *map, imageObj *img) { image = msDrawScalebar(map); + /* capture the DPI msDrawScalebar() rendered at, before it's restored below */ + svgDPI = atof(msGetOutputFormatOption(map->outputformat, "DPI", "72")); + if (imageType) { map->outputformat = msSelectOutputFormat(map, imageType); /* restore format */ @@ -656,6 +662,19 @@ int msEmbedScalebar(mapObj *map, imageObj *img) { embeddedSymbol->sizex = embeddedSymbol->pixmap_buffer->width; embeddedSymbol->sizey = embeddedSymbol->pixmap_buffer->height; } + + /* msPreloadSVGSymbol() read the SVG's declared width/height as pixels, but + * it was rendered at svgDPI, not 72 DPI (where 1 point == 1 pixel); scale + * the drawn symbol back up so it keeps its correct size on the map */ + if (embeddedSymbol->type == MS_SYMBOL_SVG && svgDPI > 0 && svgDPI != 72.0) + scalebarScale = svgDPI / 72.0; + + /* the symbol renders at sizex/sizey * scalebarScale (see + * renderSVGSymbolCairo's cairo_scale) - use that for placement, not the + * raw declared size */ + effSizeX = embeddedSymbol->sizex * scalebarScale; + effSizeY = embeddedSymbol->sizey * scalebarScale; + if (map->scalebar.transparent) { embeddedSymbol->transparent = MS_TRUE; embeddedSymbol->transparentcolor = 0; @@ -663,33 +682,33 @@ int msEmbedScalebar(mapObj *map, imageObj *img) { switch (map->scalebar.position) { case (MS_LL): - point.x = MS_NINT(embeddedSymbol->sizex / 2.0) + map->scalebar.offsetx; - point.y = map->height - MS_NINT(embeddedSymbol->sizey / 2.0) - + point.x = MS_NINT(effSizeX / 2.0) + map->scalebar.offsetx; + point.y = map->height - MS_NINT(effSizeY / 2.0) - map->scalebar.offsety; break; case (MS_LR): - point.x = map->width - MS_NINT(embeddedSymbol->sizex / 2.0) - + point.x = map->width - MS_NINT(effSizeX / 2.0) - map->scalebar.offsetx; - point.y = map->height - MS_NINT(embeddedSymbol->sizey / 2.0) - + point.y = map->height - MS_NINT(effSizeY / 2.0) - map->scalebar.offsety; break; case (MS_LC): point.x = MS_NINT(map->width / 2.0) + map->scalebar.offsetx; - point.y = map->height - MS_NINT(embeddedSymbol->sizey / 2.0) - + point.y = map->height - MS_NINT(effSizeY / 2.0) - map->scalebar.offsety; break; case (MS_UR): - point.x = map->width - MS_NINT(embeddedSymbol->sizex / 2.0) - + point.x = map->width - MS_NINT(effSizeX / 2.0) - map->scalebar.offsetx; - point.y = MS_NINT(embeddedSymbol->sizey / 2.0) + map->scalebar.offsety; + point.y = MS_NINT(effSizeY / 2.0) + map->scalebar.offsety; break; case (MS_UL): - point.x = MS_NINT(embeddedSymbol->sizex / 2.0) + map->scalebar.offsetx; - point.y = MS_NINT(embeddedSymbol->sizey / 2.0) + map->scalebar.offsety; + point.x = MS_NINT(effSizeX / 2.0) + map->scalebar.offsetx; + point.y = MS_NINT(effSizeY / 2.0) + map->scalebar.offsety; break; case (MS_UC): point.x = MS_NINT(map->width / 2.0) + map->scalebar.offsetx; - point.y = MS_NINT(embeddedSymbol->sizey / 2.0) + map->scalebar.offsety; + point.y = MS_NINT(effSizeY / 2.0) + map->scalebar.offsety; break; } @@ -716,13 +735,14 @@ int msEmbedScalebar(mapObj *map, imageObj *img) { } GET_LAYER(map, l)->status = MS_ON; - GET_LAYER(map, l)->scalefactor = 1; /* no need to magnify symbol */ + GET_LAYER(map, l)->scalefactor = scalebarScale; /* usually 1, see svgDPI correction above */ if (map->scalebar.postlabelcache) { /* add it directly to the image */ if (msMaybeAllocateClassStyle(GET_LAYER(map, l)->class[0], 0) == MS_FAILURE) return MS_FAILURE; GET_LAYER(map, l)->class[0]->styles[0]->symbol = s; status = msDrawMarkerSymbol(map, img, &point, - GET_LAYER(map, l)->class[0] -> styles[0], 1.0); + GET_LAYER(map, l)->class[0] -> styles[0], + scalebarScale); if (MS_UNLIKELY(status == MS_FAILURE)) { goto embed_cleanup; } diff --git a/src/mapscript/csharp/csmodule.i b/src/mapscript/csharp/csmodule.i index 1b731e6270..92fddf1210 100644 --- a/src/mapscript/csharp/csmodule.i +++ b/src/mapscript/csharp/csmodule.i @@ -79,12 +79,16 @@ inner exceptions. Otherwise the exception message will be concatenated*/ %exception msLoadMapFromString { errorObj *ms_error; +#if defined(WIN32) && defined(SWIGCSHARP) __try { $action - } - __except(1 /*EXCEPTION_EXECUTE_HANDLER, catch every exception so it doesn't crash IIS*/) { + } + __except(1 /*EXCEPTION_EXECUTE_HANDLER, catch every exception so it doesn't crash IIS*/) { msSetError(MS_MISCERR, "Unhandled exception in msLoadMapFromString 0x%08x", "msLoadMapFromString()", GetExceptionCode()); } +#else + $action +#endif ms_error = msGetErrorObj(); if (ms_error != NULL && ms_error->code != MS_NOERR) { if (ms_error->code != MS_NOTFOUND && ms_error->code != -1) { @@ -131,12 +135,16 @@ inner exceptions. Otherwise the exception message will be concatenated*/ %exception msLoadMapFromString { errorObj *ms_error; +#if defined(WIN32) && defined(SWIGCSHARP) __try { $action - } - __except(1 /*EXCEPTION_EXECUTE_HANDLER, catch every exception so it doesn't crash IIS*/) { + } + __except(1 /*EXCEPTION_EXECUTE_HANDLER, catch every exception so it doesn't crash IIS*/) { msSetError(MS_MISCERR, "Unhandled exception in msLoadMapFromString 0x%08x", "msLoadMapFromString()", GetExceptionCode()); } +#else + $action +#endif ms_error = msGetErrorObj(); if (ms_error != NULL && ms_error->code != MS_NOERR) { if (ms_error->code != MS_NOTFOUND && ms_error->code != -1) { diff --git a/src/mapsymbol.c b/src/mapsymbol.c index de90327cc1..7f4c981b6e 100644 --- a/src/mapsymbol.c +++ b/src/mapsymbol.c @@ -970,7 +970,8 @@ int msPreloadImageSymbol(rendererVTableObj *renderer, symbolObj *symbol) { if (symbol->renderer_free_func) symbol->renderer_free_func(symbol); - symbol->renderer_free_func = renderer->freeSymbol; + symbol->renderer_free_func = + (void (*)(symbolObj *))renderer->freeSymbol; } symbol->sizex = symbol->pixmap_buffer->width; symbol->sizey = symbol->pixmap_buffer->height;