Coverage Report

Created: 2026-06-30 11:14

next uncovered line (L), next uncovered region (R), next uncovered branch (B)
/src/libreoffice/emfio/source/reader/wmfreader.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 <wmfreader.hxx>
21
#include <emfreader.hxx>
22
23
#include <cstdlib>
24
#include <memory>
25
#include <optional>
26
#include <o3tl/safeint.hxx>
27
#include <o3tl/sprintf.hxx>
28
#include <o3tl/unit_conversion.hxx>
29
#include <rtl/crc.h>
30
#include <rtl/tencinfo.h>
31
#include <sal/log.hxx>
32
#include <tools/mapunit.hxx>
33
#include <osl/endian.h>
34
#include <vcl/gdimtf.hxx>
35
#include <vcl/svapp.hxx>
36
#include <vcl/dibtools.hxx>
37
#include <vcl/outdev.hxx>
38
#include <vcl/wmfexternal.hxx>
39
#include <tools/fract.hxx>
40
#include <vcl/BitmapReadAccess.hxx>
41
#include <vcl/BitmapWriteAccess.hxx>
42
#include <vcl/BitmapTools.hxx>
43
#include <osl/thread.h>
44
45
namespace
46
{
47
    // MS Windows defines
48
    enum WMFRecords
49
    {
50
        W_META_EOF                  = 0x0000,
51
        W_META_SETBKCOLOR           = 0x0201,
52
        W_META_SETBKMODE            = 0x0102,
53
        W_META_SETMAPMODE           = 0x0103,
54
        W_META_SETROP2              = 0x0104,
55
        W_META_SETRELABS            = 0x0105,
56
        W_META_SETPOLYFILLMODE      = 0x0106,
57
        W_META_SETSTRETCHBLTMODE    = 0x0107,
58
        W_META_SETTEXTCHAREXTRA     = 0x0108,
59
        W_META_SETTEXTCOLOR         = 0x0209,
60
        W_META_SETTEXTJUSTIFICATION = 0x020A,
61
        W_META_SETWINDOWORG         = 0x020B,
62
        W_META_SETWINDOWEXT         = 0x020C,
63
        W_META_SETVIEWPORTORG       = 0x020D,
64
        W_META_SETVIEWPORTEXT       = 0x020E,
65
        W_META_OFFSETWINDOWORG      = 0x020F,
66
        W_META_SCALEWINDOWEXT       = 0x0410,
67
        W_META_OFFSETVIEWPORTORG    = 0x0211,
68
        W_META_SCALEVIEWPORTEXT     = 0x0412,
69
        W_META_LINETO               = 0x0213,
70
        W_META_MOVETO               = 0x0214,
71
        W_META_EXCLUDECLIPRECT      = 0x0415,
72
        W_META_INTERSECTCLIPRECT    = 0x0416,
73
        W_META_ARC                  = 0x0817,
74
        W_META_ELLIPSE              = 0x0418,
75
        W_META_FLOODFILL            = 0x0419,
76
        W_META_PIE                  = 0x081A,
77
        W_META_RECTANGLE            = 0x041B,
78
        W_META_ROUNDRECT            = 0x061C,
79
        W_META_PATBLT               = 0x061D,
80
        W_META_SAVEDC               = 0x001E,
81
        W_META_SETPIXEL             = 0x041F,
82
        W_META_OFFSETCLIPRGN        = 0x0220,
83
        W_META_TEXTOUT              = 0x0521,
84
        W_META_BITBLT               = 0x0922,
85
        W_META_STRETCHBLT           = 0x0B23,
86
        W_META_POLYGON              = 0x0324,
87
        W_META_POLYLINE             = 0x0325,
88
        W_META_ESCAPE               = 0x0626,
89
        W_META_RESTOREDC            = 0x0127,
90
        W_META_FILLREGION           = 0x0228,
91
        W_META_FRAMEREGION          = 0x0429,
92
        W_META_INVERTREGION         = 0x012A,
93
        W_META_PAINTREGION          = 0x012B,
94
        W_META_SELECTCLIPREGION     = 0x012C,
95
        W_META_SELECTOBJECT         = 0x012D,
96
        W_META_SETTEXTALIGN         = 0x012E,
97
        W_META_DRAWTEXT             = 0x062F,
98
        W_META_CHORD                = 0x0830,
99
        W_META_SETMAPPERFLAGS       = 0x0231,
100
        W_META_EXTTEXTOUT           = 0x0a32,
101
        W_META_SETDIBTODEV          = 0x0d33,
102
        W_META_SELECTPALETTE        = 0x0234,
103
        W_META_REALIZEPALETTE       = 0x0035,
104
        W_META_ANIMATEPALETTE       = 0x0436,
105
        W_META_SETPALENTRIES        = 0x0037,
106
        W_META_POLYPOLYGON          = 0x0538,
107
        W_META_RESIZEPALETTE        = 0x0139,
108
        W_META_DIBBITBLT            = 0x0940,
109
        W_META_DIBSTRETCHBLT        = 0x0b41,
110
        W_META_DIBCREATEPATTERNBRUSH = 0x0142,
111
        W_META_STRETCHDIB           = 0x0f43,
112
        W_META_EXTFLOODFILL         = 0x0548,
113
        W_META_RESETDC              = 0x014C,
114
        W_META_STARTDOC             = 0x014D,
115
        W_META_STARTPAGE            = 0x004F,
116
        W_META_ENDPAGE              = 0x0050,
117
        W_META_ABORTDOC             = 0x0052,
118
        W_META_ENDDOC               = 0x005E,
119
        W_META_DELETEOBJECT         = 0x01f0,
120
        W_META_CREATEPALETTE        = 0x00f7,
121
        W_META_CREATEBRUSH          = 0x00F8,
122
        W_META_CREATEPATTERNBRUSH   = 0x01F9,
123
        W_META_CREATEPENINDIRECT    = 0x02FA,
124
        W_META_CREATEFONTINDIRECT   = 0x02FB,
125
        W_META_CREATEBRUSHINDIRECT  = 0x02FC,
126
        W_META_CREATEBITMAPINDIRECT = 0x02FD,
127
        W_META_CREATEBITMAP         = 0x06FE,
128
        W_META_CREATEREGION         = 0x06FF
129
    };
130
131
    void GetWinExtMax(const Point& rSource, tools::Rectangle& rPlaceableBound, emfio::MappingMode eMapMode)
132
188k
    {
133
188k
        Point aSource(rSource);
134
188k
        if (eMapMode == emfio::MappingMode::MM_HIMETRIC)
135
3.14k
            aSource.setY( -rSource.Y() );
136
188k
        if (aSource.X() < rPlaceableBound.Left())
137
11.8k
            rPlaceableBound.SetLeft( aSource.X() );
138
188k
        if (aSource.X() > rPlaceableBound.Right())
139
15.5k
            rPlaceableBound.SetRight( aSource.X() );
140
188k
        if (aSource.Y() < rPlaceableBound.Top())
141
8.50k
            rPlaceableBound.SetTop( aSource.Y() );
142
188k
        if (aSource.Y() > rPlaceableBound.Bottom())
143
10.3k
            rPlaceableBound.SetBottom( aSource.Y() );
144
188k
    }
145
146
    void GetWinExtMax(const tools::Rectangle& rSource, tools::Rectangle& rPlaceableBound, emfio::MappingMode nMapMode)
147
14.5k
    {
148
14.5k
        GetWinExtMax(rSource.TopLeft(), rPlaceableBound, nMapMode);
149
14.5k
        GetWinExtMax(rSource.BottomRight(), rPlaceableBound, nMapMode);
150
14.5k
    }
151
152
    const char *
153
    record_type_name(sal_uInt16 nRecType)
154
0
    {
155
0
    #ifndef SAL_LOG_INFO
156
0
        (void) nRecType;
157
0
        return "";
158
    #else
159
        switch( nRecType )
160
        {
161
        case W_META_EOF: return "W_META_EOF";
162
        case W_META_SETBKCOLOR: return "META_SETBKCOLOR";
163
        case W_META_SETBKMODE: return "META_SETBKMODE";
164
        case W_META_SETMAPMODE: return "META_SETMAPMODE";
165
        case W_META_SETROP2: return "META_SETROP2";
166
        case W_META_SETRELABS: return "META_SETRELABS";
167
        case W_META_SETPOLYFILLMODE: return "META_SETPOLYFILLMODE";
168
        case W_META_SETSTRETCHBLTMODE: return "META_SETSTRETCHBLTMODE";
169
        case W_META_SETTEXTCHAREXTRA: return "META_SETTEXTCHAREXTRA";
170
        case W_META_SETTEXTCOLOR: return "META_SETTEXTCOLOR";
171
        case W_META_SETTEXTJUSTIFICATION: return "META_SETTEXTJUSTIFICATION";
172
        case W_META_SETWINDOWORG: return "META_SETWINDOWORG";
173
        case W_META_SETWINDOWEXT: return "META_SETWINDOWEXT";
174
        case W_META_SETVIEWPORTORG: return "META_SETVIEWPORTORG";
175
        case W_META_SETVIEWPORTEXT: return "META_SETVIEWPORTEXT";
176
        case W_META_OFFSETWINDOWORG: return "META_OFFSETWINDOWORG";
177
        case W_META_SCALEWINDOWEXT: return "META_SCALEWINDOWEXT";
178
        case W_META_OFFSETVIEWPORTORG: return "META_OFFSETVIEWPORTORG";
179
        case W_META_SCALEVIEWPORTEXT: return "META_SCALEVIEWPORTEXT";
180
        case W_META_LINETO: return "META_LINETO";
181
        case W_META_MOVETO: return "META_MOVETO";
182
        case W_META_EXCLUDECLIPRECT: return "META_EXCLUDECLIPRECT";
183
        case W_META_INTERSECTCLIPRECT: return "META_INTERSECTCLIPRECT";
184
        case W_META_ARC: return "META_ARC";
185
        case W_META_ELLIPSE: return "META_ELLIPSE";
186
        case W_META_FLOODFILL: return "META_FLOODFILL";
187
        case W_META_PIE: return "META_PIE";
188
        case W_META_RECTANGLE: return "META_RECTANGLE";
189
        case W_META_ROUNDRECT: return "META_ROUNDRECT";
190
        case W_META_PATBLT: return "META_PATBLT";
191
        case W_META_SAVEDC: return "META_SAVEDC";
192
        case W_META_SETPIXEL: return "META_SETPIXEL";
193
        case W_META_OFFSETCLIPRGN: return "META_OFFSETCLIPRGN";
194
        case W_META_TEXTOUT: return "META_TEXTOUT";
195
        case W_META_BITBLT: return "META_BITBLT";
196
        case W_META_STRETCHBLT: return "META_STRETCHBLT";
197
        case W_META_POLYGON: return "META_POLYGON";
198
        case W_META_POLYLINE: return "META_POLYLINE";
199
        case W_META_ESCAPE: return "META_ESCAPE";
200
        case W_META_RESTOREDC: return "META_RESTOREDC";
201
        case W_META_FILLREGION: return "META_FILLREGION";
202
        case W_META_FRAMEREGION: return "META_FRAMEREGION";
203
        case W_META_INVERTREGION: return "META_INVERTREGION";
204
        case W_META_PAINTREGION: return "META_PAINTREGION";
205
        case W_META_SELECTCLIPREGION: return "META_SELECTCLIPREGION";
206
        case W_META_SELECTOBJECT: return "META_SELECTOBJECT";
207
        case W_META_SETTEXTALIGN: return "META_SETTEXTALIGN";
208
        case W_META_DRAWTEXT: return "META_DRAWTEXT";
209
        case W_META_CHORD: return "META_CHORD";
210
        case W_META_SETMAPPERFLAGS: return "META_SETMAPPERFLAGS";
211
        case W_META_EXTTEXTOUT: return "META_EXTTEXTOUT";
212
        case W_META_SETDIBTODEV: return "META_SETDIBTODEV";
213
        case W_META_SELECTPALETTE: return "META_SELECTPALETTE";
214
        case W_META_REALIZEPALETTE: return "META_REALIZEPALETTE";
215
        case W_META_ANIMATEPALETTE: return "META_ANIMATEPALETTE";
216
        case W_META_SETPALENTRIES: return "META_SETPALENTRIES";
217
        case W_META_POLYPOLYGON: return "META_POLYPOLYGON";
218
        case W_META_RESIZEPALETTE: return "META_RESIZEPALETTE";
219
        case W_META_DIBBITBLT: return "META_DIBBITBLT";
220
        case W_META_DIBSTRETCHBLT: return "META_DIBSTRETCHBLT";
221
        case W_META_DIBCREATEPATTERNBRUSH: return "META_DIBCREATEPATTERNBRUSH";
222
        case W_META_STRETCHDIB: return "META_STRETCHDIB";
223
        case W_META_EXTFLOODFILL: return "META_EXTFLOODFILL";
224
        case W_META_RESETDC: return "META_RESETDC";
225
        case W_META_STARTDOC: return "META_STARTDOC";
226
        case W_META_STARTPAGE: return "META_STARTPAGE";
227
        case W_META_ENDPAGE: return "META_ENDPAGE";
228
        case W_META_ABORTDOC: return "META_ABORTDOC";
229
        case W_META_ENDDOC: return "META_ENDDOC";
230
        case W_META_DELETEOBJECT: return "META_DELETEOBJECT";
231
        case W_META_CREATEPALETTE: return "META_CREATEPALETTE";
232
        case W_META_CREATEBRUSH: return "META_CREATEBRUSH";
233
        case W_META_CREATEPATTERNBRUSH: return "META_CREATEPATTERNBRUSH";
234
        case W_META_CREATEPENINDIRECT: return "META_CREATEPENINDIRECT";
235
        case W_META_CREATEFONTINDIRECT: return "META_CREATEFONTINDIRECT";
236
        case W_META_CREATEBRUSHINDIRECT: return "META_CREATEBRUSHINDIRECT";
237
        case W_META_CREATEBITMAPINDIRECT: return "META_CREATEBITMAPINDIRECT";
238
        case W_META_CREATEBITMAP: return "META_CREATEBITMAP";
239
        case W_META_CREATEREGION: return "META_CREATEREGION";
240
        default:
241
            // Yes, return a pointer to a static buffer. This is a very
242
            // local debugging output function, so no big deal.
243
            static char buffer[11];
244
            o3tl::sprintf(buffer, "0x%08" SAL_PRIxUINT32, sal_uInt32(nRecType));
245
            return buffer;
246
        }
247
    #endif
248
0
    }
249
250
    // Reads a Bitmap16 from rStream and returns it as a Bitmap. nHeaderSize
251
    // is the on-wire size of the header before the Bits field: per
252
    // [MS-WMF] 2.2.2.1 the structure is 10 bytes; META_CREATEPATTERNBRUSH
253
    // [MS-WMF] 2.3.4.4 instead wraps it in a 14-byte legacy BITMAP struct
254
    // (with a 4-byte bmBits placeholder) plus 18 bytes of padding, for a
255
    // total of 32. Only the 1bpp form actually seen in BS_PATTERN /
256
    // META_CREATEPATTERNBRUSH is supported; anything else returns an empty
257
    // Bitmap.
258
    Bitmap CreateBitmap16(SvStream& rStream, sal_uInt32 nHeaderSize)
259
419
    {
260
419
        const sal_uInt64 nHdrStart = rStream.Tell();
261
419
        sal_Int16 nType(0), nWidth(0), nHeight(0), nWidthBytes(0);
262
419
        sal_uInt8 nPlanes(0), nBitsPixel(0);
263
419
        rStream.ReadInt16(nType).ReadInt16(nWidth).ReadInt16(nHeight)
264
419
               .ReadInt16(nWidthBytes).ReadUChar(nPlanes).ReadUChar(nBitsPixel);
265
419
        rStream.Seek(nHdrStart + nHeaderSize);
266
267
419
        if (!rStream.good() || nType != 0 || nPlanes != 1 || nBitsPixel != 1
268
9
            || nWidth <= 0 || nHeight <= 0 || nWidthBytes <= 0)
269
413
        {
270
413
            SAL_WARN("emfio", "\tUnsupported Bitmap16 (Type=" << nType
271
413
                << ", Planes=" << int(nPlanes)
272
413
                << ", BitsPixel=" << int(nBitsPixel)
273
413
                << ", " << nWidth << "x" << nHeight << ")");
274
413
            return Bitmap();
275
413
        }
276
277
6
        const sal_uInt32 nMinStride = (o3tl::make_unsigned(nWidth) + 7) / 8;
278
6
        if (o3tl::make_unsigned(nWidthBytes) < nMinStride)
279
1
            return Bitmap();
280
281
5
        std::vector<sal_uInt8> aBits(o3tl::make_unsigned(nWidthBytes) * o3tl::make_unsigned(nHeight), 0);
282
5
        if (rStream.ReadBytes(aBits.data(), aBits.size()) != aBits.size())
283
1
            return Bitmap();
284
285
4
        BitmapPalette aPalette(2);
286
4
        aPalette[0] = BitmapColor(COL_WHITE);
287
4
        aPalette[1] = BitmapColor(COL_BLACK);
288
4
        Bitmap aBmp(Size(nWidth, nHeight), vcl::PixelFormat::N8_BPP, &aPalette);
289
4
        BitmapScopedWriteAccess pAccess(aBmp);
290
4
        if (!pAccess)
291
0
            return Bitmap();
292
293
127
        for (sal_Int16 y = 0; y < nHeight; ++y)
294
123
        {
295
123
            const sal_uInt8* pRow = aBits.data() + o3tl::make_unsigned(y) * o3tl::make_unsigned(nWidthBytes);
296
123
            Scanline pScan = pAccess->GetScanline(y);
297
499
            for (sal_Int16 x = 0; x < nWidth; ++x)
298
376
            {
299
                // Bit 7 of byte 0 is the leftmost pixel.
300
376
                const sal_uInt8 nMask = sal_uInt8(0x80) >> (x & 7);
301
376
                pAccess->SetPixelOnData(pScan, x, BitmapColor((pRow[x >> 3] & nMask) ? 1 : 0));
302
376
            }
303
123
        }
304
4
        return aBmp;
305
4
    }
306
}
307
308
namespace emfio
309
{
310
    inline Point WmfReader::ReadPoint()
311
296k
    {
312
296k
        short nX = 0, nY = 0;
313
296k
        mpInputStream->ReadInt16( nX ).ReadInt16( nY );
314
296k
        return Point( nX, nY );
315
296k
    }
316
317
    inline Point WmfReader::ReadYX()
318
123k
    {
319
123k
        short nX = 0, nY = 0;
320
123k
        mpInputStream->ReadInt16( nY ).ReadInt16( nX );
321
123k
        return Point( nX, nY );
322
123k
    }
323
324
    tools::Rectangle WmfReader::ReadRectangle()
325
14.6k
    {
326
14.6k
        Point aBR, aTL;
327
14.6k
        aBR = ReadYX();
328
14.6k
        aTL = ReadYX();
329
14.6k
        aBR.AdjustX( -1 );
330
14.6k
        aBR.AdjustY( -1 );
331
14.6k
        if (aTL.X() > aBR.X() || aTL.Y() > aBR.Y())
332
12.3k
        {
333
12.3k
            SAL_WARN("emfio", "broken rectangle");
334
12.3k
            return tools::Rectangle::Normalize(aTL, aBR);
335
12.3k
        }
336
2.36k
        return tools::Rectangle( aTL, aBR );
337
14.6k
    }
338
339
    Size WmfReader::ReadYXExt()
340
38.8k
    {
341
38.8k
        short nW=0, nH=0;
342
38.8k
        mpInputStream->ReadInt16( nH ).ReadInt16( nW );
343
38.8k
        return Size( nW, nH );
344
38.8k
    }
345
346
    void WmfReader::ReadRecordParams( sal_uInt32 nRecordSize, sal_uInt16 nFunc )
347
185k
    {
348
185k
        bool bRecordOk = true;
349
185k
        SAL_INFO("emfio", "\t" << record_type_name(nFunc));
350
185k
        switch(nFunc)
351
185k
        {
352
1.64k
            case W_META_SETBKCOLOR:
353
1.64k
            {
354
1.64k
                if (nRecordSize != 5)
355
2
                    bRecordOk = false;
356
1.64k
                SetBkColor(ReadColor());
357
1.64k
            }
358
1.64k
            break;
359
360
2.05k
            case W_META_SETBKMODE:
361
2.05k
            {
362
                // It could have Reserved values. Both 4 and 5 sizes are allowed
363
2.05k
                if ((nRecordSize != 4) && (nRecordSize != 5))
364
1
                    bRecordOk = false;
365
2.05k
                sal_uInt16 nDat = 0;
366
2.05k
                mpInputStream->ReadUInt16( nDat );
367
2.05k
                SetBkMode( static_cast<BackgroundMode>(nDat) );
368
2.05k
            }
369
2.05k
            break;
370
371
626
            case W_META_SETMAPMODE:
372
626
            {
373
626
                if (nRecordSize != 4)
374
2
                    bRecordOk = false;
375
626
                sal_uInt16 nMapMode = 0;
376
626
                mpInputStream->ReadUInt16(nMapMode);
377
626
                SetMapMode(static_cast<MappingMode>(nMapMode));
378
626
            }
379
626
            break;
380
381
2.53k
            case W_META_SETROP2:
382
2.53k
            {
383
                // It could have Reserved values. Both 4 and 5 sizes are allowed
384
2.53k
                if ((nRecordSize != 4) && (nRecordSize != 5))
385
1
                    bRecordOk = false;
386
2.53k
                sal_uInt16 nROP2 = 0;
387
2.53k
                mpInputStream->ReadUInt16(nROP2);
388
2.53k
                SetRasterOp(static_cast<WMFRasterOp>(nROP2));
389
2.53k
                mpInputStream->SeekRel(2); // reserved data
390
2.53k
            }
391
2.53k
            break;
392
393
1.00k
            case W_META_SETTEXTCOLOR:
394
1.00k
            {
395
1.00k
                if (nRecordSize != 5)
396
2
                    bRecordOk = false;
397
1.00k
                SetTextColor( ReadColor() );
398
1.00k
            }
399
1.00k
            break;
400
401
2.21k
            case W_META_SETWINDOWORG:
402
2.21k
            {
403
2.21k
                if (nRecordSize != 5)
404
1
                    bRecordOk = false;
405
2.21k
                SetWinOrg( ReadYX() );
406
2.21k
            }
407
2.21k
            break;
408
409
2.03k
            case W_META_SETWINDOWEXT:
410
2.03k
            {
411
2.03k
                if (nRecordSize != 5)
412
9
                    bRecordOk = false;
413
2.03k
                short nWidth = 0, nHeight = 0;
414
2.03k
                mpInputStream->ReadInt16( nHeight ).ReadInt16( nWidth );
415
2.03k
                SetWinExt( Size( nWidth, nHeight ) );
416
2.03k
            }
417
2.03k
            break;
418
419
218
            case W_META_OFFSETWINDOWORG:
420
218
            {
421
218
                if (nRecordSize != 5)
422
2
                    bRecordOk = false;
423
218
                short nXAdd = 0, nYAdd = 0;
424
218
                mpInputStream->ReadInt16( nYAdd ).ReadInt16( nXAdd );
425
218
                SetWinOrgOffset( nXAdd, nYAdd );
426
218
            }
427
218
            break;
428
429
2.14k
            case W_META_SCALEWINDOWEXT:
430
2.14k
            {
431
2.14k
                if (nRecordSize != 7)
432
15
                    bRecordOk = false;
433
2.14k
                short nXNum = 0, nXDenom = 0, nYNum = 0, nYDenom = 0;
434
2.14k
                mpInputStream->ReadInt16( nYDenom ).ReadInt16( nYNum ).ReadInt16( nXDenom ).ReadInt16( nXNum );
435
2.14k
                if (!nYDenom || !nXDenom)
436
7
                {
437
7
                    mpInputStream->SetError( SVSTREAM_FILEFORMAT_ERROR );
438
7
                    break;
439
7
                }
440
2.13k
                ScaleWinExt( static_cast<double>(nXNum) / nXDenom, static_cast<double>(nYNum) / nYDenom );
441
2.13k
            }
442
0
            break;
443
444
67
            case W_META_SETVIEWPORTORG:
445
816
            case W_META_SETVIEWPORTEXT:
446
816
            {
447
816
                if (nRecordSize != 5)
448
1
                    bRecordOk = false;
449
816
            }
450
816
            break;
451
452
649
            case W_META_OFFSETVIEWPORTORG:
453
649
            {
454
649
                if (nRecordSize != 5)
455
1
                    bRecordOk = false;
456
649
                short nXAdd = 0, nYAdd = 0;
457
649
                mpInputStream->ReadInt16( nYAdd ).ReadInt16( nXAdd );
458
649
                SetDevOrgOffset( nXAdd, nYAdd );
459
649
            }
460
649
            break;
461
462
3.39k
            case W_META_SCALEVIEWPORTEXT:
463
3.39k
            {
464
3.39k
                if (nRecordSize != 7)
465
9
                    bRecordOk = false;
466
3.39k
                short nXNum = 0, nXDenom = 0, nYNum = 0, nYDenom = 0;
467
3.39k
                mpInputStream->ReadInt16( nYDenom ).ReadInt16( nYNum ).ReadInt16( nXDenom ).ReadInt16( nXNum );
468
3.39k
                if (!nYDenom || !nXDenom)
469
3
                {
470
3
                    mpInputStream->SetError( SVSTREAM_FILEFORMAT_ERROR );
471
3
                    break;
472
3
                }
473
3.38k
                ScaleDevExt( static_cast<double>(nXNum) / nXDenom, static_cast<double>(nYNum) / nYDenom );
474
3.38k
            }
475
0
            break;
476
477
3.11k
            case W_META_LINETO:
478
3.11k
            {
479
3.11k
                if (nRecordSize != 5)
480
2
                    bRecordOk = false;
481
3.11k
                LineTo( ReadYX() );
482
3.11k
            }
483
3.11k
            break;
484
485
1.69k
            case W_META_MOVETO:
486
1.69k
            {
487
1.69k
                if (nRecordSize != 5)
488
7
                    bRecordOk = false;
489
1.69k
                MoveTo( ReadYX() );
490
1.69k
            }
491
1.69k
            break;
492
493
134
            case W_META_INTERSECTCLIPRECT:
494
134
            {
495
134
                if (nRecordSize != 7)
496
6
                    bRecordOk = false;
497
134
                IntersectClipRect(ReadRectangle());
498
134
            }
499
134
            break;
500
501
636
            case W_META_RECTANGLE:
502
636
            {
503
636
                if (nRecordSize != 7)
504
61
                    bRecordOk = false;
505
636
                DrawRect(ReadRectangle());
506
636
            }
507
636
            break;
508
509
1.65k
            case W_META_ROUNDRECT:
510
1.65k
            {
511
1.65k
                if (nRecordSize != 9)
512
36
                    bRecordOk = false;
513
1.65k
                Size aSize( ReadYXExt() );
514
1.65k
                DrawRoundRect( ReadRectangle(), Size( aSize.Width() / 2, aSize.Height() / 2 ) );
515
1.65k
            }
516
1.65k
            break;
517
518
1.30k
            case W_META_ELLIPSE:
519
1.30k
            {
520
1.30k
                if (nRecordSize != 7)
521
26
                    bRecordOk = false;
522
1.30k
                DrawEllipse(ReadRectangle());
523
1.30k
            }
524
1.30k
            break;
525
526
3.02k
            case W_META_ARC:
527
3.02k
            {
528
3.02k
                if (nRecordSize != 11)
529
188
                    bRecordOk = false;
530
3.02k
                Point aEnd( ReadYX() );
531
3.02k
                Point aStart( ReadYX() );
532
3.02k
                tools::Rectangle aRect( ReadRectangle() );
533
3.02k
                aRect.Normalize();
534
3.02k
                DrawArc( aRect, aStart, aEnd );
535
3.02k
            }
536
3.02k
            break;
537
538
978
            case W_META_PIE:
539
978
            {
540
978
                if (nRecordSize != 11)
541
96
                    bRecordOk = false;
542
978
                Point     aEnd( ReadYX() );
543
978
                Point     aStart( ReadYX() );
544
978
                tools::Rectangle aRect( ReadRectangle() );
545
978
                aRect.Normalize();
546
547
                // #i73608# OutputDevice deviates from WMF
548
                // semantics. start==end means full ellipse here.
549
978
                if( aStart == aEnd )
550
226
                    DrawEllipse( aRect );
551
752
                else
552
752
                    DrawPie( aRect, aStart, aEnd );
553
978
            }
554
978
            break;
555
556
498
            case W_META_CHORD:
557
498
            {
558
498
                if (nRecordSize != 11)
559
8
                    bRecordOk = false;
560
498
                Point aEnd( ReadYX() );
561
498
                Point aStart( ReadYX() );
562
498
                tools::Rectangle aRect( ReadRectangle() );
563
498
                aRect.Normalize();
564
498
                DrawChord( aRect, aStart, aEnd );
565
498
            }
566
498
            break;
567
568
2.40k
            case W_META_POLYGON:
569
2.40k
            {
570
2.40k
                sal_uInt16 nPoints(0);
571
2.40k
                mpInputStream->ReadUInt16(nPoints);
572
573
2.40k
                if (nPoints > mpInputStream->remainingSize() / (2 * sizeof(sal_uInt16)))
574
10
                {
575
10
                    bRecordOk = false;
576
10
                }
577
2.39k
                else
578
2.39k
                {
579
2.39k
                    tools::Polygon aPoly(nPoints);
580
32.4k
                    for (sal_uInt16 i(0); i < nPoints && mpInputStream->good(); ++i)
581
30.0k
                        aPoly[ i ] = ReadPoint();
582
2.39k
                    DrawPolygon(std::move(aPoly), false/*bRecordPath*/);
583
2.39k
                }
584
585
2.40k
                SAL_WARN_IF(!bRecordOk, "emfio", "polygon record has more points than we can handle");
586
587
2.40k
                bRecordOk &= mpInputStream->good();
588
2.40k
            }
589
0
            break;
590
591
4.11k
            case W_META_POLYPOLYGON:
592
4.11k
            {
593
4.11k
                sal_uInt16 nPolyCount(0);
594
                // Number of polygons:
595
4.11k
                mpInputStream->ReadUInt16( nPolyCount );
596
4.11k
                if (nPolyCount && mpInputStream->good())
597
3.54k
                {
598
3.54k
                    if (nPolyCount > mpInputStream->remainingSize() / sizeof(sal_uInt16))
599
238
                        break;
600
601
                    // Number of points of each polygon. Determine total number of points
602
3.30k
                    std::unique_ptr<sal_uInt16[]> xPolygonPointCounts(new sal_uInt16[nPolyCount]);
603
3.30k
                    sal_uInt16* pnPoints = xPolygonPointCounts.get();
604
3.30k
                    tools::PolyPolygon aPolyPoly(nPolyCount);
605
3.30k
                    sal_uInt16 nPoints = 0;
606
9.27k
                    for (sal_uInt16 a = 0; a < nPolyCount && mpInputStream->good(); ++a)
607
5.97k
                    {
608
5.97k
                        mpInputStream->ReadUInt16( pnPoints[a] );
609
610
5.97k
                        if (pnPoints[a] > SAL_MAX_UINT16 - nPoints)
611
6
                        {
612
6
                            bRecordOk = false;
613
6
                            break;
614
6
                        }
615
616
5.96k
                        nPoints += pnPoints[a];
617
5.96k
                    }
618
619
3.30k
                    SAL_WARN_IF(!bRecordOk, "emfio", "polypolygon record has more polygons than we can handle");
620
621
3.30k
                    bRecordOk &= mpInputStream->good();
622
623
3.30k
                    if (!bRecordOk)
624
6
                        break;
625
626
                    // Polygon points are:
627
9.23k
                    for (sal_uInt16 a = 0; a < nPolyCount && mpInputStream->good(); ++a)
628
5.94k
                    {
629
5.94k
                        const sal_uInt16 nPointCount(pnPoints[a]);
630
631
5.94k
                        if (nPointCount > mpInputStream->remainingSize() / (2 * sizeof(sal_uInt16)))
632
9
                        {
633
9
                            bRecordOk = false;
634
9
                            break;
635
9
                        }
636
637
5.93k
                        std::unique_ptr<Point[]> xPolygonPoints(new Point[nPointCount]);
638
5.93k
                        Point* pPtAry = xPolygonPoints.get();
639
640
119k
                        for(sal_uInt16 b(0); b < nPointCount && mpInputStream->good(); ++b)
641
113k
                        {
642
113k
                            pPtAry[b] = ReadPoint();
643
113k
                        }
644
645
5.93k
                        aPolyPoly.Insert( tools::Polygon(nPointCount, pPtAry) );
646
5.93k
                    }
647
648
3.30k
                    bRecordOk &= mpInputStream->good();
649
650
3.30k
                    if (!bRecordOk)
651
9
                        break;
652
653
3.29k
                    DrawPolyPolygon( aPolyPoly );
654
3.29k
                }
655
4.11k
            }
656
3.85k
            break;
657
658
3.85k
            case W_META_POLYLINE:
659
1.29k
            {
660
1.29k
                sal_uInt16 nPoints(0);
661
1.29k
                mpInputStream->ReadUInt16(nPoints);
662
663
1.29k
                if (nPoints > mpInputStream->remainingSize() / (2 * sizeof(sal_uInt16)))
664
3
                {
665
3
                    bRecordOk = false;
666
3
                }
667
1.28k
                else
668
1.28k
                {
669
1.28k
                    tools::Polygon aPoly(nPoints);
670
16.4k
                    for (sal_uInt16 i(0); i < nPoints && mpInputStream->good(); ++i)
671
15.1k
                        aPoly[ i ] = ReadPoint();
672
1.28k
                    DrawPolyLine( std::move(aPoly) );
673
1.28k
                }
674
675
1.29k
                SAL_WARN_IF(!bRecordOk, "emfio", "polyline record has more points than we can handle");
676
677
1.29k
                bRecordOk &= mpInputStream->good();
678
1.29k
            }
679
0
            break;
680
681
1.73k
            case W_META_SAVEDC:
682
1.73k
            {
683
1.73k
                if (nRecordSize != 3)
684
3
                    bRecordOk = false;
685
1.73k
                Push();
686
1.73k
            }
687
1.73k
            break;
688
689
1.19k
            case W_META_RESTOREDC:
690
1.19k
            {
691
1.19k
                sal_Int16 nSavedDC(0);
692
1.19k
                if (nRecordSize != 4)
693
18
                    bRecordOk = false;
694
1.19k
                mpInputStream->ReadInt16(nSavedDC);
695
1.19k
                SAL_INFO("emfio", "\t\t SavedDC: " << nSavedDC);
696
1.19k
                SAL_WARN_IF(nSavedDC < 0,  "emfio", "TODO implement relative to the current state");
697
1.19k
                Pop(nSavedDC);
698
1.19k
            }
699
0
            break;
700
701
80
            case W_META_SETPIXEL:
702
80
            {
703
80
                if (nRecordSize != 7)
704
4
                    bRecordOk = false;
705
80
                const Color aColor = ReadColor();
706
80
                DrawPixel( ReadYX(), aColor );
707
80
            }
708
80
            break;
709
710
74
            case W_META_OFFSETCLIPRGN:
711
74
            {
712
74
                if (nRecordSize != 5)
713
2
                    bRecordOk = false;
714
74
                MoveClipRegion( ReadYXExt() );
715
74
            }
716
74
            break;
717
718
433
            case W_META_TEXTOUT:
719
433
            {
720
                //record is Recordsize, RecordFunction, StringLength, <String>, YStart, XStart
721
433
                const sal_uInt32 nNonStringLen = sizeof(sal_uInt32) + 4 * sizeof(sal_uInt16);
722
433
                const sal_uInt32 nRecSize = nRecordSize * 2;
723
724
433
                if (nRecSize < nNonStringLen)
725
5
                {
726
5
                    bRecordOk = false;
727
5
                    break;
728
5
                }
729
730
428
                sal_uInt16 nLength = 0;
731
428
                mpInputStream->ReadUInt16(nLength);
732
428
                sal_uInt16 nStoredLength = (nLength + 1) &~ 1;
733
734
428
                if (nRecSize - nNonStringLen < nStoredLength)
735
249
                {
736
249
                    SAL_WARN("emfio", "W_META_TEXTOUT too short, truncating string");
737
249
                    nLength = nStoredLength = nRecSize - nNonStringLen;
738
249
                }
739
740
428
                if (nLength)
741
23
                {
742
23
                    std::vector<char> aChars(nStoredLength);
743
23
                    nLength = std::min<sal_uInt16>(nLength, mpInputStream->ReadBytes(aChars.data(), aChars.size()));
744
23
                    OUString aText(aChars.data(), nLength, GetCharSet());
745
23
                    Point aPosition( ReadYX() );
746
23
                    DrawText( aPosition, aText );
747
23
                }
748
428
            }
749
0
            break;
750
751
18.9k
            case W_META_EXTTEXTOUT:
752
18.9k
            {
753
                //record is Recordsize, RecordFunction, Y, X, StringLength, options, maybe rectangle, <String>
754
18.9k
                sal_uInt32 nNonStringLen = sizeof(sal_uInt32) + 5 * sizeof(sal_uInt16);
755
18.9k
                const sal_uInt32 nRecSize = nRecordSize * 2;
756
757
18.9k
                if (nRecSize < nNonStringLen)
758
1
                {
759
1
                    bRecordOk = false;
760
1
                    break;
761
1
                }
762
763
18.9k
                auto nRecordPos = mpInputStream->Tell() - 6;
764
18.9k
                Point aPosition = ReadYX();
765
18.9k
                sal_uInt16 nLen = 0, nOptions = 0;
766
18.9k
                mpInputStream->ReadUInt16( nLen ).ReadUInt16( nOptions );
767
18.9k
                SAL_INFO( "emfio", "\t\t\t Pos: " << aPosition.getX() << ":" << aPosition.getY() << " String Length: " << nLen << " Options: " << nOptions );
768
18.9k
                tools::Rectangle aRect;
769
18.9k
                if ( ( nOptions & ETO_CLIPPED ) || ( nOptions & ETO_OPAQUE ) )
770
550
                {
771
550
                    nNonStringLen += 2 * sizeof(sal_uInt16);
772
773
550
                    if (nRecSize < nNonStringLen)
774
9
                    {
775
9
                        bRecordOk = false;
776
9
                        break;
777
9
                    }
778
541
                    const Point aTopLeft = ReadPoint();
779
541
                    const Point aBottomRight = ReadPoint();
780
541
                    aRect = tools::Rectangle( aTopLeft, aBottomRight );
781
541
                    if ( nOptions & ETO_OPAQUE )
782
405
                        DrawRectWithBGColor( aRect );
783
541
                    SAL_INFO( "emfio", "\t\t\t Rectangle : " << aTopLeft.getX() << ":" << aTopLeft.getY() << ", " << aBottomRight.getX() << ":" << aBottomRight.getY() );
784
541
                }
785
786
18.9k
                vcl::text::ComplexTextLayoutFlags nTextLayoutMode = vcl::text::ComplexTextLayoutFlags::Default;
787
18.9k
                if ( nOptions & ETO_RTLREADING )
788
361
                    nTextLayoutMode = vcl::text::ComplexTextLayoutFlags::BiDiRtl | vcl::text::ComplexTextLayoutFlags::TextOriginLeft;
789
18.9k
                SetTextLayoutMode( nTextLayoutMode );
790
18.9k
                SAL_WARN_IF( ( nOptions & ( ETO_PDY | ETO_GLYPH_INDEX ) ) != 0, "emfio", "SJ: ETO_PDY || ETO_GLYPH_INDEX in WMF" );
791
792
                // output only makes sense if the text contains characters
793
18.9k
                if (nLen)
794
18.4k
                {
795
18.4k
                    sal_Int32 nOriginalTextLen = nLen;
796
18.4k
                    sal_Int32 nOriginalBlockLen = ( nOriginalTextLen + 1 ) &~ 1;
797
798
18.4k
                    auto nMaxStreamPos = nRecordPos + nRecSize;
799
18.4k
                    auto nRemainingSize = std::min(mpInputStream->remainingSize(), nMaxStreamPos - mpInputStream->Tell());
800
18.4k
                    if (nRemainingSize < o3tl::make_unsigned(nOriginalBlockLen))
801
314
                    {
802
314
                        SAL_WARN("emfio", "exttextout record claimed more data than the stream can provide");
803
314
                        nOriginalTextLen = nOriginalBlockLen = nRemainingSize;
804
314
                    }
805
806
18.4k
                    std::vector<char> pChar(nOriginalBlockLen);
807
18.4k
                    mpInputStream->ReadBytes(pChar.data(), nOriginalBlockLen);
808
18.4k
                    OUString aText(pChar.data(), nOriginalTextLen, GetCharSet()); // after this conversion the text may contain
809
18.4k
                    sal_Int32 nNewTextLen = aText.getLength();                         // less character (japanese version), so the
810
                                                                                       // dxAry will not fit
811
18.4k
                    if ( nNewTextLen )
812
18.2k
                    {
813
18.2k
                        if ( nOptions & ETO_CLIPPED )
814
164
                        {
815
164
                            Push(); // Save the current clip. It will be restored after text drawing
816
164
                            IntersectClipRect( aRect );
817
164
                        }
818
18.2k
                        SAL_INFO( "emfio", "\t\t\t Text : " << aText );
819
18.2k
                        KernArray aDXAry;
820
18.2k
                        std::unique_ptr<tools::Long[]> pDYAry;
821
18.2k
                        auto nDxArySize =  nMaxStreamPos - mpInputStream->Tell();
822
18.2k
                        auto nDxAryEntries = nDxArySize >> 1;
823
18.2k
                        bool        bUseDXAry = false;
824
825
18.2k
                        if ( ( ( nDxAryEntries % nOriginalTextLen ) == 0 ) && ( nNewTextLen <= nOriginalTextLen ) )
826
18.1k
                        {
827
18.1k
                            sal_Int32 i; // needed just outside the for
828
18.1k
                            aDXAry.resize( nNewTextLen );
829
18.1k
                            if ( nOptions & ETO_PDY )
830
1.66k
                            {
831
1.66k
                                pDYAry.reset(new tools::Long[ nNewTextLen ]);
832
1.66k
                            }
833
30.2k
                            for (i = 0; i < nNewTextLen; i++ )
834
25.3k
                            {
835
25.3k
                                if ( mpInputStream->Tell() >= nMaxStreamPos )
836
13.3k
                                    break;
837
12.0k
                                sal_Int32 nDxCount = 1;
838
12.0k
                                if ( nNewTextLen != nOriginalTextLen )
839
3.31k
                                {
840
3.31k
                                    sal_Unicode cUniChar = aText[i];
841
3.31k
                                    OString aTmp(&cUniChar, 1, GetCharSet());
842
3.31k
                                    if ( aTmp.getLength() > 1 )
843
1.12k
                                    {
844
1.12k
                                        nDxCount = aTmp.getLength();
845
1.12k
                                    }
846
3.31k
                                }
847
848
12.0k
                                sal_Int16 nDx = 0, nDy = 0;
849
23.7k
                                while ( nDxCount-- )
850
13.1k
                                {
851
13.1k
                                    if ( ( mpInputStream->Tell() + 2 ) > nMaxStreamPos )
852
273
                                        break;
853
12.8k
                                    sal_Int16 nDxTmp = 0;
854
12.8k
                                    mpInputStream->ReadInt16(nDxTmp);
855
12.8k
                                    nDx += nDxTmp;
856
12.8k
                                    if ( nOptions & ETO_PDY )
857
4.59k
                                    {
858
4.59k
                                        if ( ( mpInputStream->Tell() + 2 ) > nMaxStreamPos )
859
1.18k
                                            break;
860
3.40k
                                        sal_Int16 nDyTmp = 0;
861
3.40k
                                        mpInputStream->ReadInt16(nDyTmp);
862
3.40k
                                        nDy += nDyTmp;
863
3.40k
                                    }
864
12.8k
                                }
865
866
12.0k
                                aDXAry[i] = nDx;
867
12.0k
                                if ( nOptions & ETO_PDY )
868
4.31k
                                {
869
4.31k
                                    pDYAry[i] = nDy;
870
4.31k
                                }
871
12.0k
                            }
872
18.1k
                            if ( i == nNewTextLen )
873
4.86k
                                bUseDXAry = true;
874
18.1k
                        }
875
18.2k
                        if ( bUseDXAry )
876
4.86k
                            DrawText( aPosition, aText, &aDXAry, pDYAry.get() );
877
13.3k
                        else
878
13.3k
                            DrawText( aPosition, aText );
879
18.2k
                        if ( nOptions & ETO_CLIPPED )
880
115
                            Pop();
881
18.2k
                    }
882
18.4k
                }
883
18.9k
            }
884
18.9k
            break;
885
886
26.1k
            case W_META_SELECTOBJECT:
887
28.4k
            case W_META_SELECTPALETTE:
888
28.4k
            {
889
28.4k
                if (nRecordSize != 4)
890
10
                    bRecordOk = false;
891
28.4k
                sal_uInt16   nObjIndex = 0;
892
28.4k
                mpInputStream->ReadUInt16( nObjIndex );
893
28.4k
                SelectObject( nObjIndex );
894
28.4k
            }
895
28.4k
            break;
896
897
1.72k
            case W_META_SETTEXTALIGN:
898
1.72k
            {
899
                // It could have Reserved values. Both 4 and 5 sizes are allowed
900
1.72k
                if ((nRecordSize != 4) && (nRecordSize != 5))
901
1
                    bRecordOk = false;
902
1.72k
                sal_uInt16  nAlign = 0;
903
1.72k
                mpInputStream->ReadUInt16( nAlign );
904
1.72k
                SetTextAlign( nAlign );
905
1.72k
            }
906
1.72k
            break;
907
908
10.3k
            case W_META_BITBLT:
909
10.8k
            case W_META_STRETCHBLT:
910
10.8k
            {
911
10.8k
                sal_uInt32  nRasterOperation = 0;
912
10.8k
                sal_Int16   nSrcHeight = 0, nSrcWidth = 0, nYSrc, nXSrc, nSye, nSxe, nBitmapType, nWidth, nHeight, nBytesPerScan;
913
10.8k
                sal_uInt8   nPlanes, nBitCount;
914
10.8k
                const bool bNoSourceBitmap = ( nRecordSize == ( static_cast< sal_uInt32 >( nFunc ) >> 8 ) + 3 );
915
916
10.8k
                mpInputStream->ReadUInt32( nRasterOperation );
917
10.8k
                SAL_INFO("emfio", "\t\t Raster operation: 0x" << std::hex << nRasterOperation << std::dec << ", No source bitmap: " << bNoSourceBitmap);
918
919
10.8k
                if (nFunc == W_META_STRETCHBLT)
920
437
                {
921
437
                    if (nRecordSize < 18)
922
2
                        bRecordOk = false;
923
437
                    mpInputStream->ReadInt16(nSrcHeight).ReadInt16(nSrcWidth);
924
437
                }
925
10.3k
                else
926
10.3k
                    if (nRecordSize < 16)
927
43
                        bRecordOk = false;
928
10.8k
                mpInputStream->ReadInt16( nYSrc ).ReadInt16( nXSrc );
929
10.8k
                if ( bNoSourceBitmap )
930
2
                    mpInputStream->SeekRel( 2 ); // Skip Reserved 2 bytes (it must be ignored)
931
10.8k
                mpInputStream->ReadInt16( nSye ).ReadInt16( nSxe );
932
10.8k
                Point aPoint( ReadYX() ); // The upper-left corner of the destination rectangle.
933
10.8k
                mpInputStream->ReadInt16( nBitmapType ).ReadInt16( nWidth ).ReadInt16( nHeight ).ReadInt16( nBytesPerScan ).ReadUChar( nPlanes ).ReadUChar( nBitCount );
934
935
10.8k
                SAL_INFO("emfio", "\t\t Bitmap type:" << nBitmapType << " Width:" << nWidth << " Height:" << nHeight << " WidthBytes:" << nBytesPerScan << " Planes: " << static_cast< sal_uInt16 >( nPlanes ) << " BitCount: " << static_cast< sal_uInt16 >( nBitCount ) );
936
10.8k
                if (!mpInputStream->good() || bNoSourceBitmap || nBitCount == 4 || nBitCount == 8 || nPlanes != 1)
937
1.09k
                {
938
1.09k
                    SAL_WARN("emfio", "\t\t TODO The unsupported Bitmap record. Please fill a bug.");
939
1.09k
                    break;
940
1.09k
                }
941
9.72k
                bool bOk = nWidth > 0 && nHeight > 0 && nBytesPerScan > 0
942
8.35k
                    && (nBitCount == 1 || nBitCount == 8 || nBitCount == 24 || nBitCount == 32);
943
9.72k
                if (bOk)
944
8.24k
                {
945
                    // must be enough data to fulfil the request
946
8.24k
                    bOk = o3tl::make_unsigned( nBytesPerScan ) <= mpInputStream->remainingSize() / nHeight;
947
8.24k
                }
948
9.72k
                if (bOk)
949
7.90k
                {
950
                    // scanline must be large enough to provide all pixels
951
7.90k
                    bOk = nBytesPerScan >= nWidth * nBitCount / 8;
952
7.90k
                }
953
9.72k
                if (bOk)
954
7.64k
                {
955
7.64k
                    std::unique_ptr< sal_uInt8[] > pData;
956
7.64k
                    pData.reset( new sal_uInt8[ nHeight * nBytesPerScan ] );
957
7.64k
                    mpInputStream->ReadBytes( pData.get(), nHeight * nBytesPerScan );
958
7.64k
                    Bitmap aBitmap = vcl::bitmap::CreateFromData( pData.get(), nWidth, nHeight, nBytesPerScan, nBitCount, true );
959
7.64k
                    if ( nSye && nSxe &&
960
6.71k
                         ( nXSrc + nSxe <= nWidth ) &&
961
5.87k
                         ( nYSrc + nSye <= nHeight ) )
962
5.48k
                    {
963
5.48k
                        tools::Rectangle aCropRect( Point( nXSrc, nYSrc ), Size( nSxe, nSye ) );
964
5.48k
                        aBitmap.Crop( aCropRect );
965
5.48k
                    }
966
7.64k
                    tools::Rectangle aDestRect( aPoint, Size( nSxe, nSye ) );
967
7.64k
                    maBmpSaveList.emplace_back(aBitmap, aDestRect, nRasterOperation);
968
7.64k
                }
969
9.72k
            }
970
0
            break;
971
972
5.45k
            case W_META_DIBBITBLT:
973
7.05k
            case W_META_DIBSTRETCHBLT:
974
8.89k
            case W_META_STRETCHDIB:
975
8.89k
            {
976
8.89k
                sal_uInt32  nRasterOperation = 0;
977
8.89k
                sal_uInt16  nColorUsage = 0;
978
8.89k
                sal_Int16   nSrcHeight = 0, nSrcWidth = 0, nYSrc = 0, nXSrc = 0;
979
8.89k
                Bitmap      aBmp;
980
8.89k
                const bool bNoSourceBitmap = ( nFunc != W_META_STRETCHDIB ) && ( nRecordSize == ( ( static_cast< sal_uInt32 >( nFunc ) >> 8 ) + 3 ) );
981
982
8.89k
                if (nRecordSize < 12)
983
96
                    bRecordOk = false;
984
8.89k
                mpInputStream->ReadUInt32( nRasterOperation );
985
8.89k
                SAL_INFO("emfio", "\t\t Raster operation: 0x" << std::hex << nRasterOperation << std::dec << ", No source bitmap: " << bNoSourceBitmap);
986
8.89k
                if (nFunc == W_META_STRETCHDIB)
987
1.83k
                {
988
1.83k
                    if (nRecordSize < 15)
989
4
                        bRecordOk = false;
990
1.83k
                    mpInputStream->ReadUInt16(nColorUsage);
991
1.83k
                }
992
993
                // nSrcHeight and nSrcWidth is the number of pixels that has to been used
994
                // If they are set to zero, it is as indicator not to scale the bitmap later
995
8.89k
                if( nFunc == W_META_DIBSTRETCHBLT ||
996
7.29k
                    nFunc == W_META_STRETCHDIB )
997
3.43k
                    mpInputStream->ReadInt16( nSrcHeight ).ReadInt16( nSrcWidth );
998
999
                // nYSrc and nXSrc is the offset of the first pixel
1000
8.89k
                mpInputStream->ReadInt16( nYSrc ).ReadInt16( nXSrc );
1001
1002
8.89k
                if ( bNoSourceBitmap )
1003
6.84k
                    mpInputStream->SeekRel( 2 ); // Skip Reserved 2 bytes (it must be ignored)
1004
1005
8.89k
                Size aDestSize( ReadYXExt() );
1006
8.89k
                if ( aDestSize.Width() && aDestSize.Height() )  // #92623# do not try to read buggy bitmaps
1007
8.66k
                {
1008
8.66k
                    tools::Rectangle aDestRect( ReadYX(), aDestSize );
1009
8.66k
                    if ( !bNoSourceBitmap )
1010
2.01k
                    {
1011
                        // tdf#142625 Read the DIBHeader and check if bitmap is supported
1012
                        // If bitmap is not supported don't run ReadDIB, as it will interrupt image processing
1013
2.01k
                        const auto nOldPos(mpInputStream->Tell());
1014
2.01k
                        sal_uInt32 nHeaderSize(0);
1015
2.01k
                        mpInputStream->ReadUInt32( nHeaderSize );
1016
2.01k
                        if ( nHeaderSize == 0xC ) // BitmapCoreHeader
1017
6
                            mpInputStream->SeekRel( 6 ); // skip Width (16), Height (16), Planes (16)
1018
2.00k
                        else
1019
2.00k
                            mpInputStream->SeekRel( 10 ); // skip Width (32), Height (32), Planes (16)
1020
2.01k
                        sal_uInt16 nBitCount(0);
1021
2.01k
                        mpInputStream->ReadUInt16( nBitCount );
1022
2.01k
                        if ( nBitCount == 0 ) // TODO Undefined BitCount (JPEG/PNG), which are not supported
1023
89
                            break;
1024
1.92k
                        mpInputStream->Seek(nOldPos);
1025
1026
1.92k
                        if ( !ReadDIB( aBmp, *mpInputStream, false ) )
1027
1.92k
                            SAL_WARN( "emfio", "\tTODO Read DIB failed. Interrupting processing whole image. Please report bug report." );
1028
1.92k
                    }
1029
                    // test if it is sensible to crop
1030
8.58k
                    if ( nSrcHeight && nSrcWidth &&
1031
1.45k
                            ( nXSrc + nSrcWidth <= aBmp.GetSizePixel().Width() ) &&
1032
1.06k
                            ( nYSrc + nSrcHeight <= aBmp.GetSizePixel().Height() ) )
1033
911
                    {
1034
911
                        tools::Rectangle aCropRect( Point( nXSrc, nYSrc ), Size( nSrcWidth, nSrcHeight ) );
1035
911
                        aBmp.Crop( aCropRect );
1036
911
                    }
1037
1038
8.58k
                    maBmpSaveList.emplace_back(aBmp, aDestRect, nRasterOperation);
1039
8.58k
                }
1040
8.89k
            }
1041
8.80k
            break;
1042
1043
8.80k
            case W_META_DIBCREATEPATTERNBRUSH:
1044
2.53k
            {
1045
2.53k
                Bitmap  aBmp;
1046
2.53k
                sal_uInt16 nStyle(0), nColorUsage(0);
1047
1048
2.53k
                if (nRecordSize < 5)
1049
620
                    bRecordOk = false;
1050
2.53k
                mpInputStream->ReadUInt16( nStyle ).ReadUInt16( nColorUsage );
1051
2.53k
                BrushStyle eStyle = static_cast<BrushStyle>(nStyle);
1052
2.53k
                SAL_INFO( "emfio", "\t\t Style:" << nStyle << ", ColorUsage: " << nColorUsage );
1053
                // Per [MS-WMF] 2.3.4.8, BS_PATTERN means the Target is a
1054
                // Bitmap16 and other styles mean a DIB. In practice many
1055
                // generators write a DIB even with Style == BS_PATTERN, so
1056
                // peek at the leading DWORD: a known DIB header size means
1057
                // a DIB; otherwise fall back to Bitmap16.
1058
2.53k
                bool bIsDib = true;
1059
2.53k
                if ( eStyle == BrushStyle::BS_PATTERN )
1060
110
                {
1061
                    // The leading DWORD of a DIB header is its own size,
1062
                    // and only a small set of values is valid:
1063
                    //   12  BITMAPCOREHEADER
1064
                    //   40  BITMAPINFOHEADER
1065
                    //   52  BITMAPV2INFOHEADER (Adobe extension)
1066
                    //   56  BITMAPV3INFOHEADER (Adobe extension)
1067
                    //   64  OS22XBITMAPHEADER (OS/2 2.x)
1068
                    //   108 BITMAPV4HEADER
1069
                    //   124 BITMAPV5HEADER
1070
                    // A leading DWORD outside this set means the Target is
1071
                    // a Bitmap16, not a DIB.
1072
110
                    sal_uInt32 nProbe(0);
1073
110
                    const sal_uInt64 nProbePos = mpInputStream->Tell();
1074
110
                    mpInputStream->ReadUInt32( nProbe );
1075
110
                    mpInputStream->Seek( nProbePos );
1076
110
                    bIsDib = (nProbe == 12 || nProbe == 40 || nProbe == 52
1077
103
                            || nProbe == 56 || nProbe == 64 || nProbe == 108
1078
101
                            || nProbe == 124);
1079
110
                }
1080
2.53k
                if ( !bIsDib )
1081
101
                    aBmp = CreateBitmap16( *mpInputStream, 10 );
1082
2.43k
                else if ( !ReadDIB( aBmp, *mpInputStream, false ) )
1083
763
                    SAL_WARN( "emfio", "\tTODO Read DIB failed. Interrupting processing whole image. Please report bug report." );
1084
2.53k
                if ( aBmp.IsEmpty() )
1085
860
                    CreateObject();
1086
1.67k
                else
1087
1.67k
                    CreateObject(std::make_unique<WinMtfFillStyle>( aBmp ));
1088
2.53k
            }
1089
0
            break;
1090
1091
7.38k
            case W_META_DELETEOBJECT:
1092
7.38k
            {
1093
7.38k
                if (nRecordSize != 4)
1094
7
                    bRecordOk = false;
1095
7.38k
                sal_uInt16 nIndex = 0;
1096
7.38k
                mpInputStream->ReadUInt16( nIndex );
1097
7.38k
                DeleteObject( nIndex );
1098
7.38k
            }
1099
7.38k
            break;
1100
1101
1.01k
            case W_META_CREATEPALETTE:
1102
1.01k
            {
1103
1.01k
                sal_uInt16 nStart = 0;
1104
1.01k
                sal_uInt16 nNumberOfEntries = 0;
1105
1.01k
                mpInputStream->ReadUInt16(nStart);
1106
1.01k
                mpInputStream->ReadUInt16(nNumberOfEntries);
1107
1108
1.01k
                if (nRecordSize != 2u * nNumberOfEntries + 5u)
1109
30
                    bRecordOk = false;
1110
1.01k
                SAL_INFO("emfio", "\t\t Start 0x" << std::hex << nStart << std::dec << ", Number of entries: " << nNumberOfEntries);
1111
1.01k
                sal_uInt32 nPalleteEntry;
1112
1.01k
                std::vector< Color > aPaletteColors;
1113
684k
                for (sal_uInt16 i = 0; i < nNumberOfEntries; ++i)
1114
683k
                {
1115
                    //PALETTEENTRY: Values, Blue, Green, Red
1116
683k
                    mpInputStream->ReadUInt32( nPalleteEntry );
1117
683k
                    SAL_INFO("emfio", "\t\t " << i << ". Palette entry: " << std::setw(10) << std::showbase <<std::hex << nPalleteEntry << std::dec );
1118
683k
                    aPaletteColors.emplace_back(static_cast<sal_uInt8>(nPalleteEntry), static_cast<sal_uInt8>(nPalleteEntry >> 8), static_cast<sal_uInt8>(nPalleteEntry >> 16));
1119
683k
                }
1120
1.01k
                CreateObject(std::make_unique<WinMtfPalette>( aPaletteColors ));
1121
1.01k
            }
1122
0
            break;
1123
1124
6.70k
            case W_META_CREATEBRUSH:
1125
6.70k
            {
1126
6.70k
                SAL_WARN( "emfio", "TODO: Not implemented. Please fill the bug report" );
1127
6.70k
                CreateObject(std::make_unique<WinMtfFillStyle>( COL_WHITE, false ));
1128
6.70k
            }
1129
0
            break;
1130
1131
318
            case W_META_CREATEPATTERNBRUSH:
1132
318
            {
1133
                // [MS-WMF] 2.3.4.4: Pattern is a 32-byte legacy BITMAP
1134
                // struct (with bmBits placeholder + reserved padding)
1135
                // followed by the actual bits.
1136
318
                Bitmap aBmp = CreateBitmap16( *mpInputStream, 32 );
1137
318
                if ( aBmp.IsEmpty() )
1138
318
                    CreateObject(std::make_unique<WinMtfFillStyle>( COL_WHITE, false ));
1139
0
                else
1140
0
                    CreateObject(std::make_unique<WinMtfFillStyle>( aBmp ));
1141
318
            }
1142
318
            break;
1143
1144
5.94k
            case W_META_CREATEPENINDIRECT:
1145
5.94k
            {
1146
                // FIXME For some WMF correct size is 8 and for some 9
1147
5.94k
                if ((nRecordSize != 8) && (nRecordSize != 9))
1148
14
                    bRecordOk = false;
1149
5.94k
                LineInfo aLineInfo;
1150
5.94k
                sal_uInt16 nStyle = 0;
1151
5.94k
                sal_uInt16 nWidth = 0;
1152
5.94k
                sal_uInt16 nHeight = 0;
1153
1154
5.94k
                mpInputStream->ReadUInt16(nStyle);
1155
5.94k
                mpInputStream->ReadUInt16(nWidth);
1156
5.94k
                mpInputStream->ReadUInt16(nHeight);
1157
5.94k
                CreateObject(std::make_unique<WinMtfLineStyle>(ReadColor(), nStyle, nWidth));
1158
5.94k
            }
1159
5.94k
            break;
1160
1161
2.44k
            case W_META_CREATEBRUSHINDIRECT:
1162
2.44k
            {
1163
2.44k
                if (nRecordSize != 7)
1164
14
                    bRecordOk = false;
1165
2.44k
                sal_uInt16 nBrushStyle = 0;
1166
2.44k
                mpInputStream->ReadUInt16( nBrushStyle );
1167
2.44k
                BrushStyle eBrushStyle = static_cast<BrushStyle>(nBrushStyle);
1168
2.44k
                Color aColor = ReadColor();
1169
2.44k
                sal_uInt16 nHatch(0);
1170
2.44k
                mpInputStream->ReadUInt16( nHatch );
1171
2.44k
                if (eBrushStyle == BrushStyle::BS_HATCHED)
1172
74
                    CreateObject(std::make_unique<WinMtfFillStyle>( aColor, mapWindowsHatch(nHatch, aColor) ));
1173
2.37k
                else
1174
2.37k
                    CreateObject(std::make_unique<WinMtfFillStyle>( aColor, eBrushStyle == BrushStyle::BS_NULL ));
1175
2.44k
            }
1176
2.44k
            break;
1177
1178
16.7k
            case W_META_CREATEFONTINDIRECT:
1179
16.7k
            {
1180
16.7k
                Size aFontSize;
1181
16.7k
                char lfFaceName[LF_FACESIZE+1];
1182
16.7k
                sal_Int16 lfEscapement = 0;
1183
16.7k
                sal_Int16 lfOrientation = 0;
1184
16.7k
                sal_Int16 lfWeight = 0;
1185
1186
16.7k
                LOGFONTW aLogFont;
1187
16.7k
                aFontSize = ReadYXExt();
1188
16.7k
                mpInputStream->ReadInt16( lfEscapement );
1189
16.7k
                mpInputStream->ReadInt16( lfOrientation );
1190
16.7k
                mpInputStream->ReadInt16( lfWeight );
1191
16.7k
                mpInputStream->ReadUChar( aLogFont.lfItalic );
1192
16.7k
                mpInputStream->ReadUChar( aLogFont.lfUnderline );
1193
16.7k
                mpInputStream->ReadUChar( aLogFont.lfStrikeOut );
1194
16.7k
                mpInputStream->ReadUChar( aLogFont.lfCharSet );
1195
16.7k
                mpInputStream->ReadUChar( aLogFont.lfOutPrecision );
1196
16.7k
                mpInputStream->ReadUChar( aLogFont.lfClipPrecision );
1197
16.7k
                mpInputStream->ReadUChar( aLogFont.lfQuality );
1198
16.7k
                mpInputStream->ReadUChar( aLogFont.lfPitchAndFamily );
1199
16.7k
                size_t nRet = mpInputStream->ReadBytes( lfFaceName, LF_FACESIZE );
1200
16.7k
                lfFaceName[nRet] = 0;
1201
16.7k
                aLogFont.lfWidth = aFontSize.Width();
1202
16.7k
                aLogFont.lfHeight = aFontSize.Height();
1203
16.7k
                aLogFont.lfEscapement = lfEscapement;
1204
16.7k
                aLogFont.lfOrientation = lfOrientation;
1205
16.7k
                aLogFont.lfWeight = lfWeight;
1206
1207
16.7k
                rtl_TextEncoding eCharSet;
1208
16.7k
                if ( ( aLogFont.lfCharSet == OEM_CHARSET ) || ( aLogFont.lfCharSet == DEFAULT_CHARSET ) )
1209
1.67k
                    eCharSet = osl_getThreadTextEncoding();
1210
15.1k
                else
1211
15.1k
                    eCharSet = rtl_getTextEncodingFromWindowsCharset( aLogFont.lfCharSet );
1212
16.7k
                if ( eCharSet == RTL_TEXTENCODING_DONTKNOW )
1213
5.08k
                    eCharSet = osl_getThreadTextEncoding();
1214
16.7k
                if ( eCharSet == RTL_TEXTENCODING_SYMBOL )
1215
2.07k
                    eCharSet = RTL_TEXTENCODING_MS_1252;
1216
16.7k
                size_t nLength = strlen(lfFaceName);
1217
16.7k
                aLogFont.alfFaceName = OUString( lfFaceName, nLength, eCharSet );
1218
16.7k
                SAL_INFO("emfio", "\tFacename: " << lfFaceName);
1219
1220
16.7k
                if ((nRecordSize < 12) || (nRecordSize > 28))
1221
173
                    bRecordOk = false;
1222
16.6k
                else
1223
16.6k
                    CreateObject(std::make_unique<WinMtfFontStyle>(aLogFont));
1224
16.7k
            }
1225
0
            break;
1226
1227
387
            case W_META_CREATEBITMAPINDIRECT:
1228
387
            {
1229
387
                SAL_WARN( "emfio", "TODO: W_META_CREATEBITMAPINDIRECT is not implemented. Please fill the bug report" );
1230
387
                CreateObject();
1231
387
            }
1232
0
            break;
1233
1234
1.60k
            case W_META_CREATEBITMAP:
1235
1.60k
            {
1236
1.60k
                SAL_WARN( "emfio", "TODO: W_META_CREATEBITMAP is not implemented. Please fill the bug report" );
1237
1.60k
                CreateObject();
1238
1.60k
            }
1239
0
            break;
1240
1241
241
            case W_META_CREATEREGION:
1242
241
            {
1243
241
                SAL_WARN( "emfio", "TODO: W_META_CREATEREGION is not implemented. Please fill the bug report" );
1244
241
                CreateObject();
1245
241
            }
1246
0
            break;
1247
1248
473
            case W_META_EXCLUDECLIPRECT:
1249
473
            {
1250
473
                if (nRecordSize != 7)
1251
4
                    bRecordOk = false;
1252
473
                SAL_WARN("emfio", "TODO:  Not working correctly. Please fill the bug report");
1253
473
                ExcludeClipRect(ReadRectangle());
1254
473
            }
1255
0
            break;
1256
1257
221
            case W_META_PATBLT:
1258
221
            {
1259
221
                if (nRecordSize != 9)
1260
51
                    bRecordOk = false;
1261
221
                sal_uInt32 nROP = 0;
1262
221
                mpInputStream->ReadUInt32( nROP );
1263
221
                Size aSize = ReadYXExt();
1264
221
                WMFRasterOp nOldROP = SetRasterOp( static_cast<WMFRasterOp>(nROP) );
1265
221
                DrawRect( tools::Rectangle( ReadYX(), aSize ), false );
1266
221
                SetRasterOp( nOldROP );
1267
221
            }
1268
221
            break;
1269
1270
943
            case W_META_SELECTCLIPREGION:
1271
943
            {
1272
943
                if (nRecordSize != 4)
1273
1
                    bRecordOk = false;
1274
943
                sal_uInt16 nObjIndex = 0;
1275
943
                mpInputStream->ReadUInt16( nObjIndex );
1276
943
                SAL_WARN( "emfio", "TODO: W_META_SELECTCLIPREGION is not implemented. Please fill the bug report" );
1277
943
                if ( !nObjIndex )
1278
826
                {
1279
826
                    tools::PolyPolygon aEmptyPolyPoly;
1280
826
                    SetClipPath( aEmptyPolyPoly, RegionMode::RGN_COPY, true );
1281
826
                }
1282
943
            }
1283
0
            break;
1284
1285
7.37k
            case W_META_ESCAPE:
1286
7.37k
            {
1287
7.37k
                sal_uInt64 nMetaRecSize = static_cast<sal_uInt64>(nRecordSize - 2) * 2;
1288
7.37k
                sal_uInt64 nMetaRecEndPos = mpInputStream->Tell() + nMetaRecSize;
1289
1290
                // taking care that nRecordSize does not exceed the maximal stream position
1291
7.37k
                if (nMetaRecEndPos > mnEndPos)
1292
0
                {
1293
0
                    mpInputStream->SetError(SVSTREAM_FILEFORMAT_ERROR);
1294
0
                    break;
1295
0
                }
1296
7.37k
                sal_uInt16 nMode = 0, nLen = 0;
1297
7.37k
                mpInputStream->ReadUInt16(nMode).ReadUInt16(nLen);
1298
7.37k
                if (nRecordSize != ((nLen + 1u) >> 1u) + 5u)
1299
11
                {
1300
11
                    bRecordOk = false;
1301
11
                    break;
1302
11
                }
1303
7.36k
                if ((nMode == W_MFCOMMENT) && (nLen >= 4))
1304
6.64k
                {
1305
6.64k
                    sal_uInt32 nNewMagic = 0; // we have to read int32 for
1306
                    // META_ESCAPE_ENHANCED_METAFILE CommentIdentifier
1307
6.64k
                    mpInputStream->ReadUInt32(nNewMagic);
1308
1309
6.64k
                    if (nNewMagic == 0x2c2a4f4f && nLen >= 14)
1310
1.25k
                    {
1311
1.25k
                        sal_uInt16 nMagic2 = 0;
1312
1.25k
                        mpInputStream->ReadUInt16(nMagic2);
1313
1.25k
                        if (nMagic2 == 0x0a) // 2nd half of magic
1314
1.14k
                        { // continue with private escape
1315
1.14k
                            sal_uInt32 nCheck = 0, nEsc = 0;
1316
1.14k
                            mpInputStream->ReadUInt32(nCheck).ReadUInt32(nEsc);
1317
1318
1.14k
                            sal_uInt32 nEscLen = nLen - 14;
1319
1.14k
                            if (nEscLen <= (nRecordSize * 2))
1320
1.14k
                            {
1321
#ifdef OSL_BIGENDIAN
1322
                                sal_uInt32 nTmp = OSL_SWAPDWORD(nEsc);
1323
                                sal_uInt32 nCheckSum = rtl_crc32(0, &nTmp, 4);
1324
#else
1325
1.14k
                                sal_uInt32 nCheckSum = rtl_crc32(0, &nEsc, 4);
1326
1.14k
#endif
1327
1.14k
                                std::unique_ptr<sal_Int8[]> pData;
1328
1329
1.14k
                                if ((static_cast<sal_uInt64>(nEscLen) + mpInputStream->Tell())
1330
1.14k
                                    > nMetaRecEndPos)
1331
0
                                {
1332
0
                                    mpInputStream->SetError(SVSTREAM_FILEFORMAT_ERROR);
1333
0
                                    break;
1334
0
                                }
1335
1.14k
                                if (nEscLen > 0)
1336
1.14k
                                {
1337
1.14k
                                    pData.reset(new sal_Int8[nEscLen]);
1338
1.14k
                                    mpInputStream->ReadBytes(pData.get(), nEscLen);
1339
1.14k
                                    nCheckSum = rtl_crc32(nCheckSum, pData.get(), nEscLen);
1340
1.14k
                                }
1341
1.14k
                                if (nCheck == nCheckSum)
1342
50
                                {
1343
50
                                    switch (nEsc)
1344
50
                                    {
1345
0
                                        case PRIVATE_ESCAPE_UNICODE:
1346
0
                                        {
1347
                                            // we will use text instead of polygons only if we have the correct font
1348
0
                                            if (Application::GetDefaultDevice()->IsFontAvailable(
1349
0
                                                    GetFont().GetFamilyName()))
1350
0
                                            {
1351
0
                                                Point aPt;
1352
0
                                                sal_uInt32 nStringLen, nDXCount;
1353
0
                                                KernArray aDXAry;
1354
0
                                                SvMemoryStream aMemoryStream(nEscLen);
1355
0
                                                aMemoryStream.WriteBytes(pData.get(), nEscLen);
1356
0
                                                aMemoryStream.Seek(STREAM_SEEK_TO_BEGIN);
1357
0
                                                sal_Int32 nTmpX(0), nTmpY(0);
1358
0
                                                aMemoryStream.ReadInt32(nTmpX)
1359
0
                                                    .ReadInt32(nTmpY)
1360
0
                                                    .ReadUInt32(nStringLen);
1361
0
                                                aPt.setX(nTmpX);
1362
0
                                                aPt.setY(nTmpY);
1363
1364
0
                                                if ((static_cast<sal_uInt64>(nStringLen)
1365
0
                                                    * sizeof(sal_Unicode))
1366
0
                                                    < (nEscLen - aMemoryStream.Tell()))
1367
0
                                                {
1368
0
                                                    OUString aString = read_uInt16s_ToOUString(
1369
0
                                                        aMemoryStream, nStringLen);
1370
0
                                                    aMemoryStream.ReadUInt32(nDXCount);
1371
0
                                                    if ((static_cast<sal_uInt64>(nDXCount)
1372
0
                                                        * sizeof(sal_Int32))
1373
0
                                                        >= (nEscLen - aMemoryStream.Tell()))
1374
0
                                                        nDXCount = 0;
1375
0
                                                    if (nDXCount)
1376
0
                                                        aDXAry.resize(nDXCount);
1377
0
                                                    for (sal_uInt32 i = 0; i < nDXCount; i++)
1378
0
                                                    {
1379
0
                                                        sal_Int32 val;
1380
0
                                                        aMemoryStream.ReadInt32(val);
1381
0
                                                        aDXAry[i] = val;
1382
0
                                                    }
1383
0
                                                    aMemoryStream.ReadUInt32(mnSkipActions);
1384
0
                                                    DrawText(aPt, aString,
1385
0
                                                             aDXAry.empty() ? nullptr : &aDXAry);
1386
0
                                                }
1387
0
                                            }
1388
0
                                        }
1389
0
                                        break;
1390
50
                                    }
1391
50
                                }
1392
1.14k
                            }
1393
1.14k
                        }
1394
1.25k
                    }
1395
5.39k
                    else if ((nNewMagic == static_cast<sal_uInt32>(0x43464D57)) && (nLen >= 34)
1396
2.28k
                            && (static_cast<sal_Int32>(nLen + 10)
1397
2.28k
                                <= static_cast<sal_Int32>(nRecordSize * 2)))
1398
2.28k
                    {
1399
2.28k
                        sal_uInt32 nComType = 0, nVersion = 0, nFlags = 0, nComRecCount = 0,
1400
2.28k
                                nCurRecSize = 0, nRemainingSize = 0, nEMFTotalSize = 0;
1401
2.28k
                        sal_uInt16 nCheck = 0;
1402
1403
2.28k
                        mpInputStream->ReadUInt32(nComType)
1404
2.28k
                            .ReadUInt32(nVersion)
1405
2.28k
                            .ReadUInt16(nCheck)
1406
2.28k
                            .ReadUInt32(nFlags)
1407
2.28k
                            .ReadUInt32(nComRecCount)
1408
2.28k
                            .ReadUInt32(nCurRecSize)
1409
2.28k
                            .ReadUInt32(nRemainingSize)
1410
2.28k
                            .ReadUInt32(
1411
2.28k
                                nEMFTotalSize); // the nRemainingSize is not mentioned in MSDN documentation
1412
                            // but it seems to be required to read in data produced by OLE
1413
1414
2.28k
                        if (nComType == 0x01 && nVersion == 0x10000 && nComRecCount)
1415
736
                        {
1416
736
                            if (!mnEMFRec)
1417
275
                            { // first EMF comment
1418
275
                                mnEMFRecCount = nComRecCount;
1419
275
                                mnEMFSize = nEMFTotalSize;
1420
275
                                if (mnEMFSize > mpInputStream->remainingSize())
1421
22
                                {
1422
22
                                    SAL_WARN("emfio",
1423
22
                                            "emf size claims to be larger than remaining data");
1424
22
                                    mpEMFStream.reset();
1425
22
                                }
1426
253
                                else
1427
253
                                    mpEMFStream = std::vector<sal_uInt8>();
1428
275
                            }
1429
461
                            else if ((mnEMFRecCount != nComRecCount)
1430
351
                                    || (mnEMFSize != nEMFTotalSize)) // add additional checks here
1431
173
                            {
1432
                                // total records should be the same as in previous comments
1433
173
                                mnEMFRecCount = 0xFFFFFFFF;
1434
173
                                mpEMFStream.reset();
1435
173
                            }
1436
736
                            mnEMFRec++;
1437
1438
736
                            if (mpEMFStream && nCurRecSize + 34 > nLen)
1439
16
                            {
1440
16
                                mnEMFRecCount = 0xFFFFFFFF;
1441
16
                                mpEMFStream.reset();
1442
16
                            }
1443
1444
736
                            if (mpEMFStream && nCurRecSize > mpInputStream->remainingSize())
1445
2
                            {
1446
2
                                SAL_WARN("emfio",
1447
2
                                        "emf record size claims to be larger than remaining data");
1448
2
                                mnEMFRecCount = 0xFFFFFFFF;
1449
2
                                mpEMFStream.reset();
1450
2
                            }
1451
1452
736
                            if (mpEMFStream)
1453
523
                            {
1454
523
                                std::vector<sal_Int8> aBuf(nCurRecSize);
1455
523
                                sal_uInt32 nCount = mpInputStream->ReadBytes(aBuf.data(), nCurRecSize);
1456
523
                                if (nCount == nCurRecSize)
1457
523
                                {
1458
523
                                    mpEMFStream->insert(mpEMFStream->end(), aBuf.begin(), aBuf.end());
1459
523
                                }
1460
523
                            }
1461
736
                        }
1462
2.28k
                    }
1463
6.64k
                }
1464
7.36k
            }
1465
7.36k
            break;
1466
1467
7.36k
            case W_META_SETPOLYFILLMODE:
1468
1.75k
            {
1469
1.75k
                if ((nRecordSize != 4) && (nRecordSize != 5))
1470
1
                    bRecordOk = false;
1471
1.75k
                sal_uInt16 nDat = 0;
1472
1.75k
                mpInputStream->ReadUInt16( nDat );
1473
1.75k
                SetPolyFillMode( nDat );
1474
1.75k
            }
1475
1.75k
            break;
1476
1477
0
            case W_META_SETRELABS:
1478
28
            case W_META_SETSTRETCHBLTMODE:
1479
28
            case W_META_SETTEXTCHAREXTRA:
1480
28
            case W_META_SETTEXTJUSTIFICATION:
1481
28
            case W_META_FLOODFILL:
1482
31
            case W_META_FILLREGION:
1483
31
            case W_META_FRAMEREGION:
1484
31
            case W_META_INVERTREGION:
1485
31
            case W_META_PAINTREGION:
1486
31
            case W_META_DRAWTEXT:
1487
150
            case W_META_SETMAPPERFLAGS:
1488
150
            case W_META_SETDIBTODEV:
1489
3.44k
            case W_META_REALIZEPALETTE:
1490
3.44k
            case W_META_ANIMATEPALETTE:
1491
3.44k
            case W_META_SETPALENTRIES:
1492
3.44k
            case W_META_RESIZEPALETTE:
1493
3.44k
            case W_META_EXTFLOODFILL:
1494
3.44k
            case W_META_RESETDC:
1495
3.44k
            case W_META_STARTDOC:
1496
3.44k
            case W_META_STARTPAGE:
1497
3.44k
            case W_META_ENDPAGE:
1498
3.45k
            case W_META_ABORTDOC:
1499
3.45k
            case W_META_ENDDOC:
1500
3.45k
            {
1501
3.45k
                SAL_WARN("emfio", "TODO: WMF record not implemented: " << record_type_name(nFunc));
1502
3.45k
            }
1503
3.45k
            break;
1504
1505
13.2k
            default:
1506
13.2k
            {
1507
13.2k
                SAL_WARN("emfio", "Unknown Meta Action: 0x" << std::hex << nFunc << std::dec);
1508
13.2k
            }
1509
185k
        }
1510
1511
185k
        if (!bRecordOk)
1512
1.62k
        {
1513
1.62k
            SAL_WARN("emfio", "WMF validation failed, record: " <<
1514
1.62k
                              record_type_name(nFunc) << ", size: " << nRecordSize);
1515
1.62k
            mpInputStream->SetError(SVSTREAM_FILEFORMAT_ERROR);
1516
1.62k
        }
1517
1518
        // tdf#127471
1519
185k
        maScaledFontHelper.applyAlternativeFontScale();
1520
185k
    }
1521
1522
    const tools::Long   aMaxWidth = 1024;
1523
1524
    bool WmfReader::ReadHeader()
1525
8.25k
    {
1526
8.25k
        sal_uInt64 const nStrmPos = mpInputStream->Tell();
1527
1528
8.25k
        sal_uInt32 nPlaceableMetaKey(0);
1529
        // if available read the METAFILEHEADER
1530
8.25k
        mpInputStream->ReadUInt32( nPlaceableMetaKey );
1531
8.25k
        if (!mpInputStream->good())
1532
6
            return false;
1533
1534
8.25k
        tools::Rectangle aPlaceableBound;
1535
1536
8.25k
        mbPlaceable = nPlaceableMetaKey == 0x9ac6cdd7L;
1537
1538
8.25k
        SAL_INFO("emfio", "Placeable: \"" << (mbPlaceable ? "yes" : "no") << "\"");
1539
1540
8.25k
        if (mbPlaceable)
1541
933
        {
1542
            //TODO do some real error handling here
1543
933
            sal_Int16 nVal(0);
1544
1545
            // Skip reserved bytes
1546
933
            mpInputStream->SeekRel(2);
1547
1548
            // BoundRect
1549
            // These are simply ignored for now
1550
933
            mpInputStream->ReadInt16( nVal );
1551
933
            aPlaceableBound.SetLeft( nVal );
1552
933
            mpInputStream->ReadInt16( nVal );
1553
933
            aPlaceableBound.SetTop( nVal );
1554
933
            mpInputStream->ReadInt16( nVal );
1555
933
            aPlaceableBound.SetRight( nVal );
1556
933
            mpInputStream->ReadInt16( nVal );
1557
933
            aPlaceableBound.SetBottom( nVal );
1558
1559
            // inch
1560
933
            mpInputStream->ReadUInt16( mnUnitsPerInch );
1561
1562
933
            SAL_WARN_IF(!mnUnitsPerInch, "emfio", "Invalid WMF: mnUnitsPerInch is 0");
1563
1564
            // reserved
1565
933
            mpInputStream->SeekRel( 4 );
1566
1567
            // Skip and don't check the checksum
1568
933
            mpInputStream->SeekRel( 2 );
1569
1570
            // Skip wmf header
1571
933
            mpInputStream->Seek( nStrmPos + 40 );    // set the streampos to the start of the metaactions
1572
933
            GetPlaceableBound( aPlaceableBound, mpInputStream );
1573
            // Go back to the place after placeable header
1574
933
            mpInputStream->Seek( nStrmPos + 22);
1575
933
        }
1576
7.32k
        else
1577
7.32k
        {
1578
            // Default is 1440, but it is set to 96 to show the wmf larger
1579
7.32k
            mnUnitsPerInch = 96;
1580
1581
7.32k
            if (mpExternalHeader != nullptr
1582
0
                && mpExternalHeader->xExt > 0
1583
0
                && mpExternalHeader->yExt > 0
1584
0
                && (mpExternalHeader->mapMode == MappingMode::MM_ISOTROPIC || mpExternalHeader->mapMode == MappingMode::MM_ANISOTROPIC))
1585
0
            {
1586
                // #n417818#: If we have an external header then overwrite the bounds!
1587
0
                tools::Rectangle aExtRect(0, 0,
1588
0
                    o3tl::convert(mpExternalHeader->xExt, o3tl::Length::mm100, o3tl::Length::px),
1589
0
                    o3tl::convert(mpExternalHeader->yExt, o3tl::Length::mm100, o3tl::Length::px));
1590
0
                aPlaceableBound = aExtRect;
1591
1592
0
                SAL_INFO("emfio", "External header size "
1593
0
                    " left: " << aPlaceableBound.Left() << " top: " << aPlaceableBound.Top()
1594
0
                    << " right: " << aPlaceableBound.Right() << " bottom: " << aPlaceableBound.Bottom());
1595
1596
0
                SetMapMode(static_cast<MappingMode>(mpExternalHeader->mapMode));;
1597
0
            }
1598
7.32k
            else
1599
7.32k
            {
1600
7.32k
                mpInputStream->Seek(nStrmPos + 18);    // set the streampos to the start of the metaactions
1601
7.32k
                GetPlaceableBound(aPlaceableBound, mpInputStream);
1602
1603
                // The image size is not known so normalize the calculated bounds so that the
1604
                // resulting image is not too big
1605
7.32k
                if (aPlaceableBound.GetWidth() > aMaxWidth)
1606
5.14k
                {
1607
5.14k
                    const double fMaxWidth = static_cast<double>(aMaxWidth);
1608
5.14k
                    double fRatio = aPlaceableBound.GetWidth() / fMaxWidth;
1609
1610
                    // changing mnUnitsPerInch as a tool to scale wmf
1611
5.14k
                    mnUnitsPerInch *= fRatio;
1612
1613
5.14k
                }
1614
7.32k
                SAL_INFO("emfio", "Placeable bounds "
1615
7.32k
                                  " left: " << aPlaceableBound.Left() << " top: " << aPlaceableBound.Top() <<
1616
7.32k
                                  " right: " << aPlaceableBound.Right() << " bottom: " << aPlaceableBound.Bottom());
1617
7.32k
            }
1618
1619
7.32k
            mpInputStream->Seek( nStrmPos );
1620
7.32k
        }
1621
1622
8.25k
        SetWinOrg( aPlaceableBound.TopLeft() );
1623
8.25k
        Size aWMFSize(
1624
8.25k
            std::abs( aPlaceableBound.GetWidth() ), std::abs( aPlaceableBound.GetHeight() ) );
1625
8.25k
        SetWinExt( aWMFSize );
1626
1627
8.25k
        SAL_INFO("emfio", "WMF size  w: " << aWMFSize.Width()    << " h: " << aWMFSize.Height());
1628
1629
8.25k
        Size aDevExt( 10000, 10000 );
1630
8.25k
        if( ( std::abs( aWMFSize.Width() ) > 1 ) && ( std::abs( aWMFSize.Height() ) > 1 ) && mnUnitsPerInch )
1631
6.29k
        {
1632
6.29k
            const double    fFrac = 1.0 / mnUnitsPerInch;
1633
6.29k
            MapMode         aWMFMap( MapUnit::MapInch, Point(), fFrac, fFrac );
1634
6.29k
            Size            aSize100(OutputDevice::LogicToLogic(aWMFSize, aWMFMap, MapMode(MapUnit::Map100thMM)));
1635
6.29k
            aDevExt = Size( std::abs( aSize100.Width() ), std::abs( aSize100.Height() ) );
1636
6.29k
        }
1637
8.25k
        SetDevExt( aDevExt );
1638
1639
8.25k
        SAL_INFO("emfio", "Dev size  w: " << aDevExt.Width()    << " h: " << aDevExt.Height());
1640
1641
        // read the METAHEADER
1642
8.25k
        sal_uInt32 nMetaKey(0);
1643
8.25k
        mpInputStream->ReadUInt32( nMetaKey ); // type and headersize
1644
8.25k
        if (!mpInputStream->good())
1645
1.88k
            return false;
1646
6.36k
        if (nMetaKey != 0x00090001)
1647
3.79k
        {
1648
3.79k
            sal_uInt16 aNextWord(0);
1649
3.79k
            mpInputStream->ReadUInt16( aNextWord );
1650
3.79k
            if (nMetaKey != 0x10000 || aNextWord != 0x09)
1651
196
            {
1652
196
                mpInputStream->SetError( SVSTREAM_FILEFORMAT_ERROR );
1653
196
                return false;
1654
196
            }
1655
3.79k
        }
1656
1657
6.17k
        mpInputStream->SeekRel( 2 ); // Version (of Windows)
1658
6.17k
        mpInputStream->SeekRel( 4 ); // Size (of file in words)
1659
6.17k
        mpInputStream->SeekRel( 2 ); // NoObjects (maximum number of simultaneous objects)
1660
6.17k
        mpInputStream->SeekRel( 4 ); // MaxRecord (size of largest record in words)
1661
6.17k
        mpInputStream->SeekRel( 2 ); // NoParameters (Unused
1662
1663
6.17k
        return mpInputStream->good();
1664
6.36k
    }
1665
1666
    void WmfReader::ReadWMF()
1667
8.25k
    {
1668
8.25k
        sal_uInt16  nFunction;
1669
1670
8.25k
        mnSkipActions = 0;
1671
1672
8.25k
        mpEMFStream.reset();
1673
8.25k
        mnEMFRecCount = 0;
1674
8.25k
        mnEMFRec = 0;
1675
8.25k
        mnEMFSize = 0;
1676
1677
8.25k
        SetMapMode( MappingMode::MM_ANISOTROPIC );
1678
8.25k
        SetWinOrg( Point() );
1679
8.25k
        SetWinExt( Size( 1, 1 ) );
1680
8.25k
        SetDevExt( Size( 10000, 10000 ) );
1681
1682
8.25k
        mnEndPos=mpInputStream->TellEnd();
1683
8.25k
        mpInputStream->Seek( mnStartPos );
1684
1685
8.25k
        if ( ReadHeader( ) )
1686
6.17k
        {
1687
6.17k
            auto nPos = mpInputStream->Tell();
1688
1689
6.17k
            if( mnEndPos - mnStartPos )
1690
6.17k
            {
1691
6.17k
                bool bEMFAvailable = false;
1692
192k
                while( !mpInputStream->eof() )
1693
192k
                {
1694
192k
                    mpInputStream->ReadUInt32(mnRecSize).ReadUInt16( nFunction );
1695
1696
192k
                    if (!mpInputStream->good() || (mnRecSize < 3) || (nFunction == W_META_EOF))
1697
4.64k
                    {
1698
4.64k
                        if (mpInputStream->eof())
1699
2.54k
                            mpInputStream->SetError(SVSTREAM_FILEFORMAT_ERROR);
1700
1701
4.64k
                        break;
1702
4.64k
                    }
1703
1704
187k
                    const sal_uInt32 nAvailableBytes = mnEndPos - nPos;
1705
187k
                    const sal_uInt32 nMaxPossibleRecordSize = nAvailableBytes/2;
1706
187k
                    if (mnRecSize > nMaxPossibleRecordSize)
1707
1.23k
                    {
1708
1.23k
                        mpInputStream->SetError(SVSTREAM_FILEFORMAT_ERROR);
1709
1.23k
                        break;
1710
1.23k
                    }
1711
1712
186k
                    if ( !bEMFAvailable )
1713
185k
                    {
1714
185k
                        if(   !maBmpSaveList.empty()
1715
15.8k
                          && ( nFunction != W_META_STRETCHDIB    )
1716
14.8k
                          && ( nFunction != W_META_DIBBITBLT     )
1717
9.82k
                          && ( nFunction != W_META_DIBSTRETCHBLT )
1718
185k
                          )
1719
8.37k
                        {
1720
8.37k
                            ResolveBitmapActions( maBmpSaveList );
1721
8.37k
                        }
1722
1723
185k
                        if ( !mnSkipActions)
1724
185k
                            ReadRecordParams( mnRecSize, nFunction );
1725
0
                        else
1726
0
                            mnSkipActions--;
1727
1728
185k
                        if(mpEMFStream && mnEMFRecCount == mnEMFRec)
1729
125
                        {
1730
125
                            GDIMetaFile aMeta;
1731
125
                            SvMemoryStream aStream(mpEMFStream->data(), mpEMFStream->size(), StreamMode::STD_READ);
1732
125
                            std::unique_ptr<EmfReader> pEMFReader(std::make_unique<EmfReader>(aStream, aMeta));
1733
125
                            pEMFReader->SetEnableEMFPlus(mbEnableEMFPlus);
1734
125
                            bEMFAvailable = pEMFReader->ReadEnhWMF();
1735
125
                            pEMFReader.reset(); // destroy first!!!
1736
1737
125
                            if( bEMFAvailable )
1738
31
                            {
1739
31
                                AddFromGDIMetaFile( aMeta );
1740
31
                                SetrclFrame( tools::Rectangle( Point(0, 0), aMeta.GetPrefSize()));
1741
1742
                                // the stream needs to be set to the wmf end position,
1743
                                // otherwise the GfxLink that is created will be incorrect
1744
                                // (leading to graphic loss after swapout/swapin).
1745
                                // so we will proceed normally, but are ignoring further wmf
1746
                                // records
1747
31
                            }
1748
94
                            else
1749
94
                            {
1750
                                // something went wrong
1751
                                // continue with WMF, don't try this again
1752
94
                                mpEMFStream.reset();
1753
94
                            }
1754
125
                        }
1755
185k
                    }
1756
1757
186k
                    nPos += mnRecSize * 2;
1758
186k
                    mpInputStream->Seek(nPos);
1759
186k
                }
1760
6.17k
            }
1761
0
            else
1762
0
                mpInputStream->SetError( SVSTREAM_GENERALERROR );
1763
1764
6.17k
            if( !mpInputStream->GetError() && !maBmpSaveList.empty() )
1765
303
                ResolveBitmapActions( maBmpSaveList );
1766
6.17k
        }
1767
8.25k
        if ( mpInputStream->GetError() )
1768
6.10k
            mpInputStream->Seek( mnStartPos );
1769
8.25k
    }
1770
1771
    void WmfReader::GetPlaceableBound( tools::Rectangle& rPlaceableBound, SvStream* pStm )
1772
8.25k
    {
1773
8.25k
        bool bRet = true;
1774
1775
8.25k
        tools::Rectangle aBound;
1776
8.25k
        aBound.SetLeft( RECT_MAX );
1777
8.25k
        aBound.SetTop( RECT_MAX );
1778
8.25k
        aBound.SetRight( RECT_MIN );
1779
8.25k
        aBound.SetBottom( RECT_MIN );
1780
8.25k
        bool bBoundsDetermined = false;
1781
1782
8.25k
        auto nPos = pStm->Tell();
1783
8.25k
        auto nEnd = nPos + pStm->remainingSize();
1784
1785
8.25k
        Point aWinOrg(0,0);
1786
8.25k
        std::optional<Size>  aWinExt;
1787
1788
8.25k
        Point aViewportOrg(0,0);
1789
8.25k
        std::optional<Size>  aViewportExt;
1790
1791
8.25k
        MappingMode eMapMode = MappingMode::MM_ANISOTROPIC;
1792
1793
8.25k
        if (nEnd - nPos)
1794
8.12k
        {
1795
8.12k
            sal_uInt16 nFunction;
1796
8.12k
            sal_uInt32 nRSize;
1797
1798
119k
            while( bRet )
1799
117k
            {
1800
117k
                pStm->ReadUInt32( nRSize ).ReadUInt16( nFunction );
1801
1802
117k
                if( pStm->GetError() )
1803
30
                {
1804
30
                    bRet = false;
1805
30
                    break;
1806
30
                }
1807
117k
                else if (pStm->eof() || nRSize < 3)
1808
331
                {
1809
331
                    pStm->SetError( SVSTREAM_FILEFORMAT_ERROR );
1810
331
                    bRet = false;
1811
331
                    break;
1812
331
                }
1813
117k
                else if (nFunction == W_META_EOF)
1814
6.36k
                {
1815
6.36k
                    break;
1816
6.36k
                }
1817
1818
111k
                switch( nFunction )
1819
111k
                {
1820
1.71k
                    case W_META_SETWINDOWORG:
1821
1.71k
                    {
1822
1.71k
                        aWinOrg = ReadYX();
1823
1.71k
                    }
1824
1.71k
                    break;
1825
1826
1.63k
                    case W_META_SETWINDOWEXT:
1827
1.63k
                    {
1828
1.63k
                        sal_Int16 nWidth(0), nHeight(0);
1829
1.63k
                        pStm->ReadInt16(nHeight);
1830
1.63k
                        pStm->ReadInt16(nWidth);
1831
1.63k
                        aWinExt = Size(nWidth, nHeight);
1832
1.63k
                    }
1833
1.63k
                    break;
1834
1835
86
                    case W_META_SETVIEWPORTORG:
1836
86
                    {
1837
86
                        aViewportOrg = ReadYX();
1838
86
                    }
1839
86
                    break;
1840
1841
297
                    case W_META_SETVIEWPORTEXT:
1842
297
                    {
1843
297
                        sal_Int16 nWidth(0), nHeight(0);
1844
297
                        pStm->ReadInt16(nHeight);
1845
297
                        pStm->ReadInt16(nWidth);
1846
297
                        aViewportExt = Size(nWidth, nHeight);
1847
297
                    }
1848
297
                    break;
1849
1850
483
                    case W_META_SETMAPMODE:
1851
483
                    {
1852
483
                        sal_uInt16 nMapMode(0);
1853
483
                        pStm->ReadUInt16(nMapMode);
1854
483
                        eMapMode = static_cast<MappingMode>(nMapMode);
1855
483
                    }
1856
483
                    break;
1857
1858
2.54k
                    case W_META_MOVETO:
1859
5.12k
                    case W_META_LINETO:
1860
5.12k
                    {
1861
5.12k
                        GetWinExtMax( ReadYX(), aBound, eMapMode );
1862
5.12k
                        bBoundsDetermined = true;
1863
5.12k
                    }
1864
5.12k
                    break;
1865
1866
370
                    case W_META_RECTANGLE:
1867
929
                    case W_META_INTERSECTCLIPRECT:
1868
1.32k
                    case W_META_EXCLUDECLIPRECT:
1869
2.23k
                    case W_META_ELLIPSE:
1870
2.23k
                    {
1871
2.23k
                        GetWinExtMax( ReadRectangle(), aBound, eMapMode );
1872
2.23k
                        bBoundsDetermined = true;
1873
2.23k
                    }
1874
2.23k
                    break;
1875
1876
1.01k
                    case W_META_ROUNDRECT:
1877
1.01k
                    {
1878
1.01k
                        ReadYXExt(); // size
1879
1.01k
                        GetWinExtMax( ReadRectangle(), aBound, eMapMode );
1880
1.01k
                        bBoundsDetermined = true;
1881
1.01k
                    }
1882
1.01k
                    break;
1883
1884
2.05k
                    case W_META_ARC:
1885
2.44k
                    case W_META_PIE:
1886
2.75k
                    case W_META_CHORD:
1887
2.75k
                    {
1888
2.75k
                        ReadYX(); // end
1889
2.75k
                        ReadYX(); // start
1890
2.75k
                        GetWinExtMax( ReadRectangle(), aBound, eMapMode );
1891
2.75k
                        bBoundsDetermined = true;
1892
2.75k
                    }
1893
2.75k
                    break;
1894
1895
2.13k
                    case W_META_POLYGON:
1896
2.13k
                    {
1897
2.13k
                        bool bRecordOk = true;
1898
1899
2.13k
                        sal_uInt16 nPoints(0);
1900
2.13k
                        pStm->ReadUInt16( nPoints );
1901
1902
2.13k
                        if (nPoints > pStm->remainingSize() / (2 * sizeof(sal_uInt16)))
1903
26
                        {
1904
26
                            bRecordOk = false;
1905
26
                        }
1906
2.10k
                        else
1907
2.10k
                        {
1908
58.6k
                            for(sal_uInt16 i = 0; i < nPoints; i++ )
1909
56.5k
                            {
1910
56.5k
                                GetWinExtMax( ReadPoint(), aBound, eMapMode );
1911
56.5k
                                bBoundsDetermined = true;
1912
56.5k
                            }
1913
2.10k
                        }
1914
1915
2.13k
                        bRecordOk &= pStm->good();
1916
1917
2.13k
                        SAL_WARN_IF(!bRecordOk, "emfio", "polyline record claimed more points than the stream can provide");
1918
1919
2.13k
                        if (!bRecordOk)
1920
26
                        {
1921
26
                            pStm->SetError( SVSTREAM_FILEFORMAT_ERROR );
1922
26
                            bRet = false;
1923
26
                            break;
1924
26
                        }
1925
2.13k
                    }
1926
2.10k
                    break;
1927
1928
2.66k
                    case W_META_POLYPOLYGON:
1929
2.66k
                    {
1930
2.66k
                        bool bRecordOk = true;
1931
2.66k
                        sal_uInt16 nPoly(0), nPoints(0);
1932
2.66k
                        pStm->ReadUInt16(nPoly);
1933
2.66k
                        if (nPoly > pStm->remainingSize() / sizeof(sal_uInt16))
1934
5
                        {
1935
5
                            bRecordOk = false;
1936
5
                        }
1937
2.66k
                        else
1938
2.66k
                        {
1939
5.84k
                            for(sal_uInt16 i = 0; i < nPoly; i++ )
1940
3.18k
                            {
1941
3.18k
                                sal_uInt16 nP = 0;
1942
3.18k
                                pStm->ReadUInt16( nP );
1943
3.18k
                                if (nP > SAL_MAX_UINT16 - nPoints)
1944
5
                                {
1945
5
                                    bRecordOk = false;
1946
5
                                    break;
1947
5
                                }
1948
3.17k
                                nPoints += nP;
1949
3.17k
                            }
1950
2.66k
                        }
1951
1952
2.66k
                        SAL_WARN_IF(!bRecordOk, "emfio", "polypolygon record has more polygons than we can handle");
1953
1954
2.66k
                        bRecordOk &= pStm->good();
1955
1956
2.66k
                        if (!bRecordOk)
1957
10
                        {
1958
10
                            pStm->SetError( SVSTREAM_FILEFORMAT_ERROR );
1959
10
                            bRet = false;
1960
10
                            break;
1961
10
                        }
1962
1963
2.65k
                        if (nPoints > pStm->remainingSize() / (2 * sizeof(sal_uInt16)))
1964
14
                        {
1965
14
                            bRecordOk = false;
1966
14
                        }
1967
2.64k
                        else
1968
2.64k
                        {
1969
61.9k
                            for (sal_uInt16 i = 0; i < nPoints; i++ )
1970
59.2k
                            {
1971
59.2k
                                GetWinExtMax( ReadPoint(), aBound, eMapMode );
1972
59.2k
                                bBoundsDetermined = true;
1973
59.2k
                            }
1974
2.64k
                        }
1975
1976
2.65k
                        SAL_WARN_IF(!bRecordOk, "emfio", "polypolygon record claimed more points than the stream can provide");
1977
1978
2.65k
                        bRecordOk &= pStm->good();
1979
1980
2.65k
                        if (!bRecordOk)
1981
14
                        {
1982
14
                            pStm->SetError( SVSTREAM_FILEFORMAT_ERROR );
1983
14
                            bRet = false;
1984
14
                            break;
1985
14
                        }
1986
2.65k
                    }
1987
2.64k
                    break;
1988
1989
2.64k
                    case W_META_POLYLINE:
1990
1.36k
                    {
1991
1.36k
                        bool bRecordOk = true;
1992
1993
1.36k
                        sal_uInt16 nPoints(0);
1994
1.36k
                        pStm->ReadUInt16(nPoints);
1995
1.36k
                        if (nPoints > pStm->remainingSize() / (2 * sizeof(sal_uInt16)))
1996
5
                        {
1997
5
                            bRecordOk = false;
1998
5
                        }
1999
1.36k
                        else
2000
1.36k
                        {
2001
22.2k
                            for (sal_uInt16 i = 0; i < nPoints; ++i)
2002
20.8k
                            {
2003
20.8k
                                GetWinExtMax( ReadPoint(), aBound, eMapMode );
2004
20.8k
                                bBoundsDetermined = true;
2005
20.8k
                            }
2006
1.36k
                        }
2007
2008
1.36k
                        SAL_WARN_IF(!bRecordOk, "emfio", "polyline record claimed more points than the stream can provide");
2009
2010
1.36k
                        bRecordOk &= pStm->good();
2011
2012
1.36k
                        if (!bRecordOk)
2013
5
                        {
2014
5
                            pStm->SetError( SVSTREAM_FILEFORMAT_ERROR );
2015
5
                            bRet = false;
2016
5
                            break;
2017
5
                        }
2018
1.36k
                    }
2019
1.36k
                    break;
2020
2021
1.36k
                    case W_META_SETPIXEL:
2022
1.30k
                    {
2023
1.30k
                        ReadColor();
2024
1.30k
                        GetWinExtMax( ReadYX(), aBound, eMapMode );
2025
1.30k
                        bBoundsDetermined = true;
2026
1.30k
                    }
2027
1.30k
                    break;
2028
2029
1.13k
                    case W_META_TEXTOUT:
2030
1.13k
                    {
2031
1.13k
                        sal_uInt16 nLength(0);
2032
1.13k
                        pStm->ReadUInt16( nLength );
2033
                        // todo: we also have to take care of the text width
2034
1.13k
                        if ( nLength )
2035
945
                        {
2036
945
                            pStm->SeekRel( ( nLength + 1 ) &~ 1 );
2037
945
                            GetWinExtMax( ReadYX(), aBound, eMapMode );
2038
945
                            bBoundsDetermined = true;
2039
945
                        }
2040
1.13k
                    }
2041
1.13k
                    break;
2042
2043
15.7k
                    case W_META_EXTTEXTOUT:
2044
15.7k
                    {
2045
15.7k
                        sal_uInt16 nLen(0), nOptions;
2046
15.7k
                        Point aPosition = ReadYX();
2047
15.7k
                        pStm->ReadUInt16( nLen ).ReadUInt16( nOptions );
2048
                        // todo: we also have to take care of the text width
2049
15.7k
                        if( nLen )
2050
15.5k
                        {
2051
15.5k
                            GetWinExtMax( aPosition, aBound, eMapMode );
2052
15.5k
                            bBoundsDetermined = true;
2053
15.5k
                        }
2054
15.7k
                    }
2055
15.7k
                    break;
2056
4.97k
                    case W_META_BITBLT:
2057
7.42k
                    case W_META_DIBBITBLT:
2058
8.19k
                    case W_META_DIBSTRETCHBLT:
2059
8.32k
                    case W_META_STRETCHBLT:
2060
8.86k
                    case W_META_STRETCHDIB:
2061
8.86k
                    {
2062
8.86k
                        sal_uInt32 nRasterOperation;
2063
8.86k
                        sal_Int16 nYSrc, nXSrc;
2064
8.86k
                        sal_uInt16 nColorUsage;
2065
8.86k
                        pStm->ReadUInt32( nRasterOperation );
2066
2067
8.86k
                        if( nFunction == W_META_STRETCHDIB )
2068
543
                            pStm->ReadUInt16( nColorUsage );
2069
2070
8.86k
                        if( nFunction == W_META_DIBSTRETCHBLT ||
2071
8.09k
                            nFunction == W_META_STRETCHBLT ||
2072
7.97k
                            nFunction == W_META_STRETCHDIB )
2073
1.43k
                        {
2074
1.43k
                            sal_Int16 nSrcHeight, nSrcWidth;
2075
1.43k
                            pStm->ReadInt16( nSrcHeight ).ReadInt16( nSrcWidth );
2076
1.43k
                        }
2077
2078
                        // nYSrc and nXSrc is the offset of the first pixel
2079
8.86k
                        pStm->ReadInt16( nYSrc ).ReadInt16( nXSrc );
2080
2081
8.86k
                        const bool bNoSourceBitmap = ( nFunction != W_META_STRETCHDIB ) && ( nRSize == ( ( static_cast< sal_uInt32 >( nFunction ) >> 8 ) + 3 ) );
2082
8.86k
                        if ( bNoSourceBitmap )
2083
2.57k
                            mpInputStream->SeekRel( 2 ); // Skip Reserved 2 bytes (it must be ignored)
2084
2085
8.86k
                        Size aDestSize( ReadYXExt() );
2086
8.86k
                        if ( aDestSize.Width() && aDestSize.Height() )  // #92623# do not try to read buggy bitmaps
2087
7.23k
                        {
2088
7.23k
                            tools::Rectangle aDestRect( ReadYX(), aDestSize );
2089
7.23k
                            GetWinExtMax( aDestRect, aBound, eMapMode );
2090
7.23k
                            bBoundsDetermined = true;
2091
7.23k
                        }
2092
8.86k
                    }
2093
8.86k
                    break;
2094
2095
1.33k
                    case W_META_PATBLT:
2096
1.33k
                    {
2097
1.33k
                        sal_uInt32 nROP(0);
2098
1.33k
                        pStm->ReadUInt32( nROP );
2099
1.33k
                        Size aSize = ReadYXExt();
2100
1.33k
                        GetWinExtMax( tools::Rectangle( ReadYX(), aSize ), aBound, eMapMode );
2101
1.33k
                        bBoundsDetermined = true;
2102
1.33k
                    }
2103
1.33k
                    break;
2104
111k
                }
2105
2106
111k
                const auto nAvailableBytes = nEnd - nPos;
2107
111k
                const auto nMaxPossibleRecordSize = nAvailableBytes/2;
2108
111k
                if (nRSize <= nMaxPossibleRecordSize)
2109
109k
                {
2110
109k
                    nPos += nRSize * 2;
2111
109k
                    pStm->Seek(nPos);
2112
109k
                }
2113
1.35k
                else
2114
1.35k
                {
2115
1.35k
                    pStm->SetError( SVSTREAM_FILEFORMAT_ERROR );
2116
1.35k
                    bRet = false;
2117
1.35k
                }
2118
111k
            }
2119
8.12k
        }
2120
132
        else
2121
132
        {
2122
132
            pStm->SetError( SVSTREAM_GENERALERROR );
2123
132
            bRet = false;
2124
132
        }
2125
8.25k
        if (!bRet)
2126
1.88k
        {
2127
1.88k
            SAL_WARN("emfio", "Unable to calculate Placeable Bounds");
2128
1.88k
            return;
2129
1.88k
        }
2130
2131
6.36k
        if (aWinExt)
2132
953
        {
2133
953
            rPlaceableBound = tools::Rectangle(aWinOrg, *aWinExt);
2134
953
            if (mbPlaceable && eMapMode == MM_ANISOTROPIC)
2135
96
            {
2136
                // It seems that (in MM_ANISOTROPIC WMFs) the "inch" field (PPI) in META_PLACEABLE is
2137
                // ignored and instead competitor office suites decide what it should be arbitrarily
2138
                // Could have to do with MM_ANISOTROPICs definition:
2139
                // Logical units are mapped to arbitrary units with arbitrarily scaled axes.
2140
                // The issue is that when PPI is bigger than the window size, the image appears
2141
                // tiny (smaller than an inch squared).
2142
                // A solution is to scale PPI down in such images to an arbitrary amount that makes
2143
                // the image visible:
2144
96
                auto nWidth = rPlaceableBound.GetWidth();
2145
96
                auto nHeight = rPlaceableBound.GetHeight();
2146
96
                if (mnUnitsPerInch > nWidth && mnUnitsPerInch > nHeight)
2147
18
                    mnUnitsPerInch = std::max(nWidth, nHeight);
2148
96
            }
2149
953
            SAL_INFO("emfio", "Window dimension "
2150
953
                       " left: " << rPlaceableBound.Left()  << " top: " << rPlaceableBound.Top()
2151
953
                    << " right: " << rPlaceableBound.Right() << " bottom: " << rPlaceableBound.Bottom());
2152
953
        }
2153
5.41k
        else if (aViewportExt)
2154
23
        {
2155
23
            rPlaceableBound = tools::Rectangle(aViewportOrg, *aViewportExt);
2156
23
            SAL_INFO("emfio", "Viewport dimension "
2157
23
                       " left: " << rPlaceableBound.Left()  << " top: " << rPlaceableBound.Top()
2158
23
                    << " right: " << rPlaceableBound.Right() << " bottom: " << rPlaceableBound.Bottom());
2159
23
        }
2160
5.39k
        else if (bBoundsDetermined)
2161
655
        {
2162
655
            rPlaceableBound = aBound;
2163
655
            SAL_INFO("emfio", "Determined dimension "
2164
655
                       " left: " << rPlaceableBound.Left()  << " top: " << rPlaceableBound.Top()
2165
655
                    << " right: " << rPlaceableBound.Right() << " bottom: " << rPlaceableBound.Bottom());
2166
655
        }
2167
4.73k
        else
2168
4.73k
        {
2169
4.73k
            rPlaceableBound.SetLeft( 0 );
2170
4.73k
            rPlaceableBound.SetTop( 0 );
2171
4.73k
            rPlaceableBound.SetRight( aMaxWidth );
2172
4.73k
            rPlaceableBound.SetBottom( aMaxWidth );
2173
4.73k
            SAL_INFO("emfio", "Default dimension "
2174
4.73k
                       " left: " << rPlaceableBound.Left()  << " top: " << rPlaceableBound.Top()
2175
4.73k
                    << " right: " << rPlaceableBound.Right() << " bottom: " << rPlaceableBound.Bottom());
2176
4.73k
        }
2177
6.36k
    }
2178
2179
    WmfReader::WmfReader(SvStream& rStreamWMF, GDIMetaFile& rGDIMetaFile, const WmfExternal* pExternalHeader)
2180
8.25k
        : MtfTools(rGDIMetaFile, rStreamWMF)
2181
8.25k
        , mnUnitsPerInch(96)
2182
8.25k
        , mnRecSize(0)
2183
8.25k
        , mbPlaceable(false)
2184
8.25k
        , mnEMFRecCount(0)
2185
8.25k
        , mnEMFRec(0)
2186
8.25k
        , mnEMFSize(0)
2187
8.25k
        , mnSkipActions(0)
2188
8.25k
        , mpExternalHeader(pExternalHeader)
2189
8.25k
    {
2190
8.25k
    }
2191
}
2192
2193
/* vim:set shiftwidth=4 softtabstop=4 expandtab: */