Qt
Internal/Contributor docs for the Qt SDK. Note: These are NOT official API docs; those are found at https://doc.qt.io/
Toggle main menu visibility
Loading...
Searching...
No Matches
qxbmhandler.cpp
Go to the documentation of this file.
1
// Copyright (C) 2016 The Qt Company Ltd.
2
// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
3
// Qt-Security score:critical reason:data-parser
4
5
#
include
<
qplatformdefs
.
h
>
6
#
include
"private/qxbmhandler_p.h"
7
8
#
ifndef
QT_NO_IMAGEFORMAT_XBM
9
10
#
include
<
qimage
.
h
>
11
#
include
<
qiodevice
.
h
>
12
#
include
<
qloggingcategory
.
h
>
13
#
include
<
qvariant
.
h
>
14
#
include
<
private
/
qtools_p
.
h
>
15
#
include
<
private
/
qimage_p
.
h
>
16
17
#
include
<
cstdio
>
18
19
#
include
<
stdio
.
h
>
20
21
QT_BEGIN_NAMESPACE
22
23
using
namespace
QtMiscUtils;
24
25
/*****************************************************************************
26
X bitmap image read/write functions
27
*****************************************************************************/
28
29
static
inline
int
hex2byte
(
char
*p)
30
{
31
return
QtMiscUtils::fromHex(p[0]) * 16 | QtMiscUtils::fromHex(p[1]);
32
}
33
34
static
bool
read_xbm_header
(QIODevice *device,
int
& w,
int
& h)
35
{
36
const
int
buflen = 300;
37
const
int
maxlen = 4096;
38
char
buf[buflen + 1];
39
40
qint64 readBytes = 0;
41
qint64 totalReadBytes = 0;
42
43
buf[0] =
'\0'
;
44
45
// skip initial comment, if any
46
while
(buf[0] !=
'#'
) {
47
readBytes = device->readLine(buf, buflen);
48
49
// if readBytes >= buflen, it's very probably not a C file
50
if
(readBytes <= 0 || readBytes >= buflen -1)
51
return
false
;
52
53
// limit xbm headers to the first 4k in the file to prevent
54
// excessive reads on non-xbm files
55
totalReadBytes += readBytes;
56
if
(totalReadBytes >= maxlen)
57
return
false
;
58
}
59
60
auto
parseDefine = [] (
const
char
*buf,
int
len) ->
int
{
61
auto
checkChar = [] (
char
ch) ->
bool
{
62
return
isAsciiLetterOrNumber(ch)
63
|| ch ==
'_'
|| ch ==
'.'
;
64
};
65
auto
isAsciiSpace = [] (
char
ch) ->
bool
{
66
return
ch ==
' '
|| ch ==
'\t'
;
67
};
68
const
char
define[] =
"#define"
;
69
constexpr
size_t defineLen =
sizeof
(define) - 1;
70
if
(strncmp(buf, define, defineLen) != 0)
71
return
0;
72
int
index = defineLen;
73
while
(buf[index] && isAsciiSpace(buf[index]))
74
++index;
75
while
(buf[index] && checkChar(buf[index]))
76
++index;
77
while
(buf[index] && isAsciiSpace(buf[index]))
78
++index;
79
80
return
QByteArray(buf + index, len - index).toInt();
81
};
82
83
84
// "#define .._width <num>"
85
w = parseDefine(buf, readBytes - 1);
86
87
readBytes = device->readLine(buf, buflen);
88
// "#define .._height <num>"
89
h = parseDefine(buf, readBytes - 1);
90
91
// format error
92
if
(w <= 0 || w > 32767 || h <= 0 || h > 32767)
93
return
false
;
94
95
return
true
;
96
}
97
98
static
bool
read_xbm_body
(QIODevice *device,
int
w,
int
h, QImage *outImage)
99
{
100
const
int
buflen = 300;
101
char
buf[buflen + 1];
102
103
qint64 readBytes = 0;
104
105
char
*p;
106
107
// scan for database
108
do
{
109
if
((readBytes = device->readLine(buf, buflen)) <= 0) {
110
// end of file
111
return
false
;
112
}
113
114
buf[readBytes] =
'\0'
;
115
p = strstr(buf,
"0x"
);
116
}
while
(!p);
117
118
if
(!QImageIOHandler::allocateImage(QSize(w, h), QImage::Format_MonoLSB, outImage))
119
return
false
;
120
121
outImage->fill(Qt::color0);
// in case the image data does not cover the full image
122
123
outImage->setColorCount(2);
124
outImage->setColor(0, qRgb(255,255,255));
// white
125
outImage->setColor(1, qRgb(0,0,0));
// black
126
127
int
x = 0, y = 0;
128
uchar *b = outImage->scanLine(0);
129
w = (w+7)/8;
// byte width
130
131
while
(y < h) {
// for all encoded bytes...
132
if
(p && p < (buf + readBytes - 3)) {
// p = "0x.."
133
const
int
byte =
hex2byte
(
p + 2
)
;
134
if
(byte < 0)
// non-hex char encountered
135
return
false
;
136
*b++ = byte;
137
p += 2;
138
if
(++x == w && ++y < h) {
139
b = outImage->scanLine(y);
140
x = 0;
141
}
142
p = strstr(p,
"0x"
);
143
}
else
{
// read another line
144
if
((readBytes = device->readLine(buf,buflen)) <= 0)
// EOF ==> truncated image
145
break
;
146
buf[readBytes] =
'\0'
;
147
p = strstr(buf,
"0x"
);
148
}
149
}
150
151
return
true
;
152
}
153
154
static
bool
read_xbm_image
(QIODevice *device, QImage *outImage)
155
{
156
int
w = 0, h = 0;
157
if
(!
read_xbm_header
(
device
,
w
,
h
)
)
158
return
false
;
159
return
read_xbm_body(device, w, h, outImage);
160
}
161
162
static
bool
write_xbm_image
(
const
QImage &sourceImage, QIODevice *device,
const
QString &fileName)
163
{
164
QImage
image = sourceImage;
165
int
w = image.width();
166
int
h = image.height();
167
int
i;
168
const
QByteArray
s = fileName.toUtf8();
// get file base name
169
const
auto
msize = s.size() + 100;
170
char
*buf =
new
char
[msize];
171
172
std::snprintf(buf, msize,
"#define %s_width %d\n"
, s.data(), w);
173
device->write(buf, qstrlen(buf));
174
std::snprintf(buf, msize,
"#define %s_height %d\n"
, s.data(), h);
175
device->write(buf, qstrlen(buf));
176
std::snprintf(buf, msize,
"static char %s_bits[] = {\n "
, s.data());
177
device->write(buf, qstrlen(buf));
178
179
if
(image.format() != QImage::Format_MonoLSB)
180
image = image.convertToFormat(QImage::Format_MonoLSB);
181
182
bool
invert = qGray(image.color(0)) < qGray(image.color(1));
183
char
hexrep[16];
184
for
(i=0; i<10; i++)
185
hexrep[i] =
'0'
+ i;
186
for
(i=10; i<16; i++)
187
hexrep[i] =
'a'
-10 + i;
188
if
(invert) {
189
char
t;
190
for
(i=0; i<8; i++) {
191
t = hexrep[15-i];
192
hexrep[15-i] = hexrep[i];
193
hexrep[i] = t;
194
}
195
}
196
int
bcnt = 0;
197
char
*p = buf;
198
int
bpl = (w+7)/8;
199
for
(
int
y = 0; y < h; ++y) {
200
const
uchar *b = image.constScanLine(y);
201
for
(i = 0; i < bpl; ++i) {
202
*p++ =
'0'
; *p++ =
'x'
;
203
*p++ = hexrep[*b >> 4];
204
*p++ = hexrep[*b++ & 0xf];
205
206
if
(i < bpl - 1 || y < h - 1) {
207
*p++ =
','
;
208
if
(++bcnt > 14) {
209
*p++ =
'\n'
;
210
*p++ =
' '
;
211
*p =
'\0'
;
212
if
((
int
)qstrlen(buf) != device->write(buf, qstrlen(buf))) {
213
delete
[] buf;
214
return
false
;
215
}
216
p = buf;
217
bcnt = 0;
218
}
219
}
220
}
221
}
222
#
ifdef
Q_CC_MSVC
223
strcpy_s(p,
sizeof
(
" };\n"
),
" };\n"
);
224
#
else
225
strcpy(p,
" };\n"
);
226
#
endif
227
if
((
int
)qstrlen(buf) != device->write(buf, qstrlen(buf))) {
228
delete
[] buf;
229
return
false
;
230
}
231
232
delete
[] buf;
233
return
true
;
234
}
235
236
QXbmHandler::QXbmHandler()
237
: state(Ready)
238
{
239
}
240
241
bool
QXbmHandler::readHeader()
242
{
243
state = Error;
244
if
(!read_xbm_header(device(), width, height))
245
return
false
;
246
state = ReadHeader;
247
return
true
;
248
}
249
250
bool
QXbmHandler::canRead()
const
251
{
252
if
(state == Ready && !canRead(device()))
253
return
false
;
254
255
if
(state != Error) {
256
setFormat(
"xbm"
);
257
return
true
;
258
}
259
260
return
false
;
261
}
262
263
bool
QXbmHandler::canRead(QIODevice *device)
264
{
265
if
(!device) {
266
qCWarning
(lcImageIo,
"QXbmHandler::canRead() called with no device"
);
267
return
false
;
268
}
269
270
// it's impossible to tell whether we can load an XBM or not when
271
// it's from a sequential device, as the only way to do it is to
272
// attempt to parse the whole image.
273
if
(device->isSequential())
274
return
false
;
275
276
QImage image;
277
qint64 oldPos = device->pos();
278
bool
success = read_xbm_image(device, &image);
279
device->seek(oldPos);
280
281
return
success;
282
}
283
284
bool
QXbmHandler::read(QImage *image)
285
{
286
if
(state == Error)
287
return
false
;
288
289
if
(state == Ready && !readHeader()) {
290
state = Error;
291
return
false
;
292
}
293
294
if
(!read_xbm_body(device(), width, height, image)) {
295
state = Error;
296
return
false
;
297
}
298
299
state = Ready;
300
return
true
;
301
}
302
303
bool
QXbmHandler::write(
const
QImage &image)
304
{
305
return
write_xbm_image(image, device(), fileName);
306
}
307
308
bool
QXbmHandler::supportsOption(ImageOption option)
const
309
{
310
return
option == Name
311
|| option == Size
312
|| option == ImageFormat;
313
}
314
315
QVariant QXbmHandler::option(ImageOption option)
const
316
{
317
if
(option == Name) {
318
return
fileName;
319
}
else
if
(option == Size) {
320
if
(state == Error)
321
return
QVariant();
322
if
(state == Ready && !
const_cast
<QXbmHandler*>(
this
)->readHeader())
323
return
QVariant();
324
return
QSize(width, height);
325
}
else
if
(option == ImageFormat) {
326
return
QImage::Format_MonoLSB;
327
}
328
return
QVariant();
329
}
330
331
void
QXbmHandler::setOption(ImageOption option,
const
QVariant &value)
332
{
333
if
(option == Name)
334
fileName = value.toString();
335
}
336
337
QT_END_NAMESPACE
338
339
#
endif
// QT_NO_IMAGEFORMAT_XBM
QByteArray::FromBase64Result
\inmodule QtCore
Definition
qbytearray.h:824
QImage
\inmodule QtGui
Definition
qimage.h:38
qCWarning
#define qCWarning(category,...)
Definition
qloggingcategory.h:164
write_xbm_image
static bool write_xbm_image(const QImage &sourceImage, QIODevice *device, const QString &fileName)
Definition
qxbmhandler.cpp:162
read_xbm_body
static bool read_xbm_body(QIODevice *device, int w, int h, QImage *outImage)
Definition
qxbmhandler.cpp:98
read_xbm_header
static bool read_xbm_header(QIODevice *device, int &w, int &h)
Definition
qxbmhandler.cpp:34
read_xbm_image
static bool read_xbm_image(QIODevice *device, QImage *outImage)
Definition
qxbmhandler.cpp:154
hex2byte
static int hex2byte(char *p)
Definition
qxbmhandler.cpp:29
qtbase
src
gui
image
qxbmhandler.cpp
Generated on
for Qt by
1.18.0