File indexing completed on 2024-10-13 04:16:23
0001 // SPDX-FileCopyrightText: Lukas Sommer <sommerluk@gmail.com> 0002 // SPDX-License-Identifier: BSD-2-Clause OR MIT 0003 0004 // Own headers 0005 // First the interface, which forces the header to be self-contained. 0006 #include "iohandlerfactory.h" 0007 0008 #include "helpermath.h" 0009 #include <lcms2.h> 0010 #include <lcms2_plugin.h> 0011 #include <limits> 0012 #include <qdebug.h> 0013 #include <qfile.h> 0014 #include <qglobal.h> 0015 #include <qiodevice.h> 0016 #include <qstringliteral.h> 0017 0018 #if (QT_VERSION >= QT_VERSION_CHECK(6, 0, 0)) 0019 #include <qiodevicebase.h> 0020 #endif 0021 0022 namespace PerceptualColor 0023 { 0024 /** @internal 0025 * 0026 * @brief Read from file. 0027 * 0028 * @param iohandler The <tt>cmsIOHANDLER</tt> on which to operate 0029 * @param Buffer Pointer to the buffer to which the data should be loaded 0030 * @param size Size of the chucks that should be loaded 0031 * @param count Number of elements that should be loaded 0032 * @returns On success, <tt>count</tt> is returned. If failing (either 0033 * because less elements have been read or because zero elements have 0034 * been read), <tt>0</tt> is returned. */ 0035 cmsUInt32Number IOHandlerFactory::read(cmsIOHANDLER *iohandler, void *Buffer, cmsUInt32Number size, cmsUInt32Number count) 0036 { 0037 QFile *const myFile = static_cast<QFile *>(iohandler->stream); 0038 const cmsUInt32Number numberOfBytesRequested = size * count; 0039 const qint64 numberOfBytesRead = myFile->read( // 0040 static_cast<char *>(Buffer), 0041 size * count); 0042 if (numberOfBytesRead != numberOfBytesRequested) { 0043 return 0; 0044 } 0045 return count; 0046 } 0047 0048 /** @internal 0049 * 0050 * @brief Sets the current position within the file. 0051 * 0052 * @param iohandler The <tt>cmsIOHANDLER</tt> on which to operate 0053 * @param offset Set the current position to this position 0054 * @returns <tt>true</tt> on success, or <tt>false</tt> if an error 0055 * occurred. */ 0056 cmsBool IOHandlerFactory::seek(cmsIOHANDLER *iohandler, cmsUInt32Number offset) 0057 { 0058 QFile *const myFile = static_cast<QFile *>(iohandler->stream); 0059 const bool seekSucceeded = myFile->seek(offset); 0060 if (!seekSucceeded) { 0061 qDebug() << QStringLiteral("Seek error; probably corrupted file"); 0062 return false; 0063 } 0064 return true; 0065 } 0066 0067 /** @internal 0068 * 0069 * @brief The position that data is written to or read from. 0070 * @param iohandler The <tt>cmsIOHANDLER</tt> on which to operate 0071 * @returns The position that data is written to or read from. */ 0072 cmsUInt32Number IOHandlerFactory::tell(cmsIOHANDLER *iohandler) 0073 { 0074 const QFile *const myFile = static_cast<QFile *>(iohandler->stream); 0075 return static_cast<cmsUInt32Number>(myFile->pos()); 0076 } 0077 0078 /** @internal 0079 * 0080 * @brief Writes data to stream. 0081 * 0082 * Also keeps used space for further reference. 0083 * 0084 * @param iohandler The <tt>cmsIOHANDLER</tt> on which to operate 0085 * @param size The size of the buffer that should be written 0086 * @param Buffer The buffer that should be written 0087 * @returns Returns <tt>true</tt> on success, <tt>false</tt> on error. 0088 * 0089 * @note Because @ref IOHandlerFactory only provides support for read-only 0090 * handlers, this function does nothing and returns always <tt>false</tt>. */ 0091 cmsBool IOHandlerFactory::write(cmsIOHANDLER *iohandler, cmsUInt32Number size, const void *Buffer) 0092 { 0093 Q_UNUSED(iohandler) 0094 Q_UNUSED(size) 0095 Q_UNUSED(Buffer) 0096 return false; 0097 } 0098 0099 /** @internal 0100 * 0101 * @brief Closes the file and deletes the file handler. 0102 * @param iohandler The <tt>cmsIOHANDLER</tt> on which to operate 0103 * @returns <tt>true</tt> on success. */ 0104 cmsBool IOHandlerFactory::close(cmsIOHANDLER *iohandler) 0105 { 0106 QFile *const myFile = static_cast<QFile *>(iohandler->stream); 0107 delete myFile; // This will also close the file. 0108 iohandler->stream = nullptr; 0109 _cmsFree(iohandler->ContextID, iohandler); 0110 return true; 0111 } 0112 0113 /** @brief Create a read-only LittleCMS IO handler for a file. 0114 * 0115 * The handler has to be deleted with <tt>cmsCloseIOhandler</tt> 0116 * to free memory once it is not used anymore. 0117 * 0118 * @param ContextID Handle to user-defined context, or <tt>nullptr</tt> for 0119 * the global context 0120 * @param fileName Name of the file. See QFile::setFileName() for 0121 * the valid format. This format is portable, has standardized directory 0122 * separators and supports Unicode file names on all platforms. 0123 * @returns On success, a pointer to a new IO handler. On fail, 0124 * <tt>nullptr</tt>. The function might fail when the file does not 0125 * exist or cannot be opened for reading. 0126 * 0127 * @internal 0128 * 0129 * @note The type of the return value is not fully defined 0130 * in <tt>lcms2.h</tt> but only in <tt>lcms2_plugin.h</tt>. This is 0131 * the expected behaviour for an opaque handle. */ 0132 cmsIOHANDLER *IOHandlerFactory::createReadOnly(cmsContext ContextID, const QString &fileName) 0133 { 0134 cmsIOHANDLER *const result = static_cast<cmsIOHANDLER *>( // 0135 _cmsMallocZero(ContextID, sizeof(cmsIOHANDLER)) // 0136 ); 0137 if (result == nullptr) { 0138 return nullptr; 0139 } 0140 0141 QFile *const fileObject = new QFile(fileName); 0142 if (fileObject == nullptr) { 0143 return nullptr; 0144 } 0145 0146 const bool openSucceeded = fileObject->open(QIODevice::ReadOnly); 0147 const qint64 fileSize = fileObject->size(); 0148 // Check if the size is not negative (this might be an error indicator) 0149 // neither too big for LittleCMS’s data types: 0150 const bool isFileSizeOkay = PerceptualColor::isInRange<qint64>( // 0151 0, 0152 fileSize, 0153 std::numeric_limits<cmsInt32Number>::max()); 0154 if ((!openSucceeded) || (!isFileSizeOkay)) { 0155 delete fileObject; 0156 _cmsFree(ContextID, result); 0157 return nullptr; 0158 } 0159 0160 // Initialize data members 0161 result->ContextID = ContextID; 0162 // static_cast loses integer precision: 'qint64' to 'cmsInt32Number'. 0163 // This is okay because we have tested yet that the file is not that big. 0164 result->ReportedSize = static_cast<cmsUInt32Number>(fileSize); 0165 result->stream = static_cast<void *>(fileObject); 0166 result->UsedSpace = 0; 0167 result->PhysicalFile[0] = 0; 0168 0169 // Initialize function pointers 0170 result->Read = read; 0171 result->Seek = seek; 0172 result->Close = close; 0173 result->Tell = tell; 0174 result->Write = write; 0175 0176 return result; 0177 } 0178 0179 } // namespace PerceptualColor