Krita Source Code Documentation
Loading...
Searching...
No Matches
kis_asl_writer_utils.h
Go to the documentation of this file.
1/*
2 * SPDX-FileCopyrightText: 2015 Dmitry Kazakov <dimula73@gmail.com>
3 * SPDX-FileCopyrightText: 2021 L. E. Segovia <amy@amyspark.me>
4 *
5 * SPDX-License-Identifier: GPL-2.0-or-later
6 */
7
8#ifndef __KIS_ASL_WRITER_UTILS_H
9#define __KIS_ASL_WRITER_UTILS_H
10
11#include "kritapsdutils_export.h"
12
13#include <stdexcept>
14#include <string>
15
16#include <QIODevice>
17#include <QUuid>
18
19#include <kis_debug.h>
20#include <resources/KoPattern.h>
21
22#include "psd.h"
23#include "psd_utils.h"
24
26{
30struct KRITAPSDUTILS_EXPORT ASLWriteException : public std::runtime_error {
31 ASLWriteException(const QString &msg)
32 : std::runtime_error(msg.toLatin1().data())
33 {
34 }
35};
36
37}
38
39#define SAFE_WRITE_EX(byteOrder, device, varname) \
40 if (!psdwrite<byteOrder>(device, varname)) { \
41 QString msg = QString("Failed to write \'%1\' tag!").arg(#varname); \
42 throw KisAslWriterUtils::ASLWriteException(msg); \
43 }
44
45namespace KisAslWriterUtils
46{
47// XXX: rect uses variable-sized type, is this correct?
48template<psd_byte_order byteOrder>
49inline void writeRect(const QRect &rect, QIODevice &device)
50{
51 {
52 const qint32 rectY0 = static_cast<qint32>(rect.y());
53 SAFE_WRITE_EX(byteOrder, device, rectY0);
54 }
55 {
56 const qint32 rectX0 = static_cast<qint32>(rect.x());
57 SAFE_WRITE_EX(byteOrder, device, rectX0);
58 }
59 {
60 const qint32 rectY1 = static_cast<qint32>(rect.y() + rect.height());
61 SAFE_WRITE_EX(byteOrder, device, rectY1);
62 }
63 {
64 const qint32 rectX1 = static_cast<qint32>(rect.x() + rect.width());
65 SAFE_WRITE_EX(byteOrder, device, rectX1);
66 }
67}
68
69template<psd_byte_order byteOrder>
70inline void writeUnicodeString(const QString &value, QIODevice &device)
71{
72 const quint32 len = static_cast<quint32>(value.length() + 1);
73 SAFE_WRITE_EX(byteOrder, device, len);
74
75 const quint16 *ptr = value.utf16();
76 for (quint32 i = 0; i < len; i++) {
77 SAFE_WRITE_EX(byteOrder, device, ptr[i]);
78 }
79}
80
81template<psd_byte_order byteOrder>
82inline void writeVarString(const QString &value, QIODevice &device)
83{
84 const quint32 lenTag = static_cast<quint32>(value.length() != 4 ? value.length() : 0);
85 SAFE_WRITE_EX(byteOrder, device, lenTag);
86
87 if (!device.write(value.toLatin1().data(), value.length())) {
88 warnKrita << "WARNING: ASL: Failed to write ASL string" << ppVar(value);
89 return;
90 }
91}
92
93template<psd_byte_order byteOrder>
94inline void writePascalString(const QString &value, QIODevice &device)
95{
96 KIS_ASSERT_RECOVER_RETURN(value.length() < 256);
97 KIS_ASSERT_RECOVER_RETURN(value.length() >= 0);
98 const quint8 lenTag = static_cast<quint8>(value.length());
99 SAFE_WRITE_EX(byteOrder, device, lenTag);
100
101 if (!device.write(value.toLatin1().data(), value.length())) {
102 warnKrita << "WARNING: ASL: Failed to write ASL string" << ppVar(value);
103 return;
104 }
105}
106
107template<psd_byte_order byteOrder>
108inline void writeFixedString(const QString &value, QIODevice &device)
109{
110 KIS_ASSERT_RECOVER_RETURN(value.length() == 4);
111
112 QByteArray data = value.toLatin1();
113
114 if (byteOrder == psd_byte_order::psdLittleEndian) {
115 std::reverse(data.begin(), data.end());
116 }
117
118 if (!device.write(data.data(), value.length())) {
119 warnKrita << "WARNING: ASL: Failed to write ASL string" << ppVar(value);
120 return;
121 }
122}
123
124// Write UUID fetched from the file name or generate
125template<psd_byte_order byteOrder = psd_byte_order::psdBigEndian>
126inline QString getPatternUuidLazy(const KoPatternSP pattern)
127{
128 QUuid uuid;
129 QString patternFileName = pattern->filename();
130
131 if (patternFileName.endsWith(".pat", Qt::CaseInsensitive)) {
132 QString strUuid = patternFileName.left(patternFileName.size() - 4);
133
134 uuid = QUuid(strUuid);
135 }
136
137 if (uuid.isNull()) {
138 warnKrita << "WARNING: Saved pattern doesn't have a UUID, generating...";
139 warnKrita << ppVar(patternFileName) << ppVar(pattern->name());
140 uuid = QUuid::createUuid();
141 }
142
143 return uuid.toString().mid(1, 36);
144}
145
153inline qint64 alignOffsetCeil(qint64 pos, qint64 alignment)
154{
155 qint64 mask = alignment - 1;
156 return (pos + mask) & ~mask;
157}
158
159template<class OffsetType, psd_byte_order byteOrder>
161{
162public:
163 OffsetStreamPusher(QIODevice &device, qint64 alignOnExit = 0, qint64 externalSizeTagOffset = -1)
164 : m_device(device)
165 , m_alignOnExit(alignOnExit)
166 , m_externalSizeTagOffset(externalSizeTagOffset)
167 {
169
170 if (externalSizeTagOffset < 0) {
171 const OffsetType fakeObjectSize = OffsetType(0xdeadbeef);
172 SAFE_WRITE_EX(byteOrder, m_device, fakeObjectSize);
173 }
174 }
175
177 {
178 try {
179 if (m_alignOnExit) {
180 qint64 currentPos = m_device.pos();
181 const qint64 alignedPos = alignOffsetCeil(currentPos, m_alignOnExit);
182
183 for (; currentPos < alignedPos; currentPos++) {
184 quint8 padding = 0;
185 SAFE_WRITE_EX(byteOrder, m_device, padding);
186 }
187 }
188
189 const qint64 currentPos = m_device.pos();
190
191 qint64 writtenDataSize = 0;
192 qint64 sizeFiledOffset = 0;
193
194 if (m_externalSizeTagOffset >= 0) {
195 writtenDataSize = currentPos - m_chunkStartPos;
196 sizeFiledOffset = m_externalSizeTagOffset;
197 } else {
198 writtenDataSize = currentPos - m_chunkStartPos - sizeof(OffsetType);
199 sizeFiledOffset = m_chunkStartPos;
200 }
201
202 m_device.seek(sizeFiledOffset);
203 const OffsetType realObjectSize = writtenDataSize;
204 SAFE_WRITE_EX(byteOrder, m_device, realObjectSize);
205 m_device.seek(currentPos);
206 } catch (ASLWriteException &e) {
207 warnKrita << PREPEND_METHOD(e.what());
208 }
209 }
210
211private:
213 QIODevice &m_device;
216};
217
218}
219
220#endif /* __KIS_ASL_WRITER_UTILS_H */
float value(const T *src, size_t ch)
OffsetStreamPusher(QIODevice &device, qint64 alignOnExit=0, qint64 externalSizeTagOffset=-1)
#define SAFE_WRITE_EX(byteOrder, device, varname)
#define KIS_ASSERT_RECOVER_RETURN(cond)
Definition kis_assert.h:75
#define PREPEND_METHOD(msg)
Definition kis_debug.h:172
#define warnKrita
Definition kis_debug.h:87
#define ppVar(var)
Definition kis_debug.h:155
void writeVarString(const QString &value, QIODevice &device)
void writePascalString(const QString &value, QIODevice &device)
void writeFixedString(const QString &value, QIODevice &device)
void writeUnicodeString(const QString &value, QIODevice &device)
void writeRect(const QRect &rect, QIODevice &device)
QString getPatternUuidLazy(const KoPatternSP pattern)
qint64 alignOffsetCeil(qint64 pos, qint64 alignment)