Coverage Report

Created: 2026-06-30 11:14

next uncovered line (L), next uncovered region (R), next uncovered branch (B)
/src/libreoffice/vcl/source/bitmap/dibtools.cxx
Line
Count
Source
1
/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
2
/*
3
 * This file is part of the LibreOffice project.
4
 *
5
 * This Source Code Form is subject to the terms of the Mozilla Public
6
 * License, v. 2.0. If a copy of the MPL was not distributed with this
7
 * file, You can obtain one at http://mozilla.org/MPL/2.0/.
8
 *
9
 * This file incorporates work covered by the following license notice:
10
 *
11
 *   Licensed to the Apache Software Foundation (ASF) under one or more
12
 *   contributor license agreements. See the NOTICE file distributed
13
 *   with this work for additional information regarding copyright
14
 *   ownership. The ASF licenses this file to you under the Apache
15
 *   License, Version 2.0 (the "License"); you may not use this file
16
 *   except in compliance with the License. You may obtain a copy of
17
 *   the License at http://www.apache.org/licenses/LICENSE-2.0 .
18
 */
19
20
#include <sal/config.h>
21
#include <sal/log.hxx>
22
23
#include <cassert>
24
25
#include <o3tl/safeint.hxx>
26
#include <vcl/dibtools.hxx>
27
#include <comphelper/fileformat.h>
28
#include <tools/zcodec.hxx>
29
#include <tools/stream.hxx>
30
#include <tools/fract.hxx>
31
#include <tools/helpers.hxx>
32
#include <tools/GenericTypeSerializer.hxx>
33
#include <tools/mapunit.hxx>
34
#include <comphelper/configuration.hxx>
35
#include <vcl/alpha.hxx>
36
#include <vcl/bitmap.hxx>
37
#include <vcl/outdev.hxx>
38
#include <vcl/BitmapWriteAccess.hxx>
39
#include <vcl/ColorMask.hxx>
40
#include <memory>
41
42
157k
#define DIBCOREHEADERSIZE       ( 12UL )
43
8.54k
#define DIBINFOHEADERSIZE       ( sizeof(DIBInfoHeader) )
44
89.3k
#define DIBV5HEADERSIZE         ( sizeof(DIBV5Header) )
45
46
// - DIBInfoHeader and DIBV5Header
47
48
typedef sal_Int32 FXPT2DOT30;
49
50
namespace
51
{
52
53
struct CIEXYZ
54
{
55
    FXPT2DOT30      aXyzX;
56
    FXPT2DOT30      aXyzY;
57
    FXPT2DOT30      aXyzZ;
58
59
    CIEXYZ()
60
339k
    :   aXyzX(0),
61
339k
        aXyzY(0),
62
339k
        aXyzZ(0)
63
339k
    {}
64
};
65
66
struct CIEXYZTriple
67
{
68
    CIEXYZ          aXyzRed;
69
    CIEXYZ          aXyzGreen;
70
    CIEXYZ          aXyzBlue;
71
72
    CIEXYZTriple()
73
113k
    {}
74
};
75
76
struct DIBInfoHeader
77
{
78
    sal_uInt32      nSize;
79
    sal_Int32       nWidth;
80
    sal_Int32       nHeight;
81
    sal_uInt16      nPlanes;
82
    sal_uInt16      nBitCount;
83
    sal_uInt32      nCompression;
84
    sal_uInt32      nSizeImage;
85
    sal_Int32       nXPelsPerMeter;
86
    sal_Int32       nYPelsPerMeter;
87
    sal_uInt32      nColsUsed;
88
    sal_uInt32      nColsImportant;
89
90
    DIBInfoHeader()
91
113k
    :   nSize(0),
92
113k
        nWidth(0),
93
113k
        nHeight(0),
94
113k
        nPlanes(0),
95
113k
        nBitCount(0),
96
113k
        nCompression(0),
97
113k
        nSizeImage(0),
98
113k
        nXPelsPerMeter(0),
99
113k
        nYPelsPerMeter(0),
100
113k
        nColsUsed(0),
101
113k
        nColsImportant(0)
102
113k
    {}
103
};
104
105
struct DIBV5Header : public DIBInfoHeader
106
{
107
    sal_uInt32      nV5RedMask;
108
    sal_uInt32      nV5GreenMask;
109
    sal_uInt32      nV5BlueMask;
110
    sal_uInt32      nV5AlphaMask;
111
    sal_uInt32      nV5CSType;
112
    CIEXYZTriple    aV5Endpoints;
113
    sal_uInt32      nV5GammaRed;
114
    sal_uInt32      nV5GammaGreen;
115
    sal_uInt32      nV5GammaBlue;
116
    sal_uInt32      nV5Intent;
117
    sal_uInt32      nV5ProfileData;
118
    sal_uInt32      nV5ProfileSize;
119
    sal_uInt32      nV5Reserved;
120
121
    DIBV5Header()
122
113k
    :   nV5RedMask(0),
123
113k
        nV5GreenMask(0),
124
113k
        nV5BlueMask(0),
125
113k
        nV5AlphaMask(0),
126
113k
        nV5CSType(0),
127
113k
        nV5GammaRed(0),
128
113k
        nV5GammaGreen(0),
129
113k
        nV5GammaBlue(0),
130
113k
        nV5Intent(0),
131
113k
        nV5ProfileData(0),
132
113k
        nV5ProfileSize(0),
133
113k
        nV5Reserved(0)
134
113k
    {}
135
};
136
137
vcl::PixelFormat lcl_convertToBPP(sal_uInt16 nCount)
138
59.9k
{
139
59.9k
    return (nCount <= 8) ? vcl::PixelFormat::N8_BPP :
140
59.9k
                           vcl::PixelFormat::N24_BPP;
141
59.9k
}
142
143
bool ImplReadDIBInfoHeader(SvStream& rIStm, DIBV5Header& rHeader, bool& bTopDown, bool bMSOFormat)
144
113k
{
145
113k
    if (rIStm.remainingSize() <= 4)
146
760
        return false;
147
    // BITMAPINFOHEADER or BITMAPCOREHEADER or BITMAPV5HEADER
148
112k
    sal_uInt64 const aStartPos(rIStm.Tell());
149
112k
    rIStm.ReadUInt32( rHeader.nSize );
150
151
    // BITMAPCOREHEADER
152
112k
    if ( rHeader.nSize == DIBCOREHEADERSIZE )
153
6.95k
    {
154
6.95k
        sal_Int16 nTmp16;
155
156
6.95k
        rIStm.ReadInt16( nTmp16 ); rHeader.nWidth = nTmp16;
157
6.95k
        rIStm.ReadInt16( nTmp16 ); rHeader.nHeight = nTmp16;
158
6.95k
        rIStm.ReadUInt16( rHeader.nPlanes );
159
6.95k
        rIStm.ReadUInt16( rHeader.nBitCount );
160
6.95k
    }
161
105k
    else if ( bMSOFormat && rHeader.nSize == DIBINFOHEADERSIZE )
162
20
    {
163
20
        sal_Int16 nTmp16(0);
164
20
        rIStm.ReadInt16(nTmp16);
165
20
        rHeader.nWidth = nTmp16;
166
20
        rIStm.ReadInt16(nTmp16);
167
20
        rHeader.nHeight = nTmp16;
168
20
        sal_uInt8 nTmp8(0);
169
20
        rIStm.ReadUChar(nTmp8);
170
20
        rHeader.nPlanes = nTmp8;
171
20
        rIStm.ReadUChar(nTmp8);
172
20
        rHeader.nBitCount = nTmp8;
173
20
        rIStm.ReadInt16(nTmp16);
174
20
        rHeader.nSizeImage = nTmp16;
175
20
        rIStm.ReadInt16(nTmp16);
176
20
        rHeader.nCompression = nTmp16;
177
20
        if ( !rHeader.nSizeImage ) // uncompressed?
178
20
            rHeader.nSizeImage = ((rHeader.nWidth * rHeader.nBitCount + 31) & ~31) / 8 * rHeader.nHeight;
179
20
        rIStm.ReadInt32( rHeader.nXPelsPerMeter );
180
20
        rIStm.ReadInt32( rHeader.nYPelsPerMeter );
181
20
        rIStm.ReadUInt32( rHeader.nColsUsed );
182
20
        rIStm.ReadUInt32( rHeader.nColsImportant );
183
20
    }
184
105k
    else
185
105k
    {
186
        // BITMAPCOREHEADER, BITMAPV5HEADER or unknown. Read as far as possible
187
105k
        std::size_t nUsed(sizeof(rHeader.nSize));
188
189
211k
        auto readUInt16 = [&nUsed, &rHeader, &rIStm](sal_uInt16 & v) {
190
211k
            if (nUsed < rHeader.nSize) {
191
207k
                rIStm.ReadUInt16(v);
192
207k
                nUsed += sizeof(v);
193
207k
            }
194
211k
        };
195
1.37M
        auto readInt32 = [&nUsed, &rHeader, &rIStm](sal_Int32 & v) {
196
1.37M
            if (nUsed < rHeader.nSize) {
197
617k
                rIStm.ReadInt32(v);
198
617k
                nUsed += sizeof(v);
199
617k
            }
200
1.37M
        };
201
1.68M
        auto readUInt32 = [&nUsed, &rHeader, &rIStm](sal_uInt32 & v) {
202
1.68M
            if (nUsed < rHeader.nSize) {
203
678k
                rIStm.ReadUInt32(v);
204
678k
                nUsed += sizeof(v);
205
678k
            }
206
1.68M
        };
207
208
        // read DIBInfoHeader entries
209
105k
        readInt32( rHeader.nWidth );
210
105k
        readInt32( rHeader.nHeight );
211
105k
        readUInt16( rHeader.nPlanes );
212
105k
        readUInt16( rHeader.nBitCount );
213
105k
        readUInt32( rHeader.nCompression );
214
105k
        readUInt32( rHeader.nSizeImage );
215
105k
        readInt32( rHeader.nXPelsPerMeter );
216
105k
        readInt32( rHeader.nYPelsPerMeter );
217
105k
        readUInt32( rHeader.nColsUsed );
218
105k
        readUInt32( rHeader.nColsImportant );
219
220
        // read DIBV5HEADER members
221
105k
        readUInt32( rHeader.nV5RedMask );
222
105k
        readUInt32( rHeader.nV5GreenMask );
223
105k
        readUInt32( rHeader.nV5BlueMask );
224
105k
        readUInt32( rHeader.nV5AlphaMask );
225
105k
        readUInt32( rHeader.nV5CSType );
226
227
        // read contained CIEXYZTriple's
228
105k
        readInt32( rHeader.aV5Endpoints.aXyzRed.aXyzX );
229
105k
        readInt32( rHeader.aV5Endpoints.aXyzRed.aXyzY );
230
105k
        readInt32( rHeader.aV5Endpoints.aXyzRed.aXyzZ );
231
105k
        readInt32( rHeader.aV5Endpoints.aXyzGreen.aXyzX );
232
105k
        readInt32( rHeader.aV5Endpoints.aXyzGreen.aXyzY );
233
105k
        readInt32( rHeader.aV5Endpoints.aXyzGreen.aXyzZ );
234
105k
        readInt32( rHeader.aV5Endpoints.aXyzBlue.aXyzX );
235
105k
        readInt32( rHeader.aV5Endpoints.aXyzBlue.aXyzY );
236
105k
        readInt32( rHeader.aV5Endpoints.aXyzBlue.aXyzZ );
237
238
105k
        readUInt32( rHeader.nV5GammaRed );
239
105k
        readUInt32( rHeader.nV5GammaGreen );
240
105k
        readUInt32( rHeader.nV5GammaBlue );
241
105k
        readUInt32( rHeader.nV5Intent );
242
105k
        readUInt32( rHeader.nV5ProfileData );
243
105k
        readUInt32( rHeader.nV5ProfileSize );
244
105k
        readUInt32( rHeader.nV5Reserved );
245
246
        // Read color mask. An additional 12 bytes of color bitfields follow the info header (WinBMPv3-NT)
247
105k
        sal_uInt32 nColorMask = 0;
248
105k
        if (BITFIELDS == rHeader.nCompression && DIBINFOHEADERSIZE == rHeader.nSize)
249
1.65k
        {
250
1.65k
            rIStm.ReadUInt32( rHeader.nV5RedMask );
251
1.65k
            rIStm.ReadUInt32( rHeader.nV5GreenMask );
252
1.65k
            rIStm.ReadUInt32( rHeader.nV5BlueMask );
253
1.65k
            nColorMask = 12;
254
1.65k
        }
255
256
        // seek to EndPos
257
105k
        if (!checkSeek(rIStm, aStartPos + rHeader.nSize + nColorMask))
258
11.3k
            return false;
259
105k
    }
260
261
101k
    if (!rIStm.good() || rHeader.nHeight == SAL_MIN_INT32)
262
325
        return false;
263
264
100k
    if ( rHeader.nHeight < 0 )
265
23.9k
    {
266
23.9k
        bTopDown = true;
267
23.9k
        rHeader.nHeight *= -1;
268
23.9k
    }
269
76.9k
    else
270
76.9k
    {
271
76.9k
        bTopDown = false;
272
76.9k
    }
273
274
100k
    if ( rHeader.nWidth < 0 || rHeader.nXPelsPerMeter < 0 || rHeader.nYPelsPerMeter < 0 )
275
2.49k
    {
276
2.49k
        rIStm.SetError( SVSTREAM_FILEFORMAT_ERROR );
277
2.49k
    }
278
279
    // #144105# protect a little against damaged files
280
100k
    assert(rHeader.nHeight >= 0);
281
100k
    if (rHeader.nHeight != 0 && rHeader.nWidth >= 0
282
97.7k
        && (rHeader.nSizeImage / 16 / static_cast<sal_uInt32>(rHeader.nHeight)
283
97.7k
            > o3tl::make_unsigned(rHeader.nWidth)))
284
39.3k
    {
285
39.3k
        rHeader.nSizeImage = 0;
286
39.3k
    }
287
288
289
100k
    if (rHeader.nPlanes != 1)
290
20.5k
        return false;
291
292
80.3k
    if (rHeader.nBitCount != 0 && rHeader.nBitCount != 1 &&
293
59.7k
        rHeader.nBitCount != 4 && rHeader.nBitCount != 8 &&
294
29.8k
        rHeader.nBitCount != 16 && rHeader.nBitCount != 24 &&
295
11.0k
        rHeader.nBitCount != 32)
296
623
    {
297
623
        return false;
298
623
    }
299
300
79.6k
    return rIStm.good();
301
80.3k
}
302
303
bool ImplReadDIBPalette(SvStream& rIStm, BitmapPalette& rPal, bool bQuad)
304
44.5k
{
305
44.5k
    const sal_uInt16    nColors = rPal.GetEntryCount();
306
44.5k
    const sal_uLong     nPalSize = nColors * ( bQuad ? 4UL : 3UL );
307
44.5k
    BitmapColor     aPalColor;
308
309
44.5k
    std::unique_ptr<sal_uInt8[]> pEntries(new sal_uInt8[ nPalSize ]);
310
44.5k
    if (rIStm.ReadBytes(pEntries.get(), nPalSize) != nPalSize)
311
7.93k
    {
312
7.93k
        return false;
313
7.93k
    }
314
315
36.6k
    sal_uInt8* pTmpEntry = pEntries.get();
316
2.18M
    for( sal_uInt16 i = 0; i < nColors; i++ )
317
2.15M
    {
318
2.15M
        aPalColor.SetBlue( *pTmpEntry++ );
319
2.15M
        aPalColor.SetGreen( *pTmpEntry++ );
320
2.15M
        aPalColor.SetRed( *pTmpEntry++ );
321
322
2.15M
        if( bQuad )
323
2.13M
            pTmpEntry++;
324
325
2.15M
        rPal[i] = aPalColor;
326
2.15M
    }
327
328
36.6k
    return rIStm.GetError() == ERRCODE_NONE;
329
44.5k
}
330
331
BitmapColor SanitizePaletteIndex(sal_uInt8 nIndex, const BitmapPalette& rPalette)
332
162M
{
333
162M
    const sal_uInt16 nPaletteEntryCount = rPalette.GetEntryCount();
334
162M
    if (nPaletteEntryCount && nIndex >= nPaletteEntryCount)
335
23.6M
    {
336
23.6M
        auto nSanitizedIndex = nIndex % nPaletteEntryCount;
337
23.6M
        SAL_WARN_IF(nIndex != nSanitizedIndex, "vcl", "invalid colormap index: "
338
23.6M
                    << static_cast<unsigned int>(nIndex) << ", colormap len is: "
339
23.6M
                    << nPaletteEntryCount);
340
23.6M
        nIndex = nSanitizedIndex;
341
23.6M
    }
342
162M
    return BitmapColor(nIndex);
343
162M
}
344
345
bool ImplDecodeRLE(sal_uInt8* pBuffer, DIBV5Header const & rHeader, BitmapWriteAccess& rAcc, const BitmapPalette& rPalette, bool bRLE4)
346
9.34k
{
347
9.34k
    Scanline pRLE = pBuffer;
348
9.34k
    Scanline pEndRLE = pBuffer + rHeader.nSizeImage;
349
9.34k
    tools::Long        nY = rHeader.nHeight - 1;
350
9.34k
    const sal_uLong nWidth = rAcc.Width();
351
9.34k
    sal_uLong       nCountByte;
352
9.34k
    sal_uLong       nRunByte;
353
9.34k
    sal_uLong       nX = 0;
354
9.34k
    sal_uInt8       cTmp;
355
9.34k
    bool        bEndDecoding = false;
356
357
9.34k
    do
358
418M
    {
359
418M
        if (pRLE == pEndRLE)
360
1.06k
            return false;
361
418M
        if( ( nCountByte = *pRLE++ ) == 0 )
362
46.8M
        {
363
46.8M
            if (pRLE == pEndRLE)
364
237
                return false;
365
46.8M
            nRunByte = *pRLE++;
366
367
46.8M
            if( nRunByte > 2 )
368
1.07M
            {
369
1.07M
                Scanline pScanline = rAcc.GetScanline(nY);
370
1.07M
                if( bRLE4 )
371
1.04M
                {
372
1.04M
                    nCountByte = nRunByte >> 1;
373
374
45.5M
                    for( sal_uLong i = 0; i < nCountByte; i++ )
375
44.5M
                    {
376
44.5M
                        if (pRLE == pEndRLE)
377
816
                            return false;
378
379
44.5M
                        cTmp = *pRLE++;
380
381
44.5M
                        if( nX < nWidth )
382
293k
                            rAcc.SetPixelOnData(pScanline, nX++, SanitizePaletteIndex(cTmp >> 4, rPalette));
383
384
44.5M
                        if( nX < nWidth )
385
292k
                            rAcc.SetPixelOnData(pScanline, nX++, SanitizePaletteIndex(cTmp & 0x0f, rPalette));
386
44.5M
                    }
387
388
1.04M
                    if( nRunByte & 1 )
389
1.02M
                    {
390
1.02M
                        if (pRLE == pEndRLE)
391
818
                            return false;
392
393
1.01M
                        if( nX < nWidth )
394
8.20k
                            rAcc.SetPixelOnData(pScanline, nX++, SanitizePaletteIndex(*pRLE >> 4, rPalette));
395
396
1.01M
                        pRLE++;
397
1.01M
                    }
398
399
1.04M
                    if( ( ( nRunByte + 1 ) >> 1 ) & 1 )
400
139k
                    {
401
139k
                        if (pRLE == pEndRLE)
402
23
                            return false;
403
404
139k
                        pRLE++;
405
139k
                    }
406
1.04M
                }
407
30.7k
                else
408
30.7k
                {
409
802k
                    for( sal_uLong i = 0; i < nRunByte; i++ )
410
772k
                    {
411
772k
                        if (pRLE == pEndRLE)
412
859
                            return false;
413
414
771k
                        if( nX < nWidth )
415
89.9k
                            rAcc.SetPixelOnData(pScanline, nX++, SanitizePaletteIndex(*pRLE, rPalette));
416
417
771k
                        pRLE++;
418
771k
                    }
419
420
29.8k
                    if( nRunByte & 1 )
421
26.7k
                    {
422
26.7k
                        if (pRLE == pEndRLE)
423
79
                            return false;
424
425
26.7k
                        pRLE++;
426
26.7k
                    }
427
29.8k
                }
428
1.07M
            }
429
45.7M
            else if( !nRunByte )
430
707k
            {
431
707k
                nY--;
432
707k
                nX = 0;
433
707k
            }
434
45.0M
            else if( nRunByte == 1 )
435
3.73k
                bEndDecoding = true;
436
45.0M
            else
437
45.0M
            {
438
45.0M
                if (pRLE == pEndRLE)
439
33
                    return false;
440
441
45.0M
                nX += *pRLE++;
442
443
45.0M
                if (pRLE == pEndRLE)
444
75
                    return false;
445
446
45.0M
                nY -= *pRLE++;
447
45.0M
            }
448
46.8M
        }
449
371M
        else
450
371M
        {
451
371M
            if (pRLE == pEndRLE)
452
391
                return false;
453
371M
            cTmp = *pRLE++;
454
455
371M
            Scanline pScanline = rAcc.GetScanline(nY);
456
371M
            if( bRLE4 )
457
160M
            {
458
160M
                nRunByte = nCountByte >> 1;
459
460
182M
                for (sal_uLong i = 0; i < nRunByte && nX < nWidth; ++i)
461
21.8M
                {
462
21.8M
                    rAcc.SetPixelOnData(pScanline, nX++, SanitizePaletteIndex(cTmp >> 4, rPalette));
463
21.8M
                    if( nX < nWidth )
464
21.3M
                        rAcc.SetPixelOnData(pScanline, nX++, SanitizePaletteIndex(cTmp & 0x0f, rPalette));
465
21.8M
                }
466
467
160M
                if( ( nCountByte & 1 ) && ( nX < nWidth ) )
468
240k
                    rAcc.SetPixelOnData(pScanline, nX++, SanitizePaletteIndex(cTmp >> 4, rPalette));
469
160M
            }
470
210M
            else
471
210M
            {
472
244M
                for (sal_uLong i = 0; i < nCountByte && nX < nWidth; ++i)
473
33.2M
                    rAcc.SetPixelOnData(pScanline, nX++, SanitizePaletteIndex(cTmp, rPalette));
474
210M
            }
475
371M
        }
476
418M
    }
477
418M
    while (!bEndDecoding && (nY >= 0));
478
479
4.94k
    return true;
480
9.34k
}
481
482
bool ImplReadDIBBits(SvStream& rIStm, DIBV5Header& rHeader, BitmapWriteAccess& rAcc, const BitmapPalette& rPalette, BitmapWriteAccess* pAccAlpha,
483
                     bool bTopDown, bool& rAlphaUsed, const sal_uInt64 nAlignedWidth)
484
59.9k
{
485
59.9k
    sal_uInt32 nRMask(( rHeader.nBitCount == 16 ) ? 0x00007c00UL : 0x00ff0000UL);
486
59.9k
    sal_uInt32 nGMask(( rHeader.nBitCount == 16 ) ? 0x000003e0UL : 0x0000ff00UL);
487
59.9k
    sal_uInt32 nBMask(( rHeader.nBitCount == 16 ) ? 0x0000001fUL : 0x000000ffUL);
488
59.9k
    bool bNative(false);
489
59.9k
    bool bTCMask(!pAccAlpha && ((16 == rHeader.nBitCount) || (32 == rHeader.nBitCount)));
490
59.9k
    bool bRLE((RLE_8 == rHeader.nCompression && 8 == rHeader.nBitCount) || (RLE_4 == rHeader.nCompression && 4 == rHeader.nBitCount));
491
492
    // Is native format?
493
59.9k
    switch(rAcc.GetScanlineFormat())
494
59.9k
    {
495
19.7k
        case ScanlineFormat::N24BitTcBgr:
496
19.7k
        {
497
            // we can't trust arbitrary-sourced index based formats to have correct indexes, so we exclude the pal formats
498
            // from raw read and force checking their colormap indexes
499
19.7k
            bNative = ( ( rAcc.IsBottomUp() != bTopDown ) && !bRLE && !bTCMask && ( rAcc.GetScanlineSize() == nAlignedWidth ) );
500
19.7k
            break;
501
0
        }
502
503
40.2k
        default:
504
40.2k
        {
505
40.2k
            break;
506
0
        }
507
59.9k
    }
508
509
    // Read data
510
59.9k
    if (bNative)
511
2.28k
    {
512
2.28k
        if (nAlignedWidth
513
2.28k
            > std::numeric_limits<std::size_t>::max() / rHeader.nHeight)
514
0
        {
515
0
            return false;
516
0
        }
517
2.28k
        std::size_t n = nAlignedWidth * rHeader.nHeight;
518
2.28k
        if (rIStm.ReadBytes(rAcc.GetBuffer(), n) != n)
519
0
        {
520
0
            return false;
521
0
        }
522
2.28k
    }
523
57.6k
    else
524
57.6k
    {
525
57.6k
        if (bTCMask && BITFIELDS == rHeader.nCompression)
526
7.19k
        {
527
7.19k
            nRMask = rHeader.nV5RedMask;
528
7.19k
            nGMask = rHeader.nV5GreenMask;
529
7.19k
            nBMask = rHeader.nV5BlueMask;
530
7.19k
        }
531
532
57.6k
        const tools::Long nWidth(rHeader.nWidth);
533
57.6k
        const tools::Long nHeight(rHeader.nHeight);
534
57.6k
        tools::Long nResult = 0;
535
57.6k
        if (comphelper::IsFuzzing() && (o3tl::checked_multiply(nWidth, nHeight, nResult) || nResult > 4000000))
536
86
            return false;
537
538
57.5k
        if (bRLE)
539
9.43k
        {
540
9.43k
            if(!rHeader.nSizeImage)
541
7.86k
            {
542
7.86k
                rHeader.nSizeImage = rIStm.remainingSize();
543
7.86k
            }
544
545
9.43k
            if (rHeader.nSizeImage > rIStm.remainingSize())
546
88
                return false;
547
9.34k
            std::vector<sal_uInt8> aBuffer(rHeader.nSizeImage);
548
9.34k
            if (rIStm.ReadBytes(aBuffer.data(), rHeader.nSizeImage) != rHeader.nSizeImage)
549
0
                return false;
550
9.34k
            if (!ImplDecodeRLE(aBuffer.data(), rHeader, rAcc, rPalette, RLE_4 == rHeader.nCompression))
551
4.39k
                return false;
552
9.34k
        }
553
48.1k
        else
554
48.1k
        {
555
48.1k
            if (nAlignedWidth > rIStm.remainingSize())
556
0
            {
557
                // ofz#11188 avoid timeout
558
                // all following paths will enter a case statement, and nCount
559
                // is always at least 1, so we can check here before allocation
560
                // if at least one row can be read
561
0
                return false;
562
0
            }
563
48.1k
            std::vector<sal_uInt8> aBuf(nAlignedWidth);
564
565
48.1k
            const tools::Long nI(bTopDown ? 1 : -1);
566
48.1k
            tools::Long nY(bTopDown ? 0 : nHeight - 1);
567
48.1k
            tools::Long nCount(nHeight);
568
569
48.1k
            switch(rHeader.nBitCount)
570
48.1k
            {
571
20.0k
                case 1:
572
20.0k
                {
573
1.58M
                    for( ; nCount--; nY += nI )
574
1.56M
                    {
575
1.56M
                        sal_uInt8 * pTmp = aBuf.data();
576
1.56M
                        if (rIStm.ReadBytes(pTmp, nAlignedWidth)
577
1.56M
                            != nAlignedWidth)
578
12
                        {
579
12
                            return false;
580
12
                        }
581
1.56M
                        sal_uInt8   cTmp = *pTmp++;
582
1.56M
                        Scanline pScanline = rAcc.GetScanline(nY);
583
67.2M
                        for( tools::Long nX = 0, nShift = 8; nX < nWidth; nX++ )
584
65.7M
                        {
585
65.7M
                            if( !nShift )
586
7.84M
                            {
587
7.84M
                                nShift = 8;
588
7.84M
                                cTmp = *pTmp++;
589
7.84M
                            }
590
591
65.7M
                            auto nIndex = (cTmp >> --nShift) & 1;
592
65.7M
                            rAcc.SetPixelOnData(pScanline, nX, SanitizePaletteIndex(nIndex, rPalette));
593
65.7M
                        }
594
1.56M
                    }
595
20.0k
                }
596
20.0k
                break;
597
598
20.0k
                case 4:
599
6.48k
                {
600
1.15M
                    for( ; nCount--; nY += nI )
601
1.14M
                    {
602
1.14M
                        sal_uInt8 * pTmp = aBuf.data();
603
1.14M
                        if (rIStm.ReadBytes(pTmp, nAlignedWidth)
604
1.14M
                            != nAlignedWidth)
605
0
                        {
606
0
                            return false;
607
0
                        }
608
1.14M
                        sal_uInt8   cTmp = *pTmp++;
609
1.14M
                        Scanline pScanline = rAcc.GetScanline(nY);
610
10.6M
                        for( tools::Long nX = 0, nShift = 2; nX < nWidth; nX++ )
611
9.54M
                        {
612
9.54M
                            if( !nShift )
613
3.64M
                            {
614
3.64M
                                nShift = 2;
615
3.64M
                                cTmp = *pTmp++;
616
3.64M
                            }
617
618
9.54M
                            auto nIndex = (cTmp >> ( --nShift << 2 ) ) & 0x0f;
619
9.54M
                            rAcc.SetPixelOnData(pScanline, nX, SanitizePaletteIndex(nIndex, rPalette));
620
9.54M
                        }
621
1.14M
                    }
622
6.48k
                }
623
6.48k
                break;
624
625
6.48k
                case 8:
626
4.18k
                {
627
2.93M
                    for( ; nCount--; nY += nI )
628
2.93M
                    {
629
2.93M
                        sal_uInt8 * pTmp = aBuf.data();
630
2.93M
                        if (rIStm.ReadBytes(pTmp, nAlignedWidth)
631
2.93M
                            != nAlignedWidth)
632
1
                        {
633
1
                            return false;
634
1
                        }
635
636
2.93M
                        Scanline pScanline = rAcc.GetScanline(nY);
637
12.2M
                        for( tools::Long nX = 0; nX < nWidth; nX++ )
638
9.28M
                        {
639
9.28M
                            auto nIndex = *pTmp++;
640
9.28M
                            rAcc.SetPixelOnData(pScanline, nX, SanitizePaletteIndex(nIndex, rPalette));
641
9.28M
                        }
642
2.93M
                    }
643
4.18k
                }
644
4.18k
                break;
645
646
10.1k
                case 16:
647
10.1k
                {
648
10.1k
                    ColorMaskElement aRedMask(nRMask);
649
10.1k
                    if (!aRedMask.CalcMaskShift())
650
41
                        return false;
651
10.1k
                    ColorMaskElement aGreenMask(nGMask);
652
10.1k
                    if (!aGreenMask.CalcMaskShift())
653
66
                        return false;
654
10.0k
                    ColorMaskElement aBlueMask(nBMask);
655
10.0k
                    if (!aBlueMask.CalcMaskShift())
656
17
                        return false;
657
658
10.0k
                    ColorMask   aMask(aRedMask, aGreenMask, aBlueMask);
659
10.0k
                    BitmapColor aColor;
660
661
2.87M
                    for( ; nCount--; nY += nI )
662
2.86M
                    {
663
2.86M
                        sal_uInt16 * pTmp16 = reinterpret_cast<sal_uInt16*>(aBuf.data());
664
2.86M
                        if (rIStm.ReadBytes(pTmp16, nAlignedWidth)
665
2.86M
                            != nAlignedWidth)
666
0
                        {
667
0
                            return false;
668
0
                        }
669
670
2.86M
                        Scanline pScanline = rAcc.GetScanline(nY);
671
9.36M
                        for( tools::Long nX = 0; nX < nWidth; nX++ )
672
6.49M
                        {
673
6.49M
                            aMask.GetColorFor16BitLSB( aColor, reinterpret_cast<sal_uInt8*>(pTmp16++) );
674
6.49M
                            rAcc.SetPixelOnData(pScanline, nX, aColor);
675
6.49M
                        }
676
2.86M
                    }
677
10.0k
                }
678
10.0k
                break;
679
680
10.0k
                case 24:
681
2.42k
                {
682
2.42k
                    BitmapColor aPixelColor;
683
684
3.70M
                    for( ; nCount--; nY += nI )
685
3.70M
                    {
686
3.70M
                        sal_uInt8* pTmp = aBuf.data();
687
3.70M
                        if (rIStm.ReadBytes(pTmp, nAlignedWidth)
688
3.70M
                            != nAlignedWidth)
689
0
                        {
690
0
                            return false;
691
0
                        }
692
693
3.70M
                        Scanline pScanline = rAcc.GetScanline(nY);
694
8.12M
                        for( tools::Long nX = 0; nX < nWidth; nX++ )
695
4.42M
                        {
696
4.42M
                            aPixelColor.SetBlue( *pTmp++ );
697
4.42M
                            aPixelColor.SetGreen( *pTmp++ );
698
4.42M
                            aPixelColor.SetRed( *pTmp++ );
699
4.42M
                            rAcc.SetPixelOnData(pScanline, nX, aPixelColor);
700
4.42M
                        }
701
3.70M
                    }
702
2.42k
                }
703
2.42k
                break;
704
705
4.80k
                case 32:
706
4.80k
                {
707
4.80k
                    ColorMaskElement aRedMask(nRMask);
708
4.80k
                    if (!aRedMask.CalcMaskShift())
709
67
                        return false;
710
4.74k
                    ColorMaskElement aGreenMask(nGMask);
711
4.74k
                    if (!aGreenMask.CalcMaskShift())
712
414
                        return false;
713
4.32k
                    ColorMaskElement aBlueMask(nBMask);
714
4.32k
                    if (!aBlueMask.CalcMaskShift())
715
7
                        return false;
716
4.31k
                    ColorMask aMask(aRedMask, aGreenMask, aBlueMask);
717
718
4.31k
                    BitmapColor aColor;
719
4.31k
                    sal_uInt32* pTmp32;
720
721
4.31k
                    if(pAccAlpha)
722
759
                    {
723
759
                        sal_uInt8 aAlpha;
724
725
13.0k
                        for( ; nCount--; nY += nI )
726
12.3k
                        {
727
12.3k
                            pTmp32 = reinterpret_cast<sal_uInt32*>(aBuf.data());
728
12.3k
                            if (rIStm.ReadBytes(pTmp32, nAlignedWidth)
729
12.3k
                                != nAlignedWidth)
730
0
                            {
731
0
                                return false;
732
0
                            }
733
734
12.3k
                            Scanline pScanline = rAcc.GetScanline(nY);
735
12.3k
                            Scanline pAlphaScanline = pAccAlpha->GetScanline(nY);
736
27.9k
                            for( tools::Long nX = 0; nX < nWidth; nX++ )
737
15.5k
                            {
738
15.5k
                                aMask.GetColorAndAlphaFor32Bit( aColor, aAlpha, reinterpret_cast<sal_uInt8*>(pTmp32++) );
739
15.5k
                                rAcc.SetPixelOnData(pScanline, nX, aColor);
740
15.5k
                                pAccAlpha->SetPixelOnData(pAlphaScanline, nX, BitmapColor(sal_uInt8(0xff) - aAlpha));
741
15.5k
                                rAlphaUsed |= 0xff != aAlpha;
742
15.5k
                            }
743
12.3k
                        }
744
759
                    }
745
3.56k
                    else
746
3.56k
                    {
747
174k
                        for( ; nCount--; nY += nI )
748
171k
                        {
749
171k
                            pTmp32 = reinterpret_cast<sal_uInt32*>(aBuf.data());
750
171k
                            if (rIStm.ReadBytes(pTmp32, nAlignedWidth)
751
171k
                                != nAlignedWidth)
752
0
                            {
753
0
                                return false;
754
0
                            }
755
756
171k
                            Scanline pScanline = rAcc.GetScanline(nY);
757
1.44M
                            for( tools::Long nX = 0; nX < nWidth; nX++ )
758
1.27M
                            {
759
1.27M
                                aMask.GetColorFor32Bit( aColor, reinterpret_cast<sal_uInt8*>(pTmp32++) );
760
1.27M
                                rAcc.SetPixelOnData(pScanline, nX, aColor);
761
1.27M
                            }
762
171k
                        }
763
3.56k
                    }
764
4.31k
                }
765
48.1k
            }
766
48.1k
        }
767
57.5k
    }
768
769
54.7k
    return rIStm.GetError() == ERRCODE_NONE;
770
59.9k
}
771
772
bool ImplReadDIBBody(SvStream& rIStm, Bitmap& rBmp, AlphaMask* pBmpAlpha, sal_uInt64 nOffset, bool bMSOFormat)
773
113k
{
774
113k
    DIBV5Header aHeader;
775
113k
    const sal_uInt64 nStmPos = rIStm.Tell();
776
113k
    bool bTopDown(false);
777
778
113k
    if (!ImplReadDIBInfoHeader(rIStm, aHeader, bTopDown, bMSOFormat))
779
34.1k
        return false;
780
781
    //BI_BITCOUNT_0 jpeg/png is unsupported
782
79.1k
    if (aHeader.nBitCount == 0)
783
189
        return false;
784
785
79.0k
    if (aHeader.nWidth <= 0 || aHeader.nHeight <= 0)
786
583
        return false;
787
788
    // In case ImplReadDIB() didn't call ImplReadDIBFileHeader() before
789
    // this method, nOffset is 0, that's OK.
790
78.4k
    if (nOffset && aHeader.nSize > nOffset)
791
419
    {
792
        // Header size claims to extend into the image data.
793
        // Looks like an error.
794
419
        return false;
795
419
    }
796
797
77.9k
    sal_uInt16 nColors(0);
798
77.9k
    SvStream* pIStm;
799
77.9k
    std::unique_ptr<SvMemoryStream> pMemStm;
800
77.9k
    std::vector<sal_uInt8> aData;
801
802
77.9k
    if (aHeader.nBitCount <= 8)
803
49.1k
    {
804
49.1k
        if(aHeader.nColsUsed)
805
16.6k
        {
806
16.6k
            nColors = static_cast<sal_uInt16>(aHeader.nColsUsed);
807
16.6k
        }
808
32.5k
        else
809
32.5k
        {
810
32.5k
            nColors = ( 1 << aHeader.nBitCount );
811
32.5k
        }
812
49.1k
    }
813
814
77.9k
    if (ZCOMPRESS == aHeader.nCompression)
815
24.3k
    {
816
24.3k
        sal_uInt32 nCodedSize(0);
817
24.3k
        sal_uInt32  nUncodedSize(0);
818
819
        // read coding information
820
24.3k
        rIStm.ReadUInt32( nCodedSize ).ReadUInt32( nUncodedSize ).ReadUInt32( aHeader.nCompression );
821
24.3k
        if (nCodedSize > rIStm.remainingSize())
822
17.0k
           nCodedSize = sal_uInt32(rIStm.remainingSize());
823
824
24.3k
        pMemStm.reset(new SvMemoryStream);
825
        // There may be bytes left over or the codec might read more than
826
        // necessary. So to preserve the correctness of the source stream copy
827
        // the encoded block
828
24.3k
        pMemStm->WriteStream(rIStm, nCodedSize);
829
24.3k
        pMemStm->Seek(0);
830
831
24.3k
        size_t nSizeInc(4 * pMemStm->remainingSize());
832
24.3k
        if (nUncodedSize < nSizeInc)
833
3.68k
            nSizeInc = nUncodedSize;
834
835
24.3k
        if (nSizeInc > 0)
836
23.0k
        {
837
            // decode buffer
838
23.0k
            ZCodec aCodec;
839
23.0k
            aCodec.BeginCompression();
840
23.0k
            aData.resize(nSizeInc);
841
23.0k
            size_t nDataPos(0);
842
222k
            while (nUncodedSize > nDataPos)
843
220k
            {
844
220k
                assert(aData.size() > nDataPos);
845
220k
                const size_t nToRead(std::min<size_t>(nUncodedSize - nDataPos, aData.size() - nDataPos));
846
220k
                assert(nToRead > 0);
847
220k
                assert(!aData.empty());
848
220k
                const tools::Long nRead = aCodec.Read(*pMemStm, aData.data() + nDataPos, sal_uInt32(nToRead));
849
220k
                if (nRead > 0)
850
199k
                {
851
199k
                    nDataPos += static_cast<tools::ULong>(nRead);
852
                    // we haven't read everything yet: resize buffer and continue
853
199k
                    if (nDataPos < nUncodedSize)
854
197k
                        aData.resize(aData.size() + nSizeInc);
855
199k
                }
856
21.2k
                else
857
21.2k
                {
858
21.2k
                    break;
859
21.2k
                }
860
220k
            }
861
            // truncate the data buffer to actually read size
862
23.0k
            aData.resize(nDataPos);
863
            // set the real uncoded size
864
23.0k
            nUncodedSize = sal_uInt32(aData.size());
865
23.0k
            aCodec.EndCompression();
866
23.0k
        }
867
868
24.3k
        if (aData.empty())
869
10.3k
        {
870
            // add something so we can take address of the first element
871
10.3k
            aData.resize(1);
872
10.3k
            nUncodedSize = 0;
873
10.3k
        }
874
875
        // set decoded bytes to memory stream,
876
        // from which we will read the bitmap data
877
24.3k
        pMemStm.reset(new SvMemoryStream);
878
24.3k
        pIStm = pMemStm.get();
879
24.3k
        assert(!aData.empty());
880
24.3k
        pMemStm->SetBuffer(aData.data(), nUncodedSize, nUncodedSize);
881
24.3k
        nOffset = 0;
882
24.3k
    }
883
53.6k
    else
884
53.6k
    {
885
53.6k
        pIStm = &rIStm;
886
53.6k
    }
887
888
    // read palette
889
77.9k
    BitmapPalette aPalette;
890
77.9k
    if (nColors)
891
44.5k
    {
892
44.5k
        aPalette.SetEntryCount(nColors);
893
44.5k
        ImplReadDIBPalette(*pIStm, aPalette, aHeader.nSize != DIBCOREHEADERSIZE);
894
44.5k
    }
895
896
77.9k
    if (pIStm->GetError())
897
0
        return false;
898
899
77.9k
    if (nOffset)
900
20.6k
    {
901
        // It is problematic to seek backwards. We are at the
902
        // end of BITMAPINFOHEADER or 12 bytes further in case
903
        // of WinBMPv3-NT format. It is possible to seek forward
904
        // though because a gap may be there.
905
20.6k
        sal_Int64 nSeekRel = nOffset - (pIStm->Tell() - nStmPos);
906
20.6k
        if (nSeekRel > 0)
907
12.7k
            pIStm->SeekRel(nSeekRel);
908
20.6k
    }
909
910
77.9k
    const sal_Int64 nBitsPerLine (static_cast<sal_Int64>(aHeader.nWidth) * static_cast<sal_Int64>(aHeader.nBitCount));
911
77.9k
    if (nBitsPerLine > SAL_MAX_UINT32)
912
9.05k
        return false;
913
68.9k
    const sal_uInt64 nAlignedWidth(AlignedWidth4Bytes(static_cast<sal_uLong>(nBitsPerLine)));
914
915
68.9k
    switch (aHeader.nCompression)
916
68.9k
    {
917
3.80k
        case RLE_8:
918
3.80k
        {
919
3.80k
            if (aHeader.nBitCount != 8)
920
68
                return false;
921
            // (partially) check the image dimensions to avoid potential large bitmap allocation if the input is damaged
922
3.73k
            sal_uInt64 nMaxWidth = pIStm->remainingSize();
923
3.73k
            nMaxWidth *= 256;   //assume generous compression ratio
924
3.73k
            nMaxWidth /= aHeader.nHeight;
925
3.73k
            if (nMaxWidth < o3tl::make_unsigned(aHeader.nWidth))
926
228
                return false;
927
3.50k
            break;
928
3.73k
        }
929
6.78k
        case RLE_4:
930
6.78k
        {
931
6.78k
            if (aHeader.nBitCount != 4)
932
490
                return false;
933
6.29k
            sal_uInt64 nMaxWidth = pIStm->remainingSize();
934
6.29k
            nMaxWidth *= 512;   //assume generous compression ratio
935
6.29k
            nMaxWidth /= aHeader.nHeight;
936
6.29k
            if (nMaxWidth < o3tl::make_unsigned(aHeader.nWidth))
937
262
                return false;
938
6.02k
            break;
939
6.29k
        }
940
15.0k
        default:
941
            // tdf#122958 invalid compression value used
942
15.0k
            if (aHeader.nCompression & 0x000F)
943
3.86k
            {
944
                // let's assume that there was an error in the generating application
945
                // and allow through as COMPRESS_NONE if the bottom byte is 0
946
3.86k
                SAL_WARN( "vcl", "bad bmp compression scheme: " << aHeader.nCompression << ", rejecting bmp");
947
3.86k
                return false;
948
3.86k
            }
949
11.2k
            else
950
15.0k
                SAL_WARN( "vcl", "bad bmp compression scheme: " << aHeader.nCompression << ", assuming meant to be COMPRESS_NONE");
951
11.2k
        [[fallthrough]];
952
19.5k
        case BITFIELDS:
953
20.9k
        case ZCOMPRESS:
954
54.4k
        case COMPRESS_NONE:
955
54.4k
        {
956
            // (partially) check the image dimensions to avoid potential large bitmap allocation if the input is damaged
957
54.4k
            sal_uInt64 nMaxWidth = pIStm->remainingSize();
958
54.4k
            nMaxWidth /= aHeader.nHeight;
959
54.4k
            if (nMaxWidth < nAlignedWidth)
960
4.09k
                return false;
961
50.4k
            break;
962
54.4k
        }
963
68.9k
    }
964
965
59.9k
    const Size aSizePixel(aHeader.nWidth, aHeader.nHeight);
966
59.9k
    AlphaMask aNewBmpAlpha;
967
59.9k
    BitmapScopedWriteAccess pAccAlpha;
968
59.9k
    bool bAlphaPossible(pBmpAlpha && aHeader.nBitCount == 32);
969
970
59.9k
    if (bAlphaPossible)
971
1.36k
    {
972
1.36k
        const bool bRedSet(0 != aHeader.nV5RedMask);
973
1.36k
        const bool bGreenSet(0 != aHeader.nV5GreenMask);
974
1.36k
        const bool bBlueSet(0 != aHeader.nV5BlueMask);
975
976
        // some clipboard entries have alpha mask on zero to say that there is
977
        // no alpha; do only use this when the other masks are set. The MS docu
978
        // says that masks are only to be set when bV5Compression is set to
979
        // BI_BITFIELDS, but there seem to exist a wild variety of usages...
980
1.36k
        if((bRedSet || bGreenSet || bBlueSet) && (0 == aHeader.nV5AlphaMask))
981
596
        {
982
596
            bAlphaPossible = false;
983
596
        }
984
1.36k
    }
985
986
59.9k
    if (bAlphaPossible)
987
764
    {
988
764
        aNewBmpAlpha = AlphaMask(aSizePixel);
989
764
        pAccAlpha = aNewBmpAlpha;
990
764
    }
991
992
59.9k
    vcl::PixelFormat ePixelFormat(lcl_convertToBPP(aHeader.nBitCount));
993
59.9k
    const BitmapPalette* pPal = &aPalette;
994
    //ofz#948 match the surrounding logic of case TransparentType::Bitmap of
995
    //ReadDIBBitmapEx but do it while reading for performance
996
997
59.9k
    Bitmap aNewBmp(aSizePixel, ePixelFormat, pPal);
998
59.9k
    BitmapScopedWriteAccess pAcc(aNewBmp);
999
59.9k
    if (!pAcc)
1000
17
        return false;
1001
59.9k
    if (pAcc->Width() != aHeader.nWidth || pAcc->Height() != aHeader.nHeight)
1002
0
    {
1003
0
        return false;
1004
0
    }
1005
1006
    // read bits
1007
59.9k
    bool bAlphaUsed(false);
1008
59.9k
    bool bRet = ImplReadDIBBits(*pIStm, aHeader, *pAcc, aPalette, pAccAlpha.get(), bTopDown, bAlphaUsed, nAlignedWidth);
1009
1010
59.9k
    if (bRet && aHeader.nXPelsPerMeter && aHeader.nYPelsPerMeter)
1011
18.0k
    {
1012
18.0k
        MapMode aMapMode(
1013
18.0k
            MapUnit::MapMM,
1014
18.0k
            Point(),
1015
18.0k
            1000.0 / aHeader.nXPelsPerMeter,
1016
18.0k
            1000.0 / aHeader.nYPelsPerMeter);
1017
1018
18.0k
        aNewBmp.SetPrefMapMode(aMapMode);
1019
18.0k
        aNewBmp.SetPrefSize(Size(aHeader.nWidth, aHeader.nHeight));
1020
18.0k
    }
1021
1022
59.9k
    pAcc.reset();
1023
1024
59.9k
    if (bAlphaPossible)
1025
764
    {
1026
764
        pAccAlpha.reset();
1027
1028
764
        if(!bAlphaUsed)
1029
5
        {
1030
5
            bAlphaPossible = false;
1031
5
        }
1032
764
    }
1033
1034
59.9k
    if (bRet)
1035
54.7k
    {
1036
54.7k
        rBmp = std::move(aNewBmp);
1037
1038
54.7k
        if(bAlphaPossible)
1039
759
        {
1040
759
            *pBmpAlpha = std::move(aNewBmpAlpha);
1041
759
        }
1042
54.7k
    }
1043
1044
59.9k
    return bRet;
1045
59.9k
}
1046
1047
bool ImplReadDIBFileHeader( SvStream& rIStm, sal_uLong& rOffset )
1048
87.4k
{
1049
87.4k
    bool bRet = false;
1050
1051
87.4k
    const sal_uInt64 nStreamLength = rIStm.TellEnd();
1052
1053
87.4k
    sal_uInt16 nTmp16 = 0;
1054
87.4k
    rIStm.ReadUInt16( nTmp16 );
1055
1056
87.4k
    if ( ( 0x4D42 == nTmp16 ) || ( 0x4142 == nTmp16 ) )
1057
87.0k
    {
1058
87.0k
        sal_uInt32 nTmp32(0);
1059
87.0k
        if ( 0x4142 == nTmp16 )
1060
81
        {
1061
81
            rIStm.SeekRel( 12 );
1062
81
            rIStm.ReadUInt16( nTmp16 );
1063
81
            rIStm.SeekRel( 8 );
1064
81
            rIStm.ReadUInt32( nTmp32 );
1065
81
            if (nTmp32 < 28)
1066
12
                rIStm.SetError(SVSTREAM_FILEFORMAT_ERROR);
1067
69
            else
1068
69
            {
1069
69
                rOffset = nTmp32 - 28;
1070
69
                bRet = ( 0x4D42 == nTmp16 );
1071
69
            }
1072
81
        }
1073
86.9k
        else // 0x4D42 == nTmp16, 'MB' from BITMAPFILEHEADER
1074
86.9k
        {
1075
86.9k
            rIStm.SeekRel( 8 );        // we are on bfSize member of BITMAPFILEHEADER, forward to bfOffBits
1076
86.9k
            rIStm.ReadUInt32( nTmp32 );            // read bfOffBits
1077
86.9k
            if (nTmp32 < 14)
1078
94
                rIStm.SetError(SVSTREAM_FILEFORMAT_ERROR);
1079
86.8k
            else
1080
86.8k
            {
1081
86.8k
                rOffset = nTmp32 - 14;    // adapt offset by sizeof(BITMAPFILEHEADER)
1082
86.8k
                bRet = rIStm.GetError() == ERRCODE_NONE;
1083
86.8k
            }
1084
86.9k
        }
1085
1086
87.0k
        if ( rOffset >= nStreamLength )
1087
292
        {
1088
            // Offset claims that image starts past the end of the
1089
            // stream.  Unlikely.
1090
292
            rIStm.SetError( SVSTREAM_FILEFORMAT_ERROR );
1091
292
            bRet = false;
1092
292
        }
1093
87.0k
    }
1094
447
    else
1095
447
        rIStm.SetError( SVSTREAM_FILEFORMAT_ERROR );
1096
1097
87.4k
    return bRet;
1098
87.4k
}
1099
1100
bool ImplWriteDIBPalette( SvStream& rOStm, BitmapReadAccess const & rAcc )
1101
0
{
1102
0
    const sal_uInt16    nColors = rAcc.GetPaletteEntryCount();
1103
0
    const sal_uLong     nPalSize = nColors * 4UL;
1104
0
    std::unique_ptr<sal_uInt8[]> pEntries(new sal_uInt8[ nPalSize ]);
1105
0
    sal_uInt8*          pTmpEntry = pEntries.get();
1106
1107
0
    for( sal_uInt16 i = 0; i < nColors; i++ )
1108
0
    {
1109
0
        const BitmapColor& rPalColor = rAcc.GetPaletteColor( i );
1110
1111
0
        *pTmpEntry++ = rPalColor.GetBlue();
1112
0
        *pTmpEntry++ = rPalColor.GetGreen();
1113
0
        *pTmpEntry++ = rPalColor.GetRed();
1114
0
        *pTmpEntry++ = 0;
1115
0
    }
1116
1117
0
    rOStm.WriteBytes( pEntries.get(), nPalSize );
1118
1119
0
    return rOStm.GetError() == ERRCODE_NONE;
1120
0
}
1121
1122
bool ImplWriteRLE( SvStream& rOStm, BitmapReadAccess const & rAcc, bool bRLE4 )
1123
0
{
1124
0
    const sal_uLong nWidth = rAcc.Width();
1125
0
    const sal_uLong nHeight = rAcc.Height();
1126
0
    sal_uLong       nX;
1127
0
    sal_uLong       nSaveIndex;
1128
0
    sal_uLong       nCount;
1129
0
    sal_uLong       nBufCount;
1130
0
    std::vector<sal_uInt8> aBuf(( nWidth << 1 ) + 2);
1131
0
    sal_uInt8       cPix;
1132
0
    sal_uInt8       cLast;
1133
0
    bool        bFound;
1134
1135
0
    for ( tools::Long nY = nHeight - 1; nY >= 0; nY-- )
1136
0
    {
1137
0
        sal_uInt8* pTmp = aBuf.data();
1138
0
        nX = nBufCount = 0;
1139
0
        Scanline pScanline = rAcc.GetScanline( nY );
1140
1141
0
        while( nX < nWidth )
1142
0
        {
1143
0
            nCount = 1;
1144
0
            cPix = rAcc.GetIndexFromData( pScanline, nX++ );
1145
1146
0
            while( ( nX < nWidth ) && ( nCount < 255 )
1147
0
                && ( cPix == rAcc.GetIndexFromData( pScanline, nX ) ) )
1148
0
            {
1149
0
                nX++;
1150
0
                nCount++;
1151
0
            }
1152
1153
0
            if ( nCount > 1 )
1154
0
            {
1155
0
                *pTmp++ = static_cast<sal_uInt8>(nCount);
1156
0
                *pTmp++ = ( bRLE4 ? ( ( cPix << 4 ) | cPix ) : cPix );
1157
0
                nBufCount += 2;
1158
0
            }
1159
0
            else
1160
0
            {
1161
0
                cLast = cPix;
1162
0
                nSaveIndex = nX - 1;
1163
0
                bFound = false;
1164
1165
0
                while( ( nX < nWidth ) && ( nCount < 256 ) )
1166
0
                {
1167
0
                    cPix = rAcc.GetIndexFromData( pScanline, nX );
1168
0
                    if (cPix == cLast)
1169
0
                        break;
1170
0
                    nX++; nCount++;
1171
0
                    cLast = cPix;
1172
0
                    bFound = true;
1173
0
                }
1174
1175
0
                if ( bFound )
1176
0
                    nX--;
1177
1178
0
                if ( nCount > 3 )
1179
0
                {
1180
0
                    *pTmp++ = 0;
1181
0
                    *pTmp++ = static_cast<sal_uInt8>(--nCount);
1182
1183
0
                    if( bRLE4 )
1184
0
                    {
1185
0
                        for ( sal_uLong i = 0; i < nCount; i++, pTmp++ )
1186
0
                        {
1187
0
                            *pTmp = rAcc.GetIndexFromData( pScanline, nSaveIndex++ ) << 4;
1188
1189
0
                            if ( ++i < nCount )
1190
0
                                *pTmp |= rAcc.GetIndexFromData( pScanline, nSaveIndex++ );
1191
0
                        }
1192
1193
0
                        nCount = ( nCount + 1 ) >> 1;
1194
0
                    }
1195
0
                    else
1196
0
                    {
1197
0
                        for( sal_uLong i = 0; i < nCount; i++ )
1198
0
                            *pTmp++ = rAcc.GetIndexFromData( pScanline, nSaveIndex++ );
1199
0
                    }
1200
1201
0
                    if ( nCount & 1 )
1202
0
                    {
1203
0
                        *pTmp++ = 0;
1204
0
                        nBufCount += ( nCount + 3 );
1205
0
                    }
1206
0
                    else
1207
0
                        nBufCount += ( nCount + 2 );
1208
0
                }
1209
0
                else
1210
0
                {
1211
0
                    *pTmp++ = 1;
1212
0
                    *pTmp++ = rAcc.GetIndexFromData( pScanline, nSaveIndex ) << (bRLE4 ? 4 : 0);
1213
1214
0
                    if ( nCount == 3 )
1215
0
                    {
1216
0
                        *pTmp++ = 1;
1217
0
                        *pTmp++ = rAcc.GetIndexFromData( pScanline, ++nSaveIndex ) << ( bRLE4 ? 4 : 0 );
1218
0
                        nBufCount += 4;
1219
0
                    }
1220
0
                    else
1221
0
                        nBufCount += 2;
1222
0
                }
1223
0
            }
1224
0
        }
1225
1226
0
        aBuf[ nBufCount++ ] = 0;
1227
0
        aBuf[ nBufCount++ ] = 0;
1228
1229
0
        rOStm.WriteBytes(aBuf.data(), nBufCount);
1230
0
    }
1231
1232
0
    rOStm.WriteUChar( 0 );
1233
0
    rOStm.WriteUChar( 1 );
1234
1235
0
    return rOStm.GetError() == ERRCODE_NONE;
1236
0
}
1237
1238
bool ImplWriteDIBBits(SvStream& rOStm, BitmapReadAccess const & rAcc, sal_uLong nCompression, sal_uInt32& rImageSize)
1239
0
{
1240
0
    if(BITFIELDS == nCompression)
1241
0
    {
1242
0
        ColorMask rMask;
1243
0
        SVBT32              aVal32;
1244
1245
0
        UInt32ToSVBT32( rMask.GetRedMask(), aVal32 );
1246
0
        rOStm.WriteBytes( aVal32, 4UL );
1247
1248
0
        UInt32ToSVBT32( rMask.GetGreenMask(), aVal32 );
1249
0
        rOStm.WriteBytes( aVal32, 4UL );
1250
1251
0
        UInt32ToSVBT32( rMask.GetBlueMask(), aVal32 );
1252
0
        rOStm.WriteBytes( aVal32, 4UL );
1253
1254
0
        rImageSize = rOStm.Tell();
1255
1256
0
        if( rAcc.IsBottomUp() )
1257
0
            rOStm.WriteBytes(rAcc.GetBuffer(), rAcc.Height() * rAcc.GetScanlineSize());
1258
0
        else
1259
0
        {
1260
0
            for( tools::Long nY = rAcc.Height() - 1, nScanlineSize = rAcc.GetScanlineSize(); nY >= 0; nY-- )
1261
0
                rOStm.WriteBytes( rAcc.GetScanline(nY), nScanlineSize );
1262
0
        }
1263
0
    }
1264
0
    else if((RLE_4 == nCompression) || (RLE_8 == nCompression))
1265
0
    {
1266
0
        rImageSize = rOStm.Tell();
1267
0
        ImplWriteRLE( rOStm, rAcc, RLE_4 == nCompression );
1268
0
    }
1269
0
    else if(!nCompression)
1270
0
    {
1271
        // #i5xxx# Limit bitcount to 24bit, the 32 bit cases are not
1272
        // handled properly below (would have to set color masks, and
1273
        // nCompression=BITFIELDS - but color mask is not set for
1274
        // formats != *_TC_*). Note that this very problem might cause
1275
        // trouble at other places - the introduction of 32 bit RGBA
1276
        // bitmaps is relatively recent.
1277
        // #i59239# discretize bitcount for aligned width to 1,8,24
1278
        // (other cases are not written below)
1279
0
        const auto ePixelFormat(lcl_convertToBPP(rAcc.GetBitCount()));
1280
0
        const sal_uLong nAlignedWidth(AlignedWidth4Bytes(rAcc.Width() * sal_Int32(ePixelFormat)));
1281
0
        bool bNative(false);
1282
1283
0
        switch(rAcc.GetScanlineFormat())
1284
0
        {
1285
0
            case ScanlineFormat::N8BitPal:
1286
0
            case ScanlineFormat::N24BitTcBgr:
1287
0
            {
1288
0
                if(rAcc.IsBottomUp() && (rAcc.GetScanlineSize() == nAlignedWidth))
1289
0
                {
1290
0
                    bNative = true;
1291
0
                }
1292
1293
0
                break;
1294
0
            }
1295
1296
0
            default:
1297
0
            {
1298
0
                break;
1299
0
            }
1300
0
        }
1301
1302
0
        rImageSize = rOStm.Tell();
1303
1304
0
        if(bNative)
1305
0
        {
1306
0
            rOStm.WriteBytes(rAcc.GetBuffer(), nAlignedWidth * rAcc.Height());
1307
0
        }
1308
0
        else
1309
0
        {
1310
0
            const tools::Long nWidth(rAcc.Width());
1311
0
            const tools::Long nHeight(rAcc.Height());
1312
0
            std::vector<sal_uInt8> aBuf(nAlignedWidth);
1313
0
            switch(ePixelFormat)
1314
0
            {
1315
0
                case vcl::PixelFormat::N8_BPP:
1316
0
                {
1317
0
                    for( tools::Long nY = nHeight - 1; nY >= 0; nY-- )
1318
0
                    {
1319
0
                        sal_uInt8* pTmp = aBuf.data();
1320
0
                        Scanline pScanline = rAcc.GetScanline( nY );
1321
1322
0
                        for( tools::Long nX = 0; nX < nWidth; nX++ )
1323
0
                            *pTmp++ = rAcc.GetIndexFromData( pScanline, nX );
1324
1325
0
                        rOStm.WriteBytes(aBuf.data(), nAlignedWidth);
1326
0
                    }
1327
0
                }
1328
0
                break;
1329
1330
0
                case vcl::PixelFormat::N24_BPP:
1331
0
                {
1332
                    //valgrind, zero out the trailing unused alignment bytes
1333
0
                    size_t nUnusedBytes = nAlignedWidth - nWidth * 3;
1334
0
                    memset(aBuf.data() + nAlignedWidth - nUnusedBytes, 0, nUnusedBytes);
1335
0
                }
1336
0
                [[fallthrough]];
1337
                // #i59239# fallback to 24 bit format, if bitcount is non-default
1338
0
                default:
1339
0
                {
1340
0
                    BitmapColor aPixelColor;
1341
1342
0
                    for( tools::Long nY = nHeight - 1; nY >= 0; nY-- )
1343
0
                    {
1344
0
                        sal_uInt8* pTmp = aBuf.data();
1345
1346
0
                        for( tools::Long nX = 0; nX < nWidth; nX++ )
1347
0
                        {
1348
                            // when alpha is used, this may be non-24bit main bitmap, so use GetColor
1349
                            // instead of GetPixel to ensure RGB value
1350
0
                            aPixelColor = rAcc.GetColor( nY, nX );
1351
1352
0
                            *pTmp++ = aPixelColor.GetBlue();
1353
0
                            *pTmp++ = aPixelColor.GetGreen();
1354
0
                            *pTmp++ = aPixelColor.GetRed();
1355
0
                        }
1356
1357
0
                        rOStm.WriteBytes(aBuf.data(), nAlignedWidth);
1358
0
                    }
1359
0
                }
1360
0
                break;
1361
0
            }
1362
0
        }
1363
0
    }
1364
1365
0
    rImageSize = rOStm.Tell() - rImageSize;
1366
1367
0
    return (!rOStm.GetError());
1368
0
}
1369
1370
bool ImplWriteDIBBody(const Bitmap& rBitmap, SvStream& rOStm, BitmapReadAccess const & rAcc, bool bCompressed)
1371
0
{
1372
0
    const MapMode aMapPixel(MapUnit::MapPixel);
1373
0
    DIBV5Header aHeader;
1374
0
    sal_uInt64 nImageSizePos(0);
1375
0
    sal_uInt64 nEndPos(0);
1376
0
    sal_uInt32 nCompression(COMPRESS_NONE);
1377
0
    bool bRet(false);
1378
1379
0
    aHeader.nSize = DIBINFOHEADERSIZE; // size dependent on CF_DIB type to use
1380
0
    aHeader.nWidth = rAcc.Width();
1381
0
    aHeader.nHeight = rAcc.Height();
1382
0
    aHeader.nPlanes = 1;
1383
1384
    // #i5xxx# Limit bitcount to 24bit, the 32 bit cases are
1385
    // not handled properly below (would have to set color
1386
    // masks, and nCompression=BITFIELDS - but color mask is
1387
    // not set for formats != *_TC_*). Note that this very
1388
    // problem might cause trouble at other places - the
1389
    // introduction of 32 bit RGBA bitmaps is relatively
1390
    // recent.
1391
    // #i59239# discretize bitcount to 1,8,24 (other cases
1392
    // are not written below)
1393
0
    const auto ePixelFormat(lcl_convertToBPP(rAcc.GetBitCount()));
1394
0
    aHeader.nBitCount = sal_uInt16(ePixelFormat);
1395
0
    aHeader.nSizeImage = rAcc.Height() * AlignedWidth4Bytes(rAcc.Width() * aHeader.nBitCount);
1396
1397
0
    if (bCompressed)
1398
0
    {
1399
0
        if (ePixelFormat == vcl::PixelFormat::N8_BPP)
1400
0
            nCompression = RLE_8;
1401
0
    }
1402
1403
0
    if((rOStm.GetCompressMode() & SvStreamCompressFlags::ZBITMAP) && (rOStm.GetVersion() >= SOFFICE_FILEFORMAT_40))
1404
0
    {
1405
0
        aHeader.nCompression = ZCOMPRESS;
1406
0
    }
1407
0
    else
1408
0
    {
1409
0
        aHeader.nCompression = nCompression;
1410
0
    }
1411
1412
0
    if(rBitmap.GetPrefSize().Width() && rBitmap.GetPrefSize().Height() && (rBitmap.GetPrefMapMode() != aMapPixel))
1413
0
    {
1414
        // #i48108# Try to recover xpels/ypels as previously stored on
1415
        // disk. The problem with just converting maPrefSize to 100th
1416
        // mm and then relating that to the bitmap pixel size is that
1417
        // MapMode is integer-based, and suffers from roundoffs,
1418
        // especially if maPrefSize is small. Trying to circumvent
1419
        // that by performing part of the math in floating point.
1420
0
        const Size aScale100000(OutputDevice::LogicToLogic(Size(100000, 100000), MapMode(MapUnit::Map100thMM), rBitmap.GetPrefMapMode()));
1421
0
        const double fBmpWidthM(static_cast<double>(rBitmap.GetPrefSize().Width()) / aScale100000.Width());
1422
0
        const double fBmpHeightM(static_cast<double>(rBitmap.GetPrefSize().Height()) / aScale100000.Height());
1423
1424
0
        if(!basegfx::fTools::equalZero(fBmpWidthM) && !basegfx::fTools::equalZero(fBmpHeightM))
1425
0
        {
1426
0
            aHeader.nXPelsPerMeter = basegfx::fround(rAcc.Width() / fabs(fBmpWidthM));
1427
0
            aHeader.nYPelsPerMeter = basegfx::fround(rAcc.Height() / fabs(fBmpHeightM));
1428
0
        }
1429
0
    }
1430
1431
0
    aHeader.nColsUsed = ((aHeader.nBitCount <= 8) ? rAcc.GetPaletteEntryCount() : 0);
1432
0
    aHeader.nColsImportant = 0;
1433
1434
0
    rOStm.WriteUInt32( aHeader.nSize );
1435
0
    rOStm.WriteInt32( aHeader.nWidth );
1436
0
    rOStm.WriteInt32( aHeader.nHeight );
1437
0
    rOStm.WriteUInt16( aHeader.nPlanes );
1438
0
    rOStm.WriteUInt16( aHeader.nBitCount );
1439
0
    rOStm.WriteUInt32( aHeader.nCompression );
1440
1441
0
    nImageSizePos = rOStm.Tell();
1442
0
    rOStm.SeekRel( sizeof( aHeader.nSizeImage ) );
1443
1444
0
    rOStm.WriteInt32( aHeader.nXPelsPerMeter );
1445
0
    rOStm.WriteInt32( aHeader.nYPelsPerMeter );
1446
0
    rOStm.WriteUInt32( aHeader.nColsUsed );
1447
0
    rOStm.WriteUInt32( aHeader.nColsImportant );
1448
1449
0
    if(ZCOMPRESS == aHeader.nCompression)
1450
0
    {
1451
0
        ZCodec aCodec;
1452
0
        SvMemoryStream aMemStm(aHeader.nSizeImage + 4096, 65535);
1453
0
        sal_uInt64 nCodedPos(rOStm.Tell());
1454
0
        sal_uInt64 nLastPos(0);
1455
0
        sal_uInt32 nCodedSize(0);
1456
0
        sal_uInt32 nUncodedSize(0);
1457
1458
        // write uncoded data palette
1459
0
        if(aHeader.nColsUsed)
1460
0
        {
1461
0
            ImplWriteDIBPalette(aMemStm, rAcc);
1462
0
        }
1463
1464
        // write uncoded bits
1465
0
        bRet = ImplWriteDIBBits(aMemStm, rAcc, nCompression, aHeader.nSizeImage);
1466
1467
        // get uncoded size
1468
0
        nUncodedSize = aMemStm.Tell();
1469
1470
        // seek over compress info
1471
0
        rOStm.SeekRel(12);
1472
1473
        // write compressed data
1474
0
        aCodec.BeginCompression(3);
1475
0
        aCodec.Write(rOStm, static_cast<sal_uInt8 const *>(aMemStm.GetData()), nUncodedSize);
1476
0
        aCodec.EndCompression();
1477
1478
        // update compress info ( coded size, uncoded size, uncoded compression )
1479
0
        nLastPos = rOStm.Tell();
1480
0
        nCodedSize = nLastPos - nCodedPos - 12;
1481
0
        rOStm.Seek(nCodedPos);
1482
0
        rOStm.WriteUInt32( nCodedSize ).WriteUInt32( nUncodedSize ).WriteUInt32( nCompression );
1483
0
        rOStm.Seek(nLastPos);
1484
1485
0
        if(bRet)
1486
0
        {
1487
0
            bRet = (ERRCODE_NONE == rOStm.GetError());
1488
0
        }
1489
0
    }
1490
0
    else
1491
0
    {
1492
0
        if(aHeader.nColsUsed)
1493
0
        {
1494
0
            ImplWriteDIBPalette(rOStm, rAcc);
1495
0
        }
1496
1497
0
        bRet = ImplWriteDIBBits(rOStm, rAcc, aHeader.nCompression, aHeader.nSizeImage);
1498
0
    }
1499
1500
0
    nEndPos = rOStm.Tell();
1501
0
    rOStm.Seek(nImageSizePos);
1502
0
    rOStm.WriteUInt32( aHeader.nSizeImage );
1503
0
    rOStm.Seek(nEndPos);
1504
1505
0
    return bRet;
1506
0
}
1507
1508
bool ImplWriteDIBFileHeader(SvStream& rOStm, BitmapReadAccess const & rAcc)
1509
0
{
1510
0
    const sal_uInt32 nPalCount((rAcc.HasPalette() ? rAcc.GetPaletteEntryCount() : 0UL));
1511
0
    const sal_uInt32 nOffset(14 + DIBINFOHEADERSIZE + nPalCount * 4UL);
1512
1513
0
    rOStm.WriteUInt16( 0x4D42 ); // 'MB' from BITMAPFILEHEADER
1514
0
    rOStm.WriteUInt32( nOffset + (rAcc.Height() * rAcc.GetScanlineSize()) );
1515
0
    rOStm.WriteUInt16( 0 );
1516
0
    rOStm.WriteUInt16( 0 );
1517
0
    rOStm.WriteUInt32( nOffset );
1518
1519
0
    return rOStm.GetError() == ERRCODE_NONE;
1520
0
}
1521
1522
bool ImplReadDIB(
1523
    Bitmap& rTarget,
1524
    AlphaMask* pTargetAlpha,
1525
    SvStream& rIStm,
1526
    bool bFileHeader,
1527
    bool bMSOFormat=false)
1528
114k
{
1529
114k
    const SvStreamEndian nOldFormat(rIStm.GetEndian());
1530
114k
    const auto nOldPos(rIStm.Tell());
1531
114k
    sal_uLong nOffset(0);
1532
114k
    bool bRet(false);
1533
1534
114k
    rIStm.SetEndian(SvStreamEndian::LITTLE);
1535
1536
114k
    if(bFileHeader)
1537
87.4k
    {
1538
87.4k
        if(ImplReadDIBFileHeader(rIStm, nOffset))
1539
86.6k
        {
1540
86.6k
            bRet = ImplReadDIBBody(rIStm, rTarget, nOffset >= DIBV5HEADERSIZE ? pTargetAlpha : nullptr, nOffset, bMSOFormat);
1541
86.6k
        }
1542
87.4k
    }
1543
26.6k
    else
1544
26.6k
    {
1545
26.6k
        bRet = ImplReadDIBBody(rIStm, rTarget, nullptr, nOffset, bMSOFormat);
1546
26.6k
    }
1547
1548
114k
    if(!bRet)
1549
59.4k
    {
1550
59.4k
        if(!rIStm.GetError()) // Set error and stop processing whole stream due to security reason
1551
56.0k
        {
1552
56.0k
            rIStm.SetError(SVSTREAM_GENERALERROR);
1553
56.0k
        }
1554
1555
59.4k
        rIStm.Seek(nOldPos);
1556
59.4k
    }
1557
1558
114k
    rIStm.SetEndian(nOldFormat);
1559
1560
114k
    return bRet;
1561
114k
}
1562
1563
bool ImplWriteDIB(
1564
    const Bitmap& rSource,
1565
    SvStream& rOStm,
1566
    bool bCompressed,
1567
    bool bFileHeader)
1568
0
{
1569
0
    const Size aSizePix(rSource.GetSizePixel());
1570
0
    bool bRet(false);
1571
1572
0
    if(!aSizePix.Width() || !aSizePix.Height())
1573
0
        return false;
1574
1575
0
    const SvStreamEndian nOldFormat(rOStm.GetEndian());
1576
0
    const sal_uInt64 nOldPos(rOStm.Tell());
1577
1578
0
    rOStm.SetEndian(SvStreamEndian::LITTLE);
1579
1580
0
    if (BitmapScopedReadAccess pAcc{ rSource })
1581
0
    {
1582
0
        if (!bFileHeader || ImplWriteDIBFileHeader(rOStm, *pAcc))
1583
0
        {
1584
0
            bRet = ImplWriteDIBBody(rSource, rOStm, *pAcc, bCompressed);
1585
0
        }
1586
0
    }
1587
1588
0
    if(!bRet)
1589
0
    {
1590
0
        rOStm.SetError(SVSTREAM_GENERALERROR);
1591
0
        rOStm.Seek(nOldPos);
1592
0
    }
1593
1594
0
    rOStm.SetEndian(nOldFormat);
1595
1596
0
    return bRet;
1597
0
}
1598
1599
} // unnamed namespace
1600
1601
bool ReadDIB(
1602
    Bitmap& rTarget,
1603
    SvStream& rIStm,
1604
    bool bFileHeader,
1605
    bool bMSOFormat)
1606
75.2k
{
1607
75.2k
    return ImplReadDIB(rTarget, nullptr, rIStm, bFileHeader, bMSOFormat);
1608
75.2k
}
1609
1610
bool ReadDIBBitmapEx(
1611
    Bitmap& rTarget,
1612
    SvStream& rIStm,
1613
    bool bFileHeader,
1614
    bool bMSOFormat)
1615
21.2k
{
1616
21.2k
    Bitmap aBmp;
1617
21.2k
    if (!ImplReadDIB(aBmp, nullptr, rIStm, bFileHeader, bMSOFormat) || rIStm.GetError())
1618
352
        return false;
1619
1620
    // base bitmap was read, set as return value and try to read alpha extra-data
1621
20.9k
    const sal_uInt64 nStmPos(rIStm.Tell());
1622
20.9k
    sal_uInt32 nMagic1(0);
1623
20.9k
    sal_uInt32 nMagic2(0);
1624
1625
20.9k
    rTarget = aBmp;
1626
20.9k
    if (rIStm.remainingSize() >= 4)
1627
20.8k
        rIStm.ReadUInt32( nMagic1 ).ReadUInt32( nMagic2 );
1628
20.9k
    bool bRetval = (0x25091962 == nMagic1) && (0xACB20201 == nMagic2) && !rIStm.GetError();
1629
1630
20.9k
    if(bRetval)
1631
16.5k
    {
1632
16.5k
        sal_uInt8 tmp = 0;
1633
16.5k
        rIStm.ReadUChar( tmp );
1634
16.5k
        bRetval = !rIStm.GetError();
1635
1636
16.5k
        if(bRetval)
1637
16.5k
        {
1638
16.5k
            switch (tmp)
1639
16.5k
            {
1640
14.9k
            case 2: // TransparentType::Bitmap
1641
14.9k
                {
1642
14.9k
                    Bitmap aMask;
1643
1644
14.9k
                    bRetval = ImplReadDIB(aMask, nullptr, rIStm, true);
1645
1646
14.9k
                    if(bRetval && !aMask.IsEmpty())
1647
6.10k
                        rTarget = Bitmap(aBmp, aMask);
1648
1649
14.9k
                    break;
1650
0
                }
1651
1.44k
            case 1: // backwards compat for old option TransparentType::Color
1652
1.44k
                {
1653
1.44k
                    Color aTransparentColor;
1654
1655
1.44k
                    tools::GenericTypeSerializer aSerializer(rIStm);
1656
1.44k
                    aSerializer.readColor(aTransparentColor);
1657
1658
1.44k
                    bRetval = rIStm.good();
1659
1660
1.44k
                    if(bRetval)
1661
1.42k
                    {
1662
1.42k
                        rTarget = Bitmap(aBmp, aTransparentColor);
1663
1.42k
                    }
1664
1.44k
                    break;
1665
0
                }
1666
136
            default: break;
1667
16.5k
            }
1668
16.5k
        }
1669
16.5k
    }
1670
1671
20.9k
    if(!bRetval)
1672
13.2k
    {
1673
        // alpha extra data could not be read; reset, but use base bitmap as result
1674
13.2k
        rIStm.ResetError();
1675
13.2k
        rIStm.Seek(nStmPos);
1676
13.2k
        bRetval = true;
1677
13.2k
    }
1678
1679
20.9k
    return bRetval;
1680
20.9k
}
1681
1682
bool ReadDIBV5(
1683
    Bitmap& rTarget,
1684
    AlphaMask& rTargetAlpha,
1685
    SvStream& rIStm)
1686
2.67k
{
1687
2.67k
    bool rv = ImplReadDIB(rTarget, &rTargetAlpha, rIStm, true);
1688
    // convert transparency->alpha
1689
2.67k
    if (rv)
1690
1.70k
        rTargetAlpha.Invert();
1691
2.67k
    return rv;
1692
2.67k
}
1693
1694
bool ReadRawDIB(
1695
    Bitmap& rTarget,
1696
    const unsigned char* pBuf,
1697
    const ScanlineFormat nFormat,
1698
    const int nHeight,
1699
    const int nStride)
1700
431
{
1701
431
    if (rTarget.HasAlpha())
1702
0
    {
1703
        // Need to preserve the targets alpha information
1704
0
        Bitmap aTmp(rTarget.CreateColorBitmap());
1705
0
        AlphaMask aTmpMask(rTarget.CreateAlphaMask());
1706
0
        {
1707
0
            BitmapScopedWriteAccess pWriteAccess(aTmp);
1708
0
            for (int nRow = 0; nRow < nHeight; ++nRow)
1709
0
            {
1710
0
                pWriteAccess->CopyScanline(nRow, pBuf + (nStride * nRow), nFormat, nStride);
1711
0
            }
1712
0
        }
1713
0
        rTarget = Bitmap(aTmp, aTmpMask);
1714
0
    }
1715
431
    else
1716
431
    {
1717
431
        BitmapScopedWriteAccess pWriteAccess(rTarget);
1718
1.37k
        for (int nRow = 0; nRow < nHeight; ++nRow)
1719
947
        {
1720
947
            pWriteAccess->CopyScanline(nRow, pBuf + (nStride * nRow), nFormat, nStride);
1721
947
        }
1722
431
    }
1723
431
    return true;
1724
431
}
1725
1726
bool WriteDIB(
1727
    const Bitmap& rSource,
1728
    SvStream& rOStm,
1729
    bool bCompressed,
1730
    bool bFileHeader)
1731
0
{
1732
0
    return ImplWriteDIB(rSource, rOStm, bCompressed, bFileHeader);
1733
0
}
1734
1735
bool WriteDIB(
1736
    const Bitmap& rSource,
1737
    SvStream& rOStm,
1738
    bool bCompressed)
1739
0
{
1740
0
    return ImplWriteDIB(rSource.CreateColorBitmap(), rOStm, bCompressed, /*bFileHeader*/true);
1741
0
}
1742
1743
bool WriteDIBBitmapEx(
1744
    const Bitmap& rSource,
1745
    SvStream& rOStm)
1746
0
{
1747
0
    if(ImplWriteDIB(rSource.CreateColorBitmap(), rOStm, true, true))
1748
0
    {
1749
0
        rOStm.WriteUInt32( 0x25091962 );
1750
0
        rOStm.WriteUInt32( 0xACB20201 );
1751
0
        rOStm.WriteUChar( rSource.HasAlpha() ? 2 : 0 ); // Used to be TransparentType enum
1752
1753
0
        if(rSource.HasAlpha())
1754
0
        {
1755
            // invert the alpha because the other routines actually want transparency
1756
0
            AlphaMask tmpAlpha = rSource.CreateAlphaMask();
1757
0
            tmpAlpha.Invert();
1758
0
            return ImplWriteDIB(tmpAlpha.GetBitmap(), rOStm, true, true);
1759
0
        }
1760
0
    }
1761
1762
0
    return false;
1763
0
}
1764
1765
sal_uInt32 getDIBV5HeaderSize()
1766
2.72k
{
1767
2.72k
    return DIBV5HEADERSIZE;
1768
2.72k
}
1769
1770
/* vim:set shiftwidth=4 softtabstop=4 expandtab: */