File indexing completed on 2024-05-12 15:59:44
0001 /* 0002 * SPDX-FileCopyrightText: 2009 Boudewijn Rempt <boud@valdyas.org> 0003 * SPDX-FileCopyrightText: 2021 L. E. Segovia <amy@amyspark.me> 0004 * 0005 * SPDX-License-Identifier: GPL-2.0-or-later 0006 */ 0007 0008 #ifndef PSD_UTILS_H 0009 #define PSD_UTILS_H 0010 0011 #include "kritapsdutils_export.h" 0012 0013 #include <QtEndian> 0014 #include <QtGlobal> 0015 #include <array> 0016 #include <psd.h> 0017 #include <resources/KoPattern.h> 0018 #include <type_traits> 0019 0020 class QIODevice; 0021 class QString; 0022 0023 /** 0024 * Writing functions. 0025 */ 0026 0027 inline bool psdwriteBE(QIODevice &io, const quint8 &v) 0028 { 0029 const std::array<quint8, 2> val = {v}; 0030 const qint64 written = io.write(reinterpret_cast<const char *>(val.data()), 1); 0031 return written == 1; 0032 } 0033 0034 inline bool psdwriteLE(QIODevice &io, const quint8 &v) 0035 { 0036 const std::array<quint8, 2> val = {v}; 0037 const qint64 written = io.write(reinterpret_cast<const char *>(val.data()), 1); 0038 return written == 1; 0039 } 0040 0041 inline bool psdwriteBE(QIODevice &io, const quint16 &v) 0042 { 0043 const std::array<quint8, 2> val = { 0044 quint8(v >> 8U), 0045 quint8(v), 0046 }; 0047 const qint64 written = io.write(reinterpret_cast<const char *>(val.data()), 2); 0048 return written == 2; 0049 } 0050 0051 inline bool psdwriteLE(QIODevice &io, const quint16 &v) 0052 { 0053 const std::array<quint8, 2> val = { 0054 quint8(v), 0055 quint8(v >> 8U), 0056 }; 0057 const qint64 written = io.write(reinterpret_cast<const char *>(val.data()), 2); 0058 return written == 2; 0059 } 0060 0061 inline bool psdwriteBE(QIODevice &io, const quint32 &v) 0062 { 0063 const std::array<quint8, 4> val = { 0064 quint8(v >> 24U), 0065 quint8(v >> 16U), 0066 quint8(v >> 8U), 0067 quint8(v), 0068 }; 0069 const qint64 written = io.write(reinterpret_cast<const char *>(val.data()), 4); 0070 return written == 4; 0071 } 0072 0073 inline bool psdwriteLE(QIODevice &io, const quint32 &v) 0074 { 0075 const std::array<quint8, 4> val = { 0076 quint8(v), 0077 quint8(v >> 8U), 0078 quint8(v >> 16U), 0079 quint8(v >> 24U), 0080 }; 0081 const qint64 written = io.write(reinterpret_cast<const char *>(val.data()), 4); 0082 return written == 4; 0083 } 0084 0085 inline bool psdwriteBE(QIODevice &io, const quint64 &v) 0086 { 0087 const std::array<quint8, 8> val = { 0088 quint8(v >> 56U), 0089 quint8(v >> 48U), 0090 quint8(v >> 40U), 0091 quint8(v >> 32U), 0092 quint8(v >> 24U), 0093 quint8(v >> 16U), 0094 quint8(v >> 8U), 0095 quint8(v), 0096 }; 0097 const qint64 written = io.write(reinterpret_cast<const char *>(val.data()), 8); 0098 return written == 8; 0099 } 0100 0101 inline bool psdwriteLE(QIODevice &io, const quint64 &v) 0102 { 0103 const std::array<quint8, 8> val = { 0104 quint8(v), 0105 quint8(v >> 8U), 0106 quint8(v >> 16U), 0107 quint8(v >> 24U), 0108 quint8(v >> 32U), 0109 quint8(v >> 40U), 0110 quint8(v >> 48U), 0111 quint8(v >> 56U), 0112 }; 0113 const qint64 written = io.write(reinterpret_cast<const char *>(val.data()), 8); 0114 return written == 8; 0115 } 0116 0117 /** 0118 * Templated writing fallbacks for non-integral types. 0119 */ 0120 0121 template<typename T> 0122 inline bool psdwriteBE(QIODevice &io, std::enable_if_t<sizeof(T) == sizeof(quint8), T &> v) 0123 { 0124 return psdwriteBE(io, reinterpret_cast<quint8 &>(v)); 0125 } 0126 0127 template<typename T> 0128 inline bool psdwriteBE(QIODevice &io, std::enable_if_t<sizeof(T) == sizeof(quint16), T &> v) 0129 { 0130 return psdwriteBE(io, reinterpret_cast<quint16 &>(v)); 0131 } 0132 0133 template<typename T> 0134 inline bool psdwriteBE(QIODevice &io, std::enable_if_t<sizeof(T) == sizeof(quint32), T &> v) 0135 { 0136 return psdwriteBE(io, reinterpret_cast<quint32 &>(v)); 0137 } 0138 0139 template<typename T> 0140 inline bool psdwriteBE(QIODevice &io, std::enable_if_t<sizeof(T) == sizeof(quint64), T &> v) 0141 { 0142 return psdwriteBE(io, reinterpret_cast<quint64 &>(v)); 0143 } 0144 0145 template<typename T> 0146 inline bool psdwriteLE(QIODevice &io, std::enable_if_t<sizeof(T) == sizeof(quint8), T &> v) 0147 { 0148 return psdwriteLE(io, reinterpret_cast<quint8 &>(v)); 0149 } 0150 0151 template<typename T> 0152 inline bool psdwriteLE(QIODevice &io, std::enable_if_t<sizeof(T) == sizeof(quint16), T &> v) 0153 { 0154 return psdwriteLE(io, reinterpret_cast<quint16 &>(v)); 0155 } 0156 0157 template<typename T> 0158 inline bool psdwriteLE(QIODevice &io, std::enable_if_t<sizeof(T) == sizeof(quint32), T &> v) 0159 { 0160 return psdwriteLE(io, reinterpret_cast<quint32 &>(v)); 0161 } 0162 0163 template<typename T> 0164 inline bool psdwriteLE(QIODevice &io, std::enable_if_t<sizeof(T) == sizeof(quint64), T &> v) 0165 { 0166 return psdwriteLE(io, reinterpret_cast<quint64 &>(v)); 0167 } 0168 0169 template<psd_byte_order byteOrder = psd_byte_order::psdBigEndian, typename T> 0170 inline std::enable_if_t<std::is_arithmetic<T>::value, bool> psdwrite(QIODevice &io, T v) 0171 { 0172 if (byteOrder == psd_byte_order::psdLittleEndian) { 0173 return psdwriteLE<T>(io, v); 0174 } else { 0175 return psdwriteBE<T>(io, v); 0176 } 0177 } 0178 0179 inline bool psdwrite(QIODevice &io, const QString &s) 0180 { 0181 const QByteArray b = s.toLatin1(); 0182 int l = b.size(); 0183 const qint64 written = io.write(reinterpret_cast<const char *>(b.data()), l); 0184 return written == l; 0185 } 0186 0187 template<psd_byte_order byteOrder = psd_byte_order::psdBigEndian> 0188 inline bool psdwrite_pascalstring(QIODevice &io, const QString &s) 0189 { 0190 Q_ASSERT(s.length() < 256); 0191 Q_ASSERT(s.length() >= 0); 0192 if (s.length() < 0 || s.length() > 255) 0193 return false; 0194 0195 if (s.isNull()) { 0196 psdwrite<byteOrder>(io, quint8(0)); 0197 psdwrite<byteOrder>(io, quint8(0)); 0198 return true; 0199 } 0200 0201 quint8 length = static_cast<quint8>(s.length()); 0202 psdwrite<byteOrder>(io, length); 0203 0204 const QByteArray b = s.toLatin1(); 0205 const qint64 written = io.write(reinterpret_cast<const char *>(b.data()), length); 0206 if (written != length) 0207 return false; 0208 0209 if ((length & 0x01) != 0) { 0210 return psdwrite<byteOrder>(io, quint8(0)); 0211 } 0212 0213 return true; 0214 } 0215 0216 template<psd_byte_order byteOrder = psd_byte_order::psdBigEndian> 0217 inline bool psdwrite_pascalstring(QIODevice &io, const QString &s, int padding) 0218 { 0219 Q_ASSERT(s.length() < 256); 0220 Q_ASSERT(s.length() >= 0); 0221 if (s.length() < 0 || s.length() > 255) 0222 return false; 0223 0224 if (s.isNull()) { 0225 psdwrite<byteOrder>(io, quint8(0)); 0226 psdwrite<byteOrder>(io, quint8(0)); 0227 return true; 0228 } 0229 quint8 length = static_cast<quint8>(s.length()); 0230 psdwrite<byteOrder>(io, length); 0231 0232 QByteArray b = s.toLatin1(); 0233 const qint64 written = io.write(b.data(), length); 0234 if (written != length) 0235 return false; 0236 0237 // If the total length (length byte + content) is not a multiple of padding, add zeroes to pad 0238 length++; 0239 if ((length % padding) != 0) { 0240 for (int i = 0; i < (padding - (length % padding)); i++) { 0241 psdwrite<byteOrder>(io, quint8(0)); 0242 } 0243 } 0244 0245 return true; 0246 } 0247 0248 inline bool psdpad(QIODevice &io, quint32 padding) 0249 { 0250 for (quint32 i = 0; i < padding; i++) { 0251 const bool written = io.putChar('\0'); 0252 if (!written) 0253 return false; 0254 } 0255 return true; 0256 } 0257 0258 /** 0259 * Reading functions. 0260 */ 0261 0262 inline bool psdreadBE(QIODevice &io, quint8 &v) 0263 { 0264 std::array<quint8, 1> data; 0265 qint64 read = io.read(reinterpret_cast<char *>(data.data()), 1); 0266 if (read != 1) 0267 return false; 0268 v = data[0]; 0269 return true; 0270 } 0271 0272 inline bool psdreadLE(QIODevice &io, quint8 &v) 0273 { 0274 std::array<quint8, 1> data; 0275 qint64 read = io.read(reinterpret_cast<char *>(data.data()), 1); 0276 if (read != 1) 0277 return false; 0278 v = data[0]; 0279 return true; 0280 } 0281 0282 inline bool psdreadBE(QIODevice &io, quint16 &v) 0283 { 0284 std::array<quint8, 2> data; 0285 qint64 read = io.read(reinterpret_cast<char *>(data.data()), 2); 0286 if (read != 2) 0287 return false; 0288 v = quint16((quint16(data[0]) << 8U) | data[1]); 0289 return true; 0290 } 0291 0292 inline bool psdreadLE(QIODevice &io, quint16 &v) 0293 { 0294 std::array<quint8, 2> data; 0295 qint64 read = io.read(reinterpret_cast<char *>(data.data()), 2); 0296 if (read != 2) 0297 return false; 0298 v = quint16((quint16(data[1]) << 8U) | data[0]); 0299 return true; 0300 } 0301 0302 inline bool psdreadBE(QIODevice &io, quint32 &v) 0303 { 0304 std::array<quint8, 4> data; 0305 qint64 read = io.read(reinterpret_cast<char *>(data.data()), 4); 0306 if (read != 4) 0307 return false; 0308 v = (quint32(data[0]) << 24U) | (quint32(data[1]) << 16U) | (quint32(data[2]) << 8U) | data[3]; 0309 return true; 0310 } 0311 0312 inline bool psdreadLE(QIODevice &io, quint32 &v) 0313 { 0314 std::array<quint8, 4> data; 0315 qint64 read = io.read(reinterpret_cast<char *>(data.data()), 4); 0316 if (read != 4) 0317 return false; 0318 v = (quint32(data[3]) << 24U) | (quint32(data[2]) << 16U) | (quint32(data[1]) << 8U) | data[0]; 0319 return true; 0320 } 0321 0322 inline bool psdreadBE(QIODevice &io, quint64 &v) 0323 { 0324 std::array<quint8, 8> data; 0325 qint64 read = io.read(reinterpret_cast<char *>(data.data()), 8); 0326 if (read != 8) 0327 return false; 0328 v = (quint64(data[0]) << 56U) | (quint64(data[1]) << 48U) | (quint64(data[2]) << 40U) | (quint64(data[3]) << 32U) | (quint64(data[4]) << 24U) 0329 | (quint64(data[5]) << 16U) | (quint64(data[6]) << 8U) | data[7]; 0330 return true; 0331 } 0332 0333 inline bool psdreadLE(QIODevice &io, quint64 &v) 0334 { 0335 std::array<quint8, 8> data; 0336 qint64 read = io.read(reinterpret_cast<char *>(data.data()), 8); 0337 if (read != 8) 0338 return false; 0339 v = (quint64(data[7]) << 56U) | (quint64(data[6]) << 48U) | (quint64(data[5]) << 40U) | (quint64(data[4]) << 32U) | (quint64(data[3]) << 24U) 0340 | (quint64(data[2]) << 16U) | (quint64(data[1]) << 8U) | data[0]; 0341 return true; 0342 } 0343 0344 /** 0345 * Templated reading fallbacks for non-integral types. 0346 */ 0347 0348 template<typename T> 0349 inline bool psdreadBE(QIODevice &io, std::enable_if_t<sizeof(T) == sizeof(quint8), T &> v) 0350 { 0351 return psdreadBE(io, reinterpret_cast<quint8 &>(v)); 0352 } 0353 0354 template<typename T> 0355 inline bool psdreadBE(QIODevice &io, std::enable_if_t<sizeof(T) == sizeof(quint16), T &> v) 0356 { 0357 return psdreadBE(io, reinterpret_cast<quint16 &>(v)); 0358 } 0359 0360 template<typename T> 0361 inline bool psdreadBE(QIODevice &io, std::enable_if_t<sizeof(T) == sizeof(quint32), T &> v) 0362 { 0363 return psdreadBE(io, reinterpret_cast<quint32 &>(v)); 0364 } 0365 0366 template<typename T> 0367 inline bool psdreadBE(QIODevice &io, std::enable_if_t<sizeof(T) == sizeof(quint64), T &> v) 0368 { 0369 return psdreadBE(io, reinterpret_cast<quint64 &>(v)); 0370 } 0371 0372 template<typename T> 0373 inline bool psdreadLE(QIODevice &io, std::enable_if_t<sizeof(T) == sizeof(quint8), T &> v) 0374 { 0375 return psdreadLE(io, reinterpret_cast<quint8 &>(v)); 0376 } 0377 0378 template<typename T> 0379 inline bool psdreadLE(QIODevice &io, std::enable_if_t<sizeof(T) == sizeof(quint16), T &> v) 0380 { 0381 return psdreadLE(io, reinterpret_cast<quint16 &>(v)); 0382 } 0383 0384 template<typename T> 0385 inline bool psdreadLE(QIODevice &io, std::enable_if_t<sizeof(T) == sizeof(quint32), T &> v) 0386 { 0387 return psdreadLE(io, reinterpret_cast<quint32 &>(v)); 0388 } 0389 0390 template<typename T> 0391 inline bool psdreadLE(QIODevice &io, std::enable_if_t<sizeof(T) == sizeof(quint64), T &> v) 0392 { 0393 return psdreadLE(io, reinterpret_cast<quint64 &>(v)); 0394 } 0395 0396 template<psd_byte_order byteOrder = psd_byte_order::psdBigEndian, typename T> 0397 inline std::enable_if_t<std::is_arithmetic<T>::value, bool> psdread(QIODevice &io, T &v) 0398 { 0399 if (byteOrder == psd_byte_order::psdLittleEndian) { 0400 return psdreadLE<T>(io, v); 0401 } else { 0402 return psdreadBE<T>(io, v); 0403 } 0404 } 0405 0406 template<psd_byte_order byteOrder = psd_byte_order::psdBigEndian> 0407 inline QByteArray psdreadBytes(QIODevice &io, qint64 v) 0408 { 0409 QByteArray b = io.read(v); 0410 if (byteOrder == psd_byte_order::psdLittleEndian) { 0411 std::reverse(b.begin(), b.end()); 0412 } 0413 return b; 0414 } 0415 0416 template<psd_byte_order byteOrder = psd_byte_order::psdBigEndian> 0417 inline bool psdread_pascalstring(QIODevice &io, QString &s, qint64 padding) 0418 { 0419 quint8 length; 0420 if (!psdread<byteOrder>(io, length)) { 0421 return false; 0422 } 0423 0424 if (length == 0) { 0425 // read the padding 0426 for (qint64 i = 0; i < padding - 1; ++i) { 0427 io.seek(io.pos() + 1); 0428 } 0429 return true; 0430 } 0431 0432 QByteArray chars = io.read(length); 0433 if (chars.length() != length) { 0434 return false; 0435 } 0436 0437 // read padding byte 0438 quint32 paddedLength = length + 1; 0439 if (padding > 0) { 0440 while (paddedLength % padding != 0) { 0441 if (!io.seek(io.pos() + 1)) { 0442 return false; 0443 } 0444 paddedLength++; 0445 } 0446 } 0447 0448 s.append(QString::fromLatin1(chars)); 0449 if (s.endsWith(QChar::Space)) { 0450 s.chop(1); 0451 } 0452 0453 return true; 0454 } 0455 0456 template<psd_byte_order byteOrder = psd_byte_order::psdBigEndian> 0457 inline bool psdread_unicodestring(QIODevice &io, QString &s) 0458 { 0459 quint32 stringlen; 0460 if (!psdread<byteOrder>(io, stringlen)) { 0461 return false; 0462 } 0463 0464 s.fill(QChar::Space, static_cast<int>(stringlen)); 0465 0466 for (quint32 i = 0; i < stringlen; ++i) { 0467 quint16 ch(0); 0468 if (!psdread<byteOrder>(io, ch)) { 0469 return false; 0470 } 0471 0472 // XXX: this makes it possible to append garbage 0473 if (ch != 0) { 0474 s[i] = QChar(ch); 0475 } 0476 } 0477 if (s.endsWith(QChar::Space)) { 0478 s.chop(1); 0479 } 0480 0481 return true; 0482 } 0483 0484 template<psd_byte_order byteOrder = psd_byte_order::psdBigEndian> 0485 inline bool psd_read_blendmode(QIODevice &io, QString &blendModeKey) 0486 { 0487 QByteArray b(psdreadBytes<byteOrder>(io, 4)); 0488 if (b.size() != 4 || QString(b) != "8BIM") { 0489 return false; 0490 } 0491 blendModeKey = QString(psdreadBytes<byteOrder>(io, 4)); 0492 if (blendModeKey.size() != 4) { 0493 return false; 0494 } 0495 return true; 0496 } 0497 0498 #endif // PSD_UTILS_H