File indexing completed on 2024-05-12 15:59:43

0001 /*
0002  *  SPDX-FileCopyrightText: 2004-2007 Graphest Software <libpsd@graphest.com>
0003  *  SPDX-FileCopyrightText: 2007 John Marshall
0004  *  SPDX-FileCopyrightText: 2010 Boudewijn Rempt <boud@valdyas.org>
0005  *  SPDX-FileCopyrightText: 2021 L. E. Segovia <amy@amyspark.me>
0006  *
0007  *  SPDX-License-Identifier: GPL-2.0-or-later
0008  */
0009 
0010 #include "compression.h"
0011 
0012 #include <QBuffer>
0013 #include <QtEndian>
0014 #include <algorithm>
0015 #include <zlib.h>
0016 
0017 #include <kis_debug.h>
0018 #include <psd_utils.h>
0019 
0020 namespace KisRLE
0021 {
0022 // from gimp's psd-save.c
0023 int compress(const QByteArray &src, QByteArray &dst)
0024 {
0025     int length = src.size();
0026     dst.resize(length * 2);
0027     dst.fill(0, length * 2);
0028 
0029     int remaining = length;
0030     quint8 i, j;
0031     quint32 dest_ptr = 0;
0032     const char *start = src.constData();
0033 
0034     length = 0;
0035     while (remaining > 0) {
0036         /* Look for characters matching the first */
0037         i = 0;
0038         while ((i < 128) && (remaining - i > 0) && (start[0] == start[i]))
0039             i++;
0040 
0041         if (i > 1) /* Match found */
0042         {
0043             dst[dest_ptr++] = static_cast<char>(-(i - 1));
0044             dst[dest_ptr++] = *start;
0045 
0046             start += i;
0047             remaining -= i;
0048             length += 2;
0049         } else { /* Look for characters different from the previous */
0050             i = 0;
0051             while ((i < 128) && (remaining - (i + 1) > 0) && (start[i] != start[(i + 1)] || remaining - (i + 2) <= 0 || start[i] != start[(i + 2)]))
0052                 i++;
0053 
0054             /* If there's only 1 remaining, the previous WHILE stmt doesn't
0055              catch it */
0056 
0057             if (remaining == 1) {
0058                 i = 1;
0059             }
0060 
0061             if (i > 0) /* Some distinct ones found */
0062             {
0063                 dst[dest_ptr++] = static_cast<char>(i - 1U);
0064                 for (j = 0; j < i; j++) {
0065                     dst[dest_ptr++] = start[j];
0066                 }
0067                 start += i;
0068                 remaining -= i;
0069                 length += i + 1;
0070             }
0071         }
0072     }
0073     dst.resize(length);
0074     return length;
0075 }
0076 
0077 QByteArray compress(const QByteArray &data)
0078 {
0079     QByteArray output;
0080     const int result = KisRLE::compress(data, output);
0081     if (result <= 0)
0082         return QByteArray();
0083     else
0084         return output;
0085 }
0086 
0087 QByteArray decompress(const QByteArray &input, int unpacked_len)
0088 {
0089     QByteArray output;
0090     output.resize(unpacked_len);
0091 
0092     const auto *src = input.cbegin();
0093     auto *dst = output.begin();
0094 
0095     while (src < input.end() && dst < output.end()) {
0096         // NOLINTNEXTLINE(*-reinterpret-cast,readability-identifier-length)
0097         const int8_t n = *reinterpret_cast<const int8_t *>(src);
0098         src += 1;
0099 
0100         if (n >= 0) { // copy next n+1 chars
0101             const int bytes = 1 + n;
0102             if (src + bytes > input.cend()) {
0103                 errFile << "Input buffer exhausted in replicate of" << bytes << "chars, left" << (input.cend() - src);
0104                 return {};
0105             }
0106             if (dst + bytes > output.end()) {
0107                 errFile << "Overrun in packbits replicate of" << bytes << "chars, left" << (output.end() - dst);
0108                 return {};
0109             }
0110             std::copy_n(src, bytes, dst);
0111             src += bytes;
0112             dst += bytes;
0113         } else if (n >= -127 && n <= -1) { // replicate next char -n+1 times
0114             const int bytes = 1 - n;
0115             if (src >= input.cend()) {
0116                 errFile << "Input buffer exhausted in copy";
0117                 return {};
0118             }
0119             if (dst + bytes > output.end()) {
0120                 errFile << "Output buffer exhausted in copy of" << bytes << "chars, left" << (output.end() - dst);
0121                 return {};
0122             }
0123             const auto byte = *src;
0124             std::fill_n(dst, bytes, byte);
0125             src += 1;
0126             dst += bytes;
0127         } else if (n == -128) {
0128             continue;
0129         }
0130     }
0131 
0132     if (dst < output.end()) {
0133         errFile << "Packbits decode - unpack left" << (output.end() - dst);
0134         std::fill(dst, output.end(), 0);
0135     }
0136 
0137     // If the input line was odd width, there's a padding byte
0138     if (src + 1 < input.cend()) {
0139         QByteArray leftovers;
0140         leftovers.resize(static_cast<int>(input.cend() - src));
0141         std::copy(src, input.cend(), leftovers.begin());
0142         errFile << "Packbits decode - pack left" << leftovers.size() << leftovers.toHex();
0143     }
0144 
0145     return output;
0146 }
0147 } // namespace KisRLE
0148 
0149 namespace KisZip
0150 {
0151 // Based on the reverse of psd_unzip_without_prediction
0152 int compress(const char *input, int unpacked_len, char *dst, int maxout)
0153 {
0154     z_stream stream{};
0155     int state;
0156 
0157     stream.data_type = Z_BINARY;
0158     stream.next_in = const_cast<Bytef *>(reinterpret_cast<const Bytef *>(input));
0159     stream.avail_in = static_cast<uInt>(unpacked_len);
0160     stream.next_out = reinterpret_cast<Bytef *>(dst);
0161     stream.avail_out = static_cast<uInt>(maxout);
0162 
0163     dbgFile << "Expected unpacked length:" << unpacked_len << ", maxout:" << maxout;
0164 
0165     if (deflateInit(&stream, -1) != Z_OK) {
0166         dbgFile << "Failed deflate initialization";
0167         return 0;
0168     }
0169 
0170     int flush = Z_PARTIAL_FLUSH;
0171 
0172     do {
0173         state = deflate(&stream, flush);
0174         if (state == Z_STREAM_END) {
0175             dbgFile << "Finished deflating";
0176             flush = Z_FINISH;
0177         } else if (state != Z_OK) {
0178             dbgFile << "Error deflating" << state << stream.msg;
0179             break;
0180         }
0181     } while (stream.avail_in > 0);
0182 
0183     if (state != Z_OK || stream.avail_in > 0) {
0184         dbgFile << "Failed deflating" << state << stream.msg;
0185         return 0;
0186     }
0187 
0188     dbgFile << "Success, deflated size:" << stream.total_out;
0189 
0190     return static_cast<int>(stream.total_out);
0191 }
0192 
0193 QByteArray compress(const QByteArray &data)
0194 {
0195     QByteArray output(data.length() * 4, '\0');
0196     const int result = KisZip::compress(data.constData(), data.size(), output.data(), output.size());
0197     output.resize(result);
0198     return output;
0199 }
0200 
0201 /**********************************************************************/
0202 /* Two functions copied from the abandoned PSDParse library (GPL)     */
0203 /* See: http://www.telegraphics.com.au/svn/psdparse/trunk/psd_zip.c   */
0204 /* Created by Patrick in 2007.02.02, libpsd@graphest.com              */
0205 /* Modifications by Toby Thain <toby@telegraphics.com.au>             */
0206 /* Refactored by L. E. Segovia <amy@amyspark.me>, 2021.06.30          */
0207 /**********************************************************************/
0208 int psd_unzip_without_prediction(const char *src, int packed_len, char *dst, int unpacked_len)
0209 {
0210     z_stream stream{};
0211     int state;
0212 
0213     stream.data_type = Z_BINARY;
0214     stream.next_in = const_cast<Bytef *>(reinterpret_cast<const Bytef *>(src));
0215     stream.avail_in = static_cast<uInt>(packed_len);
0216     stream.next_out = reinterpret_cast<Bytef *>(dst);
0217     stream.avail_out = static_cast<uInt>(unpacked_len);
0218 
0219     if (inflateInit(&stream) != Z_OK)
0220         return 0;
0221 
0222     int flush = Z_PARTIAL_FLUSH;
0223 
0224     do {
0225         state = inflate(&stream, flush);
0226         if (state == Z_STREAM_END) {
0227             dbgFile << "Finished inflating";
0228             break;
0229         } else if (state == Z_DATA_ERROR) {
0230             dbgFile << "Error inflating" << state << stream.msg;
0231             if (inflateSync(&stream) != Z_OK)
0232                 return 0;
0233             continue;
0234         }
0235     } while (stream.avail_out > 0);
0236 
0237     if ((state != Z_STREAM_END && state != Z_OK) || stream.avail_out > 0) {
0238         dbgFile << "Failed inflating" << state << stream.msg;
0239         return 0;
0240     }
0241 
0242     return static_cast<int>(stream.total_out);
0243 }
0244 
0245 template<typename T>
0246 inline void psd_unzip_with_prediction(QByteArray &dst_buf, int row_size);
0247 
0248 template<>
0249 inline void psd_unzip_with_prediction<uint8_t>(QByteArray &dst_buf, const int row_size)
0250 {
0251     auto *buf = reinterpret_cast<uint8_t *>(dst_buf.data());
0252     int len = 0;
0253     int dst_len = dst_buf.size();
0254 
0255     while (dst_len > 0) {
0256         len = row_size;
0257         while (--len) {
0258             *(buf + 1) += *buf;
0259             buf++;
0260         }
0261         buf++;
0262         dst_len -= row_size;
0263     }
0264 }
0265 
0266 template<>
0267 inline void psd_unzip_with_prediction<uint16_t>(QByteArray &dst_buf, const int row_size)
0268 {
0269     auto *buf = reinterpret_cast<uint8_t *>(dst_buf.data());
0270     int len = 0;
0271     int dst_len = dst_buf.size();
0272 
0273     while (dst_len > 0) {
0274         len = row_size;
0275         while (--len) {
0276             buf[2] += buf[0] + ((buf[1] + buf[3]) >> 8);
0277             buf[3] += buf[1];
0278             buf += 2;
0279         }
0280         buf += 2;
0281         dst_len -= row_size * 2;
0282     }
0283 }
0284 
0285 QByteArray psd_unzip_with_prediction(const QByteArray &src, int dst_len, int row_size, int color_depth)
0286 {
0287     QByteArray dst_buf = Compression::uncompress(dst_len, src, psd_compression_type::ZIP);
0288 
0289     if (dst_buf.size() == 0)
0290         return {};
0291 
0292     if (color_depth == 32) {
0293         // Placeholded for future implementation.
0294         errKrita << "Unsupported bit depth for prediction";
0295         return {};
0296     } else if (color_depth == 16) {
0297         psd_unzip_with_prediction<quint16>(dst_buf, row_size);
0298     } else {
0299         psd_unzip_with_prediction<quint8>(dst_buf, row_size);
0300     }
0301 
0302     return dst_buf;
0303 }
0304 
0305 /**********************************************************************/
0306 /* End of third party block                                           */
0307 /**********************************************************************/
0308 
0309 template<typename T>
0310 inline void psd_zip_with_prediction(QByteArray &dst_buf, int row_size);
0311 
0312 template<>
0313 inline void psd_zip_with_prediction<uint8_t>(QByteArray &dst_buf, const int row_size)
0314 {
0315     auto *buf = reinterpret_cast<uint8_t *>(dst_buf.data());
0316     int len = 0;
0317     int dst_len = dst_buf.size();
0318 
0319     while (dst_len > 0) {
0320         len = row_size;
0321         while (--len) {
0322             *(buf + 1) -= *buf;
0323             buf++;
0324         }
0325         buf++;
0326         dst_len -= row_size;
0327     }
0328 }
0329 
0330 template<>
0331 inline void psd_zip_with_prediction<uint16_t>(QByteArray &dst_buf, const int row_size)
0332 {
0333     auto *buf = reinterpret_cast<uint8_t *>(dst_buf.data());
0334     int len = 0;
0335     int dst_len = dst_buf.size();
0336 
0337     while (dst_len > 0) {
0338         len = row_size;
0339         while (--len) {
0340             buf[2] -= buf[0] + ((buf[1] + buf[3]) >> 8);
0341             buf[3] -= buf[1];
0342             buf += 2;
0343         }
0344         buf += 2;
0345         dst_len -= row_size * 2;
0346     }
0347 }
0348 
0349 QByteArray psd_zip_with_prediction(const QByteArray &src, int row_size, int color_depth)
0350 {
0351     QByteArray dst_buf(src);
0352     if (color_depth == 32) {
0353         // Placeholded for future implementation.
0354         errKrita << "Unsupported bit depth for prediction";
0355         return {};
0356     } else if (color_depth == 16) {
0357         psd_zip_with_prediction<quint16>(dst_buf, row_size);
0358     } else {
0359         psd_zip_with_prediction<quint8>(dst_buf, row_size);
0360     }
0361 
0362     return Compression::compress(dst_buf, psd_compression_type::ZIP);
0363 }
0364 
0365 QByteArray decompress(const QByteArray &data, int expected_length)
0366 {
0367     QByteArray output(expected_length, '\0');
0368     const int result = psd_unzip_without_prediction(data.constData(), data.size(), output.data(), expected_length);
0369     if (result == 0)
0370         return QByteArray();
0371     else
0372         return output;
0373 }
0374 } // namespace KisZip
0375 
0376 QByteArray Compression::uncompress(int unpacked_len, QByteArray bytes, psd_compression_type compressionType, int row_size, int color_depth)
0377 {
0378     if (bytes.size() < 1)
0379         return QByteArray();
0380 
0381     switch (compressionType) {
0382     case Uncompressed:
0383         return bytes;
0384     case RLE:
0385         return KisRLE::decompress(bytes, unpacked_len);
0386     case ZIP:
0387         return KisZip::decompress(bytes, unpacked_len);
0388     case ZIPWithPrediction:
0389         return KisZip::psd_unzip_with_prediction(bytes, unpacked_len, row_size, color_depth);
0390     default:
0391         qFatal("Cannot uncompress layer data: invalid compression type");
0392     }
0393 
0394     return QByteArray();
0395 }
0396 
0397 QByteArray Compression::compress(QByteArray bytes, psd_compression_type compressionType, int row_size, int color_depth)
0398 {
0399     if (bytes.size() < 1)
0400         return QByteArray();
0401 
0402     switch (compressionType) {
0403     case Uncompressed:
0404         return bytes;
0405     case RLE:
0406         return KisRLE::compress(bytes);
0407     case ZIP:
0408         return KisZip::compress(bytes);
0409     case ZIPWithPrediction:
0410         return KisZip::psd_zip_with_prediction(bytes, row_size, color_depth);
0411     default:
0412         qFatal("Cannot compress layer data: invalid compression type");
0413     }
0414 
0415     return QByteArray();
0416 }