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