File indexing completed on 2024-06-23 04:23:33
0001 /* 0002 * SPDX-FileCopyrightText: 2015 Dmitry Kazakov <dimula73@gmail.com> 0003 * SPDX-FileCopyrightText: 2021 L. E. Segovia <amy@amyspark.me> 0004 * 0005 * SPDX-License-Identifier: GPL-2.0-or-later 0006 */ 0007 0008 #ifndef __KIS_ASL_READER_UTILS_H 0009 #define __KIS_ASL_READER_UTILS_H 0010 0011 #include "psd.h" 0012 #include "psd_utils.h" 0013 0014 #include <algorithm> 0015 #include <stdexcept> 0016 #include <string> 0017 0018 #include <QtEndian> 0019 0020 #include <kis_debug.h> 0021 0022 /** 0023 * Default value for variable read from a file 0024 */ 0025 0026 #define GARBAGE_VALUE_MARK 999 0027 0028 namespace KisAslReaderUtils 0029 { 0030 /** 0031 * Exception that is emitted when any parse error appear. 0032 * Thanks to KisOffsetOnExitVerifier parsing can be continued 0033 * most of the time, based on the offset values written in PSD. 0034 */ 0035 0036 struct KRITAPSDUTILS_EXPORT ASLParseException : public std::runtime_error { 0037 ASLParseException(const QString &msg) 0038 : std::runtime_error(msg.toLatin1().data()) 0039 { 0040 } 0041 }; 0042 0043 } 0044 0045 #define SAFE_READ_EX(byteOrder, device, varname) \ 0046 if (!psdread<byteOrder>(device, varname)) { \ 0047 QString msg = QString("Failed to read \'%1\' tag!").arg(#varname); \ 0048 throw KisAslReaderUtils::ASLParseException(msg); \ 0049 } 0050 0051 #define SAFE_READ_SIGNATURE_EX(byteOrder, device, varname, expected) \ 0052 if (!psdread<byteOrder>(device, varname) || varname != expected) { \ 0053 QString msg = QString( \ 0054 "Failed to check signature \'%1\' tag!\n" \ 0055 "Value: \'%2\' Expected: \'%3\'") \ 0056 .arg(#varname) \ 0057 .arg(varname) \ 0058 .arg(expected); \ 0059 throw KisAslReaderUtils::ASLParseException(msg); \ 0060 } 0061 0062 template<psd_byte_order byteOrder, typename T, size_t S> 0063 inline bool TRY_READ_SIGNATURE_2OPS_EX(QIODevice &device, const std::array<T, S> &expected1, const std::array<T, S> &expected2) 0064 { 0065 QByteArray bytes = device.peek(S); 0066 0067 if (byteOrder == psd_byte_order::psdLittleEndian) { 0068 std::reverse(bytes.begin(), bytes.end()); 0069 } 0070 0071 if (bytes.size() != S) { 0072 return false; 0073 } 0074 0075 // If read successfully, adjust current position of the io device 0076 0077 if (std::equal(bytes.constBegin(), bytes.constEnd(), expected1.begin()) 0078 || std::equal(bytes.constBegin(), bytes.constEnd(), expected2.begin())) { 0079 // read, not seek, to support sequential devices 0080 auto bytesRead = psdreadBytes(device, S); 0081 if (bytesRead.size() == S) { 0082 return true; 0083 } 0084 } 0085 0086 dbgFile << "Photoshop signature verification failed! Got: " << bytes.toHex() << "(" << QString(bytes) << ")"; 0087 return false; 0088 } 0089 0090 template<typename T, size_t S> 0091 inline bool TRY_READ_SIGNATURE_2OPS_EX(psd_byte_order byteOrder, QIODevice &device, const std::array<T, S> &expected1, const std::array<T, S> &expected2) 0092 { 0093 switch (byteOrder) { 0094 case psd_byte_order::psdLittleEndian: 0095 return TRY_READ_SIGNATURE_2OPS_EX<psd_byte_order::psdLittleEndian>(device, expected1, expected2); 0096 default: 0097 return TRY_READ_SIGNATURE_2OPS_EX<psd_byte_order::psdBigEndian>(device, expected1, expected2); 0098 } 0099 } 0100 0101 namespace KisAslReaderUtils 0102 { 0103 /** 0104 * String fetch functions 0105 * 0106 * ASL has 4 types of strings: 0107 * 0108 * - fixed length (4 bytes) 0109 * - variable length (length (4 bytes) + string (var)) 0110 * - pascal (length (1 byte) + string (var)) 0111 * - unicode string (length (4 bytes) + null-terminated unicode string (var) 0112 */ 0113 0114 template<psd_byte_order byteOrder = psd_byte_order::psdBigEndian> 0115 inline QString readStringCommon(QIODevice &device, int length) 0116 { 0117 QByteArray data = psdreadBytes<byteOrder>(device, length); 0118 0119 if (data.size() != length) { 0120 QString msg = QString( 0121 "Failed to read a string! " 0122 "Bytes read: %1 Expected: %2") 0123 .arg(data.size()) 0124 .arg(length); 0125 throw ASLParseException(msg); 0126 } 0127 0128 return QString(data); 0129 } 0130 0131 template<psd_byte_order byteOrder = psd_byte_order::psdBigEndian> 0132 inline QString readFixedString(QIODevice &device) 0133 { 0134 return readStringCommon<byteOrder>(device, 4); 0135 } 0136 0137 template<psd_byte_order byteOrder = psd_byte_order::psdBigEndian> 0138 inline QString readVarString(QIODevice &device) 0139 { 0140 quint32 length = 0; 0141 SAFE_READ_EX(byteOrder, device, length); 0142 0143 if (!length) { 0144 length = 4; 0145 } 0146 0147 return readStringCommon<byteOrder>(device, length); 0148 } 0149 0150 template<psd_byte_order byteOrder = psd_byte_order::psdBigEndian> 0151 inline QString readPascalString(QIODevice &device) 0152 { 0153 quint8 length = 0; 0154 SAFE_READ_EX(byteOrder, device, length); 0155 0156 return readStringCommon(device, length); 0157 } 0158 0159 template<psd_byte_order byteOrder = psd_byte_order::psdBigEndian> 0160 inline QString readUnicodeString(QIODevice &device) 0161 { 0162 QString string; 0163 0164 if (!psdread_unicodestring<byteOrder>(device, string)) { 0165 QString msg = QString("Failed to read a unicode string!"); 0166 throw ASLParseException(msg); 0167 } 0168 0169 return string; 0170 } 0171 } 0172 0173 #endif /* __KIS_ASL_READER_UTILS_H */