diff --git a/rtengine/imagedata.cc b/rtengine/imagedata.cc index f8e257ddc..8dfd90ab3 100644 --- a/rtengine/imagedata.cc +++ b/rtengine/imagedata.cc @@ -46,8 +46,6 @@ ImageMetaData* ImageMetaData::fromFile (const Glib::ustring& fname, RawMetaDataL ImageData::ImageData (Glib::ustring fname, RawMetaDataLocation* ri) : iso_speed(0), aperture(0.), shutter(0.) { - - size_t dotpos = fname.find_last_of ('.'); root = nullptr; iptc = nullptr; @@ -72,7 +70,7 @@ ImageData::ImageData (Glib::ustring fname, RawMetaDataLocation* ri) : iso_speed( fclose (f); extractInfo (); } - } else if ((dotpos < fname.size() - 3 && !fname.casefold().compare (dotpos, 4, ".jpg")) || (dotpos < fname.size() - 4 && !fname.casefold().compare (dotpos, 5, ".jpeg"))) { + } else if (hasJpegExtension(fname)) { FILE* f = g_fopen (fname.c_str (), "rb"); if (f) { @@ -83,7 +81,7 @@ ImageData::ImageData (Glib::ustring fname, RawMetaDataLocation* ri) : iso_speed( iptc = iptc_data_new_from_jpeg_file (ff); fclose (ff); } - } else if ((dotpos < fname.size() - 3 && !fname.casefold().compare (dotpos, 4, ".tif")) || (dotpos < fname.size() - 4 && !fname.casefold().compare (dotpos, 5, ".tiff"))) { + } else if (hasTiffExtension(fname)) { FILE* f = g_fopen (fname.c_str (), "rb"); if (f) { diff --git a/rtengine/imageio.cc b/rtengine/imageio.cc index e886dabce..59f7cf541 100644 --- a/rtengine/imageio.cc +++ b/rtengine/imageio.cc @@ -1441,19 +1441,11 @@ void png_flush(png_structp png_ptr) int ImageIO::load (Glib::ustring fname) { - size_t lastdot = fname.find_last_of ('.'); - - if( Glib::ustring::npos == lastdot ) { - return IMIO_FILETYPENOTSUPPORTED; - } - - if (!fname.casefold().compare (lastdot, 4, ".png")) { + if (hasPngExtension(fname)) { return loadPNG (fname); - } else if (!fname.casefold().compare (lastdot, 4, ".jpg") || - !fname.casefold().compare (lastdot, 5, ".jpeg")) { + } else if (hasJpegExtension(fname)) { return loadJPEG (fname); - } else if (!fname.casefold().compare (lastdot, 4, ".tif") || - !fname.casefold().compare (lastdot, 5, ".tiff")) { + } else if (hasTiffExtension(fname)) { return loadTIFF (fname); } else { return IMIO_FILETYPENOTSUPPORTED; @@ -1462,20 +1454,11 @@ int ImageIO::load (Glib::ustring fname) int ImageIO::save (Glib::ustring fname) { - - size_t lastdot = fname.find_last_of ('.'); - - if( Glib::ustring::npos == lastdot ) { - return IMIO_FILETYPENOTSUPPORTED; - } - - if (!fname.casefold().compare (lastdot, 4, ".png")) { + if (hasPngExtension(fname)) { return savePNG (fname); - } else if (!fname.casefold().compare (lastdot, 4, ".jpg") || - !fname.casefold().compare (lastdot, 5, ".jpeg")) { + } else if (hasJpegExtension(fname)) { return saveJPEG (fname); - } else if (!fname.casefold().compare (lastdot, 4, ".tif") || - !fname.casefold().compare (lastdot, 5, ".tiff")) { + } else if (hasTiffExtension(fname)) { return saveTIFF (fname); } else { return IMIO_FILETYPENOTSUPPORTED; diff --git a/rtengine/stdimagesource.cc b/rtengine/stdimagesource.cc index 6017a1ca6..601cbe89c 100644 --- a/rtengine/stdimagesource.cc +++ b/rtengine/stdimagesource.cc @@ -74,27 +74,19 @@ void StdImageSource::getSampleFormat (const Glib::ustring &fname, IIOSampleForma sFormat = IIOSF_UNKNOWN; sArrangement = IIOSA_UNKNOWN; - size_t lastdot = fname.find_last_of ('.'); - - if( Glib::ustring::npos == lastdot ) { - return; - } - - if (!fname.casefold().compare (lastdot, 4, ".jpg") || - !fname.casefold().compare (lastdot, 5, ".jpeg")) { + if (hasJpegExtension(fname)) { // For now, png and jpeg files are converted to unsigned short by the loader itself, // but there should be functions that read the sample format first, like the TIFF case below sFormat = IIOSF_UNSIGNED_CHAR; sArrangement = IIOSA_CHUNKY; return; - } else if (!fname.casefold().compare (lastdot, 4, ".png")) { + } else if (hasPngExtension(fname)) { int result = ImageIO::getPNGSampleFormat (fname, sFormat, sArrangement); if (result == IMIO_SUCCESS) { return; } - } else if (!fname.casefold().compare (lastdot, 4, ".tif") || - !fname.casefold().compare (lastdot, 5, ".tiff")) { + } else if (hasTiffExtension(fname)) { int result = ImageIO::getTIFFSampleFormat (fname, sFormat, sArrangement); if (result == IMIO_SUCCESS) { diff --git a/rtengine/utils.cc b/rtengine/utils.cc index b862e290f..c23823c59 100644 --- a/rtengine/utils.cc +++ b/rtengine/utils.cc @@ -224,6 +224,34 @@ void vflip (unsigned char* img, int w, int h) delete [] flipped; } +/** + * Return lower case extension without the "." or "" if the given name contains no "." + */ +Glib::ustring getFileExtension(const Glib::ustring &fname) { + // issue 3598 do not use casefold() to compare ignoring case - it seems to mangle sharp-s character and length of string + // simply get extension first, then use lowercase() + const Glib::ustring::size_type lastdot = fname.find_last_of ('.'); + if( Glib::ustring::npos == lastdot ) { + return ""; + } + return fname.substr(lastdot + 1).lowercase(); +} + +bool hasJpegExtension(const Glib::ustring &fname) { + const Glib::ustring extension = getFileExtension(fname); + return ((extension == "jpg") || (extension == "jpeg")); +} + +bool hasTiffExtension(const Glib::ustring &fname) { + const Glib::ustring extension = getFileExtension(fname); + return ((extension == "tif") || (extension == "tiff")); +} + +bool hasPngExtension(const Glib::ustring &fname) { + const Glib::ustring extension = getFileExtension(fname); + return (extension == "png"); +} + } diff --git a/rtengine/utils.h b/rtengine/utils.h index c46999219..50286239b 100644 --- a/rtengine/utils.h +++ b/rtengine/utils.h @@ -19,6 +19,7 @@ #pragma once #include +#include namespace rtengine { @@ -42,4 +43,24 @@ typename std::underlying_type::type toUnderlying(ENUM value) return static_cast::type>(value); } +/** + * Return lower case extension without the "." or "" if the given name contains no "." + */ +Glib::ustring getFileExtension(const Glib::ustring &fname); + +/** + * Return true if file has .jpeg or .jpg extension (ignoring case) + */ +bool hasJpegExtension(const Glib::ustring &fname); + +/** + * Return true if file has .tiff or .tif extension (ignoring case) + */ +bool hasTiffExtension(const Glib::ustring &fname); + +/** + * Return true if file has .png extension (ignoring case) + */ +bool hasPngExtension(const Glib::ustring &fname); + } diff --git a/rtgui/options.cc b/rtgui/options.cc index 397b5996a..4d8a3a36b 100644 --- a/rtgui/options.cc +++ b/rtgui/options.cc @@ -2377,7 +2377,7 @@ bool Options::has_retained_extention (Glib::ustring fname) bool Options::is_extention_enabled (Glib::ustring ext) { for (int j = 0; j < (int)parseExtensions.size(); j++) - if (parseExtensions[j].casefold() == ext.casefold()) { + if (parseExtensions[j].casefold() == ext.casefold()) { // issue 3598 REVIEW OK - no change required return j >= (int)parseExtensionsEnabled.size() || parseExtensionsEnabled[j]; } diff --git a/rtgui/profilestore.cc b/rtgui/profilestore.cc index c80bbe388..f3d480382 100644 --- a/rtgui/profilestore.cc +++ b/rtgui/profilestore.cc @@ -277,13 +277,14 @@ const ProfileStoreEntry* ProfileStore::findEntryFromFullPathU(Glib::ustring path if (path == DEFPROFILE_INTERNAL) { return internalDefaultEntry; } + // consistently apply casefold() to make sure dot position is correct + const Glib::ustring::size_type lastdot = path.casefold().find_last_of ('.'); - size_t lastdot = path.find_last_of ('.'); - - if (lastdot != Glib::ustring::npos && lastdot <= path.size() - 4 && !path.casefold().compare (lastdot, 4, paramFileExtension)) + if ((lastdot != Glib::ustring::npos) && (lastdot <= path.casefold().size() - 4) && (!path.casefold().compare (lastdot, 4, paramFileExtension))) // removing the extension { - path = path.substr(0, lastdot); + // now use dot position without casefold() + path = path.substr(0, path.find_last_of ('.')); } // dir separator may come from options file and may be \ or /, we convert them to G_DIR_SEPARATOR_S