File indexing completed on 2024-05-12 04:44:34
0001 // SPDX-FileCopyrightText: Lukas Sommer <sommerluk@gmail.com> 0002 // SPDX-License-Identifier: BSD-2-Clause OR MIT 0003 0004 #ifndef IOHANDLERFACTORY_H 0005 #define IOHANDLERFACTORY_H 0006 0007 #include "lcms2.h" 0008 #include <qglobal.h> 0009 #include <qstring.h> 0010 0011 namespace PerceptualColor 0012 { 0013 /** @internal 0014 * 0015 * @brief Portable and Unicode-enabled file access for 0016 * LittleCMS IO handlers. 0017 * 0018 * @internal 0019 * 0020 * This class is necessary because LittleCMS does not provide portable 0021 * support for Unicode file names. 0022 * 0023 * - LittleCMS allows to open profiles directly from file names, but with 0024 * a <tt>char*</tt> as argument for the file name. This leads to non-portable 0025 * behaviour because the file name encoding differs between operation 0026 * systems. And on Windows, apparently, you even need to use wide-characters 0027 * to get support for Unicode file names. This does not work for us because 0028 * LittleCMS requires narrow-characters for the file name. For the same 0029 * reason, QFile::decodeName() and QFile::encodeName() would not help us 0030 * either doing this conversion. And we would have to use either <tt>/</tt> 0031 * or <tt>\\</tt> as directory separator, depending on the OS. C itself 0032 * does not seem to provide any portable methods for working with Unicode 0033 * file names. So this solution is both: not portable and not comfortable. 0034 * 0035 * - LittleCMS allows to open profiles directly from <tt>FILE *</tt>. We 0036 * could open a file in <tt>QFile</tt>, call <tt>QFile::handle()</tt> 0037 * to get a file descriptor, and use <tt>dup</tt> to create a duplicate. 0038 * Then, close the <tt>QFile</tt>, and use <tt>fdopen</tt> to create a 0039 * <tt>FILE *</tt> from the duplicate file descriptor. (We need to create 0040 * a duplicate of the file handle because otherwise, during the following 0041 * calls, fclose() might be called by LittleCMS before QFile::close is 0042 * called. This leads to undefined behaviour in some rare cases: 0043 * https://stackoverflow.com/questions/9465727/convert-qfile-to-file) 0044 * However, <tt>fdopen()</tt> and <tt>dup()</tt> are not part of C, but 0045 * of Posix; this might not be portable. Windows, for example, has 0046 * no <tt>fdopen()</tt> function but a <tt>_fdopen()</tt> function. 0047 * Other systems might not have them at all. So this solution is 0048 * not portable. 0049 * 0050 * - C++17 has <tt>filesystem::path</tt>, which seams to open files with 0051 * Unicode file names. But it does not allow to generate C-Standard 0052 * <tt>FILE</tt> handles, which would be necessary to connect with 0053 * LittleCMS, which has a C-only interface. 0054 * - Using an external library (maybe the boost library) for portable 0055 * file name handling would introduce another external dependency, 0056 * what we do not want. 0057 0058 * - LittleCMS allows to open profiles directly from a memory buffer. 0059 * We could use <tt>QFile</tt> for portability, load the hole file into 0060 * a memory buffer and let LittleCMS work with the memory buffer. 0061 * The disadvantage would be that it raises our memory usage. This might 0062 * be problematic if the ICC profile has various megabytes. It might 0063 * produce a crash, when by mistake the file name points to a 10-GB 0064 * video file, which would have to load completely into the buffer before 0065 * being rejected. 0066 * 0067 * Therefore, this class provides a custom LittleCMS IO handler which 0068 * internally (but invisible for LittleCMS) relies on QFile. This gives 0069 * us Qt’s portability and avoids the above-mentioned disadvantages. */ 0070 class IOHandlerFactory 0071 { 0072 public: 0073 [[nodiscard]] static cmsIOHANDLER *createReadOnly(cmsContext ContextID, const QString &fileName); 0074 0075 private: 0076 Q_DISABLE_COPY(IOHandlerFactory) 0077 0078 /** @internal 0079 * 0080 * @brief No constructor, because no objects of this class are 0081 * necessary. */ 0082 IOHandlerFactory() = delete; 0083 0084 static cmsBool close(cmsIOHANDLER *iohandler); 0085 static cmsUInt32Number read(cmsIOHANDLER *iohandler, void *Buffer, cmsUInt32Number size, cmsUInt32Number count); 0086 static cmsBool seek(cmsIOHANDLER *iohandler, cmsUInt32Number offset); 0087 [[nodiscard]] static cmsUInt32Number tell(cmsIOHANDLER *iohandler); 0088 static cmsBool write(cmsIOHANDLER *iohandler, cmsUInt32Number size, const void *Buffer); 0089 }; 0090 0091 } // namespace PerceptualColor 0092 0093 #endif // IOHANDLERFACTORY_H