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